1/*
2 * Copyright (c) 1998-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#define IOKIT_ENABLE_SHARED_PTR
30
31#include <libkern/c++/OSAllocation.h>
32#include <libkern/c++/OSKext.h>
33#include <libkern/c++/OSMetaClass.h>
34#include <libkern/OSAtomic.h>
35#include <libkern/OSDebug.h>
36#include <IOKit/IOWorkLoop.h>
37#include <IOKit/IOCommandGate.h>
38#include <IOKit/IOTimerEventSource.h>
39#include <IOKit/IOPlatformExpert.h>
40#include <IOKit/IOCPU.h>
41#include <IOKit/IOPlatformActions.h>
42#include <IOKit/IOKitDebug.h>
43#include <IOKit/IOTimeStamp.h>
44#include <IOKit/pwr_mgt/IOPMlog.h>
45#include <IOKit/pwr_mgt/RootDomain.h>
46#include <IOKit/pwr_mgt/IOPMPrivate.h>
47#include <IOKit/IODeviceTreeSupport.h>
48#include <IOKit/IOMessage.h>
49#include <IOKit/IOReturn.h>
50#include <IOKit/IONVRAM.h>
51#include "RootDomainUserClient.h"
52#include "IOKit/pwr_mgt/IOPowerConnection.h"
53#include "IOPMPowerStateQueue.h"
54#include <IOKit/IOCatalogue.h>
55#include <IOKit/IOReportMacros.h>
56#include <IOKit/IOLib.h>
57#include <IOKit/IOKitKeys.h>
58#include <IOKit/IOUserServer.h>
59#include "IOKitKernelInternal.h"
60#if HIBERNATION
61#include <IOKit/IOHibernatePrivate.h>
62#endif /* HIBERNATION */
63#include <console/video_console.h>
64#include <sys/syslog.h>
65#include <sys/sysctl.h>
66#include <sys/vnode.h>
67#include <sys/vnode_internal.h>
68#include <sys/fcntl.h>
69#include <os/log.h>
70#include <pexpert/protos.h>
71#include <AssertMacros.h>
72
73#include <sys/time.h>
74#include "IOServicePrivate.h" // _IOServiceInterestNotifier
75#include "IOServicePMPrivate.h"
76
77#include <libkern/zlib.h>
78#include <os/cpp_util.h>
79#include <os/atomic_private.h>
80#include <libkern/c++/OSBoundedArrayRef.h>
81
82#if DEVELOPMENT || DEBUG
83#include <os/system_event_log.h>
84#endif /* DEVELOPMENT || DEBUG */
85
86__BEGIN_DECLS
87#include <mach/shared_region.h>
88#include <kern/clock.h>
89__END_DECLS
90
91#if defined(__i386__) || defined(__x86_64__)
92__BEGIN_DECLS
93#include "IOPMrootDomainInternal.h"
94const char *processor_to_datastring(const char *prefix, processor_t target_processor);
95__END_DECLS
96#endif
97
98#define kIOPMrootDomainClass "IOPMrootDomain"
99#define LOG_PREFIX "PMRD: "
100
101
102#define MSG(x...) \
103 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
104
105#define LOG(x...) \
106 do { kprintf(LOG_PREFIX x); } while (false)
107
108#if DEVELOPMENT || DEBUG
109#define DEBUG_LOG(x...) do { \
110 if (kIOLogPMRootDomain & gIOKitDebug) \
111 kprintf(LOG_PREFIX x); \
112 os_log_debug(OS_LOG_DEFAULT, LOG_PREFIX x); \
113} while (false)
114#else
115#define DEBUG_LOG(x...)
116#endif
117
118#define DLOG(x...) do { \
119 if (kIOLogPMRootDomain & gIOKitDebug) \
120 IOLog(LOG_PREFIX x); \
121 else \
122 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
123} while (false)
124
125#define DMSG(x...) do { \
126 if (kIOLogPMRootDomain & gIOKitDebug) { \
127 kprintf(LOG_PREFIX x); \
128 } \
129} while (false)
130
131
132#define _LOG(x...)
133
134#define CHECK_THREAD_CONTEXT
135#ifdef CHECK_THREAD_CONTEXT
136static IOWorkLoop * gIOPMWorkLoop = NULL;
137#define ASSERT_GATED() \
138do { \
139 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
140 panic("RootDomain: not inside PM gate"); \
141 } \
142} while(false)
143#else
144#define ASSERT_GATED()
145#endif /* CHECK_THREAD_CONTEXT */
146
147#define CAP_LOSS(c) \
148 (((_pendingCapability & (c)) == 0) && \
149 ((_currentCapability & (c)) != 0))
150
151#define CAP_GAIN(c) \
152 (((_currentCapability & (c)) == 0) && \
153 ((_pendingCapability & (c)) != 0))
154
155#define CAP_CHANGE(c) \
156 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
157
158#define CAP_CURRENT(c) \
159 ((_currentCapability & (c)) != 0)
160
161#define CAP_HIGHEST(c) \
162 ((_highestCapability & (c)) != 0)
163
164#define CAP_PENDING(c) \
165 ((_pendingCapability & (c)) != 0)
166
167// rdar://problem/9157444
168#if defined(__i386__) || defined(__x86_64__)
169#define DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY 20
170#endif
171
172// Event types for IOPMPowerStateQueue::submitPowerEvent()
173enum {
174 kPowerEventFeatureChanged = 1, // 1
175 kPowerEventReceivedPowerNotification, // 2
176 kPowerEventSystemBootCompleted, // 3
177 kPowerEventSystemShutdown, // 4
178 kPowerEventUserDisabledSleep, // 5
179 kPowerEventRegisterSystemCapabilityClient, // 6
180 kPowerEventRegisterKernelCapabilityClient, // 7
181 kPowerEventPolicyStimulus, // 8
182 kPowerEventAssertionCreate, // 9
183 kPowerEventAssertionRelease, // 10
184 kPowerEventAssertionSetLevel, // 11
185 kPowerEventQueueSleepWakeUUID, // 12
186 kPowerEventPublishSleepWakeUUID, // 13
187 kPowerEventSetDisplayPowerOn, // 14
188 kPowerEventPublishWakeType, // 15
189 kPowerEventAOTEvaluate // 16
190};
191
192// For evaluatePolicy()
193// List of stimuli that affects the root domain policy.
194enum {
195 kStimulusDisplayWranglerSleep, // 0
196 kStimulusDisplayWranglerWake, // 1
197 kStimulusAggressivenessChanged, // 2
198 kStimulusDemandSystemSleep, // 3
199 kStimulusAllowSystemSleepChanged, // 4
200 kStimulusDarkWakeActivityTickle, // 5
201 kStimulusDarkWakeEntry, // 6
202 kStimulusDarkWakeReentry, // 7
203 kStimulusDarkWakeEvaluate, // 8
204 kStimulusNoIdleSleepPreventers, // 9
205 kStimulusEnterUserActiveState, // 10
206 kStimulusLeaveUserActiveState // 11
207};
208
209// Internal power state change reasons
210// Must be less than kIOPMSleepReasonClamshell=101
211enum {
212 kCPSReasonNone = 0, // 0
213 kCPSReasonInit, // 1
214 kCPSReasonWake, // 2
215 kCPSReasonIdleSleepPrevent, // 3
216 kCPSReasonIdleSleepAllow, // 4
217 kCPSReasonPowerOverride, // 5
218 kCPSReasonPowerDownCancel, // 6
219 kCPSReasonAOTExit, // 7
220 kCPSReasonAdjustPowerState, // 8
221 kCPSReasonDarkWakeCannotSleep, // 9
222 kCPSReasonIdleSleepEnabled, // 10
223 kCPSReasonEvaluatePolicy, // 11
224 kCPSReasonSustainFullWake, // 12
225 kCPSReasonPMInternals = (kIOPMSleepReasonClamshell - 1)
226};
227
228extern "C" {
229IOReturn OSKextSystemSleepOrWake( UInt32 );
230}
231extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
232extern "C" addr64_t kvtophys(vm_offset_t va);
233extern "C" boolean_t kdp_has_polled_corefile();
234
235static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
236static void notifySystemShutdown( IOService * root, uint32_t messageType );
237static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
238static void pmEventTimeStamp(uint64_t *recordTS);
239static void powerButtonUpCallout( thread_call_param_t, thread_call_param_t );
240static void powerButtonDownCallout( thread_call_param_t, thread_call_param_t );
241static OSPtr<const OSSymbol> copyKextIdentifierWithAddress(vm_address_t address);
242
243static int IOPMConvertSecondsToCalendar(clock_sec_t secs, IOPMCalendarStruct * dt);
244static clock_sec_t IOPMConvertCalendarToSeconds(const IOPMCalendarStruct * dt);
245#define YMDTF "%04d/%02d/%d %02d:%02d:%02d"
246#define YMDT(cal) ((int)(cal)->year), (cal)->month, (cal)->day, (cal)->hour, (cal)->minute, (cal)->second
247
248// "IOPMSetSleepSupported" callPlatformFunction name
249static OSSharedPtr<const OSSymbol> sleepSupportedPEFunction;
250static OSSharedPtr<const OSSymbol> sleepMessagePEFunction;
251static OSSharedPtr<const OSSymbol> gIOPMWakeTypeUserKey;
252
253static OSSharedPtr<const OSSymbol> gIOPMPSExternalConnectedKey;
254static OSSharedPtr<const OSSymbol> gIOPMPSExternalChargeCapableKey;
255static OSSharedPtr<const OSSymbol> gIOPMPSBatteryInstalledKey;
256static OSSharedPtr<const OSSymbol> gIOPMPSIsChargingKey;
257static OSSharedPtr<const OSSymbol> gIOPMPSAtWarnLevelKey;
258static OSSharedPtr<const OSSymbol> gIOPMPSAtCriticalLevelKey;
259static OSSharedPtr<const OSSymbol> gIOPMPSCurrentCapacityKey;
260static OSSharedPtr<const OSSymbol> gIOPMPSMaxCapacityKey;
261static OSSharedPtr<const OSSymbol> gIOPMPSDesignCapacityKey;
262static OSSharedPtr<const OSSymbol> gIOPMPSTimeRemainingKey;
263static OSSharedPtr<const OSSymbol> gIOPMPSAmperageKey;
264static OSSharedPtr<const OSSymbol> gIOPMPSVoltageKey;
265static OSSharedPtr<const OSSymbol> gIOPMPSCycleCountKey;
266static OSSharedPtr<const OSSymbol> gIOPMPSMaxErrKey;
267static OSSharedPtr<const OSSymbol> gIOPMPSAdapterInfoKey;
268static OSSharedPtr<const OSSymbol> gIOPMPSLocationKey;
269static OSSharedPtr<const OSSymbol> gIOPMPSErrorConditionKey;
270static OSSharedPtr<const OSSymbol> gIOPMPSManufacturerKey;
271static OSSharedPtr<const OSSymbol> gIOPMPSManufactureDateKey;
272static OSSharedPtr<const OSSymbol> gIOPMPSModelKey;
273static OSSharedPtr<const OSSymbol> gIOPMPSSerialKey;
274static OSSharedPtr<const OSSymbol> gIOPMPSLegacyBatteryInfoKey;
275static OSSharedPtr<const OSSymbol> gIOPMPSBatteryHealthKey;
276static OSSharedPtr<const OSSymbol> gIOPMPSHealthConfidenceKey;
277static OSSharedPtr<const OSSymbol> gIOPMPSCapacityEstimatedKey;
278static OSSharedPtr<const OSSymbol> gIOPMPSBatteryChargeStatusKey;
279static OSSharedPtr<const OSSymbol> gIOPMPSBatteryTemperatureKey;
280static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsKey;
281static OSSharedPtr<const OSSymbol> gIOPMPSChargerConfigurationKey;
282static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsIDKey;
283static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsWattsKey;
284static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsRevisionKey;
285static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSerialNumberKey;
286static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsFamilyKey;
287static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsAmperageKey;
288static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsDescriptionKey;
289static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsPMUConfigurationKey;
290static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSourceIDKey;
291static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsErrorFlagsKey;
292static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSharedSourceKey;
293static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsCloakedKey;
294static OSSharedPtr<const OSSymbol> gIOPMPSInvalidWakeSecondsKey;
295static OSSharedPtr<const OSSymbol> gIOPMPSPostChargeWaitSecondsKey;
296static OSSharedPtr<const OSSymbol> gIOPMPSPostDishargeWaitSecondsKey;
297
298#define kIOSleepSupportedKey "IOSleepSupported"
299#define kIOPMSystemCapabilitiesKey "System Capabilities"
300#define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict"
301
302#define kIORequestWranglerIdleKey "IORequestIdle"
303#define kDefaultWranglerIdlePeriod 1000 // in milliseconds
304
305#define kIOSleepWakeFailureString "SleepWakeFailureString"
306#define kIOEFIBootRomFailureKey "wake-failure"
307#define kIOSleepWakeFailurePanic "SleepWakeFailurePanic"
308
309#define kRD_AllPowerSources (kIOPMSupportedOnAC \
310 | kIOPMSupportedOnBatt \
311 | kIOPMSupportedOnUPS)
312
313#define kLocalEvalClamshellCommand (1 << 15)
314#define kIdleSleepRetryInterval (3 * 60 * 1000)
315
316// Minimum time in milliseconds after AP wake that we allow idle timer to expire.
317// We impose this minimum to avoid race conditions in the AP wake path where
318// userspace clients are not able to acquire power assertions before the idle timer expires.
319#define kMinimumTimeBeforeIdleSleep 1000
320
321#define DISPLAY_WRANGLER_PRESENT (!NO_KERNEL_HID)
322
323enum {
324 kWranglerPowerStateMin = 0,
325 kWranglerPowerStateSleep = 2,
326 kWranglerPowerStateDim = 3,
327 kWranglerPowerStateMax = 4
328};
329
330enum {
331 OFF_STATE = 0,
332 RESTART_STATE = 1,
333 SLEEP_STATE = 2,
334 AOT_STATE = 3,
335 ON_STATE = 4,
336 NUM_POWER_STATES
337};
338
339const char *
340getPowerStateString( uint32_t state )
341{
342#define POWER_STATE(x) {(uint32_t) x, #x}
343
344 static const IONamedValue powerStates[] = {
345 POWER_STATE( OFF_STATE ),
346 POWER_STATE( RESTART_STATE ),
347 POWER_STATE( SLEEP_STATE ),
348 POWER_STATE( AOT_STATE ),
349 POWER_STATE( ON_STATE ),
350 { .value: 0, NULL }
351 };
352 return IOFindNameForValue(value: state, namedValueArray: powerStates);
353}
354
355#define ON_POWER kIOPMPowerOn
356#define RESTART_POWER kIOPMRestart
357#define SLEEP_POWER kIOPMAuxPowerOn
358
359static IOPMPowerState
360 ourPowerStates[NUM_POWER_STATES] =
361{
362 { .version = 1,
363 .capabilityFlags = 0,
364 .outputPowerCharacter = 0,
365 .inputPowerRequirement = 0 },
366 { .version = 1,
367 .capabilityFlags = kIOPMRestartCapability,
368 .outputPowerCharacter = kIOPMRestart,
369 .inputPowerRequirement = RESTART_POWER },
370 { .version = 1,
371 .capabilityFlags = kIOPMSleepCapability,
372 .outputPowerCharacter = kIOPMSleep,
373 .inputPowerRequirement = SLEEP_POWER },
374 { .version = 1,
375 .capabilityFlags = kIOPMAOTCapability,
376 .outputPowerCharacter = kIOPMAOTPower,
377 .inputPowerRequirement = ON_POWER },
378 { .version = 1,
379 .capabilityFlags = kIOPMPowerOn,
380 .outputPowerCharacter = kIOPMPowerOn,
381 .inputPowerRequirement = ON_POWER },
382};
383
384#define kIOPMRootDomainWakeTypeSleepService "SleepService"
385#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
386#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
387#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
388#define kIOPMRootDomainWakeTypeUser "User"
389#define kIOPMRootDomainWakeTypeAlarm "Alarm"
390#define kIOPMRootDomainWakeTypeNetwork "Network"
391#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
392#define kIOPMRootDomainWakeTypeNotification "Notification"
393#define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
394
395// Special interest that entitles the interested client from receiving
396// all system messages. Only used by powerd.
397//
398#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
399
400// Entitlement required for root domain clients
401#define kRootDomainEntitlementSetProperty "com.apple.private.iokit.rootdomain-set-property"
402
403#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
404#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
405
406/*
407 * Aggressiveness
408 */
409#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
410#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
411
412#define kAggressivesMinValue 1
413
414const char *
415getAggressivenessTypeString( uint32_t type )
416{
417#define AGGRESSIVENESS_TYPE(x) {(uint32_t) x, #x}
418
419 static const IONamedValue aggressivenessTypes[] = {
420 AGGRESSIVENESS_TYPE( kPMGeneralAggressiveness ),
421 AGGRESSIVENESS_TYPE( kPMMinutesToDim ),
422 AGGRESSIVENESS_TYPE( kPMMinutesToSpinDown ),
423 AGGRESSIVENESS_TYPE( kPMMinutesToSleep ),
424 AGGRESSIVENESS_TYPE( kPMEthernetWakeOnLANSettings ),
425 AGGRESSIVENESS_TYPE( kPMSetProcessorSpeed ),
426 AGGRESSIVENESS_TYPE( kPMPowerSource),
427 AGGRESSIVENESS_TYPE( kPMMotionSensor ),
428 AGGRESSIVENESS_TYPE( kPMLastAggressivenessType ),
429 { .value: 0, NULL }
430 };
431 return IOFindNameForValue(value: type, namedValueArray: aggressivenessTypes);
432}
433
434enum {
435 kAggressivesStateBusy = 0x01,
436 kAggressivesStateQuickSpindown = 0x02
437};
438
439struct AggressivesRecord {
440 uint32_t flags;
441 uint32_t type;
442 uint32_t value;
443};
444
445struct AggressivesRequest {
446 queue_chain_t chain;
447 uint32_t options;
448 uint32_t dataType;
449 union {
450 OSSharedPtr<IOService> service;
451 AggressivesRecord record;
452 } data;
453};
454
455enum {
456 kAggressivesRequestTypeService = 1,
457 kAggressivesRequestTypeRecord
458};
459
460enum {
461 kAggressivesOptionSynchronous = 0x00000001,
462 kAggressivesOptionQuickSpindownEnable = 0x00000100,
463 kAggressivesOptionQuickSpindownDisable = 0x00000200,
464 kAggressivesOptionQuickSpindownMask = 0x00000300
465};
466
467enum {
468 kAggressivesRecordFlagModified = 0x00000001,
469 kAggressivesRecordFlagMinValue = 0x00000002
470};
471
472// System Sleep Preventers
473
474enum {
475 kPMUserDisabledAllSleep = 1,
476 kPMSystemRestartBootingInProgress,
477 kPMConfigPreventSystemSleep,
478 kPMChildPreventSystemSleep,
479 kPMCPUAssertion,
480 kPMPCIUnsupported,
481 kPMDKNotReady,
482};
483
484const char *
485getSystemSleepPreventerString( uint32_t preventer )
486{
487#define SYSTEM_SLEEP_PREVENTER(x) {(int) x, #x}
488 static const IONamedValue systemSleepPreventers[] = {
489 SYSTEM_SLEEP_PREVENTER( kPMUserDisabledAllSleep ),
490 SYSTEM_SLEEP_PREVENTER( kPMSystemRestartBootingInProgress ),
491 SYSTEM_SLEEP_PREVENTER( kPMConfigPreventSystemSleep ),
492 SYSTEM_SLEEP_PREVENTER( kPMChildPreventSystemSleep ),
493 SYSTEM_SLEEP_PREVENTER( kPMCPUAssertion ),
494 SYSTEM_SLEEP_PREVENTER( kPMPCIUnsupported ),
495 SYSTEM_SLEEP_PREVENTER( kPMDKNotReady ),
496 { .value: 0, NULL }
497 };
498 return IOFindNameForValue(value: preventer, namedValueArray: systemSleepPreventers);
499}
500
501// gDarkWakeFlags
502enum {
503 kDarkWakeFlagPromotionNone = 0x0000,
504 kDarkWakeFlagPromotionEarly = 0x0001, // promote before gfx clamp
505 kDarkWakeFlagPromotionLate = 0x0002, // promote after gfx clamp
506 kDarkWakeFlagPromotionMask = 0x0003,
507 kDarkWakeFlagAlarmIsDark = 0x0100,
508 kDarkWakeFlagAudioNotSuppressed = 0x0200,
509 kDarkWakeFlagUserWakeWorkaround = 0x1000
510};
511
512// gClamshellFlags
513// The workaround for 9157444 is enabled at compile time using the
514// DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY macro and is not represented below.
515enum {
516 kClamshell_WAR_38378787 = 0x00000001,
517 kClamshell_WAR_47715679 = 0x00000002,
518 kClamshell_WAR_58009435 = 0x00000004
519};
520
521// acceptSystemWakeEvents()
522enum {
523 kAcceptSystemWakeEvents_Disable = 0,
524 kAcceptSystemWakeEvents_Enable,
525 kAcceptSystemWakeEvents_Reenable
526};
527
528static IOPMrootDomain * gRootDomain;
529static IORootParent * gPatriarch;
530static IONotifier * gSysPowerDownNotifier = NULL;
531static UInt32 gSleepOrShutdownPending = 0;
532static UInt32 gWillShutdown = 0;
533static UInt32 gPagingOff = 0;
534static UInt32 gSleepWakeUUIDIsSet = false;
535static uint32_t gAggressivesState = 0;
536uint32_t gHaltTimeMaxLog;
537uint32_t gHaltTimeMaxPanic;
538IOLock * gHaltLogLock;
539static char * gHaltLog;
540enum { kHaltLogSize = 2048 };
541static size_t gHaltLogPos;
542static uint64_t gHaltStartTime;
543static char gKextNameBuf[64];
544static size_t gKextNamePos;
545static bool gKextNameEnd;
546
547uuid_string_t bootsessionuuid_string;
548
549#if defined(XNU_TARGET_OS_OSX)
550#if DISPLAY_WRANGLER_PRESENT
551static uint32_t gDarkWakeFlags = kDarkWakeFlagPromotionNone;
552#elif defined(__arm64__)
553// Enable temporary full wake promotion workarounds
554static uint32_t gDarkWakeFlags = kDarkWakeFlagUserWakeWorkaround;
555#else
556// Enable full wake promotion workarounds
557static uint32_t gDarkWakeFlags = kDarkWakeFlagUserWakeWorkaround;
558#endif
559#else /* !defined(XNU_TARGET_OS_OSX) */
560static uint32_t gDarkWakeFlags = kDarkWakeFlagPromotionEarly;
561#endif /* !defined(XNU_TARGET_OS_OSX) */
562
563static uint32_t gNoIdleFlag = 0;
564static uint32_t gSleepDisabledFlag = 0;
565static uint32_t gSwdPanic = 1;
566static uint32_t gSwdSleepTimeout = 0;
567static uint32_t gSwdWakeTimeout = 0;
568static uint32_t gSwdSleepWakeTimeout = 0;
569static PMStatsStruct gPMStats;
570#if DEVELOPMENT || DEBUG
571static uint32_t swd_panic_phase;
572#endif
573
574static uint32_t gClamshellFlags = 0
575#if defined(__i386__) || defined(__x86_64__)
576 | kClamshell_WAR_58009435
577#endif
578;
579
580#if HIBERNATION
581
582#if defined(__arm64__)
583static IOReturn
584defaultSleepPolicyHandler(void *ctx, const IOPMSystemSleepPolicyVariables *vars, IOPMSystemSleepParameters *params)
585{
586 uint32_t sleepType = kIOPMSleepTypeDeepIdle;
587
588 assert(vars->signature == kIOPMSystemSleepPolicySignature);
589 assert(vars->version == kIOPMSystemSleepPolicyVersion);
590
591 // Hibernation enabled and either user forced hibernate or low battery sleep
592 if ((vars->hibernateMode & kIOHibernateModeOn) &&
593 (((vars->hibernateMode & kIOHibernateModeSleep) == 0) ||
594 (vars->sleepFactors & kIOPMSleepFactorBatteryLow))) {
595 sleepType = kIOPMSleepTypeHibernate;
596 }
597 params->version = kIOPMSystemSleepParametersVersion;
598 params->sleepType = sleepType;
599 return kIOReturnSuccess;
600}
601static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = &defaultSleepPolicyHandler;
602#else /* defined(__arm64__) */
603static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = NULL;
604#endif /* defined(__arm64__) */
605
606static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = NULL;
607static void * gSleepPolicyTarget;
608#endif
609
610struct timeval gIOLastSleepTime;
611struct timeval gIOLastWakeTime;
612AbsoluteTime gIOLastWakeAbsTime;
613AbsoluteTime gIOLastSleepAbsTime;
614
615struct timeval gIOLastUserSleepTime;
616
617static char gWakeReasonString[128];
618static char gBootReasonString[80];
619static char gShutdownReasonString[80];
620static bool gWakeReasonSysctlRegistered = false;
621static bool gBootReasonSysctlRegistered = false;
622static bool gShutdownReasonSysctlRegistered = false;
623static bool gWillShutdownSysctlRegistered = false;
624static AbsoluteTime gUserActiveAbsTime;
625static AbsoluteTime gUserInactiveAbsTime;
626
627#if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
628static bool gSpinDumpBufferFull = false;
629#endif
630
631z_stream swd_zs;
632vm_offset_t swd_zs_zmem;
633//size_t swd_zs_zsize;
634size_t swd_zs_zoffset;
635#if defined(__i386__) || defined(__x86_64__)
636IOCPU *currentShutdownTarget = NULL;
637#endif
638
639static unsigned int gPMHaltBusyCount;
640static unsigned int gPMHaltIdleCount;
641static int gPMHaltDepth;
642static uint32_t gPMHaltMessageType;
643static IOLock * gPMHaltLock = NULL;
644static OSSharedPtr<OSArray> gPMHaltArray;
645static OSSharedPtr<const OSSymbol> gPMHaltClientAcknowledgeKey;
646static bool gPMQuiesced;
647
648// Constants used as arguments to IOPMrootDomain::informCPUStateChange
649#define kCPUUnknownIndex 9999999
650enum {
651 kInformAC = 0,
652 kInformLid = 1,
653 kInformableCount = 2
654};
655
656OSSharedPtr<const OSSymbol> gIOPMStatsResponseTimedOut;
657OSSharedPtr<const OSSymbol> gIOPMStatsResponseCancel;
658OSSharedPtr<const OSSymbol> gIOPMStatsResponseSlow;
659OSSharedPtr<const OSSymbol> gIOPMStatsResponsePrompt;
660OSSharedPtr<const OSSymbol> gIOPMStatsDriverPSChangeSlow;
661
662#define kBadPMFeatureID 0
663
664/*
665 * PMSettingHandle
666 * Opaque handle passed to clients of registerPMSettingController()
667 */
668class PMSettingHandle : public OSObject
669{
670 OSDeclareFinalStructors( PMSettingHandle );
671 friend class PMSettingObject;
672
673private:
674 PMSettingObject *pmso;
675 void free(void) APPLE_KEXT_OVERRIDE;
676};
677
678/*
679 * PMSettingObject
680 * Internal object to track each PM setting controller
681 */
682class PMSettingObject : public OSObject
683{
684 OSDeclareFinalStructors( PMSettingObject );
685 friend class IOPMrootDomain;
686
687private:
688 queue_head_t calloutQueue;
689 thread_t waitThread;
690 IOPMrootDomain *parent;
691 PMSettingHandle *pmsh;
692 IOPMSettingControllerCallback func;
693 OSObject *target;
694 uintptr_t refcon;
695 OSDataAllocation<uint32_t> publishedFeatureID;
696 uint32_t settingCount;
697 bool disabled;
698
699 void free(void) APPLE_KEXT_OVERRIDE;
700
701public:
702 static PMSettingObject *pmSettingObject(
703 IOPMrootDomain *parent_arg,
704 IOPMSettingControllerCallback handler_arg,
705 OSObject *target_arg,
706 uintptr_t refcon_arg,
707 uint32_t supportedPowerSources,
708 const OSSymbol *settings[],
709 OSObject **handle_obj);
710
711 IOReturn dispatchPMSetting(const OSSymbol *type, OSObject *object);
712 void clientHandleFreed(void);
713};
714
715struct PMSettingCallEntry {
716 queue_chain_t link;
717 thread_t thread;
718};
719
720#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
721#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
722#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
723#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
724
725/*
726 * PMTraceWorker
727 * Internal helper object for logging trace points to RTC
728 * IOPMrootDomain and only IOPMrootDomain should instantiate
729 * exactly one of these.
730 */
731
732typedef void (*IOPMTracePointHandler)(
733 void * target, uint32_t code, uint32_t data );
734
735class PMTraceWorker : public OSObject
736{
737 OSDeclareDefaultStructors(PMTraceWorker);
738public:
739 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
740
741 static OSPtr<PMTraceWorker> tracer( IOPMrootDomain * );
742 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
743 void tracePoint(uint8_t phase);
744 void traceDetail(uint32_t detail);
745 void traceComponentWakeProgress(uint32_t component, uint32_t data);
746 int recordTopLevelPCIDevice(IOService *);
747 void RTC_TRACE(void);
748 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
749
750 IOPMTracePointHandler tracePointHandler;
751 void * tracePointTarget;
752 uint64_t getPMStatusCode();
753 uint8_t getTracePhase();
754 uint32_t getTraceData();
755private:
756 IOPMrootDomain *owner;
757 IOLock *pmTraceWorkerLock;
758 OSSharedPtr<OSArray> pciDeviceBitMappings;
759
760 uint8_t addedToRegistry;
761 uint8_t tracePhase;
762 uint32_t traceData32;
763 uint8_t loginWindowData;
764 uint8_t coreDisplayData;
765 uint8_t coreGraphicsData;
766};
767
768/*
769 * this should be treated as POD, as it's byte-copied around
770 * and we cannot rely on d'tor firing at the right time
771 */
772struct PMAssertStruct {
773 IOPMDriverAssertionID id;
774 IOPMDriverAssertionType assertionBits;
775 uint64_t createdTime;
776 uint64_t modifiedTime;
777 const OSSymbol *ownerString;
778 IOService *ownerService;
779 uint64_t registryEntryID;
780 IOPMDriverAssertionLevel level;
781 uint64_t assertCPUStartTime;
782 uint64_t assertCPUDuration;
783};
784OSDefineValueObjectForDependentType(PMAssertStruct)
785
786/*
787 * PMAssertionsTracker
788 * Tracks kernel and user space PM assertions
789 */
790class PMAssertionsTracker : public OSObject
791{
792 OSDeclareFinalStructors(PMAssertionsTracker);
793public:
794 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
795
796 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
797 IOReturn releaseAssertion(IOPMDriverAssertionID);
798 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
799 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
800
801 OSSharedPtr<OSArray> copyAssertionsArray(void);
802 IOPMDriverAssertionType getActivatedAssertions(void);
803 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
804
805 IOReturn handleCreateAssertion(OSValueObject<PMAssertStruct> *);
806 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
807 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
808 IOReturn handleSetUserAssertionLevels(void * arg0);
809 void publishProperties(void);
810 void reportCPUBitAccounting(void);
811 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
812
813private:
814 uint32_t tabulateProducerCount;
815 uint32_t tabulateConsumerCount;
816
817 uint64_t maxAssertCPUDuration;
818 uint64_t maxAssertCPUEntryId;
819
820 void tabulate(void);
821 void updateCPUBitAccounting(PMAssertStruct * assertStruct);
822
823 IOPMrootDomain *owner;
824 OSSharedPtr<OSArray> assertionsArray;
825 IOLock *assertionsArrayLock;
826 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8)));/* aligned for atomic access */
827 IOPMDriverAssertionType assertionsKernel;
828 IOPMDriverAssertionType assertionsUser;
829 IOPMDriverAssertionType assertionsCombined;
830};
831
832OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
833
834/*
835 * PMHaltWorker
836 * Internal helper object for Shutdown/Restart notifications.
837 */
838#define kPMHaltMaxWorkers 8
839#define kPMHaltTimeoutMS 100
840
841class PMHaltWorker : public OSObject
842{
843 OSDeclareFinalStructors( PMHaltWorker );
844
845public:
846 IOService * service;// service being worked on
847 AbsoluteTime startTime; // time when work started
848 int depth; // work on nubs at this PM-tree depth
849 int visits; // number of nodes visited (debug)
850 IOLock * lock;
851 bool timeout;// service took too long
852
853 static PMHaltWorker * worker( void );
854 static void main( void * arg, wait_result_t waitResult );
855 static void work( PMHaltWorker * me );
856 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
857 virtual void free( void ) APPLE_KEXT_OVERRIDE;
858};
859
860OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
861
862
863#define super IOService
864OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
865
866boolean_t
867IOPMRootDomainGetWillShutdown(void)
868{
869 return gWillShutdown != 0;
870}
871
872static void
873IOPMRootDomainWillShutdown(void)
874{
875 if (OSCompareAndSwap(0, 1, &gWillShutdown)) {
876 IOService::willShutdown();
877 for (int i = 0; i < 100; i++) {
878 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) {
879 break;
880 }
881 IOSleep( milliseconds: 100 );
882 }
883 }
884}
885
886extern "C" IONotifier *
887registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
888{
889 return gRootDomain->registerInterest( typeOfInterest: gIOGeneralInterest, handler, target: self, ref ).detach();
890}
891
892extern "C" IONotifier *
893registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
894{
895 return gRootDomain->registerInterest( typeOfInterest: gIOPriorityPowerStateInterest, handler, target: self, ref ).detach();
896}
897
898extern "C" IOReturn
899acknowledgeSleepWakeNotification(void * PMrefcon)
900{
901 return gRootDomain->allowPowerChange(refcon: (unsigned long)PMrefcon );
902}
903
904extern "C" IOReturn
905vetoSleepWakeNotification(void * PMrefcon)
906{
907 return gRootDomain->cancelPowerChange(refcon: (unsigned long)PMrefcon );
908}
909
910extern "C" IOReturn
911rootDomainRestart( void )
912{
913 return gRootDomain->restartSystem();
914}
915
916extern "C" IOReturn
917rootDomainShutdown( void )
918{
919 return gRootDomain->shutdownSystem();
920}
921
922static void
923halt_log_putc(char c)
924{
925 if (gHaltLogPos >= (kHaltLogSize - 2)) {
926 return;
927 }
928 gHaltLog[gHaltLogPos++] = c;
929}
930
931extern "C" void
932_doprnt_log(const char *fmt,
933 va_list *argp,
934 void (*putc)(char),
935 int radix);
936
937static int
938halt_log(const char *fmt, ...)
939{
940 va_list listp;
941
942 va_start(listp, fmt);
943 _doprnt_log(fmt, argp: &listp, putc: &halt_log_putc, radix: 16);
944 va_end(listp);
945
946 return 0;
947}
948
949extern "C" void
950halt_log_enter(const char * what, const void * pc, uint64_t time)
951{
952 uint64_t nano, millis;
953
954 if (!gHaltLog) {
955 return;
956 }
957 absolutetime_to_nanoseconds(abstime: time, result: &nano);
958 millis = nano / NSEC_PER_MSEC;
959 if (millis < 100) {
960 return;
961 }
962
963 IOLockLock(gHaltLogLock);
964 if (pc) {
965 halt_log(fmt: "%s: %qd ms @ 0x%lx, ", what, millis, VM_KERNEL_UNSLIDE(pc));
966 OSKext::printKextsInBacktrace(addr: (vm_offset_t *) &pc, cnt: 1, printf_func: &halt_log,
967 flags: OSKext::kPrintKextsLock | OSKext::kPrintKextsUnslide | OSKext::kPrintKextsTerse);
968 } else {
969 halt_log(fmt: "%s: %qd ms\n", what, millis);
970 }
971
972 gHaltLog[gHaltLogPos] = 0;
973 IOLockUnlock(gHaltLogLock);
974}
975
976extern uint32_t gFSState;
977
978extern "C" void
979IOSystemShutdownNotification(int howto, int stage)
980{
981 uint64_t startTime;
982
983 if (kIOSystemShutdownNotificationStageRootUnmount == stage) {
984#if defined(XNU_TARGET_OS_OSX)
985 uint64_t nano, millis;
986 startTime = mach_absolute_time();
987 IOService::getPlatform()->waitQuiet(timeout: 30 * NSEC_PER_SEC);
988 absolutetime_to_nanoseconds(abstime: mach_absolute_time() - startTime, result: &nano);
989 millis = nano / NSEC_PER_MSEC;
990 if (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog)) {
991 printf("waitQuiet() for unmount %qd ms\n", millis);
992 }
993#endif /* defined(XNU_TARGET_OS_OSX) */
994 return;
995 }
996
997 if (kIOSystemShutdownNotificationTerminateDEXTs == stage) {
998 uint64_t nano, millis;
999 startTime = mach_absolute_time();
1000 IOServicePH::systemHalt(howto);
1001 absolutetime_to_nanoseconds(abstime: mach_absolute_time() - startTime, result: &nano);
1002 millis = nano / NSEC_PER_MSEC;
1003 if (true || (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog))) {
1004 printf("IOServicePH::systemHalt took %qd ms\n", millis);
1005 }
1006 return;
1007 }
1008
1009 assert(kIOSystemShutdownNotificationStageProcessExit == stage);
1010
1011 IOLockLock(gHaltLogLock);
1012 if (!gHaltLog) {
1013 gHaltLog = IONewData(char, (vm_size_t)kHaltLogSize);
1014 gHaltStartTime = mach_absolute_time();
1015 if (gHaltLog) {
1016 halt_log_putc(c: '\n');
1017 }
1018 }
1019 IOLockUnlock(gHaltLogLock);
1020
1021 startTime = mach_absolute_time();
1022 IOPMRootDomainWillShutdown();
1023 halt_log_enter(what: "IOPMRootDomainWillShutdown", NULL, time: mach_absolute_time() - startTime);
1024#if HIBERNATION
1025 startTime = mach_absolute_time();
1026 IOHibernateSystemPostWake(true);
1027 halt_log_enter("IOHibernateSystemPostWake", NULL, mach_absolute_time() - startTime);
1028#endif
1029 if (OSCompareAndSwap(0, 1, &gPagingOff)) {
1030 gRootDomain->handlePlatformHaltRestart(pe_type: kPEPagingOff);
1031 }
1032}
1033
1034extern "C" int sync_internal(void);
1035
1036/*
1037 * A device is always in the highest power state which satisfies its driver,
1038 * its policy-maker, and any power children it has, but within the constraint
1039 * of the power state provided by its parent. The driver expresses its desire by
1040 * calling changePowerStateTo(), the policy-maker expresses its desire by calling
1041 * changePowerStateToPriv(), and the children express their desires by calling
1042 * requestPowerDomainState().
1043 *
1044 * The Root Power Domain owns the policy for idle and demand sleep for the system.
1045 * It is a power-managed IOService just like the others in the system.
1046 * It implements several power states which map to what we see as Sleep and On.
1047 *
1048 * The sleep policy is as follows:
1049 * 1. Sleep is prevented if the case is open so that nobody will think the machine
1050 * is off and plug/unplug cards.
1051 * 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
1052 * 3. System cannot Sleep if some object in the tree is in a power state marked
1053 * kIOPMPreventSystemSleep.
1054 *
1055 * These three conditions are enforced using the "driver clamp" by calling
1056 * changePowerStateTo(). For example, if the case is opened,
1057 * changePowerStateTo(ON_STATE) is called to hold the system on regardless
1058 * of the desires of the children of the root or the state of the other clamp.
1059 *
1060 * Demand Sleep is initiated by pressing the front panel power button, closing
1061 * the clamshell, or selecting the menu item. In this case the root's parent
1062 * actually initiates the power state change so that the root domain has no
1063 * choice and does not give applications the opportunity to veto the change.
1064 *
1065 * Idle Sleep occurs if no objects in the tree are in a state marked
1066 * kIOPMPreventIdleSleep. When this is true, the root's children are not holding
1067 * the root on, so it sets the "policy-maker clamp" by calling
1068 * changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
1069 * This timer is set for the difference between the sleep timeout slider and the
1070 * display dim timeout slider. When the timer expires, it releases its clamp and
1071 * now nothing is holding it awake, so it falls asleep.
1072 *
1073 * Demand sleep is prevented when the system is booting. When preferences are
1074 * transmitted by the loginwindow at the end of boot, a flag is cleared,
1075 * and this allows subsequent Demand Sleep.
1076 */
1077
1078//******************************************************************************
1079
1080IOPMrootDomain *
1081IOPMrootDomain::construct( void )
1082{
1083 IOPMrootDomain *root;
1084
1085 root = new IOPMrootDomain;
1086 if (root) {
1087 root->init();
1088 }
1089
1090 return root;
1091}
1092
1093//******************************************************************************
1094// updateConsoleUsersCallout
1095//
1096//******************************************************************************
1097
1098static void
1099updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
1100{
1101 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
1102 rootDomain->updateConsoleUsers();
1103}
1104
1105void
1106IOPMrootDomain::updateConsoleUsers(void)
1107{
1108 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
1109 updateTasksSuspend(newTasksSuspended: kTasksSuspendUnsuspended, newAOTTasksSuspended: kTasksSuspendNoChange);
1110}
1111
1112bool
1113IOPMrootDomain::updateTasksSuspend(int newTasksSuspended, int newAOTTasksSuspended)
1114{
1115 bool newSuspend;
1116
1117 WAKEEVENT_LOCK();
1118 if (newTasksSuspended != kTasksSuspendNoChange) {
1119 tasksSuspended = (newTasksSuspended != kTasksSuspendUnsuspended);
1120 }
1121 if (newAOTTasksSuspended != kTasksSuspendNoChange) {
1122 _aotTasksSuspended = (newAOTTasksSuspended != kTasksSuspendUnsuspended);
1123 }
1124 newSuspend = (tasksSuspended || _aotTasksSuspended);
1125 if (newSuspend == tasksSuspendState) {
1126 WAKEEVENT_UNLOCK();
1127 return false;
1128 }
1129 tasksSuspendState = newSuspend;
1130 WAKEEVENT_UNLOCK();
1131 tasks_system_suspend(suspend: newSuspend);
1132 return true;
1133}
1134
1135//******************************************************************************
1136
1137static void
1138disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
1139{
1140 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
1141 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
1142 uint32_t powerState = rootDomain->getPowerState();
1143
1144 DLOG("disk_sync_callout ps=%u\n", powerState);
1145
1146 if (ON_STATE == powerState) {
1147 sync_internal();
1148
1149#if HIBERNATION
1150 // Block sleep until trim issued on previous wake path is completed.
1151 IOHibernateSystemPostWake(true);
1152#endif
1153 }
1154#if HIBERNATION
1155 else {
1156 IOHibernateSystemPostWake(false);
1157
1158 rootDomain->sleepWakeDebugSaveSpinDumpFile();
1159 }
1160#endif
1161
1162 rootDomain->allowPowerChange(refcon: notifyRef);
1163 DLOG("disk_sync_callout finish\n");
1164}
1165
1166//******************************************************************************
1167static UInt32
1168computeDeltaTimeMS( const AbsoluteTime * startTime, AbsoluteTime * elapsedTime )
1169{
1170 AbsoluteTime endTime;
1171 UInt64 nano = 0;
1172
1173 clock_get_uptime(result: &endTime);
1174 if (CMP_ABSOLUTETIME(&endTime, startTime) <= 0) {
1175 *elapsedTime = 0;
1176 } else {
1177 SUB_ABSOLUTETIME(&endTime, startTime);
1178 absolutetime_to_nanoseconds(abstime: endTime, result: &nano);
1179 *elapsedTime = endTime;
1180 }
1181
1182 return (UInt32)(nano / NSEC_PER_MSEC);
1183}
1184
1185//******************************************************************************
1186
1187static int
1188sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
1189{
1190 struct timeval *swt = (struct timeval *)arg1;
1191 struct proc *p = req->p;
1192
1193 if (p == kernproc) {
1194 return sysctl_io_opaque(req, pValue: swt, valueSize: sizeof(*swt), NULL);
1195 } else if (proc_is64bit(p)) {
1196 struct user64_timeval t = {};
1197 t.tv_sec = swt->tv_sec;
1198 t.tv_usec = swt->tv_usec;
1199 return sysctl_io_opaque(req, pValue: &t, valueSize: sizeof(t), NULL);
1200 } else {
1201 struct user32_timeval t = {};
1202 t.tv_sec = (typeof(t.tv_sec))swt->tv_sec;
1203 t.tv_usec = swt->tv_usec;
1204 return sysctl_io_opaque(req, pValue: &t, valueSize: sizeof(t), NULL);
1205 }
1206}
1207
1208static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
1209 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1210 &gIOLastUserSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
1211
1212static SYSCTL_PROC(_kern, OID_AUTO, waketime,
1213 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1214 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
1215
1216SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
1217SYSCTL_QUAD(_kern, OID_AUTO, sleep_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gIOLastSleepAbsTime, "");
1218SYSCTL_QUAD(_kern, OID_AUTO, useractive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gUserActiveAbsTime, "");
1219SYSCTL_QUAD(_kern, OID_AUTO, userinactive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gUserInactiveAbsTime, "");
1220
1221static int
1222sysctl_willshutdown SYSCTL_HANDLER_ARGS
1223{
1224 int new_value, changed, error;
1225
1226 if (!gWillShutdownSysctlRegistered) {
1227 return ENOENT;
1228 }
1229
1230 error = sysctl_io_number(req, bigValue: gWillShutdown, valueSize: sizeof(int), pValue: &new_value, changed: &changed);
1231 if (changed) {
1232 if (!gWillShutdown && (new_value == 1)) {
1233 IOPMRootDomainWillShutdown();
1234 } else {
1235 error = EINVAL;
1236 }
1237 }
1238 return error;
1239}
1240
1241static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
1242 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1243 NULL, 0, sysctl_willshutdown, "I", "");
1244
1245#if defined(XNU_TARGET_OS_OSX)
1246
1247static int
1248sysctl_progressmeterenable
1249(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1250{
1251 int error;
1252 int new_value, changed;
1253
1254 error = sysctl_io_number(req, bigValue: vc_progressmeter_enable, valueSize: sizeof(int), pValue: &new_value, changed: &changed);
1255
1256 if (changed) {
1257 vc_enable_progressmeter(new_value);
1258 }
1259
1260 return error;
1261}
1262
1263static int
1264sysctl_progressmeter
1265(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1266{
1267 int error;
1268 int new_value, changed;
1269
1270 error = sysctl_io_number(req, bigValue: vc_progressmeter_value, valueSize: sizeof(int), pValue: &new_value, changed: &changed);
1271
1272 if (changed) {
1273 vc_set_progressmeter(new_value);
1274 }
1275
1276 return error;
1277}
1278
1279static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
1280 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1281 NULL, 0, sysctl_progressmeterenable, "I", "");
1282
1283static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
1284 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1285 NULL, 0, sysctl_progressmeter, "I", "");
1286
1287#endif /* defined(XNU_TARGET_OS_OSX) */
1288
1289
1290
1291static int
1292sysctl_consoleoptions
1293(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1294{
1295 int error, changed;
1296 uint32_t new_value;
1297
1298 error = sysctl_io_number(req, bigValue: vc_user_options.options, valueSize: sizeof(uint32_t), pValue: &new_value, changed: &changed);
1299
1300 if (changed) {
1301 vc_user_options.options = new_value;
1302 }
1303
1304 return error;
1305}
1306
1307static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
1308 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1309 NULL, 0, sysctl_consoleoptions, "I", "");
1310
1311
1312static int
1313sysctl_progressoptions SYSCTL_HANDLER_ARGS
1314{
1315 return sysctl_io_opaque(req, pValue: &vc_user_options, valueSize: sizeof(vc_user_options), NULL);
1316}
1317
1318static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
1319 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
1320 NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
1321
1322
1323static int
1324sysctl_wakereason SYSCTL_HANDLER_ARGS
1325{
1326 char wr[sizeof(gWakeReasonString)];
1327
1328 wr[0] = '\0';
1329 if (gRootDomain && gWakeReasonSysctlRegistered) {
1330 gRootDomain->copyWakeReasonString(outBuf: wr, bufSize: sizeof(wr));
1331 } else {
1332 return ENOENT;
1333 }
1334
1335 return sysctl_io_string(req, pValue: wr, valueSize: 0, trunc: 0, NULL);
1336}
1337
1338SYSCTL_PROC(_kern, OID_AUTO, wakereason,
1339 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1340 NULL, 0, sysctl_wakereason, "A", "wakereason");
1341
1342static int
1343sysctl_bootreason SYSCTL_HANDLER_ARGS
1344{
1345 if (!os_atomic_load(&gBootReasonSysctlRegistered, acquire)) {
1346 return ENOENT;
1347 }
1348
1349 return sysctl_io_string(req, pValue: gBootReasonString, valueSize: 0, trunc: 0, NULL);
1350}
1351
1352SYSCTL_PROC(_kern, OID_AUTO, bootreason,
1353 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1354 NULL, 0, sysctl_bootreason, "A", "");
1355
1356static int
1357sysctl_shutdownreason SYSCTL_HANDLER_ARGS
1358{
1359 char sr[sizeof(gShutdownReasonString)];
1360
1361 sr[0] = '\0';
1362 if (gRootDomain && gShutdownReasonSysctlRegistered) {
1363 gRootDomain->copyShutdownReasonString(outBuf: sr, bufSize: sizeof(sr));
1364 } else {
1365 return ENOENT;
1366 }
1367
1368 return sysctl_io_string(req, pValue: sr, valueSize: 0, trunc: 0, NULL);
1369}
1370
1371SYSCTL_PROC(_kern, OID_AUTO, shutdownreason,
1372 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1373 NULL, 0, sysctl_shutdownreason, "A", "shutdownreason");
1374
1375static int
1376sysctl_targettype SYSCTL_HANDLER_ARGS
1377{
1378 IOService * root;
1379 OSSharedPtr<OSObject> obj;
1380 OSData * data;
1381 char tt[32];
1382
1383 tt[0] = '\0';
1384 root = IOService::getServiceRoot();
1385 if (root && (obj = root->copyProperty(aKey: gIODTTargetTypeKey))) {
1386 if ((data = OSDynamicCast(OSData, obj.get()))) {
1387 strlcpy(dst: tt, src: (const char *) data->getBytesNoCopy(), n: sizeof(tt));
1388 }
1389 }
1390 return sysctl_io_string(req, pValue: tt, valueSize: 0, trunc: 0, NULL);
1391}
1392
1393SYSCTL_PROC(_hw, OID_AUTO, targettype,
1394 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1395 NULL, 0, sysctl_targettype, "A", "targettype");
1396
1397static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
1398static SYSCTL_INT(_debug, OID_AUTO, swd_sleep_timeout, CTLFLAG_RW, &gSwdSleepTimeout, 0, "");
1399static SYSCTL_INT(_debug, OID_AUTO, swd_wake_timeout, CTLFLAG_RW, &gSwdWakeTimeout, 0, "");
1400static SYSCTL_INT(_debug, OID_AUTO, swd_timeout, CTLFLAG_RW, &gSwdSleepWakeTimeout, 0, "");
1401static SYSCTL_INT(_debug, OID_AUTO, swd_panic, CTLFLAG_RW, &gSwdPanic, 0, "");
1402#if DEVELOPMENT || DEBUG
1403static SYSCTL_INT(_debug, OID_AUTO, swd_panic_phase, CTLFLAG_RW, &swd_panic_phase, 0, "");
1404#if defined(XNU_TARGET_OS_OSX)
1405static SYSCTL_INT(_debug, OID_AUTO, clamshell, CTLFLAG_RW, &gClamshellFlags, 0, "");
1406static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
1407#endif /* defined(XNU_TARGET_OS_OSX) */
1408#endif /* DEVELOPMENT || DEBUG */
1409
1410//******************************************************************************
1411// AOT
1412
1413static int
1414sysctl_aotmetrics SYSCTL_HANDLER_ARGS
1415{
1416 if (NULL == gRootDomain) {
1417 return ENOENT;
1418 }
1419 if (NULL == gRootDomain->_aotMetrics) {
1420 IOPMAOTMetrics nullMetrics = {};
1421 return sysctl_io_opaque(req, pValue: &nullMetrics, valueSize: sizeof(IOPMAOTMetrics), NULL);
1422 }
1423 return sysctl_io_opaque(req, pValue: gRootDomain->_aotMetrics, valueSize: sizeof(IOPMAOTMetrics), NULL);
1424}
1425
1426static SYSCTL_PROC(_kern, OID_AUTO, aotmetrics,
1427 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
1428 NULL, 0, sysctl_aotmetrics, "S,IOPMAOTMetrics", "");
1429
1430
1431static int
1432update_aotmode(uint32_t mode)
1433{
1434 int result;
1435
1436 if (!gIOPMWorkLoop) {
1437 return ENOENT;
1438 }
1439 result = gIOPMWorkLoop->runActionBlock(action: ^IOReturn (void) {
1440 unsigned int oldCount;
1441
1442 if (mode && !gRootDomain->_aotMetrics) {
1443 gRootDomain->_aotMetrics = IOMallocType(IOPMAOTMetrics);
1444 }
1445
1446 oldCount = gRootDomain->idleSleepPreventersCount();
1447 gRootDomain->_aotMode = (mode & kIOPMAOTModeMask);
1448 gRootDomain->updatePreventIdleSleepListInternal(NULL, addNotRemove: false, oldCount);
1449 return 0;
1450 });
1451 return result;
1452}
1453
1454static int
1455sysctl_aotmodebits
1456(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1457{
1458 int error, changed;
1459 uint32_t new_value;
1460
1461 if (NULL == gRootDomain) {
1462 return ENOENT;
1463 }
1464 error = sysctl_io_number(req, bigValue: gRootDomain->_aotMode, valueSize: sizeof(uint32_t), pValue: &new_value, changed: &changed);
1465 if (changed && gIOPMWorkLoop) {
1466 error = update_aotmode(mode: new_value);
1467 }
1468
1469 return error;
1470}
1471
1472static SYSCTL_PROC(_kern, OID_AUTO, aotmodebits,
1473 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1474 NULL, 0, sysctl_aotmodebits, "I", "");
1475
1476static int
1477sysctl_aotmode
1478(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1479{
1480 int error, changed;
1481 uint32_t new_value;
1482
1483 if (NULL == gRootDomain) {
1484 return ENOENT;
1485 }
1486 error = sysctl_io_number(req, bigValue: gRootDomain->_aotMode, valueSize: sizeof(uint32_t), pValue: &new_value, changed: &changed);
1487 if (changed && gIOPMWorkLoop) {
1488 if (new_value) {
1489 new_value = kIOPMAOTModeDefault; // & ~kIOPMAOTModeRespectTimers;
1490 }
1491 error = update_aotmode(mode: new_value);
1492 }
1493
1494 return error;
1495}
1496
1497static SYSCTL_PROC(_kern, OID_AUTO, aotmode,
1498 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
1499 NULL, 0, sysctl_aotmode, "I", "");
1500
1501//******************************************************************************
1502
1503static OSSharedPtr<const OSSymbol> gIOPMSettingAutoWakeCalendarKey;
1504static OSSharedPtr<const OSSymbol> gIOPMSettingAutoWakeSecondsKey;
1505static OSSharedPtr<const OSSymbol> gIOPMSettingAutoPowerCalendarKey;
1506static OSSharedPtr<const OSSymbol> gIOPMSettingAutoPowerSecondsKey;
1507static OSSharedPtr<const OSSymbol> gIOPMSettingDebugWakeRelativeKey;
1508static OSSharedPtr<const OSSymbol> gIOPMSettingDebugPowerRelativeKey;
1509static OSSharedPtr<const OSSymbol> gIOPMSettingMaintenanceWakeCalendarKey;
1510static OSSharedPtr<const OSSymbol> gIOPMSettingSleepServiceWakeCalendarKey;
1511static OSSharedPtr<const OSSymbol> gIOPMSettingSilentRunningKey;
1512static OSSharedPtr<const OSSymbol> gIOPMUserTriggeredFullWakeKey;
1513static OSSharedPtr<const OSSymbol> gIOPMUserIsActiveKey;
1514static OSSharedPtr<const OSSymbol> gIOPMSettingLowLatencyAudioModeKey;
1515
1516//******************************************************************************
1517// start
1518//
1519//******************************************************************************
1520
1521#define kRootDomainSettingsCount 20
1522#define kRootDomainNoPublishSettingsCount 4
1523
1524bool
1525IOPMrootDomain::start( IOService * nub )
1526{
1527 OSSharedPtr<OSIterator> psIterator;
1528 OSSharedPtr<OSDictionary> tmpDict;
1529
1530 super::start(provider: nub);
1531
1532 gRootDomain = this;
1533 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
1534 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
1535 gIOPMSettingAutoPowerCalendarKey = OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey);
1536 gIOPMSettingAutoPowerSecondsKey = OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey);
1537 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
1538 gIOPMSettingDebugPowerRelativeKey = OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey);
1539 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
1540 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
1541 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
1542 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
1543 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
1544 gIOPMSettingLowLatencyAudioModeKey = OSSymbol::withCStringNoCopy(kIOPMSettingLowLatencyAudioModeKey);
1545
1546 gIOPMStatsResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
1547 gIOPMStatsResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
1548 gIOPMStatsResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
1549 gIOPMStatsResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
1550 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
1551
1552 sleepSupportedPEFunction = OSSymbol::withCString(cString: "IOPMSetSleepSupported");
1553 sleepMessagePEFunction = OSSymbol::withCString(cString: "IOPMSystemSleepMessage");
1554 gIOPMWakeTypeUserKey = OSSymbol::withCStringNoCopy(kIOPMRootDomainWakeTypeUser);
1555
1556 OSSharedPtr<const OSSymbol> settingsArr[kRootDomainSettingsCount] =
1557 {
1558 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
1559 gIOPMSettingAutoWakeSecondsKey,
1560 gIOPMSettingAutoPowerSecondsKey,
1561 gIOPMSettingAutoWakeCalendarKey,
1562 gIOPMSettingAutoPowerCalendarKey,
1563 gIOPMSettingDebugWakeRelativeKey,
1564 gIOPMSettingDebugPowerRelativeKey,
1565 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
1566 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
1567 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
1568 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
1569 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
1570 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
1571 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
1572 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
1573 OSSymbol::withCString(kIOPMStateConsoleShutdown),
1574 OSSymbol::withCString(kIOPMSettingProModeControl),
1575 OSSymbol::withCString(kIOPMSettingProModeDefer),
1576 gIOPMSettingSilentRunningKey,
1577 gIOPMSettingLowLatencyAudioModeKey,
1578 };
1579
1580 OSSharedPtr<const OSSymbol> noPublishSettingsArr[kRootDomainNoPublishSettingsCount] =
1581 {
1582 OSSymbol::withCString(kIOPMSettingProModeControl),
1583 OSSymbol::withCString(kIOPMSettingProModeDefer),
1584 gIOPMSettingSilentRunningKey,
1585 gIOPMSettingLowLatencyAudioModeKey,
1586 };
1587
1588#if DEVELOPMENT || DEBUG
1589#if defined(XNU_TARGET_OS_OSX)
1590 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
1591 PE_parse_boot_argn("clamshell", &gClamshellFlags, sizeof(gClamshellFlags));
1592#endif /* defined(XNU_TARGET_OS_OSX) */
1593#endif /* DEVELOPMENT || DEBUG */
1594
1595 PE_parse_boot_argn(arg_string: "noidle", arg_ptr: &gNoIdleFlag, max_arg: sizeof(gNoIdleFlag));
1596 PE_parse_boot_argn(arg_string: "swd_sleeptimeout", arg_ptr: &gSwdSleepTimeout, max_arg: sizeof(gSwdSleepTimeout));
1597 PE_parse_boot_argn(arg_string: "swd_waketimeout", arg_ptr: &gSwdWakeTimeout, max_arg: sizeof(gSwdWakeTimeout));
1598 PE_parse_boot_argn(arg_string: "swd_timeout", arg_ptr: &gSwdSleepWakeTimeout, max_arg: sizeof(gSwdSleepWakeTimeout));
1599 PE_parse_boot_argn(arg_string: "haltmspanic", arg_ptr: &gHaltTimeMaxPanic, max_arg: sizeof(gHaltTimeMaxPanic));
1600 PE_parse_boot_argn(arg_string: "haltmslog", arg_ptr: &gHaltTimeMaxLog, max_arg: sizeof(gHaltTimeMaxLog));
1601
1602 // read noidle setting from Device Tree
1603 if (PE_get_default(property_name: "no-idle", property_ptr: &gNoIdleFlag, max_property: sizeof(gNoIdleFlag))) {
1604 DLOG("Setting gNoIdleFlag to %u from device tree\n", gNoIdleFlag);
1605 }
1606
1607 queue_init(&aggressivesQueue);
1608 aggressivesThreadCall = thread_call_allocate(func: handleAggressivesFunction, param0: this);
1609 aggressivesData = OSData::withCapacity(
1610 capacity: sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
1611
1612 featuresDictLock = IOLockAlloc();
1613 settingsCtrlLock = IOLockAlloc();
1614 wakeEventLock = IOLockAlloc();
1615 gHaltLogLock = IOLockAlloc();
1616 setPMRootDomain(this);
1617
1618 extraSleepTimer = thread_call_allocate(
1619 func: idleSleepTimerExpired,
1620 param0: (thread_call_param_t) this);
1621
1622 powerButtonDown = thread_call_allocate(
1623 func: powerButtonDownCallout,
1624 param0: (thread_call_param_t) this);
1625
1626 powerButtonUp = thread_call_allocate(
1627 func: powerButtonUpCallout,
1628 param0: (thread_call_param_t) this);
1629
1630 diskSyncCalloutEntry = thread_call_allocate(
1631 func: &disk_sync_callout,
1632 param0: (thread_call_param_t) this);
1633 updateConsoleUsersEntry = thread_call_allocate(
1634 func: &updateConsoleUsersCallout,
1635 param0: (thread_call_param_t) this);
1636
1637#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
1638 fullWakeThreadCall = thread_call_allocate_with_options(
1639 OSMemberFunctionCast(thread_call_func_t, this,
1640 &IOPMrootDomain::fullWakeDelayedWork),
1641 (thread_call_param_t) this, THREAD_CALL_PRIORITY_KERNEL,
1642 THREAD_CALL_OPTIONS_ONCE);
1643#endif
1644
1645 setProperty(kIOSleepSupportedKey, aBoolean: true);
1646
1647 bzero(s: &gPMStats, n: sizeof(gPMStats));
1648
1649 pmTracer = PMTraceWorker::tracer(this);
1650
1651 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1652
1653 userDisabledAllSleep = false;
1654 systemBooting = true;
1655 idleSleepEnabled = false;
1656 sleepSlider = 0;
1657 idleSleepTimerPending = false;
1658 wrangler = NULL;
1659 clamshellClosed = false;
1660 clamshellExists = false;
1661#if DISPLAY_WRANGLER_PRESENT
1662 clamshellDisabled = true;
1663#else
1664 clamshellDisabled = false;
1665#endif
1666 clamshellIgnoreClose = false;
1667 acAdaptorConnected = true;
1668 clamshellSleepDisableMask = 0;
1669 gWakeReasonString[0] = '\0';
1670
1671 // Initialize to user active.
1672 // Will never transition to user inactive w/o wrangler.
1673 fullWakeReason = kFullWakeReasonLocalUser;
1674 userIsActive = userWasActive = true;
1675 clock_get_uptime(result: &gUserActiveAbsTime);
1676 setProperty(aKey: gIOPMUserIsActiveKey.get(), anObject: kOSBooleanTrue);
1677
1678 // Set the default system capabilities at boot.
1679 _currentCapability = kIOPMSystemCapabilityCPU |
1680 kIOPMSystemCapabilityGraphics |
1681 kIOPMSystemCapabilityAudio |
1682 kIOPMSystemCapabilityNetwork;
1683
1684 _pendingCapability = _currentCapability;
1685 _desiredCapability = _currentCapability;
1686 _highestCapability = _currentCapability;
1687 setProperty(kIOPMSystemCapabilitiesKey, aValue: _currentCapability, aNumberOfBits: 64);
1688
1689 queuedSleepWakeUUIDString = NULL;
1690 initializeBootSessionUUID();
1691 pmStatsAppResponses = OSArray::withCapacity(capacity: 5);
1692 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
1693 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
1694 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
1695 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
1696 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
1697 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
1698 assertOnWakeSecs = -1;// Invalid value to prevent updates
1699
1700 pmStatsLock = IOLockAlloc();
1701 idxPMCPUClamshell = kCPUUnknownIndex;
1702 idxPMCPULimitedPower = kCPUUnknownIndex;
1703
1704 tmpDict = OSDictionary::withCapacity(capacity: 1);
1705 setProperty(kRootDomainSupportedFeatures, anObject: tmpDict.get());
1706
1707 // Set a default "SystemPowerProfileOverrideDict" for platform
1708 // drivers without any overrides.
1709 if (!propertyExists(kIOPMSystemDefaultOverrideKey)) {
1710 tmpDict = OSDictionary::withCapacity(capacity: 1);
1711 setProperty(kIOPMSystemDefaultOverrideKey, anObject: tmpDict.get());
1712 }
1713
1714 settingsCallbacks = OSDictionary::withCapacity(capacity: 1);
1715
1716 // Create a list of the valid PM settings that we'll relay to
1717 // interested clients in setProperties() => setPMSetting()
1718 allowedPMSettings = OSArray::withObjects(
1719 objects: (const OSObject **)settingsArr,
1720 kRootDomainSettingsCount,
1721 capacity: 0);
1722
1723 // List of PM settings that should not automatically publish itself
1724 // as a feature when registered by a listener.
1725 noPublishPMSettings = OSArray::withObjects(
1726 objects: (const OSObject **)noPublishSettingsArr,
1727 kRootDomainNoPublishSettingsCount,
1728 capacity: 0);
1729
1730 fPMSettingsDict = OSDictionary::withCapacity(capacity: 5);
1731 preventIdleSleepList = OSSet::withCapacity(capacity: 8);
1732 preventSystemSleepList = OSSet::withCapacity(capacity: 2);
1733
1734 PMinit(); // creates gIOPMWorkLoop
1735 gIOPMWorkLoop = getIOPMWorkloop();
1736
1737 // Create IOPMPowerStateQueue used to queue external power
1738 // events, and to handle those events on the PM work loop.
1739 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
1740 owner: this, OSMemberFunctionCast(IOEventSource::Action, this,
1741 &IOPMrootDomain::dispatchPowerEvent));
1742 gIOPMWorkLoop->addEventSource(newEvent: pmPowerStateQueue);
1743
1744 _aotMode = 0;
1745 _aotTimerES = IOTimerEventSource::timerEventSource(owner: this,
1746 OSMemberFunctionCast(IOTimerEventSource::Action,
1747 this, &IOPMrootDomain::aotEvaluate));
1748 gIOPMWorkLoop->addEventSource(newEvent: _aotTimerES.get());
1749
1750 // Avoid publishing service early so gIOPMWorkLoop is
1751 // guaranteed to be initialized by rootDomain.
1752 publishPMRootDomain();
1753
1754 // create our power parent
1755 gPatriarch = new IORootParent;
1756 gPatriarch->init();
1757 gPatriarch->attach(provider: this);
1758 gPatriarch->start(nub: this);
1759 gPatriarch->addPowerChild(theChild: this);
1760
1761 registerPowerDriver(controllingDriver: this, powerStates: ourPowerStates, numberOfStates: NUM_POWER_STATES);
1762 changePowerStateWithTagToPriv(ordinal: ON_STATE, tag: kCPSReasonInit);
1763
1764 // install power change handler
1765 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( handler: &sysPowerDownHandler, self: this, NULL);
1766
1767#if DISPLAY_WRANGLER_PRESENT
1768 wranglerIdleSettings = OSDictionary::withCapacity(1);
1769 OSSharedPtr<OSNumber> wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
1770
1771 if (wranglerIdleSettings && wranglerIdlePeriod) {
1772 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
1773 wranglerIdlePeriod.get());
1774 }
1775
1776#endif /* DISPLAY_WRANGLER_PRESENT */
1777
1778 lowLatencyAudioNotifierDict = OSDictionary::withCapacity(capacity: 2);
1779 lowLatencyAudioNotifyStateSym = OSSymbol::withCString(cString: "LowLatencyAudioNotifyState");
1780 lowLatencyAudioNotifyTimestampSym = OSSymbol::withCString(cString: "LowLatencyAudioNotifyTimestamp");
1781 lowLatencyAudioNotifyStateVal = OSNumber::withNumber(value: 0ull, numberOfBits: 32);
1782 lowLatencyAudioNotifyTimestampVal = OSNumber::withNumber(value: 0ull, numberOfBits: 64);
1783
1784 if (lowLatencyAudioNotifierDict && lowLatencyAudioNotifyStateSym && lowLatencyAudioNotifyTimestampSym &&
1785 lowLatencyAudioNotifyStateVal && lowLatencyAudioNotifyTimestampVal) {
1786 lowLatencyAudioNotifierDict->setObject(aKey: lowLatencyAudioNotifyStateSym.get(), anObject: lowLatencyAudioNotifyStateVal.get());
1787 lowLatencyAudioNotifierDict->setObject(aKey: lowLatencyAudioNotifyTimestampSym.get(), anObject: lowLatencyAudioNotifyTimestampVal.get());
1788 }
1789
1790 OSSharedPtr<const OSSymbol> ucClassName = OSSymbol::withCStringNoCopy(cString: "RootDomainUserClient");
1791 setProperty(aKey: gIOUserClientClassKey, anObject: const_cast<OSObject *>(static_cast<const OSObject *>(ucClassName.get())));
1792
1793 // IOBacklightDisplay can take a long time to load at boot, or it may
1794 // not load at all if you're booting with clamshell closed. We publish
1795 // 'DisplayDims' here redundantly to get it published early and at all.
1796 OSSharedPtr<OSDictionary> matching;
1797 matching = serviceMatching(className: "IOPMPowerSource");
1798 psIterator = getMatchingServices(matching: matching.get());
1799
1800 if (psIterator && psIterator->getNextObject()) {
1801 // There's at least one battery on the system, so we publish
1802 // 'DisplayDims' support for the LCD.
1803 publishFeature(feature: "DisplayDims");
1804 }
1805
1806 // read swd_panic boot-arg
1807 PE_parse_boot_argn(arg_string: "swd_panic", arg_ptr: &gSwdPanic, max_arg: sizeof(gSwdPanic));
1808 gWillShutdownSysctlRegistered = true;
1809
1810#if HIBERNATION
1811#if defined(__arm64__)
1812#endif /* defined(__arm64__) */
1813 IOHibernateSystemInit(this);
1814#endif
1815
1816 registerService(); // let clients find us
1817
1818 return true;
1819}
1820
1821//******************************************************************************
1822// setProperties
1823//
1824// Receive a setProperty call
1825// The "System Boot" property means the system is completely booted.
1826//******************************************************************************
1827
1828IOReturn
1829IOPMrootDomain::setProperties( OSObject * props_obj )
1830{
1831 IOReturn return_value = kIOReturnSuccess;
1832 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1833 OSBoolean *b = NULL;
1834 OSNumber *n = NULL;
1835 const OSSymbol *key = NULL;
1836 OSObject *obj = NULL;
1837 OSSharedPtr<OSCollectionIterator> iter;
1838
1839 if (!dict) {
1840 return kIOReturnBadArgument;
1841 }
1842
1843 bool clientEntitled = false;
1844 {
1845 OSSharedPtr<OSObject> obj = IOUserClient::copyClientEntitlement(task: current_task(), kRootDomainEntitlementSetProperty);
1846 clientEntitled = (obj == kOSBooleanTrue);
1847 }
1848
1849 if (!clientEntitled) {
1850 const char * errorSuffix = NULL;
1851
1852 // IOPMSchedulePowerEvent() clients may not be entitled, but must be root.
1853 // That API can set 6 possible keys that are checked below.
1854 if ((dict->getCount() == 1) &&
1855 (dict->getObject(aKey: gIOPMSettingAutoWakeSecondsKey.get()) ||
1856 dict->getObject(aKey: gIOPMSettingAutoPowerSecondsKey.get()) ||
1857 dict->getObject(aKey: gIOPMSettingAutoWakeCalendarKey.get()) ||
1858 dict->getObject(aKey: gIOPMSettingAutoPowerCalendarKey.get()) ||
1859 dict->getObject(aKey: gIOPMSettingDebugWakeRelativeKey.get()) ||
1860 dict->getObject(aKey: gIOPMSettingDebugPowerRelativeKey.get()))) {
1861 return_value = IOUserClient::clientHasPrivilege(securityToken: current_task(), kIOClientPrivilegeAdministrator);
1862 if (return_value != kIOReturnSuccess) {
1863 errorSuffix = "privileged";
1864 }
1865 } else {
1866 return_value = kIOReturnNotPermitted;
1867 errorSuffix = "entitled";
1868 }
1869
1870 if (return_value != kIOReturnSuccess) {
1871 OSSharedPtr<OSString> procName(IOCopyLogNameForPID(pid: proc_selfpid()), OSNoRetain);
1872 DLOG("%s failed, process %s is not %s\n", __func__,
1873 procName ? procName->getCStringNoCopy() : "", errorSuffix);
1874 return return_value;
1875 }
1876 }
1877
1878 OSSharedPtr<const OSSymbol> publish_simulated_battery_string = OSSymbol::withCString(cString: "SoftwareSimulatedBatteries");
1879 OSSharedPtr<const OSSymbol> boot_complete_string = OSSymbol::withCString(cString: "System Boot Complete");
1880 OSSharedPtr<const OSSymbol> sys_shutdown_string = OSSymbol::withCString(cString: "System Shutdown");
1881 OSSharedPtr<const OSSymbol> stall_halt_string = OSSymbol::withCString(cString: "StallSystemAtHalt");
1882 OSSharedPtr<const OSSymbol> battery_warning_disabled_string = OSSymbol::withCString(cString: "BatteryWarningsDisabled");
1883 OSSharedPtr<const OSSymbol> idle_seconds_string = OSSymbol::withCString(cString: "System Idle Seconds");
1884 OSSharedPtr<const OSSymbol> idle_milliseconds_string = OSSymbol::withCString(cString: "System Idle Milliseconds");
1885 OSSharedPtr<const OSSymbol> sleepdisabled_string = OSSymbol::withCString(cString: "SleepDisabled");
1886 OSSharedPtr<const OSSymbol> ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1887 OSSharedPtr<const OSSymbol> loginwindow_progress_string = OSSymbol::withCString(kIOPMLoginWindowProgressKey);
1888 OSSharedPtr<const OSSymbol> coredisplay_progress_string = OSSymbol::withCString(kIOPMCoreDisplayProgressKey);
1889 OSSharedPtr<const OSSymbol> coregraphics_progress_string = OSSymbol::withCString(kIOPMCoreGraphicsProgressKey);
1890#if DEBUG || DEVELOPMENT
1891 OSSharedPtr<const OSSymbol> clamshell_close_string = OSSymbol::withCString("IOPMTestClamshellClose");
1892 OSSharedPtr<const OSSymbol> clamshell_open_string = OSSymbol::withCString("IOPMTestClamshellOpen");
1893 OSSharedPtr<const OSSymbol> ac_detach_string = OSSymbol::withCString("IOPMTestACDetach");
1894 OSSharedPtr<const OSSymbol> ac_attach_string = OSSymbol::withCString("IOPMTestACAttach");
1895 OSSharedPtr<const OSSymbol> desktopmode_set_string = OSSymbol::withCString("IOPMTestDesktopModeSet");
1896 OSSharedPtr<const OSSymbol> desktopmode_remove_string = OSSymbol::withCString("IOPMTestDesktopModeRemove");
1897#endif
1898
1899#if HIBERNATION
1900 OSSharedPtr<const OSSymbol> hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1901 OSSharedPtr<const OSSymbol> hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1902 OSSharedPtr<const OSSymbol> hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1903 OSSharedPtr<const OSSymbol> hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
1904 OSSharedPtr<const OSSymbol> hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1905 OSSharedPtr<const OSSymbol> hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
1906#endif
1907
1908 iter = OSCollectionIterator::withCollection(inColl: dict);
1909 if (!iter) {
1910 return_value = kIOReturnNoMemory;
1911 goto exit;
1912 }
1913
1914 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1915 (obj = dict->getObject(aKey: key))) {
1916 if (key->isEqualTo(aSymbol: publish_simulated_battery_string.get())) {
1917 if (OSDynamicCast(OSBoolean, obj)) {
1918 publishResource(key, value: kOSBooleanTrue);
1919 }
1920 } else if (key->isEqualTo(aSymbol: idle_seconds_string.get())) {
1921 if ((n = OSDynamicCast(OSNumber, obj))) {
1922 setProperty(aKey: key, anObject: n);
1923 idleMilliSeconds = n->unsigned32BitValue() * 1000;
1924 }
1925 } else if (key->isEqualTo(aSymbol: idle_milliseconds_string.get())) {
1926 if ((n = OSDynamicCast(OSNumber, obj))) {
1927 setProperty(aKey: key, anObject: n);
1928 idleMilliSeconds = n->unsigned32BitValue();
1929 }
1930 } else if (key->isEqualTo(aSymbol: boot_complete_string.get())) {
1931 pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventSystemBootCompleted);
1932 } else if (key->isEqualTo(aSymbol: sys_shutdown_string.get())) {
1933 if ((b = OSDynamicCast(OSBoolean, obj))) {
1934 pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventSystemShutdown, arg0: (void *) b);
1935 }
1936 } else if (key->isEqualTo(aSymbol: battery_warning_disabled_string.get())) {
1937 setProperty(aKey: key, anObject: obj);
1938 }
1939#if HIBERNATION
1940 else if (key->isEqualTo(hibernatemode_string.get()) ||
1941 key->isEqualTo(hibernatefilemin_string.get()) ||
1942 key->isEqualTo(hibernatefilemax_string.get()) ||
1943 key->isEqualTo(hibernatefreeratio_string.get()) ||
1944 key->isEqualTo(hibernatefreetime_string.get())) {
1945 if ((n = OSDynamicCast(OSNumber, obj))) {
1946 setProperty(key, n);
1947 }
1948 } else if (key->isEqualTo(hibernatefile_string.get())) {
1949 OSString * str = OSDynamicCast(OSString, obj);
1950 if (str) {
1951 setProperty(key, str);
1952 }
1953 }
1954#endif
1955 else if (key->isEqualTo(aSymbol: sleepdisabled_string.get())) {
1956 if ((b = OSDynamicCast(OSBoolean, obj))) {
1957 setProperty(aKey: key, anObject: b);
1958 pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventUserDisabledSleep, arg0: (void *) b);
1959 }
1960 } else if (key->isEqualTo(aSymbol: ondeck_sleepwake_uuid_string.get())) {
1961 obj->retain();
1962 pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventQueueSleepWakeUUID, arg0: (void *)obj);
1963 } else if (key->isEqualTo(aSymbol: loginwindow_progress_string.get())) {
1964 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1965 uint32_t data = n->unsigned32BitValue();
1966 pmTracer->traceComponentWakeProgress(component: kIOPMLoginWindowProgress, data);
1967 kdebugTrace(event: kPMLogComponentWakeProgress, regId: 0, param1: kIOPMLoginWindowProgress, param2: data);
1968 }
1969 } else if (key->isEqualTo(aSymbol: coredisplay_progress_string.get())) {
1970 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1971 uint32_t data = n->unsigned32BitValue();
1972 pmTracer->traceComponentWakeProgress(component: kIOPMCoreDisplayProgress, data);
1973 kdebugTrace(event: kPMLogComponentWakeProgress, regId: 0, param1: kIOPMCoreDisplayProgress, param2: data);
1974 }
1975 } else if (key->isEqualTo(aSymbol: coregraphics_progress_string.get())) {
1976 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1977 uint32_t data = n->unsigned32BitValue();
1978 pmTracer->traceComponentWakeProgress(component: kIOPMCoreGraphicsProgress, data);
1979 kdebugTrace(event: kPMLogComponentWakeProgress, regId: 0, param1: kIOPMCoreGraphicsProgress, param2: data);
1980 }
1981 } else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1982 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1983 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
1984 key->isEqualTo(aSymbol: stall_halt_string.get())) {
1985 if ((b = OSDynamicCast(OSBoolean, obj))) {
1986 setProperty(aKey: key, anObject: b);
1987 }
1988 } else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
1989 key->isEqualTo(kIOPMDeepSleepTimerKey) ||
1990 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1991 key->isEqualTo(kIOPMAutoPowerOffTimerKey)) {
1992 if ((n = OSDynamicCast(OSNumber, obj))) {
1993 setProperty(aKey: key, anObject: n);
1994 }
1995 } else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey)) {
1996 if (kOSBooleanTrue == obj) {
1997 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarmMask);
1998 } else {
1999 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarmMask);
2000 }
2001 DLOG("_userScheduledAlarmMask 0x%x\n", (uint32_t) _userScheduledAlarmMask);
2002 }
2003#if DEBUG || DEVELOPMENT
2004 else if (key->isEqualTo(clamshell_close_string.get())) {
2005 DLOG("SetProperties: setting clamshell close\n");
2006 UInt32 msg = kIOPMClamshellClosed;
2007 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2008 } else if (key->isEqualTo(clamshell_open_string.get())) {
2009 DLOG("SetProperties: setting clamshell open\n");
2010 UInt32 msg = kIOPMClamshellOpened;
2011 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2012 } else if (key->isEqualTo(ac_detach_string.get())) {
2013 DLOG("SetProperties: setting ac detach\n");
2014 UInt32 msg = kIOPMSetACAdaptorConnected;
2015 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2016 } else if (key->isEqualTo(ac_attach_string.get())) {
2017 DLOG("SetProperties: setting ac attach\n");
2018 UInt32 msg = kIOPMSetACAdaptorConnected | kIOPMSetValue;
2019 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2020 } else if (key->isEqualTo(desktopmode_set_string.get())) {
2021 DLOG("SetProperties: setting desktopmode");
2022 UInt32 msg = kIOPMSetDesktopMode | kIOPMSetValue;
2023 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2024 } else if (key->isEqualTo(desktopmode_remove_string.get())) {
2025 DLOG("SetProperties: removing desktopmode\n");
2026 UInt32 msg = kIOPMSetDesktopMode;
2027 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2028 }
2029#endif
2030 // Relay our allowed PM settings onto our registered PM clients
2031 else if ((allowedPMSettings->getNextIndexOfObject(anObject: key, index: 0) != (unsigned int) -1)) {
2032 return_value = setPMSetting(key, obj);
2033 if (kIOReturnSuccess != return_value) {
2034 break;
2035 }
2036 } else {
2037 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
2038 }
2039 }
2040
2041exit:
2042 return return_value;
2043}
2044
2045// MARK: -
2046// MARK: Aggressiveness
2047
2048//******************************************************************************
2049// setAggressiveness
2050//
2051// Override IOService::setAggressiveness()
2052//******************************************************************************
2053
2054IOReturn
2055IOPMrootDomain::setAggressiveness(
2056 unsigned long type,
2057 unsigned long value )
2058{
2059 return setAggressiveness( type, value, options: 0 );
2060}
2061
2062/*
2063 * Private setAggressiveness() with an internal options argument.
2064 */
2065IOReturn
2066IOPMrootDomain::setAggressiveness(
2067 unsigned long type,
2068 unsigned long value,
2069 IOOptionBits options )
2070{
2071 AggressivesRequest * entry;
2072 AggressivesRequest * request;
2073 bool found = false;
2074
2075 if ((type > UINT_MAX) || (value > UINT_MAX)) {
2076 return kIOReturnBadArgument;
2077 }
2078
2079 if (type == kPMMinutesToDim || type == kPMMinutesToSleep) {
2080 DLOG("setAggressiveness(%x) %s = %u\n",
2081 (uint32_t) options, getAggressivenessTypeString((uint32_t) type), (uint32_t) value);
2082 } else {
2083 DEBUG_LOG("setAggressiveness(%x) %s = %u\n",
2084 (uint32_t) options, getAggressivenessTypeString((uint32_t) type), (uint32_t) value);
2085 }
2086
2087 request = IOMallocType(AggressivesRequest);
2088 request->options = options;
2089 request->dataType = kAggressivesRequestTypeRecord;
2090 request->data.record.type = (uint32_t) type;
2091 request->data.record.value = (uint32_t) value;
2092
2093 AGGRESSIVES_LOCK();
2094
2095 // Update disk quick spindown flag used by getAggressiveness().
2096 // Never merge requests with quick spindown flags set.
2097
2098 if (options & kAggressivesOptionQuickSpindownEnable) {
2099 gAggressivesState |= kAggressivesStateQuickSpindown;
2100 } else if (options & kAggressivesOptionQuickSpindownDisable) {
2101 gAggressivesState &= ~kAggressivesStateQuickSpindown;
2102 } else {
2103 // Coalesce requests with identical aggressives types.
2104 // Deal with callers that calls us too "aggressively".
2105
2106 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
2107 {
2108 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
2109 (entry->data.record.type == type) &&
2110 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) {
2111 entry->data.record.value = (uint32_t) value;
2112 found = true;
2113 break;
2114 }
2115 }
2116 }
2117
2118 if (!found) {
2119 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
2120 }
2121
2122 AGGRESSIVES_UNLOCK();
2123
2124 if (found) {
2125 IOFreeType(request, AggressivesRequest);
2126 }
2127
2128 if (options & kAggressivesOptionSynchronous) {
2129 handleAggressivesRequests(); // not truly synchronous
2130 } else {
2131 thread_call_enter(call: aggressivesThreadCall);
2132 }
2133
2134 return kIOReturnSuccess;
2135}
2136
2137//******************************************************************************
2138// getAggressiveness
2139//
2140// Override IOService::setAggressiveness()
2141// Fetch the aggressiveness factor with the given type.
2142//******************************************************************************
2143
2144IOReturn
2145IOPMrootDomain::getAggressiveness(
2146 unsigned long type,
2147 unsigned long * outLevel )
2148{
2149 uint32_t value = 0;
2150 int source = 0;
2151
2152 if (!outLevel || (type > UINT_MAX)) {
2153 return kIOReturnBadArgument;
2154 }
2155
2156 AGGRESSIVES_LOCK();
2157
2158 // Disk quick spindown in effect, report value = 1
2159
2160 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
2161 (type == kPMMinutesToSpinDown)) {
2162 value = kAggressivesMinValue;
2163 source = 1;
2164 }
2165
2166 // Consult the pending request queue.
2167
2168 if (!source) {
2169 AggressivesRequest * entry;
2170
2171 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
2172 {
2173 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
2174 (entry->data.record.type == type) &&
2175 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) {
2176 value = entry->data.record.value;
2177 source = 2;
2178 break;
2179 }
2180 }
2181 }
2182
2183 // Consult the backend records.
2184
2185 if (!source && aggressivesData) {
2186 AggressivesRecord * record;
2187 int i, count;
2188
2189 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2190 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2191
2192 for (i = 0; i < count; i++, record++) {
2193 if (record->type == type) {
2194 value = record->value;
2195 source = 3;
2196 break;
2197 }
2198 }
2199 }
2200
2201 AGGRESSIVES_UNLOCK();
2202
2203 if (source) {
2204 *outLevel = (unsigned long) value;
2205 return kIOReturnSuccess;
2206 } else {
2207 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
2208 *outLevel = 0; // default return = 0, driver may not check for error
2209 return kIOReturnInvalid;
2210 }
2211}
2212
2213//******************************************************************************
2214// joinAggressiveness
2215//
2216// Request from IOService to join future aggressiveness broadcasts.
2217//******************************************************************************
2218
2219IOReturn
2220IOPMrootDomain::joinAggressiveness(
2221 IOService * service )
2222{
2223 AggressivesRequest * request;
2224
2225 if (!service || (service == this)) {
2226 return kIOReturnBadArgument;
2227 }
2228
2229 DEBUG_LOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
2230
2231 request = IOMallocType(AggressivesRequest);
2232 request->dataType = kAggressivesRequestTypeService;
2233 request->data.service.reset(p: service, OSRetain); // released by synchronizeAggressives()
2234
2235 AGGRESSIVES_LOCK();
2236 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
2237 AGGRESSIVES_UNLOCK();
2238
2239 thread_call_enter(call: aggressivesThreadCall);
2240
2241 return kIOReturnSuccess;
2242}
2243
2244//******************************************************************************
2245// handleAggressivesRequests
2246//
2247// Backend thread processes all incoming aggressiveness requests in the queue.
2248//******************************************************************************
2249
2250static void
2251handleAggressivesFunction(
2252 thread_call_param_t param1,
2253 thread_call_param_t param2 )
2254{
2255 if (param1) {
2256 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
2257 }
2258}
2259
2260void
2261IOPMrootDomain::handleAggressivesRequests( void )
2262{
2263 AggressivesRecord * start;
2264 AggressivesRecord * record;
2265 AggressivesRequest * request;
2266 queue_head_t joinedQueue;
2267 int i, count;
2268 bool broadcast;
2269 bool found;
2270 bool pingSelf = false;
2271
2272 AGGRESSIVES_LOCK();
2273
2274 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
2275 queue_empty(&aggressivesQueue)) {
2276 goto unlock_done;
2277 }
2278
2279 gAggressivesState |= kAggressivesStateBusy;
2280 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2281 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2282
2283 do{
2284 broadcast = false;
2285 queue_init(&joinedQueue);
2286
2287 do{
2288 // Remove request from the incoming queue in FIFO order.
2289 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
2290 switch (request->dataType) {
2291 case kAggressivesRequestTypeRecord:
2292 // Update existing record if found.
2293 found = false;
2294 for (i = 0, record = start; i < count; i++, record++) {
2295 if (record->type == request->data.record.type) {
2296 found = true;
2297
2298 if (request->options & kAggressivesOptionQuickSpindownEnable) {
2299 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) {
2300 broadcast = true;
2301 record->flags |= (kAggressivesRecordFlagMinValue |
2302 kAggressivesRecordFlagModified);
2303 DLOG("disk spindown accelerated, was %u min\n",
2304 record->value);
2305 }
2306 } else if (request->options & kAggressivesOptionQuickSpindownDisable) {
2307 if (record->flags & kAggressivesRecordFlagMinValue) {
2308 broadcast = true;
2309 record->flags |= kAggressivesRecordFlagModified;
2310 record->flags &= ~kAggressivesRecordFlagMinValue;
2311 DLOG("disk spindown restored to %u min\n",
2312 record->value);
2313 }
2314 } else if (record->value != request->data.record.value) {
2315 record->value = request->data.record.value;
2316 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) {
2317 broadcast = true;
2318 record->flags |= kAggressivesRecordFlagModified;
2319 }
2320 }
2321 break;
2322 }
2323 }
2324
2325 // No matching record, append a new record.
2326 if (!found &&
2327 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0)) {
2328 AggressivesRecord newRecord;
2329
2330 newRecord.flags = kAggressivesRecordFlagModified;
2331 newRecord.type = request->data.record.type;
2332 newRecord.value = request->data.record.value;
2333 if (request->options & kAggressivesOptionQuickSpindownEnable) {
2334 newRecord.flags |= kAggressivesRecordFlagMinValue;
2335 DLOG("disk spindown accelerated\n");
2336 }
2337
2338 aggressivesData->appendValue(value: newRecord);
2339
2340 // OSData may have switched to another (larger) buffer.
2341 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2342 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2343 broadcast = true;
2344 }
2345
2346 // Finished processing the request, release it.
2347 IOFreeType(request, AggressivesRequest);
2348 break;
2349
2350 case kAggressivesRequestTypeService:
2351 // synchronizeAggressives() will free request.
2352 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
2353 break;
2354
2355 default:
2356 panic("bad aggressives request type %x", request->dataType);
2357 break;
2358 }
2359 } while (!queue_empty(&aggressivesQueue));
2360
2361 // Release the lock to perform work, with busy flag set.
2362 if (!queue_empty(&joinedQueue) || broadcast) {
2363 AGGRESSIVES_UNLOCK();
2364 if (!queue_empty(&joinedQueue)) {
2365 synchronizeAggressives(services: &joinedQueue, array: start, count);
2366 }
2367 if (broadcast) {
2368 broadcastAggressives(array: start, count);
2369 }
2370 AGGRESSIVES_LOCK();
2371 }
2372
2373 // Remove the modified flag from all records.
2374 for (i = 0, record = start; i < count; i++, record++) {
2375 if ((record->flags & kAggressivesRecordFlagModified) &&
2376 ((record->type == kPMMinutesToDim) ||
2377 (record->type == kPMMinutesToSleep))) {
2378 pingSelf = true;
2379 }
2380
2381 record->flags &= ~kAggressivesRecordFlagModified;
2382 }
2383
2384 // Check the incoming queue again since new entries may have been
2385 // added while lock was released above.
2386 } while (!queue_empty(&aggressivesQueue));
2387
2388 gAggressivesState &= ~kAggressivesStateBusy;
2389
2390unlock_done:
2391 AGGRESSIVES_UNLOCK();
2392
2393 // Root domain is interested in system and display sleep slider changes.
2394 // Submit a power event to handle those changes on the PM work loop.
2395
2396 if (pingSelf && pmPowerStateQueue) {
2397 pmPowerStateQueue->submitPowerEvent(
2398 eventType: kPowerEventPolicyStimulus,
2399 arg0: (void *) kStimulusAggressivenessChanged );
2400 }
2401}
2402
2403//******************************************************************************
2404// synchronizeAggressives
2405//
2406// Push all known aggressiveness records to one or more IOService.
2407//******************************************************************************
2408
2409void
2410IOPMrootDomain::synchronizeAggressives(
2411 queue_head_t * joinedQueue,
2412 const AggressivesRecord * array,
2413 int count )
2414{
2415 OSSharedPtr<IOService> service;
2416 AggressivesRequest * request;
2417 const AggressivesRecord * record;
2418 IOPMDriverCallEntry callEntry;
2419 uint32_t value;
2420 int i;
2421
2422 while (!queue_empty(joinedQueue)) {
2423 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
2424 if (request->dataType == kAggressivesRequestTypeService) {
2425 // retained by joinAggressiveness(), so take ownership
2426 service = os::move(t&: request->data.service);
2427 } else {
2428 service.reset();
2429 }
2430
2431 IOFreeType(request, AggressivesRequest);
2432 request = NULL;
2433
2434 if (service) {
2435 if (service->assertPMDriverCall(callEntry: &callEntry, method: kIOPMDriverCallMethodSetAggressive)) {
2436 for (i = 0, record = array; i < count; i++, record++) {
2437 value = record->value;
2438 if (record->flags & kAggressivesRecordFlagMinValue) {
2439 value = kAggressivesMinValue;
2440 }
2441
2442 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2443 record->type, value, service->getName());
2444 service->setAggressiveness(type: record->type, newLevel: value);
2445 }
2446 service->deassertPMDriverCall(callEntry: &callEntry);
2447 }
2448 }
2449 }
2450}
2451
2452//******************************************************************************
2453// broadcastAggressives
2454//
2455// Traverse PM tree and call setAggressiveness() for records that have changed.
2456//******************************************************************************
2457
2458void
2459IOPMrootDomain::broadcastAggressives(
2460 const AggressivesRecord * array,
2461 int count )
2462{
2463 OSSharedPtr<IORegistryIterator> iter;
2464 IORegistryEntry *entry;
2465 OSSharedPtr<IORegistryEntry> child;
2466 IOPowerConnection *connect;
2467 IOService *service;
2468 const AggressivesRecord *record;
2469 IOPMDriverCallEntry callEntry;
2470 uint32_t value;
2471 int i;
2472
2473 iter = IORegistryIterator::iterateOver(
2474 start: this, plane: gIOPowerPlane, options: kIORegistryIterateRecursively);
2475 if (iter) {
2476 do{
2477 // !! reset the iterator
2478 iter->reset();
2479 while ((entry = iter->getNextObject())) {
2480 connect = OSDynamicCast(IOPowerConnection, entry);
2481 if (!connect || !connect->getReadyFlag()) {
2482 continue;
2483 }
2484
2485 child = connect->copyChildEntry(plane: gIOPowerPlane);
2486 if (child) {
2487 if ((service = OSDynamicCast(IOService, child.get()))) {
2488 if (service->assertPMDriverCall(callEntry: &callEntry, method: kIOPMDriverCallMethodSetAggressive)) {
2489 for (i = 0, record = array; i < count; i++, record++) {
2490 if (record->flags & kAggressivesRecordFlagModified) {
2491 value = record->value;
2492 if (record->flags & kAggressivesRecordFlagMinValue) {
2493 value = kAggressivesMinValue;
2494 }
2495 _LOG("broadcastAggressives %x = %u to %s\n",
2496 record->type, value, service->getName());
2497 service->setAggressiveness(type: record->type, newLevel: value);
2498 }
2499 }
2500 service->deassertPMDriverCall(callEntry: &callEntry);
2501 }
2502 }
2503 }
2504 }
2505 }while (!entry && !iter->isValid());
2506 }
2507}
2508
2509//*****************************************
2510// stackshot on power button press
2511// ***************************************
2512static void
2513powerButtonDownCallout(thread_call_param_t us, thread_call_param_t )
2514{
2515 /* Power button pressed during wake
2516 * Take a stackshot
2517 */
2518 DEBUG_LOG("Powerbutton: down. Taking stackshot\n");
2519 ((IOPMrootDomain *)us)->takeStackshot(restart: false);
2520}
2521
2522static void
2523powerButtonUpCallout(thread_call_param_t us, thread_call_param_t)
2524{
2525 /* Power button released.
2526 * Delete any stackshot data
2527 */
2528 DEBUG_LOG("PowerButton: up callout. Delete stackshot\n");
2529 ((IOPMrootDomain *)us)->deleteStackshot();
2530}
2531//*************************************************************************
2532//
2533
2534// MARK: -
2535// MARK: System Sleep
2536
2537//******************************************************************************
2538// startIdleSleepTimer
2539//
2540//******************************************************************************
2541
2542void
2543IOPMrootDomain::startIdleSleepTimer( uint32_t inMilliSeconds )
2544{
2545 AbsoluteTime deadline;
2546
2547 ASSERT_GATED();
2548 if (gNoIdleFlag) {
2549 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
2550 return;
2551 }
2552 if (inMilliSeconds) {
2553 if (inMilliSeconds < kMinimumTimeBeforeIdleSleep) {
2554 AbsoluteTime now;
2555 uint64_t nsec_since_wake;
2556 uint64_t msec_since_wake;
2557
2558 // Adjust idle timer so it will not expire until atleast kMinimumTimeBeforeIdleSleep milliseconds
2559 // after the most recent AP wake.
2560 clock_get_uptime(result: &now);
2561 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2562 absolutetime_to_nanoseconds(abstime: now, result: &nsec_since_wake);
2563 msec_since_wake = nsec_since_wake / NSEC_PER_MSEC;
2564
2565 if (msec_since_wake < kMinimumTimeBeforeIdleSleep) {
2566 uint32_t newIdleTimer = kMinimumTimeBeforeIdleSleep - (uint32_t)msec_since_wake;
2567
2568 // Ensure that our new idle timer is not less than inMilliSeconds,
2569 // as we should only be increasing the timer duration, not decreasing it
2570 if (newIdleTimer > inMilliSeconds) {
2571 DLOG("startIdleSleepTimer increasing timeout from %u to %u\n", inMilliSeconds, newIdleTimer);
2572 inMilliSeconds = newIdleTimer;
2573 }
2574 }
2575 }
2576 clock_interval_to_deadline(interval: inMilliSeconds, scale_factor: kMillisecondScale, result: &deadline);
2577 thread_call_enter_delayed(call: extraSleepTimer, deadline);
2578 idleSleepTimerPending = true;
2579 } else {
2580 thread_call_enter(call: extraSleepTimer);
2581 }
2582 DLOG("idle timer set for %u milliseconds\n", inMilliSeconds);
2583}
2584
2585//******************************************************************************
2586// cancelIdleSleepTimer
2587//
2588//******************************************************************************
2589
2590void
2591IOPMrootDomain::cancelIdleSleepTimer( void )
2592{
2593 ASSERT_GATED();
2594 if (idleSleepTimerPending) {
2595 DLOG("idle timer cancelled\n");
2596 thread_call_cancel(call: extraSleepTimer);
2597 idleSleepTimerPending = false;
2598
2599 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
2600 AbsoluteTime now;
2601 clock_usec_t microsecs;
2602 clock_get_uptime(result: &now);
2603 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2604 absolutetime_to_microtime(abstime: now, secs: &assertOnWakeSecs, microsecs: &microsecs);
2605 if (assertOnWakeReport) {
2606 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2607 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2608 }
2609 }
2610 }
2611}
2612
2613//******************************************************************************
2614// idleSleepTimerExpired
2615//
2616//******************************************************************************
2617
2618static void
2619idleSleepTimerExpired(
2620 thread_call_param_t us, thread_call_param_t )
2621{
2622 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
2623}
2624
2625//******************************************************************************
2626// handleSleepTimerExpiration
2627//
2628// The time between the sleep idle timeout and the next longest one has elapsed.
2629// It's time to sleep. Start that by removing the clamp that's holding us awake.
2630//******************************************************************************
2631
2632void
2633IOPMrootDomain::handleSleepTimerExpiration( void )
2634{
2635 if (!gIOPMWorkLoop->inGate()) {
2636 gIOPMWorkLoop->runAction(
2637 OSMemberFunctionCast(IOWorkLoop::Action, this,
2638 &IOPMrootDomain::handleSleepTimerExpiration),
2639 target: this);
2640 return;
2641 }
2642
2643 DLOG("sleep timer expired\n");
2644 ASSERT_GATED();
2645
2646 idleSleepTimerPending = false;
2647 setQuickSpinDownTimeout();
2648 adjustPowerState(sleepASAP: true);
2649}
2650
2651//******************************************************************************
2652// getTimeToIdleSleep
2653//
2654// Returns number of milliseconds left before going into idle sleep.
2655// Caller has to make sure that idle sleep is allowed at the time of calling
2656// this function
2657//******************************************************************************
2658
2659uint32_t
2660IOPMrootDomain::getTimeToIdleSleep( void )
2661{
2662 AbsoluteTime now, lastActivityTime;
2663 uint64_t nanos;
2664 uint32_t minutesSinceUserInactive = 0;
2665 uint32_t sleepDelay = 0;
2666
2667 if (!idleSleepEnabled) {
2668 return 0xffffffff;
2669 }
2670
2671 if (userActivityTime) {
2672 lastActivityTime = userActivityTime;
2673 } else {
2674 lastActivityTime = userBecameInactiveTime;
2675 }
2676
2677 // Ignore any lastActivityTime that predates the last system wake.
2678 // The goal is to avoid a sudden idle sleep right after a dark wake
2679 // due to sleepDelay=0 computed below. The alternative 60s minimum
2680 // timeout should be large enough to allow dark wake to complete,
2681 // at which point the idle timer will be promptly cancelled.
2682 clock_get_uptime(result: &now);
2683 if ((CMP_ABSOLUTETIME(&lastActivityTime, &gIOLastWakeAbsTime) >= 0) &&
2684 (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)) {
2685 SUB_ABSOLUTETIME(&now, &lastActivityTime);
2686 absolutetime_to_nanoseconds(abstime: now, result: &nanos);
2687 minutesSinceUserInactive = nanos / (60000000000ULL);
2688
2689 if (minutesSinceUserInactive >= sleepSlider) {
2690 sleepDelay = 0;
2691 } else {
2692 sleepDelay = sleepSlider - minutesSinceUserInactive;
2693 }
2694 } else {
2695 DLOG("ignoring lastActivityTime 0x%qx, now 0x%qx, wake 0x%qx\n",
2696 lastActivityTime, now, gIOLastWakeAbsTime);
2697 sleepDelay = sleepSlider;
2698 }
2699
2700 DLOG("user inactive %u min, time to idle sleep %u min\n",
2701 minutesSinceUserInactive, sleepDelay);
2702
2703 return sleepDelay * 60 * 1000;
2704}
2705
2706//******************************************************************************
2707// setQuickSpinDownTimeout
2708//
2709//******************************************************************************
2710
2711void
2712IOPMrootDomain::setQuickSpinDownTimeout( void )
2713{
2714 ASSERT_GATED();
2715 setAggressiveness(
2716 type: kPMMinutesToSpinDown, value: 0, options: kAggressivesOptionQuickSpindownEnable );
2717}
2718
2719//******************************************************************************
2720// restoreUserSpinDownTimeout
2721//
2722//******************************************************************************
2723
2724void
2725IOPMrootDomain::restoreUserSpinDownTimeout( void )
2726{
2727 ASSERT_GATED();
2728 setAggressiveness(
2729 type: kPMMinutesToSpinDown, value: 0, options: kAggressivesOptionQuickSpindownDisable );
2730}
2731
2732//******************************************************************************
2733// sleepSystem
2734//
2735//******************************************************************************
2736
2737/* public */
2738IOReturn
2739IOPMrootDomain::sleepSystem( void )
2740{
2741 return sleepSystemOptions(NULL);
2742}
2743
2744/* private */
2745IOReturn
2746IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2747{
2748 OSObject *obj = NULL;
2749 OSString *reason = NULL;
2750 /* sleepSystem is a public function, and may be called by any kernel driver.
2751 * And that's bad - drivers should sleep the system by calling
2752 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2753 *
2754 * Note that user space app calls to IOPMSleepSystem() will also travel
2755 * this code path and thus be correctly identified as software sleeps.
2756 */
2757
2758 if (options && options->getObject(aKey: "OSSwitch")) {
2759 // Log specific sleep cause for OS Switch hibernation
2760 return privateSleepSystem( sleepReason: kIOPMSleepReasonOSSwitchHibernate);
2761 }
2762
2763 if (options && (obj = options->getObject(aKey: "Sleep Reason"))) {
2764 reason = OSDynamicCast(OSString, obj);
2765 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey)) {
2766 return privateSleepSystem(sleepReason: kIOPMSleepReasonDarkWakeThermalEmergency);
2767 }
2768 if (reason && reason->isEqualTo(kIOPMNotificationWakeExitKey)) {
2769 return privateSleepSystem(sleepReason: kIOPMSleepReasonNotificationWakeExit);
2770 }
2771 }
2772
2773 return privateSleepSystem( sleepReason: kIOPMSleepReasonSoftware);
2774}
2775
2776/* private */
2777IOReturn
2778IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2779{
2780 /* Called from both gated and non-gated context */
2781
2782 if (!checkSystemSleepEnabled() || !pmPowerStateQueue) {
2783 return kIOReturnNotPermitted;
2784 }
2785
2786 pmPowerStateQueue->submitPowerEvent(
2787 eventType: kPowerEventPolicyStimulus,
2788 arg0: (void *) kStimulusDemandSystemSleep,
2789 arg1: sleepReason);
2790
2791 return kIOReturnSuccess;
2792}
2793
2794//******************************************************************************
2795// powerChangeDone
2796//
2797// This overrides powerChangeDone in IOService.
2798//******************************************************************************
2799void
2800IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
2801{
2802#if !__i386__ && !__x86_64__
2803 uint64_t timeSinceReset = 0;
2804#endif
2805 uint64_t now;
2806 unsigned long newState;
2807 clock_sec_t secs;
2808 clock_usec_t microsecs;
2809 uint32_t lastDebugWakeSeconds;
2810 clock_sec_t adjWakeTime;
2811 IOPMCalendarStruct nowCalendar;
2812
2813 ASSERT_GATED();
2814 newState = getPowerState();
2815 DLOG("PowerChangeDone: %s->%s\n",
2816 getPowerStateString((uint32_t) previousPowerState), getPowerStateString((uint32_t) getPowerState()));
2817
2818 if (previousPowerState == newState) {
2819 return;
2820 }
2821
2822 notifierThread = current_thread();
2823 switch (getPowerState()) {
2824 case SLEEP_STATE: {
2825 if (kPMCalendarTypeInvalid != _aotWakeTimeCalendar.selector) {
2826 secs = 0;
2827 microsecs = 0;
2828 PEGetUTCTimeOfDay(secs: &secs, usecs: &microsecs);
2829
2830 adjWakeTime = 0;
2831 if ((kIOPMAOTModeRespectTimers & _aotMode) && (_calendarWakeAlarmUTC < _aotWakeTimeUTC)) {
2832 IOLog(format: "use _calendarWakeAlarmUTC\n");
2833 adjWakeTime = _calendarWakeAlarmUTC;
2834 } else if (kIOPMWakeEventAOTExitFlags & _aotPendingFlags) {
2835 IOLog(format: "accelerate _aotWakeTime for exit\n");
2836 adjWakeTime = secs;
2837 } else if (kIOPMDriverAssertionLevelOn == getPMAssertionLevel(whichAssertionBits: kIOPMDriverAssertionCPUBit)) {
2838 IOLog(format: "accelerate _aotWakeTime for assertion\n");
2839 adjWakeTime = secs;
2840 }
2841 if (adjWakeTime) {
2842 IOPMConvertSecondsToCalendar(secs: adjWakeTime, dt: &_aotWakeTimeCalendar);
2843 }
2844
2845 IOPMConvertSecondsToCalendar(secs, dt: &nowCalendar);
2846 IOLog(format: "aotSleep at " YMDTF " sched: " YMDTF "\n", YMDT(&nowCalendar), YMDT(&_aotWakeTimeCalendar));
2847
2848 IOReturn __unused ret = setMaintenanceWakeCalendar(&_aotWakeTimeCalendar);
2849 assert(kIOReturnSuccess == ret);
2850 }
2851 if (_aotLastWakeTime) {
2852 _aotMetrics->totalTime += mach_absolute_time() - _aotLastWakeTime;
2853 if (_aotMetrics->sleepCount && (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax)) {
2854 strlcpy(dst: &_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount - 1][0],
2855 src: gWakeReasonString,
2856 n: sizeof(_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount]));
2857 }
2858 }
2859 _aotPendingFlags &= ~kIOPMWakeEventAOTPerCycleFlags;
2860 if (_aotTimerScheduled) {
2861 _aotTimerES->cancelTimeout();
2862 _aotTimerScheduled = false;
2863 }
2864 acceptSystemWakeEvents(control: kAcceptSystemWakeEvents_Enable);
2865
2866 // re-enable this timer for next sleep
2867 cancelIdleSleepTimer();
2868
2869 if (clamshellExists) {
2870#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
2871 if (gClamshellFlags & kClamshell_WAR_58009435) {
2872 // Disable clamshell sleep until system has completed full wake.
2873 // This prevents a system sleep request (due to a clamshell close)
2874 // from being queued until the end of system full wake - even if
2875 // other clamshell disable bits outside of our control is wrong.
2876 setClamShellSleepDisable(true, kClamshellSleepDisableInternal);
2877 }
2878#endif
2879
2880 // Log the last known clamshell state before system sleep
2881 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
2882 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask,
2883 desktopMode, acAdaptorConnected);
2884 }
2885
2886 clock_get_calendar_absolute_and_microtime(secs: &secs, microsecs: &microsecs, abstime: &now);
2887 logtime(secs);
2888 gIOLastSleepTime.tv_sec = secs;
2889 gIOLastSleepTime.tv_usec = microsecs;
2890 if (!_aotLastWakeTime) {
2891 gIOLastUserSleepTime = gIOLastSleepTime;
2892 }
2893
2894 gIOLastWakeTime.tv_sec = 0;
2895 gIOLastWakeTime.tv_usec = 0;
2896 gIOLastSleepAbsTime = now;
2897
2898 if (wake2DarkwakeDelay && sleepDelaysReport) {
2899 clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
2900 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2901
2902 SUB_ABSOLUTETIME(&now, &ts_sleepStart);
2903 absolutetime_to_microtime(abstime: now, secs: &darkwake2SleepSecs, microsecs: &microsecs);
2904 absolutetime_to_microtime(abstime: wake2DarkwakeDelay, secs: &wake2DarkwakeSecs, microsecs: &microsecs);
2905 HISTREPORT_TALLYVALUE(sleepDelaysReport,
2906 (int64_t)(wake2DarkwakeSecs + darkwake2SleepSecs));
2907
2908 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
2909 wake2DarkwakeDelay = 0;
2910 }
2911#if HIBERNATION
2912 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2913#if (DEVELOPMENT || DEBUG)
2914 record_system_event(SYSTEM_EVENT_TYPE_INFO,
2915 SYSTEM_EVENT_SUBSYSTEM_PMRD,
2916 "System State",
2917 gIOHibernateState ? "Enter Hibernate" : "Enter Sleep"
2918 );
2919#endif /* DEVELOPMENT || DEBUG */
2920 IOHibernateSystemHasSlept();
2921
2922 evaluateSystemSleepPolicyFinal();
2923#else
2924 LOG("System Sleep\n");
2925#if (DEVELOPMENT || DEBUG)
2926 record_system_event(SYSTEM_EVENT_TYPE_INFO,
2927 SYSTEM_EVENT_SUBSYSTEM_PMRD,
2928 "System State", "Enter Sleep");
2929#endif /* DEVELOPMENT || DEBUG */
2930#endif
2931 if (thermalWarningState) {
2932 OSSharedPtr<const OSSymbol> event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
2933 if (event) {
2934 systemPowerEventOccurred(event: event.get(), intValue: kIOPMThermalLevelUnknown);
2935 }
2936 }
2937 assertOnWakeSecs = 0;
2938 lowBatteryCondition = false;
2939 thermalEmergencyState = false;
2940
2941#if DEVELOPMENT || DEBUG
2942 extern int g_should_log_clock_adjustments;
2943 if (g_should_log_clock_adjustments) {
2944 clock_sec_t secs = 0;
2945 clock_usec_t microsecs = 0;
2946 uint64_t now_b = mach_absolute_time();
2947
2948 secs = 0;
2949 microsecs = 0;
2950 PEGetUTCTimeOfDay(&secs, &microsecs);
2951
2952 uint64_t now_a = mach_absolute_time();
2953 os_log(OS_LOG_DEFAULT, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2954 __func__, (unsigned long)secs, microsecs, now_b, now_a);
2955 }
2956#endif
2957
2958 getPlatform()->sleepKernel();
2959
2960 // The CPU(s) are off at this point,
2961 // Code will resume execution here upon wake.
2962
2963 clock_get_uptime(result: &gIOLastWakeAbsTime);
2964 IOLog(format: "gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
2965#if DEVELOPMENT || DEBUG
2966 record_system_event(SYSTEM_EVENT_TYPE_INFO,
2967 SYSTEM_EVENT_SUBSYSTEM_PMRD,
2968 "System State", "Waking Up"
2969 );
2970#endif /* DEVELOPMENT || DEBUG */
2971 _highestCapability = 0;
2972
2973#if HIBERNATION
2974 IOHibernateSystemWake();
2975#endif
2976
2977 // sleep transition complete
2978 gSleepOrShutdownPending = 0;
2979
2980 // trip the reset of the calendar clock
2981 clock_wakeup_calendar();
2982 clock_get_calendar_microtime(secs: &secs, microsecs: &microsecs);
2983 gIOLastWakeTime.tv_sec = secs;
2984 gIOLastWakeTime.tv_usec = microsecs;
2985
2986 // aot
2987 if (_aotWakeTimeCalendar.selector != kPMCalendarTypeInvalid) {
2988 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
2989 secs = 0;
2990 microsecs = 0;
2991 PEGetUTCTimeOfDay(secs: &secs, usecs: &microsecs);
2992 IOPMConvertSecondsToCalendar(secs, dt: &nowCalendar);
2993 IOLog(format: "aotWake at " YMDTF " sched: " YMDTF "\n", YMDT(&nowCalendar), YMDT(&_aotWakeTimeCalendar));
2994 _aotMetrics->sleepCount++;
2995 _aotLastWakeTime = gIOLastWakeAbsTime;
2996 if (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax) {
2997 _aotMetrics->kernelSleepTime[_aotMetrics->sleepCount - 1]
2998 = (((uint64_t) gIOLastSleepTime.tv_sec) << 10) + (gIOLastSleepTime.tv_usec / 1000);
2999 _aotMetrics->kernelWakeTime[_aotMetrics->sleepCount - 1]
3000 = (((uint64_t) gIOLastWakeTime.tv_sec) << 10) + (gIOLastWakeTime.tv_usec / 1000);
3001 }
3002
3003 if (_aotTestTime) {
3004 if (_aotWakeTimeUTC <= secs) {
3005 _aotTestTime = _aotTestTime + _aotTestInterval;
3006 }
3007 setWakeTime(_aotTestTime);
3008 }
3009 }
3010
3011#if HIBERNATION
3012 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
3013#endif
3014
3015 lastSleepReason = 0;
3016
3017 lastDebugWakeSeconds = _debugWakeSeconds;
3018 _debugWakeSeconds = 0;
3019 _scheduledAlarmMask = 0;
3020 _nextScheduledAlarmType = NULL;
3021
3022 darkWakeExit = false;
3023 darkWakePowerClamped = false;
3024 darkWakePostTickle = false;
3025 darkWakeHibernateError = false;
3026 darkWakeToSleepASAP = true;
3027 darkWakeLogClamp = true;
3028 sleepTimerMaintenance = false;
3029 sleepToStandby = false;
3030 wranglerTickled = false;
3031 userWasActive = false;
3032 isRTCAlarmWake = false;
3033 clamshellIgnoreClose = false;
3034 fullWakeReason = kFullWakeReasonNone;
3035
3036#if defined(__i386__) || defined(__x86_64__)
3037 kdebugTrace(kPMLogSystemWake, 0, 0, 0);
3038
3039 OSSharedPtr<OSObject> wakeTypeProp = copyProperty(kIOPMRootDomainWakeTypeKey);
3040 OSSharedPtr<OSObject> wakeReasonProp = copyProperty(kIOPMRootDomainWakeReasonKey);
3041 OSString * wakeType = OSDynamicCast(OSString, wakeTypeProp.get());
3042 OSString * wakeReason = OSDynamicCast(OSString, wakeReasonProp.get());
3043
3044 if (wakeReason && (wakeReason->getLength() >= 2) &&
3045 gWakeReasonString[0] == '\0') {
3046 WAKEEVENT_LOCK();
3047 // Until the platform driver can claim its wake reasons
3048 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
3049 sizeof(gWakeReasonString));
3050 if (!gWakeReasonSysctlRegistered) {
3051 gWakeReasonSysctlRegistered = true;
3052 }
3053 WAKEEVENT_UNLOCK();
3054 }
3055
3056 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery)) {
3057 lowBatteryCondition = true;
3058 darkWakeMaintenance = true;
3059 } else {
3060#if HIBERNATION
3061 OSSharedPtr<OSObject> hibOptionsProp = copyProperty(kIOHibernateOptionsKey);
3062 OSNumber * hibOptions = OSDynamicCast( OSNumber, hibOptionsProp.get());
3063 if (hibernateAborted || ((hibOptions &&
3064 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)))) {
3065 // Hibernate aborted, or EFI brought up graphics
3066 darkWakeExit = true;
3067 if (hibernateAborted) {
3068 DLOG("Hibernation aborted\n");
3069 } else {
3070 DLOG("EFI brought up graphics. Going to full wake. HibOptions: 0x%x\n", hibOptions->unsigned32BitValue());
3071 }
3072 } else
3073#endif
3074 if (wakeType && (
3075 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
3076 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))) {
3077 // User wake or RTC alarm
3078 darkWakeExit = true;
3079 if (wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)) {
3080 isRTCAlarmWake = true;
3081 }
3082 } else if (wakeType &&
3083 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer)) {
3084 // SMC standby timer trumps SleepX
3085 darkWakeMaintenance = true;
3086 sleepTimerMaintenance = true;
3087 } else if ((lastDebugWakeSeconds != 0) &&
3088 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) {
3089 // SleepX before maintenance
3090 darkWakeExit = true;
3091 } else if (wakeType &&
3092 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance)) {
3093 darkWakeMaintenance = true;
3094 } else if (wakeType &&
3095 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService)) {
3096 darkWakeMaintenance = true;
3097 darkWakeSleepService = true;
3098#if HIBERNATION
3099 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
3100 sleepToStandby = true;
3101 }
3102#endif
3103 } else if (wakeType &&
3104 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError)) {
3105 darkWakeMaintenance = true;
3106 darkWakeHibernateError = true;
3107 } else {
3108 // Unidentified wake source, resume to full wake if debug
3109 // alarm is pending.
3110
3111 if (lastDebugWakeSeconds &&
3112 (!wakeReason || wakeReason->isEqualTo(""))) {
3113 darkWakeExit = true;
3114 }
3115 }
3116 }
3117
3118 if (darkWakeExit) {
3119 darkWakeToSleepASAP = false;
3120 fullWakeReason = kFullWakeReasonLocalUser;
3121 reportUserInput();
3122 } else if (displayPowerOnRequested && checkSystemCanSustainFullWake()) {
3123 handleSetDisplayPowerOn(true);
3124 } else if (!darkWakeMaintenance) {
3125 // Early/late tickle for non-maintenance wake.
3126 if ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) != kDarkWakeFlagPromotionNone) {
3127 darkWakePostTickle = true;
3128 }
3129 }
3130#else /* !__i386__ && !__x86_64__ */
3131 timeSinceReset = ml_get_time_since_reset();
3132 kdebugTrace(event: kPMLogSystemWake, regId: 0, param1: (uintptr_t)(timeSinceReset >> 32), param2: (uintptr_t) timeSinceReset);
3133
3134 if ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) == kDarkWakeFlagPromotionEarly) {
3135 wranglerTickled = true;
3136 fullWakeReason = kFullWakeReasonLocalUser;
3137 requestUserActive(driver: this, reason: "Full wake on dark wake promotion boot-arg");
3138 } else if ((lastDebugWakeSeconds != 0) && !(gDarkWakeFlags & kDarkWakeFlagAlarmIsDark)) {
3139 isRTCAlarmWake = true;
3140 fullWakeReason = kFullWakeReasonLocalUser;
3141 requestUserActive(driver: this, reason: "RTC debug alarm");
3142 } else {
3143#if HIBERNATION
3144 OSSharedPtr<OSObject> hibOptionsProp = copyProperty(kIOHibernateOptionsKey);
3145 OSNumber * hibOptions = OSDynamicCast(OSNumber, hibOptionsProp.get());
3146 if (hibOptions && !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)) {
3147 fullWakeReason = kFullWakeReasonLocalUser;
3148 requestUserActive(this, "hibernate user wake");
3149 }
3150#endif
3151 }
3152
3153 // stay awake for at least 30 seconds
3154 startIdleSleepTimer(inMilliSeconds: 30 * 1000);
3155#endif
3156 sleepCnt++;
3157
3158 thread_call_enter(call: updateConsoleUsersEntry);
3159
3160 // Skip AOT_STATE if we are waking up from an RTC timer.
3161 // This check needs to be done after the epoch change is processed
3162 // and before the changePowerStateWithTagToPriv() call below.
3163 WAKEEVENT_LOCK();
3164 aotShouldExit(checkTimeSet: false, software: false);
3165 WAKEEVENT_UNLOCK();
3166
3167 changePowerStateWithTagToPriv(ordinal: getRUN_STATE(), tag: kCPSReasonWake);
3168 break;
3169 }
3170#if !__i386__ && !__x86_64__
3171 case ON_STATE:
3172 case AOT_STATE:
3173 {
3174 DLOG("Force re-evaluating aggressiveness\n");
3175 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
3176 pmPowerStateQueue->submitPowerEvent(
3177 eventType: kPowerEventPolicyStimulus,
3178 arg0: (void *) kStimulusNoIdleSleepPreventers );
3179
3180 // After changing to ON_STATE, invalidate any previously queued
3181 // request to change to a state less than ON_STATE. This isn't
3182 // necessary for AOT_STATE or if the device has only one running
3183 // state since the changePowerStateToPriv() issued at the tail
3184 // end of SLEEP_STATE case should take care of that.
3185 if (getPowerState() == ON_STATE) {
3186 changePowerStateWithTagToPriv(ordinal: ON_STATE, tag: kCPSReasonWake);
3187 }
3188 break;
3189 }
3190#endif /* !__i386__ && !__x86_64__ */
3191 }
3192 notifierThread = NULL;
3193}
3194
3195//******************************************************************************
3196// requestPowerDomainState
3197//
3198// Extend implementation in IOService. Running on PM work loop thread.
3199//******************************************************************************
3200
3201IOReturn
3202IOPMrootDomain::requestPowerDomainState(
3203 IOPMPowerFlags childDesire,
3204 IOPowerConnection * childConnection,
3205 unsigned long specification )
3206{
3207 // Idle and system sleep prevention flags affects driver desire.
3208 // Children desire are irrelevant so they are cleared.
3209
3210 return super::requestPowerDomainState(desiredState: 0, whichChild: childConnection, specificationFlags: specification);
3211}
3212
3213
3214static void
3215makeSleepPreventersListLog(const OSSharedPtr<OSSet> &preventers, char *buf, size_t buf_size)
3216{
3217 if (!preventers->getCount()) {
3218 return;
3219 }
3220
3221 char *buf_iter = buf + strlen(s: buf);
3222 char *buf_end = buf + buf_size;
3223
3224 OSSharedPtr<OSCollectionIterator> iterator = OSCollectionIterator::withCollection(inColl: preventers.get());
3225 OSObject *obj = NULL;
3226
3227 while ((obj = iterator->getNextObject())) {
3228 IOService *srv = OSDynamicCast(IOService, obj);
3229 if (buf_iter < buf_end) {
3230 buf_iter += snprintf(buf_iter, count: buf_end - buf_iter, " %s", srv->getName());
3231 } else {
3232 DLOG("Print buffer exhausted for sleep preventers list\n");
3233 break;
3234 }
3235 }
3236}
3237
3238//******************************************************************************
3239// updatePreventIdleSleepList
3240//
3241// Called by IOService on PM work loop.
3242// Returns true if PM policy recognized the driver's desire to prevent idle
3243// sleep and updated the list of idle sleep preventers. Returns false otherwise
3244//******************************************************************************
3245
3246bool
3247IOPMrootDomain::updatePreventIdleSleepList(
3248 IOService * service, bool addNotRemove)
3249{
3250 unsigned int oldCount;
3251
3252 oldCount = idleSleepPreventersCount();
3253 return updatePreventIdleSleepListInternal(service, addNotRemove, oldCount);
3254}
3255
3256bool
3257IOPMrootDomain::updatePreventIdleSleepListInternal(
3258 IOService * service, bool addNotRemove, unsigned int oldCount)
3259{
3260 unsigned int newCount;
3261
3262 ASSERT_GATED();
3263
3264#if defined(XNU_TARGET_OS_OSX)
3265 // Only the display wrangler and no-idle-sleep kernel assertions
3266 // can prevent idle sleep. The kIOPMPreventIdleSleep capability flag
3267 // reported by drivers in their power state table is ignored.
3268 if (service && (service != wrangler) && (service != this)) {
3269 return false;
3270 }
3271#endif
3272
3273 if (service) {
3274 if (addNotRemove) {
3275 preventIdleSleepList->setObject(service);
3276 DLOG("Added %s to idle sleep preventers list (Total %u)\n",
3277 service->getName(), preventIdleSleepList->getCount());
3278 } else if (preventIdleSleepList->member(anObject: service)) {
3279 preventIdleSleepList->removeObject(anObject: service);
3280 DLOG("Removed %s from idle sleep preventers list (Total %u)\n",
3281 service->getName(), preventIdleSleepList->getCount());
3282 }
3283
3284 if (preventIdleSleepList->getCount()) {
3285 char buf[256] = "Idle Sleep Preventers:";
3286 makeSleepPreventersListLog(preventers: preventIdleSleepList, buf, buf_size: sizeof(buf));
3287 DLOG("%s\n", buf);
3288 }
3289 }
3290
3291 newCount = idleSleepPreventersCount();
3292
3293 if ((oldCount == 0) && (newCount != 0)) {
3294 // Driver added to empty prevent list.
3295 // Update the driver desire to prevent idle sleep.
3296 // Driver desire does not prevent demand sleep.
3297
3298 changePowerStateWithTagTo(ordinal: getRUN_STATE(), tag: kCPSReasonIdleSleepPrevent);
3299 } else if ((oldCount != 0) && (newCount == 0)) {
3300 // Last driver removed from prevent list.
3301 // Drop the driver clamp to allow idle sleep.
3302
3303 changePowerStateWithTagTo(ordinal: SLEEP_STATE, tag: kCPSReasonIdleSleepAllow);
3304 evaluatePolicy( stimulus: kStimulusNoIdleSleepPreventers );
3305 }
3306 messageClient(kIOPMMessageIdleSleepPreventers, client: systemCapabilityNotifier.get(),
3307 messageArgument: &newCount, argSize: sizeof(newCount));
3308
3309#if defined(XNU_TARGET_OS_OSX)
3310 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake()) {
3311 DLOG("Cannot cancel idle sleep\n");
3312 return false; // do not idle-cancel
3313 }
3314#endif
3315
3316 return true;
3317}
3318
3319//******************************************************************************
3320// startSpinDump
3321//******************************************************************************
3322
3323void
3324IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
3325{
3326 messageClients(kIOPMMessageLaunchBootSpinDump, argument: (void *)(uintptr_t)spindumpKind);
3327}
3328
3329//******************************************************************************
3330// preventSystemSleepListUpdate
3331//
3332// Called by IOService on PM work loop.
3333//******************************************************************************
3334
3335void
3336IOPMrootDomain::updatePreventSystemSleepList(
3337 IOService * service, bool addNotRemove )
3338{
3339 unsigned int oldCount, newCount;
3340
3341 ASSERT_GATED();
3342 if (this == service) {
3343 return;
3344 }
3345
3346 oldCount = preventSystemSleepList->getCount();
3347 if (addNotRemove) {
3348 preventSystemSleepList->setObject(service);
3349 DLOG("Added %s to system sleep preventers list (Total %u)\n",
3350 service->getName(), preventSystemSleepList->getCount());
3351 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3352 AbsoluteTime now;
3353 clock_usec_t microsecs;
3354 clock_get_uptime(result: &now);
3355 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3356 absolutetime_to_microtime(abstime: now, secs: &assertOnWakeSecs, microsecs: &microsecs);
3357 if (assertOnWakeReport) {
3358 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
3359 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
3360 }
3361 }
3362 } else if (preventSystemSleepList->member(anObject: service)) {
3363 preventSystemSleepList->removeObject(anObject: service);
3364 DLOG("Removed %s from system sleep preventers list (Total %u)\n",
3365 service->getName(), preventSystemSleepList->getCount());
3366
3367 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0)) {
3368 // Lost all system sleep preventers.
3369 // Send stimulus if system sleep was blocked, and is in dark wake.
3370 evaluatePolicy( stimulus: kStimulusDarkWakeEvaluate );
3371 }
3372 }
3373
3374 newCount = preventSystemSleepList->getCount();
3375 if (newCount) {
3376 char buf[256] = "System Sleep Preventers:";
3377 makeSleepPreventersListLog(preventers: preventSystemSleepList, buf, buf_size: sizeof(buf));
3378 DLOG("%s\n", buf);
3379 }
3380
3381 messageClient(kIOPMMessageSystemSleepPreventers, client: systemCapabilityNotifier.get(),
3382 messageArgument: &newCount, argSize: sizeof(newCount));
3383}
3384
3385void
3386IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
3387{
3388 OSSharedPtr<OSCollectionIterator> iterator;
3389 OSObject *object = NULL;
3390 OSSharedPtr<OSArray> array;
3391
3392 if (!gIOPMWorkLoop->inGate()) {
3393 gIOPMWorkLoop->runAction(
3394 OSMemberFunctionCast(IOWorkLoop::Action, this,
3395 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
3396 target: this, arg0: (void *)idleSleepList, arg1: (void *)systemSleepList);
3397 return;
3398 }
3399
3400 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0)) {
3401 iterator = OSCollectionIterator::withCollection(inColl: preventIdleSleepList.get());
3402 array = OSArray::withCapacity(capacity: 5);
3403
3404 if (iterator && array) {
3405 while ((object = iterator->getNextObject())) {
3406 IOService *service = OSDynamicCast(IOService, object);
3407 if (service) {
3408 OSSharedPtr<const OSSymbol> name = service->copyName();
3409 if (name) {
3410 array->setObject(name.get());
3411 }
3412 }
3413 }
3414 }
3415 *idleSleepList = array.detach();
3416 }
3417
3418 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0)) {
3419 iterator = OSCollectionIterator::withCollection(inColl: preventSystemSleepList.get());
3420 array = OSArray::withCapacity(capacity: 5);
3421
3422 if (iterator && array) {
3423 while ((object = iterator->getNextObject())) {
3424 IOService *service = OSDynamicCast(IOService, object);
3425 if (service) {
3426 OSSharedPtr<const OSSymbol> name = service->copyName();
3427 if (name) {
3428 array->setObject(name.get());
3429 }
3430 }
3431 }
3432 }
3433 *systemSleepList = array.detach();
3434 }
3435}
3436
3437void
3438IOPMrootDomain::copySleepPreventersListWithID(OSArray **idleSleepList, OSArray **systemSleepList)
3439{
3440 OSSharedPtr<OSCollectionIterator> iterator;
3441 OSObject *object = NULL;
3442 OSSharedPtr<OSArray> array;
3443
3444 if (!gIOPMWorkLoop->inGate()) {
3445 gIOPMWorkLoop->runAction(
3446 OSMemberFunctionCast(IOWorkLoop::Action, this,
3447 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersListWithID),
3448 target: this, arg0: (void *)idleSleepList, arg1: (void *)systemSleepList);
3449 return;
3450 }
3451
3452 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0)) {
3453 iterator = OSCollectionIterator::withCollection(inColl: preventIdleSleepList.get());
3454 array = OSArray::withCapacity(capacity: 5);
3455
3456 if (iterator && array) {
3457 while ((object = iterator->getNextObject())) {
3458 IOService *service = OSDynamicCast(IOService, object);
3459 if (service) {
3460 OSSharedPtr<OSDictionary> dict = OSDictionary::withCapacity(capacity: 2);
3461 OSSharedPtr<const OSSymbol> name = service->copyName();
3462 OSSharedPtr<OSNumber> id = OSNumber::withNumber(value: service->getRegistryEntryID(), numberOfBits: 64);
3463 if (dict && name && id) {
3464 dict->setObject(kIOPMDriverAssertionRegistryEntryIDKey, anObject: id.get());
3465 dict->setObject(kIOPMDriverAssertionOwnerStringKey, anObject: name.get());
3466 array->setObject(dict.get());
3467 }
3468 }
3469 }
3470 }
3471 *idleSleepList = array.detach();
3472 }
3473
3474 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0)) {
3475 iterator = OSCollectionIterator::withCollection(inColl: preventSystemSleepList.get());
3476 array = OSArray::withCapacity(capacity: 5);
3477
3478 if (iterator && array) {
3479 while ((object = iterator->getNextObject())) {
3480 IOService *service = OSDynamicCast(IOService, object);
3481 if (service) {
3482 OSSharedPtr<OSDictionary> dict = OSDictionary::withCapacity(capacity: 2);
3483 OSSharedPtr<const OSSymbol> name = service->copyName();
3484 OSSharedPtr<OSNumber> id = OSNumber::withNumber(value: service->getRegistryEntryID(), numberOfBits: 64);
3485 if (dict && name && id) {
3486 dict->setObject(kIOPMDriverAssertionRegistryEntryIDKey, anObject: id.get());
3487 dict->setObject(kIOPMDriverAssertionOwnerStringKey, anObject: name.get());
3488 array->setObject(dict.get());
3489 }
3490 }
3491 }
3492 }
3493 *systemSleepList = array.detach();
3494 }
3495}
3496
3497//******************************************************************************
3498// tellChangeDown
3499//
3500// Override the superclass implementation to send a different message type.
3501//******************************************************************************
3502
3503bool
3504IOPMrootDomain::tellChangeDown( unsigned long stateNum )
3505{
3506 DLOG("tellChangeDown %s->%s\n",
3507 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3508
3509 if (SLEEP_STATE == stateNum) {
3510 // Legacy apps were already told in the full->dark transition
3511 if (!ignoreTellChangeDown) {
3512 tracePoint( point: kIOPMTracePointSleepApplications );
3513 } else {
3514 tracePoint( point: kIOPMTracePointSleepPriorityClients );
3515 }
3516 }
3517
3518 if (!ignoreTellChangeDown) {
3519 userActivityAtSleep = userActivityCount;
3520 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
3521
3522 if (SLEEP_STATE == stateNum) {
3523 hibernateAborted = false;
3524
3525 // Direct callout into OSKext so it can disable kext unloads
3526 // during sleep/wake to prevent deadlocks.
3527 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
3528
3529 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
3530
3531 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3532 // But tellClientsWithResponse() must be called for both.
3533 ignoreTellChangeDown = true;
3534 }
3535 }
3536
3537 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
3538}
3539
3540//******************************************************************************
3541// askChangeDown
3542//
3543// Override the superclass implementation to send a different message type.
3544// This must be idle sleep since we don't ask during any other power change.
3545//******************************************************************************
3546
3547bool
3548IOPMrootDomain::askChangeDown( unsigned long stateNum )
3549{
3550 DLOG("askChangeDown %s->%s\n",
3551 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3552
3553 // Don't log for dark wake entry
3554 if (kSystemTransitionSleep == _systemTransitionType) {
3555 tracePoint( point: kIOPMTracePointSleepApplications );
3556 }
3557
3558 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
3559}
3560
3561//******************************************************************************
3562// askChangeDownDone
3563//
3564// An opportunity for root domain to cancel the power transition,
3565// possibily due to an assertion created by powerd in response to
3566// kIOMessageCanSystemSleep.
3567//
3568// Idle sleep:
3569// full -> dark wake transition
3570// 1. Notify apps and powerd with kIOMessageCanSystemSleep
3571// 2. askChangeDownDone()
3572// dark -> sleep transition
3573// 1. Notify powerd with kIOMessageCanSystemSleep
3574// 2. askChangeDownDone()
3575//
3576// Demand sleep:
3577// full -> dark wake transition
3578// 1. Notify powerd with kIOMessageCanSystemSleep
3579// 2. askChangeDownDone()
3580// dark -> sleep transition
3581// 1. Notify powerd with kIOMessageCanSystemSleep
3582// 2. askChangeDownDone()
3583//******************************************************************************
3584
3585void
3586IOPMrootDomain::askChangeDownDone(
3587 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
3588{
3589 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
3590 *inOutChangeFlags, *cancel,
3591 _systemTransitionType,
3592 _currentCapability, _pendingCapability);
3593
3594 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType)) {
3595 // Dark->Sleep transition.
3596 // Check if there are any deny sleep assertions.
3597 // lastSleepReason already set by handleOurPowerChangeStart()
3598
3599 if (!checkSystemCanSleep(sleepReason: lastSleepReason)) {
3600 // Cancel dark wake to sleep transition.
3601 // Must re-scan assertions upon entering dark wake.
3602
3603 *cancel = true;
3604 DLOG("cancel dark->sleep\n");
3605 }
3606 if (_aotMode && (kPMCalendarTypeInvalid != _aotWakeTimeCalendar.selector)) {
3607 uint64_t now = mach_continuous_time();
3608 if (((now + _aotWakePreWindow) >= _aotWakeTimeContinuous)
3609 && (now < (_aotWakeTimeContinuous + _aotWakePostWindow))) {
3610 *cancel = true;
3611 IOLog(format: "AOT wake window cancel: %qd, %qd\n", now, _aotWakeTimeContinuous);
3612 }
3613 }
3614 }
3615}
3616
3617//******************************************************************************
3618// systemDidNotSleep
3619//
3620// Work common to both canceled or aborted sleep.
3621//******************************************************************************
3622
3623void
3624IOPMrootDomain::systemDidNotSleep( void )
3625{
3626 // reset console lock state
3627 thread_call_enter(call: updateConsoleUsersEntry);
3628
3629 if (idleSleepEnabled) {
3630 if (!wrangler) {
3631#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
3632 startIdleSleepTimer(kIdleSleepRetryInterval);
3633#else
3634 startIdleSleepTimer(idleMilliSeconds);
3635#endif
3636 } else if (!userIsActive) {
3637 // Manually start the idle sleep timer besides waiting for
3638 // the user to become inactive.
3639 startIdleSleepTimer(kIdleSleepRetryInterval);
3640 }
3641 }
3642
3643 preventTransitionToUserActive(prevent: false);
3644 IOService::setAdvisoryTickleEnable( true );
3645
3646 // After idle revert and cancel, send a did-change message to powerd
3647 // to balance the previous will-change message. Kernel clients do not
3648 // need this since sleep cannot be canceled once they are notified.
3649
3650 if (toldPowerdCapWillChange && systemCapabilityNotifier &&
3651 (_pendingCapability != _currentCapability) &&
3652 ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0)) {
3653 // Differs from a real capability gain change where notifyRef != 0,
3654 // but it is zero here since no response is expected.
3655
3656 IOPMSystemCapabilityChangeParameters params;
3657
3658 bzero(s: &params, n: sizeof(params));
3659 params.fromCapabilities = _pendingCapability;
3660 params.toCapabilities = _currentCapability;
3661 params.changeFlags = kIOPMSystemCapabilityDidChange;
3662
3663 DLOG("MESG cap %x->%x did change\n",
3664 params.fromCapabilities, params.toCapabilities);
3665 messageClient(kIOMessageSystemCapabilityChange, client: systemCapabilityNotifier.get(),
3666 messageArgument: &params, argSize: sizeof(params));
3667 }
3668}
3669
3670//******************************************************************************
3671// tellNoChangeDown
3672//
3673// Notify registered applications and kernel clients that we are not dropping
3674// power.
3675//
3676// We override the superclass implementation so we can send a different message
3677// type to the client or application being notified.
3678//
3679// This must be a vetoed idle sleep, since no other power change can be vetoed.
3680//******************************************************************************
3681
3682void
3683IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
3684{
3685 DLOG("tellNoChangeDown %s->%s\n",
3686 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3687
3688 // Sleep canceled, clear the sleep trace point.
3689 tracePoint(point: kIOPMTracePointSystemUp);
3690
3691 systemDidNotSleep();
3692 return tellClients( kIOMessageSystemWillNotSleep );
3693}
3694
3695//******************************************************************************
3696// tellChangeUp
3697//
3698// Notify registered applications and kernel clients that we are raising power.
3699//
3700// We override the superclass implementation so we can send a different message
3701// type to the client or application being notified.
3702//******************************************************************************
3703
3704void
3705IOPMrootDomain::tellChangeUp( unsigned long stateNum )
3706{
3707 DLOG("tellChangeUp %s->%s\n",
3708 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3709
3710 ignoreTellChangeDown = false;
3711
3712 if (stateNum == ON_STATE) {
3713 // Direct callout into OSKext so it can disable kext unloads
3714 // during sleep/wake to prevent deadlocks.
3715 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
3716
3717 // Notify platform that sleep was cancelled or resumed.
3718 getPlatform()->callPlatformFunction(
3719 functionName: sleepMessagePEFunction.get(), waitForFunction: false,
3720 param1: (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
3721 NULL, NULL, NULL);
3722
3723 if (getPowerState() == ON_STATE) {
3724 // Sleep was cancelled by idle cancel or revert
3725 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
3726 // rdar://problem/50363791
3727 // If system is in dark wake and sleep is cancelled, do not
3728 // send SystemWillPowerOn/HasPoweredOn messages to kernel
3729 // priority clients. They haven't yet seen a SystemWillSleep
3730 // message before the cancellation. So make sure the kernel
3731 // client bit is cleared in _systemMessageClientMask before
3732 // invoking the tellClients() below. This bit may have been
3733 // set by handleOurPowerChangeStart() anticipating a successful
3734 // sleep and setting the filter mask ahead of time allows the
3735 // SystemWillSleep message to go through.
3736 _systemMessageClientMask &= ~kSystemMessageClientKernel;
3737 }
3738
3739 systemDidNotSleep();
3740 tellClients( kIOMessageSystemWillPowerOn );
3741 }
3742
3743 tracePoint( point: kIOPMTracePointWakeApplications );
3744 tellClients( kIOMessageSystemHasPoweredOn );
3745 } else if (stateNum == AOT_STATE) {
3746 if (getPowerState() == AOT_STATE) {
3747 // Sleep was cancelled by idle cancel or revert
3748 startIdleSleepTimer(inMilliSeconds: idleMilliSeconds);
3749 }
3750 }
3751}
3752
3753#define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3754 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3755 ((params)->fromCapabilities & (flag)) && \
3756 (((params)->toCapabilities & (flag)) == 0))
3757
3758#define CAP_DID_CHANGE_TO_ON(params, flag) \
3759 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3760 ((params)->toCapabilities & (flag)) && \
3761 (((params)->fromCapabilities & (flag)) == 0))
3762
3763#define CAP_DID_CHANGE_TO_OFF(params, flag) \
3764 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3765 ((params)->fromCapabilities & (flag)) && \
3766 (((params)->toCapabilities & (flag)) == 0))
3767
3768#define CAP_WILL_CHANGE_TO_ON(params, flag) \
3769 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3770 ((params)->toCapabilities & (flag)) && \
3771 (((params)->fromCapabilities & (flag)) == 0))
3772
3773//******************************************************************************
3774// sysPowerDownHandler
3775//
3776// Perform a vfs sync before system sleep.
3777//******************************************************************************
3778
3779IOReturn
3780IOPMrootDomain::sysPowerDownHandler(
3781 void * target, void * refCon,
3782 UInt32 messageType, IOService * service,
3783 void * messageArgs, vm_size_t argSize )
3784{
3785 static UInt32 lastSystemMessageType = 0;
3786 IOReturn ret = 0;
3787
3788 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
3789
3790 // rdar://problem/50363791
3791 // Sanity check to make sure the SystemWill/Has message types are
3792 // received in the expected order for all kernel priority clients.
3793 if (messageType == kIOMessageSystemWillSleep ||
3794 messageType == kIOMessageSystemWillPowerOn ||
3795 messageType == kIOMessageSystemHasPoweredOn) {
3796 switch (messageType) {
3797 case kIOMessageSystemWillPowerOn:
3798 assert(lastSystemMessageType == kIOMessageSystemWillSleep);
3799 break;
3800 case kIOMessageSystemHasPoweredOn:
3801 assert(lastSystemMessageType == kIOMessageSystemWillPowerOn);
3802 break;
3803 }
3804
3805 lastSystemMessageType = messageType;
3806 }
3807
3808 if (!gRootDomain) {
3809 return kIOReturnUnsupported;
3810 }
3811
3812 if (messageType == kIOMessageSystemCapabilityChange) {
3813 IOPMSystemCapabilityChangeParameters * params =
3814 (IOPMSystemCapabilityChangeParameters *) messageArgs;
3815
3816 // Interested applications have been notified of an impending power
3817 // change and have acked (when applicable).
3818 // This is our chance to save whatever state we can before powering
3819 // down.
3820 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3821 // via callout
3822
3823 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3824 params->fromCapabilities, params->toCapabilities,
3825 params->changeFlags);
3826
3827 if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU)) {
3828 // We will ack within 20 seconds
3829 params->maxWaitForReply = 20 * 1000 * 1000;
3830
3831#if HIBERNATION
3832 gRootDomain->evaluateSystemSleepPolicyEarly();
3833
3834 // add in time we could spend freeing pages
3835 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled) {
3836 params->maxWaitForReply = kCapabilityClientMaxWait;
3837 }
3838 DLOG("sysPowerDownHandler max wait %d s\n",
3839 (int) (params->maxWaitForReply / 1000 / 1000));
3840#endif
3841
3842 // Notify platform that sleep has begun, after the early
3843 // sleep policy evaluation.
3844 getPlatform()->callPlatformFunction(
3845 functionName: sleepMessagePEFunction.get(), waitForFunction: false,
3846 param1: (void *)(uintptr_t) kIOMessageSystemWillSleep,
3847 NULL, NULL, NULL);
3848
3849 if (!OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending )) {
3850 // Purposely delay the ack and hope that shutdown occurs quickly.
3851 // Another option is not to schedule the thread and wait for
3852 // ack timeout...
3853 AbsoluteTime deadline;
3854 clock_interval_to_deadline( interval: 30, scale_factor: kSecondScale, result: &deadline );
3855 thread_call_enter1_delayed(
3856 call: gRootDomain->diskSyncCalloutEntry,
3857 param1: (thread_call_param_t)(uintptr_t) params->notifyRef,
3858 deadline );
3859 } else {
3860 thread_call_enter1(
3861 call: gRootDomain->diskSyncCalloutEntry,
3862 param1: (thread_call_param_t)(uintptr_t) params->notifyRef);
3863 }
3864 }
3865#if HIBERNATION
3866 else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU)) {
3867 // We will ack within 110 seconds
3868 params->maxWaitForReply = 110 * 1000 * 1000;
3869
3870 thread_call_enter1(
3871 gRootDomain->diskSyncCalloutEntry,
3872 (thread_call_param_t)(uintptr_t) params->notifyRef);
3873 }
3874#endif
3875 ret = kIOReturnSuccess;
3876 }
3877
3878 return ret;
3879}
3880
3881//******************************************************************************
3882// handleQueueSleepWakeUUID
3883//
3884// Called from IOPMrootDomain when we're initiating a sleep,
3885// or indirectly from PM configd when PM decides to clear the UUID.
3886// PM clears the UUID several minutes after successful wake from sleep,
3887// so that we might associate App spindumps with the immediately previous
3888// sleep/wake.
3889//
3890// @param obj has a retain on it. We're responsible for releasing that retain.
3891//******************************************************************************
3892
3893void
3894IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
3895{
3896 OSSharedPtr<OSString> str;
3897
3898 if (kOSBooleanFalse == obj) {
3899 handlePublishSleepWakeUUID(shouldPublish: false);
3900 } else {
3901 str.reset(OSDynamicCast(OSString, obj), OSNoRetain);
3902 if (str) {
3903 // This branch caches the UUID for an upcoming sleep/wake
3904 queuedSleepWakeUUIDString = str;
3905 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
3906 }
3907 }
3908}
3909//******************************************************************************
3910// handlePublishSleepWakeUUID
3911//
3912// Called from IOPMrootDomain when we're initiating a sleep,
3913// or indirectly from PM configd when PM decides to clear the UUID.
3914// PM clears the UUID several minutes after successful wake from sleep,
3915// so that we might associate App spindumps with the immediately previous
3916// sleep/wake.
3917//******************************************************************************
3918
3919void
3920IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
3921{
3922 ASSERT_GATED();
3923
3924 /*
3925 * Clear the current UUID
3926 */
3927 if (gSleepWakeUUIDIsSet) {
3928 DLOG("SleepWake UUID cleared\n");
3929
3930 gSleepWakeUUIDIsSet = false;
3931
3932 removeProperty(kIOPMSleepWakeUUIDKey);
3933 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
3934 }
3935
3936 /*
3937 * Optionally, publish a new UUID
3938 */
3939 if (queuedSleepWakeUUIDString && shouldPublish) {
3940 OSSharedPtr<OSString> publishThisUUID;
3941
3942 publishThisUUID = queuedSleepWakeUUIDString;
3943
3944 if (publishThisUUID) {
3945 setProperty(kIOPMSleepWakeUUIDKey, anObject: publishThisUUID.get());
3946 }
3947
3948 gSleepWakeUUIDIsSet = true;
3949 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
3950
3951 queuedSleepWakeUUIDString.reset();
3952 }
3953}
3954
3955//******************************************************************************
3956// IOPMGetSleepWakeUUIDKey
3957//
3958// Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3959// To get the full key -- a C string -- the buffer must large enough for
3960// the end-of-string character.
3961// The key is expected to be an UUID string
3962//******************************************************************************
3963
3964extern "C" bool
3965IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len)
3966{
3967 if (!gSleepWakeUUIDIsSet) {
3968 return false;
3969 }
3970
3971 if (buffer != NULL) {
3972 OSSharedPtr<OSString> string =
3973 OSDynamicPtrCast<OSString>(source: gRootDomain->copyProperty(kIOPMSleepWakeUUIDKey));
3974
3975 if (!string) {
3976 *buffer = '\0';
3977 } else {
3978 strlcpy(dst: buffer, src: string->getCStringNoCopy(), n: buf_len);
3979 }
3980 }
3981
3982 return true;
3983}
3984
3985//******************************************************************************
3986// lowLatencyAudioNotify
3987//
3988// Used to send an update about low latency audio activity to interested
3989// clients. To keep the overhead minimal the OSDictionary used here
3990// is initialized at boot.
3991//******************************************************************************
3992
3993void
3994IOPMrootDomain::lowLatencyAudioNotify(uint64_t time, boolean_t state)
3995{
3996 if (lowLatencyAudioNotifierDict && lowLatencyAudioNotifyStateSym && lowLatencyAudioNotifyTimestampSym &&
3997 lowLatencyAudioNotifyStateVal && lowLatencyAudioNotifyTimestampVal) {
3998 lowLatencyAudioNotifyTimestampVal->setValue(time);
3999 lowLatencyAudioNotifyStateVal->setValue(state);
4000 setPMSetting(gIOPMSettingLowLatencyAudioModeKey.get(), lowLatencyAudioNotifierDict.get());
4001 } else {
4002 DLOG("LowLatencyAudioNotify error\n");
4003 }
4004 return;
4005}
4006
4007//******************************************************************************
4008// IOPMrootDomainRTNotifier
4009//
4010// Used by performance controller to update the timestamp and state associated
4011// with low latency audio activity in the system.
4012//******************************************************************************
4013
4014extern "C" void
4015IOPMrootDomainRTNotifier(uint64_t time, boolean_t state)
4016{
4017 gRootDomain->lowLatencyAudioNotify(time, state);
4018 return;
4019}
4020
4021//******************************************************************************
4022// initializeBootSessionUUID
4023//
4024// Initialize the boot session uuid at boot up and sets it into registry.
4025//******************************************************************************
4026
4027void
4028IOPMrootDomain::initializeBootSessionUUID(void)
4029{
4030 uuid_t new_uuid;
4031 uuid_string_t new_uuid_string;
4032
4033 uuid_generate(out: new_uuid);
4034 uuid_unparse_upper(uu: new_uuid, out: new_uuid_string);
4035 memcpy(dst: bootsessionuuid_string, src: new_uuid_string, n: sizeof(uuid_string_t));
4036
4037 setProperty(kIOPMBootSessionUUIDKey, aString: new_uuid_string);
4038}
4039
4040//******************************************************************************
4041// Root domain uses the private and tagged changePowerState methods for
4042// tracking and logging purposes.
4043//******************************************************************************
4044
4045#define REQUEST_TAG_TO_REASON(x) ((uint16_t)x)
4046
4047static uint32_t
4048nextRequestTag( IOPMRequestTag tag )
4049{
4050 static SInt16 msb16 = 1;
4051 uint16_t id = OSAddAtomic16(amount: 1, address: &msb16);
4052 return ((uint32_t)id << 16) | REQUEST_TAG_TO_REASON(tag);
4053}
4054
4055// TODO: remove this shim function and exported symbol
4056IOReturn
4057IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
4058{
4059 return changePowerStateWithTagTo(ordinal, tag: kCPSReasonNone);
4060}
4061
4062// TODO: remove this shim function and exported symbol
4063IOReturn
4064IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
4065{
4066 return changePowerStateWithTagToPriv(ordinal, tag: kCPSReasonNone);
4067}
4068
4069IOReturn
4070IOPMrootDomain::changePowerStateWithOverrideTo(
4071 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
4072{
4073 uint32_t tag = nextRequestTag(tag: reason);
4074 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
4075
4076 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
4077 return kIOReturnUnsupported;
4078 }
4079
4080 return super::changePowerStateWithOverrideTo(ordinal, tag);
4081}
4082
4083IOReturn
4084IOPMrootDomain::changePowerStateWithTagTo(
4085 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
4086{
4087 uint32_t tag = nextRequestTag(tag: reason);
4088 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
4089
4090 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
4091 return kIOReturnUnsupported;
4092 }
4093
4094 return super::changePowerStateWithTagTo(ordinal, tag);
4095}
4096
4097IOReturn
4098IOPMrootDomain::changePowerStateWithTagToPriv(
4099 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
4100{
4101 uint32_t tag = nextRequestTag(tag: reason);
4102 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
4103
4104 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
4105 return kIOReturnUnsupported;
4106 }
4107
4108 return super::changePowerStateWithTagToPriv(ordinal, tag);
4109}
4110
4111//******************************************************************************
4112// activity detect
4113//
4114//******************************************************************************
4115
4116bool
4117IOPMrootDomain::activitySinceSleep(void)
4118{
4119 return userActivityCount != userActivityAtSleep;
4120}
4121
4122bool
4123IOPMrootDomain::abortHibernation(void)
4124{
4125#if __arm64__
4126 // don't allow hibernation to be aborted on ARM due to user activity
4127 // since once ApplePMGR decides we're hibernating, we can't turn back
4128 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
4129 return false;
4130#else
4131 bool ret = activitySinceSleep();
4132
4133 if (ret && !hibernateAborted && checkSystemCanSustainFullWake()) {
4134 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
4135 hibernateAborted = true;
4136 }
4137 return ret;
4138#endif
4139}
4140
4141extern "C" int
4142hibernate_should_abort(void)
4143{
4144 if (gRootDomain) {
4145 return gRootDomain->abortHibernation();
4146 } else {
4147 return 0;
4148 }
4149}
4150
4151//******************************************************************************
4152// willNotifyPowerChildren
4153//
4154// Called after all interested drivers have all acknowledged the power change,
4155// but before any power children is informed. Dispatched though a thread call,
4156// so it is safe to perform work that might block on a sleeping disk. PM state
4157// machine (not thread) will block w/o timeout until this function returns.
4158//******************************************************************************
4159
4160void
4161IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
4162{
4163 OSSharedPtr<OSDictionary> dict;
4164 OSSharedPtr<OSNumber> secs;
4165
4166 if (SLEEP_STATE == newPowerState) {
4167 notifierThread = current_thread();
4168 if (updateTasksSuspend(newTasksSuspended: kTasksSuspendSuspended, newAOTTasksSuspended: kTasksSuspendNoChange)) {
4169 AbsoluteTime deadline;
4170
4171 clock_interval_to_deadline(interval: 10, scale_factor: kSecondScale, result: &deadline);
4172#if defined(XNU_TARGET_OS_OSX)
4173 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
4174#endif /* defined(XNU_TARGET_OS_OSX) */
4175 }
4176
4177 _aotReadyToFullWake = false;
4178#if 0
4179 if (_aotLingerTime) {
4180 uint64_t deadline;
4181 IOLog("aot linger no return\n");
4182 clock_absolutetime_interval_to_deadline(_aotLingerTime, &deadline);
4183 clock_delay_until(deadline);
4184 }
4185#endif
4186 if (!_aotMode) {
4187 _aotTestTime = 0;
4188 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
4189 _aotLastWakeTime = 0;
4190 if (_aotMetrics) {
4191 bzero(s: _aotMetrics, n: sizeof(IOPMAOTMetrics));
4192 }
4193 } else if (!_aotNow && !_debugWakeSeconds) {
4194 _aotNow = true;
4195 _aotPendingFlags = 0;
4196 _aotTasksSuspended = true;
4197 _aotLastWakeTime = 0;
4198 bzero(s: _aotMetrics, n: sizeof(IOPMAOTMetrics));
4199 if (kIOPMAOTModeCycle & _aotMode) {
4200 clock_interval_to_absolutetime_interval(interval: 60, scale_factor: kSecondScale, result: &_aotTestInterval);
4201 _aotTestTime = mach_continuous_time() + _aotTestInterval;
4202 setWakeTime(_aotTestTime);
4203 }
4204 uint32_t lingerSecs;
4205 if (!PE_parse_boot_argn(arg_string: "aotlinger", arg_ptr: &lingerSecs, max_arg: sizeof(lingerSecs))) {
4206 lingerSecs = 0;
4207 }
4208 clock_interval_to_absolutetime_interval(interval: lingerSecs, scale_factor: kSecondScale, result: &_aotLingerTime);
4209 clock_interval_to_absolutetime_interval(interval: 2000, scale_factor: kMillisecondScale, result: &_aotWakePreWindow);
4210 clock_interval_to_absolutetime_interval(interval: 1100, scale_factor: kMillisecondScale, result: &_aotWakePostWindow);
4211 }
4212
4213#if HIBERNATION
4214 IOHibernateSystemSleep();
4215 IOHibernateIOKitSleep();
4216#endif
4217#if defined(__arm64__) && HIBERNATION
4218 // On AS, hibernation cannot be aborted. Resetting RTC to 1s during hibernation upon detecting
4219 // user activity is pointless (we are likely to spend >1s hibernating). It also clears existing
4220 // alarms, which can mess with cycler tools.
4221 if (gRootDomain->activitySinceSleep() && gIOHibernateState == kIOHibernateStateInactive) {
4222#else /* defined(__arm64__) && HIBERNATION */
4223 // On non-AS, hibernation can be aborted if user activity is detected. So continue to reset the
4224 // RTC alarm (even during hibernation) so we can immediately wake from regular S2R if needed.
4225 if (gRootDomain->activitySinceSleep()) {
4226#endif /* defined(__arm64__) && HIBERNATION */
4227 dict = OSDictionary::withCapacity(capacity: 1);
4228 secs = OSNumber::withNumber(value: 1, numberOfBits: 32);
4229
4230 if (dict && secs) {
4231 dict->setObject(aKey: gIOPMSettingDebugWakeRelativeKey.get(), anObject: secs.get());
4232 gRootDomain->setProperties(dict.get());
4233 MSG("Reverting sleep with relative wake\n");
4234 }
4235 }
4236
4237 notifierThread = NULL;
4238 }
4239}
4240
4241//******************************************************************************
4242// willTellSystemCapabilityDidChange
4243//
4244// IOServicePM calls this from OurChangeTellCapabilityDidChange() when root
4245// domain is raising its power state, immediately after notifying interested
4246// drivers and power children.
4247//******************************************************************************
4248
4249void
4250IOPMrootDomain::willTellSystemCapabilityDidChange( void )
4251{
4252 if ((_systemTransitionType == kSystemTransitionWake) &&
4253 !CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
4254 // After powering up drivers, dark->full promotion on the current wake
4255 // transition is no longer possible. That is because the next machine
4256 // state will issue the system capability change messages.
4257 // The darkWakePowerClamped flag may already be set if the system has
4258 // at least one driver that was power clamped due to dark wake.
4259 // This function sets the darkWakePowerClamped flag in case there
4260 // is no power-clamped driver in the system.
4261 //
4262 // Last opportunity to exit dark wake using:
4263 // requestFullWake( kFullWakeReasonLocalUser );
4264
4265 if (!darkWakePowerClamped) {
4266 if (darkWakeLogClamp) {
4267 AbsoluteTime now;
4268 uint64_t nsec;
4269
4270 clock_get_uptime(result: &now);
4271 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
4272 absolutetime_to_nanoseconds(abstime: now, result: &nsec);
4273 DLOG("dark wake promotion disabled at %u ms\n",
4274 ((int)((nsec) / NSEC_PER_MSEC)));
4275 }
4276 darkWakePowerClamped = true;
4277 }
4278 }
4279}
4280
4281//******************************************************************************
4282// sleepOnClamshellClosed
4283//
4284// contains the logic to determine if the system should sleep when the clamshell
4285// is closed.
4286//******************************************************************************
4287
4288bool
4289IOPMrootDomain::shouldSleepOnClamshellClosed( void )
4290{
4291 if (!clamshellExists) {
4292 return false;
4293 }
4294
4295 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4296 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
4297
4298 return !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisableMask;
4299}
4300
4301bool
4302IOPMrootDomain::shouldSleepOnRTCAlarmWake( void )
4303{
4304 // Called once every RTC/Alarm wake. Device should go to sleep if on clamshell
4305 // closed && battery
4306 if (!clamshellExists) {
4307 return false;
4308 }
4309
4310 DLOG("shouldSleepOnRTCAlarmWake: clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4311 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
4312
4313 return !acAdaptorConnected && !clamshellSleepDisableMask;
4314}
4315
4316void
4317IOPMrootDomain::sendClientClamshellNotification( void )
4318{
4319 /* Only broadcast clamshell alert if clamshell exists. */
4320 if (!clamshellExists) {
4321 return;
4322 }
4323
4324 setProperty(kAppleClamshellStateKey,
4325 anObject: clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
4326
4327 setProperty(kAppleClamshellCausesSleepKey,
4328 anObject: shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
4329
4330 /* Argument to message is a bitfiel of
4331 * ( kClamshellStateBit | kClamshellSleepBit )
4332 */
4333 messageClients(kIOPMMessageClamshellStateChange,
4334 argument: (void *)(uintptr_t) ((clamshellClosed ? kClamshellStateBit : 0)
4335 | (shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)));
4336}
4337
4338//******************************************************************************
4339// getSleepSupported
4340//
4341// Deprecated
4342//******************************************************************************
4343
4344IOOptionBits
4345IOPMrootDomain::getSleepSupported( void )
4346{
4347 return platformSleepSupport;
4348}
4349
4350//******************************************************************************
4351// setSleepSupported
4352//
4353// Deprecated
4354//******************************************************************************
4355
4356void
4357IOPMrootDomain::setSleepSupported( IOOptionBits flags )
4358{
4359 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
4360 OSBitOrAtomic(flags, &platformSleepSupport);
4361}
4362
4363//******************************************************************************
4364// setClamShellSleepDisable
4365//
4366//******************************************************************************
4367
4368void
4369IOPMrootDomain::setClamShellSleepDisable( bool disable, uint32_t bitmask )
4370{
4371 uint32_t oldMask;
4372
4373 // User client calls this in non-gated context
4374 if (gIOPMWorkLoop->inGate() == false) {
4375 gIOPMWorkLoop->runAction(
4376 OSMemberFunctionCast(IOWorkLoop::Action, this,
4377 &IOPMrootDomain::setClamShellSleepDisable),
4378 target: (OSObject *) this,
4379 arg0: (void *) disable, arg1: (void *)(uintptr_t) bitmask);
4380 return;
4381 }
4382
4383 oldMask = clamshellSleepDisableMask;
4384 if (disable) {
4385 clamshellSleepDisableMask |= bitmask;
4386 } else {
4387 clamshellSleepDisableMask &= ~bitmask;
4388 }
4389 DLOG("setClamShellSleepDisable(%x->%x)\n", oldMask, clamshellSleepDisableMask);
4390
4391 if (clamshellExists && clamshellClosed &&
4392 (clamshellSleepDisableMask != oldMask) &&
4393 (clamshellSleepDisableMask == 0)) {
4394 handlePowerNotification(kLocalEvalClamshellCommand);
4395 }
4396}
4397
4398//******************************************************************************
4399// wakeFromDoze
4400//
4401// Deprecated.
4402//******************************************************************************
4403
4404void
4405IOPMrootDomain::wakeFromDoze( void )
4406{
4407 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
4408}
4409
4410//******************************************************************************
4411// recordRTCAlarm
4412//
4413// Record the earliest scheduled RTC alarm to determine whether a RTC wake
4414// should be a dark wake or a full wake. Both Maintenance and SleepService
4415// alarms are dark wake, while AutoWake (WakeByCalendarDate) and DebugWake
4416// (WakeRelativeToSleep) should trigger a full wake. Scheduled power-on
4417// PMSettings are ignored.
4418//
4419// Caller serialized using settingsCtrlLock.
4420//******************************************************************************
4421
4422void
4423IOPMrootDomain::recordRTCAlarm(
4424 const OSSymbol *type,
4425 OSObject *object )
4426{
4427 uint32_t previousAlarmMask = _scheduledAlarmMask;
4428
4429 if (type == gIOPMSettingDebugWakeRelativeKey) {
4430 OSNumber * n = OSDynamicCast(OSNumber, object);
4431 if (n) {
4432 // Debug wake has highest scheduling priority so it overrides any
4433 // pre-existing alarm.
4434 uint32_t debugSecs = n->unsigned32BitValue();
4435 _nextScheduledAlarmType.reset(p: type, OSRetain);
4436 _nextScheduledAlarmUTC = debugSecs;
4437
4438 _debugWakeSeconds = debugSecs;
4439 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarmMask);
4440 DLOG("next alarm (%s) in %u secs\n",
4441 type->getCStringNoCopy(), debugSecs);
4442 }
4443 } else if ((type == gIOPMSettingAutoWakeCalendarKey.get()) ||
4444 (type == gIOPMSettingMaintenanceWakeCalendarKey.get()) ||
4445 (type == gIOPMSettingSleepServiceWakeCalendarKey.get())) {
4446 OSData * data = OSDynamicCast(OSData, object);
4447 if (data && (data->getLength() == sizeof(IOPMCalendarStruct))) {
4448 const IOPMCalendarStruct * cs;
4449 bool replaceNextAlarm = false;
4450 clock_sec_t secs;
4451
4452 cs = (const IOPMCalendarStruct *) data->getBytesNoCopy();
4453 secs = IOPMConvertCalendarToSeconds(dt: cs);
4454 DLOG("%s " YMDTF "\n", type->getCStringNoCopy(), YMDT(cs));
4455
4456 // Update the next scheduled alarm type
4457 if ((_nextScheduledAlarmType == NULL) ||
4458 ((_nextScheduledAlarmType != gIOPMSettingDebugWakeRelativeKey) &&
4459 (secs < _nextScheduledAlarmUTC))) {
4460 replaceNextAlarm = true;
4461 }
4462
4463 if (type == gIOPMSettingAutoWakeCalendarKey.get()) {
4464 if (cs->year) {
4465 _calendarWakeAlarmUTC = IOPMConvertCalendarToSeconds(dt: cs);
4466 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarmMask);
4467 } else {
4468 // TODO: can this else-block be removed?
4469 _calendarWakeAlarmUTC = 0;
4470 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarmMask);
4471 }
4472 }
4473 if (type == gIOPMSettingMaintenanceWakeCalendarKey.get()) {
4474 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarmMask);
4475 }
4476 if (type == gIOPMSettingSleepServiceWakeCalendarKey.get()) {
4477 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarmMask);
4478 }
4479
4480 if (replaceNextAlarm) {
4481 _nextScheduledAlarmType.reset(p: type, OSRetain);
4482 _nextScheduledAlarmUTC = secs;
4483 DLOG("next alarm (%s) " YMDTF "\n", type->getCStringNoCopy(), YMDT(cs));
4484 }
4485 }
4486 }
4487
4488 if (_scheduledAlarmMask != previousAlarmMask) {
4489 DLOG("scheduled alarm mask 0x%x\n", (uint32_t) _scheduledAlarmMask);
4490 }
4491}
4492
4493// MARK: -
4494// MARK: Features
4495
4496//******************************************************************************
4497// publishFeature
4498//
4499// Adds a new feature to the supported features dictionary
4500//******************************************************************************
4501
4502void
4503IOPMrootDomain::publishFeature( const char * feature )
4504{
4505 publishFeature(feature, kRD_AllPowerSources, NULL);
4506}
4507
4508//******************************************************************************
4509// publishFeature (with supported power source specified)
4510//
4511// Adds a new feature to the supported features dictionary
4512//******************************************************************************
4513
4514void
4515IOPMrootDomain::publishFeature(
4516 const char *feature,
4517 uint32_t supportedWhere,
4518 uint32_t *uniqueFeatureID)
4519{
4520 static uint16_t next_feature_id = 500;
4521
4522 OSSharedPtr<OSNumber> new_feature_data;
4523 OSNumber *existing_feature = NULL;
4524 OSArray *existing_feature_arr_raw = NULL;
4525 OSSharedPtr<OSArray> existing_feature_arr;
4526 OSObject *osObj = NULL;
4527 uint32_t feature_value = 0;
4528
4529 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
4530
4531 if (!supportedWhere) {
4532 // Feature isn't supported anywhere!
4533 return;
4534 }
4535
4536 if (next_feature_id > 5000) {
4537 // Far, far too many features!
4538 return;
4539 }
4540
4541 if (featuresDictLock) {
4542 IOLockLock(featuresDictLock);
4543 }
4544
4545 OSSharedPtr<OSObject> origFeaturesProp = copyProperty(kRootDomainSupportedFeatures);
4546 OSDictionary *origFeatures = OSDynamicCast(OSDictionary, origFeaturesProp.get());
4547 OSSharedPtr<OSDictionary> features;
4548
4549 // Create new features dict if necessary
4550 if (origFeatures) {
4551 features = OSDictionary::withDictionary(dict: origFeatures);
4552 } else {
4553 features = OSDictionary::withCapacity(capacity: 1);
4554 }
4555
4556 // Create OSNumber to track new feature
4557
4558 next_feature_id += 1;
4559 if (uniqueFeatureID) {
4560 // We don't really mind if the calling kext didn't give us a place
4561 // to stash their unique id. Many kexts don't plan to unload, and thus
4562 // have no need to remove themselves later.
4563 *uniqueFeatureID = next_feature_id;
4564 }
4565
4566 feature_value = (uint32_t)next_feature_id;
4567 feature_value <<= 16;
4568 feature_value += supportedWhere;
4569
4570 new_feature_data = OSNumber::withNumber(
4571 value: (unsigned long long)feature_value, numberOfBits: 32);
4572
4573 // Does features object already exist?
4574 if ((osObj = features->getObject(aKey: feature))) {
4575 if ((existing_feature = OSDynamicCast(OSNumber, osObj))) {
4576 // We need to create an OSArray to hold the now 2 elements.
4577 existing_feature_arr = OSArray::withObjects(
4578 objects: (const OSObject **)&existing_feature, count: 1, capacity: 2);
4579 } else if ((existing_feature_arr_raw = OSDynamicCast(OSArray, osObj))) {
4580 // Add object to existing array
4581 existing_feature_arr = OSArray::withArray(
4582 array: existing_feature_arr_raw,
4583 capacity: existing_feature_arr_raw->getCount() + 1);
4584 }
4585
4586 if (existing_feature_arr) {
4587 existing_feature_arr->setObject(new_feature_data.get());
4588 features->setObject(aKey: feature, anObject: existing_feature_arr.get());
4589 }
4590 } else {
4591 // The easy case: no previously existing features listed. We simply
4592 // set the OSNumber at key 'feature' and we're on our way.
4593 features->setObject(aKey: feature, anObject: new_feature_data.get());
4594 }
4595
4596 setProperty(kRootDomainSupportedFeatures, anObject: features.get());
4597
4598 if (featuresDictLock) {
4599 IOLockUnlock(featuresDictLock);
4600 }
4601
4602 // Notify EnergySaver and all those in user space so they might
4603 // re-populate their feature specific UI
4604 if (pmPowerStateQueue) {
4605 pmPowerStateQueue->submitPowerEvent( eventType: kPowerEventFeatureChanged );
4606 }
4607}
4608
4609//******************************************************************************
4610// removePublishedFeature
4611//
4612// Removes previously published feature
4613//******************************************************************************
4614
4615IOReturn
4616IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
4617{
4618 IOReturn ret = kIOReturnError;
4619 uint32_t feature_value = 0;
4620 uint16_t feature_id = 0;
4621 bool madeAChange = false;
4622
4623 OSSymbol *dictKey = NULL;
4624 OSSharedPtr<OSCollectionIterator> dictIterator;
4625 OSArray *arrayMember = NULL;
4626 OSNumber *numberMember = NULL;
4627 OSObject *osObj = NULL;
4628 OSNumber *osNum = NULL;
4629 OSSharedPtr<OSArray> arrayMemberCopy;
4630
4631 if (kBadPMFeatureID == removeFeatureID) {
4632 return kIOReturnNotFound;
4633 }
4634
4635 if (featuresDictLock) {
4636 IOLockLock(featuresDictLock);
4637 }
4638
4639 OSSharedPtr<OSObject> origFeaturesProp = copyProperty(kRootDomainSupportedFeatures);
4640 OSDictionary *origFeatures = OSDynamicCast(OSDictionary, origFeaturesProp.get());
4641 OSSharedPtr<OSDictionary> features;
4642
4643 if (origFeatures) {
4644 // Any modifications to the dictionary are made to the copy to prevent
4645 // races & crashes with userland clients. Dictionary updated
4646 // automically later.
4647 features = OSDictionary::withDictionary(dict: origFeatures);
4648 } else {
4649 features = NULL;
4650 ret = kIOReturnNotFound;
4651 goto exit;
4652 }
4653
4654 // We iterate 'features' dictionary looking for an entry tagged
4655 // with 'removeFeatureID'. If found, we remove it from our tracking
4656 // structures and notify the OS via a general interest message.
4657
4658 dictIterator = OSCollectionIterator::withCollection(inColl: features.get());
4659 if (!dictIterator) {
4660 goto exit;
4661 }
4662
4663 while ((dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject()))) {
4664 osObj = features->getObject(aKey: dictKey);
4665
4666 // Each Feature is either tracked by an OSNumber
4667 if (osObj && (numberMember = OSDynamicCast(OSNumber, osObj))) {
4668 feature_value = numberMember->unsigned32BitValue();
4669 feature_id = (uint16_t)(feature_value >> 16);
4670
4671 if (feature_id == (uint16_t)removeFeatureID) {
4672 // Remove this node
4673 features->removeObject(aKey: dictKey);
4674 madeAChange = true;
4675 break;
4676 }
4677
4678 // Or tracked by an OSArray of OSNumbers
4679 } else if (osObj && (arrayMember = OSDynamicCast(OSArray, osObj))) {
4680 unsigned int arrayCount = arrayMember->getCount();
4681
4682 for (unsigned int i = 0; i < arrayCount; i++) {
4683 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
4684 if (!osNum) {
4685 continue;
4686 }
4687
4688 feature_value = osNum->unsigned32BitValue();
4689 feature_id = (uint16_t)(feature_value >> 16);
4690
4691 if (feature_id == (uint16_t)removeFeatureID) {
4692 // Remove this node
4693 if (1 == arrayCount) {
4694 // If the array only contains one element, remove
4695 // the whole thing.
4696 features->removeObject(aKey: dictKey);
4697 } else {
4698 // Otherwise remove the element from a copy of the array.
4699 arrayMemberCopy = OSArray::withArray(array: arrayMember);
4700 if (arrayMemberCopy) {
4701 arrayMemberCopy->removeObject(index: i);
4702 features->setObject(aKey: dictKey, anObject: arrayMemberCopy.get());
4703 }
4704 }
4705
4706 madeAChange = true;
4707 break;
4708 }
4709 }
4710 }
4711 }
4712
4713 if (madeAChange) {
4714 ret = kIOReturnSuccess;
4715
4716 setProperty(kRootDomainSupportedFeatures, anObject: features.get());
4717
4718 // Notify EnergySaver and all those in user space so they might
4719 // re-populate their feature specific UI
4720 if (pmPowerStateQueue) {
4721 pmPowerStateQueue->submitPowerEvent( eventType: kPowerEventFeatureChanged );
4722 }
4723 } else {
4724 ret = kIOReturnNotFound;
4725 }
4726
4727exit:
4728 if (featuresDictLock) {
4729 IOLockUnlock(featuresDictLock);
4730 }
4731 return ret;
4732}
4733
4734//******************************************************************************
4735// publishPMSetting (private)
4736//
4737// Should only be called by PMSettingObject to publish a PM Setting as a
4738// supported feature.
4739//******************************************************************************
4740
4741void
4742IOPMrootDomain::publishPMSetting(
4743 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
4744{
4745 if (noPublishPMSettings &&
4746 (noPublishPMSettings->getNextIndexOfObject(anObject: feature, index: 0) != (unsigned int)-1)) {
4747 // Setting found in noPublishPMSettings array
4748 *featureID = kBadPMFeatureID;
4749 return;
4750 }
4751
4752 publishFeature(
4753 feature: feature->getCStringNoCopy(), supportedWhere: where, uniqueFeatureID: featureID);
4754}
4755
4756//******************************************************************************
4757// setPMSetting (private)
4758//
4759// Internal helper to relay PM settings changes from user space to individual
4760// drivers. Should be called only by IOPMrootDomain::setProperties.
4761//******************************************************************************
4762
4763IOReturn
4764IOPMrootDomain::setPMSetting(
4765 const OSSymbol *type,
4766 OSObject *object )
4767{
4768 PMSettingCallEntry *entries = NULL;
4769 OSSharedPtr<OSArray> chosen;
4770 const OSArray *array;
4771 PMSettingObject *pmso;
4772 thread_t thisThread;
4773 int i, j, count, capacity;
4774 bool ok = false;
4775 IOReturn ret;
4776
4777 if (NULL == type) {
4778 return kIOReturnBadArgument;
4779 }
4780
4781 PMSETTING_LOCK();
4782
4783 // Update settings dict so changes are visible from copyPMSetting().
4784 fPMSettingsDict->setObject(aKey: type, anObject: object);
4785
4786 // Prep all PMSetting objects with the given 'type' for callout.
4787 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
4788 if (!array || ((capacity = array->getCount()) == 0)) {
4789 goto unlock_exit;
4790 }
4791
4792 // Array to retain PMSetting objects targeted for callout.
4793 chosen = OSArray::withCapacity(capacity);
4794 if (!chosen) {
4795 goto unlock_exit; // error
4796 }
4797 entries = IONew(PMSettingCallEntry, capacity);
4798 if (!entries) {
4799 goto unlock_exit; // error
4800 }
4801 memset(s: entries, c: 0, n: sizeof(PMSettingCallEntry) * capacity);
4802
4803 thisThread = current_thread();
4804
4805 for (i = 0, j = 0; i < capacity; i++) {
4806 pmso = (PMSettingObject *) array->getObject(index: i);
4807 if (pmso->disabled) {
4808 continue;
4809 }
4810 entries[j].thread = thisThread;
4811 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
4812 chosen->setObject(pmso);
4813 j++;
4814 }
4815 count = j;
4816 if (!count) {
4817 goto unlock_exit;
4818 }
4819
4820 PMSETTING_UNLOCK();
4821
4822 // Call each pmso in the chosen array.
4823 for (i = 0; i < count; i++) {
4824 pmso = (PMSettingObject *) chosen->getObject(index: i);
4825 ret = pmso->dispatchPMSetting(type, object);
4826 if (ret == kIOReturnSuccess) {
4827 // At least one setting handler was successful
4828 ok = true;
4829#if DEVELOPMENT || DEBUG
4830 } else {
4831 // Log the handler and kext that failed
4832 OSSharedPtr<const OSSymbol> kextName = copyKextIdentifierWithAddress((vm_address_t) pmso->func);
4833 if (kextName) {
4834 DLOG("PMSetting(%s) error 0x%x from %s\n",
4835 type->getCStringNoCopy(), ret, kextName->getCStringNoCopy());
4836 }
4837#endif
4838 }
4839 }
4840
4841 PMSETTING_LOCK();
4842 for (i = 0; i < count; i++) {
4843 pmso = (PMSettingObject *) chosen->getObject(index: i);
4844 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
4845 if (pmso->waitThread) {
4846 PMSETTING_WAKEUP(pmso);
4847 }
4848 }
4849
4850 if (ok) {
4851 recordRTCAlarm(type, object);
4852 }
4853unlock_exit:
4854 PMSETTING_UNLOCK();
4855
4856 if (entries) {
4857 IODelete(entries, PMSettingCallEntry, capacity);
4858 }
4859
4860 return kIOReturnSuccess;
4861}
4862
4863//******************************************************************************
4864// copyPMSetting (public)
4865//
4866// Allows kexts to safely read setting values, without being subscribed to
4867// notifications.
4868//******************************************************************************
4869
4870OSSharedPtr<OSObject>
4871IOPMrootDomain::copyPMSetting(
4872 OSSymbol *whichSetting)
4873{
4874 OSSharedPtr<OSObject> obj;
4875
4876 if (!whichSetting) {
4877 return NULL;
4878 }
4879
4880 PMSETTING_LOCK();
4881 obj.reset(p: fPMSettingsDict->getObject(aKey: whichSetting), OSRetain);
4882 PMSETTING_UNLOCK();
4883
4884 return obj;
4885}
4886
4887//******************************************************************************
4888// registerPMSettingController (public)
4889//
4890// direct wrapper to registerPMSettingController with uint32_t power source arg
4891//******************************************************************************
4892
4893IOReturn
4894IOPMrootDomain::registerPMSettingController(
4895 const OSSymbol * settings[],
4896 IOPMSettingControllerCallback func,
4897 OSObject *target,
4898 uintptr_t refcon,
4899 OSObject **handle)
4900{
4901 return registerPMSettingController(
4902 settings,
4903 supportedPowerSources: (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
4904 callout: func, target, refcon, handle);
4905}
4906
4907//******************************************************************************
4908// registerPMSettingController (public)
4909//
4910// Kexts may register for notifications when a particular setting is changed.
4911// A list of settings is available in IOPM.h.
4912// Arguments:
4913// * settings - An OSArray containing OSSymbols. Caller should populate this
4914// array with a list of settings caller wants notifications from.
4915// * func - A C function callback of the type IOPMSettingControllerCallback
4916// * target - caller may provide an OSObject *, which PM will pass as an
4917// target to calls to "func"
4918// * refcon - caller may provide an void *, which PM will pass as an
4919// argument to calls to "func"
4920// * handle - This is a return argument. We will populate this pointer upon
4921// call success. Hold onto this and pass this argument to
4922// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
4923// Returns:
4924// kIOReturnSuccess on success
4925//******************************************************************************
4926
4927IOReturn
4928IOPMrootDomain::registerPMSettingController(
4929 const OSSymbol * settings[],
4930 uint32_t supportedPowerSources,
4931 IOPMSettingControllerCallback func,
4932 OSObject *target,
4933 uintptr_t refcon,
4934 OSObject **handle)
4935{
4936 PMSettingObject *pmso = NULL;
4937 OSObject *pmsh = NULL;
4938 int i;
4939
4940 if (NULL == settings ||
4941 NULL == func ||
4942 NULL == handle) {
4943 return kIOReturnBadArgument;
4944 }
4945
4946 pmso = PMSettingObject::pmSettingObject(
4947 parent_arg: (IOPMrootDomain *) this, handler_arg: func, target_arg: target,
4948 refcon_arg: refcon, supportedPowerSources, settings, handle_obj: &pmsh);
4949
4950 if (!pmso) {
4951 *handle = NULL;
4952 return kIOReturnInternalError;
4953 }
4954
4955 PMSETTING_LOCK();
4956 for (i = 0; settings[i]; i++) {
4957 OSSharedPtr<OSArray> newList;
4958 OSArray *list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
4959 if (!list) {
4960 // New array of callbacks for this setting
4961 newList = OSArray::withCapacity(capacity: 1);
4962 settingsCallbacks->setObject(aKey: settings[i], anObject: newList.get());
4963 list = newList.get();
4964 }
4965
4966 // Add caller to the callback list
4967 list->setObject(pmso);
4968 }
4969 PMSETTING_UNLOCK();
4970
4971 // Return handle to the caller, the setting object is private.
4972 *handle = pmsh;
4973
4974 return kIOReturnSuccess;
4975}
4976
4977//******************************************************************************
4978// deregisterPMSettingObject (private)
4979//
4980// Only called from PMSettingObject.
4981//******************************************************************************
4982
4983void
4984IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
4985{
4986 thread_t thisThread = current_thread();
4987 PMSettingCallEntry *callEntry;
4988 OSSharedPtr<OSCollectionIterator> iter;
4989 OSSymbol *sym;
4990 OSArray *array;
4991 int index;
4992 bool wait;
4993
4994 PMSETTING_LOCK();
4995
4996 pmso->disabled = true;
4997
4998 // Wait for all callout threads to finish.
4999 do {
5000 wait = false;
5001 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
5002 {
5003 if (callEntry->thread != thisThread) {
5004 wait = true;
5005 break;
5006 }
5007 }
5008 if (wait) {
5009 assert(NULL == pmso->waitThread);
5010 pmso->waitThread = thisThread;
5011 PMSETTING_WAIT(pmso);
5012 pmso->waitThread = NULL;
5013 }
5014 } while (wait);
5015
5016 // Search each PM settings array in the kernel.
5017 iter = OSCollectionIterator::withCollection(inColl: settingsCallbacks.get());
5018 if (iter) {
5019 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
5020 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
5021 index = array->getNextIndexOfObject(anObject: pmso, index: 0);
5022 if (-1 != index) {
5023 array->removeObject(index);
5024 }
5025 }
5026 }
5027
5028 PMSETTING_UNLOCK();
5029
5030 pmso->release();
5031}
5032
5033//******************************************************************************
5034// informCPUStateChange
5035//
5036// Call into PM CPU code so that CPU power savings may dynamically adjust for
5037// running on battery, with the lid closed, etc.
5038//
5039// informCPUStateChange is a no-op on non x86 systems
5040// only x86 has explicit support in the IntelCPUPowerManagement kext
5041//******************************************************************************
5042
5043void
5044IOPMrootDomain::informCPUStateChange(
5045 uint32_t type,
5046 uint32_t value )
5047{
5048#if defined(__i386__) || defined(__x86_64__)
5049
5050 pmioctlVariableInfo_t varInfoStruct;
5051 int pmCPUret = 0;
5052 const char *varNameStr = NULL;
5053 int32_t *varIndex = NULL;
5054
5055 if (kInformAC == type) {
5056 varNameStr = kIOPMRootDomainBatPowerCString;
5057 varIndex = &idxPMCPULimitedPower;
5058 } else if (kInformLid == type) {
5059 varNameStr = kIOPMRootDomainLidCloseCString;
5060 varIndex = &idxPMCPUClamshell;
5061 } else {
5062 return;
5063 }
5064
5065 // Set the new value!
5066 // pmCPUControl will assign us a new ID if one doesn't exist yet
5067 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
5068 varInfoStruct.varID = *varIndex;
5069 varInfoStruct.varType = vBool;
5070 varInfoStruct.varInitValue = value;
5071 varInfoStruct.varCurValue = value;
5072 strlcpy((char *)varInfoStruct.varName,
5073 (const char *)varNameStr,
5074 sizeof(varInfoStruct.varName));
5075
5076 // Set!
5077 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
5078
5079 // pmCPU only assigns numerical id's when a new varName is specified
5080 if ((0 == pmCPUret)
5081 && (*varIndex == kCPUUnknownIndex)) {
5082 // pmCPUControl has assigned us a new variable ID.
5083 // Let's re-read the structure we just SET to learn that ID.
5084 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
5085
5086 if (0 == pmCPUret) {
5087 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
5088 *varIndex = varInfoStruct.varID;
5089 }
5090 }
5091
5092 return;
5093
5094#endif /* __i386__ || __x86_64__ */
5095}
5096
5097// MARK: -
5098// MARK: Deep Sleep Policy
5099
5100#if HIBERNATION
5101
5102//******************************************************************************
5103// evaluateSystemSleepPolicy
5104//******************************************************************************
5105
5106#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
5107
5108// Sleep flags
5109enum {
5110 kIOPMSleepFlagHibernate = 0x00000001,
5111 kIOPMSleepFlagSleepTimerEnable = 0x00000002
5112};
5113
5114struct IOPMSystemSleepPolicyEntry {
5115 uint32_t factorMask;
5116 uint32_t factorBits;
5117 uint32_t sleepFlags;
5118 uint32_t wakeEvents;
5119} __attribute__((packed));
5120
5121struct IOPMSystemSleepPolicyTable {
5122 uint32_t signature;
5123 uint16_t version;
5124 uint16_t entryCount;
5125 IOPMSystemSleepPolicyEntry entries[];
5126} __attribute__((packed));
5127
5128enum {
5129 kIOPMSleepAttributeHibernateSetup = 0x00000001,
5130 kIOPMSleepAttributeHibernateSleep = 0x00000002
5131};
5132
5133static uint32_t
5134getSleepTypeAttributes( uint32_t sleepType )
5135{
5136 static const uint32_t sleepTypeAttributes[kIOPMSleepTypeLast] =
5137 {
5138 /* invalid */ 0,
5139 /* abort */ 0,
5140 /* normal */ 0,
5141 /* safesleep */ kIOPMSleepAttributeHibernateSetup,
5142 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5143 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5144 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5145 /* deepidle */ 0
5146 };
5147
5148 if (sleepType >= kIOPMSleepTypeLast) {
5149 return 0;
5150 }
5151
5152 return sleepTypeAttributes[sleepType];
5153}
5154
5155bool
5156IOPMrootDomain::evaluateSystemSleepPolicy(
5157 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
5158{
5159#define SLEEP_FACTOR(x) {(uint32_t) kIOPMSleepFactor ## x, #x}
5160
5161 static const IONamedValue factorValues[] = {
5162 SLEEP_FACTOR( SleepTimerWake ),
5163 SLEEP_FACTOR( LidOpen ),
5164 SLEEP_FACTOR( ACPower ),
5165 SLEEP_FACTOR( BatteryLow ),
5166 SLEEP_FACTOR( StandbyNoDelay ),
5167 SLEEP_FACTOR( StandbyForced ),
5168 SLEEP_FACTOR( StandbyDisabled ),
5169 SLEEP_FACTOR( USBExternalDevice ),
5170 SLEEP_FACTOR( BluetoothHIDDevice ),
5171 SLEEP_FACTOR( ExternalMediaMounted ),
5172 SLEEP_FACTOR( ThunderboltDevice ),
5173 SLEEP_FACTOR( RTCAlarmScheduled ),
5174 SLEEP_FACTOR( MagicPacketWakeEnabled ),
5175 SLEEP_FACTOR( HibernateForced ),
5176 SLEEP_FACTOR( AutoPowerOffDisabled ),
5177 SLEEP_FACTOR( AutoPowerOffForced ),
5178 SLEEP_FACTOR( ExternalDisplay ),
5179 SLEEP_FACTOR( NetworkKeepAliveActive ),
5180 SLEEP_FACTOR( LocalUserActivity ),
5181 SLEEP_FACTOR( HibernateFailed ),
5182 SLEEP_FACTOR( ThermalWarning ),
5183 SLEEP_FACTOR( DisplayCaptured ),
5184 { 0, NULL }
5185 };
5186
5187 const IOPMSystemSleepPolicyTable * pt;
5188 OSSharedPtr<OSObject> prop;
5189 OSData * policyData;
5190 uint64_t currentFactors = 0;
5191 char currentFactorsBuf[512];
5192 uint32_t standbyDelay = 0;
5193 uint32_t powerOffDelay = 0;
5194 uint32_t powerOffTimer = 0;
5195 uint32_t standbyTimer = 0;
5196 uint32_t mismatch;
5197 bool standbyEnabled;
5198 bool powerOffEnabled;
5199 bool found = false;
5200
5201 // Get platform's sleep policy table
5202 if (!gSleepPolicyHandler) {
5203 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
5204 if (!prop) {
5205 goto done;
5206 }
5207 }
5208
5209 // Fetch additional settings
5210 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
5211 && propertyHasValue(kIOPMDeepSleepEnabledKey, kOSBooleanTrue));
5212 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
5213 && propertyHasValue(kIOPMAutoPowerOffEnabledKey, kOSBooleanTrue));
5214 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer)) {
5215 powerOffTimer = powerOffDelay;
5216 }
5217 if (!getSleepOption(kIOPMDeepSleepTimerKey, &standbyTimer)) {
5218 standbyTimer = standbyDelay;
5219 }
5220
5221 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
5222 sleepPhase, standbyEnabled, standbyDelay, standbyTimer,
5223 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
5224
5225 currentFactorsBuf[0] = 0;
5226 // pmset level overrides
5227 if ((*hibMode & kIOHibernateModeOn) == 0) {
5228 if (!gSleepPolicyHandler) {
5229 standbyEnabled = false;
5230 powerOffEnabled = false;
5231 }
5232 } else if (!(*hibMode & kIOHibernateModeSleep)) {
5233 // Force hibernate (i.e. mode 25)
5234 // If standby is enabled, force standy.
5235 // If poweroff is enabled, force poweroff.
5236 if (standbyEnabled) {
5237 currentFactors |= kIOPMSleepFactorStandbyForced;
5238 } else if (powerOffEnabled) {
5239 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
5240 } else {
5241 currentFactors |= kIOPMSleepFactorHibernateForced;
5242 }
5243 }
5244
5245 // Current factors based on environment and assertions
5246 if (sleepTimerMaintenance) {
5247 currentFactors |= kIOPMSleepFactorSleepTimerWake;
5248 }
5249 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler) {
5250 currentFactors |= kIOPMSleepFactorSleepTimerWake;
5251 }
5252 if (!clamshellClosed) {
5253 currentFactors |= kIOPMSleepFactorLidOpen;
5254 }
5255 if (acAdaptorConnected) {
5256 currentFactors |= kIOPMSleepFactorACPower;
5257 }
5258 if (lowBatteryCondition) {
5259 hibernateMode = 0;
5260 getSleepOption(kIOHibernateModeKey, &hibernateMode);
5261 if ((hibernateMode & kIOHibernateModeOn) == 0) {
5262 DLOG("HibernateMode is 0. Not sending LowBattery factor to IOPPF\n");
5263 } else {
5264 currentFactors |= kIOPMSleepFactorBatteryLow;
5265 }
5266 }
5267 if (!standbyDelay || !standbyTimer) {
5268 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
5269 }
5270 if (standbyNixed || !standbyEnabled) {
5271 currentFactors |= kIOPMSleepFactorStandbyDisabled;
5272 }
5273 if (resetTimers) {
5274 currentFactors |= kIOPMSleepFactorLocalUserActivity;
5275 currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
5276 }
5277 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
5278 kIOPMDriverAssertionLevelOff) {
5279 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
5280 }
5281 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
5282 kIOPMDriverAssertionLevelOff) {
5283 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
5284 }
5285 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
5286 kIOPMDriverAssertionLevelOff) {
5287 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
5288 }
5289 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
5290 kIOPMDriverAssertionLevelOff) {
5291 currentFactors |= kIOPMSleepFactorThunderboltDevice;
5292 }
5293 if (_scheduledAlarmMask != 0) {
5294 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
5295 }
5296 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
5297 kIOPMDriverAssertionLevelOff) {
5298 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
5299 }
5300#define TCPKEEPALIVE 1
5301#if TCPKEEPALIVE
5302 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
5303 kIOPMDriverAssertionLevelOff) {
5304 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
5305 }
5306#endif
5307 if (!powerOffEnabled) {
5308 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
5309 }
5310 if (desktopMode) {
5311 currentFactors |= kIOPMSleepFactorExternalDisplay;
5312 }
5313 if (userWasActive) {
5314 currentFactors |= kIOPMSleepFactorLocalUserActivity;
5315 }
5316 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
5317 currentFactors |= kIOPMSleepFactorHibernateFailed;
5318 }
5319 if (thermalWarningState) {
5320 currentFactors |= kIOPMSleepFactorThermalWarning;
5321 }
5322
5323 for (int factorBit = 0; factorBit < (8 * sizeof(uint32_t)); factorBit++) {
5324 uint32_t factor = 1 << factorBit;
5325 if (factor & currentFactors) {
5326 strlcat(currentFactorsBuf, ", ", sizeof(currentFactorsBuf));
5327 strlcat(currentFactorsBuf, IOFindNameForValue(factor, factorValues), sizeof(currentFactorsBuf));
5328 }
5329 }
5330 DLOG("sleep factors 0x%llx%s\n", currentFactors, currentFactorsBuf);
5331
5332 if (gSleepPolicyHandler) {
5333 uint32_t savedHibernateMode;
5334 IOReturn result;
5335
5336 if (!gSleepPolicyVars) {
5337 gSleepPolicyVars = IOMallocType(IOPMSystemSleepPolicyVariables);
5338 }
5339 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
5340 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
5341 gSleepPolicyVars->currentCapability = _currentCapability;
5342 gSleepPolicyVars->highestCapability = _highestCapability;
5343 gSleepPolicyVars->sleepFactors = currentFactors;
5344 gSleepPolicyVars->sleepReason = lastSleepReason;
5345 gSleepPolicyVars->sleepPhase = sleepPhase;
5346 gSleepPolicyVars->standbyDelay = standbyDelay;
5347 gSleepPolicyVars->standbyTimer = standbyTimer;
5348 gSleepPolicyVars->poweroffDelay = powerOffDelay;
5349 gSleepPolicyVars->scheduledAlarms = _scheduledAlarmMask | _userScheduledAlarmMask;
5350 gSleepPolicyVars->poweroffTimer = powerOffTimer;
5351
5352 if (kIOPMSleepPhase0 == sleepPhase) {
5353 // preserve hibernateMode
5354 savedHibernateMode = gSleepPolicyVars->hibernateMode;
5355 gSleepPolicyVars->hibernateMode = *hibMode;
5356 } else if (kIOPMSleepPhase1 == sleepPhase) {
5357 // use original hibernateMode for phase2
5358 gSleepPolicyVars->hibernateMode = *hibMode;
5359 }
5360
5361 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
5362
5363 if (kIOPMSleepPhase0 == sleepPhase) {
5364 // restore hibernateMode
5365 gSleepPolicyVars->hibernateMode = savedHibernateMode;
5366 }
5367
5368 if ((result != kIOReturnSuccess) ||
5369 (kIOPMSleepTypeInvalid == params->sleepType) ||
5370 (params->sleepType >= kIOPMSleepTypeLast) ||
5371 (kIOPMSystemSleepParametersVersion != params->version)) {
5372 MSG("sleep policy handler error\n");
5373 goto done;
5374 }
5375
5376 if ((getSleepTypeAttributes(params->sleepType) &
5377 kIOPMSleepAttributeHibernateSetup) &&
5378 ((*hibMode & kIOHibernateModeOn) == 0)) {
5379 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
5380 }
5381
5382 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
5383 params->version, params->sleepType, params->sleepFlags,
5384 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
5385 found = true;
5386 goto done;
5387 }
5388
5389 // Policy table is meaningless without standby enabled
5390 if (!standbyEnabled) {
5391 goto done;
5392 }
5393
5394 // Validate the sleep policy table
5395 policyData = OSDynamicCast(OSData, prop.get());
5396 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable))) {
5397 goto done;
5398 }
5399
5400 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
5401 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
5402 (pt->version != 1) || (0 == pt->entryCount)) {
5403 goto done;
5404 }
5405
5406 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
5407 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))) {
5408 goto done;
5409 }
5410
5411 for (uint32_t i = 0; i < pt->entryCount; i++) {
5412 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
5413 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
5414
5415 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
5416 entry->factorMask, entry->factorBits,
5417 entry->sleepFlags, entry->wakeEvents, mismatch);
5418 if (mismatch) {
5419 continue;
5420 }
5421
5422 DLOG("^ found match\n");
5423 found = true;
5424
5425 params->version = kIOPMSystemSleepParametersVersion;
5426 params->reserved1 = 1;
5427 if (entry->sleepFlags & kIOPMSleepFlagHibernate) {
5428 params->sleepType = kIOPMSleepTypeStandby;
5429 } else {
5430 params->sleepType = kIOPMSleepTypeNormalSleep;
5431 }
5432
5433 params->ecWakeEvents = entry->wakeEvents;
5434 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable) {
5435 if (kIOPMSleepPhase2 == sleepPhase) {
5436 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
5437
5438 if (!_standbyTimerResetSeconds ||
5439 (now_secs <= _standbyTimerResetSeconds)) {
5440 // Reset standby timer adjustment
5441 _standbyTimerResetSeconds = now_secs;
5442 DLOG("standby delay %u, reset %u\n",
5443 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
5444 } else if (standbyDelay) {
5445 // Shorten the standby delay timer
5446 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
5447 if (standbyDelay > elapsed) {
5448 standbyDelay -= elapsed;
5449 } else {
5450 standbyDelay = 1; // must be > 0
5451 }
5452 DLOG("standby delay %u, elapsed %u\n",
5453 standbyDelay, (uint32_t) elapsed);
5454 }
5455 }
5456 params->ecWakeTimer = standbyDelay;
5457 } else if (kIOPMSleepPhase2 == sleepPhase) {
5458 // A sleep that does not enable the sleep timer will reset
5459 // the standby delay adjustment.
5460 _standbyTimerResetSeconds = 0;
5461 }
5462 break;
5463 }
5464
5465done:
5466 return found;
5467}
5468
5469static IOPMSystemSleepParameters gEarlySystemSleepParams;
5470
5471void
5472IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
5473{
5474 // Evaluate early (priority interest phase), before drivers sleep.
5475
5476 DLOG("%s\n", __FUNCTION__);
5477 removeProperty(kIOPMSystemSleepParametersKey);
5478
5479 // Full wake resets the standby timer delay adjustment
5480 if (_highestCapability & kIOPMSystemCapabilityGraphics) {
5481 _standbyTimerResetSeconds = 0;
5482 }
5483
5484 hibernateDisabled = false;
5485 hibernateMode = 0;
5486 getSleepOption(kIOHibernateModeKey, &hibernateMode);
5487
5488 // Save for late evaluation if sleep is aborted
5489 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
5490
5491 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
5492 &hibernateMode)) {
5493 if (!hibernateRetry &&
5494 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
5495 kIOPMSleepAttributeHibernateSetup) == 0)) {
5496 // skip hibernate setup
5497 hibernateDisabled = true;
5498 }
5499 }
5500
5501 // Publish IOPMSystemSleepType
5502 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
5503 if (sleepType == kIOPMSleepTypeInvalid) {
5504 // no sleep policy
5505 sleepType = kIOPMSleepTypeNormalSleep;
5506 if (hibernateMode & kIOHibernateModeOn) {
5507 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
5508 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
5509 }
5510 } else if ((sleepType == kIOPMSleepTypeStandby) &&
5511 (gEarlySystemSleepParams.ecPoweroffTimer)) {
5512 // report the lowest possible sleep state
5513 sleepType = kIOPMSleepTypePowerOff;
5514 }
5515
5516 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
5517}
5518
5519void
5520IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
5521{
5522 IOPMSystemSleepParameters params;
5523 OSSharedPtr<OSData> paramsData;
5524 bool wakeNow;
5525 // Evaluate sleep policy after sleeping drivers but before platform sleep.
5526
5527 DLOG("%s\n", __FUNCTION__);
5528
5529 bzero(&params, sizeof(params));
5530 wakeNow = false;
5531 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode)) {
5532 if ((kIOPMSleepTypeStandby == params.sleepType)
5533 && gIOHibernateStandbyDisabled && gSleepPolicyVars
5534 && (!((kIOPMSleepFactorStandbyForced | kIOPMSleepFactorAutoPowerOffForced | kIOPMSleepFactorHibernateForced)
5535 & gSleepPolicyVars->sleepFactors))) {
5536 standbyNixed = true;
5537 wakeNow = true;
5538 }
5539 if (wakeNow
5540 || ((hibernateDisabled || hibernateAborted) &&
5541 (getSleepTypeAttributes(params.sleepType) &
5542 kIOPMSleepAttributeHibernateSetup))) {
5543 // Final evaluation picked a state requiring hibernation,
5544 // but hibernate isn't going to proceed. Arm a short sleep using
5545 // the early non-hibernate sleep parameters.
5546 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
5547 params.sleepType = kIOPMSleepTypeAbortedSleep;
5548 params.ecWakeTimer = 1;
5549 if (standbyNixed) {
5550 resetTimers = true;
5551 } else {
5552 // Set hibernateRetry flag to force hibernate setup on the
5553 // next sleep.
5554 hibernateRetry = true;
5555 }
5556 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
5557 params.ecWakeTimer, hibernateDisabled, hibernateAborted, standbyNixed);
5558 } else {
5559 hibernateRetry = false;
5560 }
5561
5562 if (kIOPMSleepTypeAbortedSleep != params.sleepType) {
5563 resetTimers = false;
5564 }
5565
5566 paramsData = OSData::withValue(params);
5567 if (paramsData) {
5568 setProperty(kIOPMSystemSleepParametersKey, paramsData.get());
5569 }
5570
5571 if (getSleepTypeAttributes(params.sleepType) &
5572 kIOPMSleepAttributeHibernateSleep) {
5573 // Disable sleep to force hibernation
5574 gIOHibernateMode &= ~kIOHibernateModeSleep;
5575 }
5576 }
5577}
5578
5579bool
5580IOPMrootDomain::getHibernateSettings(
5581 uint32_t * hibernateModePtr,
5582 uint32_t * hibernateFreeRatio,
5583 uint32_t * hibernateFreeTime )
5584{
5585 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
5586 // has updated the hibernateDisabled flag.
5587
5588 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
5589 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
5590 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
5591 if (hibernateDisabled) {
5592 *hibernateModePtr = 0;
5593 } else if (gSleepPolicyHandler) {
5594 *hibernateModePtr = hibernateMode;
5595 }
5596 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
5597 return ok;
5598}
5599
5600bool
5601IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
5602{
5603 OSSharedPtr<OSObject> optionsProp;
5604 OSDictionary * optionsDict;
5605 OSSharedPtr<OSObject> obj;
5606 OSNumber * num;
5607 bool ok = false;
5608
5609 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
5610 optionsDict = OSDynamicCast(OSDictionary, optionsProp.get());
5611
5612 if (optionsDict) {
5613 obj.reset(optionsDict->getObject(key), OSRetain);
5614 }
5615 if (!obj) {
5616 obj = copyProperty(key);
5617 }
5618 if (obj) {
5619 if ((num = OSDynamicCast(OSNumber, obj.get()))) {
5620 *option = num->unsigned32BitValue();
5621 ok = true;
5622 } else if (OSDynamicCast(OSBoolean, obj.get())) {
5623 *option = (obj == kOSBooleanTrue) ? 1 : 0;
5624 ok = true;
5625 }
5626 }
5627
5628 return ok;
5629}
5630#endif /* HIBERNATION */
5631
5632IOReturn
5633IOPMrootDomain::getSystemSleepType( uint32_t * sleepType, uint32_t * standbyTimer )
5634{
5635#if HIBERNATION
5636 IOPMSystemSleepParameters params;
5637 uint32_t hibMode = 0;
5638 bool ok;
5639
5640 if (gIOPMWorkLoop->inGate() == false) {
5641 IOReturn ret = gIOPMWorkLoop->runAction(
5642 OSMemberFunctionCast(IOWorkLoop::Action, this,
5643 &IOPMrootDomain::getSystemSleepType),
5644 (OSObject *) this,
5645 (void *) sleepType, (void *) standbyTimer);
5646 return ret;
5647 }
5648
5649 getSleepOption(kIOHibernateModeKey, &hibMode);
5650 bzero(&params, sizeof(params));
5651
5652 ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
5653 if (ok) {
5654 *sleepType = params.sleepType;
5655 if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer) &&
5656 !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
5657 DLOG("Standby delay is not set\n");
5658 *standbyTimer = 0;
5659 }
5660 return kIOReturnSuccess;
5661 }
5662#endif
5663
5664 return kIOReturnUnsupported;
5665}
5666
5667// MARK: -
5668// MARK: Shutdown and Restart
5669
5670//******************************************************************************
5671// handlePlatformHaltRestart
5672//
5673//******************************************************************************
5674
5675// Phases while performing shutdown/restart
5676typedef enum {
5677 kNotifyDone = 0x00,
5678 kNotifyPriorityClients = 0x10,
5679 kNotifyPowerPlaneDrivers = 0x20,
5680 kNotifyHaltRestartAction = 0x30,
5681 kQuiescePM = 0x40,
5682} shutdownPhase_t;
5683
5684
5685struct HaltRestartApplierContext {
5686 IOPMrootDomain * RootDomain;
5687 unsigned long PowerState;
5688 IOPMPowerFlags PowerFlags;
5689 UInt32 MessageType;
5690 UInt32 Counter;
5691 const char * LogString;
5692 shutdownPhase_t phase;
5693
5694 IOServiceInterestHandler handler;
5695} gHaltRestartCtx;
5696
5697const char *
5698shutdownPhase2String(shutdownPhase_t phase)
5699{
5700 switch (phase) {
5701 case kNotifyDone:
5702 return "Notifications completed";
5703 case kNotifyPriorityClients:
5704 return "Notifying priority clients";
5705 case kNotifyPowerPlaneDrivers:
5706 return "Notifying power plane drivers";
5707 case kNotifyHaltRestartAction:
5708 return "Notifying HaltRestart action handlers";
5709 case kQuiescePM:
5710 return "Quiescing PM";
5711 default:
5712 return "Unknown";
5713 }
5714}
5715
5716static void
5717platformHaltRestartApplier( OSObject * object, void * context )
5718{
5719 IOPowerStateChangeNotification notify;
5720 HaltRestartApplierContext * ctx;
5721 AbsoluteTime startTime, elapsedTime;
5722 uint32_t deltaTime;
5723
5724 ctx = (HaltRestartApplierContext *) context;
5725
5726 _IOServiceInterestNotifier * notifier;
5727 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5728 memset(s: &notify, c: 0, n: sizeof(notify));
5729 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
5730 notify.returnValue = 0;
5731 notify.stateNumber = ctx->PowerState;
5732 notify.stateFlags = ctx->PowerFlags;
5733
5734 if (notifier) {
5735 ctx->handler = notifier->handler;
5736 }
5737
5738 clock_get_uptime(result: &startTime);
5739 ctx->RootDomain->messageClient( messageType: ctx->MessageType, client: object, messageArgument: (void *)&notify );
5740 deltaTime = computeDeltaTimeMS(startTime: &startTime, elapsedTime: &elapsedTime);
5741
5742 if ((deltaTime > kPMHaltTimeoutMS) && notifier) {
5743 LOG("%s handler %p took %u ms\n",
5744 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
5745 halt_log_enter(what: "PowerOff/Restart message to priority client", pc: (const void *) notifier->handler, time: elapsedTime);
5746 }
5747
5748 ctx->handler = NULL;
5749 ctx->Counter++;
5750}
5751
5752static void
5753quiescePowerTreeCallback( void * target, void * param )
5754{
5755 IOLockLock(gPMHaltLock);
5756 gPMQuiesced = true;
5757 thread_wakeup(param);
5758 IOLockUnlock(gPMHaltLock);
5759}
5760
5761void
5762IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
5763{
5764 AbsoluteTime startTime, elapsedTime;
5765 uint32_t deltaTime;
5766 bool nvramSync = false;
5767
5768 memset(s: &gHaltRestartCtx, c: 0, n: sizeof(gHaltRestartCtx));
5769 gHaltRestartCtx.RootDomain = this;
5770
5771 clock_get_uptime(result: &startTime);
5772 switch (pe_type) {
5773 case kPEHaltCPU:
5774 case kPEUPSDelayHaltCPU:
5775 gHaltRestartCtx.PowerState = OFF_STATE;
5776 gHaltRestartCtx.MessageType = kIOMessageSystemWillPowerOff;
5777 gHaltRestartCtx.LogString = "PowerOff";
5778 nvramSync = true;
5779 break;
5780
5781 case kPERestartCPU:
5782 gHaltRestartCtx.PowerState = RESTART_STATE;
5783 gHaltRestartCtx.MessageType = kIOMessageSystemWillRestart;
5784 gHaltRestartCtx.LogString = "Restart";
5785 nvramSync = true;
5786 break;
5787
5788 case kPEPagingOff:
5789 gHaltRestartCtx.PowerState = ON_STATE;
5790 gHaltRestartCtx.MessageType = kIOMessageSystemPagingOff;
5791 gHaltRestartCtx.LogString = "PagingOff";
5792 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
5793#if HIBERNATION
5794 IOHibernateSystemRestart();
5795#endif
5796 break;
5797
5798 default:
5799 return;
5800 }
5801
5802 if (nvramSync) {
5803 PESyncNVRAM();
5804 }
5805
5806 gHaltRestartCtx.phase = kNotifyPriorityClients;
5807 // Notify legacy clients
5808 applyToInterested(typeOfInterest: gIOPriorityPowerStateInterest, applier: platformHaltRestartApplier, context: &gHaltRestartCtx);
5809
5810 // For normal shutdown, turn off File Server Mode.
5811 if (kPEHaltCPU == pe_type) {
5812 OSSharedPtr<const OSSymbol> setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
5813 OSSharedPtr<OSNumber> num = OSNumber::withNumber(value: (unsigned long long) 0, numberOfBits: 32);
5814 if (setting && num) {
5815 setPMSetting(type: setting.get(), object: num.get());
5816 }
5817 }
5818
5819 if (kPEPagingOff != pe_type) {
5820 gHaltRestartCtx.phase = kNotifyPowerPlaneDrivers;
5821 // Notify in power tree order
5822 notifySystemShutdown(root: this, messageType: gHaltRestartCtx.MessageType);
5823 }
5824
5825 gHaltRestartCtx.phase = kNotifyHaltRestartAction;
5826#if defined(XNU_TARGET_OS_OSX)
5827 IOCPURunPlatformHaltRestartActions(message: pe_type);
5828#else /* !defined(XNU_TARGET_OS_OSX) */
5829 if (kPEPagingOff != pe_type) {
5830 IOCPURunPlatformHaltRestartActions(pe_type);
5831 }
5832#endif /* !defined(XNU_TARGET_OS_OSX) */
5833
5834 // Wait for PM to quiesce
5835 if ((kPEPagingOff != pe_type) && gPMHaltLock) {
5836 gHaltRestartCtx.phase = kQuiescePM;
5837 AbsoluteTime quiesceTime = mach_absolute_time();
5838
5839 IOLockLock(gPMHaltLock);
5840 gPMQuiesced = false;
5841 if (quiescePowerTree(target: this, action: &quiescePowerTreeCallback, param: &gPMQuiesced) ==
5842 kIOReturnSuccess) {
5843 while (!gPMQuiesced) {
5844 IOLockSleep(lock: gPMHaltLock, event: &gPMQuiesced, THREAD_UNINT);
5845 }
5846 }
5847 IOLockUnlock(gPMHaltLock);
5848 deltaTime = computeDeltaTimeMS(startTime: &quiesceTime, elapsedTime: &elapsedTime);
5849 DLOG("PM quiesce took %u ms\n", deltaTime);
5850 halt_log_enter(what: "Quiesce", NULL, time: elapsedTime);
5851 }
5852 gHaltRestartCtx.phase = kNotifyDone;
5853
5854 deltaTime = computeDeltaTimeMS(startTime: &startTime, elapsedTime: &elapsedTime);
5855 LOG("%s all drivers took %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5856
5857 halt_log_enter(what: gHaltRestartCtx.LogString, NULL, time: elapsedTime);
5858
5859 deltaTime = computeDeltaTimeMS(startTime: &gHaltStartTime, elapsedTime: &elapsedTime);
5860 LOG("%s total %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5861
5862 if (gHaltLog && gHaltTimeMaxLog && (deltaTime >= gHaltTimeMaxLog)) {
5863 printf("%s total %d ms:%s\n", gHaltRestartCtx.LogString, deltaTime, gHaltLog);
5864 }
5865
5866 checkShutdownTimeout();
5867}
5868
5869bool
5870IOPMrootDomain::checkShutdownTimeout()
5871{
5872 AbsoluteTime elapsedTime;
5873 uint32_t deltaTime = computeDeltaTimeMS(startTime: &gHaltStartTime, elapsedTime: &elapsedTime);
5874
5875 if (gHaltTimeMaxPanic && (deltaTime >= gHaltTimeMaxPanic)) {
5876 return true;
5877 }
5878 return false;
5879}
5880
5881void
5882IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs)
5883{
5884 if (gHaltLog) {
5885 if ((gHaltRestartCtx.phase == kNotifyPriorityClients) && gHaltRestartCtx.handler) {
5886 halt_log_enter(what: "Blocked on priority client", pc: (void *)gHaltRestartCtx.handler, time: mach_absolute_time() - gHaltStartTime);
5887 }
5888 panic("%s timed out in phase '%s'. Total %d ms:%s",
5889 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs, gHaltLog);
5890 } else {
5891 panic("%s timed out in phase \'%s\'. Total %d ms",
5892 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs);
5893 }
5894}
5895
5896//******************************************************************************
5897// shutdownSystem
5898//
5899//******************************************************************************
5900
5901IOReturn
5902IOPMrootDomain::shutdownSystem( void )
5903{
5904 return kIOReturnUnsupported;
5905}
5906
5907//******************************************************************************
5908// restartSystem
5909//
5910//******************************************************************************
5911
5912IOReturn
5913IOPMrootDomain::restartSystem( void )
5914{
5915 return kIOReturnUnsupported;
5916}
5917
5918// MARK: -
5919// MARK: System Capability
5920
5921//******************************************************************************
5922// tagPowerPlaneService
5923//
5924// Running on PM work loop thread.
5925//******************************************************************************
5926
5927void
5928IOPMrootDomain::tagPowerPlaneService(
5929 IOService * service,
5930 IOPMActions * actions,
5931 IOPMPowerStateIndex maxPowerState )
5932{
5933 uint32_t flags = 0;
5934
5935 memset(s: actions, c: 0, n: sizeof(*actions));
5936 actions->target = this;
5937
5938 if (service == this) {
5939 actions->actionPowerChangeStart =
5940 OSMemberFunctionCast(
5941 IOPMActionPowerChangeStart, this,
5942 &IOPMrootDomain::handleOurPowerChangeStart);
5943
5944 actions->actionPowerChangeDone =
5945 OSMemberFunctionCast(
5946 IOPMActionPowerChangeDone, this,
5947 &IOPMrootDomain::handleOurPowerChangeDone);
5948
5949 actions->actionPowerChangeOverride =
5950 OSMemberFunctionCast(
5951 IOPMActionPowerChangeOverride, this,
5952 &IOPMrootDomain::overrideOurPowerChange);
5953 return;
5954 }
5955
5956#if DISPLAY_WRANGLER_PRESENT
5957 if (NULL != service->metaCast("IODisplayWrangler")) {
5958 // XXX should this really retain?
5959 wrangler.reset(service, OSRetain);
5960 wrangler->registerInterest(gIOGeneralInterest,
5961 &displayWranglerNotification, this, NULL);
5962
5963 // found the display wrangler, check for any display assertions already created
5964 if (pmAssertions->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit) {
5965 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
5966 wrangler->setIgnoreIdleTimer( true );
5967 }
5968 flags |= kPMActionsFlagIsDisplayWrangler;
5969 }
5970#endif /* DISPLAY_WRANGLER_PRESENT */
5971
5972 if (service->propertyExists(aKey: "IOPMStrictTreeOrder")) {
5973 flags |= kPMActionsFlagIsGraphicsDriver;
5974 }
5975 if (service->propertyExists(aKey: "IOPMUnattendedWakePowerState")) {
5976 flags |= kPMActionsFlagIsAudioDriver;
5977 }
5978
5979 // Find the power connection object that is a child of the PCI host
5980 // bridge, and has a graphics/audio device attached below. Mark the
5981 // power branch for delayed child notifications.
5982
5983 if (flags) {
5984 IORegistryEntry * child = service;
5985 IORegistryEntry * parent = child->getParentEntry(plane: gIOPowerPlane);
5986
5987 while (child != this) {
5988 if (child->propertyHasValue(aKey: "IOPCITunnelled", value: kOSBooleanTrue)) {
5989 // Skip delaying notifications and clamping power on external graphics and audio devices.
5990 DLOG("Avoiding delayChildNotification on object 0x%llx. flags: 0x%x\n", service->getRegistryEntryID(), flags);
5991 flags = 0;
5992 break;
5993 }
5994 if ((parent == pciHostBridgeDriver) ||
5995 (parent == this)) {
5996 if (OSDynamicCast(IOPowerConnection, child)) {
5997 IOPowerConnection * conn = (IOPowerConnection *) child;
5998 conn->delayChildNotification = true;
5999 DLOG("delayChildNotification for 0x%llx\n", conn->getRegistryEntryID());
6000 }
6001 break;
6002 }
6003 child = parent;
6004 parent = child->getParentEntry(plane: gIOPowerPlane);
6005 }
6006 }
6007
6008 OSSharedPtr<OSObject> prop = service->copyProperty(kIOPMDarkWakeMaxPowerStateKey);
6009 if (prop) {
6010 OSNumber * num = OSDynamicCast(OSNumber, prop.get());
6011 if (num) {
6012 actions->darkWakePowerState = num->unsigned32BitValue();
6013 if (actions->darkWakePowerState < maxPowerState) {
6014 flags |= kPMActionsFlagHasDarkWakePowerState;
6015 }
6016 }
6017 }
6018
6019
6020 if (flags) {
6021 DLOG("%s tag flags %x\n", service->getName(), flags);
6022 actions->flags |= flags;
6023 actions->actionPowerChangeOverride =
6024 OSMemberFunctionCast(
6025 IOPMActionPowerChangeOverride, this,
6026 &IOPMrootDomain::overridePowerChangeForService);
6027
6028 if (flags & kPMActionsFlagIsDisplayWrangler) {
6029 actions->actionActivityTickle =
6030 OSMemberFunctionCast(
6031 IOPMActionActivityTickle, this,
6032 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
6033
6034 actions->actionUpdatePowerClient =
6035 OSMemberFunctionCast(
6036 IOPMActionUpdatePowerClient, this,
6037 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
6038 }
6039 return;
6040 }
6041
6042 // Locate the first PCI host bridge for PMTrace.
6043 if (!pciHostBridgeDevice && service->metaCast(toMeta: "IOPCIBridge")) {
6044 IOService * provider = service->getProvider();
6045 if (OSDynamicCast(IOPlatformDevice, provider) &&
6046 provider->inPlane(plane: gIODTPlane)) {
6047 pciHostBridgeDevice.reset(p: provider, OSNoRetain);
6048 pciHostBridgeDriver.reset(p: service, OSNoRetain);
6049 DLOG("PMTrace found PCI host bridge %s->%s\n",
6050 provider->getName(), service->getName());
6051 }
6052 }
6053
6054 // Tag top-level PCI devices. The order of PMinit() call does not
6055 // change across boots and is used as the PCI bit number.
6056 if (pciHostBridgeDevice && service->metaCast(toMeta: "IOPCIDevice")) {
6057 // Would prefer to check built-in property, but tagPowerPlaneService()
6058 // is called before pciDevice->registerService().
6059 IORegistryEntry * parent = service->getParentEntry(plane: gIODTPlane);
6060 if ((parent == pciHostBridgeDevice) && service->propertyExists(aKey: "acpi-device")) {
6061 int bit = pmTracer->recordTopLevelPCIDevice( service );
6062 if (bit >= 0) {
6063 // Save the assigned bit for fast lookup.
6064 actions->flags |= (bit & kPMActionsPCIBitNumberMask);
6065
6066 actions->actionPowerChangeStart =
6067 OSMemberFunctionCast(
6068 IOPMActionPowerChangeStart, this,
6069 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
6070
6071 actions->actionPowerChangeDone =
6072 OSMemberFunctionCast(
6073 IOPMActionPowerChangeDone, this,
6074 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
6075 }
6076 }
6077 }
6078}
6079
6080//******************************************************************************
6081// PM actions for root domain
6082//******************************************************************************
6083
6084void
6085IOPMrootDomain::overrideOurPowerChange(
6086 IOService * service,
6087 IOPMActions * actions,
6088 const IOPMRequest * request,
6089 IOPMPowerStateIndex * inOutPowerState,
6090 IOPMPowerChangeFlags * inOutChangeFlags )
6091{
6092 uint32_t changeFlags = *inOutChangeFlags;
6093 uint32_t desiredPowerState = (uint32_t) *inOutPowerState;
6094 uint32_t currentPowerState = (uint32_t) getPowerState();
6095
6096 if (request->getTag() == 0) {
6097 // Set a tag for any request that originates from IOServicePM
6098 (const_cast<IOPMRequest *>(request))->fTag = nextRequestTag(tag: kCPSReasonPMInternals);
6099 }
6100
6101 DLOG("PowerChangeOverride (%s->%s, %x, 0x%x) tag 0x%x\n",
6102 getPowerStateString(currentPowerState),
6103 getPowerStateString(desiredPowerState),
6104 _currentCapability, changeFlags,
6105 request->getTag());
6106
6107
6108#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6109 /*
6110 * ASBM send lowBattery notifications every 1 second until the device
6111 * enters hibernation. This queues up multiple sleep requests.
6112 * After the device wakes from hibernation, none of these previously
6113 * queued sleep requests are valid.
6114 * lowBattteryCondition variable is set when ASBM notifies rootDomain
6115 * and is cleared at the very last point in sleep.
6116 * Any attempt to sleep with reason kIOPMSleepReasonLowPower without
6117 * lowBatteryCondition is invalid
6118 */
6119 if (REQUEST_TAG_TO_REASON(request->getTag()) == kIOPMSleepReasonLowPower) {
6120 if (!lowBatteryCondition) {
6121 DLOG("Duplicate lowBattery sleep");
6122 *inOutChangeFlags |= kIOPMNotDone;
6123 return;
6124 }
6125 }
6126#endif
6127
6128 if ((AOT_STATE == desiredPowerState) && (ON_STATE == currentPowerState)) {
6129 // Assertion may have been taken in AOT leading to changePowerStateTo(AOT)
6130 *inOutChangeFlags |= kIOPMNotDone;
6131 return;
6132 }
6133
6134 if (changeFlags & kIOPMParentInitiated) {
6135 // Root parent is permanently pegged at max power,
6136 // a parent initiated power change is unexpected.
6137 *inOutChangeFlags |= kIOPMNotDone;
6138 return;
6139 }
6140
6141 if (desiredPowerState < currentPowerState) {
6142 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
6143 // Root domain is dropping power state from ON->SLEEP.
6144 // If system is in full wake, first enter dark wake by
6145 // converting the power drop to a capability change.
6146 // Once in dark wake, transition to sleep state ASAP.
6147
6148 darkWakeToSleepASAP = true;
6149
6150 // Drop graphics and audio capability
6151 _desiredCapability &= ~(
6152 kIOPMSystemCapabilityGraphics |
6153 kIOPMSystemCapabilityAudio);
6154
6155 // Convert to capability change (ON->ON)
6156 *inOutPowerState = getRUN_STATE();
6157 *inOutChangeFlags |= kIOPMSynchronize;
6158
6159 // Revert device desire from SLEEP to ON
6160 changePowerStateWithTagToPriv(ordinal: getRUN_STATE(), reason: kCPSReasonPowerOverride);
6161 } else {
6162 // System is already in dark wake, ok to drop power state.
6163 // Broadcast root power down to entire tree.
6164 *inOutChangeFlags |= kIOPMRootChangeDown;
6165 }
6166 } else if (desiredPowerState > currentPowerState) {
6167 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0) {
6168 // Broadcast power up when waking from sleep, but not for the
6169 // initial power change at boot by checking for cpu capability.
6170 *inOutChangeFlags |= kIOPMRootChangeUp;
6171 }
6172 }
6173}
6174
6175void
6176IOPMrootDomain::handleOurPowerChangeStart(
6177 IOService * service,
6178 IOPMActions * actions,
6179 const IOPMRequest * request,
6180 IOPMPowerStateIndex newPowerState,
6181 IOPMPowerChangeFlags * inOutChangeFlags )
6182{
6183 IOPMRequestTag requestTag = request->getTag();
6184 IOPMRequestTag sleepReason;
6185
6186 uint32_t changeFlags = *inOutChangeFlags;
6187 uint32_t currentPowerState = (uint32_t) getPowerState();
6188 bool publishSleepReason = false;
6189
6190 // Check if request has a valid sleep reason
6191 sleepReason = REQUEST_TAG_TO_REASON(requestTag);
6192 if (sleepReason < kIOPMSleepReasonClamshell) {
6193 sleepReason = kIOPMSleepReasonIdle;
6194 }
6195
6196 _systemTransitionType = kSystemTransitionNone;
6197 _systemMessageClientMask = 0;
6198 capabilityLoss = false;
6199 toldPowerdCapWillChange = false;
6200
6201 // Emergency notifications may arrive after the initial sleep request
6202 // has been queued. Override the sleep reason so powerd and others can
6203 // treat this as an emergency sleep.
6204 if (lowBatteryCondition) {
6205 sleepReason = kIOPMSleepReasonLowPower;
6206 } else if (thermalEmergencyState) {
6207 sleepReason = kIOPMSleepReasonThermalEmergency;
6208 }
6209
6210 // 1. Explicit capability change.
6211 if (changeFlags & kIOPMSynchronize) {
6212 if (newPowerState == ON_STATE) {
6213 if (changeFlags & kIOPMSyncNoChildNotify) {
6214 _systemTransitionType = kSystemTransitionNewCapClient;
6215 } else {
6216 _systemTransitionType = kSystemTransitionCapability;
6217 }
6218 }
6219 }
6220 // 2. Going to sleep (cancellation still possible).
6221 else if (newPowerState < currentPowerState) {
6222 _systemTransitionType = kSystemTransitionSleep;
6223 }
6224 // 3. Woke from (idle or demand) sleep.
6225 else if (!systemBooting &&
6226 (changeFlags & kIOPMSelfInitiated) &&
6227 (newPowerState > currentPowerState)) {
6228 _systemTransitionType = kSystemTransitionWake;
6229 _desiredCapability = kIOPMSystemCapabilityCPU | kIOPMSystemCapabilityNetwork;
6230
6231 // Early exit from dark wake to full (e.g. LID open)
6232 if (kFullWakeReasonNone != fullWakeReason) {
6233 _desiredCapability |= (
6234 kIOPMSystemCapabilityGraphics |
6235 kIOPMSystemCapabilityAudio);
6236
6237#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6238 if (fullWakeReason == kFullWakeReasonLocalUser) {
6239 darkWakeExit = true;
6240 darkWakeToSleepASAP = false;
6241 setProperty(kIOPMRootDomainWakeTypeKey, aString: isRTCAlarmWake ?
6242 kIOPMRootDomainWakeTypeAlarm : kIOPMRootDomainWakeTypeUser);
6243 }
6244#endif
6245 }
6246#if HIBERNATION
6247 IOHibernateSetWakeCapabilities(_desiredCapability);
6248#endif
6249 }
6250
6251 // Update pending wake capability at the beginning of every
6252 // state transition (including synchronize). This will become
6253 // the current capability at the end of the transition.
6254
6255 if (kSystemTransitionSleep == _systemTransitionType) {
6256 _pendingCapability = 0;
6257 capabilityLoss = true;
6258 } else if (kSystemTransitionNewCapClient != _systemTransitionType) {
6259 _pendingCapability = _desiredCapability |
6260 kIOPMSystemCapabilityCPU |
6261 kIOPMSystemCapabilityNetwork;
6262
6263 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6264 _pendingCapability |= kIOPMSystemCapabilityAudio;
6265 }
6266
6267 if ((kSystemTransitionCapability == _systemTransitionType) &&
6268 (_pendingCapability == _currentCapability)) {
6269 // Cancel the PM state change.
6270 _systemTransitionType = kSystemTransitionNone;
6271 *inOutChangeFlags |= kIOPMNotDone;
6272 }
6273 if (__builtin_popcount(_pendingCapability) <
6274 __builtin_popcount(_currentCapability)) {
6275 capabilityLoss = true;
6276 }
6277 }
6278
6279 // 1. Capability change.
6280 if (kSystemTransitionCapability == _systemTransitionType) {
6281 // Dark to Full transition.
6282 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
6283 tracePoint( point: kIOPMTracePointDarkWakeExit );
6284
6285#if defined(XNU_TARGET_OS_OSX)
6286 // rdar://problem/65627936
6287 // When a dark->full wake promotion is scheduled before an ON->SLEEP
6288 // power state drop, invalidate any request to drop power state already
6289 // in the queue, including the override variant, unless full wake cannot
6290 // be sustained. Any power state drop queued after this SustainFullWake
6291 // request will not be affected.
6292 if (checkSystemCanSustainFullWake()) {
6293 changePowerStateWithOverrideTo(ordinal: getRUN_STATE(), reason: kCPSReasonSustainFullWake);
6294 }
6295#endif
6296
6297 willEnterFullWake();
6298 }
6299
6300 // Full to Dark transition.
6301 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
6302 // Clear previous stats
6303 IOLockLock(pmStatsLock);
6304 if (pmStatsAppResponses) {
6305 pmStatsAppResponses = OSArray::withCapacity(capacity: 5);
6306 }
6307 IOLockUnlock(pmStatsLock);
6308
6309 tracePoint( point: kIOPMTracePointDarkWakeEntry );
6310 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
6311 _systemMessageClientMask = kSystemMessageClientPowerd |
6312 kSystemMessageClientLegacyApp;
6313
6314 // rdar://15971327
6315 // Prevent user active transitions before notifying clients
6316 // that system will sleep.
6317 preventTransitionToUserActive(prevent: true);
6318
6319 IOService::setAdvisoryTickleEnable( false );
6320
6321 // Publish the sleep reason for full to dark wake
6322 publishSleepReason = true;
6323 lastSleepReason = fullToDarkReason = sleepReason;
6324
6325 // Publish a UUID for the Sleep --> Wake cycle
6326 handlePublishSleepWakeUUID(shouldPublish: true);
6327 if (sleepDelaysReport) {
6328 clock_get_uptime(result: &ts_sleepStart);
6329 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
6330 }
6331
6332 darkWakeExit = false;
6333 }
6334 }
6335 // 2. System sleep.
6336 else if (kSystemTransitionSleep == _systemTransitionType) {
6337 // Beginning of a system sleep transition.
6338 // Cancellation is still possible.
6339 tracePoint( point: kIOPMTracePointSleepStarted );
6340
6341 _systemMessageClientMask = kSystemMessageClientAll;
6342 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) {
6343 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
6344 }
6345 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) {
6346 // Kernel priority clients are only notified on the initial
6347 // transition to full wake, so don't notify them unless system
6348 // has gained graphics capability since the last system wake.
6349 _systemMessageClientMask &= ~kSystemMessageClientKernel;
6350 } else {
6351 // System was in full wake, but the downwards power transition is driven
6352 // by a request that originates from IOServicePM, so it isn't tagged with
6353 // a valid system sleep reason.
6354 if (REQUEST_TAG_TO_REASON(requestTag) == kCPSReasonPMInternals) {
6355 // Publish the same reason for full to dark
6356 sleepReason = fullToDarkReason;
6357 }
6358 }
6359#if HIBERNATION
6360 gIOHibernateState = 0;
6361#endif
6362
6363 // Record the reason for dark wake back to sleep
6364 // System may not have ever achieved full wake
6365
6366 publishSleepReason = true;
6367 lastSleepReason = sleepReason;
6368 if (sleepDelaysReport) {
6369 clock_get_uptime(result: &ts_sleepStart);
6370 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
6371 }
6372 }
6373 // 3. System wake.
6374 else if (kSystemTransitionWake == _systemTransitionType) {
6375 tracePoint( point: kIOPMTracePointWakeWillPowerOnClients );
6376 // Clear stats about sleep
6377
6378 if (AOT_STATE == newPowerState) {
6379 _pendingCapability = 0;
6380 }
6381
6382 if (AOT_STATE == currentPowerState) {
6383 // Wake events are no longer accepted after waking to AOT_STATE.
6384 // Re-enable wake event acceptance to append wake events claimed
6385 // during the AOT to ON_STATE transition.
6386 acceptSystemWakeEvents(control: kAcceptSystemWakeEvents_Reenable);
6387 }
6388
6389 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6390 willEnterFullWake();
6391 }
6392 }
6393
6394 // The only location where the sleep reason is published. At this point
6395 // sleep can still be cancelled, but sleep reason should be published
6396 // early for logging purposes.
6397
6398 if (publishSleepReason) {
6399 static const char * IOPMSleepReasons[] =
6400 {
6401 kIOPMClamshellSleepKey,
6402 kIOPMPowerButtonSleepKey,
6403 kIOPMSoftwareSleepKey,
6404 kIOPMOSSwitchHibernationKey,
6405 kIOPMIdleSleepKey,
6406 kIOPMLowPowerSleepKey,
6407 kIOPMThermalEmergencySleepKey,
6408 kIOPMMaintenanceSleepKey,
6409 kIOPMSleepServiceExitKey,
6410 kIOPMDarkWakeThermalEmergencyKey,
6411 kIOPMNotificationWakeExitKey
6412 };
6413
6414 // Record sleep cause in IORegistry
6415 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
6416 if (reasonIndex < sizeof(IOPMSleepReasons) / sizeof(IOPMSleepReasons[0])) {
6417 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
6418#if DEVELOPMENT || DEBUG
6419 record_system_event(SYSTEM_EVENT_TYPE_INFO,
6420 SYSTEM_EVENT_SUBSYSTEM_PMRD,
6421 "Sleep Reason", "%s\n", IOPMSleepReasons[reasonIndex]
6422 );
6423#endif /* DEVELOPMENT || DEBUG */
6424 setProperty(kRootDomainSleepReasonKey, aString: IOPMSleepReasons[reasonIndex]);
6425 }
6426 }
6427
6428 if ((kSystemTransitionNone != _systemTransitionType) &&
6429 (kSystemTransitionNewCapClient != _systemTransitionType)) {
6430 _systemStateGeneration++;
6431 systemDarkWake = false;
6432
6433 DLOG("=== START (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6434 getPowerStateString(currentPowerState),
6435 getPowerStateString((uint32_t) newPowerState),
6436 _currentCapability, _pendingCapability,
6437 *inOutChangeFlags, _systemStateGeneration, _systemMessageClientMask,
6438 requestTag);
6439#if DEVELOPMENT || DEBUG
6440 if (currentPowerState != (uint32_t) newPowerState) {
6441 record_system_event(SYSTEM_EVENT_TYPE_INFO,
6442 SYSTEM_EVENT_SUBSYSTEM_PMRD,
6443 "Start Power State Trans.",
6444 "(%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6445 getPowerStateString(currentPowerState),
6446 getPowerStateString((uint32_t) newPowerState),
6447 _currentCapability,
6448 _pendingCapability,
6449 *inOutChangeFlags,
6450 _systemStateGeneration,
6451 _systemMessageClientMask,
6452 requestTag
6453 );
6454 }
6455#endif /* DEVELOPMENT || DEBUG */
6456 }
6457
6458 if ((AOT_STATE == newPowerState) && (SLEEP_STATE != currentPowerState)) {
6459 panic("illegal AOT entry from %s", getPowerStateString(currentPowerState));
6460 }
6461 if (_aotNow && (ON_STATE == newPowerState)) {
6462 WAKEEVENT_LOCK();
6463 aotShouldExit(checkTimeSet: false, software: true);
6464 WAKEEVENT_UNLOCK();
6465 aotExit(cps: false);
6466 }
6467}
6468
6469void
6470IOPMrootDomain::handleOurPowerChangeDone(
6471 IOService * service,
6472 IOPMActions * actions,
6473 const IOPMRequest * request,
6474 IOPMPowerStateIndex oldPowerState,
6475 IOPMPowerChangeFlags changeFlags )
6476{
6477 if (kSystemTransitionNewCapClient == _systemTransitionType) {
6478 _systemTransitionType = kSystemTransitionNone;
6479 return;
6480 }
6481
6482 if (_systemTransitionType != kSystemTransitionNone) {
6483 uint32_t currentPowerState = (uint32_t) getPowerState();
6484
6485 if (changeFlags & kIOPMNotDone) {
6486 // Power down was cancelled or vetoed.
6487 _pendingCapability = _currentCapability;
6488 lastSleepReason = 0;
6489
6490 // When sleep is cancelled or reverted, don't report
6491 // the target (lower) power state as the previous state.
6492 oldPowerState = currentPowerState;
6493
6494 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
6495 CAP_CURRENT(kIOPMSystemCapabilityCPU)) {
6496#if defined(XNU_TARGET_OS_OSX)
6497 pmPowerStateQueue->submitPowerEvent(
6498 eventType: kPowerEventPolicyStimulus,
6499 arg0: (void *) kStimulusDarkWakeReentry,
6500 arg1: _systemStateGeneration );
6501#else /* !defined(XNU_TARGET_OS_OSX) */
6502 // On embedded, there are no factors that can prolong a
6503 // "darkWake" when a power down is vetoed. We need to
6504 // promote to "fullWake" at least once so that factors
6505 // that prevent idle sleep can assert themselves if required
6506 pmPowerStateQueue->submitPowerEvent(
6507 kPowerEventPolicyStimulus,
6508 (void *) kStimulusDarkWakeActivityTickle);
6509#endif /* !defined(XNU_TARGET_OS_OSX) */
6510 }
6511
6512 // Revert device desire to max.
6513 changePowerStateWithTagToPriv(ordinal: getRUN_STATE(), reason: kCPSReasonPowerDownCancel);
6514 } else {
6515 // Send message on dark wake to full wake promotion.
6516 // tellChangeUp() handles the normal SLEEP->ON case.
6517
6518 if (kSystemTransitionCapability == _systemTransitionType) {
6519 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
6520 lastSleepReason = 0; // stop logging wrangler tickles
6521 tellClients(kIOMessageSystemHasPoweredOn);
6522 }
6523 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
6524 // Going dark, reset full wake state
6525 // userIsActive will be cleared by wrangler powering down
6526 fullWakeReason = kFullWakeReasonNone;
6527
6528 if (ts_sleepStart) {
6529 clock_get_uptime(result: &wake2DarkwakeDelay);
6530 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
6531 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
6532 ts_sleepStart = 0;
6533 }
6534 }
6535 }
6536
6537 // Reset state after exiting from dark wake.
6538
6539 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
6540 CAP_LOSS(kIOPMSystemCapabilityCPU)) {
6541 darkWakeMaintenance = false;
6542 darkWakeToSleepASAP = false;
6543 pciCantSleepValid = false;
6544 darkWakeSleepService = false;
6545
6546 if (CAP_LOSS(kIOPMSystemCapabilityCPU)) {
6547 // Remove the influence of display power assertion
6548 // before next system wake.
6549 if (wrangler) {
6550 wrangler->changePowerStateForRootDomain(
6551 ordinal: kWranglerPowerStateMin );
6552 }
6553 removeProperty(aKey: gIOPMUserTriggeredFullWakeKey.get());
6554 }
6555 }
6556
6557 // Entered dark mode.
6558
6559 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6560 (_pendingCapability & kIOPMSystemCapabilityCPU)) {
6561 // Queue an evaluation of whether to remain in dark wake,
6562 // and for how long. This serves the purpose of draining
6563 // any assertions from the queue.
6564
6565 pmPowerStateQueue->submitPowerEvent(
6566 eventType: kPowerEventPolicyStimulus,
6567 arg0: (void *) kStimulusDarkWakeEntry,
6568 arg1: _systemStateGeneration );
6569 }
6570 }
6571
6572#if DEVELOPMENT || DEBUG
6573 if (currentPowerState != (uint32_t) oldPowerState) {
6574 record_system_event(SYSTEM_EVENT_TYPE_INFO,
6575 SYSTEM_EVENT_SUBSYSTEM_PMRD,
6576 "Finish Power State Trans.",
6577 "(%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6578 getPowerStateString((uint32_t)oldPowerState),
6579 getPowerStateString(currentPowerState),
6580 _currentCapability,
6581 _pendingCapability,
6582 changeFlags,
6583 _systemStateGeneration,
6584 _systemMessageClientMask,
6585 request->getTag()
6586 );
6587 }
6588#endif /* DEVELOPMENT || DEBUG */
6589
6590 DLOG("=== FINISH (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6591 getPowerStateString((uint32_t) oldPowerState), getPowerStateString(currentPowerState),
6592 _currentCapability, _pendingCapability,
6593 changeFlags, _systemStateGeneration, _systemMessageClientMask,
6594 request->getTag());
6595
6596 if ((currentPowerState == ON_STATE) && pmAssertions) {
6597 pmAssertions->reportCPUBitAccounting();
6598 }
6599
6600 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6601 displayWakeCnt++;
6602#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
6603 if (clamshellExists && fullWakeThreadCall) {
6604 AbsoluteTime deadline;
6605 clock_interval_to_deadline(DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY, kSecondScale, &deadline);
6606 thread_call_enter_delayed(fullWakeThreadCall, deadline);
6607 }
6608#endif
6609 } else if (CAP_GAIN(kIOPMSystemCapabilityCPU)) {
6610 darkWakeCnt++;
6611 }
6612
6613 // Update current system capability.
6614 if (_currentCapability != _pendingCapability) {
6615 _currentCapability = _pendingCapability;
6616 }
6617
6618 // Update highest system capability.
6619
6620 _highestCapability |= _currentCapability;
6621
6622 if (darkWakePostTickle &&
6623 (kSystemTransitionWake == _systemTransitionType) &&
6624 (gDarkWakeFlags & kDarkWakeFlagPromotionMask) ==
6625 kDarkWakeFlagPromotionLate) {
6626 darkWakePostTickle = false;
6627 reportUserInput();
6628 } else if (darkWakeExit) {
6629 requestFullWake( reason: kFullWakeReasonLocalUser );
6630 }
6631
6632 // Reset tracepoint at completion of capability change,
6633 // completion of wake transition, and aborted sleep transition.
6634
6635 if ((_systemTransitionType == kSystemTransitionCapability) ||
6636 (_systemTransitionType == kSystemTransitionWake) ||
6637 ((_systemTransitionType == kSystemTransitionSleep) &&
6638 (changeFlags & kIOPMNotDone))) {
6639 setProperty(kIOPMSystemCapabilitiesKey, aValue: _currentCapability, aNumberOfBits: 64);
6640 tracePoint( point: kIOPMTracePointSystemUp );
6641 }
6642
6643 _systemTransitionType = kSystemTransitionNone;
6644 _systemMessageClientMask = 0;
6645 toldPowerdCapWillChange = false;
6646
6647 darkWakeLogClamp = false;
6648
6649 if (lowBatteryCondition) {
6650 privateSleepSystem(sleepReason: kIOPMSleepReasonLowPower);
6651 } else if (thermalEmergencyState) {
6652 privateSleepSystem(sleepReason: kIOPMSleepReasonThermalEmergency);
6653 } else if ((fullWakeReason == kFullWakeReasonDisplayOn) && !displayPowerOnRequested) {
6654 // Request for full wake is removed while system is waking up to full wake
6655 DLOG("DisplayOn fullwake request is removed\n");
6656 handleSetDisplayPowerOn(powerOn: false);
6657 }
6658
6659 if ((gClamshellFlags & kClamshell_WAR_47715679) && isRTCAlarmWake) {
6660 pmPowerStateQueue->submitPowerEvent(
6661 eventType: kPowerEventReceivedPowerNotification, arg0: (void *)(uintptr_t) kLocalEvalClamshellCommand );
6662 }
6663 }
6664}
6665
6666//******************************************************************************
6667// PM actions for graphics and audio.
6668//******************************************************************************
6669
6670void
6671IOPMrootDomain::overridePowerChangeForService(
6672 IOService * service,
6673 IOPMActions * actions,
6674 const IOPMRequest * request,
6675 IOPMPowerStateIndex * inOutPowerState,
6676 IOPMPowerChangeFlags * inOutChangeFlags )
6677{
6678 uint32_t powerState = (uint32_t) *inOutPowerState;
6679 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
6680 const uint32_t actionFlags = actions->flags;
6681
6682 if (kSystemTransitionNone == _systemTransitionType) {
6683 // Not in midst of a system transition.
6684 // Do not set kPMActionsStatePowerClamped.
6685 } else if ((actions->state & kPMActionsStatePowerClamped) == 0) {
6686 bool enableClamp = false;
6687
6688 // For most drivers, enable the clamp during ON->Dark transition
6689 // which has the kIOPMSynchronize flag set in changeFlags.
6690 if ((actionFlags & kPMActionsFlagIsDisplayWrangler) &&
6691 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6692 (changeFlags & kIOPMSynchronize)) {
6693 enableClamp = true;
6694 } else if ((actionFlags & kPMActionsFlagIsAudioDriver) &&
6695 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
6696 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
6697 (changeFlags & kIOPMSynchronize)) {
6698 enableClamp = true;
6699 } else if ((actionFlags & kPMActionsFlagHasDarkWakePowerState) &&
6700 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6701 (changeFlags & kIOPMSynchronize)) {
6702 enableClamp = true;
6703 } else if ((actionFlags & kPMActionsFlagIsGraphicsDriver) &&
6704 (_systemTransitionType == kSystemTransitionSleep)) {
6705 // For graphics drivers, clamp power when entering
6706 // system sleep. Not when dropping to dark wake.
6707 enableClamp = true;
6708 }
6709
6710 if (enableClamp) {
6711 actions->state |= kPMActionsStatePowerClamped;
6712 DLOG("power clamp enabled %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6713 service->getName(), service->getRegistryEntryID(),
6714 _pendingCapability, powerState, changeFlags);
6715 }
6716 } else if ((actions->state & kPMActionsStatePowerClamped) != 0) {
6717 bool disableClamp = false;
6718
6719 if ((actionFlags & (
6720 kPMActionsFlagIsDisplayWrangler |
6721 kPMActionsFlagIsGraphicsDriver)) &&
6722 (_pendingCapability & kIOPMSystemCapabilityGraphics)) {
6723 disableClamp = true;
6724 } else if ((actionFlags & kPMActionsFlagIsAudioDriver) &&
6725 (_pendingCapability & kIOPMSystemCapabilityAudio)) {
6726 disableClamp = true;
6727 } else if ((actionFlags & kPMActionsFlagHasDarkWakePowerState) &&
6728 (_pendingCapability & kIOPMSystemCapabilityGraphics)) {
6729 disableClamp = true;
6730 }
6731
6732 if (disableClamp) {
6733 actions->state &= ~kPMActionsStatePowerClamped;
6734 DLOG("power clamp removed %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6735 service->getName(), service->getRegistryEntryID(),
6736 _pendingCapability, powerState, changeFlags);
6737 }
6738 }
6739
6740 if (actions->state & kPMActionsStatePowerClamped) {
6741 uint32_t maxPowerState = 0;
6742
6743 // Determine the max power state allowed when clamp is enabled
6744 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange)) {
6745 // Parent intiated power state changes
6746 if ((service->getPowerState() > maxPowerState) &&
6747 (actionFlags & kPMActionsFlagIsDisplayWrangler)) {
6748 maxPowerState++;
6749
6750 // Remove lingering effects of any tickle before entering
6751 // dark wake. It will take a new tickle to return to full
6752 // wake, so the existing tickle state is useless.
6753
6754 if (changeFlags & kIOPMDomainDidChange) {
6755 *inOutChangeFlags |= kIOPMExpireIdleTimer;
6756 }
6757 } else if (actionFlags & kPMActionsFlagIsGraphicsDriver) {
6758 maxPowerState++;
6759 } else if (actionFlags & kPMActionsFlagHasDarkWakePowerState) {
6760 maxPowerState = actions->darkWakePowerState;
6761 }
6762 } else {
6763 // Deny all self-initiated changes when power is limited.
6764 // Wrangler tickle should never defeat the limiter.
6765 maxPowerState = service->getPowerState();
6766 }
6767
6768 if (powerState > maxPowerState) {
6769 DLOG("power clamped %s %qx, ps %u->%u, cflags 0x%x)\n",
6770 service->getName(), service->getRegistryEntryID(),
6771 powerState, maxPowerState, changeFlags);
6772 *inOutPowerState = maxPowerState;
6773
6774 if (darkWakePostTickle &&
6775 (actionFlags & kPMActionsFlagIsDisplayWrangler) &&
6776 (changeFlags & kIOPMDomainWillChange) &&
6777 ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) ==
6778 kDarkWakeFlagPromotionEarly)) {
6779 darkWakePostTickle = false;
6780 reportUserInput();
6781 }
6782 }
6783
6784 if (!darkWakePowerClamped && (changeFlags & kIOPMDomainDidChange)) {
6785 if (darkWakeLogClamp) {
6786 AbsoluteTime now;
6787 uint64_t nsec;
6788
6789 clock_get_uptime(result: &now);
6790 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
6791 absolutetime_to_nanoseconds(abstime: now, result: &nsec);
6792 DLOG("dark wake power clamped after %u ms\n",
6793 ((int)((nsec) / NSEC_PER_MSEC)));
6794 }
6795 darkWakePowerClamped = true;
6796 }
6797 }
6798}
6799
6800void
6801IOPMrootDomain::handleActivityTickleForDisplayWrangler(
6802 IOService * service,
6803 IOPMActions * actions )
6804{
6805#if DISPLAY_WRANGLER_PRESENT
6806 // Warning: Not running in PM work loop context - don't modify state !!!
6807 // Trap tickle directed to IODisplayWrangler while running with graphics
6808 // capability suppressed.
6809
6810 assert(service == wrangler);
6811
6812 clock_get_uptime(&userActivityTime);
6813 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
6814 || (lastSleepReason == kIOPMSleepReasonMaintenance)
6815 || (lastSleepReason == kIOPMSleepReasonSoftware));
6816 if (aborting) {
6817 userActivityCount++;
6818 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
6819 userActivityCount, lastSleepReason);
6820 }
6821
6822 if (!darkWakeExit && ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0)) {
6823 DLOG("display wrangler tickled\n");
6824 if (kIOLogPMRootDomain & gIOKitDebug) {
6825 OSReportWithBacktrace("Dark wake display tickle");
6826 }
6827 if (pmPowerStateQueue) {
6828 pmPowerStateQueue->submitPowerEvent(
6829 kPowerEventPolicyStimulus,
6830 (void *) kStimulusDarkWakeActivityTickle,
6831 true /* set wake type */ );
6832 }
6833 }
6834#endif /* DISPLAY_WRANGLER_PRESENT */
6835}
6836
6837void
6838IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
6839 IOService * service,
6840 IOPMActions * actions,
6841 const OSSymbol * powerClient,
6842 IOPMPowerStateIndex oldPowerState,
6843 IOPMPowerStateIndex newPowerState )
6844{
6845#if DISPLAY_WRANGLER_PRESENT
6846 assert(service == wrangler);
6847
6848 // This function implements half of the user active detection
6849 // by monitoring changes to the display wrangler's device desire.
6850 //
6851 // User becomes active when either:
6852 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
6853 // in max power state. This desire change in absence of a power state
6854 // change is detected within. This handles the case when user becomes
6855 // active while the display is already lit by setDisplayPowerOn().
6856 //
6857 // 2. Power state change to max, and DeviceDesire is also at max.
6858 // Handled by displayWranglerNotification().
6859 //
6860 // User becomes inactive when DeviceDesire drops to sleep state or below.
6861
6862 DLOG("wrangler %s (ps %u, %u->%u)\n",
6863 powerClient->getCStringNoCopy(),
6864 (uint32_t) service->getPowerState(),
6865 (uint32_t) oldPowerState, (uint32_t) newPowerState);
6866
6867 if (powerClient == gIOPMPowerClientDevice) {
6868 if ((newPowerState > oldPowerState) &&
6869 (newPowerState == kWranglerPowerStateMax) &&
6870 (service->getPowerState() == kWranglerPowerStateMax)) {
6871 evaluatePolicy( kStimulusEnterUserActiveState );
6872 } else if ((newPowerState < oldPowerState) &&
6873 (newPowerState <= kWranglerPowerStateSleep)) {
6874 evaluatePolicy( kStimulusLeaveUserActiveState );
6875 }
6876 }
6877
6878 if (newPowerState <= kWranglerPowerStateSleep) {
6879 evaluatePolicy( kStimulusDisplayWranglerSleep );
6880 } else if (newPowerState == kWranglerPowerStateMax) {
6881 evaluatePolicy( kStimulusDisplayWranglerWake );
6882 }
6883#endif /* DISPLAY_WRANGLER_PRESENT */
6884}
6885
6886//******************************************************************************
6887// User active state management
6888//******************************************************************************
6889
6890void
6891IOPMrootDomain::preventTransitionToUserActive( bool prevent )
6892{
6893#if DISPLAY_WRANGLER_PRESENT
6894 _preventUserActive = prevent;
6895 if (wrangler && !_preventUserActive) {
6896 // Allowing transition to user active, but the wrangler may have
6897 // already powered ON in case of sleep cancel/revert. Poll the
6898 // same conditions checked for in displayWranglerNotification()
6899 // to bring the user active state up to date.
6900
6901 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
6902 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
6903 kWranglerPowerStateMax)) {
6904 evaluatePolicy( kStimulusEnterUserActiveState );
6905 }
6906 }
6907#endif /* DISPLAY_WRANGLER_PRESENT */
6908}
6909
6910//******************************************************************************
6911// Approve usage of delayed child notification by PM.
6912//******************************************************************************
6913
6914bool
6915IOPMrootDomain::shouldDelayChildNotification(
6916 IOService * service )
6917{
6918 if ((kFullWakeReasonNone == fullWakeReason) &&
6919 (kSystemTransitionWake == _systemTransitionType)) {
6920 DLOG("%s: delay child notify\n", service->getName());
6921 return true;
6922 }
6923 return false;
6924}
6925
6926//******************************************************************************
6927// PM actions for PCI device.
6928//******************************************************************************
6929
6930void
6931IOPMrootDomain::handlePowerChangeStartForPCIDevice(
6932 IOService * service,
6933 IOPMActions * actions,
6934 const IOPMRequest * request,
6935 IOPMPowerStateIndex powerState,
6936 IOPMPowerChangeFlags * inOutChangeFlags )
6937{
6938 pmTracer->tracePCIPowerChange(
6939 PMTraceWorker::kPowerChangeStart,
6940 service, *inOutChangeFlags,
6941 (actions->flags & kPMActionsPCIBitNumberMask));
6942}
6943
6944void
6945IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
6946 IOService * service,
6947 IOPMActions * actions,
6948 const IOPMRequest * request,
6949 IOPMPowerStateIndex powerState,
6950 IOPMPowerChangeFlags changeFlags )
6951{
6952 pmTracer->tracePCIPowerChange(
6953 PMTraceWorker::kPowerChangeCompleted,
6954 service, changeFlags,
6955 (actions->flags & kPMActionsPCIBitNumberMask));
6956}
6957
6958//******************************************************************************
6959// registerInterest
6960//
6961// Override IOService::registerInterest() for root domain clients.
6962//******************************************************************************
6963
6964class IOPMServiceInterestNotifier : public _IOServiceInterestNotifier
6965{
6966 friend class IOPMrootDomain;
6967 OSDeclareDefaultStructors(IOPMServiceInterestNotifier);
6968
6969protected:
6970 uint32_t ackTimeoutCnt;
6971 uint32_t msgType; // Last type seen by the message filter
6972 uint32_t lastSleepWakeMsgType;
6973 uint32_t msgIndex;
6974 uint32_t maxMsgDelayMS;
6975 uint32_t maxAckDelayMS;
6976 uint64_t msgAbsTime;
6977 uint64_t uuid0;
6978 uint64_t uuid1;
6979 OSSharedPtr<const OSSymbol> identifier;
6980 OSSharedPtr<const OSSymbol> clientName;
6981};
6982
6983OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
6984
6985OSSharedPtr<IONotifier>
6986IOPMrootDomain::registerInterest(
6987 const OSSymbol * typeOfInterest,
6988 IOServiceInterestHandler handler,
6989 void * target, void * ref )
6990{
6991 IOPMServiceInterestNotifier* notifier;
6992 bool isSystemCapabilityClient;
6993 bool isKernelCapabilityClient;
6994 IOReturn rc = kIOReturnError;
6995
6996 isSystemCapabilityClient = typeOfInterest &&
6997 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
6998
6999 isKernelCapabilityClient = typeOfInterest &&
7000 typeOfInterest->isEqualTo(aSymbol: gIOPriorityPowerStateInterest);
7001
7002 if (isSystemCapabilityClient) {
7003 typeOfInterest = gIOAppPowerStateInterest;
7004 }
7005
7006 notifier = new IOPMServiceInterestNotifier;
7007 if (!notifier) {
7008 return NULL;
7009 }
7010
7011 if (notifier->init()) {
7012 rc = super::registerInterestForNotifier(notify: notifier, typeOfInterest, handler, target, ref);
7013 }
7014 if (rc != kIOReturnSuccess) {
7015 OSSafeReleaseNULL(notifier);
7016 return NULL;
7017 }
7018
7019 notifier->ackTimeoutCnt = 0;
7020
7021 if (pmPowerStateQueue) {
7022 if (isSystemCapabilityClient) {
7023 notifier->retain();
7024 if (pmPowerStateQueue->submitPowerEvent(
7025 eventType: kPowerEventRegisterSystemCapabilityClient, arg0: notifier) == false) {
7026 notifier->release();
7027 }
7028 }
7029
7030 if (isKernelCapabilityClient) {
7031 notifier->retain();
7032 if (pmPowerStateQueue->submitPowerEvent(
7033 eventType: kPowerEventRegisterKernelCapabilityClient, arg0: notifier) == false) {
7034 notifier->release();
7035 }
7036 }
7037 }
7038
7039 OSSharedPtr<OSData> data;
7040 uint8_t *uuid = NULL;
7041 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithAddress(address: (vm_address_t)handler);
7042 if (kext) {
7043 data = kext->copyUUID();
7044 }
7045 if (data && (data->getLength() == sizeof(uuid_t))) {
7046 uuid = (uint8_t *)(data->getBytesNoCopy());
7047
7048 notifier->uuid0 = ((uint64_t)(uuid[0]) << 56) | ((uint64_t)(uuid[1]) << 48) | ((uint64_t)(uuid[2]) << 40) |
7049 ((uint64_t)(uuid[3]) << 32) | ((uint64_t)(uuid[4]) << 24) | ((uint64_t)(uuid[5]) << 16) |
7050 ((uint64_t)(uuid[6]) << 8) | (uuid[7]);
7051 notifier->uuid1 = ((uint64_t)(uuid[8]) << 56) | ((uint64_t)(uuid[9]) << 48) | ((uint64_t)(uuid[10]) << 40) |
7052 ((uint64_t)(uuid[11]) << 32) | ((uint64_t)(uuid[12]) << 24) | ((uint64_t)(uuid[13]) << 16) |
7053 ((uint64_t)(uuid[14]) << 8) | (uuid[15]);
7054
7055 notifier->identifier = copyKextIdentifierWithAddress(address: (vm_address_t) handler);
7056 }
7057 return OSSharedPtr<IOPMServiceInterestNotifier>(notifier, OSNoRetain);
7058}
7059
7060//******************************************************************************
7061// systemMessageFilter
7062//
7063//******************************************************************************
7064
7065bool
7066IOPMrootDomain::systemMessageFilter(
7067 void * object, void * arg1, void * arg2, void * arg3 )
7068{
7069 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
7070 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
7071 bool isCapPowerd = (object == (void *) systemCapabilityNotifier.get());
7072 bool isCapClient = false;
7073 bool allow = false;
7074 OSBoolean **waitForReply = (typeof(waitForReply))arg3;
7075 IOPMServiceInterestNotifier *notifier;
7076
7077 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
7078
7079 do {
7080 // When powerd and kernel priority clients register capability interest,
7081 // the power tree is sync'ed to inform those clients about the current
7082 // system capability. Only allow capability change messages during sync.
7083 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
7084 (!isCapMsg || !_joinedCapabilityClients ||
7085 !_joinedCapabilityClients->containsObject(anObject: (OSObject *) object))) {
7086 break;
7087 }
7088
7089 // Capability change message for powerd and kernel clients
7090 if (isCapMsg) {
7091 // Kernel priority clients
7092 if ((context->notifyType == kNotifyPriority) ||
7093 (context->notifyType == kNotifyCapabilityChangePriority)) {
7094 isCapClient = true;
7095 }
7096
7097 // powerd will maintain two client registrations with root domain.
7098 // isCapPowerd will be TRUE for any message targeting the powerd
7099 // exclusive (capability change) interest registration.
7100 if (isCapPowerd && (context->notifyType == kNotifyCapabilityChangeApps)) {
7101 isCapClient = true;
7102 }
7103 }
7104
7105 if (isCapClient) {
7106 IOPMSystemCapabilityChangeParameters * capArgs =
7107 (IOPMSystemCapabilityChangeParameters *) arg2;
7108
7109 if (kSystemTransitionNewCapClient == _systemTransitionType) {
7110 capArgs->fromCapabilities = 0;
7111 capArgs->toCapabilities = _currentCapability;
7112 capArgs->changeFlags = 0;
7113 } else {
7114 capArgs->fromCapabilities = _currentCapability;
7115 capArgs->toCapabilities = _pendingCapability;
7116
7117 if (context->isPreChange) {
7118 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
7119 } else {
7120 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
7121 }
7122
7123 if (isCapPowerd && context->isPreChange) {
7124 toldPowerdCapWillChange = true;
7125 }
7126 }
7127
7128 // App level capability change messages must only go to powerd.
7129 // Wait for response post-change if capabilitiy is increasing.
7130 // Wait for response pre-change if capability is decreasing.
7131
7132 if ((context->notifyType == kNotifyCapabilityChangeApps) && waitForReply &&
7133 ((capabilityLoss && context->isPreChange) ||
7134 (!capabilityLoss && !context->isPreChange))) {
7135 *waitForReply = kOSBooleanTrue;
7136 }
7137
7138 allow = true;
7139 break;
7140 }
7141
7142 // powerd will always receive CanSystemSleep, even for a demand sleep.
7143 // It will also have a final chance to veto sleep after all clients
7144 // have responded to SystemWillSleep
7145
7146 if ((kIOMessageCanSystemSleep == context->messageType) ||
7147 (kIOMessageSystemWillNotSleep == context->messageType)) {
7148 if (isCapPowerd) {
7149 allow = true;
7150 break;
7151 }
7152
7153 // Demand sleep, don't ask apps for permission
7154 if (context->changeFlags & kIOPMSkipAskPowerDown) {
7155 break;
7156 }
7157 }
7158
7159 if (kIOPMMessageLastCallBeforeSleep == context->messageType) {
7160 if (isCapPowerd && CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
7161 (fullToDarkReason == kIOPMSleepReasonIdle)) {
7162 allow = true;
7163 }
7164 break;
7165 }
7166
7167 // Drop capability change messages for legacy clients.
7168 // Drop legacy system sleep messages for powerd capability interest.
7169 if (isCapMsg || isCapPowerd) {
7170 break;
7171 }
7172
7173 // Not a capability change message.
7174 // Perform message filtering based on _systemMessageClientMask.
7175
7176 if ((context->notifyType == kNotifyApps) &&
7177 (_systemMessageClientMask & kSystemMessageClientLegacyApp)) {
7178 if (!notifier) {
7179 break;
7180 }
7181
7182 if ((notifier->lastSleepWakeMsgType == context->messageType) &&
7183 (notifier->lastSleepWakeMsgType == kIOMessageSystemWillPowerOn)) {
7184 break; // drop any duplicate WillPowerOn for AOT devices
7185 }
7186
7187 allow = true;
7188
7189 if (waitForReply) {
7190 if (notifier->ackTimeoutCnt >= 3) {
7191 *waitForReply = kOSBooleanFalse;
7192 } else {
7193 *waitForReply = kOSBooleanTrue;
7194 }
7195 }
7196 } else if ((context->notifyType == kNotifyPriority) &&
7197 (_systemMessageClientMask & kSystemMessageClientKernel)) {
7198 allow = true;
7199 }
7200
7201 // Check sleep/wake message ordering
7202 if (allow) {
7203 if (context->messageType == kIOMessageSystemWillSleep ||
7204 context->messageType == kIOMessageSystemWillPowerOn ||
7205 context->messageType == kIOMessageSystemHasPoweredOn) {
7206 notifier->lastSleepWakeMsgType = context->messageType;
7207 }
7208 }
7209 } while (false);
7210
7211 if (allow && isCapMsg && _joinedCapabilityClients) {
7212 _joinedCapabilityClients->removeObject(anObject: (OSObject *) object);
7213 if (_joinedCapabilityClients->getCount() == 0) {
7214 DMSG("destroyed capability client set %p\n",
7215 OBFUSCATE(_joinedCapabilityClients.get()));
7216 _joinedCapabilityClients.reset();
7217 }
7218 }
7219 if (notifier) {
7220 // Record the last seen message type even if the message is dropped
7221 // for traceFilteredNotification().
7222 notifier->msgType = context->messageType;
7223 }
7224
7225 return allow;
7226}
7227
7228//******************************************************************************
7229// setMaintenanceWakeCalendar
7230//
7231//******************************************************************************
7232
7233IOReturn
7234IOPMrootDomain::setMaintenanceWakeCalendar(
7235 const IOPMCalendarStruct * calendar )
7236{
7237 OSSharedPtr<OSData> data;
7238 IOReturn ret = 0;
7239
7240 if (!calendar) {
7241 return kIOReturnBadArgument;
7242 }
7243
7244 data = OSData::withValue(value: *calendar);
7245 if (!data) {
7246 return kIOReturnNoMemory;
7247 }
7248
7249 if (kPMCalendarTypeMaintenance == calendar->selector) {
7250 ret = setPMSetting(type: gIOPMSettingMaintenanceWakeCalendarKey.get(), object: data.get());
7251 } else if (kPMCalendarTypeSleepService == calendar->selector) {
7252 ret = setPMSetting(type: gIOPMSettingSleepServiceWakeCalendarKey.get(), object: data.get());
7253 }
7254
7255 return ret;
7256}
7257
7258// MARK: -
7259// MARK: Display Wrangler
7260
7261//******************************************************************************
7262// displayWranglerNotification
7263//
7264// Handle the notification when the IODisplayWrangler changes power state.
7265//******************************************************************************
7266
7267IOReturn
7268IOPMrootDomain::displayWranglerNotification(
7269 void * target, void * refCon,
7270 UInt32 messageType, IOService * service,
7271 void * messageArgument, vm_size_t argSize )
7272{
7273#if DISPLAY_WRANGLER_PRESENT
7274 IOPMPowerStateIndex displayPowerState;
7275 IOPowerStateChangeNotification * params =
7276 (IOPowerStateChangeNotification *) messageArgument;
7277
7278 if ((messageType != kIOMessageDeviceWillPowerOff) &&
7279 (messageType != kIOMessageDeviceHasPoweredOn)) {
7280 return kIOReturnUnsupported;
7281 }
7282
7283 ASSERT_GATED();
7284 if (!gRootDomain) {
7285 return kIOReturnUnsupported;
7286 }
7287
7288 displayPowerState = params->stateNumber;
7289 DLOG("wrangler %s ps %d\n",
7290 getIOMessageString(messageType), (uint32_t) displayPowerState);
7291
7292 switch (messageType) {
7293 case kIOMessageDeviceWillPowerOff:
7294 // Display wrangler has dropped power due to display idle
7295 // or force system sleep.
7296 //
7297 // 4 Display ON kWranglerPowerStateMax
7298 // 3 Display Dim kWranglerPowerStateDim
7299 // 2 Display Sleep kWranglerPowerStateSleep
7300 // 1 Not visible to user
7301 // 0 Not visible to user kWranglerPowerStateMin
7302
7303 if (displayPowerState <= kWranglerPowerStateSleep) {
7304 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
7305 }
7306 break;
7307
7308 case kIOMessageDeviceHasPoweredOn:
7309 // Display wrangler has powered on due to user activity
7310 // or wake from sleep.
7311
7312 if (kWranglerPowerStateMax == displayPowerState) {
7313 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
7314
7315 // See comment in handleUpdatePowerClientForDisplayWrangler
7316 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
7317 kWranglerPowerStateMax) {
7318 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
7319 }
7320 }
7321 break;
7322 }
7323#endif /* DISPLAY_WRANGLER_PRESENT */
7324 return kIOReturnUnsupported;
7325}
7326
7327//******************************************************************************
7328// reportUserInput
7329//
7330//******************************************************************************
7331
7332void
7333IOPMrootDomain::updateUserActivity( void )
7334{
7335#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7336 clock_get_uptime(result: &userActivityTime);
7337 bool aborting = ((lastSleepReason == kIOPMSleepReasonSoftware)
7338 || (lastSleepReason == kIOPMSleepReasonIdle)
7339 || (lastSleepReason == kIOPMSleepReasonMaintenance));
7340 if (aborting) {
7341 userActivityCount++;
7342 DLOG("user activity reported %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
7343 }
7344#endif
7345}
7346void
7347IOPMrootDomain::reportUserInput( void )
7348{
7349 if (wrangler) {
7350 wrangler->activityTickle(type: 0, stateNumber: 0);
7351 }
7352#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7353 // Update user activity
7354 updateUserActivity();
7355
7356 if (!darkWakeExit && ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0)) {
7357 // update user active abs time
7358 clock_get_uptime(result: &gUserActiveAbsTime);
7359 pmPowerStateQueue->submitPowerEvent(
7360 eventType: kPowerEventPolicyStimulus,
7361 arg0: (void *) kStimulusDarkWakeActivityTickle,
7362 arg1: true /* set wake type */ );
7363 }
7364#endif
7365}
7366
7367void
7368IOPMrootDomain::requestUserActive(IOService *device, const char *reason)
7369{
7370#if DISPLAY_WRANGLER_PRESENT
7371 if (wrangler) {
7372 wrangler->activityTickle(0, 0);
7373 }
7374#else
7375 if (!device) {
7376 DLOG("requestUserActive: device is null\n");
7377 return;
7378 }
7379 OSSharedPtr<const OSSymbol> deviceName = device->copyName();
7380 uint64_t registryID = device->getRegistryEntryID();
7381
7382 if (!deviceName || !registryID) {
7383 DLOG("requestUserActive: no device name or registry entry\n");
7384 return;
7385 }
7386 const char *name = deviceName->getCStringNoCopy();
7387 char payload[128];
7388 snprintf(payload, count: sizeof(payload), "%s:%s", name, reason);
7389 DLOG("requestUserActive from %s (0x%llx) for %s\n", name, registryID, reason);
7390 messageClient(kIOPMMessageRequestUserActive, client: systemCapabilityNotifier.get(), messageArgument: (void *)payload, argSize: sizeof(payload));
7391#endif
7392}
7393
7394//******************************************************************************
7395// latchDisplayWranglerTickle
7396//******************************************************************************
7397
7398bool
7399IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
7400{
7401#if DISPLAY_WRANGLER_PRESENT
7402 if (latch) {
7403 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
7404 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7405 !checkSystemCanSustainFullWake()) {
7406 // Currently in dark wake, and not transitioning to full wake.
7407 // Full wake is unsustainable, so latch the tickle to prevent
7408 // the display from lighting up momentarily.
7409 wranglerTickled = true;
7410 } else {
7411 wranglerTickled = false;
7412 }
7413 } else if (wranglerTickled && checkSystemCanSustainFullWake()) {
7414 wranglerTickled = false;
7415
7416 pmPowerStateQueue->submitPowerEvent(
7417 kPowerEventPolicyStimulus,
7418 (void *) kStimulusDarkWakeActivityTickle );
7419 }
7420
7421 return wranglerTickled;
7422#else /* ! DISPLAY_WRANGLER_PRESENT */
7423 return false;
7424#endif /* ! DISPLAY_WRANGLER_PRESENT */
7425}
7426
7427//******************************************************************************
7428// setDisplayPowerOn
7429//
7430// For root domain user client
7431//******************************************************************************
7432
7433void
7434IOPMrootDomain::setDisplayPowerOn( uint32_t options )
7435{
7436 pmPowerStateQueue->submitPowerEvent( eventType: kPowerEventSetDisplayPowerOn,
7437 arg0: (void *) NULL, arg1: options );
7438}
7439
7440// MARK: -
7441// MARK: System PM Policy
7442
7443//******************************************************************************
7444// checkSystemSleepAllowed
7445//
7446//******************************************************************************
7447
7448bool
7449IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
7450 uint32_t sleepReason )
7451{
7452 uint32_t err = 0;
7453
7454 // Conditions that prevent idle and demand system sleep.
7455
7456 do {
7457 if (gSleepDisabledFlag) {
7458 err = kPMConfigPreventSystemSleep;
7459 break;
7460 }
7461
7462 if (userDisabledAllSleep) {
7463 err = kPMUserDisabledAllSleep; // 1. user-space sleep kill switch
7464 break;
7465 }
7466
7467 if (systemBooting || systemShutdown || gWillShutdown) {
7468 err = kPMSystemRestartBootingInProgress; // 2. restart or shutdown in progress
7469 break;
7470 }
7471
7472 if (options == 0) {
7473 break;
7474 }
7475
7476 // Conditions above pegs the system at full wake.
7477 // Conditions below prevent system sleep but does not prevent
7478 // dark wake, and must be called from gated context.
7479
7480#if !CONFIG_SLEEP
7481 err = kPMConfigPreventSystemSleep; // 3. config does not support sleep
7482 break;
7483#endif
7484
7485 if (lowBatteryCondition || thermalWarningState || thermalEmergencyState) {
7486 break; // always sleep on low battery or when in thermal warning/emergency state
7487 }
7488
7489 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency) {
7490 break; // always sleep on dark wake thermal emergencies
7491 }
7492
7493 if (preventSystemSleepList->getCount() != 0) {
7494 err = kPMChildPreventSystemSleep; // 4. child prevent system sleep clamp
7495 break;
7496 }
7497
7498 if (_driverKitMatchingAssertionCount != 0) {
7499 err = kPMCPUAssertion;
7500 break;
7501 }
7502
7503 // Check for any dexts currently being added to the PM tree. Sleeping while
7504 // this is in flight can cause IOServicePH to timeout.
7505 if (!IOServicePH::checkPMReady()) {
7506#if !defined(XNU_TARGET_OS_OSX)
7507 // 116893363: kPMDKNotReady sleep cancellations often leaves embedded devices
7508 // in dark wake for long periods of time, which causes issues as apps were
7509 // already informed of sleep during the f->9 transition. As a temporary
7510 // measure, always full wake if we hit this specific condition.
7511 pmPowerStateQueue->submitPowerEvent(
7512 kPowerEventPolicyStimulus,
7513 (void *) kStimulusDarkWakeActivityTickle);
7514#endif
7515 err = kPMDKNotReady;
7516 break;
7517 }
7518
7519 if (getPMAssertionLevel( whichAssertionBits: kIOPMDriverAssertionCPUBit ) ==
7520 kIOPMDriverAssertionLevelOn) {
7521 err = kPMCPUAssertion; // 5. CPU assertion
7522 break;
7523 }
7524
7525 if (pciCantSleepValid) {
7526 if (pciCantSleepFlag) {
7527 err = kPMPCIUnsupported; // 6. PCI card does not support PM (cached)
7528 }
7529 break;
7530 } else if (sleepSupportedPEFunction &&
7531 CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
7532 IOReturn ret;
7533 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
7534 ret = getPlatform()->callPlatformFunction(
7535 functionName: sleepSupportedPEFunction.get(), waitForFunction: false,
7536 NULL, NULL, NULL, NULL);
7537 pciCantSleepValid = true;
7538 pciCantSleepFlag = false;
7539 if ((platformSleepSupport & kPCICantSleep) ||
7540 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported))) {
7541 err = 6; // 6. PCI card does not support PM
7542 pciCantSleepFlag = true;
7543 break;
7544 }
7545 }
7546 }while (false);
7547
7548 if (err) {
7549 DLOG("System sleep prevented by %s\n", getSystemSleepPreventerString(err));
7550 return false;
7551 }
7552 return true;
7553}
7554
7555bool
7556IOPMrootDomain::checkSystemSleepEnabled( void )
7557{
7558 return checkSystemSleepAllowed(options: 0, sleepReason: 0);
7559}
7560
7561bool
7562IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
7563{
7564 ASSERT_GATED();
7565 return checkSystemSleepAllowed(options: 1, sleepReason);
7566}
7567
7568//******************************************************************************
7569// checkSystemCanSustainFullWake
7570//******************************************************************************
7571
7572bool
7573IOPMrootDomain::checkSystemCanSustainFullWake( void )
7574{
7575 if (lowBatteryCondition || thermalWarningState || thermalEmergencyState) {
7576 // Low battery wake, or received a low battery notification
7577 // while system is awake. This condition will persist until
7578 // the following wake.
7579 return false;
7580 }
7581
7582 if (clamshellExists && clamshellClosed && !clamshellSleepDisableMask) {
7583 // Graphics state is unknown and external display might not be probed.
7584 // Do not incorporate state that requires graphics to be in max power
7585 // such as desktopMode or clamshellDisabled.
7586
7587 if (!acAdaptorConnected) {
7588 DLOG("full wake check: no AC\n");
7589 return false;
7590 }
7591 }
7592 return true;
7593}
7594
7595//******************************************************************************
7596// mustHibernate
7597//******************************************************************************
7598
7599#if HIBERNATION
7600
7601bool
7602IOPMrootDomain::mustHibernate( void )
7603{
7604 return lowBatteryCondition || thermalWarningState;
7605}
7606
7607#endif /* HIBERNATION */
7608
7609//******************************************************************************
7610// AOT
7611//******************************************************************************
7612
7613// Tables for accumulated days in year by month, latter used for leap years
7614
7615static const unsigned int daysbymonth[] =
7616{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
7617
7618static const unsigned int lydaysbymonth[] =
7619{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
7620
7621static int __unused
7622IOPMConvertSecondsToCalendar(clock_sec_t secs, IOPMCalendarStruct * dt)
7623{
7624 const unsigned int * dbm = daysbymonth;
7625 clock_sec_t n, x, y, z;
7626
7627 // Calculate seconds, minutes and hours
7628
7629 n = secs % (24 * 3600);
7630 dt->second = n % 60;
7631 n /= 60;
7632 dt->minute = n % 60;
7633 dt->hour = (typeof(dt->hour))(n / 60);
7634
7635 // Calculate day of week
7636
7637 n = secs / (24 * 3600);
7638// dt->dayWeek = (n + 4) % 7;
7639
7640 // Calculate year
7641 // Rebase from days since Unix epoch (1/1/1970) store in 'n',
7642 // to days since 1/1/1968 to start on 4 year cycle, beginning
7643 // on a leap year.
7644
7645 n += (366 + 365);
7646
7647 // Every 4 year cycle will be exactly (366 + 365 * 3) = 1461 days.
7648 // Valid before 2100, since 2100 is not a leap year.
7649
7650 x = n / 1461; // number of 4 year cycles
7651 y = n % 1461; // days into current 4 year cycle
7652 z = 1968 + (4 * x);
7653
7654 // Add in years in the current 4 year cycle
7655
7656 if (y >= 366) {
7657 y -= 366; // days after the leap year
7658 n = y % 365; // days into the current year
7659 z += (1 + y / 365); // years after the past 4-yr cycle
7660 } else {
7661 n = y;
7662 dbm = lydaysbymonth;
7663 }
7664 if (z > 2099) {
7665 return 0;
7666 }
7667
7668 dt->year = (typeof(dt->year))z;
7669
7670 // Adjust remaining days value to start at 1
7671
7672 n += 1;
7673
7674 // Calculate month
7675
7676 for (x = 1; (n > dbm[x]) && (x < 12); x++) {
7677 continue;
7678 }
7679 dt->month = (typeof(dt->month))x;
7680
7681 // Calculate day of month
7682
7683 dt->day = (typeof(dt->day))(n - dbm[x - 1]);
7684
7685 return 1;
7686}
7687
7688static clock_sec_t
7689IOPMConvertCalendarToSeconds(const IOPMCalendarStruct * dt)
7690{
7691 const unsigned int * dbm = daysbymonth;
7692 long y, secs, days;
7693
7694 if (dt->year < 1970 || dt->month > 12) {
7695 return 0;
7696 }
7697
7698 // Seconds elapsed in the current day
7699
7700 secs = dt->second + 60 * dt->minute + 3600 * dt->hour;
7701
7702 // Number of days from 1/1/70 to beginning of current year
7703 // Account for extra day every 4 years starting at 1973
7704
7705 y = dt->year - 1970;
7706 days = (y * 365) + ((y + 1) / 4);
7707
7708 // Change table if current year is a leap year
7709
7710 if ((dt->year % 4) == 0) {
7711 dbm = lydaysbymonth;
7712 }
7713
7714 // Add in days elapsed in the current year
7715
7716 days += (dt->day - 1) + dbm[dt->month - 1];
7717
7718 // Add accumulated days to accumulated seconds
7719
7720 secs += 24 * 3600 * days;
7721
7722 return secs;
7723}
7724
7725unsigned long
7726IOPMrootDomain::getRUN_STATE(void)
7727{
7728 return (_aotNow && !(kIOPMWakeEventAOTExitFlags & _aotPendingFlags)) ? AOT_STATE : ON_STATE;
7729}
7730
7731bool
7732IOPMrootDomain::isAOTMode()
7733{
7734 return _aotNow;
7735}
7736
7737IOReturn
7738IOPMrootDomain::setWakeTime(uint64_t wakeContinuousTime)
7739{
7740 clock_sec_t nowsecs, wakesecs;
7741 clock_usec_t nowmicrosecs, wakemicrosecs;
7742 uint64_t nowAbs, wakeAbs;
7743
7744 if (!_aotMode) {
7745 return kIOReturnNotReady;
7746 }
7747
7748 clock_gettimeofday_and_absolute_time(secs: &nowsecs, microsecs: &nowmicrosecs, absolute_time: &nowAbs);
7749 wakeAbs = continuoustime_to_absolutetime(conttime: wakeContinuousTime);
7750 if (wakeAbs < nowAbs) {
7751 printf(LOG_PREFIX "wakeAbs %qd < nowAbs %qd\n", wakeAbs, nowAbs);
7752 wakeAbs = nowAbs;
7753 }
7754 wakeAbs -= nowAbs;
7755 absolutetime_to_microtime(abstime: wakeAbs, secs: &wakesecs, microsecs: &wakemicrosecs);
7756
7757 wakesecs += nowsecs;
7758 wakemicrosecs += nowmicrosecs;
7759 if (wakemicrosecs >= USEC_PER_SEC) {
7760 wakesecs++;
7761 wakemicrosecs -= USEC_PER_SEC;
7762 }
7763 if (wakemicrosecs >= (USEC_PER_SEC / 10)) {
7764 wakesecs++;
7765 }
7766
7767 IOPMConvertSecondsToCalendar(secs: wakesecs, dt: &_aotWakeTimeCalendar);
7768
7769 if (_aotWakeTimeContinuous != wakeContinuousTime) {
7770 _aotWakeTimeContinuous = wakeContinuousTime;
7771 IOLog(LOG_PREFIX "setWakeTime: " YMDTF "\n", YMDT(&_aotWakeTimeCalendar));
7772 }
7773 _aotWakeTimeCalendar.selector = kPMCalendarTypeMaintenance;
7774 _aotWakeTimeUTC = wakesecs;
7775
7776 return kIOReturnSuccess;
7777}
7778
7779// assumes WAKEEVENT_LOCK
7780bool
7781IOPMrootDomain::aotShouldExit(bool checkTimeSet, bool software)
7782{
7783 bool exitNow = false;
7784 const char * reason = "";
7785
7786 if (!_aotNow) {
7787 return false;
7788 }
7789
7790 if (software) {
7791 exitNow = true;
7792 _aotMetrics->softwareRequestCount++;
7793 reason = "software request";
7794 } else if (kIOPMWakeEventAOTExitFlags & _aotPendingFlags) {
7795 exitNow = true;
7796 reason = gWakeReasonString;
7797 } else if (checkTimeSet && (kPMCalendarTypeInvalid == _aotWakeTimeCalendar.selector)) {
7798 exitNow = true;
7799 _aotMetrics->noTimeSetCount++;
7800 reason = "flipbook expired";
7801 } else if ((kIOPMAOTModeRespectTimers & _aotMode) && _calendarWakeAlarmUTC) {
7802 clock_sec_t sec;
7803 clock_usec_t usec;
7804 clock_get_calendar_microtime(secs: &sec, microsecs: &usec);
7805 if (_calendarWakeAlarmUTC <= sec) {
7806 exitNow = true;
7807 _aotMetrics->rtcAlarmsCount++;
7808 reason = "user alarm";
7809 }
7810 }
7811 if (exitNow) {
7812 _aotPendingFlags |= kIOPMWakeEventAOTExit;
7813 IOLog(LOG_PREFIX "AOT exit for %s, sc %d po %d, cp %d, rj %d, ex %d, nt %d, rt %d\n",
7814 reason,
7815 _aotMetrics->sleepCount,
7816 _aotMetrics->possibleCount,
7817 _aotMetrics->confirmedPossibleCount,
7818 _aotMetrics->rejectedPossibleCount,
7819 _aotMetrics->expiredPossibleCount,
7820 _aotMetrics->noTimeSetCount,
7821 _aotMetrics->rtcAlarmsCount);
7822 }
7823 return exitNow;
7824}
7825
7826void
7827IOPMrootDomain::aotExit(bool cps)
7828{
7829 uint32_t savedMessageMask;
7830
7831 ASSERT_GATED();
7832 _aotNow = false;
7833 _aotReadyToFullWake = false;
7834 if (_aotTimerScheduled) {
7835 _aotTimerES->cancelTimeout();
7836 _aotTimerScheduled = false;
7837 }
7838 updateTasksSuspend(newTasksSuspended: kTasksSuspendNoChange, newAOTTasksSuspended: kTasksSuspendUnsuspended);
7839
7840 _aotMetrics->totalTime += mach_absolute_time() - _aotLastWakeTime;
7841 _aotLastWakeTime = 0;
7842 if (_aotMetrics->sleepCount && (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax)) {
7843 WAKEEVENT_LOCK();
7844 strlcpy(dst: &_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount - 1][0],
7845 src: gWakeReasonString,
7846 n: sizeof(_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount]));
7847 WAKEEVENT_UNLOCK();
7848 }
7849
7850 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
7851
7852 // Preserve the message mask since a system wake transition
7853 // may have already started and initialized the mask.
7854 savedMessageMask = _systemMessageClientMask;
7855 _systemMessageClientMask = kSystemMessageClientLegacyApp;
7856 tellClients(kIOMessageSystemWillPowerOn);
7857 _systemMessageClientMask = savedMessageMask | kSystemMessageClientLegacyApp;
7858
7859 if (cps) {
7860 changePowerStateWithTagToPriv(ordinal: getRUN_STATE(), reason: kCPSReasonAOTExit);
7861 }
7862}
7863
7864void
7865IOPMrootDomain::aotEvaluate(IOTimerEventSource * timer)
7866{
7867 bool exitNow;
7868
7869 IOLog(format: "aotEvaluate(%d) 0x%x\n", (timer != NULL), _aotPendingFlags);
7870
7871 WAKEEVENT_LOCK();
7872 exitNow = aotShouldExit(checkTimeSet: false, software: false);
7873 if (timer != NULL) {
7874 _aotTimerScheduled = false;
7875 }
7876 WAKEEVENT_UNLOCK();
7877 if (exitNow) {
7878 aotExit(cps: true);
7879 } else {
7880#if 0
7881 if (_aotLingerTime) {
7882 uint64_t deadline;
7883 IOLog("aot linger before sleep\n");
7884 clock_absolutetime_interval_to_deadline(_aotLingerTime, &deadline);
7885 clock_delay_until(deadline);
7886 }
7887#endif
7888 privateSleepSystem(sleepReason: kIOPMSleepReasonSoftware);
7889 }
7890}
7891
7892//******************************************************************************
7893// adjustPowerState
7894//
7895// Conditions that affect our wake/sleep decision has changed.
7896// If conditions dictate that the system must remain awake, clamp power
7897// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
7898// is TRUE, then remove the power clamp and allow the power state to drop
7899// to SLEEP_STATE.
7900//******************************************************************************
7901
7902void
7903IOPMrootDomain::adjustPowerState( bool sleepASAP )
7904{
7905 DEBUG_LOG("adjustPowerState %s, asap %d, idleSleepEnabled %d\n",
7906 getPowerStateString((uint32_t) getPowerState()), sleepASAP, idleSleepEnabled);
7907
7908 ASSERT_GATED();
7909
7910 if (_aotNow) {
7911 bool exitNow;
7912
7913 if (AOT_STATE != getPowerState()) {
7914 return;
7915 }
7916 WAKEEVENT_LOCK();
7917 exitNow = aotShouldExit(checkTimeSet: true, software: false);
7918 if (!exitNow
7919 && !_aotTimerScheduled
7920 && (kIOPMWakeEventAOTPossibleExit == (kIOPMWakeEventAOTPossibleFlags & _aotPendingFlags))) {
7921 _aotTimerScheduled = true;
7922 if (_aotLingerTime) {
7923 _aotTimerES->setTimeout(_aotLingerTime);
7924 } else {
7925 _aotTimerES->setTimeout(interval: 800, scale_factor: kMillisecondScale);
7926 }
7927 }
7928 WAKEEVENT_UNLOCK();
7929 if (exitNow) {
7930 aotExit(cps: true);
7931 } else {
7932 _aotReadyToFullWake = true;
7933 if (!_aotTimerScheduled) {
7934 if (kIOPMDriverAssertionLevelOn == getPMAssertionLevel(whichAssertionBits: kIOPMDriverAssertionCPUBit)) {
7935 // Don't try to force sleep during AOT while IOMobileFramebuffer is holding a power assertion.
7936 // Doing so will result in the sleep being cancelled anyway,
7937 // but this check avoids unnecessary thrashing in the power state engine.
7938 return;
7939 }
7940 privateSleepSystem(sleepReason: kIOPMSleepReasonSoftware);
7941 }
7942 }
7943 return;
7944 }
7945
7946 if ((!idleSleepEnabled) || !checkSystemSleepEnabled()) {
7947 changePowerStateWithTagToPriv(ordinal: getRUN_STATE(), reason: kCPSReasonAdjustPowerState);
7948 } else if (sleepASAP) {
7949 changePowerStateWithTagToPriv(ordinal: SLEEP_STATE, reason: kCPSReasonAdjustPowerState);
7950 }
7951}
7952
7953void
7954IOPMrootDomain::handleSetDisplayPowerOn(bool powerOn)
7955{
7956 if (powerOn) {
7957 if (!checkSystemCanSustainFullWake()) {
7958 DLOG("System cannot sustain full wake\n");
7959 return;
7960 }
7961
7962 // Force wrangler to max power state. If system is in dark wake
7963 // this alone won't raise the wrangler's power state.
7964 if (wrangler) {
7965 wrangler->changePowerStateForRootDomain(ordinal: kWranglerPowerStateMax);
7966 }
7967
7968 // System in dark wake, always requesting full wake should
7969 // not have any bad side-effects, even if the request fails.
7970
7971 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
7972 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
7973 requestFullWake( reason: kFullWakeReasonDisplayOn );
7974 }
7975 } else {
7976 // Relenquish desire to power up display.
7977 // Must first transition to state 1 since wrangler doesn't
7978 // power off the displays at state 0. At state 0 the root
7979 // domain is removed from the wrangler's power client list.
7980 if (wrangler) {
7981 wrangler->changePowerStateForRootDomain(ordinal: kWranglerPowerStateMin + 1);
7982 wrangler->changePowerStateForRootDomain(ordinal: kWranglerPowerStateMin);
7983 }
7984 }
7985}
7986
7987//******************************************************************************
7988// dispatchPowerEvent
7989//
7990// IOPMPowerStateQueue callback function. Running on PM work loop thread.
7991//******************************************************************************
7992
7993void
7994IOPMrootDomain::dispatchPowerEvent(
7995 uint32_t event, void * arg0, uint64_t arg1 )
7996{
7997 ASSERT_GATED();
7998
7999 switch (event) {
8000 case kPowerEventFeatureChanged:
8001 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8002 messageClients(kIOPMMessageFeatureChange, argument: this);
8003 break;
8004
8005 case kPowerEventReceivedPowerNotification:
8006 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8007 handlePowerNotification(msg: (UInt32)(uintptr_t) arg0 );
8008 break;
8009
8010 case kPowerEventSystemBootCompleted:
8011 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8012 if (systemBooting) {
8013 systemBooting = false;
8014
8015 if (PE_get_default(property_name: "sleep-disabled", property_ptr: &gSleepDisabledFlag, max_property: sizeof(gSleepDisabledFlag))) {
8016 DLOG("Setting gSleepDisabledFlag to %u from device tree\n", gSleepDisabledFlag);
8017 }
8018 if (lowBatteryCondition || thermalEmergencyState) {
8019 if (lowBatteryCondition) {
8020 privateSleepSystem(sleepReason: kIOPMSleepReasonLowPower);
8021 } else {
8022 privateSleepSystem(sleepReason: kIOPMSleepReasonThermalEmergency);
8023 }
8024 // The rest is unnecessary since the system is expected
8025 // to sleep immediately. The following wake will update
8026 // everything.
8027 break;
8028 }
8029
8030 sleepWakeDebugMemAlloc();
8031 saveFailureData2File();
8032
8033 // If lid is closed, re-send lid closed notification
8034 // now that booting is complete.
8035 if (clamshellClosed) {
8036 handlePowerNotification(kLocalEvalClamshellCommand);
8037 }
8038 evaluatePolicy( stimulus: kStimulusAllowSystemSleepChanged );
8039 }
8040 break;
8041
8042 case kPowerEventSystemShutdown:
8043 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8044 if (kOSBooleanTrue == (OSBoolean *) arg0) {
8045 /* We set systemShutdown = true during shutdown
8046 * to prevent sleep at unexpected times while loginwindow is trying
8047 * to shutdown apps and while the OS is trying to transition to
8048 * complete power of.
8049 *
8050 * Set to true during shutdown, as soon as loginwindow shows
8051 * the "shutdown countdown dialog", through individual app
8052 * termination, and through black screen kernel shutdown.
8053 */
8054 systemShutdown = true;
8055 } else {
8056 /*
8057 * A shutdown was initiated, but then the shutdown
8058 * was cancelled, clearing systemShutdown to false here.
8059 */
8060 systemShutdown = false;
8061 }
8062 break;
8063
8064 case kPowerEventUserDisabledSleep:
8065 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8066 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
8067 break;
8068
8069 case kPowerEventRegisterSystemCapabilityClient:
8070 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8071
8072 // reset() handles the arg0 == nullptr case for us
8073 systemCapabilityNotifier.reset(p: (IONotifier *) arg0, OSRetain);
8074 /* intentional fall-through */
8075 [[clang::fallthrough]];
8076
8077 case kPowerEventRegisterKernelCapabilityClient:
8078 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8079 if (!_joinedCapabilityClients) {
8080 _joinedCapabilityClients = OSSet::withCapacity(capacity: 8);
8081 }
8082 if (arg0) {
8083 OSSharedPtr<IONotifier> notify((IONotifier *) arg0, OSNoRetain);
8084 if (_joinedCapabilityClients) {
8085 _joinedCapabilityClients->setObject(notify.get());
8086 synchronizePowerTree( kIOPMSyncNoChildNotify );
8087 }
8088 }
8089 break;
8090
8091 case kPowerEventPolicyStimulus:
8092 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8093 if (arg0) {
8094 int stimulus = (int)(uintptr_t) arg0;
8095 evaluatePolicy(stimulus, arg: (uint32_t) arg1);
8096 }
8097 break;
8098
8099 case kPowerEventAssertionCreate:
8100 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8101 if (pmAssertions) {
8102 pmAssertions->handleCreateAssertion((OSValueObject<PMAssertStruct> *)arg0);
8103 }
8104 break;
8105
8106
8107 case kPowerEventAssertionRelease:
8108 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8109 if (pmAssertions) {
8110 pmAssertions->handleReleaseAssertion(arg1);
8111 }
8112 break;
8113
8114 case kPowerEventAssertionSetLevel:
8115 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8116 if (pmAssertions) {
8117 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
8118 }
8119 break;
8120
8121 case kPowerEventQueueSleepWakeUUID:
8122 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8123 handleQueueSleepWakeUUID(obj: (OSObject *)arg0);
8124 break;
8125 case kPowerEventPublishSleepWakeUUID:
8126 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8127 handlePublishSleepWakeUUID(shouldPublish: (bool)arg0);
8128 break;
8129
8130 case kPowerEventSetDisplayPowerOn:
8131 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8132 if (arg1 != 0) {
8133 displayPowerOnRequested = true;
8134 } else {
8135 displayPowerOnRequested = false;
8136 }
8137 handleSetDisplayPowerOn(powerOn: displayPowerOnRequested);
8138 break;
8139
8140 case kPowerEventPublishWakeType:
8141 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8142
8143 // Don't replace wake type property if already set
8144 if ((arg0 == gIOPMWakeTypeUserKey) ||
8145 !propertyExists(kIOPMRootDomainWakeTypeKey)) {
8146 const char * wakeType = NULL;
8147
8148 if (arg0 == gIOPMWakeTypeUserKey) {
8149 requestUserActive(device: this, reason: "WakeTypeUser");
8150 wakeType = kIOPMRootDomainWakeTypeUser;
8151 } else if (arg0 == gIOPMSettingDebugWakeRelativeKey) {
8152 if (!(gDarkWakeFlags & kDarkWakeFlagAlarmIsDark)) {
8153 requestUserActive(device: this, reason: "WakeTypeAlarm");
8154 }
8155 wakeType = kIOPMRootDomainWakeTypeAlarm;
8156 } else if (arg0 == gIOPMSettingSleepServiceWakeCalendarKey) {
8157 darkWakeSleepService = true;
8158 wakeType = kIOPMRootDomainWakeTypeSleepService;
8159 } else if (arg0 == gIOPMSettingMaintenanceWakeCalendarKey) {
8160 wakeType = kIOPMRootDomainWakeTypeMaintenance;
8161 }
8162
8163 if (wakeType) {
8164 setProperty(kIOPMRootDomainWakeTypeKey, aString: wakeType);
8165 }
8166 }
8167 break;
8168
8169 case kPowerEventAOTEvaluate:
8170 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8171 if (_aotReadyToFullWake) {
8172 aotEvaluate(NULL);
8173 }
8174 break;
8175 }
8176}
8177
8178//******************************************************************************
8179// systemPowerEventOccurred
8180//
8181// The power controller is notifying us of a hardware-related power management
8182// event that we must handle.
8183//
8184// systemPowerEventOccurred covers the same functionality that
8185// receivePowerNotification does; it simply provides a richer API for conveying
8186// more information.
8187//******************************************************************************
8188
8189IOReturn
8190IOPMrootDomain::systemPowerEventOccurred(
8191 const OSSymbol *event,
8192 uint32_t intValue)
8193{
8194 IOReturn attempt = kIOReturnSuccess;
8195 OSSharedPtr<OSNumber> newNumber;
8196
8197 if (!event) {
8198 return kIOReturnBadArgument;
8199 }
8200
8201 newNumber = OSNumber::withNumber(value: intValue, numberOfBits: 8 * sizeof(intValue));
8202 if (!newNumber) {
8203 return kIOReturnInternalError;
8204 }
8205
8206 attempt = systemPowerEventOccurred(event, value: static_cast<OSObject *>(newNumber.get()));
8207
8208 return attempt;
8209}
8210
8211void
8212IOPMrootDomain::setThermalState(OSObject *value)
8213{
8214 OSNumber * num;
8215
8216 if (gIOPMWorkLoop->inGate() == false) {
8217 gIOPMWorkLoop->runAction(
8218 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
8219 target: (OSObject *)this,
8220 arg0: (void *)value);
8221
8222 return;
8223 }
8224 if (value && (num = OSDynamicCast(OSNumber, value))) {
8225 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
8226 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
8227 }
8228}
8229
8230IOReturn
8231IOPMrootDomain::systemPowerEventOccurred(
8232 const OSSymbol *event,
8233 OSObject *value)
8234{
8235 OSSharedPtr<OSDictionary> thermalsDict;
8236 bool shouldUpdate = true;
8237
8238 if (!event || !value) {
8239 return kIOReturnBadArgument;
8240 }
8241
8242 // LOCK
8243 // We reuse featuresDict Lock because it already exists and guards
8244 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
8245 // of stepping on that lock.
8246 if (featuresDictLock) {
8247 IOLockLock(featuresDictLock);
8248 }
8249
8250 OSSharedPtr<OSObject> origThermalsProp = copyProperty(kIOPMRootDomainPowerStatusKey);
8251 OSDictionary * origThermalsDict = OSDynamicCast(OSDictionary, origThermalsProp.get());
8252
8253 if (origThermalsDict) {
8254 thermalsDict = OSDictionary::withDictionary(dict: origThermalsDict);
8255 } else {
8256 thermalsDict = OSDictionary::withCapacity(capacity: 1);
8257 }
8258
8259 if (!thermalsDict) {
8260 shouldUpdate = false;
8261 goto exit;
8262 }
8263
8264 thermalsDict->setObject(aKey: event, anObject: value);
8265
8266 setProperty(kIOPMRootDomainPowerStatusKey, anObject: thermalsDict.get());
8267
8268exit:
8269 // UNLOCK
8270 if (featuresDictLock) {
8271 IOLockUnlock(featuresDictLock);
8272 }
8273
8274 if (shouldUpdate) {
8275 if (event &&
8276 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
8277 setThermalState(value);
8278 }
8279 messageClients(kIOPMMessageSystemPowerEventOccurred, argument: (void *)NULL);
8280 }
8281
8282 return kIOReturnSuccess;
8283}
8284
8285//******************************************************************************
8286// receivePowerNotification
8287//
8288// The power controller is notifying us of a hardware-related power management
8289// event that we must handle. This may be a result of an 'environment' interrupt
8290// from the power mgt micro.
8291//******************************************************************************
8292
8293IOReturn
8294IOPMrootDomain::receivePowerNotification( UInt32 msg )
8295{
8296 if (msg & kIOPMPowerButton) {
8297 uint32_t currentPhase = pmTracer->getTracePhase();
8298 if (currentPhase != kIOPMTracePointSystemUp && currentPhase > kIOPMTracePointSystemSleep) {
8299 DEBUG_LOG("power button pressed during wake. phase = %u\n", currentPhase);
8300 swd_flags |= SWD_PWR_BTN_STACKSHOT;
8301 thread_call_enter(call: powerButtonDown);
8302 } else {
8303 DEBUG_LOG("power button pressed when system is up\n");
8304 }
8305 } else if (msg & kIOPMPowerButtonUp) {
8306 if (swd_flags & SWD_PWR_BTN_STACKSHOT) {
8307 swd_flags &= ~SWD_PWR_BTN_STACKSHOT;
8308 thread_call_enter(call: powerButtonUp);
8309 }
8310 } else {
8311 pmPowerStateQueue->submitPowerEvent(
8312 eventType: kPowerEventReceivedPowerNotification, arg0: (void *)(uintptr_t) msg );
8313 }
8314 return kIOReturnSuccess;
8315}
8316
8317void
8318IOPMrootDomain::handlePowerNotification( UInt32 msg )
8319{
8320 bool eval_clamshell = false;
8321 bool eval_clamshell_alarm = false;
8322
8323 ASSERT_GATED();
8324
8325 /*
8326 * Local (IOPMrootDomain only) eval clamshell command
8327 */
8328 if (msg & kLocalEvalClamshellCommand) {
8329 if ((gClamshellFlags & kClamshell_WAR_47715679) && isRTCAlarmWake) {
8330 eval_clamshell_alarm = true;
8331
8332 // reset isRTCAlarmWake. This evaluation should happen only once
8333 // on RTC/Alarm wake. Any clamshell events after wake should follow
8334 // the regular evaluation
8335 isRTCAlarmWake = false;
8336 } else {
8337 eval_clamshell = true;
8338 }
8339 }
8340
8341 /*
8342 * Overtemp
8343 */
8344 if (msg & kIOPMOverTemp) {
8345 DLOG("Thermal overtemp message received!\n");
8346 thermalEmergencyState = true;
8347 privateSleepSystem(sleepReason: kIOPMSleepReasonThermalEmergency);
8348 }
8349
8350 /*
8351 * Forward DW thermal notification to client, if system is not going to sleep
8352 */
8353 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep)) {
8354 DLOG("DarkWake thermal limits message received!\n");
8355 messageClients(kIOPMMessageDarkWakeThermalEmergency);
8356 }
8357
8358 /*
8359 * Sleep Now!
8360 */
8361 if (msg & kIOPMSleepNow) {
8362 privateSleepSystem(sleepReason: kIOPMSleepReasonSoftware);
8363 }
8364
8365 /*
8366 * Power Emergency
8367 */
8368 if (msg & kIOPMPowerEmergency) {
8369 DLOG("Received kIOPMPowerEmergency");
8370 lowBatteryCondition = true;
8371 privateSleepSystem(sleepReason: kIOPMSleepReasonLowPower);
8372 }
8373
8374 /*
8375 * Clamshell OPEN
8376 */
8377 if (msg & kIOPMClamshellOpened) {
8378 DLOG("Clamshell opened\n");
8379 // Received clamshel open message from clamshell controlling driver
8380 // Update our internal state and tell general interest clients
8381 clamshellClosed = false;
8382 clamshellExists = true;
8383
8384 // Don't issue a hid tickle when lid is open and polled on wake
8385 if (msg & kIOPMSetValue) {
8386 setProperty(kIOPMRootDomainWakeTypeKey, aString: "Lid Open");
8387 reportUserInput();
8388 }
8389
8390 // Tell PMCPU
8391 informCPUStateChange(type: kInformLid, value: 0);
8392
8393 // Tell general interest clients
8394 sendClientClamshellNotification();
8395
8396 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
8397 || (lastSleepReason == kIOPMSleepReasonIdle)
8398 || (lastSleepReason == kIOPMSleepReasonMaintenance));
8399 if (aborting) {
8400 userActivityCount++;
8401 }
8402 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
8403 }
8404
8405 /*
8406 * Clamshell CLOSED
8407 * Send the clamshell interest notification since the lid is closing.
8408 */
8409 if (msg & kIOPMClamshellClosed) {
8410 if ((clamshellIgnoreClose || (gClamshellFlags & kClamshell_WAR_38378787)) &&
8411 clamshellClosed && clamshellExists) {
8412 DLOG("Ignoring redundant Clamshell close event\n");
8413 } else {
8414 DLOG("Clamshell closed\n");
8415 // Received clamshel open message from clamshell controlling driver
8416 // Update our internal state and tell general interest clients
8417 clamshellClosed = true;
8418 clamshellExists = true;
8419
8420 // Ignore all following clamshell close events until the clamshell
8421 // is opened or the system sleeps. When a clamshell close triggers
8422 // a system wake, the lid driver may send us two clamshell close
8423 // events, one for the clamshell close event itself, and a second
8424 // close event when the driver polls the lid state on wake.
8425 clamshellIgnoreClose = true;
8426
8427 // Tell PMCPU
8428 informCPUStateChange(type: kInformLid, value: 1);
8429
8430 // Tell general interest clients
8431 sendClientClamshellNotification();
8432
8433 // And set eval_clamshell = so we can attempt
8434 eval_clamshell = true;
8435 }
8436 }
8437
8438 /*
8439 * Set Desktop mode (sent from graphics)
8440 *
8441 * -> reevaluate lid state
8442 */
8443 if (msg & kIOPMSetDesktopMode) {
8444 desktopMode = (0 != (msg & kIOPMSetValue));
8445 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
8446 DLOG("Desktop mode %d\n", desktopMode);
8447
8448 sendClientClamshellNotification();
8449
8450 // Re-evaluate the lid state
8451 eval_clamshell = true;
8452 }
8453
8454 /*
8455 * AC Adaptor connected
8456 *
8457 * -> reevaluate lid state
8458 */
8459 if (msg & kIOPMSetACAdaptorConnected) {
8460 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
8461 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
8462
8463 // Tell CPU PM
8464 informCPUStateChange(type: kInformAC, value: !acAdaptorConnected);
8465
8466 // Tell BSD if AC is connected
8467 // 0 == external power source; 1 == on battery
8468 post_sys_powersource(acAdaptorConnected ? 0:1);
8469
8470 sendClientClamshellNotification();
8471
8472 IOUserServer::powerSourceChanged(acAttached: acAdaptorConnected);
8473
8474 // Re-evaluate the lid state
8475 eval_clamshell = true;
8476
8477 // Lack of AC may have latched a display wrangler tickle.
8478 // This mirrors the hardware's USB wake event latch, where a latched
8479 // USB wake event followed by an AC attach will trigger a full wake.
8480 latchDisplayWranglerTickle( latch: false );
8481
8482#if HIBERNATION
8483 // AC presence will reset the standy timer delay adjustment.
8484 _standbyTimerResetSeconds = 0;
8485#endif
8486 if (!userIsActive) {
8487 // Reset userActivityTime when power supply is changed(rdr 13789330)
8488 clock_get_uptime(result: &userActivityTime);
8489 }
8490 }
8491
8492 /*
8493 * Enable Clamshell (external display disappear)
8494 *
8495 * -> reevaluate lid state
8496 */
8497 if (msg & kIOPMEnableClamshell) {
8498 DLOG("Clamshell enabled\n");
8499
8500 // Re-evaluate the lid state
8501 // System should sleep on external display disappearance
8502 // in lid closed operation.
8503 if (true == clamshellDisabled) {
8504 eval_clamshell = true;
8505
8506#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8507 // Also clear kClamshellSleepDisableInternal when graphics enables
8508 // the clamshell during a full wake. When graphics is behaving as
8509 // expected, this will allow clamshell close to be honored earlier
8510 // rather than waiting for the delayed evaluation.
8511 if ((clamshellSleepDisableMask & kClamshellSleepDisableInternal) &&
8512 (CAP_PENDING(kIOPMSystemCapabilityGraphics) ||
8513 CAP_CURRENT(kIOPMSystemCapabilityGraphics))) {
8514 setClamShellSleepDisable(false, kClamshellSleepDisableInternal);
8515
8516 // Cancel the TC to avoid an extra kLocalEvalClamshellCommand
8517 // when timer expires which is harmless but useless.
8518 thread_call_cancel(fullWakeThreadCall);
8519 }
8520#endif
8521 }
8522
8523 clamshellDisabled = false;
8524 sendClientClamshellNotification();
8525 }
8526
8527 /*
8528 * Disable Clamshell (external display appeared)
8529 * We don't bother re-evaluating clamshell state. If the system is awake,
8530 * the lid is probably open.
8531 */
8532 if (msg & kIOPMDisableClamshell) {
8533 DLOG("Clamshell disabled\n");
8534 clamshellDisabled = true;
8535 sendClientClamshellNotification();
8536 }
8537
8538 /*
8539 * Evaluate clamshell and SLEEP if appropriate
8540 */
8541 if (eval_clamshell_alarm && clamshellClosed) {
8542 if (shouldSleepOnRTCAlarmWake()) {
8543 privateSleepSystem(sleepReason: kIOPMSleepReasonClamshell);
8544 }
8545 } else if (eval_clamshell && clamshellClosed) {
8546 if (shouldSleepOnClamshellClosed()) {
8547 privateSleepSystem(sleepReason: kIOPMSleepReasonClamshell);
8548 } else {
8549 evaluatePolicy( stimulus: kStimulusDarkWakeEvaluate );
8550 }
8551 }
8552
8553 if (msg & kIOPMProModeEngaged) {
8554 int newState = 1;
8555 DLOG("ProModeEngaged\n");
8556 messageClient(kIOPMMessageProModeStateChange, client: systemCapabilityNotifier.get(), messageArgument: &newState, argSize: sizeof(newState));
8557 }
8558
8559 if (msg & kIOPMProModeDisengaged) {
8560 int newState = 0;
8561 DLOG("ProModeDisengaged\n");
8562 messageClient(kIOPMMessageProModeStateChange, client: systemCapabilityNotifier.get(), messageArgument: &newState, argSize: sizeof(newState));
8563 }
8564}
8565
8566//******************************************************************************
8567// evaluatePolicy
8568//
8569// Evaluate root-domain policy in response to external changes.
8570//******************************************************************************
8571
8572void
8573IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
8574{
8575 union {
8576 struct {
8577 int idleSleepEnabled : 1;
8578 int idleSleepDisabled : 1;
8579 int displaySleep : 1;
8580 int sleepDelayChanged : 1;
8581 int evaluateDarkWake : 1;
8582 int adjustPowerState : 1;
8583 int userBecameInactive : 1;
8584 int displaySleepEntry : 1;
8585 } bit;
8586 uint32_t u32;
8587 } flags;
8588
8589
8590 ASSERT_GATED();
8591 flags.u32 = 0;
8592
8593 switch (stimulus) {
8594 case kStimulusDisplayWranglerSleep:
8595 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8596 if (!wranglerPowerOff) {
8597 // wrangler is in sleep state or lower
8598 flags.bit.displaySleep = true;
8599 }
8600 if (!wranglerAsleep) {
8601 // transition from wrangler wake to wrangler sleep
8602 flags.bit.displaySleepEntry = true;
8603 wranglerAsleep = true;
8604 }
8605 break;
8606
8607 case kStimulusDisplayWranglerWake:
8608 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8609 displayIdleForDemandSleep = false;
8610 wranglerPowerOff = false;
8611 wranglerAsleep = false;
8612 break;
8613
8614 case kStimulusEnterUserActiveState:
8615 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8616 if (_preventUserActive) {
8617 DLOG("user active dropped\n");
8618 break;
8619 }
8620 if (!userIsActive) {
8621 userIsActive = true;
8622 userWasActive = true;
8623 clock_get_uptime(result: &gUserActiveAbsTime);
8624
8625 // Stay awake after dropping demand for display power on
8626 if (kFullWakeReasonDisplayOn == fullWakeReason) {
8627 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
8628 DLOG("User activity while in notification wake\n");
8629 changePowerStateWithOverrideTo( ordinal: getRUN_STATE(), reason: 0);
8630 }
8631
8632 kdebugTrace(event: kPMLogUserActiveState, regId: 0, param1: 1, param2: 0);
8633 setProperty(aKey: gIOPMUserIsActiveKey.get(), anObject: kOSBooleanTrue);
8634 messageClients(kIOPMMessageUserIsActiveChanged);
8635 }
8636 flags.bit.idleSleepDisabled = true;
8637 break;
8638
8639 case kStimulusLeaveUserActiveState:
8640 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8641 if (userIsActive) {
8642 clock_get_uptime(result: &gUserInactiveAbsTime);
8643 userIsActive = false;
8644 clock_get_uptime(result: &userBecameInactiveTime);
8645 flags.bit.userBecameInactive = true;
8646
8647 kdebugTrace(event: kPMLogUserActiveState, regId: 0, param1: 0, param2: 0);
8648 setProperty(aKey: gIOPMUserIsActiveKey.get(), anObject: kOSBooleanFalse);
8649 messageClients(kIOPMMessageUserIsActiveChanged);
8650 }
8651 break;
8652
8653 case kStimulusAggressivenessChanged:
8654 {
8655 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8656 unsigned long aggressiveValue;
8657 uint32_t minutesToIdleSleep = 0;
8658 uint32_t minutesToDisplayDim = 0;
8659 uint32_t minutesDelta = 0;
8660
8661 // Fetch latest display and system sleep slider values.
8662 aggressiveValue = 0;
8663 getAggressiveness(type: kPMMinutesToSleep, outLevel: &aggressiveValue);
8664 minutesToIdleSleep = (uint32_t) aggressiveValue;
8665
8666 aggressiveValue = 0;
8667 getAggressiveness(type: kPMMinutesToDim, outLevel: &aggressiveValue);
8668 minutesToDisplayDim = (uint32_t) aggressiveValue;
8669 DLOG("aggressiveness changed: system %u->%u, display %u\n",
8670 sleepSlider, minutesToIdleSleep, minutesToDisplayDim);
8671
8672 DLOG("idle time -> %d ms (ena %d)\n",
8673 idleMilliSeconds, (minutesToIdleSleep != 0));
8674
8675 // How long to wait before sleeping the system once
8676 // the displays turns off is indicated by 'extraSleepDelay'.
8677
8678 if (minutesToIdleSleep > minutesToDisplayDim) {
8679 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
8680 } else if (minutesToIdleSleep == minutesToDisplayDim) {
8681 minutesDelta = 1;
8682 }
8683
8684 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0)) {
8685 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
8686 }
8687
8688 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
8689 flags.bit.idleSleepDisabled = true;
8690 idleSleepEnabled = false;
8691 }
8692#if !defined(XNU_TARGET_OS_OSX)
8693 if (0x7fffffff == minutesToIdleSleep) {
8694 minutesToIdleSleep = idleMilliSeconds / 1000;
8695 }
8696#endif /* !defined(XNU_TARGET_OS_OSX) */
8697
8698 if (((minutesDelta != extraSleepDelay) ||
8699 (userActivityTime != userActivityTime_prev)) &&
8700 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled) {
8701 flags.bit.sleepDelayChanged = true;
8702 }
8703
8704 if (systemDarkWake && !darkWakeToSleepASAP &&
8705 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled)) {
8706 // Reconsider decision to remain in dark wake
8707 flags.bit.evaluateDarkWake = true;
8708 }
8709
8710 sleepSlider = minutesToIdleSleep;
8711 extraSleepDelay = minutesDelta;
8712 userActivityTime_prev = userActivityTime;
8713 } break;
8714
8715 case kStimulusDemandSystemSleep:
8716 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8717 displayIdleForDemandSleep = true;
8718 if (wrangler && wranglerIdleSettings) {
8719 // Request wrangler idle only when demand sleep is triggered
8720 // from full wake.
8721 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
8722 wrangler->setProperties(wranglerIdleSettings.get());
8723 DLOG("Requested wrangler idle\n");
8724 }
8725 }
8726 // arg = sleepReason
8727 changePowerStateWithOverrideTo( ordinal: SLEEP_STATE, reason: arg );
8728 break;
8729
8730 case kStimulusAllowSystemSleepChanged:
8731 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8732 flags.bit.adjustPowerState = true;
8733 break;
8734
8735 case kStimulusDarkWakeActivityTickle:
8736 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8737 // arg == true implies real and not self generated wrangler tickle.
8738 // Update wake type on PM work loop instead of the tickle thread to
8739 // eliminate the possibility of an early tickle clobbering the wake
8740 // type set by the platform driver.
8741 if (arg == true) {
8742 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
8743 }
8744
8745 if (!darkWakeExit) {
8746 if (latchDisplayWranglerTickle(latch: true)) {
8747 DLOG("latched tickle\n");
8748 break;
8749 }
8750
8751 darkWakeExit = true;
8752 DLOG("Requesting full wake due to dark wake activity tickle\n");
8753 requestFullWake( reason: kFullWakeReasonLocalUser );
8754 }
8755 break;
8756
8757 case kStimulusDarkWakeEntry:
8758 case kStimulusDarkWakeReentry:
8759 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8760 // Any system transitions since the last dark wake transition
8761 // will invalid the stimulus.
8762
8763 if (arg == _systemStateGeneration) {
8764 DLOG("dark wake entry\n");
8765 systemDarkWake = true;
8766
8767 // Keep wranglerPowerOff an invariant when wrangler is absent
8768 if (wrangler) {
8769 wranglerPowerOff = true;
8770 }
8771
8772 if (kStimulusDarkWakeEntry == stimulus) {
8773 clock_get_uptime(result: &userBecameInactiveTime);
8774 flags.bit.evaluateDarkWake = true;
8775 if (activitySinceSleep()) {
8776 DLOG("User activity recorded while going to darkwake\n");
8777 reportUserInput();
8778 }
8779 }
8780
8781 // Always accelerate disk spindown while in dark wake,
8782 // even if system does not support/allow sleep.
8783
8784 cancelIdleSleepTimer();
8785 setQuickSpinDownTimeout();
8786 }
8787 break;
8788
8789 case kStimulusDarkWakeEvaluate:
8790 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8791 if (systemDarkWake) {
8792 flags.bit.evaluateDarkWake = true;
8793 }
8794 break;
8795
8796 case kStimulusNoIdleSleepPreventers:
8797 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8798 flags.bit.adjustPowerState = true;
8799 break;
8800 } /* switch(stimulus) */
8801
8802 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason)) {
8803 DLOG("DarkWake: sleepASAP %d, clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
8804 darkWakeToSleepASAP, clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
8805 if (darkWakeToSleepASAP ||
8806 (clamshellClosed && !(desktopMode && acAdaptorConnected))) {
8807 uint32_t newSleepReason;
8808
8809 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
8810 // System was previously in full wake. Sleep reason from
8811 // full to dark already recorded in fullToDarkReason.
8812
8813 if (lowBatteryCondition) {
8814 newSleepReason = kIOPMSleepReasonLowPower;
8815 } else if (thermalEmergencyState) {
8816 newSleepReason = kIOPMSleepReasonThermalEmergency;
8817 } else {
8818 newSleepReason = fullToDarkReason;
8819 }
8820 } else {
8821 // In dark wake from system sleep.
8822
8823 if (darkWakeSleepService) {
8824 newSleepReason = kIOPMSleepReasonSleepServiceExit;
8825 } else {
8826 newSleepReason = kIOPMSleepReasonMaintenance;
8827 }
8828 }
8829
8830 if (checkSystemCanSleep(sleepReason: newSleepReason)) {
8831 privateSleepSystem(sleepReason: newSleepReason);
8832 }
8833 } else { // non-maintenance (network) dark wake
8834 if (checkSystemCanSleep(sleepReason: kIOPMSleepReasonIdle)) {
8835 // Release power clamp, and wait for children idle.
8836 adjustPowerState(sleepASAP: true);
8837 } else {
8838 changePowerStateWithTagToPriv(ordinal: getRUN_STATE(), reason: kCPSReasonDarkWakeCannotSleep);
8839 }
8840 }
8841 }
8842
8843 if (systemDarkWake) {
8844 // The rest are irrelevant while system is in dark wake.
8845 flags.u32 = 0;
8846 }
8847
8848 if ((flags.bit.displaySleepEntry) &&
8849 (kFullWakeReasonDisplayOn == fullWakeReason)) {
8850 // kIOPMSleepReasonNotificationWakeExit
8851 DLOG("Display sleep while in notification wake\n");
8852 changePowerStateWithOverrideTo(ordinal: SLEEP_STATE, reason: kIOPMSleepReasonNotificationWakeExit);
8853 }
8854
8855 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged) {
8856 bool cancelQuickSpindown = false;
8857
8858 if (flags.bit.sleepDelayChanged) {
8859 // Cancel existing idle sleep timer and quick disk spindown.
8860 // New settings will be applied by the idleSleepEnabled flag
8861 // handler below if idle sleep is enabled.
8862
8863 DLOG("extra sleep timer changed\n");
8864 cancelIdleSleepTimer();
8865 cancelQuickSpindown = true;
8866 } else {
8867 DLOG("user inactive\n");
8868 }
8869
8870 if (!userIsActive && idleSleepEnabled) {
8871 startIdleSleepTimer(inMilliSeconds: getTimeToIdleSleep());
8872 }
8873
8874 if (cancelQuickSpindown) {
8875 restoreUserSpinDownTimeout();
8876 }
8877 }
8878
8879 if (flags.bit.idleSleepEnabled) {
8880 DLOG("idle sleep timer enabled\n");
8881 if (!wrangler) {
8882#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8883 startIdleSleepTimer(inMilliSeconds: getTimeToIdleSleep());
8884#else
8885 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonIdleSleepEnabled);
8886 startIdleSleepTimer( idleMilliSeconds );
8887#endif
8888 } else {
8889 // Start idle timer if prefs now allow system sleep
8890 // and user is already inactive. Disk spindown is
8891 // accelerated upon timer expiration.
8892
8893 if (!userIsActive) {
8894 startIdleSleepTimer(inMilliSeconds: getTimeToIdleSleep());
8895 }
8896 }
8897 }
8898
8899 if (flags.bit.idleSleepDisabled) {
8900 DLOG("idle sleep timer disabled\n");
8901 cancelIdleSleepTimer();
8902 restoreUserSpinDownTimeout();
8903 adjustPowerState();
8904 }
8905
8906 if (flags.bit.adjustPowerState) {
8907 bool sleepASAP = false;
8908
8909 if (!systemBooting && (0 == idleSleepPreventersCount())) {
8910 if (!wrangler) {
8911 changePowerStateWithTagToPriv(ordinal: getRUN_STATE(), reason: kCPSReasonEvaluatePolicy);
8912 if (idleSleepEnabled) {
8913#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8914 if (!extraSleepDelay && !idleSleepTimerPending && !gNoIdleFlag) {
8915 sleepASAP = true;
8916 }
8917#else
8918 // stay awake for at least idleMilliSeconds
8919 startIdleSleepTimer(idleMilliSeconds);
8920#endif
8921 }
8922 } else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake && !gNoIdleFlag) {
8923 sleepASAP = true;
8924 }
8925 }
8926
8927 adjustPowerState(sleepASAP);
8928 }
8929}
8930
8931//******************************************************************************
8932
8933unsigned int
8934IOPMrootDomain::idleSleepPreventersCount()
8935{
8936 if (_aotMode) {
8937 unsigned int count __block;
8938 count = 0;
8939 preventIdleSleepList->iterateObjects(block: ^bool (OSObject * obj)
8940 {
8941 count += (NULL == obj->metaCast(toMeta: "AppleARMBacklight"));
8942 return false;
8943 });
8944 return count;
8945 }
8946
8947 return preventIdleSleepList->getCount();
8948}
8949
8950
8951//******************************************************************************
8952// requestFullWake
8953//
8954// Request transition from dark wake to full wake
8955//******************************************************************************
8956
8957void
8958IOPMrootDomain::requestFullWake( FullWakeReason reason )
8959{
8960 uint32_t options = 0;
8961 IOService * pciRoot = NULL;
8962 bool promotion = false;
8963
8964 // System must be in dark wake and a valid reason for entering full wake
8965 if ((kFullWakeReasonNone == reason) ||
8966 (kFullWakeReasonNone != fullWakeReason) ||
8967 (CAP_CURRENT(kIOPMSystemCapabilityGraphics))) {
8968 return;
8969 }
8970
8971 // Will clear reason upon exit from full wake
8972 fullWakeReason = reason;
8973
8974 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
8975 kIOPMSystemCapabilityAudio);
8976
8977 if ((kSystemTransitionWake == _systemTransitionType) &&
8978 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
8979 !darkWakePowerClamped) {
8980 // Promote to full wake while waking up to dark wake due to tickle.
8981 // PM will hold off notifying the graphics subsystem about system wake
8982 // as late as possible, so if a HID tickle does arrive, graphics can
8983 // power up from this same wake transition. Otherwise, the latency to
8984 // power up graphics on the following transition can be huge on certain
8985 // systems. However, once any power clamping has taken effect, it is
8986 // too late to promote the current dark wake transition to a full wake.
8987 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
8988 kIOPMSystemCapabilityAudio);
8989
8990 // Tell the PCI parent of audio and graphics drivers to stop
8991 // delaying the child notifications. Same for root domain.
8992 pciRoot = pciHostBridgeDriver.get();
8993 willEnterFullWake();
8994 promotion = true;
8995 }
8996
8997 // Unsafe to cancel once graphics was powered.
8998 // If system woke from dark wake, the return to sleep can
8999 // be cancelled. "awake -> dark -> sleep" transition
9000 // can be cancelled also, during the "dark -> sleep" phase
9001 // *prior* to driver power down.
9002 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
9003 _pendingCapability == 0) {
9004 options |= kIOPMSyncCancelPowerDown;
9005 }
9006
9007 synchronizePowerTree(options, notifyRoot: pciRoot);
9008
9009 if (kFullWakeReasonLocalUser == fullWakeReason) {
9010 // IOGraphics doesn't light the display even though graphics is
9011 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
9012 // So, do an explicit activity tickle
9013 if (wrangler) {
9014 wrangler->activityTickle(type: 0, stateNumber: 0);
9015 }
9016 }
9017
9018 // Log a timestamp for the initial full wake request.
9019 // System may not always honor this full wake request.
9020 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
9021 AbsoluteTime now;
9022 uint64_t nsec;
9023
9024 clock_get_uptime(result: &now);
9025 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
9026 absolutetime_to_nanoseconds(abstime: now, result: &nsec);
9027 MSG("full wake %s (reason %u) %u ms\n",
9028 promotion ? "promotion" : "request",
9029 fullWakeReason, ((int)((nsec) / NSEC_PER_MSEC)));
9030 }
9031}
9032
9033//******************************************************************************
9034// willEnterFullWake
9035//
9036// System will enter full wake from sleep, from dark wake, or from dark
9037// wake promotion. This function aggregate things that are in common to
9038// all three full wake transitions.
9039//
9040// Assumptions: fullWakeReason was updated
9041//******************************************************************************
9042
9043void
9044IOPMrootDomain::willEnterFullWake( void )
9045{
9046 hibernateRetry = false;
9047 sleepToStandby = false;
9048 standbyNixed = false;
9049 resetTimers = false;
9050 sleepTimerMaintenance = false;
9051
9052 assert(!CAP_CURRENT(kIOPMSystemCapabilityGraphics));
9053
9054 _systemMessageClientMask = kSystemMessageClientPowerd |
9055 kSystemMessageClientLegacyApp;
9056
9057 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) {
9058 // First time to attain full wake capability since the last wake
9059 _systemMessageClientMask |= kSystemMessageClientKernel;
9060
9061 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
9062 setProperty(aKey: gIOPMUserTriggeredFullWakeKey.get(),
9063 anObject: (kFullWakeReasonLocalUser == fullWakeReason) ?
9064 kOSBooleanTrue : kOSBooleanFalse);
9065 }
9066#if HIBERNATION
9067 IOHibernateSetWakeCapabilities(_pendingCapability);
9068#endif
9069
9070 IOService::setAdvisoryTickleEnable( true );
9071 tellClients(kIOMessageSystemWillPowerOn);
9072 preventTransitionToUserActive(prevent: false);
9073}
9074
9075//******************************************************************************
9076// fullWakeDelayedWork
9077//
9078// System has already entered full wake. Invoked by a delayed thread call.
9079//******************************************************************************
9080
9081void
9082IOPMrootDomain::fullWakeDelayedWork( void )
9083{
9084#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
9085 if (!gIOPMWorkLoop->inGate()) {
9086 gIOPMWorkLoop->runAction(
9087 OSMemberFunctionCast(IOWorkLoop::Action, this,
9088 &IOPMrootDomain::fullWakeDelayedWork), this);
9089 return;
9090 }
9091
9092 DLOG("fullWakeDelayedWork cap cur %x pend %x high %x, clamshell disable %x/%x\n",
9093 _currentCapability, _pendingCapability, _highestCapability,
9094 clamshellDisabled, clamshellSleepDisableMask);
9095
9096 if (clamshellExists &&
9097 CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
9098 !CAP_CHANGE(kIOPMSystemCapabilityGraphics)) {
9099 if (clamshellSleepDisableMask & kClamshellSleepDisableInternal) {
9100 setClamShellSleepDisable(false, kClamshellSleepDisableInternal);
9101 } else {
9102 // Not the initial full wake after waking from sleep.
9103 // Evaluate the clamshell for rdar://problem/9157444.
9104 receivePowerNotification(kLocalEvalClamshellCommand);
9105 }
9106 }
9107#endif
9108}
9109
9110//******************************************************************************
9111// evaluateAssertions
9112//
9113//******************************************************************************
9114
9115// Bitmask of all kernel assertions that prevent system idle sleep.
9116// kIOPMDriverAssertionReservedBit7 is reserved for IOMediaBSDClient.
9117#define NO_IDLE_SLEEP_ASSERTIONS_MASK \
9118 (kIOPMDriverAssertionReservedBit7 | \
9119 kIOPMDriverAssertionPreventSystemIdleSleepBit)
9120
9121void
9122IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
9123{
9124 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
9125
9126 messageClients(kIOPMMessageDriverAssertionsChanged);
9127
9128 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
9129 if (wrangler) {
9130 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
9131
9132 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
9133 wrangler->setIgnoreIdleTimer( value );
9134 }
9135 }
9136
9137 if (changedBits & kIOPMDriverAssertionCPUBit) {
9138 if (_aotNow) {
9139 IOLog(format: "CPU assertions %d\n", (0 != (kIOPMDriverAssertionCPUBit & newAssertions)));
9140 }
9141 evaluatePolicy(stimulus: _aotNow ? kStimulusNoIdleSleepPreventers : kStimulusDarkWakeEvaluate);
9142 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
9143 AbsoluteTime now;
9144 clock_usec_t microsecs;
9145 clock_get_uptime(result: &now);
9146 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
9147 absolutetime_to_microtime(abstime: now, secs: &assertOnWakeSecs, microsecs: &microsecs);
9148 if (assertOnWakeReport) {
9149 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
9150 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
9151 }
9152 }
9153 }
9154
9155 if (changedBits & NO_IDLE_SLEEP_ASSERTIONS_MASK) {
9156 if ((newAssertions & NO_IDLE_SLEEP_ASSERTIONS_MASK) != 0) {
9157 if ((oldAssertions & NO_IDLE_SLEEP_ASSERTIONS_MASK) == 0) {
9158 DLOG("PreventIdleSleep driver assertion raised\n");
9159 bool ok = updatePreventIdleSleepList(service: this, addNotRemove: true);
9160 if (ok && (changedBits & kIOPMDriverAssertionPreventSystemIdleSleepBit)) {
9161 // Cancel idle sleep if there is one in progress
9162 cancelIdlePowerDown(service: this);
9163 }
9164 }
9165 } else {
9166 DLOG("PreventIdleSleep driver assertion dropped\n");
9167 updatePreventIdleSleepList(service: this, addNotRemove: false);
9168 }
9169 }
9170}
9171
9172// MARK: -
9173// MARK: Statistics
9174
9175//******************************************************************************
9176// pmStats
9177//
9178//******************************************************************************
9179
9180void
9181IOPMrootDomain::pmStatsRecordEvent(
9182 int eventIndex,
9183 AbsoluteTime timestamp)
9184{
9185 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
9186 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
9187 uint64_t delta;
9188 uint64_t nsec;
9189 OSSharedPtr<OSData> publishPMStats;
9190
9191 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
9192
9193 absolutetime_to_nanoseconds(abstime: timestamp, result: &nsec);
9194
9195 switch (eventIndex) {
9196 case kIOPMStatsHibernateImageWrite:
9197 if (starting) {
9198 gPMStats.hibWrite.start = nsec;
9199 } else if (stopping) {
9200 gPMStats.hibWrite.stop = nsec;
9201 }
9202
9203 if (stopping) {
9204 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
9205 IOLog(format: "PMStats: Hibernate write took %qd ms\n", delta / NSEC_PER_MSEC);
9206 }
9207 break;
9208 case kIOPMStatsHibernateImageRead:
9209 if (starting) {
9210 gPMStats.hibRead.start = nsec;
9211 } else if (stopping) {
9212 gPMStats.hibRead.stop = nsec;
9213 }
9214
9215 if (stopping) {
9216 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
9217 IOLog(format: "PMStats: Hibernate read took %qd ms\n", delta / NSEC_PER_MSEC);
9218
9219 publishPMStats = OSData::withValue(value: gPMStats);
9220 setProperty(kIOPMSleepStatisticsKey, anObject: publishPMStats.get());
9221 bzero(s: &gPMStats, n: sizeof(gPMStats));
9222 }
9223 break;
9224 }
9225}
9226
9227/*
9228 * Appends a record of the application response to
9229 * IOPMrootDomain::pmStatsAppResponses
9230 */
9231void
9232IOPMrootDomain::pmStatsRecordApplicationResponse(
9233 const OSSymbol *response,
9234 const char *name,
9235 int messageType,
9236 uint32_t delay_ms,
9237 uint64_t id,
9238 OSObject *object,
9239 IOPMPowerStateIndex powerState,
9240 bool async)
9241{
9242 OSSharedPtr<OSDictionary> responseDescription;
9243 OSSharedPtr<OSNumber> delayNum;
9244 OSSharedPtr<OSNumber> powerCaps;
9245 OSSharedPtr<OSNumber> pidNum;
9246 OSSharedPtr<OSNumber> msgNum;
9247 OSSharedPtr<const OSSymbol> appname;
9248 OSSharedPtr<const OSSymbol> sleep;
9249 OSSharedPtr<const OSSymbol> wake;
9250 IOPMServiceInterestNotifier *notify = NULL;
9251
9252 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object))) {
9253 if (response->isEqualTo(aSymbol: gIOPMStatsResponseTimedOut.get())) {
9254 notify->ackTimeoutCnt++;
9255 } else {
9256 notify->ackTimeoutCnt = 0;
9257 }
9258 }
9259
9260 if (response->isEqualTo(aSymbol: gIOPMStatsResponsePrompt.get()) ||
9261 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient)) {
9262 return;
9263 }
9264
9265
9266 if (response->isEqualTo(aSymbol: gIOPMStatsDriverPSChangeSlow.get())) {
9267 kdebugTrace(event: kPMLogDrvPSChangeDelay, regId: id, param1: messageType, param2: delay_ms);
9268 } else if (notify) {
9269 // User space app or kernel capability client
9270 if (id) {
9271 kdebugTrace(event: kPMLogAppResponseDelay, regId: id, param1: notify->msgType, param2: delay_ms);
9272 } else {
9273 kdebugTrace(event: kPMLogDrvResponseDelay, regId: notify->uuid0, param1: messageType, param2: delay_ms);
9274 }
9275 notify->msgType = 0;
9276 }
9277
9278 responseDescription = OSDictionary::withCapacity(capacity: 5);
9279 if (responseDescription) {
9280 if (response) {
9281 responseDescription->setObject(aKey: _statsResponseTypeKey.get(), anObject: response);
9282 }
9283
9284 msgNum = OSNumber::withNumber(value: messageType, numberOfBits: 32);
9285 if (msgNum) {
9286 responseDescription->setObject(aKey: _statsMessageTypeKey.get(), anObject: msgNum.get());
9287 }
9288
9289 if (!name && notify && notify->identifier) {
9290 name = notify->identifier->getCStringNoCopy();
9291 }
9292
9293 if (name && (strlen(s: name) > 0)) {
9294 appname = OSSymbol::withCString(cString: name);
9295 if (appname) {
9296 responseDescription->setObject(aKey: _statsNameKey.get(), anObject: appname.get());
9297 }
9298 }
9299
9300 if (!id && notify) {
9301 id = notify->uuid0;
9302 }
9303 pidNum = OSNumber::withNumber(value: id, numberOfBits: 64);
9304 if (pidNum) {
9305 responseDescription->setObject(aKey: _statsPIDKey.get(), anObject: pidNum.get());
9306 }
9307
9308 delayNum = OSNumber::withNumber(value: delay_ms, numberOfBits: 32);
9309 if (delayNum) {
9310 responseDescription->setObject(aKey: _statsTimeMSKey.get(), anObject: delayNum.get());
9311 }
9312
9313 if (response->isEqualTo(aSymbol: gIOPMStatsDriverPSChangeSlow.get())) {
9314 powerCaps = OSNumber::withNumber(value: powerState, numberOfBits: 32);
9315
9316#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
9317 static const char * driverCallTypes[] = {
9318 [kDriverCallInformPreChange] = "powerStateWillChangeTo",
9319 [kDriverCallInformPostChange] = "powerStateDidChangeTo",
9320 [kDriverCallSetPowerState] = "setPowerState"
9321 };
9322
9323 if (messageType < (sizeof(driverCallTypes) / sizeof(driverCallTypes[0]))) {
9324 DLOG("%s[0x%qx]::%s(%u) %stook %d ms\n",
9325 name, id, driverCallTypes[messageType], (uint32_t) powerState,
9326 async ? "async " : "", delay_ms);
9327 }
9328#endif
9329 } else {
9330 powerCaps = OSNumber::withNumber(value: _pendingCapability, numberOfBits: 32);
9331 }
9332 if (powerCaps) {
9333 responseDescription->setObject(aKey: _statsPowerCapsKey.get(), anObject: powerCaps.get());
9334 }
9335
9336 sleep = OSSymbol::withCString(cString: "Sleep");
9337 wake = OSSymbol::withCString(cString: "Wake");
9338 if (_systemTransitionType == kSystemTransitionSleep) {
9339 responseDescription->setObject(kIOPMStatsSystemTransitionKey, anObject: sleep.get());
9340 } else if (_systemTransitionType == kSystemTransitionWake) {
9341 responseDescription->setObject(kIOPMStatsSystemTransitionKey, anObject: wake.get());
9342 } else if (_systemTransitionType == kSystemTransitionCapability) {
9343 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
9344 responseDescription->setObject(kIOPMStatsSystemTransitionKey, anObject: sleep.get());
9345 } else if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
9346 responseDescription->setObject(kIOPMStatsSystemTransitionKey, anObject: wake.get());
9347 }
9348 }
9349
9350 IOLockLock(pmStatsLock);
9351 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
9352 pmStatsAppResponses->setObject(responseDescription.get());
9353 }
9354 IOLockUnlock(pmStatsLock);
9355 }
9356
9357 return;
9358}
9359
9360// MARK: -
9361// MARK: PMTraceWorker
9362
9363//******************************************************************************
9364// TracePoint support
9365//
9366//******************************************************************************
9367
9368#define kIOPMRegisterNVRAMTracePointHandlerKey \
9369 "IOPMRegisterNVRAMTracePointHandler"
9370
9371IOReturn
9372IOPMrootDomain::callPlatformFunction(
9373 const OSSymbol * functionName,
9374 bool waitForFunction,
9375 void * param1, void * param2,
9376 void * param3, void * param4 )
9377{
9378 if (pmTracer && functionName &&
9379 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
9380 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget) {
9381 uint32_t tracePointPhases, tracePointPCI;
9382 uint64_t statusCode;
9383
9384 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
9385 pmTracer->tracePointTarget = (void *) param2;
9386 tracePointPCI = (uint32_t)(uintptr_t) param3;
9387 tracePointPhases = (uint32_t)(uintptr_t) param4;
9388 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
9389 OSSharedPtr<IORegistryEntry> node = IORegistryEntry::fromPath( path: "/chosen", plane: gIODTPlane );
9390 if (node) {
9391 OSSharedPtr<OSObject> bootRomFailureProp;
9392 bootRomFailureProp = node->copyProperty(kIOEFIBootRomFailureKey);
9393 OSData *data = OSDynamicCast(OSData, bootRomFailureProp.get());
9394 uint32_t bootFailureCode;
9395 if (data && data->getLength() == sizeof(bootFailureCode)) {
9396 // Failure code from EFI/BootRom is a four byte structure
9397 memcpy(dst: &bootFailureCode, src: data->getBytesNoCopy(), n: sizeof(bootFailureCode));
9398 tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
9399 }
9400 }
9401 }
9402 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
9403 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
9404 MSG("Sleep failure code 0x%08x 0x%08x\n",
9405 tracePointPCI, tracePointPhases);
9406 }
9407 setProperty(kIOPMSleepWakeFailureCodeKey, aValue: statusCode, aNumberOfBits: 64);
9408 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
9409
9410 return kIOReturnSuccess;
9411 }
9412#if HIBERNATION
9413 else if (functionName &&
9414 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey)) {
9415 if (gSleepPolicyHandler) {
9416 return kIOReturnExclusiveAccess;
9417 }
9418 if (!param1) {
9419 return kIOReturnBadArgument;
9420 }
9421 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
9422 gSleepPolicyTarget = (void *) param2;
9423 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
9424 return kIOReturnSuccess;
9425 }
9426#endif
9427
9428 return super::callPlatformFunction(
9429 functionName, waitForFunction, param1, param2, param3, param4);
9430}
9431
9432void
9433IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
9434 uintptr_t param1, uintptr_t param2, uintptr_t param3)
9435{
9436 uint32_t code = IODBG_POWER(event);
9437 uint64_t regId = id;
9438 if (regId == 0) {
9439 regId = getRegistryEntryID();
9440 }
9441 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, code, (uintptr_t) regId, param1, param2, param3, 0);
9442}
9443
9444void
9445IOPMrootDomain::tracePoint( uint8_t point )
9446{
9447 if (systemBooting) {
9448 return;
9449 }
9450
9451 if (kIOPMTracePointWakeCapabilityClients == point) {
9452 acceptSystemWakeEvents(control: kAcceptSystemWakeEvents_Disable);
9453 }
9454
9455 kdebugTrace(event: kPMLogSleepWakeTracePoint, id: 0, param1: point, param2: 0);
9456 pmTracer->tracePoint(phase: point);
9457}
9458
9459static void
9460kext_log_putc(char c)
9461{
9462 if (gKextNameEnd || gKextNamePos >= (sizeof(gKextNameBuf) - 1)) {
9463 return;
9464 }
9465 if (c == '(' || c == '[' || c == ' ') {
9466 c = 0;
9467 gKextNameEnd = true;
9468 }
9469
9470 gKextNameBuf[gKextNamePos++] = c;
9471}
9472
9473static int
9474kext_log(const char *fmt, ...)
9475{
9476 va_list listp;
9477
9478 va_start(listp, fmt);
9479 _doprnt(format: fmt, arg: &listp, lputc: &kext_log_putc, radix: 16);
9480 va_end(listp);
9481
9482 return 0;
9483}
9484
9485static OSPtr<const OSSymbol>
9486copyKextIdentifierWithAddress(vm_address_t address)
9487{
9488 OSSharedPtr<const OSSymbol> identifer;
9489
9490 IOLockLock(gHaltLogLock);
9491
9492 gKextNameEnd = false;
9493 gKextNamePos = 0;
9494 gKextNameBuf[0] = 0;
9495
9496 OSKext::printKextsInBacktrace(addr: &address, cnt: 1, printf_func: kext_log, flags: OSKext::kPrintKextsLock | OSKext::kPrintKextsTerse);
9497 gKextNameBuf[sizeof(gKextNameBuf) - 1] = 0;
9498 identifer = OSSymbol::withCString(cString: (gKextNameBuf[0] != 0) ? gKextNameBuf : kOSKextKernelIdentifier);
9499
9500 IOLockUnlock(gHaltLogLock);
9501
9502 return identifer;
9503}
9504
9505// Caller serialized using PM workloop
9506const char *
9507IOPMrootDomain::getNotificationClientName(OSObject *object)
9508{
9509 IOPMServiceInterestNotifier *notifier = (typeof(notifier))object;
9510 const char *clientName = "UNKNOWN";
9511
9512 if (!notifier->clientName) {
9513 // Check for user client
9514 if (systemCapabilityNotifier && (((IOPMServiceInterestNotifier *) systemCapabilityNotifier.get())->handler == notifier->handler)) {
9515 OSNumber *clientID = NULL;
9516 messageClient(kIOMessageCopyClientID, client: object, messageArgument: &clientID);
9517 if (clientID) {
9518 OSSharedPtr<OSString> string(IOCopyLogNameForPID(pid: clientID->unsigned32BitValue()), OSNoRetain);
9519 if (string) {
9520 notifier->clientName = OSSymbol::withString(aString: string.get());
9521 }
9522 clientID->release();
9523 }
9524 } else if (notifier->identifier) {
9525 notifier->clientName.reset(p: notifier->identifier.get(), OSRetain);
9526 }
9527 }
9528
9529 if (notifier->clientName) {
9530 clientName = notifier->clientName->getCStringNoCopy();
9531 }
9532
9533 return clientName;
9534}
9535
9536void
9537IOPMrootDomain::traceNotification(OSObject *object, bool start, uint64_t timestamp, uint32_t msgIndex)
9538{
9539 IOPMServiceInterestNotifier *notifier;
9540
9541 if (systemBooting) {
9542 return;
9543 }
9544 notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9545 if (!notifier) {
9546 return;
9547 }
9548
9549 if (start) {
9550 pmTracer->traceDetail(detail: notifier->uuid0 >> 32);
9551 kdebugTrace(event: kPMLogSleepWakeMessage, id: pmTracer->getTracePhase(),
9552 param1: (uintptr_t) notifier->msgType, param2: (uintptr_t) notifier->uuid0, param3: (uintptr_t) notifier->uuid1);
9553
9554 // Update notifier state used for response/ack logging
9555 notifier->msgIndex = msgIndex;
9556 notifier->msgAbsTime = timestamp;
9557
9558 if (msgIndex != UINT_MAX) {
9559 DLOG("%s[%u] to %s\n", getIOMessageString(notifier->msgType), msgIndex, getNotificationClientName(notifier));
9560 } else {
9561 DLOG("%s to %s\n", getIOMessageString(notifier->msgType), getNotificationClientName(notifier));
9562 }
9563
9564 assert(notifierObject == NULL);
9565 notifierThread = current_thread();
9566 notifierObject.reset(p: notifier, OSRetain);
9567 } else {
9568 uint64_t nsec;
9569 uint32_t delayMS;
9570
9571 SUB_ABSOLUTETIME(&timestamp, &notifier->msgAbsTime);
9572 absolutetime_to_nanoseconds(abstime: timestamp, result: &nsec);
9573 delayMS = (uint32_t)(nsec / 1000000ULL);
9574 if (delayMS > notifier->maxMsgDelayMS) {
9575 notifier->maxMsgDelayMS = delayMS;
9576 }
9577
9578 assert(notifierObject == notifier);
9579 notifierObject.reset();
9580 notifierThread = NULL;
9581 }
9582}
9583
9584void
9585IOPMrootDomain::traceNotificationAck(OSObject *object, uint32_t delay_ms)
9586{
9587 if (systemBooting) {
9588 return;
9589 }
9590 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9591 if (!notifier) {
9592 return;
9593 }
9594
9595 kdebugTrace(event: kPMLogDrvResponseDelay, id: notifier->uuid0,
9596 param1: (uintptr_t) notifier->uuid1, param2: (uintptr_t) 0, param3: (uintptr_t) delay_ms);
9597
9598 DLOG("%s[%u] ack from %s took %d ms\n",
9599 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms);
9600 if (delay_ms > notifier->maxAckDelayMS) {
9601 notifier->maxAckDelayMS = delay_ms;
9602 }
9603}
9604
9605void
9606IOPMrootDomain::traceNotificationResponse(OSObject *object, uint32_t delay_ms, uint32_t ack_time_us)
9607{
9608 if (systemBooting) {
9609 return;
9610 }
9611 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9612 if (!notifier) {
9613 return;
9614 }
9615
9616 kdebugTrace(event: kPMLogDrvResponseDelay, id: notifier->uuid0,
9617 param1: (uintptr_t) notifier->uuid1, param2: (uintptr_t)(ack_time_us / 1000), param3: (uintptr_t) delay_ms);
9618
9619 if (ack_time_us == 0) {
9620 // Client work is done and ack will not be forthcoming
9621 DLOG("%s[%u] response from %s took %d ms\n",
9622 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms);
9623 } else {
9624 // Client needs more time and it must ack within ack_time_us
9625 DLOG("%s[%u] response from %s took %d ms (ack in %d us)\n",
9626 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms, ack_time_us);
9627 }
9628}
9629
9630void
9631IOPMrootDomain::traceFilteredNotification(OSObject *object)
9632{
9633 if ((kIOLogDebugPower & gIOKitDebug) == 0) {
9634 return;
9635 }
9636 if (systemBooting) {
9637 return;
9638 }
9639 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9640 if (!notifier) {
9641 return;
9642 }
9643
9644 DLOG("%s to %s dropped\n", getIOMessageString(notifier->msgType), getNotificationClientName(notifier));
9645}
9646
9647void
9648IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uint32_t delay)
9649{
9650 if (!systemBooting) {
9651 uint32_t detail = ((msgType & 0xffff) << 16) | (delay & 0xffff);
9652 pmTracer->traceDetail( detail );
9653 kdebugTrace(event: kPMLogSleepWakeTracePoint, id: pmTracer->getTracePhase(), param1: msgType, param2: delay);
9654 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
9655 }
9656}
9657
9658void
9659IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
9660{
9661 size_t reportSize;
9662 void **report = NULL;
9663 uint32_t bktCnt;
9664 uint32_t bktSize;
9665 uint32_t *clientCnt;
9666
9667 ASSERT_GATED();
9668
9669 report = NULL;
9670 if (channel_id == kAssertDelayChID) {
9671 report = &assertOnWakeReport;
9672 bktCnt = kAssertDelayBcktCnt;
9673 bktSize = kAssertDelayBcktSize;
9674 clientCnt = &assertOnWakeClientCnt;
9675 } else if (channel_id == kSleepDelaysChID) {
9676 report = &sleepDelaysReport;
9677 bktCnt = kSleepDelaysBcktCnt;
9678 bktSize = kSleepDelaysBcktSize;
9679 clientCnt = &sleepDelaysClientCnt;
9680 } else {
9681 assert(false);
9682 return;
9683 }
9684
9685 switch (action) {
9686 case kIOReportEnable:
9687
9688 if (*report) {
9689 (*clientCnt)++;
9690 break;
9691 }
9692
9693 reportSize = HISTREPORT_BUFSIZE(bktCnt);
9694 *report = IOMallocZeroData(reportSize);
9695 if (*report == NULL) {
9696 break;
9697 }
9698 HISTREPORT_INIT((uint16_t)bktCnt, bktSize, *report, reportSize,
9699 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
9700
9701 if (channel_id == kAssertDelayChID) {
9702 assertOnWakeSecs = 0;
9703 }
9704
9705 break;
9706
9707 case kIOReportDisable:
9708 if (*clientCnt == 0) {
9709 break;
9710 }
9711 if (*clientCnt == 1) {
9712 IOFreeData(address: *report, HISTREPORT_BUFSIZE(bktCnt));
9713 *report = NULL;
9714 }
9715 (*clientCnt)--;
9716
9717 if (channel_id == kAssertDelayChID) {
9718 assertOnWakeSecs = -1; // Invalid value to prevent updates
9719 }
9720 break;
9721
9722 case kIOReportGetDimensions:
9723 if (*report) {
9724 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
9725 }
9726 break;
9727 }
9728
9729 return;
9730}
9731
9732IOReturn
9733IOPMrootDomain::configureReport(IOReportChannelList *channelList,
9734 IOReportConfigureAction action,
9735 void *result,
9736 void *destination)
9737{
9738 unsigned cnt;
9739 uint64_t configAction = (uint64_t)action;
9740
9741 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9742 if ((channelList->channels[cnt].channel_id == kSleepCntChID) ||
9743 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
9744 (channelList->channels[cnt].channel_id == kUserWkCntChID)) {
9745 if (action != kIOReportGetDimensions) {
9746 continue;
9747 }
9748 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
9749 } else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
9750 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
9751 gIOPMWorkLoop->runAction(
9752 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
9753 target: (OSObject *)this, arg0: (void *)channelList->channels[cnt].channel_id,
9754 arg1: (void *)configAction, arg2: (void *)result);
9755 }
9756 }
9757
9758 return super::configureReport(channels: channelList, action, result, destination);
9759}
9760
9761IOReturn
9762IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
9763{
9764 uint32_t size2cpy;
9765 void *data2cpy;
9766 void **report;
9767
9768 ASSERT_GATED();
9769
9770 report = NULL;
9771 if (ch_id == kAssertDelayChID) {
9772 report = &assertOnWakeReport;
9773 } else if (ch_id == kSleepDelaysChID) {
9774 report = &sleepDelaysReport;
9775 } else {
9776 assert(false);
9777 return kIOReturnBadArgument;
9778 }
9779
9780 if (*report == NULL) {
9781 return kIOReturnNotOpen;
9782 }
9783
9784 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
9785 if (size2cpy > (dest->getCapacity() - dest->getLength())) {
9786 return kIOReturnOverrun;
9787 }
9788
9789 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
9790 dest->appendBytes(bytes: data2cpy, withLength: size2cpy);
9791
9792 return kIOReturnSuccess;
9793}
9794
9795IOReturn
9796IOPMrootDomain::updateReport(IOReportChannelList *channelList,
9797 IOReportUpdateAction action,
9798 void *result,
9799 void *destination)
9800{
9801 uint32_t size2cpy;
9802 void *data2cpy;
9803 uint8_t buf[SIMPLEREPORT_BUFSIZE];
9804 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
9805 unsigned cnt;
9806 uint64_t ch_id;
9807
9808 if (action != kIOReportCopyChannelData) {
9809 goto exit;
9810 }
9811
9812 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9813 ch_id = channelList->channels[cnt].channel_id;
9814
9815 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
9816 gIOPMWorkLoop->runAction(
9817 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
9818 target: (OSObject *)this, arg0: (void *)ch_id,
9819 arg1: (void *)result, arg2: (void *)dest);
9820 continue;
9821 } else if ((ch_id == kSleepCntChID) ||
9822 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
9823 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
9824 } else {
9825 continue;
9826 }
9827
9828 if (ch_id == kSleepCntChID) {
9829 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
9830 } else if (ch_id == kDarkWkCntChID) {
9831 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
9832 } else if (ch_id == kUserWkCntChID) {
9833 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
9834 }
9835
9836 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
9837 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
9838 dest->appendBytes(bytes: data2cpy, withLength: size2cpy);
9839 }
9840
9841exit:
9842 return super::updateReport(channels: channelList, action, result, destination);
9843}
9844
9845
9846//******************************************************************************
9847// PMTraceWorker Class
9848//
9849//******************************************************************************
9850
9851#undef super
9852#define super OSObject
9853OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
9854
9855#define kPMBestGuessPCIDevicesCount 25
9856#define kPMMaxRTCBitfieldSize 32
9857
9858OSPtr<PMTraceWorker>
9859PMTraceWorker::tracer(IOPMrootDomain * owner)
9860{
9861 OSSharedPtr<PMTraceWorker> me = OSMakeShared<PMTraceWorker>();
9862 if (!me || !me->init()) {
9863 return NULL;
9864 }
9865
9866 DLOG("PMTraceWorker %p\n", OBFUSCATE(me.get()));
9867
9868 // Note that we cannot instantiate the PCI device -> bit mappings here, since
9869 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
9870 // this dictionary lazily.
9871 me->owner = owner;
9872 me->pciDeviceBitMappings = NULL;
9873 me->pmTraceWorkerLock = IOLockAlloc();
9874 me->tracePhase = kIOPMTracePointSystemUp;
9875 me->traceData32 = 0;
9876 me->loginWindowData = 0;
9877 me->coreDisplayData = 0;
9878 me->coreGraphicsData = 0;
9879 return me;
9880}
9881
9882void
9883PMTraceWorker::RTC_TRACE(void)
9884{
9885 if (tracePointHandler && tracePointTarget) {
9886 uint32_t wordA;
9887
9888 IOLockLock(pmTraceWorkerLock);
9889 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
9890 (coreGraphicsData << 8) | tracePhase;
9891 IOLockUnlock(pmTraceWorkerLock);
9892
9893 tracePointHandler( tracePointTarget, traceData32, wordA );
9894 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
9895 }
9896#if DEVELOPMENT || DEBUG
9897 if ((swd_panic_phase != 0) && (swd_panic_phase == tracePhase)) {
9898 DEBUG_LOG("Causing sleep wake failure in phase 0x%08x\n", tracePhase);
9899 IOLock *l = IOLockAlloc();
9900 IOLockLock(l);
9901 IOLockLock(l);
9902 }
9903#endif /* DEVELOPMENT || DEBUG */
9904}
9905
9906int
9907PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
9908{
9909 OSSharedPtr<const OSSymbol> deviceName;
9910 int index = -1;
9911
9912 IOLockLock(pmTraceWorkerLock);
9913
9914 if (!pciDeviceBitMappings) {
9915 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
9916 if (!pciDeviceBitMappings) {
9917 goto exit;
9918 }
9919 }
9920
9921 // Check for bitmask overflow.
9922 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize) {
9923 goto exit;
9924 }
9925
9926 if ((deviceName = pciDevice->copyName()) &&
9927 (pciDeviceBitMappings->getNextIndexOfObject(anObject: deviceName.get(), index: 0) == (unsigned int)-1) &&
9928 pciDeviceBitMappings->setObject(deviceName.get())) {
9929 index = pciDeviceBitMappings->getCount() - 1;
9930 _LOG("PMTrace PCI array: set object %s => %d\n",
9931 deviceName->getCStringNoCopy(), index);
9932 }
9933
9934 if (!addedToRegistry && (index >= 0)) {
9935 addedToRegistry = owner->setProperty(aKey: "PCITopLevel", anObject: this);
9936 }
9937
9938exit:
9939 IOLockUnlock(pmTraceWorkerLock);
9940 return index;
9941}
9942
9943bool
9944PMTraceWorker::serialize(OSSerialize *s) const
9945{
9946 bool ok = false;
9947 if (pciDeviceBitMappings) {
9948 IOLockLock(pmTraceWorkerLock);
9949 ok = pciDeviceBitMappings->serialize(serializer: s);
9950 IOLockUnlock(pmTraceWorkerLock);
9951 }
9952 return ok;
9953}
9954
9955void
9956PMTraceWorker::tracePoint(uint8_t phase)
9957{
9958 // clear trace detail when phase begins
9959 if (tracePhase != phase) {
9960 traceData32 = 0;
9961 }
9962
9963 tracePhase = phase;
9964
9965 DLOG("trace point 0x%02x\n", tracePhase);
9966 RTC_TRACE();
9967}
9968
9969void
9970PMTraceWorker::traceDetail(uint32_t detail)
9971{
9972 if (detail == traceData32) {
9973 return;
9974 }
9975 traceData32 = detail;
9976 RTC_TRACE();
9977}
9978
9979void
9980PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
9981{
9982 switch (component) {
9983 case kIOPMLoginWindowProgress:
9984 loginWindowData = data & kIOPMLoginWindowProgressMask;
9985 break;
9986 case kIOPMCoreDisplayProgress:
9987 coreDisplayData = data & kIOPMCoreDisplayProgressMask;
9988 break;
9989 case kIOPMCoreGraphicsProgress:
9990 coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
9991 break;
9992 default:
9993 return;
9994 }
9995
9996 DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
9997 RTC_TRACE();
9998}
9999
10000void
10001PMTraceWorker::tracePCIPowerChange(
10002 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
10003{
10004 uint32_t bitMask;
10005 uint32_t expectedFlag;
10006
10007 // Ignore PCI changes outside of system sleep/wake.
10008 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
10009 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase)) {
10010 return;
10011 }
10012
10013 // Only record the WillChange transition when going to sleep,
10014 // and the DidChange on the way up.
10015 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
10016 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
10017 kIOPMDomainWillChange : kIOPMDomainDidChange;
10018 if (changeFlags != expectedFlag) {
10019 return;
10020 }
10021
10022 // Mark this device off in our bitfield
10023 if (bitNum < kPMMaxRTCBitfieldSize) {
10024 bitMask = (1 << bitNum);
10025
10026 if (kPowerChangeStart == type) {
10027 traceData32 |= bitMask;
10028 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
10029 service->getName(), bitNum, bitMask, traceData32);
10030 owner->kdebugTrace(event: kPMLogPCIDevChangeStart, id: service->getRegistryEntryID(), param1: traceData32, param2: 0);
10031 } else {
10032 traceData32 &= ~bitMask;
10033 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
10034 service->getName(), bitNum, bitMask, traceData32);
10035 owner->kdebugTrace(event: kPMLogPCIDevChangeDone, id: service->getRegistryEntryID(), param1: traceData32, param2: 0);
10036 }
10037
10038 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
10039 RTC_TRACE();
10040 }
10041}
10042
10043uint64_t
10044PMTraceWorker::getPMStatusCode()
10045{
10046 return ((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase);
10047}
10048
10049uint8_t
10050PMTraceWorker::getTracePhase()
10051{
10052 return tracePhase;
10053}
10054
10055uint32_t
10056PMTraceWorker::getTraceData()
10057{
10058 return traceData32;
10059}
10060
10061// MARK: -
10062// MARK: PMHaltWorker
10063
10064//******************************************************************************
10065// PMHaltWorker Class
10066//
10067//******************************************************************************
10068
10069PMHaltWorker *
10070PMHaltWorker::worker( void )
10071{
10072 PMHaltWorker * me;
10073 IOThread thread;
10074
10075 do {
10076 me = OSTypeAlloc( PMHaltWorker );
10077 if (!me || !me->init()) {
10078 break;
10079 }
10080
10081 me->lock = IOLockAlloc();
10082 if (!me->lock) {
10083 break;
10084 }
10085
10086 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
10087 me->retain(); // thread holds extra retain
10088 if (KERN_SUCCESS != kernel_thread_start(continuation: &PMHaltWorker::main, parameter: (void *) me, new_thread: &thread)) {
10089 me->release();
10090 break;
10091 }
10092 thread_deallocate(thread);
10093 return me;
10094 } while (false);
10095
10096 if (me) {
10097 me->release();
10098 }
10099 return NULL;
10100}
10101
10102void
10103PMHaltWorker::free( void )
10104{
10105 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
10106 if (lock) {
10107 IOLockFree(lock);
10108 lock = NULL;
10109 }
10110 return OSObject::free();
10111}
10112
10113void
10114PMHaltWorker::main( void * arg, wait_result_t waitResult )
10115{
10116 PMHaltWorker * me = (PMHaltWorker *) arg;
10117
10118 IOLockLock( gPMHaltLock );
10119 gPMHaltBusyCount++;
10120 me->depth = gPMHaltDepth;
10121 IOLockUnlock( gPMHaltLock );
10122
10123 while (me->depth >= 0) {
10124 PMHaltWorker::work( me );
10125
10126 IOLockLock( gPMHaltLock );
10127 if (++gPMHaltIdleCount >= gPMHaltBusyCount) {
10128 // This is the last thread to finish work on this level,
10129 // inform everyone to start working on next lower level.
10130 gPMHaltDepth--;
10131 me->depth = gPMHaltDepth;
10132 gPMHaltIdleCount = 0;
10133 thread_wakeup((event_t) &gPMHaltIdleCount);
10134 } else {
10135 // One or more threads are still working on this level,
10136 // this thread must wait.
10137 me->depth = gPMHaltDepth - 1;
10138 do {
10139 IOLockSleep(lock: gPMHaltLock, event: &gPMHaltIdleCount, THREAD_UNINT);
10140 } while (me->depth != gPMHaltDepth);
10141 }
10142 IOLockUnlock( gPMHaltLock );
10143 }
10144
10145 // No more work to do, terminate thread
10146 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
10147 thread_wakeup( &gPMHaltDepth );
10148 me->release();
10149}
10150
10151void
10152PMHaltWorker::work( PMHaltWorker * me )
10153{
10154 OSSharedPtr<IOService> service;
10155 OSSet * inner;
10156 AbsoluteTime startTime, elapsedTime;
10157 UInt32 deltaTime;
10158 bool timeout;
10159
10160 while (true) {
10161 timeout = false;
10162
10163 // Claim an unit of work from the shared pool
10164 IOLockLock( gPMHaltLock );
10165 inner = (OSSet *)gPMHaltArray->getObject(index: me->depth);
10166 if (inner) {
10167 service.reset(OSDynamicCast(IOService, inner->getAnyObject()), OSRetain);
10168 if (service) {
10169 inner->removeObject(anObject: service.get());
10170 }
10171 }
10172 IOLockUnlock( gPMHaltLock );
10173 if (!service) {
10174 break; // no more work at this depth
10175 }
10176 clock_get_uptime(result: &startTime);
10177
10178 if (!service->isInactive() &&
10179 service->setProperty(aKey: gPMHaltClientAcknowledgeKey.get(), anObject: me)) {
10180 IOLockLock(me->lock);
10181 me->startTime = startTime;
10182 me->service = service.get();
10183 me->timeout = false;
10184 IOLockUnlock(me->lock);
10185
10186 service->systemWillShutdown( specifier: gPMHaltMessageType);
10187
10188 // Wait for driver acknowledgement
10189 IOLockLock(me->lock);
10190 while (service->propertyExists(aKey: gPMHaltClientAcknowledgeKey.get())) {
10191 IOLockSleep(lock: me->lock, event: me, THREAD_UNINT);
10192 }
10193 me->service = NULL;
10194 timeout = me->timeout;
10195 IOLockUnlock(me->lock);
10196 }
10197
10198 deltaTime = computeDeltaTimeMS(startTime: &startTime, elapsedTime: &elapsedTime);
10199 if ((deltaTime > kPMHaltTimeoutMS) || timeout) {
10200 LOG("%s driver %s (0x%llx) took %u ms\n",
10201 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
10202 "PowerOff" : "Restart",
10203 service->getName(), service->getRegistryEntryID(),
10204 (uint32_t) deltaTime );
10205 halt_log_enter(what: "PowerOff/Restart handler completed",
10206 OSMemberFunctionCast(const void *, service.get(), &IOService::systemWillShutdown),
10207 time: elapsedTime);
10208 }
10209
10210 me->visits++;
10211 }
10212}
10213
10214void
10215PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
10216{
10217 UInt64 nano;
10218 AbsoluteTime startTime;
10219 AbsoluteTime endTime;
10220
10221 endTime = *now;
10222
10223 IOLockLock(me->lock);
10224 if (me->service && !me->timeout) {
10225 startTime = me->startTime;
10226 nano = 0;
10227 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
10228 SUB_ABSOLUTETIME(&endTime, &startTime);
10229 absolutetime_to_nanoseconds(abstime: endTime, result: &nano);
10230 }
10231 if (nano > 3000000000ULL) {
10232 me->timeout = true;
10233
10234 halt_log_enter(what: "PowerOff/Restart still waiting on handler",
10235 OSMemberFunctionCast(const void *, me->service, &IOService::systemWillShutdown),
10236 time: endTime);
10237 MSG("%s still waiting on %s\n",
10238 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
10239 me->service->getName());
10240 }
10241 }
10242 IOLockUnlock(me->lock);
10243}
10244
10245//******************************************************************************
10246// acknowledgeSystemWillShutdown
10247//
10248// Acknowledgement from drivers that they have prepared for shutdown/restart.
10249//******************************************************************************
10250
10251void
10252IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
10253{
10254 PMHaltWorker * worker;
10255 OSSharedPtr<OSObject> prop;
10256
10257 if (!from) {
10258 return;
10259 }
10260
10261 //DLOG("%s acknowledged\n", from->getName());
10262 prop = from->copyProperty( aKey: gPMHaltClientAcknowledgeKey.get());
10263 if (prop) {
10264 worker = (PMHaltWorker *) prop.get();
10265 IOLockLock(worker->lock);
10266 from->removeProperty( aKey: gPMHaltClientAcknowledgeKey.get());
10267 thread_wakeup((event_t) worker);
10268 IOLockUnlock(worker->lock);
10269 } else {
10270 DLOG("%s acknowledged without worker property\n",
10271 from->getName());
10272 }
10273}
10274
10275
10276//******************************************************************************
10277// notifySystemShutdown
10278//
10279// Notify all objects in PM tree that system will shutdown or restart
10280//******************************************************************************
10281
10282static void
10283notifySystemShutdown( IOService * root, uint32_t messageType )
10284{
10285#define PLACEHOLDER ((OSSet *)gPMHaltArray.get())
10286 OSSharedPtr<IORegistryIterator> iter;
10287 IORegistryEntry * entry;
10288 IOService * node;
10289 OSSet * inner;
10290 OSSharedPtr<OSSet> newInner;
10291 PMHaltWorker * workers[kPMHaltMaxWorkers];
10292 AbsoluteTime deadline;
10293 unsigned int totalNodes = 0;
10294 unsigned int depth;
10295 unsigned int rootDepth;
10296 unsigned int numWorkers;
10297 unsigned int count;
10298 int waitResult;
10299 void * baseFunc;
10300 bool ok;
10301
10302 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
10303
10304 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
10305
10306 // Iterate the entire PM tree starting from root
10307
10308 rootDepth = root->getDepth( plane: gIOPowerPlane );
10309 if (!rootDepth) {
10310 goto done;
10311 }
10312
10313 // debug - for repeated test runs
10314 while (PMHaltWorker::metaClass->getInstanceCount()) {
10315 IOSleep(milliseconds: 1);
10316 }
10317
10318 if (!gPMHaltArray) {
10319 gPMHaltArray = OSArray::withCapacity(capacity: 40);
10320 if (!gPMHaltArray) {
10321 goto done;
10322 }
10323 } else { // debug
10324 gPMHaltArray->flushCollection();
10325 }
10326
10327 if (!gPMHaltLock) {
10328 gPMHaltLock = IOLockAlloc();
10329 if (!gPMHaltLock) {
10330 goto done;
10331 }
10332 }
10333
10334 if (!gPMHaltClientAcknowledgeKey) {
10335 gPMHaltClientAcknowledgeKey =
10336 OSSymbol::withCStringNoCopy(cString: "PMShutdown");
10337 if (!gPMHaltClientAcknowledgeKey) {
10338 goto done;
10339 }
10340 }
10341
10342 gPMHaltMessageType = messageType;
10343
10344 // Depth-first walk of PM plane
10345
10346 iter = IORegistryIterator::iterateOver(
10347 start: root, plane: gIOPowerPlane, options: kIORegistryIterateRecursively);
10348
10349 if (iter) {
10350 while ((entry = iter->getNextObject())) {
10351 node = OSDynamicCast(IOService, entry);
10352 if (!node) {
10353 continue;
10354 }
10355
10356 if (baseFunc ==
10357 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown)) {
10358 continue;
10359 }
10360
10361 depth = node->getDepth( plane: gIOPowerPlane );
10362 if (depth <= rootDepth) {
10363 continue;
10364 }
10365
10366 ok = false;
10367
10368 // adjust to zero based depth
10369 depth -= (rootDepth + 1);
10370
10371 // gPMHaltArray is an array of containers, each container
10372 // refers to nodes with the same depth.
10373
10374 count = gPMHaltArray->getCount();
10375 while (depth >= count) {
10376 // expand array and insert placeholders
10377 gPMHaltArray->setObject(PLACEHOLDER);
10378 count++;
10379 }
10380 count = gPMHaltArray->getCount();
10381 if (depth < count) {
10382 inner = (OSSet *)gPMHaltArray->getObject(index: depth);
10383 if (inner == PLACEHOLDER) {
10384 newInner = OSSet::withCapacity(capacity: 40);
10385 if (newInner) {
10386 gPMHaltArray->replaceObject(index: depth, anObject: newInner.get());
10387 inner = newInner.get();
10388 }
10389 }
10390
10391 // PM nodes that appear more than once in the tree will have
10392 // the same depth, OSSet will refuse to add the node twice.
10393 if (inner) {
10394 ok = inner->setObject(node);
10395 }
10396 }
10397 if (!ok) {
10398 DLOG("Skipped PM node %s\n", node->getName());
10399 }
10400 }
10401 }
10402
10403 // debug only
10404 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(index: i)); i++) {
10405 count = 0;
10406 if (inner != PLACEHOLDER) {
10407 count = inner->getCount();
10408 }
10409 DLOG("Nodes at depth %u = %u\n", i, count);
10410 }
10411
10412 // strip placeholders (not all depths are populated)
10413 numWorkers = 0;
10414 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(index: i));) {
10415 if (inner == PLACEHOLDER) {
10416 gPMHaltArray->removeObject(index: i);
10417 continue;
10418 }
10419 count = inner->getCount();
10420 if (count > numWorkers) {
10421 numWorkers = count;
10422 }
10423 totalNodes += count;
10424 i++;
10425 }
10426
10427 if (gPMHaltArray->getCount() == 0 || !numWorkers) {
10428 goto done;
10429 }
10430
10431 gPMHaltBusyCount = 0;
10432 gPMHaltIdleCount = 0;
10433 gPMHaltDepth = gPMHaltArray->getCount() - 1;
10434
10435 // Create multiple workers (and threads)
10436
10437 if (numWorkers > kPMHaltMaxWorkers) {
10438 numWorkers = kPMHaltMaxWorkers;
10439 }
10440
10441 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
10442 totalNodes, gPMHaltArray->getCount(), numWorkers);
10443
10444 for (unsigned int i = 0; i < numWorkers; i++) {
10445 workers[i] = PMHaltWorker::worker();
10446 }
10447
10448 // Wait for workers to exhaust all available work
10449
10450 IOLockLock(gPMHaltLock);
10451 while (gPMHaltDepth >= 0) {
10452 clock_interval_to_deadline(interval: 1000, scale_factor: kMillisecondScale, result: &deadline);
10453
10454 waitResult = IOLockSleepDeadline(
10455 lock: gPMHaltLock, event: &gPMHaltDepth, deadline, THREAD_UNINT);
10456 if (THREAD_TIMED_OUT == waitResult) {
10457 AbsoluteTime now;
10458 clock_get_uptime(result: &now);
10459
10460 IOLockUnlock(gPMHaltLock);
10461 for (unsigned int i = 0; i < numWorkers; i++) {
10462 if (workers[i]) {
10463 PMHaltWorker::checkTimeout(me: workers[i], now: &now);
10464 }
10465 }
10466 IOLockLock(gPMHaltLock);
10467 }
10468 }
10469 IOLockUnlock(gPMHaltLock);
10470
10471 // Release all workers
10472
10473 for (unsigned int i = 0; i < numWorkers; i++) {
10474 if (workers[i]) {
10475 workers[i]->release();
10476 }
10477 // worker also retained by it's own thread
10478 }
10479
10480done:
10481 DLOG("%s done\n", __FUNCTION__);
10482 return;
10483}
10484
10485// MARK: -
10486// MARK: Kernel Assertion
10487
10488/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10489
10490IOPMDriverAssertionID
10491IOPMrootDomain::createPMAssertion(
10492 IOPMDriverAssertionType whichAssertionBits,
10493 IOPMDriverAssertionLevel assertionLevel,
10494 IOService *ownerService,
10495 const char *ownerDescription)
10496{
10497 IOReturn ret;
10498 IOPMDriverAssertionID newAssertion;
10499
10500 if (!pmAssertions) {
10501 return 0;
10502 }
10503
10504 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
10505
10506 if (kIOReturnSuccess == ret) {
10507#if (DEVELOPMENT || DEBUG)
10508 if (_aotNow || (kIOLogPMRootDomain & gIOKitDebug)) {
10509 OSReportWithBacktrace("PMRD: createPMAssertion(0x%qx) %s (%s)", newAssertion, ownerService->getName(), ownerDescription);
10510 }
10511#endif /* (DEVELOPMENT || DEBUG) */
10512 return newAssertion;
10513 } else {
10514 return 0;
10515 }
10516}
10517
10518IOReturn
10519IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
10520{
10521#if (DEVELOPMENT || DEBUG)
10522 if (_aotNow || (kIOLogPMRootDomain & gIOKitDebug)) {
10523 PMAssertStruct *details = pmAssertions->detailsForID(releaseAssertion, NULL);
10524 if (details && details->ownerService && details->ownerString) {
10525 OSReportWithBacktrace("PMRD: releasePMAssertion(0x%qx) %s (%s)", releaseAssertion,
10526 details->ownerService->getName(), details->ownerString->getCStringNoCopy());
10527 } else {
10528 OSReportWithBacktrace("PMRD: releasePMAssertion(0x%qx)", releaseAssertion);
10529 }
10530 }
10531#endif /* (DEVELOPMENT || DEBUG) */
10532 if (!pmAssertions) {
10533 return kIOReturnInternalError;
10534 }
10535 return pmAssertions->releaseAssertion(releaseAssertion);
10536}
10537
10538
10539IOReturn
10540IOPMrootDomain::setPMAssertionLevel(
10541 IOPMDriverAssertionID assertionID,
10542 IOPMDriverAssertionLevel assertionLevel)
10543{
10544 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
10545}
10546
10547IOPMDriverAssertionLevel
10548IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
10549{
10550 IOPMDriverAssertionType sysLevels;
10551
10552 if (!pmAssertions || whichAssertion == 0) {
10553 return kIOPMDriverAssertionLevelOff;
10554 }
10555
10556 sysLevels = pmAssertions->getActivatedAssertions();
10557
10558 // Check that every bit set in argument 'whichAssertion' is asserted
10559 // in the aggregate bits.
10560 if ((sysLevels & whichAssertion) == whichAssertion) {
10561 return kIOPMDriverAssertionLevelOn;
10562 } else {
10563 return kIOPMDriverAssertionLevelOff;
10564 }
10565}
10566
10567IOReturn
10568IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
10569{
10570 if (!pmAssertions) {
10571 return kIOReturnNotFound;
10572 }
10573
10574 return pmAssertions->setUserAssertionLevels(inLevels);
10575}
10576
10577IOReturn
10578IOPMrootDomain::acquireDriverKitMatchingAssertion()
10579{
10580 return gIOPMWorkLoop->runActionBlock(action: ^{
10581 if (_driverKitMatchingAssertionCount != 0) {
10582 _driverKitMatchingAssertionCount++;
10583 return kIOReturnSuccess;
10584 } else {
10585 if (kSystemTransitionSleep == _systemTransitionType) {
10586 // system going to sleep
10587 return kIOReturnBusy;
10588 } else {
10589 // createPMAssertion is asynchronous.
10590 // we must also set _driverKitMatchingAssertionCount under the PM workloop lock so that we can cancel sleep immediately
10591 // The assertion is used so that on release, we reevaluate all assertions
10592 _driverKitMatchingAssertion = createPMAssertion(whichAssertionBits: kIOPMDriverAssertionCPUBit, kIOPMDriverAssertionLevelOn, ownerService: this, ownerDescription: "DK matching");
10593 if (_driverKitMatchingAssertion != kIOPMUndefinedDriverAssertionID) {
10594 _driverKitMatchingAssertionCount = 1;
10595 return kIOReturnSuccess;
10596 } else {
10597 return kIOReturnBusy;
10598 }
10599 }
10600 }
10601 });
10602}
10603
10604void
10605IOPMrootDomain::releaseDriverKitMatchingAssertion()
10606{
10607 gIOPMWorkLoop->runActionBlock(action: ^{
10608 if (_driverKitMatchingAssertionCount != 0) {
10609 _driverKitMatchingAssertionCount--;
10610 if (_driverKitMatchingAssertionCount == 0) {
10611 releasePMAssertion(releaseAssertion: _driverKitMatchingAssertion);
10612 _driverKitMatchingAssertion = kIOPMUndefinedDriverAssertionID;
10613 }
10614 } else {
10615 panic("Over-release of driverkit matching assertion");
10616 }
10617 return kIOReturnSuccess;
10618 });
10619}
10620
10621bool
10622IOPMrootDomain::serializeProperties( OSSerialize * s ) const
10623{
10624 if (pmAssertions) {
10625 pmAssertions->publishProperties();
10626 }
10627 return IOService::serializeProperties(s);
10628}
10629
10630OSSharedPtr<OSObject>
10631IOPMrootDomain::copyProperty( const char * aKey) const
10632{
10633 OSSharedPtr<OSObject> obj;
10634 obj = IOService::copyProperty(aKey);
10635
10636 if (obj) {
10637 return obj;
10638 }
10639
10640 if (!strncmp(s1: aKey, kIOPMSleepWakeWdogRebootKey,
10641 n: sizeof(kIOPMSleepWakeWdogRebootKey))) {
10642 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
10643 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10644 } else {
10645 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10646 }
10647 }
10648
10649 if (!strncmp(s1: aKey, kIOPMSleepWakeWdogLogsValidKey,
10650 n: sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
10651 if (swd_flags & SWD_VALID_LOGS) {
10652 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10653 } else {
10654 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10655 }
10656 }
10657
10658 /*
10659 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
10660 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
10661 * issued by DisplayWrangler on darkwake.
10662 */
10663 if (!strcmp(s1: aKey, s2: "DesktopMode")) {
10664 if (desktopMode) {
10665 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10666 } else {
10667 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10668 }
10669 }
10670 if (!strcmp(s1: aKey, s2: "DisplayIdleForDemandSleep")) {
10671 if (displayIdleForDemandSleep) {
10672 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10673 } else {
10674 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10675 }
10676 }
10677
10678 if (!strcmp(s1: aKey, kIOPMDriverWakeEventsKey)) {
10679 OSSharedPtr<OSArray> array;
10680 WAKEEVENT_LOCK();
10681 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
10682 OSSharedPtr<OSCollection> collection = _systemWakeEventsArray->copyCollection();
10683 if (collection) {
10684 array = OSDynamicPtrCast<OSArray>(source: collection);
10685 }
10686 }
10687 WAKEEVENT_UNLOCK();
10688 return os::move(t&: array);
10689 }
10690
10691 if (!strcmp(s1: aKey, kIOPMSleepStatisticsAppsKey)) {
10692 OSSharedPtr<OSArray> array;
10693 IOLockLock(pmStatsLock);
10694 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
10695 OSSharedPtr<OSCollection> collection = pmStatsAppResponses->copyCollection();
10696 if (collection) {
10697 array = OSDynamicPtrCast<OSArray>(source: collection);
10698 }
10699 }
10700 IOLockUnlock(pmStatsLock);
10701 return os::move(t&: array);
10702 }
10703
10704 if (!strcmp(s1: aKey, kIOPMIdleSleepPreventersKey)) {
10705 OSArray *idleSleepList = NULL;
10706 gRootDomain->copySleepPreventersList(idleSleepList: &idleSleepList, NULL);
10707 return OSSharedPtr<OSArray>(idleSleepList, OSNoRetain);
10708 }
10709
10710 if (!strcmp(s1: aKey, kIOPMSystemSleepPreventersKey)) {
10711 OSArray *systemSleepList = NULL;
10712 gRootDomain->copySleepPreventersList(NULL, systemSleepList: &systemSleepList);
10713 return OSSharedPtr<OSArray>(systemSleepList, OSNoRetain);
10714 }
10715
10716 if (!strcmp(s1: aKey, kIOPMIdleSleepPreventersWithIDKey)) {
10717 OSArray *idleSleepList = NULL;
10718 gRootDomain->copySleepPreventersListWithID(idleSleepList: &idleSleepList, NULL);
10719 return OSSharedPtr<OSArray>(idleSleepList, OSNoRetain);
10720 }
10721
10722 if (!strcmp(s1: aKey, kIOPMSystemSleepPreventersWithIDKey)) {
10723 OSArray *systemSleepList = NULL;
10724 gRootDomain->copySleepPreventersListWithID(NULL, systemSleepList: &systemSleepList);
10725 return OSSharedPtr<OSArray>(systemSleepList, OSNoRetain);
10726 }
10727 return NULL;
10728}
10729
10730// MARK: -
10731// MARK: Wake Event Reporting
10732
10733void
10734IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
10735{
10736 WAKEEVENT_LOCK();
10737 strlcpy(dst: outBuf, src: gWakeReasonString, n: bufSize);
10738 WAKEEVENT_UNLOCK();
10739}
10740
10741void
10742IOPMrootDomain::copyShutdownReasonString( char * outBuf, size_t bufSize )
10743{
10744 WAKEEVENT_LOCK();
10745 strlcpy(dst: outBuf, src: gShutdownReasonString, n: bufSize);
10746 WAKEEVENT_UNLOCK();
10747}
10748
10749//******************************************************************************
10750// acceptSystemWakeEvents
10751//
10752// Private control for the acceptance of driver wake event claims.
10753//******************************************************************************
10754
10755void
10756IOPMrootDomain::acceptSystemWakeEvents( uint32_t control )
10757{
10758 bool logWakeReason = false;
10759
10760 WAKEEVENT_LOCK();
10761 switch (control) {
10762 case kAcceptSystemWakeEvents_Enable:
10763 assert(_acceptSystemWakeEvents == false);
10764 if (!_systemWakeEventsArray) {
10765 _systemWakeEventsArray = OSArray::withCapacity(capacity: 4);
10766 }
10767 _acceptSystemWakeEvents = (_systemWakeEventsArray != NULL);
10768 if (!(_aotNow && (kIOPMWakeEventAOTExitFlags & _aotPendingFlags))) {
10769 gWakeReasonString[0] = '\0';
10770 if (_systemWakeEventsArray) {
10771 _systemWakeEventsArray->flushCollection();
10772 }
10773 }
10774
10775 // Remove stale WakeType property before system sleep
10776 removeProperty(kIOPMRootDomainWakeTypeKey);
10777 removeProperty(kIOPMRootDomainWakeReasonKey);
10778 break;
10779
10780 case kAcceptSystemWakeEvents_Disable:
10781 _acceptSystemWakeEvents = false;
10782#if defined(XNU_TARGET_OS_OSX)
10783 logWakeReason = (gWakeReasonString[0] != '\0');
10784#else /* !defined(XNU_TARGET_OS_OSX) */
10785 logWakeReason = gWakeReasonSysctlRegistered;
10786#if DEVELOPMENT
10787 static int panic_allowed = -1;
10788
10789 if ((panic_allowed == -1) &&
10790 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed, sizeof(panic_allowed)) == false)) {
10791 panic_allowed = 0;
10792 }
10793
10794 if (panic_allowed) {
10795 size_t i = 0;
10796 // Panic if wake reason is null or empty
10797 for (i = 0; (i < strlen(gWakeReasonString)); i++) {
10798 if ((gWakeReasonString[i] != ' ') && (gWakeReasonString[i] != '\t')) {
10799 break;
10800 }
10801 }
10802 if (i >= strlen(gWakeReasonString)) {
10803 panic("Wake reason is empty");
10804 }
10805 }
10806#endif /* DEVELOPMENT */
10807#endif /* !defined(XNU_TARGET_OS_OSX) */
10808
10809 // publish kIOPMRootDomainWakeReasonKey if not already set
10810 if (!propertyExists(kIOPMRootDomainWakeReasonKey)) {
10811 setProperty(kIOPMRootDomainWakeReasonKey, aString: gWakeReasonString);
10812 }
10813 break;
10814
10815 case kAcceptSystemWakeEvents_Reenable:
10816 assert(_acceptSystemWakeEvents == false);
10817 _acceptSystemWakeEvents = (_systemWakeEventsArray != NULL);
10818 removeProperty(kIOPMRootDomainWakeReasonKey);
10819 break;
10820 }
10821 WAKEEVENT_UNLOCK();
10822
10823 if (logWakeReason) {
10824 MSG("system wake events: %s\n", gWakeReasonString);
10825 }
10826}
10827
10828//******************************************************************************
10829// claimSystemWakeEvent
10830//
10831// For a driver to claim a device is the source/conduit of a system wake event.
10832//******************************************************************************
10833
10834void
10835IOPMrootDomain::claimSystemWakeEvent(
10836 IOService * device,
10837 IOOptionBits flags,
10838 const char * reason,
10839 OSObject * details )
10840{
10841 OSSharedPtr<const OSSymbol> deviceName;
10842 OSSharedPtr<OSNumber> deviceRegId;
10843 OSSharedPtr<OSNumber> claimTime;
10844 OSSharedPtr<OSData> flagsData;
10845 OSSharedPtr<OSString> reasonString;
10846 OSSharedPtr<OSDictionary> dict;
10847 uint64_t timestamp;
10848 bool addWakeReason;
10849
10850 if (!device || !reason) {
10851 return;
10852 }
10853
10854 pmEventTimeStamp(recordTS: &timestamp);
10855
10856 IOOptionBits aotFlags = 0;
10857 bool needAOTEvaluate = FALSE;
10858
10859 if (kIOPMAOTModeAddEventFlags & _aotMode) {
10860 if (!strcmp(s1: "hold", s2: reason)
10861 || !strcmp(s1: "help", s2: reason)
10862 || !strcmp(s1: "menu", s2: reason)
10863 || !strcmp(s1: "stockholm", s2: reason)
10864 || !strcmp(s1: "ringer", s2: reason)
10865 || !strcmp(s1: "ringerab", s2: reason)
10866 || !strcmp(s1: "smc0", s2: reason)
10867 || !strcmp(s1: "AOP.RTPWakeupAP", s2: reason)
10868 || !strcmp(s1: "AOP.RTP_AP_IRQ", s2: reason)
10869 || !strcmp(s1: "BT.OutboxNotEmpty", s2: reason)
10870 || !strcmp(s1: "WL.OutboxNotEmpty", s2: reason)) {
10871 flags |= kIOPMWakeEventAOTExit;
10872 }
10873 }
10874
10875#if DEVELOPMENT || DEBUG
10876 if (_aotLingerTime && !strcmp("rtc", reason)) {
10877 flags |= kIOPMWakeEventAOTPossibleExit;
10878 }
10879#endif /* DEVELOPMENT || DEBUG */
10880
10881#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
10882 // Publishing the WakeType is serialized by the PM work loop
10883 if (!strcmp(s1: "rtc", s2: reason) && (_nextScheduledAlarmType != NULL)) {
10884 pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventPublishWakeType,
10885 arg0: (void *) _nextScheduledAlarmType.get());
10886 }
10887
10888 // Workaround for the missing wake HID event
10889 if (gDarkWakeFlags & kDarkWakeFlagUserWakeWorkaround) {
10890 if (!strcmp(s1: "trackpadkeyboard", s2: reason)) {
10891 pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventPublishWakeType,
10892 arg0: (void *) gIOPMWakeTypeUserKey.get());
10893 }
10894 }
10895#endif
10896
10897 deviceName = device->copyName(plane: gIOServicePlane);
10898 deviceRegId = OSNumber::withNumber(value: device->getRegistryEntryID(), numberOfBits: 64);
10899 claimTime = OSNumber::withNumber(value: timestamp, numberOfBits: 64);
10900 flagsData = OSData::withValue(value: flags);
10901 reasonString = OSString::withCString(cString: reason);
10902 dict = OSDictionary::withCapacity(capacity: 5 + (details ? 1 : 0));
10903 if (!dict || !deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString) {
10904 goto done;
10905 }
10906
10907 dict->setObject(aKey: gIONameKey, anObject: deviceName.get());
10908 dict->setObject(aKey: gIORegistryEntryIDKey, anObject: deviceRegId.get());
10909 dict->setObject(kIOPMWakeEventTimeKey, anObject: claimTime.get());
10910 dict->setObject(kIOPMWakeEventFlagsKey, anObject: flagsData.get());
10911 dict->setObject(kIOPMWakeEventReasonKey, anObject: reasonString.get());
10912 if (details) {
10913 dict->setObject(kIOPMWakeEventDetailsKey, anObject: details);
10914 }
10915
10916 WAKEEVENT_LOCK();
10917 addWakeReason = _acceptSystemWakeEvents;
10918 if (_aotMode) {
10919 IOLog(format: "claimSystemWakeEvent(%s, %s, 0x%x) 0x%x %d\n", reason, deviceName->getCStringNoCopy(), (int)flags, _aotPendingFlags, _aotReadyToFullWake);
10920 }
10921 aotFlags = (kIOPMWakeEventAOTFlags & flags);
10922 aotFlags = (aotFlags & ~_aotPendingFlags);
10923 needAOTEvaluate = false;
10924 if (_aotNow && aotFlags) {
10925 if (kIOPMWakeEventAOTPossibleExit & flags) {
10926 _aotMetrics->possibleCount++;
10927 }
10928 if (kIOPMWakeEventAOTConfirmedPossibleExit & flags) {
10929 _aotMetrics->confirmedPossibleCount++;
10930 }
10931 if (kIOPMWakeEventAOTRejectedPossibleExit & flags) {
10932 _aotMetrics->rejectedPossibleCount++;
10933 }
10934 if (kIOPMWakeEventAOTExpiredPossibleExit & flags) {
10935 _aotMetrics->expiredPossibleCount++;
10936 }
10937
10938 _aotPendingFlags |= aotFlags;
10939 addWakeReason = _aotNow && _systemWakeEventsArray && ((kIOPMWakeEventAOTExitFlags & aotFlags));
10940 needAOTEvaluate = _aotReadyToFullWake;
10941 }
10942 DMSG("claimSystemWakeEvent(%s, 0x%x, %s, 0x%llx) aot %d phase 0x%x add %d\n",
10943 reason, (int)flags, deviceName->getCStringNoCopy(), device->getRegistryEntryID(),
10944 _aotNow, pmTracer->getTracePhase(), addWakeReason);
10945
10946#if DEVELOPMENT || DEBUG
10947 if (addWakeReason) {
10948 record_system_event(SYSTEM_EVENT_TYPE_INFO,
10949 SYSTEM_EVENT_SUBSYSTEM_PMRD,
10950 "Report System Wake Event",
10951 "Reason: %s Flags: 0x%x Device: %s, DeviceRegEntry: 0x%llx\n",
10952 reason,
10953 (int)flags,
10954 deviceName->getCStringNoCopy(),
10955 device->getRegistryEntryID()
10956 );
10957 }
10958#endif /* DEVELOPMENT || DEBUG */
10959
10960 if (!gWakeReasonSysctlRegistered) {
10961 // Lazy registration until the platform driver stops registering
10962 // the same name.
10963 gWakeReasonSysctlRegistered = true;
10964 }
10965 if (addWakeReason) {
10966 _systemWakeEventsArray->setObject(dict.get());
10967 if (gWakeReasonString[0] != '\0') {
10968 strlcat(dst: gWakeReasonString, src: " ", n: sizeof(gWakeReasonString));
10969 }
10970 strlcat(dst: gWakeReasonString, src: reason, n: sizeof(gWakeReasonString));
10971 }
10972
10973 WAKEEVENT_UNLOCK();
10974 if (needAOTEvaluate) {
10975 // Call aotEvaluate() on PM work loop since it may call
10976 // aotExit() which accesses PM state.
10977 pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventAOTEvaluate);
10978 }
10979
10980done:
10981 return;
10982}
10983
10984//******************************************************************************
10985// claimSystemBootEvent
10986//
10987// For a driver to claim a device is the source/conduit of a system boot event.
10988//******************************************************************************
10989
10990void
10991IOPMrootDomain::claimSystemBootEvent(
10992 IOService * device,
10993 IOOptionBits flags,
10994 const char * reason,
10995 __unused OSObject * details )
10996{
10997 if (!device || !reason) {
10998 return;
10999 }
11000
11001 DEBUG_LOG("claimSystemBootEvent(%s, %s, 0x%x)\n", reason, device->getName(), (uint32_t) flags);
11002#if DEVELOPMENT || DEBUG
11003 record_system_event(SYSTEM_EVENT_TYPE_INFO,
11004 SYSTEM_EVENT_SUBSYSTEM_PMRD,
11005 "Report System Boot Device",
11006 "Reason: %s Flags: 0x%x Device: %s",
11007 reason,
11008 (int)flags,
11009 device->getName()
11010 );
11011#endif /* DEVELOPMENT || DEBUG */
11012 WAKEEVENT_LOCK();
11013 if (!gBootReasonSysctlRegistered) {
11014 // Lazy sysctl registration after setting gBootReasonString
11015 strlcat(dst: gBootReasonString, src: reason, n: sizeof(gBootReasonString));
11016 os_atomic_store(&gBootReasonSysctlRegistered, true, release);
11017 }
11018 WAKEEVENT_UNLOCK();
11019}
11020
11021//******************************************************************************
11022// claimSystemShutdownEvent
11023//
11024// For drivers to claim a system shutdown event on the ensuing boot.
11025//******************************************************************************
11026
11027void
11028IOPMrootDomain::claimSystemShutdownEvent(
11029 IOService * device,
11030 IOOptionBits flags,
11031 const char * reason,
11032 __unused OSObject * details )
11033{
11034 if (!device || !reason) {
11035 return;
11036 }
11037
11038 DEBUG_LOG("claimSystemShutdownEvent(%s, %s, 0x%x)\n", reason, device->getName(), (uint32_t) flags);
11039#if DEVELOPMENT || DEBUG
11040 record_system_event(SYSTEM_EVENT_TYPE_INFO,
11041 SYSTEM_EVENT_SUBSYSTEM_PMRD,
11042 "Report System Shutdown Cause From Previous Boot",
11043 "Reason: %s Flags: 0x%x Device: %s",
11044 reason,
11045 (int)flags,
11046 device->getName()
11047 );
11048#endif /* DEVELOPMENT || DEBUG */
11049 WAKEEVENT_LOCK();
11050 if (gShutdownReasonString[0] != '\0') {
11051 strlcat(dst: gShutdownReasonString, src: " ", n: sizeof(gShutdownReasonString));
11052 }
11053 strlcat(dst: gShutdownReasonString, src: reason, n: sizeof(gShutdownReasonString));
11054
11055 gShutdownReasonSysctlRegistered = true;
11056 WAKEEVENT_UNLOCK();
11057}
11058
11059/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11060
11061// MARK: -
11062// MARK: PMSettingHandle
11063
11064OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
11065
11066void
11067PMSettingHandle::free( void )
11068{
11069 if (pmso) {
11070 pmso->clientHandleFreed();
11071 pmso->release();
11072 pmso = NULL;
11073 }
11074
11075 OSObject::free();
11076}
11077
11078// MARK: -
11079// MARK: PMSettingObject
11080
11081#undef super
11082#define super OSObject
11083OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
11084
11085/*
11086 * Static constructor/initializer for PMSettingObject
11087 */
11088PMSettingObject *PMSettingObject::pmSettingObject(
11089 IOPMrootDomain * parent_arg,
11090 IOPMSettingControllerCallback handler_arg,
11091 OSObject * target_arg,
11092 uintptr_t refcon_arg,
11093 uint32_t supportedPowerSources,
11094 const OSSymbol * settings[],
11095 OSObject * *handle_obj)
11096{
11097 uint32_t settingCount = 0;
11098 PMSettingObject *pmso = NULL;
11099 PMSettingHandle *pmsh = NULL;
11100
11101 if (!parent_arg || !handler_arg || !settings || !handle_obj) {
11102 return NULL;
11103 }
11104
11105 // count OSSymbol entries in NULL terminated settings array
11106 while (settings[settingCount]) {
11107 settingCount++;
11108 }
11109 if (0 == settingCount) {
11110 return NULL;
11111 }
11112
11113 pmso = new PMSettingObject;
11114 if (!pmso || !pmso->init()) {
11115 goto fail;
11116 }
11117
11118 pmsh = new PMSettingHandle;
11119 if (!pmsh || !pmsh->init()) {
11120 goto fail;
11121 }
11122
11123 queue_init(&pmso->calloutQueue);
11124 pmso->parent = parent_arg;
11125 pmso->func = handler_arg;
11126 pmso->target = target_arg;
11127 pmso->refcon = refcon_arg;
11128 pmso->settingCount = settingCount;
11129
11130 pmso->retain(); // handle holds a retain on pmso
11131 pmsh->pmso = pmso;
11132 pmso->pmsh = pmsh;
11133
11134 pmso->publishedFeatureID = OSDataAllocation<uint32_t>(settingCount, OSAllocateMemory);
11135 if (pmso->publishedFeatureID) {
11136 for (unsigned int i = 0; i < settingCount; i++) {
11137 // Since there is now at least one listener to this setting, publish
11138 // PM root domain support for it.
11139 parent_arg->publishPMSetting( feature: settings[i],
11140 where: supportedPowerSources, featureID: &pmso->publishedFeatureID[i] );
11141 }
11142 }
11143
11144 *handle_obj = pmsh;
11145 return pmso;
11146
11147fail:
11148 if (pmso) {
11149 pmso->release();
11150 }
11151 if (pmsh) {
11152 pmsh->release();
11153 }
11154 return NULL;
11155}
11156
11157void
11158PMSettingObject::free( void )
11159{
11160 if (publishedFeatureID) {
11161 for (const auto& featureID : publishedFeatureID) {
11162 if (featureID) {
11163 parent->removePublishedFeature( removeFeatureID: featureID );
11164 }
11165 }
11166
11167 publishedFeatureID = {};
11168 }
11169
11170 super::free();
11171}
11172
11173IOReturn
11174PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
11175{
11176 return (*func)(target, type, object, refcon);
11177}
11178
11179void
11180PMSettingObject::clientHandleFreed( void )
11181{
11182 parent->deregisterPMSettingObject(pmso: this);
11183}
11184
11185// MARK: -
11186// MARK: PMAssertionsTracker
11187
11188//*********************************************************************************
11189//*********************************************************************************
11190//*********************************************************************************
11191// class PMAssertionsTracker Implementation
11192
11193#define kAssertUniqueIDStart 500
11194
11195PMAssertionsTracker *
11196PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
11197{
11198 PMAssertionsTracker *me;
11199
11200 me = new PMAssertionsTracker;
11201 if (!me || !me->init()) {
11202 if (me) {
11203 me->release();
11204 }
11205 return NULL;
11206 }
11207
11208 me->owner = rootDomain;
11209 me->issuingUniqueID = kAssertUniqueIDStart;
11210 me->assertionsArray = OSArray::withCapacity(capacity: 5);
11211 me->assertionsKernel = 0;
11212 me->assertionsUser = 0;
11213 me->assertionsCombined = 0;
11214 me->assertionsArrayLock = IOLockAlloc();
11215 me->tabulateProducerCount = me->tabulateConsumerCount = 0;
11216
11217 assert(me->assertionsArray);
11218 assert(me->assertionsArrayLock);
11219
11220 return me;
11221}
11222
11223/* tabulate
11224 * - Update assertionsKernel to reflect the state of all
11225 * assertions in the kernel.
11226 * - Update assertionsCombined to reflect both kernel & user space.
11227 */
11228void
11229PMAssertionsTracker::tabulate(void)
11230{
11231 int i;
11232 int count;
11233 const PMAssertStruct *_a = nullptr;
11234 OSValueObject<PMAssertStruct> *_d = nullptr;
11235
11236 IOPMDriverAssertionType oldKernel = assertionsKernel;
11237 IOPMDriverAssertionType oldCombined = assertionsCombined;
11238
11239 ASSERT_GATED();
11240
11241 assertionsKernel = 0;
11242 assertionsCombined = 0;
11243
11244 if (!assertionsArray) {
11245 return;
11246 }
11247
11248 if ((count = assertionsArray->getCount())) {
11249 for (i = 0; i < count; i++) {
11250 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11251 if (_d) {
11252 _a = _d->getBytesNoCopy();
11253 if (_a && (kIOPMDriverAssertionLevelOn == _a->level)) {
11254 assertionsKernel |= _a->assertionBits;
11255 }
11256 }
11257 }
11258 }
11259
11260 tabulateProducerCount++;
11261 assertionsCombined = assertionsKernel | assertionsUser;
11262
11263 if ((assertionsKernel != oldKernel) ||
11264 (assertionsCombined != oldCombined)) {
11265 owner->evaluateAssertions(newAssertions: assertionsCombined, oldAssertions: oldCombined);
11266 }
11267}
11268
11269void
11270PMAssertionsTracker::updateCPUBitAccounting( PMAssertStruct *assertStruct )
11271{
11272 AbsoluteTime now;
11273 uint64_t nsec;
11274
11275 if (((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) == 0) ||
11276 (assertStruct->assertCPUStartTime == 0)) {
11277 return;
11278 }
11279
11280 now = mach_absolute_time();
11281 SUB_ABSOLUTETIME(&now, &assertStruct->assertCPUStartTime);
11282 absolutetime_to_nanoseconds(abstime: now, result: &nsec);
11283 assertStruct->assertCPUDuration += nsec;
11284 assertStruct->assertCPUStartTime = 0;
11285
11286 if (assertStruct->assertCPUDuration > maxAssertCPUDuration) {
11287 maxAssertCPUDuration = assertStruct->assertCPUDuration;
11288 maxAssertCPUEntryId = assertStruct->registryEntryID;
11289 }
11290}
11291
11292void
11293PMAssertionsTracker::reportCPUBitAccounting( void )
11294{
11295 const PMAssertStruct *_a = nullptr;
11296 OSValueObject<PMAssertStruct> *_d = nullptr;
11297 int i, count;
11298 AbsoluteTime now;
11299 uint64_t nsec;
11300
11301 ASSERT_GATED();
11302
11303 // Account for drivers that are still holding the CPU assertion
11304 if (assertionsKernel & kIOPMDriverAssertionCPUBit) {
11305 now = mach_absolute_time();
11306 if ((count = assertionsArray->getCount())) {
11307 for (i = 0; i < count; i++) {
11308 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11309 if (_d) {
11310 _a = _d->getBytesNoCopy();
11311 if ((_a->assertionBits & kIOPMDriverAssertionCPUBit) &&
11312 (_a->level == kIOPMDriverAssertionLevelOn) &&
11313 (_a->assertCPUStartTime != 0)) {
11314 // Don't modify PMAssertStruct, leave that
11315 // for updateCPUBitAccounting()
11316 SUB_ABSOLUTETIME(&now, &_a->assertCPUStartTime);
11317 absolutetime_to_nanoseconds(abstime: now, result: &nsec);
11318 nsec += _a->assertCPUDuration;
11319 if (nsec > maxAssertCPUDuration) {
11320 maxAssertCPUDuration = nsec;
11321 maxAssertCPUEntryId = _a->registryEntryID;
11322 }
11323 }
11324 }
11325 }
11326 }
11327 }
11328
11329 if (maxAssertCPUDuration) {
11330 DLOG("cpu assertion held for %llu ms by 0x%llx\n",
11331 (maxAssertCPUDuration / NSEC_PER_MSEC), maxAssertCPUEntryId);
11332 }
11333
11334 maxAssertCPUDuration = 0;
11335 maxAssertCPUEntryId = 0;
11336}
11337
11338void
11339PMAssertionsTracker::publishProperties( void )
11340{
11341 OSSharedPtr<OSArray> assertionsSummary;
11342
11343 if (tabulateConsumerCount != tabulateProducerCount) {
11344 IOLockLock(assertionsArrayLock);
11345
11346 tabulateConsumerCount = tabulateProducerCount;
11347
11348 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
11349 */
11350 assertionsSummary = copyAssertionsArray();
11351 if (assertionsSummary) {
11352 owner->setProperty(kIOPMAssertionsDriverDetailedKey, anObject: assertionsSummary.get());
11353 } else {
11354 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
11355 }
11356
11357 /* Publish the IOPMrootDomain property "DriverPMAssertions"
11358 */
11359 owner->setProperty(kIOPMAssertionsDriverKey, aValue: assertionsKernel, aNumberOfBits: 64);
11360
11361 IOLockUnlock(assertionsArrayLock);
11362 }
11363}
11364
11365PMAssertStruct *
11366PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
11367{
11368 PMAssertStruct *_a = NULL;
11369 OSValueObject<PMAssertStruct> *_d = nullptr;
11370 int found = -1;
11371 int count = 0;
11372 int i = 0;
11373
11374 if (assertionsArray
11375 && (count = assertionsArray->getCount())) {
11376 for (i = 0; i < count; i++) {
11377 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11378 if (_d) {
11379 _a = _d->getMutableBytesNoCopy();
11380 if (_a && (_id == _a->id)) {
11381 found = i;
11382 break;
11383 }
11384 }
11385 }
11386 }
11387
11388 if (-1 == found) {
11389 return NULL;
11390 } else {
11391 if (index) {
11392 *index = found;
11393 }
11394 return _a;
11395 }
11396}
11397
11398/* PMAssertionsTracker::handleCreateAssertion
11399 * Perform assertion work on the PM workloop. Do not call directly.
11400 */
11401IOReturn
11402PMAssertionsTracker::handleCreateAssertion(OSValueObject<PMAssertStruct> *newAssertion)
11403{
11404 PMAssertStruct *assertStruct = nullptr;
11405
11406 ASSERT_GATED();
11407
11408 if (newAssertion) {
11409 IOLockLock(assertionsArrayLock);
11410 assertStruct = newAssertion->getMutableBytesNoCopy();
11411 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11412 (assertStruct->level == kIOPMDriverAssertionLevelOn)) {
11413 assertStruct->assertCPUStartTime = mach_absolute_time();
11414 }
11415 assertionsArray->setObject(newAssertion);
11416 IOLockUnlock(assertionsArrayLock);
11417 newAssertion->release();
11418
11419 tabulate();
11420 }
11421 return kIOReturnSuccess;
11422}
11423
11424/* PMAssertionsTracker::createAssertion
11425 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
11426 * appropiate.
11427 */
11428IOReturn
11429PMAssertionsTracker::createAssertion(
11430 IOPMDriverAssertionType which,
11431 IOPMDriverAssertionLevel level,
11432 IOService *serviceID,
11433 const char *whoItIs,
11434 IOPMDriverAssertionID *outID)
11435{
11436 OSSharedPtr<OSValueObject<PMAssertStruct> > dataStore;
11437 PMAssertStruct track;
11438
11439 // Warning: trillions and trillions of created assertions may overflow the unique ID.
11440 track.id = OSIncrementAtomic64(address: (SInt64*) &issuingUniqueID);
11441 track.level = level;
11442 track.assertionBits = which;
11443
11444 // NB: ownerString is explicitly managed by PMAssertStruct
11445 // it will be released in `handleReleaseAssertion' below
11446 track.ownerString = whoItIs ? OSSymbol::withCString(cString: whoItIs).detach():nullptr;
11447 track.ownerService = serviceID;
11448 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
11449 track.modifiedTime = 0;
11450 pmEventTimeStamp(recordTS: &track.createdTime);
11451 track.assertCPUStartTime = 0;
11452 track.assertCPUDuration = 0;
11453
11454 dataStore = OSValueObjectWithValue(value: track);
11455 if (!dataStore) {
11456 if (track.ownerString) {
11457 track.ownerString->release();
11458 track.ownerString = NULL;
11459 }
11460 return kIOReturnNoMemory;
11461 }
11462
11463 *outID = track.id;
11464
11465 if (owner && owner->pmPowerStateQueue) {
11466 // queue action is responsible for releasing dataStore
11467 owner->pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventAssertionCreate, arg0: (void *)dataStore.detach());
11468 }
11469
11470 return kIOReturnSuccess;
11471}
11472
11473/* PMAssertionsTracker::handleReleaseAssertion
11474 * Runs in PM workloop. Do not call directly.
11475 */
11476IOReturn
11477PMAssertionsTracker::handleReleaseAssertion(
11478 IOPMDriverAssertionID _id)
11479{
11480 ASSERT_GATED();
11481
11482 int index;
11483 PMAssertStruct *assertStruct = detailsForID(_id, index: &index);
11484
11485 if (!assertStruct) {
11486 return kIOReturnNotFound;
11487 }
11488
11489 IOLockLock(assertionsArrayLock);
11490
11491 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11492 (assertStruct->level == kIOPMDriverAssertionLevelOn)) {
11493 updateCPUBitAccounting(assertStruct);
11494 }
11495
11496 if (assertStruct->ownerString) {
11497 assertStruct->ownerString->release();
11498 assertStruct->ownerString = NULL;
11499 }
11500
11501 assertionsArray->removeObject(index);
11502 IOLockUnlock(assertionsArrayLock);
11503
11504 tabulate();
11505 return kIOReturnSuccess;
11506}
11507
11508/* PMAssertionsTracker::releaseAssertion
11509 * Releases an assertion and affects system behavior if appropiate.
11510 * Actual work happens on PM workloop.
11511 */
11512IOReturn
11513PMAssertionsTracker::releaseAssertion(
11514 IOPMDriverAssertionID _id)
11515{
11516 if (owner && owner->pmPowerStateQueue) {
11517 owner->pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventAssertionRelease, NULL, arg1: _id);
11518 }
11519 return kIOReturnSuccess;
11520}
11521
11522/* PMAssertionsTracker::handleSetAssertionLevel
11523 * Runs in PM workloop. Do not call directly.
11524 */
11525IOReturn
11526PMAssertionsTracker::handleSetAssertionLevel(
11527 IOPMDriverAssertionID _id,
11528 IOPMDriverAssertionLevel _level)
11529{
11530 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
11531
11532 ASSERT_GATED();
11533
11534 if (!assertStruct) {
11535 return kIOReturnNotFound;
11536 }
11537
11538 IOLockLock(assertionsArrayLock);
11539 pmEventTimeStamp(recordTS: &assertStruct->modifiedTime);
11540 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11541 (assertStruct->level != _level)) {
11542 if (_level == kIOPMDriverAssertionLevelOn) {
11543 assertStruct->assertCPUStartTime = mach_absolute_time();
11544 } else {
11545 updateCPUBitAccounting(assertStruct);
11546 }
11547 }
11548 assertStruct->level = _level;
11549 IOLockUnlock(assertionsArrayLock);
11550
11551 tabulate();
11552 return kIOReturnSuccess;
11553}
11554
11555/* PMAssertionsTracker::setAssertionLevel
11556 */
11557IOReturn
11558PMAssertionsTracker::setAssertionLevel(
11559 IOPMDriverAssertionID _id,
11560 IOPMDriverAssertionLevel _level)
11561{
11562 if (owner && owner->pmPowerStateQueue) {
11563 owner->pmPowerStateQueue->submitPowerEvent(eventType: kPowerEventAssertionSetLevel,
11564 arg0: (void *)(uintptr_t)_level, arg1: _id);
11565 }
11566
11567 return kIOReturnSuccess;
11568}
11569
11570IOReturn
11571PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
11572{
11573 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
11574
11575 ASSERT_GATED();
11576
11577 if (new_user_levels != assertionsUser) {
11578 DLOG("assertionsUser 0x%llx->0x%llx\n", assertionsUser, new_user_levels);
11579 assertionsUser = new_user_levels;
11580 }
11581
11582 tabulate();
11583 return kIOReturnSuccess;
11584}
11585
11586IOReturn
11587PMAssertionsTracker::setUserAssertionLevels(
11588 IOPMDriverAssertionType new_user_levels)
11589{
11590 if (gIOPMWorkLoop) {
11591 gIOPMWorkLoop->runAction(
11592 OSMemberFunctionCast(
11593 IOWorkLoop::Action,
11594 this,
11595 &PMAssertionsTracker::handleSetUserAssertionLevels),
11596 target: this,
11597 arg0: (void *) &new_user_levels, NULL, NULL, NULL);
11598 }
11599
11600 return kIOReturnSuccess;
11601}
11602
11603
11604OSSharedPtr<OSArray>
11605PMAssertionsTracker::copyAssertionsArray(void)
11606{
11607 int count;
11608 int i;
11609 OSSharedPtr<OSArray> outArray = NULL;
11610
11611 if (!assertionsArray || (0 == (count = assertionsArray->getCount()))) {
11612 goto exit;
11613 }
11614 outArray = OSArray::withCapacity(capacity: count);
11615 if (!outArray) {
11616 goto exit;
11617 }
11618
11619 for (i = 0; i < count; i++) {
11620 const PMAssertStruct *_a = nullptr;
11621 OSValueObject<PMAssertStruct> *_d = nullptr;
11622 OSSharedPtr<OSDictionary> details;
11623
11624 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11625 if (_d && (_a = _d->getBytesNoCopy())) {
11626 OSSharedPtr<OSNumber> _n;
11627
11628 details = OSDictionary::withCapacity(capacity: 7);
11629 if (!details) {
11630 continue;
11631 }
11632
11633 outArray->setObject(details.get());
11634
11635 _n = OSNumber::withNumber(value: _a->id, numberOfBits: 64);
11636 if (_n) {
11637 details->setObject(kIOPMDriverAssertionIDKey, anObject: _n.get());
11638 }
11639 _n = OSNumber::withNumber(value: _a->createdTime, numberOfBits: 64);
11640 if (_n) {
11641 details->setObject(kIOPMDriverAssertionCreatedTimeKey, anObject: _n.get());
11642 }
11643 _n = OSNumber::withNumber(value: _a->modifiedTime, numberOfBits: 64);
11644 if (_n) {
11645 details->setObject(kIOPMDriverAssertionModifiedTimeKey, anObject: _n.get());
11646 }
11647 _n = OSNumber::withNumber(value: (uintptr_t)_a->registryEntryID, numberOfBits: 64);
11648 if (_n) {
11649 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, anObject: _n.get());
11650 }
11651 _n = OSNumber::withNumber(value: _a->level, numberOfBits: 64);
11652 if (_n) {
11653 details->setObject(kIOPMDriverAssertionLevelKey, anObject: _n.get());
11654 }
11655 _n = OSNumber::withNumber(value: _a->assertionBits, numberOfBits: 64);
11656 if (_n) {
11657 details->setObject(kIOPMDriverAssertionAssertedKey, anObject: _n.get());
11658 }
11659
11660 if (_a->ownerString) {
11661 details->setObject(kIOPMDriverAssertionOwnerStringKey, anObject: _a->ownerString);
11662 }
11663 }
11664 }
11665
11666exit:
11667 return os::move(t&: outArray);
11668}
11669
11670IOPMDriverAssertionType
11671PMAssertionsTracker::getActivatedAssertions(void)
11672{
11673 return assertionsCombined;
11674}
11675
11676IOPMDriverAssertionLevel
11677PMAssertionsTracker::getAssertionLevel(
11678 IOPMDriverAssertionType type)
11679{
11680 // FIXME: unused and also wrong
11681 if (type && ((type & assertionsKernel) == assertionsKernel)) {
11682 return kIOPMDriverAssertionLevelOn;
11683 } else {
11684 return kIOPMDriverAssertionLevelOff;
11685 }
11686}
11687
11688//*********************************************************************************
11689//*********************************************************************************
11690//*********************************************************************************
11691
11692
11693static void
11694pmEventTimeStamp(uint64_t *recordTS)
11695{
11696 clock_sec_t tsec;
11697 clock_usec_t tusec;
11698
11699 if (!recordTS) {
11700 return;
11701 }
11702
11703 // We assume tsec fits into 32 bits; 32 bits holds enough
11704 // seconds for 136 years since the epoch in 1970.
11705 clock_get_calendar_microtime(secs: &tsec, microsecs: &tusec);
11706
11707
11708 // Pack the sec & microsec calendar time into a uint64_t, for fun.
11709 *recordTS = 0;
11710 *recordTS |= (uint32_t)tusec;
11711 *recordTS |= ((uint64_t)tsec << 32);
11712
11713 return;
11714}
11715
11716// MARK: -
11717// MARK: IORootParent
11718
11719/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11720
11721OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
11722
11723// The reason that root domain needs a root parent is to facilitate demand
11724// sleep, since a power change from the root parent cannot be vetoed.
11725//
11726// The above statement is no longer true since root domain now performs
11727// demand sleep using overrides. But root parent remains to avoid changing
11728// the power tree stacking. Root parent is parked at the max power state.
11729
11730
11731static IOPMPowerState patriarchPowerStates[2] =
11732{
11733 {.version: 1, .capabilityFlags: 0, ON_POWER, .inputPowerRequirement: 0, .staticPower: 0, .stateOrder: 0, .powerToAttain: 0, .timeToAttain: 0, .settleUpTime: 0, .timeToLower: 0, .settleDownTime: 0, .powerDomainBudget: 0},
11734 {.version: 1, .capabilityFlags: 0, ON_POWER, .inputPowerRequirement: 0, .staticPower: 0, .stateOrder: 0, .powerToAttain: 0, .timeToAttain: 0, .settleUpTime: 0, .timeToLower: 0, .settleDownTime: 0, .powerDomainBudget: 0},
11735};
11736
11737void
11738IORootParent::initialize( void )
11739{
11740
11741 gIOPMPSExternalConnectedKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey);
11742 gIOPMPSExternalChargeCapableKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey);
11743 gIOPMPSBatteryInstalledKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey);
11744 gIOPMPSIsChargingKey = OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey);
11745 gIOPMPSAtWarnLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey);
11746 gIOPMPSAtCriticalLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey);
11747 gIOPMPSCurrentCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey);
11748 gIOPMPSMaxCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey);
11749 gIOPMPSDesignCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey);
11750 gIOPMPSTimeRemainingKey = OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey);
11751 gIOPMPSAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey);
11752 gIOPMPSVoltageKey = OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey);
11753 gIOPMPSCycleCountKey = OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey);
11754 gIOPMPSMaxErrKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey);
11755 gIOPMPSAdapterInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey);
11756 gIOPMPSLocationKey = OSSymbol::withCStringNoCopy(kIOPMPSLocationKey);
11757 gIOPMPSErrorConditionKey = OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey);
11758 gIOPMPSManufacturerKey = OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey);
11759 gIOPMPSManufactureDateKey = OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey);
11760 gIOPMPSModelKey = OSSymbol::withCStringNoCopy(kIOPMPSModelKey);
11761 gIOPMPSSerialKey = OSSymbol::withCStringNoCopy(kIOPMPSSerialKey);
11762 gIOPMPSLegacyBatteryInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey);
11763 gIOPMPSBatteryHealthKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey);
11764 gIOPMPSHealthConfidenceKey = OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey);
11765 gIOPMPSCapacityEstimatedKey = OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey);
11766 gIOPMPSBatteryChargeStatusKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey);
11767 gIOPMPSBatteryTemperatureKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey);
11768 gIOPMPSAdapterDetailsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey);
11769 gIOPMPSChargerConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey);
11770 gIOPMPSAdapterDetailsIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey);
11771 gIOPMPSAdapterDetailsWattsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey);
11772 gIOPMPSAdapterDetailsRevisionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey);
11773 gIOPMPSAdapterDetailsSerialNumberKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey);
11774 gIOPMPSAdapterDetailsFamilyKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey);
11775 gIOPMPSAdapterDetailsAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey);
11776 gIOPMPSAdapterDetailsDescriptionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey);
11777 gIOPMPSAdapterDetailsPMUConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey);
11778 gIOPMPSAdapterDetailsSourceIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey);
11779 gIOPMPSAdapterDetailsErrorFlagsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey);
11780 gIOPMPSAdapterDetailsSharedSourceKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey);
11781 gIOPMPSAdapterDetailsCloakedKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey);
11782 gIOPMPSInvalidWakeSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey);
11783 gIOPMPSPostChargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey);
11784 gIOPMPSPostDishargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey);
11785}
11786
11787bool
11788IORootParent::start( IOService * nub )
11789{
11790 IOService::start(provider: nub);
11791 attachToParent( parent: getRegistryRoot(), plane: gIOPowerPlane );
11792 PMinit();
11793 registerPowerDriver(controllingDriver: this, powerStates: patriarchPowerStates, numberOfStates: 2);
11794 makeUsable();
11795 return true;
11796}
11797
11798void
11799IORootParent::shutDownSystem( void )
11800{
11801}
11802
11803void
11804IORootParent::restartSystem( void )
11805{
11806}
11807
11808void
11809IORootParent::sleepSystem( void )
11810{
11811}
11812
11813void
11814IORootParent::dozeSystem( void )
11815{
11816}
11817
11818void
11819IORootParent::sleepToDoze( void )
11820{
11821}
11822
11823void
11824IORootParent::wakeSystem( void )
11825{
11826}
11827
11828OSSharedPtr<OSObject>
11829IORootParent::copyProperty( const char * aKey) const
11830{
11831 return IOService::copyProperty(aKey);
11832}
11833
11834uint32_t
11835IOPMrootDomain::getWatchdogTimeout()
11836{
11837 if (gSwdSleepWakeTimeout) {
11838 gSwdSleepTimeout = gSwdWakeTimeout = gSwdSleepWakeTimeout;
11839 }
11840 if ((pmTracer->getTracePhase() < kIOPMTracePointSystemSleep) ||
11841 (pmTracer->getTracePhase() == kIOPMTracePointDarkWakeEntry)) {
11842 return gSwdSleepTimeout ? gSwdSleepTimeout : WATCHDOG_SLEEP_TIMEOUT;
11843 } else {
11844 return gSwdWakeTimeout ? gSwdWakeTimeout : WATCHDOG_WAKE_TIMEOUT;
11845 }
11846}
11847
11848
11849#if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
11850IOReturn
11851IOPMrootDomain::restartWithStackshot()
11852{
11853 takeStackshot(true);
11854
11855 return kIOReturnSuccess;
11856}
11857
11858void
11859IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
11860{
11861 takeStackshot(wdogTrigger);
11862}
11863
11864void
11865IOPMrootDomain::tracePhase2String(uint32_t tracePhase, const char **phaseString, const char **description)
11866{
11867 switch (tracePhase) {
11868 case kIOPMTracePointSleepStarted:
11869 *phaseString = "kIOPMTracePointSleepStarted";
11870 *description = "starting sleep";
11871 break;
11872
11873 case kIOPMTracePointSleepApplications:
11874 *phaseString = "kIOPMTracePointSleepApplications";
11875 *description = "notifying applications";
11876 break;
11877
11878 case kIOPMTracePointSleepPriorityClients:
11879 *phaseString = "kIOPMTracePointSleepPriorityClients";
11880 *description = "notifying clients about upcoming system capability changes";
11881 break;
11882
11883 case kIOPMTracePointSleepWillChangeInterests:
11884 *phaseString = "kIOPMTracePointSleepWillChangeInterests";
11885 *description = "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
11886 break;
11887
11888 case kIOPMTracePointSleepPowerPlaneDrivers:
11889 *phaseString = "kIOPMTracePointSleepPowerPlaneDrivers";
11890 *description = "calling power state change callbacks";
11891 break;
11892
11893 case kIOPMTracePointSleepDidChangeInterests:
11894 *phaseString = "kIOPMTracePointSleepDidChangeInterests";
11895 *description = "calling rootDomain's clients about rootDomain's state changes";
11896 break;
11897
11898 case kIOPMTracePointSleepCapabilityClients:
11899 *phaseString = "kIOPMTracePointSleepCapabilityClients";
11900 *description = "notifying clients about current system capabilities";
11901 break;
11902
11903 case kIOPMTracePointSleepPlatformActions:
11904 *phaseString = "kIOPMTracePointSleepPlatformActions";
11905 *description = "calling Quiesce/Sleep action callbacks";
11906 break;
11907
11908 case kIOPMTracePointSleepCPUs:
11909 {
11910 *phaseString = "kIOPMTracePointSleepCPUs";
11911#if defined(__i386__) || defined(__x86_64__)
11912 /*
11913 * We cannot use the getCPUNumber() method to get the cpu number, since
11914 * that cpu number is unrelated to the cpu number we need (we need the cpu
11915 * number as enumerated by the scheduler, NOT the CPU number enumerated
11916 * by ACPIPlatform as the CPUs are enumerated in MADT order).
11917 * Instead, pass the Mach processor pointer associated with the current
11918 * shutdown target so its associated cpu_id can be used in
11919 * processor_to_datastring.
11920 */
11921 if (currentShutdownTarget != NULL &&
11922 currentShutdownTarget->getMachProcessor() != NULL) {
11923 const char *sbuf = processor_to_datastring("halting all non-boot CPUs",
11924 currentShutdownTarget->getMachProcessor());
11925 *description = sbuf;
11926 } else {
11927 *description = "halting all non-boot CPUs";
11928 }
11929#else
11930 *description = "halting all non-boot CPUs";
11931#endif
11932 break;
11933 }
11934 case kIOPMTracePointSleepPlatformDriver:
11935 *phaseString = "kIOPMTracePointSleepPlatformDriver";
11936 *description = "executing platform specific code";
11937 break;
11938
11939 case kIOPMTracePointHibernate:
11940 *phaseString = "kIOPMTracePointHibernate";
11941 *description = "writing the hibernation image";
11942 break;
11943
11944 case kIOPMTracePointSystemSleep:
11945 *phaseString = "kIOPMTracePointSystemSleep";
11946 *description = "in EFI/Bootrom after last point of entry to sleep";
11947 break;
11948
11949 case kIOPMTracePointWakePlatformDriver:
11950 *phaseString = "kIOPMTracePointWakePlatformDriver";
11951 *description = "executing platform specific code";
11952 break;
11953
11954
11955 case kIOPMTracePointWakePlatformActions:
11956 *phaseString = "kIOPMTracePointWakePlatformActions";
11957 *description = "calling Wake action callbacks";
11958 break;
11959
11960 case kIOPMTracePointWakeCPUs:
11961 *phaseString = "kIOPMTracePointWakeCPUs";
11962 *description = "starting non-boot CPUs";
11963 break;
11964
11965 case kIOPMTracePointWakeWillPowerOnClients:
11966 *phaseString = "kIOPMTracePointWakeWillPowerOnClients";
11967 *description = "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
11968 break;
11969
11970 case kIOPMTracePointWakeWillChangeInterests:
11971 *phaseString = "kIOPMTracePointWakeWillChangeInterests";
11972 *description = "calling rootDomain's clients about upcoming rootDomain's state changes";
11973 break;
11974
11975 case kIOPMTracePointWakeDidChangeInterests:
11976 *phaseString = "kIOPMTracePointWakeDidChangeInterests";
11977 *description = "calling rootDomain's clients about completed rootDomain's state changes";
11978 break;
11979
11980 case kIOPMTracePointWakePowerPlaneDrivers:
11981 *phaseString = "kIOPMTracePointWakePowerPlaneDrivers";
11982 *description = "calling power state change callbacks";
11983 break;
11984
11985 case kIOPMTracePointWakeCapabilityClients:
11986 *phaseString = "kIOPMTracePointWakeCapabilityClients";
11987 *description = "informing clients about current system capabilities";
11988 break;
11989
11990 case kIOPMTracePointWakeApplications:
11991 *phaseString = "kIOPMTracePointWakeApplications";
11992 *description = "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
11993 break;
11994
11995 case kIOPMTracePointDarkWakeEntry:
11996 *phaseString = "kIOPMTracePointDarkWakeEntry";
11997 *description = "entering darkwake on way to sleep";
11998 break;
11999
12000 case kIOPMTracePointDarkWakeExit:
12001 *phaseString = "kIOPMTracePointDarkWakeExit";
12002 *description = "entering fullwake from darkwake";
12003 break;
12004
12005 default:
12006 *phaseString = NULL;
12007 *description = NULL;
12008 }
12009}
12010
12011void
12012IOPMrootDomain::saveFailureData2File()
12013{
12014 unsigned int len = 0;
12015 char failureStr[512];
12016 errno_t error;
12017 char *outbuf;
12018 OSNumber *statusCode;
12019 uint64_t pmStatusCode = 0;
12020 uint32_t phaseData = 0;
12021 uint32_t phaseDetail = 0;
12022 bool efiFailure = false;
12023
12024 OSSharedPtr<OSObject> statusCodeProp = copyProperty(kIOPMSleepWakeFailureCodeKey);
12025 statusCode = OSDynamicCast(OSNumber, statusCodeProp.get());
12026 if (statusCode) {
12027 pmStatusCode = statusCode->unsigned64BitValue();
12028 phaseData = pmStatusCode & 0xFFFFFFFF;
12029 phaseDetail = (pmStatusCode >> 32) & 0xFFFFFFFF;
12030 if ((phaseData & 0xFF) == kIOPMTracePointSystemSleep) {
12031 LOG("Sleep Wake failure in EFI\n");
12032 efiFailure = true;
12033 failureStr[0] = 0;
12034 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);
12035 len = (typeof(len))strnlen(failureStr, sizeof(failureStr));
12036 }
12037 }
12038
12039 if (!efiFailure) {
12040 if (PEReadNVRAMProperty(kIOSleepWakeFailurePanic, NULL, &len)) {
12041 swd_flags |= SWD_BOOT_BY_SW_WDOG;
12042 PERemoveNVRAMProperty(kIOSleepWakeFailurePanic);
12043 // dump panic will handle saving nvram data
12044 return;
12045 }
12046
12047 /* Keeping this around for capturing data during power
12048 * button press */
12049
12050 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString, NULL, &len)) {
12051 DLOG("No sleep wake failure string\n");
12052 return;
12053 }
12054 if (len == 0) {
12055 DLOG("Ignoring zero byte SleepWake failure string\n");
12056 goto exit;
12057 }
12058
12059 // if PMStatus code is zero, delete stackshot and return
12060 if (statusCode) {
12061 if (((pmStatusCode & 0xFFFFFFFF) & 0xFF) == 0) {
12062 // there was no sleep wake failure
12063 // this can happen if delete stackshot was called
12064 // before take stackshot completed. Let us delete any
12065 // sleep wake failure data in nvram
12066 DLOG("Deleting stackshot on successful wake\n");
12067 deleteStackshot();
12068 return;
12069 }
12070 }
12071
12072 if (len > sizeof(failureStr)) {
12073 len = sizeof(failureStr);
12074 }
12075 failureStr[0] = 0;
12076 PEReadNVRAMProperty(kIOSleepWakeFailureString, failureStr, &len);
12077 }
12078 if (failureStr[0] != 0) {
12079 error = sleepWakeDebugSaveFile(kSleepWakeFailureStringFile, failureStr, len);
12080 if (error) {
12081 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error);
12082 } else {
12083 DLOG("Saved SleepWake failure string to file.\n");
12084 }
12085 }
12086
12087 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12088 goto exit;
12089 }
12090
12091 if (swd_buffer) {
12092 unsigned int len = 0;
12093 errno_t error;
12094 char nvram_var_name_buffer[20];
12095 unsigned int concat_len = 0;
12096 swd_hdr *hdr = NULL;
12097
12098
12099 hdr = (swd_hdr *)swd_buffer;
12100 outbuf = (char *)hdr + hdr->spindump_offset;
12101 OSBoundedArrayRef<char> boundedOutBuf(outbuf, hdr->alloc_size - hdr->spindump_offset);
12102
12103 for (int i = 0; i < 8; i++) {
12104 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i + 1);
12105 if (!PEReadNVRAMProperty(nvram_var_name_buffer, NULL, &len)) {
12106 LOG("No SleepWake blob to read beyond chunk %d\n", i);
12107 break;
12108 }
12109 if (PEReadNVRAMProperty(nvram_var_name_buffer, boundedOutBuf.slice(concat_len, len).data(), &len) == FALSE) {
12110 PERemoveNVRAMProperty(nvram_var_name_buffer);
12111 LOG("Could not read the property :-(\n");
12112 break;
12113 }
12114 PERemoveNVRAMProperty(nvram_var_name_buffer);
12115 concat_len += len;
12116 }
12117 LOG("Concatenated length for the SWD blob %d\n", concat_len);
12118
12119 if (concat_len) {
12120 error = sleepWakeDebugSaveFile(kSleepWakeStacksFilename, outbuf, concat_len);
12121 if (error) {
12122 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
12123 } else {
12124 LOG("Saved SleepWake zipped data to file.\n");
12125 }
12126 } else {
12127 // There is a sleep wake failure string but no stackshot
12128 // Write a placeholder stacks file so that swd runs
12129 snprintf(outbuf, 20, "%s", "No stackshot data\n");
12130 error = sleepWakeDebugSaveFile(kSleepWakeStacksFilename, outbuf, 20);
12131 if (error) {
12132 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
12133 } else {
12134 LOG("Saved SleepWake zipped data to file.\n");
12135 }
12136 }
12137 } else {
12138 LOG("No buffer allocated to save failure stackshot\n");
12139 }
12140
12141
12142 gRootDomain->swd_lock = 0;
12143exit:
12144 PERemoveNVRAMProperty(kIOSleepWakeFailureString);
12145 return;
12146}
12147
12148
12149void
12150IOPMrootDomain::getFailureData(thread_t *thread, char *failureStr, size_t strLen)
12151{
12152 OSSharedPtr<IORegistryIterator> iter;
12153 OSSharedPtr<const OSSymbol> kextName = NULL;
12154 IORegistryEntry * entry;
12155 IOService * node;
12156 bool nodeFound = false;
12157
12158 const void * callMethod = NULL;
12159 const char * objectName = NULL;
12160 uint32_t timeout = getWatchdogTimeout();
12161 const char * phaseString = NULL;
12162 const char * phaseDescription = NULL;
12163
12164 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, notifierObject.get());
12165 uint32_t tracePhase = pmTracer->getTracePhase();
12166
12167 *thread = NULL;
12168 if ((tracePhase < kIOPMTracePointSystemSleep) || (tracePhase == kIOPMTracePointDarkWakeEntry)) {
12169 snprintf(failureStr, strLen, "Sleep transition timed out after %d seconds", timeout);
12170 } else {
12171 snprintf(failureStr, strLen, "Wake transition timed out after %d seconds", timeout);
12172 }
12173 tracePhase2String(tracePhase, &phaseString, &phaseDescription);
12174
12175 if (notifierThread) {
12176 if (notifier && (notifier->identifier)) {
12177 objectName = notifier->identifier->getCStringNoCopy();
12178 }
12179 *thread = notifierThread;
12180 } else {
12181 iter = IORegistryIterator::iterateOver(
12182 getPMRootDomain(), gIOPowerPlane, kIORegistryIterateRecursively);
12183
12184 if (iter) {
12185 while ((entry = iter->getNextObject())) {
12186 node = OSDynamicCast(IOService, entry);
12187 if (!node) {
12188 continue;
12189 }
12190 if (OSDynamicCast(IOPowerConnection, node)) {
12191 continue;
12192 }
12193
12194 if (node->getBlockingDriverCall(thread, &callMethod)) {
12195 nodeFound = true;
12196 break;
12197 }
12198 }
12199 }
12200 if (nodeFound) {
12201 kextName = copyKextIdentifierWithAddress((vm_address_t) callMethod);
12202 if (kextName) {
12203 objectName = kextName->getCStringNoCopy();
12204 }
12205 }
12206 }
12207 if (phaseDescription) {
12208 strlcat(failureStr, " while ", strLen);
12209 strlcat(failureStr, phaseDescription, strLen);
12210 strlcat(failureStr, ".", strLen);
12211 }
12212 if (objectName) {
12213 strlcat(failureStr, " Suspected bundle: ", strLen);
12214 strlcat(failureStr, objectName, strLen);
12215 strlcat(failureStr, ".", strLen);
12216 }
12217 if (*thread) {
12218 char threadName[40];
12219 snprintf(threadName, sizeof(threadName), " Thread 0x%llx.", thread_tid(*thread));
12220 strlcat(failureStr, threadName, strLen);
12221 }
12222
12223 DLOG("%s\n", failureStr);
12224}
12225
12226struct swd_stackshot_compressed_data {
12227 z_output_func zoutput;
12228 size_t zipped;
12229 uint64_t totalbytes;
12230 uint64_t lastpercent;
12231 IOReturn error;
12232 unsigned outremain;
12233 unsigned outlen;
12234 unsigned writes;
12235 Bytef * outbuf;
12236};
12237struct swd_stackshot_compressed_data swd_zip_var = { };
12238
12239static void *
12240swd_zs_alloc(void *__unused ref, u_int items, u_int size)
12241{
12242 void *result;
12243 LOG("Alloc in zipping %d items of size %d\n", items, size);
12244
12245 result = (void *)(swd_zs_zmem + swd_zs_zoffset);
12246 swd_zs_zoffset += ~31L & (31 + (items * size)); // 32b align for vector crc
12247 LOG("Offset %zu\n", swd_zs_zoffset);
12248 return result;
12249}
12250
12251static int
12252swd_zinput(z_streamp strm, Bytef *buf, unsigned size)
12253{
12254 unsigned len;
12255
12256 len = strm->avail_in;
12257
12258 if (len > size) {
12259 len = size;
12260 }
12261 if (len == 0) {
12262 return 0;
12263 }
12264
12265 if (strm->next_in != (Bytef *) strm) {
12266 memcpy(buf, strm->next_in, len);
12267 } else {
12268 bzero(buf, len);
12269 }
12270
12271 strm->adler = z_crc32(strm->adler, buf, len);
12272
12273 strm->avail_in -= len;
12274 strm->next_in += len;
12275 strm->total_in += len;
12276
12277 return (int)len;
12278}
12279
12280static int
12281swd_zoutput(z_streamp strm, Bytef *buf, unsigned len)
12282{
12283 unsigned int i = 0;
12284 // if outlen > max size don't add to the buffer
12285 assert(buf != NULL);
12286 if (strm && buf) {
12287 if (swd_zip_var.outlen + len > SWD_COMPRESSED_BUFSIZE) {
12288 LOG("No space to GZIP... not writing to NVRAM\n");
12289 return len;
12290 }
12291 }
12292 for (i = 0; i < len; i++) {
12293 *(swd_zip_var.outbuf + swd_zip_var.outlen + i) = *(buf + i);
12294 }
12295 swd_zip_var.outlen += len;
12296 return len;
12297}
12298
12299static void
12300swd_zs_free(void * __unused ref, void * __unused ptr)
12301{
12302}
12303
12304static int
12305swd_compress(char *inPtr, char *outPtr, size_t numBytes)
12306{
12307 int wbits = 12;
12308 int memlevel = 3;
12309
12310 if (((unsigned int) numBytes) != numBytes) {
12311 return 0;
12312 }
12313
12314 if (!swd_zs.zalloc) {
12315 swd_zs.zalloc = swd_zs_alloc;
12316 swd_zs.zfree = swd_zs_free;
12317 if (deflateInit2(&swd_zs, Z_BEST_SPEED, Z_DEFLATED, wbits + 16, memlevel, Z_DEFAULT_STRATEGY)) {
12318 // allocation failed
12319 bzero(&swd_zs, sizeof(swd_zs));
12320 // swd_zs_zoffset = 0;
12321 } else {
12322 LOG("PMRD inited the zlib allocation routines\n");
12323 }
12324 }
12325
12326 swd_zip_var.zipped = 0;
12327 swd_zip_var.totalbytes = 0; // should this be the max that we have?
12328 swd_zip_var.lastpercent = 0;
12329 swd_zip_var.error = kIOReturnSuccess;
12330 swd_zip_var.outremain = 0;
12331 swd_zip_var.outlen = 0;
12332 swd_zip_var.writes = 0;
12333 swd_zip_var.outbuf = (Bytef *)outPtr;
12334
12335 swd_zip_var.totalbytes = numBytes;
12336
12337 swd_zs.avail_in = 0;
12338 swd_zs.next_in = NULL;
12339 swd_zs.avail_out = 0;
12340 swd_zs.next_out = NULL;
12341
12342 deflateResetWithIO(&swd_zs, swd_zinput, swd_zoutput);
12343
12344 z_stream *zs;
12345 int zr;
12346 zs = &swd_zs;
12347
12348 while (swd_zip_var.error >= 0) {
12349 if (!zs->avail_in) {
12350 zs->next_in = (unsigned char *)inPtr ? (Bytef *)inPtr : (Bytef *)zs; /* zero marker? */
12351 zs->avail_in = (unsigned int) numBytes;
12352 }
12353 if (!zs->avail_out) {
12354 zs->next_out = (Bytef *)zs;
12355 zs->avail_out = UINT32_MAX;
12356 }
12357 zr = deflate(zs, Z_NO_FLUSH);
12358 if (Z_STREAM_END == zr) {
12359 break;
12360 }
12361 if (zr != Z_OK) {
12362 LOG("ZERR %d\n", zr);
12363 swd_zip_var.error = zr;
12364 } else {
12365 if (zs->total_in == numBytes) {
12366 break;
12367 }
12368 }
12369 }
12370
12371 //now flush the stream
12372 while (swd_zip_var.error >= 0) {
12373 if (!zs->avail_out) {
12374 zs->next_out = (Bytef *)zs;
12375 zs->avail_out = UINT32_MAX;
12376 }
12377 zr = deflate(zs, Z_FINISH);
12378 if (Z_STREAM_END == zr) {
12379 break;
12380 }
12381 if (zr != Z_OK) {
12382 LOG("ZERR %d\n", zr);
12383 swd_zip_var.error = zr;
12384 } else {
12385 if (zs->total_in == numBytes) {
12386 LOG("Total output size %d\n", swd_zip_var.outlen);
12387 break;
12388 }
12389 }
12390 }
12391
12392 return swd_zip_var.outlen;
12393}
12394
12395void
12396IOPMrootDomain::deleteStackshot()
12397{
12398 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12399 // takeStackshot hasn't completed
12400 return;
12401 }
12402 LOG("Deleting any sleepwake failure data in nvram\n");
12403
12404 PERemoveNVRAMProperty(kIOSleepWakeFailureString);
12405 char nvram_var_name_buf[20];
12406 for (int i = 0; i < 8; i++) {
12407 snprintf(nvram_var_name_buf, sizeof(nvram_var_name_buf), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i + 1);
12408 if (PERemoveNVRAMProperty(nvram_var_name_buf) == false) {
12409 LOG("Removing %s returned false\n", nvram_var_name_buf);
12410 }
12411 }
12412 // force NVRAM sync
12413 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey)) == false) {
12414 DLOG("Failed to force nvram sync\n");
12415 }
12416 gRootDomain->swd_lock = 0;
12417}
12418
12419void
12420IOPMrootDomain::takeStackshot(bool wdogTrigger)
12421{
12422 swd_hdr * hdr = NULL;
12423 int cnt = 0;
12424 int max_cnt;
12425 pid_t pid = 0;
12426 kern_return_t kr = KERN_SUCCESS;
12427 uint64_t flags;
12428
12429 char * dstAddr;
12430 uint32_t size;
12431 uint32_t bytesRemaining;
12432 unsigned bytesWritten = 0;
12433
12434 char failureStr[512];
12435 thread_t thread = NULL;
12436 const char * swfPanic = "swfPanic";
12437
12438 uint32_t bufSize;
12439 int success = 0;
12440
12441#if defined(__i386__) || defined(__x86_64__)
12442 const bool concise = false;
12443#else
12444 const bool concise = true;
12445#endif
12446
12447 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12448 return;
12449 }
12450
12451 failureStr[0] = 0;
12452 if ((kIOSleepWakeWdogOff & gIOKitDebug) || systemBooting || systemShutdown || gWillShutdown) {
12453 return;
12454 }
12455
12456 if (wdogTrigger) {
12457 getFailureData(&thread, failureStr, sizeof(failureStr));
12458
12459 if (concise || (PEGetCoprocessorVersion() >= kCoprocessorVersion2)) {
12460 goto skip_stackshot;
12461 }
12462 } else {
12463 AbsoluteTime now;
12464 uint64_t nsec;
12465 clock_get_uptime(&now);
12466 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
12467 absolutetime_to_nanoseconds(now, &nsec);
12468 snprintf(failureStr, sizeof(failureStr), "Power button pressed during wake transition after %u ms.\n", ((int)((nsec) / NSEC_PER_MSEC)));
12469 }
12470
12471 if (swd_buffer == NULL) {
12472 sleepWakeDebugMemAlloc();
12473 if (swd_buffer == NULL) {
12474 return;
12475 }
12476 }
12477 hdr = (swd_hdr *)swd_buffer;
12478 bufSize = hdr->alloc_size;
12479
12480 dstAddr = (char*)hdr + hdr->spindump_offset;
12481 flags = STACKSHOT_KCDATA_FORMAT | STACKSHOT_NO_IO_STATS | STACKSHOT_SAVE_KEXT_LOADINFO | STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY | STACKSHOT_THREAD_WAITINFO | STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL;
12482
12483 /* If not wdogTrigger only take kernel tasks stackshot
12484 */
12485 if (wdogTrigger) {
12486 pid = -1;
12487 max_cnt = 3;
12488 } else {
12489 pid = 0;
12490 max_cnt = 2;
12491 }
12492
12493 /* Attempt to take stackshot with all ACTIVE_KERNEL_THREADS
12494 * If we run out of space, take stackshot with only kernel task
12495 */
12496 while (success == 0 && cnt < max_cnt) {
12497 bytesRemaining = bufSize - hdr->spindump_offset;
12498 cnt++;
12499 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
12500
12501 size = bytesRemaining;
12502 kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, 0, &bytesWritten);
12503 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%llx bytesWritten: %d\n",
12504 kr, pid, size, flags, bytesWritten);
12505 if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
12506 if (pid == -1) {
12507 pid = 0;
12508 } else if (flags & STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL) {
12509 flags = flags & ~STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL;
12510 } else {
12511 LOG("Insufficient buffer size for only kernel task\n");
12512 break;
12513 }
12514 }
12515 if (kr == KERN_SUCCESS) {
12516 if (bytesWritten == 0) {
12517 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%llx\n", kr, size, flags);
12518 continue;
12519 }
12520 bytesRemaining -= bytesWritten;
12521 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
12522
12523 memset(hdr->reason, 0x20, sizeof(hdr->reason));
12524
12525 // Compress stackshot and save to NVRAM
12526 {
12527 char *outbuf = (char *)swd_compressed_buffer;
12528 int outlen = 0;
12529 int num_chunks = 0;
12530 int max_chunks = 0;
12531 int leftover = 0;
12532 char nvram_var_name_buffer[20];
12533
12534 outlen = swd_compress((char*)hdr + hdr->spindump_offset, outbuf, bytesWritten);
12535
12536 if (outlen) {
12537 max_chunks = outlen / (2096 - 200);
12538 leftover = outlen % (2096 - 200);
12539
12540 if (max_chunks < 8) {
12541 for (num_chunks = 0; num_chunks < max_chunks; num_chunks++) {
12542 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks + 1);
12543 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer, (outbuf + (num_chunks * (2096 - 200))), (2096 - 200)) == FALSE) {
12544 LOG("Failed to update NVRAM %d\n", num_chunks);
12545 break;
12546 }
12547 }
12548 if (leftover) {
12549 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks + 1);
12550 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer, (outbuf + (num_chunks * (2096 - 200))), leftover) == FALSE) {
12551 LOG("Failed to update NVRAM with leftovers\n");
12552 }
12553 }
12554 success = 1;
12555 LOG("Successfully saved stackshot to NVRAM\n");
12556 } else {
12557 if (pid == -1) {
12558 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen);
12559 pid = 0;
12560 } else if (flags & STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL) {
12561 LOG("Compressed failure stackshot of kernel+dexts is too large size=%d bytes\n", outlen);
12562 flags = flags & ~STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL;
12563 } else {
12564 LOG("Compressed failure stackshot of only kernel is too large size=%d bytes\n", outlen);
12565 break;
12566 }
12567 }
12568 }
12569 }
12570 }
12571 }
12572
12573 if (failureStr[0]) {
12574 // append sleep-wake failure code
12575 char traceCode[80];
12576 snprintf(traceCode, sizeof(traceCode), "\nFailure code:: 0x%08x %08x\n",
12577 pmTracer->getTraceData(), pmTracer->getTracePhase());
12578 strlcat(failureStr, traceCode, sizeof(failureStr));
12579 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString, failureStr, (unsigned int) strnlen(failureStr, sizeof(failureStr))) == false) {
12580 DLOG("Failed to write SleepWake failure string\n");
12581 }
12582 }
12583
12584 // force NVRAM sync
12585 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey)) == false) {
12586 DLOG("Failed to force nvram sync\n");
12587 }
12588
12589skip_stackshot:
12590 if (wdogTrigger) {
12591 if (PEGetCoprocessorVersion() < kCoprocessorVersion2) {
12592 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
12593 // If current boot is due to this watch dog trigger restart in previous boot,
12594 // then don't trigger again until at least 1 successful sleep & wake.
12595 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
12596 LOG("Shutting down due to repeated Sleep/Wake failures\n");
12597 updateTasksSuspend(kTasksSuspendSuspended, kTasksSuspendNoChange);
12598 PEHaltRestart(kPEHaltCPU);
12599 return;
12600 }
12601 }
12602 if (gSwdPanic == 0) {
12603 LOG("Calling panic prevented by swd_panic boot-args. Calling restart");
12604 updateTasksSuspend(kTasksSuspendSuspended, kTasksSuspendNoChange);
12605 PEHaltRestart(kPERestartCPU);
12606 }
12607 }
12608 if (!concise && (PEWriteNVRAMProperty(kIOSleepWakeFailurePanic, swfPanic, (unsigned int) strlen(swfPanic)) == false)) {
12609 DLOG("Failed to write SleepWake failure panic key\n");
12610 }
12611#if defined(__x86_64__)
12612 if (thread) {
12613 panic_with_thread_context(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, thread, "%s", failureStr);
12614 } else
12615#endif /* defined(__x86_64__) */
12616 {
12617 panic_with_options(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, "%s", failureStr);
12618 }
12619 } else {
12620 gRootDomain->swd_lock = 0;
12621 return;
12622 }
12623}
12624
12625void
12626IOPMrootDomain::sleepWakeDebugMemAlloc()
12627{
12628 vm_size_t size = SWD_STACKSHOT_SIZE + SWD_COMPRESSED_BUFSIZE + SWD_ZLIB_BUFSIZE;
12629
12630 swd_hdr *hdr = NULL;
12631 void *bufPtr = NULL;
12632
12633 OSSharedPtr<IOBufferMemoryDescriptor> memDesc;
12634
12635
12636 if (kIOSleepWakeWdogOff & gIOKitDebug) {
12637 return;
12638 }
12639
12640 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12641 return;
12642 }
12643
12644 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
12645 kernel_task, kIODirectionIn | kIOMemoryMapperNone,
12646 size);
12647 if (memDesc == NULL) {
12648 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
12649 goto exit;
12650 }
12651
12652 bufPtr = memDesc->getBytesNoCopy();
12653
12654 // Carve out memory for zlib routines
12655 swd_zs_zmem = (vm_offset_t)bufPtr;
12656 bufPtr = (char *)bufPtr + SWD_ZLIB_BUFSIZE;
12657
12658 // Carve out memory for compressed stackshots
12659 swd_compressed_buffer = bufPtr;
12660 bufPtr = (char *)bufPtr + SWD_COMPRESSED_BUFSIZE;
12661
12662 // Remaining is used for holding stackshot
12663 hdr = (swd_hdr *)bufPtr;
12664 memset(hdr, 0, sizeof(swd_hdr));
12665
12666 hdr->signature = SWD_HDR_SIGNATURE;
12667 hdr->alloc_size = SWD_STACKSHOT_SIZE;
12668
12669 hdr->spindump_offset = sizeof(swd_hdr);
12670 swd_buffer = (void *)hdr;
12671 swd_memDesc = os::move(memDesc);
12672 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
12673
12674exit:
12675 gRootDomain->swd_lock = 0;
12676}
12677
12678void
12679IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc()
12680{
12681#if UNUSED
12682 vm_size_t size = SWD_SPINDUMP_SIZE;
12683
12684 swd_hdr *hdr = NULL;
12685
12686 OSSharedPtr<IOBufferMemoryDescriptor> memDesc;
12687
12688 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12689 return;
12690 }
12691
12692 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
12693 kernel_task, kIODirectionIn | kIOMemoryMapperNone,
12694 SWD_SPINDUMP_SIZE);
12695
12696 if (memDesc == NULL) {
12697 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
12698 goto exit;
12699 }
12700
12701
12702 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
12703 memset(hdr, 0, sizeof(swd_hdr));
12704
12705 hdr->signature = SWD_HDR_SIGNATURE;
12706 hdr->alloc_size = size;
12707
12708 hdr->spindump_offset = sizeof(swd_hdr);
12709 swd_spindump_buffer = (void *)hdr;
12710 swd_spindump_memDesc = os::move(memDesc);
12711
12712exit:
12713 gRootDomain->swd_lock = 0;
12714#endif /* UNUSED */
12715}
12716
12717void
12718IOPMrootDomain::sleepWakeDebugEnableWdog()
12719{
12720}
12721
12722bool
12723IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12724{
12725 return !systemBooting && !systemShutdown && !gWillShutdown;
12726}
12727
12728void
12729IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12730{
12731 swd_hdr *hdr = NULL;
12732 errno_t error = EIO;
12733
12734 if (swd_spindump_buffer && gSpinDumpBufferFull) {
12735 hdr = (swd_hdr *)swd_spindump_buffer;
12736
12737 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
12738 (char*)hdr + hdr->spindump_offset, hdr->spindump_size);
12739
12740 if (error) {
12741 return;
12742 }
12743
12744 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
12745 (char*)hdr + offsetof(swd_hdr, UUID),
12746 sizeof(swd_hdr) - offsetof(swd_hdr, UUID));
12747
12748 gSpinDumpBufferFull = false;
12749 }
12750}
12751
12752errno_t
12753IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
12754{
12755 struct vnode *vp = NULL;
12756 vfs_context_t ctx = vfs_context_create(vfs_context_current());
12757 kauth_cred_t cred = vfs_context_ucred(ctx);
12758 struct vnode_attr va;
12759 errno_t error = EIO;
12760
12761 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
12762 S_IRUSR | S_IRGRP | S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0) {
12763 LOG("Failed to open the file %s\n", name);
12764 swd_flags |= SWD_FILEOP_ERROR;
12765 goto exit;
12766 }
12767 VATTR_INIT(&va);
12768 VATTR_WANTED(&va, va_nlink);
12769 /* Don't dump to non-regular files or files with links. */
12770 if (vp->v_type != VREG ||
12771 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
12772 LOG("Bailing as this is not a regular file\n");
12773 swd_flags |= SWD_FILEOP_ERROR;
12774 goto exit;
12775 }
12776 VATTR_INIT(&va);
12777 VATTR_SET(&va, va_data_size, 0);
12778 vnode_setattr(vp, &va, ctx);
12779
12780
12781 if (buf != NULL) {
12782 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
12783 UIO_SYSSPACE, IO_NODELOCKED | IO_UNIT, cred, (int *) NULL, vfs_context_proc(ctx));
12784 if (error != 0) {
12785 LOG("Failed to save sleep wake log. err 0x%x\n", error);
12786 swd_flags |= SWD_FILEOP_ERROR;
12787 } else {
12788 DLOG("Saved %d bytes to file %s\n", len, name);
12789 }
12790 }
12791
12792exit:
12793 if (vp) {
12794 vnode_close(vp, FWRITE, ctx);
12795 }
12796 if (ctx) {
12797 vfs_context_rele(ctx);
12798 }
12799
12800 return error;
12801}
12802
12803#else /* defined(__i386__) || defined(__x86_64__) */
12804
12805void
12806IOPMrootDomain::sleepWakeDebugTrig(bool restart)
12807{
12808 if (restart) {
12809 if (gSwdPanic == 0) {
12810 return;
12811 }
12812 panic("Sleep/Wake hang detected");
12813 return;
12814 }
12815}
12816
12817void
12818IOPMrootDomain::takeStackshot(bool restart)
12819{
12820#pragma unused(restart)
12821}
12822
12823void
12824IOPMrootDomain::deleteStackshot()
12825{
12826}
12827
12828void
12829IOPMrootDomain::sleepWakeDebugMemAlloc()
12830{
12831}
12832
12833void
12834IOPMrootDomain::saveFailureData2File()
12835{
12836}
12837
12838void
12839IOPMrootDomain::sleepWakeDebugEnableWdog()
12840{
12841}
12842
12843bool
12844IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12845{
12846 return false;
12847}
12848
12849void
12850IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12851{
12852}
12853
12854errno_t
12855IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
12856{
12857 return 0;
12858}
12859
12860#endif /* defined(__i386__) || defined(__x86_64__) */
12861
12862