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"
94 const 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 kprintf(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
136 static IOWorkLoop * gIOPMWorkLoop = NULL;
137 #define ASSERT_GATED() \
138 do { \
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()
173 enum {
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.
194 enum {
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
211 enum {
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
228 extern "C" {
229 IOReturn OSKextSystemSleepOrWake( UInt32 );
230 }
231 extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
232 extern "C" addr64_t kvtophys(vm_offset_t va);
233 extern "C" boolean_t kdp_has_polled_corefile();
234
235 static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
236 static void notifySystemShutdown( IOService * root, uint32_t messageType );
237 static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
238 static void pmEventTimeStamp(uint64_t *recordTS);
239 static void powerButtonUpCallout( thread_call_param_t, thread_call_param_t );
240 static void powerButtonDownCallout( thread_call_param_t, thread_call_param_t );
241 static OSPtr<const OSSymbol> copyKextIdentifierWithAddress(vm_address_t address);
242
243 static int IOPMConvertSecondsToCalendar(clock_sec_t secs, IOPMCalendarStruct * dt);
244 static 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
249 static OSSharedPtr<const OSSymbol> sleepSupportedPEFunction;
250 static OSSharedPtr<const OSSymbol> sleepMessagePEFunction;
251 static OSSharedPtr<const OSSymbol> gIOPMWakeTypeUserKey;
252
253 static OSSharedPtr<const OSSymbol> gIOPMPSExternalConnectedKey;
254 static OSSharedPtr<const OSSymbol> gIOPMPSExternalChargeCapableKey;
255 static OSSharedPtr<const OSSymbol> gIOPMPSBatteryInstalledKey;
256 static OSSharedPtr<const OSSymbol> gIOPMPSIsChargingKey;
257 static OSSharedPtr<const OSSymbol> gIOPMPSAtWarnLevelKey;
258 static OSSharedPtr<const OSSymbol> gIOPMPSAtCriticalLevelKey;
259 static OSSharedPtr<const OSSymbol> gIOPMPSCurrentCapacityKey;
260 static OSSharedPtr<const OSSymbol> gIOPMPSMaxCapacityKey;
261 static OSSharedPtr<const OSSymbol> gIOPMPSDesignCapacityKey;
262 static OSSharedPtr<const OSSymbol> gIOPMPSTimeRemainingKey;
263 static OSSharedPtr<const OSSymbol> gIOPMPSAmperageKey;
264 static OSSharedPtr<const OSSymbol> gIOPMPSVoltageKey;
265 static OSSharedPtr<const OSSymbol> gIOPMPSCycleCountKey;
266 static OSSharedPtr<const OSSymbol> gIOPMPSMaxErrKey;
267 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterInfoKey;
268 static OSSharedPtr<const OSSymbol> gIOPMPSLocationKey;
269 static OSSharedPtr<const OSSymbol> gIOPMPSErrorConditionKey;
270 static OSSharedPtr<const OSSymbol> gIOPMPSManufacturerKey;
271 static OSSharedPtr<const OSSymbol> gIOPMPSManufactureDateKey;
272 static OSSharedPtr<const OSSymbol> gIOPMPSModelKey;
273 static OSSharedPtr<const OSSymbol> gIOPMPSSerialKey;
274 static OSSharedPtr<const OSSymbol> gIOPMPSLegacyBatteryInfoKey;
275 static OSSharedPtr<const OSSymbol> gIOPMPSBatteryHealthKey;
276 static OSSharedPtr<const OSSymbol> gIOPMPSHealthConfidenceKey;
277 static OSSharedPtr<const OSSymbol> gIOPMPSCapacityEstimatedKey;
278 static OSSharedPtr<const OSSymbol> gIOPMPSBatteryChargeStatusKey;
279 static OSSharedPtr<const OSSymbol> gIOPMPSBatteryTemperatureKey;
280 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsKey;
281 static OSSharedPtr<const OSSymbol> gIOPMPSChargerConfigurationKey;
282 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsIDKey;
283 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsWattsKey;
284 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsRevisionKey;
285 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSerialNumberKey;
286 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsFamilyKey;
287 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsAmperageKey;
288 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsDescriptionKey;
289 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsPMUConfigurationKey;
290 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSourceIDKey;
291 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsErrorFlagsKey;
292 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSharedSourceKey;
293 static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsCloakedKey;
294 static OSSharedPtr<const OSSymbol> gIOPMPSInvalidWakeSecondsKey;
295 static OSSharedPtr<const OSSymbol> gIOPMPSPostChargeWaitSecondsKey;
296 static 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
323 enum {
324 kWranglerPowerStateMin = 0,
325 kWranglerPowerStateSleep = 2,
326 kWranglerPowerStateDim = 3,
327 kWranglerPowerStateMax = 4
328 };
329
330 enum {
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
339 const char *
getPowerStateString(uint32_t state)340 getPowerStateString( 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 { 0, NULL }
351 };
352 return IOFindNameForValue(state, powerStates);
353 }
354
355 #define ON_POWER kIOPMPowerOn
356 #define RESTART_POWER kIOPMRestart
357 #define SLEEP_POWER kIOPMAuxPowerOn
358
359 static 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
414 const char *
getAggressivenessTypeString(uint32_t type)415 getAggressivenessTypeString( 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 { 0, NULL }
430 };
431 return IOFindNameForValue(type, aggressivenessTypes);
432 }
433
434 enum {
435 kAggressivesStateBusy = 0x01,
436 kAggressivesStateQuickSpindown = 0x02
437 };
438
439 struct AggressivesRecord {
440 uint32_t flags;
441 uint32_t type;
442 uint32_t value;
443 };
444
445 struct 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
455 enum {
456 kAggressivesRequestTypeService = 1,
457 kAggressivesRequestTypeRecord
458 };
459
460 enum {
461 kAggressivesOptionSynchronous = 0x00000001,
462 kAggressivesOptionQuickSpindownEnable = 0x00000100,
463 kAggressivesOptionQuickSpindownDisable = 0x00000200,
464 kAggressivesOptionQuickSpindownMask = 0x00000300
465 };
466
467 enum {
468 kAggressivesRecordFlagModified = 0x00000001,
469 kAggressivesRecordFlagMinValue = 0x00000002
470 };
471
472 // System Sleep Preventers
473
474 enum {
475 kPMUserDisabledAllSleep = 1,
476 kPMSystemRestartBootingInProgress,
477 kPMConfigPreventSystemSleep,
478 kPMChildPreventSystemSleep,
479 kPMCPUAssertion,
480 kPMPCIUnsupported,
481 };
482
483 const char *
getSystemSleepPreventerString(uint32_t preventer)484 getSystemSleepPreventerString( uint32_t preventer )
485 {
486 #define SYSTEM_SLEEP_PREVENTER(x) {(int) x, #x}
487 static const IONamedValue systemSleepPreventers[] = {
488 SYSTEM_SLEEP_PREVENTER( kPMUserDisabledAllSleep ),
489 SYSTEM_SLEEP_PREVENTER( kPMSystemRestartBootingInProgress ),
490 SYSTEM_SLEEP_PREVENTER( kPMConfigPreventSystemSleep ),
491 SYSTEM_SLEEP_PREVENTER( kPMChildPreventSystemSleep ),
492 SYSTEM_SLEEP_PREVENTER( kPMCPUAssertion ),
493 SYSTEM_SLEEP_PREVENTER( kPMPCIUnsupported ),
494 { 0, NULL }
495 };
496 return IOFindNameForValue(preventer, systemSleepPreventers);
497 }
498
499 // gDarkWakeFlags
500 enum {
501 kDarkWakeFlagPromotionNone = 0x0000,
502 kDarkWakeFlagPromotionEarly = 0x0001, // promote before gfx clamp
503 kDarkWakeFlagPromotionLate = 0x0002, // promote after gfx clamp
504 kDarkWakeFlagPromotionMask = 0x0003,
505 kDarkWakeFlagAlarmIsDark = 0x0100,
506 kDarkWakeFlagAudioNotSuppressed = 0x0200,
507 kDarkWakeFlagUserWakeWorkaround = 0x1000
508 };
509
510 // gClamshellFlags
511 // The workaround for 9157444 is enabled at compile time using the
512 // DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY macro and is not represented below.
513 enum {
514 kClamshell_WAR_38378787 = 0x00000001,
515 kClamshell_WAR_47715679 = 0x00000002,
516 kClamshell_WAR_58009435 = 0x00000004
517 };
518
519 // acceptSystemWakeEvents()
520 enum {
521 kAcceptSystemWakeEvents_Disable = 0,
522 kAcceptSystemWakeEvents_Enable,
523 kAcceptSystemWakeEvents_Reenable
524 };
525
526 static IOPMrootDomain * gRootDomain;
527 static IORootParent * gPatriarch;
528 static IONotifier * gSysPowerDownNotifier = NULL;
529 static UInt32 gSleepOrShutdownPending = 0;
530 static UInt32 gWillShutdown = 0;
531 static UInt32 gPagingOff = 0;
532 static UInt32 gSleepWakeUUIDIsSet = false;
533 static uint32_t gAggressivesState = 0;
534 uint32_t gHaltTimeMaxLog;
535 uint32_t gHaltTimeMaxPanic;
536 IOLock * gHaltLogLock;
537 static char * gHaltLog;
538 enum { kHaltLogSize = 2048 };
539 static size_t gHaltLogPos;
540 static uint64_t gHaltStartTime;
541 static char gKextNameBuf[64];
542 static size_t gKextNamePos;
543 static bool gKextNameEnd;
544
545 uuid_string_t bootsessionuuid_string;
546
547 #if defined(XNU_TARGET_OS_OSX)
548 #if DISPLAY_WRANGLER_PRESENT
549 static uint32_t gDarkWakeFlags = kDarkWakeFlagPromotionNone;
550 #elif defined(__arm64__)
551 // Enable temporary full wake promotion workarounds
552 static uint32_t gDarkWakeFlags = kDarkWakeFlagUserWakeWorkaround;
553 #else
554 // Enable full wake promotion workarounds
555 static uint32_t gDarkWakeFlags = kDarkWakeFlagUserWakeWorkaround;
556 #endif
557 #else /* !defined(XNU_TARGET_OS_OSX) */
558 static uint32_t gDarkWakeFlags = kDarkWakeFlagPromotionEarly;
559 #endif /* !defined(XNU_TARGET_OS_OSX) */
560
561 static uint32_t gNoIdleFlag = 0;
562 static uint32_t gSleepDisabledFlag = 0;
563 static uint32_t gSwdPanic = 1;
564 static uint32_t gSwdSleepTimeout = 0;
565 static uint32_t gSwdWakeTimeout = 0;
566 static uint32_t gSwdSleepWakeTimeout = 0;
567 static PMStatsStruct gPMStats;
568 #if DEVELOPMENT || DEBUG
569 static uint32_t swd_panic_phase;
570 #endif
571
572 static uint32_t gClamshellFlags = 0
573 #if defined(__i386__) || defined(__x86_64__)
574 | kClamshell_WAR_58009435
575 #endif
576 ;
577
578 #if HIBERNATION
579
580 #if defined(__arm64__)
581 static IOReturn
defaultSleepPolicyHandler(void * ctx,const IOPMSystemSleepPolicyVariables * vars,IOPMSystemSleepParameters * params)582 defaultSleepPolicyHandler(void *ctx, const IOPMSystemSleepPolicyVariables *vars, IOPMSystemSleepParameters *params)
583 {
584 uint32_t sleepType = kIOPMSleepTypeDeepIdle;
585
586 assert(vars->signature == kIOPMSystemSleepPolicySignature);
587 assert(vars->version == kIOPMSystemSleepPolicyVersion);
588
589 // Hibernation enabled and either user forced hibernate or low battery sleep
590 if ((vars->hibernateMode & kIOHibernateModeOn) &&
591 (((vars->hibernateMode & kIOHibernateModeSleep) == 0) ||
592 (vars->sleepFactors & kIOPMSleepFactorBatteryLow))) {
593 sleepType = kIOPMSleepTypeHibernate;
594 }
595 params->version = kIOPMSystemSleepParametersVersion;
596 params->sleepType = sleepType;
597 return kIOReturnSuccess;
598 }
599 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = &defaultSleepPolicyHandler;
600 #else /* defined(__arm64__) */
601 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = NULL;
602 #endif /* defined(__arm64__) */
603
604 static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = NULL;
605 static void * gSleepPolicyTarget;
606 #endif
607
608 struct timeval gIOLastSleepTime;
609 struct timeval gIOLastWakeTime;
610 AbsoluteTime gIOLastWakeAbsTime;
611 AbsoluteTime gIOLastSleepAbsTime;
612
613 struct timeval gIOLastUserSleepTime;
614
615 static char gWakeReasonString[128];
616 static char gBootReasonString[80];
617 static char gShutdownReasonString[80];
618 static bool gWakeReasonSysctlRegistered = false;
619 static bool gBootReasonSysctlRegistered = false;
620 static bool gShutdownReasonSysctlRegistered = false;
621 static bool gWillShutdownSysctlRegistered = false;
622 static AbsoluteTime gUserActiveAbsTime;
623 static AbsoluteTime gUserInactiveAbsTime;
624
625 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
626 static bool gSpinDumpBufferFull = false;
627 #endif
628
629 z_stream swd_zs;
630 vm_offset_t swd_zs_zmem;
631 //size_t swd_zs_zsize;
632 size_t swd_zs_zoffset;
633 #if defined(__i386__) || defined(__x86_64__)
634 IOCPU *currentShutdownTarget = NULL;
635 #endif
636
637 static unsigned int gPMHaltBusyCount;
638 static unsigned int gPMHaltIdleCount;
639 static int gPMHaltDepth;
640 static uint32_t gPMHaltMessageType;
641 static IOLock * gPMHaltLock = NULL;
642 static OSSharedPtr<OSArray> gPMHaltArray;
643 static OSSharedPtr<const OSSymbol> gPMHaltClientAcknowledgeKey;
644 static bool gPMQuiesced;
645
646 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
647 #define kCPUUnknownIndex 9999999
648 enum {
649 kInformAC = 0,
650 kInformLid = 1,
651 kInformableCount = 2
652 };
653
654 OSSharedPtr<const OSSymbol> gIOPMStatsResponseTimedOut;
655 OSSharedPtr<const OSSymbol> gIOPMStatsResponseCancel;
656 OSSharedPtr<const OSSymbol> gIOPMStatsResponseSlow;
657 OSSharedPtr<const OSSymbol> gIOPMStatsResponsePrompt;
658 OSSharedPtr<const OSSymbol> gIOPMStatsDriverPSChangeSlow;
659
660 #define kBadPMFeatureID 0
661
662 /*
663 * PMSettingHandle
664 * Opaque handle passed to clients of registerPMSettingController()
665 */
666 class PMSettingHandle : public OSObject
667 {
668 OSDeclareFinalStructors( PMSettingHandle );
669 friend class PMSettingObject;
670
671 private:
672 PMSettingObject *pmso;
673 void free(void) APPLE_KEXT_OVERRIDE;
674 };
675
676 /*
677 * PMSettingObject
678 * Internal object to track each PM setting controller
679 */
680 class PMSettingObject : public OSObject
681 {
682 OSDeclareFinalStructors( PMSettingObject );
683 friend class IOPMrootDomain;
684
685 private:
686 queue_head_t calloutQueue;
687 thread_t waitThread;
688 IOPMrootDomain *parent;
689 PMSettingHandle *pmsh;
690 IOPMSettingControllerCallback func;
691 OSObject *target;
692 uintptr_t refcon;
693 OSDataAllocation<uint32_t> publishedFeatureID;
694 uint32_t settingCount;
695 bool disabled;
696
697 void free(void) APPLE_KEXT_OVERRIDE;
698
699 public:
700 static PMSettingObject *pmSettingObject(
701 IOPMrootDomain *parent_arg,
702 IOPMSettingControllerCallback handler_arg,
703 OSObject *target_arg,
704 uintptr_t refcon_arg,
705 uint32_t supportedPowerSources,
706 const OSSymbol *settings[],
707 OSObject **handle_obj);
708
709 IOReturn dispatchPMSetting(const OSSymbol *type, OSObject *object);
710 void clientHandleFreed(void);
711 };
712
713 struct PMSettingCallEntry {
714 queue_chain_t link;
715 thread_t thread;
716 };
717
718 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
719 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
720 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
721 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
722
723 /*
724 * PMTraceWorker
725 * Internal helper object for logging trace points to RTC
726 * IOPMrootDomain and only IOPMrootDomain should instantiate
727 * exactly one of these.
728 */
729
730 typedef void (*IOPMTracePointHandler)(
731 void * target, uint32_t code, uint32_t data );
732
733 class PMTraceWorker : public OSObject
734 {
735 OSDeclareDefaultStructors(PMTraceWorker);
736 public:
737 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
738
739 static OSPtr<PMTraceWorker> tracer( IOPMrootDomain * );
740 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
741 void tracePoint(uint8_t phase);
742 void traceDetail(uint32_t detail);
743 void traceComponentWakeProgress(uint32_t component, uint32_t data);
744 int recordTopLevelPCIDevice(IOService *);
745 void RTC_TRACE(void);
746 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
747
748 IOPMTracePointHandler tracePointHandler;
749 void * tracePointTarget;
750 uint64_t getPMStatusCode();
751 uint8_t getTracePhase();
752 uint32_t getTraceData();
753 private:
754 IOPMrootDomain *owner;
755 IOLock *pmTraceWorkerLock;
756 OSSharedPtr<OSArray> pciDeviceBitMappings;
757
758 uint8_t addedToRegistry;
759 uint8_t tracePhase;
760 uint32_t traceData32;
761 uint8_t loginWindowData;
762 uint8_t coreDisplayData;
763 uint8_t coreGraphicsData;
764 };
765
766 /*
767 * this should be treated as POD, as it's byte-copied around
768 * and we cannot rely on d'tor firing at the right time
769 */
770 struct PMAssertStruct {
771 IOPMDriverAssertionID id;
772 IOPMDriverAssertionType assertionBits;
773 uint64_t createdTime;
774 uint64_t modifiedTime;
775 const OSSymbol *ownerString;
776 IOService *ownerService;
777 uint64_t registryEntryID;
778 IOPMDriverAssertionLevel level;
779 uint64_t assertCPUStartTime;
780 uint64_t assertCPUDuration;
781 };
782 OSDefineValueObjectForDependentType(PMAssertStruct)
783
784 /*
785 * PMAssertionsTracker
786 * Tracks kernel and user space PM assertions
787 */
788 class PMAssertionsTracker : public OSObject
789 {
790 OSDeclareFinalStructors(PMAssertionsTracker);
791 public:
792 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
793
794 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
795 IOReturn releaseAssertion(IOPMDriverAssertionID);
796 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
797 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
798
799 OSSharedPtr<OSArray> copyAssertionsArray(void);
800 IOPMDriverAssertionType getActivatedAssertions(void);
801 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
802
803 IOReturn handleCreateAssertion(OSValueObject<PMAssertStruct> *);
804 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
805 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
806 IOReturn handleSetUserAssertionLevels(void * arg0);
807 void publishProperties(void);
808 void reportCPUBitAccounting(void);
809
810 private:
811 uint32_t tabulateProducerCount;
812 uint32_t tabulateConsumerCount;
813
814 uint64_t maxAssertCPUDuration;
815 uint64_t maxAssertCPUEntryId;
816
817 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
818 void tabulate(void);
819 void updateCPUBitAccounting(PMAssertStruct * assertStruct);
820
821 IOPMrootDomain *owner;
822 OSSharedPtr<OSArray> assertionsArray;
823 IOLock *assertionsArrayLock;
824 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8)));/* aligned for atomic access */
825 IOPMDriverAssertionType assertionsKernel;
826 IOPMDriverAssertionType assertionsUser;
827 IOPMDriverAssertionType assertionsCombined;
828 };
829
830 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
831
832 /*
833 * PMHaltWorker
834 * Internal helper object for Shutdown/Restart notifications.
835 */
836 #define kPMHaltMaxWorkers 8
837 #define kPMHaltTimeoutMS 100
838
839 class PMHaltWorker : public OSObject
840 {
841 OSDeclareFinalStructors( PMHaltWorker );
842
843 public:
844 IOService * service;// service being worked on
845 AbsoluteTime startTime; // time when work started
846 int depth; // work on nubs at this PM-tree depth
847 int visits; // number of nodes visited (debug)
848 IOLock * lock;
849 bool timeout;// service took too long
850
851 static PMHaltWorker * worker( void );
852 static void main( void * arg, wait_result_t waitResult );
853 static void work( PMHaltWorker * me );
854 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
855 virtual void free( void ) APPLE_KEXT_OVERRIDE;
856 };
857
OSDefineMetaClassAndFinalStructors(PMHaltWorker,OSObject)858 OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
859
860
861 #define super IOService
862 OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
863
864 boolean_t
865 IOPMRootDomainGetWillShutdown(void)
866 {
867 return gWillShutdown != 0;
868 }
869
870 static void
IOPMRootDomainWillShutdown(void)871 IOPMRootDomainWillShutdown(void)
872 {
873 if (OSCompareAndSwap(0, 1, &gWillShutdown)) {
874 IOService::willShutdown();
875 for (int i = 0; i < 100; i++) {
876 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) {
877 break;
878 }
879 IOSleep( 100 );
880 }
881 }
882 }
883
884 extern "C" IONotifier *
registerSleepWakeInterest(IOServiceInterestHandler handler,void * self,void * ref)885 registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
886 {
887 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref ).detach();
888 }
889
890 extern "C" IONotifier *
registerPrioritySleepWakeInterest(IOServiceInterestHandler handler,void * self,void * ref)891 registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
892 {
893 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref ).detach();
894 }
895
896 extern "C" IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon)897 acknowledgeSleepWakeNotification(void * PMrefcon)
898 {
899 return gRootDomain->allowPowerChange((unsigned long)PMrefcon );
900 }
901
902 extern "C" IOReturn
vetoSleepWakeNotification(void * PMrefcon)903 vetoSleepWakeNotification(void * PMrefcon)
904 {
905 return gRootDomain->cancelPowerChange((unsigned long)PMrefcon );
906 }
907
908 extern "C" IOReturn
rootDomainRestart(void)909 rootDomainRestart( void )
910 {
911 return gRootDomain->restartSystem();
912 }
913
914 extern "C" IOReturn
rootDomainShutdown(void)915 rootDomainShutdown( void )
916 {
917 return gRootDomain->shutdownSystem();
918 }
919
920 static void
halt_log_putc(char c)921 halt_log_putc(char c)
922 {
923 if (gHaltLogPos >= (kHaltLogSize - 2)) {
924 return;
925 }
926 gHaltLog[gHaltLogPos++] = c;
927 }
928
929 extern "C" void
930 _doprnt_log(const char *fmt,
931 va_list *argp,
932 void (*putc)(char),
933 int radix);
934
935 static int
halt_log(const char * fmt,...)936 halt_log(const char *fmt, ...)
937 {
938 va_list listp;
939
940 va_start(listp, fmt);
941 _doprnt_log(fmt, &listp, &halt_log_putc, 16);
942 va_end(listp);
943
944 return 0;
945 }
946
947 extern "C" void
halt_log_enter(const char * what,const void * pc,uint64_t time)948 halt_log_enter(const char * what, const void * pc, uint64_t time)
949 {
950 uint64_t nano, millis;
951
952 if (!gHaltLog) {
953 return;
954 }
955 absolutetime_to_nanoseconds(time, &nano);
956 millis = nano / NSEC_PER_MSEC;
957 if (millis < 100) {
958 return;
959 }
960
961 IOLockLock(gHaltLogLock);
962 if (pc) {
963 halt_log("%s: %qd ms @ 0x%lx, ", what, millis, VM_KERNEL_UNSLIDE(pc));
964 OSKext::printKextsInBacktrace((vm_offset_t *) &pc, 1, &halt_log,
965 OSKext::kPrintKextsLock | OSKext::kPrintKextsUnslide | OSKext::kPrintKextsTerse);
966 } else {
967 halt_log("%s: %qd ms\n", what, millis);
968 }
969
970 gHaltLog[gHaltLogPos] = 0;
971 IOLockUnlock(gHaltLogLock);
972 }
973
974 extern uint32_t gFSState;
975
976 extern "C" void
IOSystemShutdownNotification(int howto,int stage)977 IOSystemShutdownNotification(int howto, int stage)
978 {
979 uint64_t startTime;
980
981 if (kIOSystemShutdownNotificationStageRootUnmount == stage) {
982 #if defined(XNU_TARGET_OS_OSX)
983 uint64_t nano, millis;
984 startTime = mach_absolute_time();
985 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC);
986 absolutetime_to_nanoseconds(mach_absolute_time() - startTime, &nano);
987 millis = nano / NSEC_PER_MSEC;
988 if (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog)) {
989 printf("waitQuiet() for unmount %qd ms\n", millis);
990 }
991 #endif /* defined(XNU_TARGET_OS_OSX) */
992 return;
993 }
994
995 if (kIOSystemShutdownNotificationTerminateDEXTs == stage) {
996 uint64_t nano, millis;
997 startTime = mach_absolute_time();
998 IOServicePH::systemHalt(howto);
999 absolutetime_to_nanoseconds(mach_absolute_time() - startTime, &nano);
1000 millis = nano / NSEC_PER_MSEC;
1001 if (true || (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog))) {
1002 printf("IOServicePH::systemHalt took %qd ms\n", millis);
1003 }
1004 return;
1005 }
1006
1007 assert(kIOSystemShutdownNotificationStageProcessExit == stage);
1008
1009 IOLockLock(gHaltLogLock);
1010 if (!gHaltLog) {
1011 gHaltLog = IONewData(char, (vm_size_t)kHaltLogSize);
1012 gHaltStartTime = mach_absolute_time();
1013 if (gHaltLog) {
1014 halt_log_putc('\n');
1015 }
1016 }
1017 IOLockUnlock(gHaltLogLock);
1018
1019 startTime = mach_absolute_time();
1020 IOPMRootDomainWillShutdown();
1021 halt_log_enter("IOPMRootDomainWillShutdown", NULL, mach_absolute_time() - startTime);
1022 #if HIBERNATION
1023 startTime = mach_absolute_time();
1024 IOHibernateSystemPostWake(true);
1025 halt_log_enter("IOHibernateSystemPostWake", NULL, mach_absolute_time() - startTime);
1026 #endif
1027 if (OSCompareAndSwap(0, 1, &gPagingOff)) {
1028 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
1029 }
1030 }
1031
1032 extern "C" int sync_internal(void);
1033
1034 /*
1035 * A device is always in the highest power state which satisfies its driver,
1036 * its policy-maker, and any power children it has, but within the constraint
1037 * of the power state provided by its parent. The driver expresses its desire by
1038 * calling changePowerStateTo(), the policy-maker expresses its desire by calling
1039 * changePowerStateToPriv(), and the children express their desires by calling
1040 * requestPowerDomainState().
1041 *
1042 * The Root Power Domain owns the policy for idle and demand sleep for the system.
1043 * It is a power-managed IOService just like the others in the system.
1044 * It implements several power states which map to what we see as Sleep and On.
1045 *
1046 * The sleep policy is as follows:
1047 * 1. Sleep is prevented if the case is open so that nobody will think the machine
1048 * is off and plug/unplug cards.
1049 * 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
1050 * 3. System cannot Sleep if some object in the tree is in a power state marked
1051 * kIOPMPreventSystemSleep.
1052 *
1053 * These three conditions are enforced using the "driver clamp" by calling
1054 * changePowerStateTo(). For example, if the case is opened,
1055 * changePowerStateTo(ON_STATE) is called to hold the system on regardless
1056 * of the desires of the children of the root or the state of the other clamp.
1057 *
1058 * Demand Sleep is initiated by pressing the front panel power button, closing
1059 * the clamshell, or selecting the menu item. In this case the root's parent
1060 * actually initiates the power state change so that the root domain has no
1061 * choice and does not give applications the opportunity to veto the change.
1062 *
1063 * Idle Sleep occurs if no objects in the tree are in a state marked
1064 * kIOPMPreventIdleSleep. When this is true, the root's children are not holding
1065 * the root on, so it sets the "policy-maker clamp" by calling
1066 * changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
1067 * This timer is set for the difference between the sleep timeout slider and the
1068 * display dim timeout slider. When the timer expires, it releases its clamp and
1069 * now nothing is holding it awake, so it falls asleep.
1070 *
1071 * Demand sleep is prevented when the system is booting. When preferences are
1072 * transmitted by the loginwindow at the end of boot, a flag is cleared,
1073 * and this allows subsequent Demand Sleep.
1074 */
1075
1076 //******************************************************************************
1077
1078 IOPMrootDomain *
construct(void)1079 IOPMrootDomain::construct( void )
1080 {
1081 IOPMrootDomain *root;
1082
1083 root = new IOPMrootDomain;
1084 if (root) {
1085 root->init();
1086 }
1087
1088 return root;
1089 }
1090
1091 //******************************************************************************
1092 // updateConsoleUsersCallout
1093 //
1094 //******************************************************************************
1095
1096 static void
updateConsoleUsersCallout(thread_call_param_t p0,thread_call_param_t p1)1097 updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
1098 {
1099 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
1100 rootDomain->updateConsoleUsers();
1101 }
1102
1103 void
updateConsoleUsers(void)1104 IOPMrootDomain::updateConsoleUsers(void)
1105 {
1106 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
1107 updateTasksSuspend(kTasksSuspendUnsuspended, kTasksSuspendNoChange);
1108 }
1109
1110 bool
updateTasksSuspend(int newTasksSuspended,int newAOTTasksSuspended)1111 IOPMrootDomain::updateTasksSuspend(int newTasksSuspended, int newAOTTasksSuspended)
1112 {
1113 bool newSuspend;
1114
1115 WAKEEVENT_LOCK();
1116 if (newTasksSuspended != kTasksSuspendNoChange) {
1117 tasksSuspended = (newTasksSuspended != kTasksSuspendUnsuspended);
1118 }
1119 if (newAOTTasksSuspended != kTasksSuspendNoChange) {
1120 _aotTasksSuspended = (newAOTTasksSuspended != kTasksSuspendUnsuspended);
1121 }
1122 newSuspend = (tasksSuspended || _aotTasksSuspended);
1123 if (newSuspend == tasksSuspendState) {
1124 WAKEEVENT_UNLOCK();
1125 return false;
1126 }
1127 tasksSuspendState = newSuspend;
1128 WAKEEVENT_UNLOCK();
1129 tasks_system_suspend(newSuspend);
1130 return true;
1131 }
1132
1133 //******************************************************************************
1134
1135 static void
disk_sync_callout(thread_call_param_t p0,thread_call_param_t p1)1136 disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
1137 {
1138 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
1139 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
1140 uint32_t powerState = rootDomain->getPowerState();
1141
1142 DLOG("disk_sync_callout ps=%u\n", powerState);
1143
1144 if (ON_STATE == powerState) {
1145 sync_internal();
1146
1147 #if HIBERNATION
1148 // Block sleep until trim issued on previous wake path is completed.
1149 IOHibernateSystemPostWake(true);
1150 #endif
1151 }
1152 #if HIBERNATION
1153 else {
1154 IOHibernateSystemPostWake(false);
1155
1156 rootDomain->sleepWakeDebugSaveSpinDumpFile();
1157 }
1158 #endif
1159
1160 rootDomain->allowPowerChange(notifyRef);
1161 DLOG("disk_sync_callout finish\n");
1162 }
1163
1164 //******************************************************************************
1165 static UInt32
computeDeltaTimeMS(const AbsoluteTime * startTime,AbsoluteTime * elapsedTime)1166 computeDeltaTimeMS( const AbsoluteTime * startTime, AbsoluteTime * elapsedTime )
1167 {
1168 AbsoluteTime endTime;
1169 UInt64 nano = 0;
1170
1171 clock_get_uptime(&endTime);
1172 if (CMP_ABSOLUTETIME(&endTime, startTime) <= 0) {
1173 *elapsedTime = 0;
1174 } else {
1175 SUB_ABSOLUTETIME(&endTime, startTime);
1176 absolutetime_to_nanoseconds(endTime, &nano);
1177 *elapsedTime = endTime;
1178 }
1179
1180 return (UInt32)(nano / NSEC_PER_MSEC);
1181 }
1182
1183 //******************************************************************************
1184
1185 static int
1186 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
1187 {
1188 struct timeval *swt = (struct timeval *)arg1;
1189 struct proc *p = req->p;
1190
1191 if (p == kernproc) {
1192 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
1193 } else if (proc_is64bit(p)) {
1194 struct user64_timeval t = {};
1195 t.tv_sec = swt->tv_sec;
1196 t.tv_usec = swt->tv_usec;
1197 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
1198 } else {
1199 struct user32_timeval t = {};
1200 t.tv_sec = (typeof(t.tv_sec))swt->tv_sec;
1201 t.tv_usec = swt->tv_usec;
1202 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
1203 }
1204 }
1205
1206 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
1207 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1208 &gIOLastUserSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
1209
1210 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
1211 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1212 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
1213
1214 SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
1215 SYSCTL_QUAD(_kern, OID_AUTO, sleep_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gIOLastSleepAbsTime, "");
1216 SYSCTL_QUAD(_kern, OID_AUTO, useractive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gUserActiveAbsTime, "");
1217 SYSCTL_QUAD(_kern, OID_AUTO, userinactive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gUserInactiveAbsTime, "");
1218
1219 static int
1220 sysctl_willshutdown SYSCTL_HANDLER_ARGS
1221 {
1222 int new_value, changed, error;
1223
1224 if (!gWillShutdownSysctlRegistered) {
1225 return ENOENT;
1226 }
1227
1228 error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
1229 if (changed) {
1230 if (!gWillShutdown && (new_value == 1)) {
1231 IOPMRootDomainWillShutdown();
1232 } else {
1233 error = EINVAL;
1234 }
1235 }
1236 return error;
1237 }
1238
1239 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
1240 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1241 NULL, 0, sysctl_willshutdown, "I", "");
1242
1243 #if defined(XNU_TARGET_OS_OSX)
1244
1245 static int
sysctl_progressmeterenable(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1246 sysctl_progressmeterenable
1247 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1248 {
1249 int error;
1250 int new_value, changed;
1251
1252 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
1253
1254 if (changed) {
1255 vc_enable_progressmeter(new_value);
1256 }
1257
1258 return error;
1259 }
1260
1261 static int
sysctl_progressmeter(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1262 sysctl_progressmeter
1263 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1264 {
1265 int error;
1266 int new_value, changed;
1267
1268 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
1269
1270 if (changed) {
1271 vc_set_progressmeter(new_value);
1272 }
1273
1274 return error;
1275 }
1276
1277 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
1278 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1279 NULL, 0, sysctl_progressmeterenable, "I", "");
1280
1281 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
1282 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1283 NULL, 0, sysctl_progressmeter, "I", "");
1284
1285 #endif /* defined(XNU_TARGET_OS_OSX) */
1286
1287
1288
1289 static int
sysctl_consoleoptions(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1290 sysctl_consoleoptions
1291 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1292 {
1293 int error, changed;
1294 uint32_t new_value;
1295
1296 error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
1297
1298 if (changed) {
1299 vc_user_options.options = new_value;
1300 }
1301
1302 return error;
1303 }
1304
1305 static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
1306 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1307 NULL, 0, sysctl_consoleoptions, "I", "");
1308
1309
1310 static int
1311 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1312 {
1313 return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
1314 }
1315
1316 static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
1317 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
1318 NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
1319
1320
1321 static int
1322 sysctl_wakereason SYSCTL_HANDLER_ARGS
1323 {
1324 char wr[sizeof(gWakeReasonString)];
1325
1326 wr[0] = '\0';
1327 if (gRootDomain && gWakeReasonSysctlRegistered) {
1328 gRootDomain->copyWakeReasonString(wr, sizeof(wr));
1329 } else {
1330 return ENOENT;
1331 }
1332
1333 return sysctl_io_string(req, wr, 0, 0, NULL);
1334 }
1335
1336 SYSCTL_PROC(_kern, OID_AUTO, wakereason,
1337 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1338 NULL, 0, sysctl_wakereason, "A", "wakereason");
1339
1340 static int
1341 sysctl_bootreason SYSCTL_HANDLER_ARGS
1342 {
1343 if (!os_atomic_load(&gBootReasonSysctlRegistered, acquire)) {
1344 return ENOENT;
1345 }
1346
1347 return sysctl_io_string(req, gBootReasonString, 0, 0, NULL);
1348 }
1349
1350 SYSCTL_PROC(_kern, OID_AUTO, bootreason,
1351 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1352 NULL, 0, sysctl_bootreason, "A", "");
1353
1354 static int
1355 sysctl_shutdownreason SYSCTL_HANDLER_ARGS
1356 {
1357 char sr[sizeof(gShutdownReasonString)];
1358
1359 sr[0] = '\0';
1360 if (gRootDomain && gShutdownReasonSysctlRegistered) {
1361 gRootDomain->copyShutdownReasonString(sr, sizeof(sr));
1362 } else {
1363 return ENOENT;
1364 }
1365
1366 return sysctl_io_string(req, sr, 0, 0, NULL);
1367 }
1368
1369 SYSCTL_PROC(_kern, OID_AUTO, shutdownreason,
1370 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1371 NULL, 0, sysctl_shutdownreason, "A", "shutdownreason");
1372
1373 static int
1374 sysctl_targettype SYSCTL_HANDLER_ARGS
1375 {
1376 IOService * root;
1377 OSSharedPtr<OSObject> obj;
1378 OSData * data;
1379 char tt[32];
1380
1381 tt[0] = '\0';
1382 root = IOService::getServiceRoot();
1383 if (root && (obj = root->copyProperty(gIODTTargetTypeKey))) {
1384 if ((data = OSDynamicCast(OSData, obj.get()))) {
1385 strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
1386 }
1387 }
1388 return sysctl_io_string(req, tt, 0, 0, NULL);
1389 }
1390
1391 SYSCTL_PROC(_hw, OID_AUTO, targettype,
1392 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1393 NULL, 0, sysctl_targettype, "A", "targettype");
1394
1395 static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
1396 static SYSCTL_INT(_debug, OID_AUTO, swd_sleep_timeout, CTLFLAG_RW, &gSwdSleepTimeout, 0, "");
1397 static SYSCTL_INT(_debug, OID_AUTO, swd_wake_timeout, CTLFLAG_RW, &gSwdWakeTimeout, 0, "");
1398 static SYSCTL_INT(_debug, OID_AUTO, swd_timeout, CTLFLAG_RW, &gSwdSleepWakeTimeout, 0, "");
1399 static SYSCTL_INT(_debug, OID_AUTO, swd_panic, CTLFLAG_RW, &gSwdPanic, 0, "");
1400 #if DEVELOPMENT || DEBUG
1401 static SYSCTL_INT(_debug, OID_AUTO, swd_panic_phase, CTLFLAG_RW, &swd_panic_phase, 0, "");
1402 #if defined(XNU_TARGET_OS_OSX)
1403 static SYSCTL_INT(_debug, OID_AUTO, clamshell, CTLFLAG_RW, &gClamshellFlags, 0, "");
1404 static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
1405 #endif /* defined(XNU_TARGET_OS_OSX) */
1406 #endif /* DEVELOPMENT || DEBUG */
1407
1408 //******************************************************************************
1409 // AOT
1410
1411 static int
1412 sysctl_aotmetrics SYSCTL_HANDLER_ARGS
1413 {
1414 if (NULL == gRootDomain) {
1415 return ENOENT;
1416 }
1417 if (NULL == gRootDomain->_aotMetrics) {
1418 IOPMAOTMetrics nullMetrics = {};
1419 return sysctl_io_opaque(req, &nullMetrics, sizeof(IOPMAOTMetrics), NULL);
1420 }
1421 return sysctl_io_opaque(req, gRootDomain->_aotMetrics, sizeof(IOPMAOTMetrics), NULL);
1422 }
1423
1424 static SYSCTL_PROC(_kern, OID_AUTO, aotmetrics,
1425 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
1426 NULL, 0, sysctl_aotmetrics, "S,IOPMAOTMetrics", "");
1427
1428
1429 static int
update_aotmode(uint32_t mode)1430 update_aotmode(uint32_t mode)
1431 {
1432 int result;
1433
1434 if (!gIOPMWorkLoop) {
1435 return ENOENT;
1436 }
1437 result = gIOPMWorkLoop->runActionBlock(^IOReturn (void) {
1438 unsigned int oldCount;
1439
1440 if (mode && !gRootDomain->_aotMetrics) {
1441 gRootDomain->_aotMetrics = IOMallocType(IOPMAOTMetrics);
1442 }
1443
1444 oldCount = gRootDomain->idleSleepPreventersCount();
1445 gRootDomain->_aotMode = (mode & kIOPMAOTModeMask);
1446 gRootDomain->updatePreventIdleSleepListInternal(NULL, false, oldCount);
1447 return 0;
1448 });
1449 return result;
1450 }
1451
1452 static int
sysctl_aotmodebits(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1453 sysctl_aotmodebits
1454 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1455 {
1456 int error, changed;
1457 uint32_t new_value;
1458
1459 if (NULL == gRootDomain) {
1460 return ENOENT;
1461 }
1462 error = sysctl_io_number(req, gRootDomain->_aotMode, sizeof(uint32_t), &new_value, &changed);
1463 if (changed && gIOPMWorkLoop) {
1464 error = update_aotmode(new_value);
1465 }
1466
1467 return error;
1468 }
1469
1470 static SYSCTL_PROC(_kern, OID_AUTO, aotmodebits,
1471 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1472 NULL, 0, sysctl_aotmodebits, "I", "");
1473
1474 static int
sysctl_aotmode(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1475 sysctl_aotmode
1476 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1477 {
1478 int error, changed;
1479 uint32_t new_value;
1480
1481 if (NULL == gRootDomain) {
1482 return ENOENT;
1483 }
1484 error = sysctl_io_number(req, gRootDomain->_aotMode, sizeof(uint32_t), &new_value, &changed);
1485 if (changed && gIOPMWorkLoop) {
1486 if (new_value) {
1487 new_value = kIOPMAOTModeDefault; // & ~kIOPMAOTModeRespectTimers;
1488 }
1489 error = update_aotmode(new_value);
1490 }
1491
1492 return error;
1493 }
1494
1495 static SYSCTL_PROC(_kern, OID_AUTO, aotmode,
1496 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
1497 NULL, 0, sysctl_aotmode, "I", "");
1498
1499 //******************************************************************************
1500
1501 static OSSharedPtr<const OSSymbol> gIOPMSettingAutoWakeCalendarKey;
1502 static OSSharedPtr<const OSSymbol> gIOPMSettingAutoWakeSecondsKey;
1503 static OSSharedPtr<const OSSymbol> gIOPMSettingAutoPowerCalendarKey;
1504 static OSSharedPtr<const OSSymbol> gIOPMSettingAutoPowerSecondsKey;
1505 static OSSharedPtr<const OSSymbol> gIOPMSettingDebugWakeRelativeKey;
1506 static OSSharedPtr<const OSSymbol> gIOPMSettingDebugPowerRelativeKey;
1507 static OSSharedPtr<const OSSymbol> gIOPMSettingMaintenanceWakeCalendarKey;
1508 static OSSharedPtr<const OSSymbol> gIOPMSettingSleepServiceWakeCalendarKey;
1509 static OSSharedPtr<const OSSymbol> gIOPMSettingSilentRunningKey;
1510 static OSSharedPtr<const OSSymbol> gIOPMUserTriggeredFullWakeKey;
1511 static OSSharedPtr<const OSSymbol> gIOPMUserIsActiveKey;
1512 static OSSharedPtr<const OSSymbol> gIOPMSettingLowLatencyAudioModeKey;
1513
1514 //******************************************************************************
1515 // start
1516 //
1517 //******************************************************************************
1518
1519 #define kRootDomainSettingsCount 20
1520 #define kRootDomainNoPublishSettingsCount 4
1521
1522 bool
start(IOService * nub)1523 IOPMrootDomain::start( IOService * nub )
1524 {
1525 OSSharedPtr<OSIterator> psIterator;
1526 OSSharedPtr<OSDictionary> tmpDict;
1527
1528 super::start(nub);
1529
1530 gRootDomain = this;
1531 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
1532 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
1533 gIOPMSettingAutoPowerCalendarKey = OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey);
1534 gIOPMSettingAutoPowerSecondsKey = OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey);
1535 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
1536 gIOPMSettingDebugPowerRelativeKey = OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey);
1537 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
1538 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
1539 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
1540 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
1541 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
1542 gIOPMSettingLowLatencyAudioModeKey = OSSymbol::withCStringNoCopy(kIOPMSettingLowLatencyAudioModeKey);
1543
1544 gIOPMStatsResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
1545 gIOPMStatsResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
1546 gIOPMStatsResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
1547 gIOPMStatsResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
1548 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
1549
1550 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
1551 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
1552 gIOPMWakeTypeUserKey = OSSymbol::withCStringNoCopy(kIOPMRootDomainWakeTypeUser);
1553
1554 OSSharedPtr<const OSSymbol> settingsArr[kRootDomainSettingsCount] =
1555 {
1556 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
1557 gIOPMSettingAutoWakeSecondsKey,
1558 gIOPMSettingAutoPowerSecondsKey,
1559 gIOPMSettingAutoWakeCalendarKey,
1560 gIOPMSettingAutoPowerCalendarKey,
1561 gIOPMSettingDebugWakeRelativeKey,
1562 gIOPMSettingDebugPowerRelativeKey,
1563 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
1564 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
1565 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
1566 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
1567 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
1568 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
1569 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
1570 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
1571 OSSymbol::withCString(kIOPMStateConsoleShutdown),
1572 OSSymbol::withCString(kIOPMSettingProModeControl),
1573 OSSymbol::withCString(kIOPMSettingProModeDefer),
1574 gIOPMSettingSilentRunningKey,
1575 gIOPMSettingLowLatencyAudioModeKey,
1576 };
1577
1578 OSSharedPtr<const OSSymbol> noPublishSettingsArr[kRootDomainNoPublishSettingsCount] =
1579 {
1580 OSSymbol::withCString(kIOPMSettingProModeControl),
1581 OSSymbol::withCString(kIOPMSettingProModeDefer),
1582 gIOPMSettingSilentRunningKey,
1583 gIOPMSettingLowLatencyAudioModeKey,
1584 };
1585
1586 #if DEVELOPMENT || DEBUG
1587 #if defined(XNU_TARGET_OS_OSX)
1588 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
1589 PE_parse_boot_argn("clamshell", &gClamshellFlags, sizeof(gClamshellFlags));
1590 #endif /* defined(XNU_TARGET_OS_OSX) */
1591 #endif /* DEVELOPMENT || DEBUG */
1592
1593 PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
1594 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout, sizeof(gSwdSleepTimeout));
1595 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout, sizeof(gSwdWakeTimeout));
1596 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout, sizeof(gSwdSleepWakeTimeout));
1597 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic, sizeof(gHaltTimeMaxPanic));
1598 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog, sizeof(gHaltTimeMaxLog));
1599
1600 // read noidle setting from Device Tree
1601 if (PE_get_default("no-idle", &gNoIdleFlag, sizeof(gNoIdleFlag))) {
1602 DLOG("Setting gNoIdleFlag to %u from device tree\n", gNoIdleFlag);
1603 }
1604
1605 queue_init(&aggressivesQueue);
1606 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
1607 aggressivesData = OSData::withCapacity(
1608 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
1609
1610 featuresDictLock = IOLockAlloc();
1611 settingsCtrlLock = IOLockAlloc();
1612 wakeEventLock = IOLockAlloc();
1613 gHaltLogLock = IOLockAlloc();
1614 setPMRootDomain(this);
1615
1616 extraSleepTimer = thread_call_allocate(
1617 idleSleepTimerExpired,
1618 (thread_call_param_t) this);
1619
1620 powerButtonDown = thread_call_allocate(
1621 powerButtonDownCallout,
1622 (thread_call_param_t) this);
1623
1624 powerButtonUp = thread_call_allocate(
1625 powerButtonUpCallout,
1626 (thread_call_param_t) this);
1627
1628 diskSyncCalloutEntry = thread_call_allocate(
1629 &disk_sync_callout,
1630 (thread_call_param_t) this);
1631 updateConsoleUsersEntry = thread_call_allocate(
1632 &updateConsoleUsersCallout,
1633 (thread_call_param_t) this);
1634
1635 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
1636 fullWakeThreadCall = thread_call_allocate_with_options(
1637 OSMemberFunctionCast(thread_call_func_t, this,
1638 &IOPMrootDomain::fullWakeDelayedWork),
1639 (thread_call_param_t) this, THREAD_CALL_PRIORITY_KERNEL,
1640 THREAD_CALL_OPTIONS_ONCE);
1641 #endif
1642
1643 setProperty(kIOSleepSupportedKey, true);
1644
1645 bzero(&gPMStats, sizeof(gPMStats));
1646
1647 pmTracer = PMTraceWorker::tracer(this);
1648
1649 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1650
1651 userDisabledAllSleep = false;
1652 systemBooting = true;
1653 idleSleepEnabled = false;
1654 sleepSlider = 0;
1655 idleSleepTimerPending = false;
1656 wrangler = NULL;
1657 clamshellClosed = false;
1658 clamshellExists = false;
1659 #if DISPLAY_WRANGLER_PRESENT
1660 clamshellDisabled = true;
1661 #else
1662 clamshellDisabled = false;
1663 #endif
1664 clamshellIgnoreClose = false;
1665 acAdaptorConnected = true;
1666 clamshellSleepDisableMask = 0;
1667 gWakeReasonString[0] = '\0';
1668
1669 // Initialize to user active.
1670 // Will never transition to user inactive w/o wrangler.
1671 fullWakeReason = kFullWakeReasonLocalUser;
1672 userIsActive = userWasActive = true;
1673 clock_get_uptime(&gUserActiveAbsTime);
1674 setProperty(gIOPMUserIsActiveKey.get(), kOSBooleanTrue);
1675
1676 // Set the default system capabilities at boot.
1677 _currentCapability = kIOPMSystemCapabilityCPU |
1678 kIOPMSystemCapabilityGraphics |
1679 kIOPMSystemCapabilityAudio |
1680 kIOPMSystemCapabilityNetwork;
1681
1682 _pendingCapability = _currentCapability;
1683 _desiredCapability = _currentCapability;
1684 _highestCapability = _currentCapability;
1685 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
1686
1687 queuedSleepWakeUUIDString = NULL;
1688 initializeBootSessionUUID();
1689 pmStatsAppResponses = OSArray::withCapacity(5);
1690 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
1691 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
1692 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
1693 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
1694 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
1695 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
1696 assertOnWakeSecs = -1;// Invalid value to prevent updates
1697
1698 pmStatsLock = IOLockAlloc();
1699 idxPMCPUClamshell = kCPUUnknownIndex;
1700 idxPMCPULimitedPower = kCPUUnknownIndex;
1701
1702 tmpDict = OSDictionary::withCapacity(1);
1703 setProperty(kRootDomainSupportedFeatures, tmpDict.get());
1704
1705 // Set a default "SystemPowerProfileOverrideDict" for platform
1706 // drivers without any overrides.
1707 if (!propertyExists(kIOPMSystemDefaultOverrideKey)) {
1708 tmpDict = OSDictionary::withCapacity(1);
1709 setProperty(kIOPMSystemDefaultOverrideKey, tmpDict.get());
1710 }
1711
1712 settingsCallbacks = OSDictionary::withCapacity(1);
1713
1714 // Create a list of the valid PM settings that we'll relay to
1715 // interested clients in setProperties() => setPMSetting()
1716 allowedPMSettings = OSArray::withObjects(
1717 (const OSObject **)settingsArr,
1718 kRootDomainSettingsCount,
1719 0);
1720
1721 // List of PM settings that should not automatically publish itself
1722 // as a feature when registered by a listener.
1723 noPublishPMSettings = OSArray::withObjects(
1724 (const OSObject **)noPublishSettingsArr,
1725 kRootDomainNoPublishSettingsCount,
1726 0);
1727
1728 fPMSettingsDict = OSDictionary::withCapacity(5);
1729 preventIdleSleepList = OSSet::withCapacity(8);
1730 preventSystemSleepList = OSSet::withCapacity(2);
1731
1732 PMinit(); // creates gIOPMWorkLoop
1733 gIOPMWorkLoop = getIOPMWorkloop();
1734
1735 // Create IOPMPowerStateQueue used to queue external power
1736 // events, and to handle those events on the PM work loop.
1737 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
1738 this, OSMemberFunctionCast(IOEventSource::Action, this,
1739 &IOPMrootDomain::dispatchPowerEvent));
1740 gIOPMWorkLoop->addEventSource(pmPowerStateQueue);
1741
1742 _aotMode = 0;
1743 _aotTimerES = IOTimerEventSource::timerEventSource(this,
1744 OSMemberFunctionCast(IOTimerEventSource::Action,
1745 this, &IOPMrootDomain::aotEvaluate));
1746 gIOPMWorkLoop->addEventSource(_aotTimerES.get());
1747
1748 // Avoid publishing service early so gIOPMWorkLoop is
1749 // guaranteed to be initialized by rootDomain.
1750 publishPMRootDomain();
1751
1752 // create our power parent
1753 gPatriarch = new IORootParent;
1754 gPatriarch->init();
1755 gPatriarch->attach(this);
1756 gPatriarch->start(this);
1757 gPatriarch->addPowerChild(this);
1758
1759 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
1760 changePowerStateWithTagToPriv(ON_STATE, kCPSReasonInit);
1761
1762 // install power change handler
1763 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, NULL);
1764
1765 #if DISPLAY_WRANGLER_PRESENT
1766 wranglerIdleSettings = OSDictionary::withCapacity(1);
1767 OSSharedPtr<OSNumber> wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
1768
1769 if (wranglerIdleSettings && wranglerIdlePeriod) {
1770 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
1771 wranglerIdlePeriod.get());
1772 }
1773
1774 #endif /* DISPLAY_WRANGLER_PRESENT */
1775
1776 lowLatencyAudioNotifierDict = OSDictionary::withCapacity(2);
1777 lowLatencyAudioNotifyStateSym = OSSymbol::withCString("LowLatencyAudioNotifyState");
1778 lowLatencyAudioNotifyTimestampSym = OSSymbol::withCString("LowLatencyAudioNotifyTimestamp");
1779 lowLatencyAudioNotifyStateVal = OSNumber::withNumber(0ull, 32);
1780 lowLatencyAudioNotifyTimestampVal = OSNumber::withNumber(0ull, 64);
1781
1782 if (lowLatencyAudioNotifierDict && lowLatencyAudioNotifyStateSym && lowLatencyAudioNotifyTimestampSym &&
1783 lowLatencyAudioNotifyStateVal && lowLatencyAudioNotifyTimestampVal) {
1784 lowLatencyAudioNotifierDict->setObject(lowLatencyAudioNotifyStateSym.get(), lowLatencyAudioNotifyStateVal.get());
1785 lowLatencyAudioNotifierDict->setObject(lowLatencyAudioNotifyTimestampSym.get(), lowLatencyAudioNotifyTimestampVal.get());
1786 }
1787
1788 OSSharedPtr<const OSSymbol> ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
1789 setProperty(gIOUserClientClassKey, const_cast<OSObject *>(static_cast<const OSObject *>(ucClassName.get())));
1790
1791 // IOBacklightDisplay can take a long time to load at boot, or it may
1792 // not load at all if you're booting with clamshell closed. We publish
1793 // 'DisplayDims' here redundantly to get it published early and at all.
1794 OSSharedPtr<OSDictionary> matching;
1795 matching = serviceMatching("IOPMPowerSource");
1796 psIterator = getMatchingServices(matching.get());
1797
1798 if (psIterator && psIterator->getNextObject()) {
1799 // There's at least one battery on the system, so we publish
1800 // 'DisplayDims' support for the LCD.
1801 publishFeature("DisplayDims");
1802 }
1803
1804 // read swd_panic boot-arg
1805 PE_parse_boot_argn("swd_panic", &gSwdPanic, sizeof(gSwdPanic));
1806 gWillShutdownSysctlRegistered = true;
1807
1808 #if HIBERNATION
1809 #if defined(__arm64__)
1810 #endif /* defined(__arm64__) */
1811 IOHibernateSystemInit(this);
1812 #endif
1813
1814 registerService(); // let clients find us
1815
1816 return true;
1817 }
1818
1819 //******************************************************************************
1820 // setProperties
1821 //
1822 // Receive a setProperty call
1823 // The "System Boot" property means the system is completely booted.
1824 //******************************************************************************
1825
1826 IOReturn
setProperties(OSObject * props_obj)1827 IOPMrootDomain::setProperties( OSObject * props_obj )
1828 {
1829 IOReturn return_value = kIOReturnSuccess;
1830 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1831 OSBoolean *b = NULL;
1832 OSNumber *n = NULL;
1833 const OSSymbol *key = NULL;
1834 OSObject *obj = NULL;
1835 OSSharedPtr<OSCollectionIterator> iter;
1836
1837 if (!dict) {
1838 return kIOReturnBadArgument;
1839 }
1840
1841 bool clientEntitled = false;
1842 {
1843 OSSharedPtr<OSObject> obj = IOUserClient::copyClientEntitlement(current_task(), kRootDomainEntitlementSetProperty);
1844 clientEntitled = (obj == kOSBooleanTrue);
1845 }
1846
1847 if (!clientEntitled) {
1848 const char * errorSuffix = NULL;
1849
1850 // IOPMSchedulePowerEvent() clients may not be entitled, but must be root.
1851 // That API can set 6 possible keys that are checked below.
1852 if ((dict->getCount() == 1) &&
1853 (dict->getObject(gIOPMSettingAutoWakeSecondsKey.get()) ||
1854 dict->getObject(gIOPMSettingAutoPowerSecondsKey.get()) ||
1855 dict->getObject(gIOPMSettingAutoWakeCalendarKey.get()) ||
1856 dict->getObject(gIOPMSettingAutoPowerCalendarKey.get()) ||
1857 dict->getObject(gIOPMSettingDebugWakeRelativeKey.get()) ||
1858 dict->getObject(gIOPMSettingDebugPowerRelativeKey.get()))) {
1859 return_value = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
1860 if (return_value != kIOReturnSuccess) {
1861 errorSuffix = "privileged";
1862 }
1863 } else {
1864 return_value = kIOReturnNotPermitted;
1865 errorSuffix = "entitled";
1866 }
1867
1868 if (return_value != kIOReturnSuccess) {
1869 OSSharedPtr<OSString> procName(IOCopyLogNameForPID(proc_selfpid()), OSNoRetain);
1870 DLOG("%s failed, process %s is not %s\n", __func__,
1871 procName ? procName->getCStringNoCopy() : "", errorSuffix);
1872 return return_value;
1873 }
1874 }
1875
1876 OSSharedPtr<const OSSymbol> publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1877 OSSharedPtr<const OSSymbol> boot_complete_string = OSSymbol::withCString("System Boot Complete");
1878 OSSharedPtr<const OSSymbol> sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1879 OSSharedPtr<const OSSymbol> stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1880 OSSharedPtr<const OSSymbol> battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1881 OSSharedPtr<const OSSymbol> idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1882 OSSharedPtr<const OSSymbol> idle_milliseconds_string = OSSymbol::withCString("System Idle Milliseconds");
1883 OSSharedPtr<const OSSymbol> sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1884 OSSharedPtr<const OSSymbol> ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1885 OSSharedPtr<const OSSymbol> loginwindow_progress_string = OSSymbol::withCString(kIOPMLoginWindowProgressKey);
1886 OSSharedPtr<const OSSymbol> coredisplay_progress_string = OSSymbol::withCString(kIOPMCoreDisplayProgressKey);
1887 OSSharedPtr<const OSSymbol> coregraphics_progress_string = OSSymbol::withCString(kIOPMCoreGraphicsProgressKey);
1888 #if DEBUG || DEVELOPMENT
1889 OSSharedPtr<const OSSymbol> clamshell_close_string = OSSymbol::withCString("IOPMTestClamshellClose");
1890 OSSharedPtr<const OSSymbol> clamshell_open_string = OSSymbol::withCString("IOPMTestClamshellOpen");
1891 OSSharedPtr<const OSSymbol> ac_detach_string = OSSymbol::withCString("IOPMTestACDetach");
1892 OSSharedPtr<const OSSymbol> ac_attach_string = OSSymbol::withCString("IOPMTestACAttach");
1893 OSSharedPtr<const OSSymbol> desktopmode_set_string = OSSymbol::withCString("IOPMTestDesktopModeSet");
1894 OSSharedPtr<const OSSymbol> desktopmode_remove_string = OSSymbol::withCString("IOPMTestDesktopModeRemove");
1895 #endif
1896
1897 #if HIBERNATION
1898 OSSharedPtr<const OSSymbol> hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1899 OSSharedPtr<const OSSymbol> hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1900 OSSharedPtr<const OSSymbol> hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1901 OSSharedPtr<const OSSymbol> hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
1902 OSSharedPtr<const OSSymbol> hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1903 OSSharedPtr<const OSSymbol> hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
1904 #endif
1905
1906 iter = OSCollectionIterator::withCollection(dict);
1907 if (!iter) {
1908 return_value = kIOReturnNoMemory;
1909 goto exit;
1910 }
1911
1912 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1913 (obj = dict->getObject(key))) {
1914 if (key->isEqualTo(publish_simulated_battery_string.get())) {
1915 if (OSDynamicCast(OSBoolean, obj)) {
1916 publishResource(key, kOSBooleanTrue);
1917 }
1918 } else if (key->isEqualTo(idle_seconds_string.get())) {
1919 if ((n = OSDynamicCast(OSNumber, obj))) {
1920 setProperty(key, n);
1921 idleMilliSeconds = n->unsigned32BitValue() * 1000;
1922 }
1923 } else if (key->isEqualTo(idle_milliseconds_string.get())) {
1924 if ((n = OSDynamicCast(OSNumber, obj))) {
1925 setProperty(key, n);
1926 idleMilliSeconds = n->unsigned32BitValue();
1927 }
1928 } else if (key->isEqualTo(boot_complete_string.get())) {
1929 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
1930 } else if (key->isEqualTo(sys_shutdown_string.get())) {
1931 if ((b = OSDynamicCast(OSBoolean, obj))) {
1932 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1933 }
1934 } else if (key->isEqualTo(battery_warning_disabled_string.get())) {
1935 setProperty(key, obj);
1936 }
1937 #if HIBERNATION
1938 else if (key->isEqualTo(hibernatemode_string.get()) ||
1939 key->isEqualTo(hibernatefilemin_string.get()) ||
1940 key->isEqualTo(hibernatefilemax_string.get()) ||
1941 key->isEqualTo(hibernatefreeratio_string.get()) ||
1942 key->isEqualTo(hibernatefreetime_string.get())) {
1943 if ((n = OSDynamicCast(OSNumber, obj))) {
1944 setProperty(key, n);
1945 }
1946 } else if (key->isEqualTo(hibernatefile_string.get())) {
1947 OSString * str = OSDynamicCast(OSString, obj);
1948 if (str) {
1949 setProperty(key, str);
1950 }
1951 }
1952 #endif
1953 else if (key->isEqualTo(sleepdisabled_string.get())) {
1954 if ((b = OSDynamicCast(OSBoolean, obj))) {
1955 setProperty(key, b);
1956 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1957 }
1958 } else if (key->isEqualTo(ondeck_sleepwake_uuid_string.get())) {
1959 obj->retain();
1960 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
1961 } else if (key->isEqualTo(loginwindow_progress_string.get())) {
1962 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1963 uint32_t data = n->unsigned32BitValue();
1964 pmTracer->traceComponentWakeProgress(kIOPMLoginWindowProgress, data);
1965 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMLoginWindowProgress, data);
1966 }
1967 } else if (key->isEqualTo(coredisplay_progress_string.get())) {
1968 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1969 uint32_t data = n->unsigned32BitValue();
1970 pmTracer->traceComponentWakeProgress(kIOPMCoreDisplayProgress, data);
1971 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreDisplayProgress, data);
1972 }
1973 } else if (key->isEqualTo(coregraphics_progress_string.get())) {
1974 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1975 uint32_t data = n->unsigned32BitValue();
1976 pmTracer->traceComponentWakeProgress(kIOPMCoreGraphicsProgress, data);
1977 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreGraphicsProgress, data);
1978 }
1979 } else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1980 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1981 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
1982 key->isEqualTo(stall_halt_string.get())) {
1983 if ((b = OSDynamicCast(OSBoolean, obj))) {
1984 setProperty(key, b);
1985 }
1986 } else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
1987 key->isEqualTo(kIOPMDeepSleepTimerKey) ||
1988 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1989 key->isEqualTo(kIOPMAutoPowerOffTimerKey)) {
1990 if ((n = OSDynamicCast(OSNumber, obj))) {
1991 setProperty(key, n);
1992 }
1993 } else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey)) {
1994 if (kOSBooleanTrue == obj) {
1995 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarmMask);
1996 } else {
1997 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarmMask);
1998 }
1999 DLOG("_userScheduledAlarmMask 0x%x\n", (uint32_t) _userScheduledAlarmMask);
2000 }
2001 #if DEBUG || DEVELOPMENT
2002 else if (key->isEqualTo(clamshell_close_string.get())) {
2003 DLOG("SetProperties: setting clamshell close\n");
2004 UInt32 msg = kIOPMClamshellClosed;
2005 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2006 } else if (key->isEqualTo(clamshell_open_string.get())) {
2007 DLOG("SetProperties: setting clamshell open\n");
2008 UInt32 msg = kIOPMClamshellOpened;
2009 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2010 } else if (key->isEqualTo(ac_detach_string.get())) {
2011 DLOG("SetProperties: setting ac detach\n");
2012 UInt32 msg = kIOPMSetACAdaptorConnected;
2013 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2014 } else if (key->isEqualTo(ac_attach_string.get())) {
2015 DLOG("SetProperties: setting ac attach\n");
2016 UInt32 msg = kIOPMSetACAdaptorConnected | kIOPMSetValue;
2017 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2018 } else if (key->isEqualTo(desktopmode_set_string.get())) {
2019 DLOG("SetProperties: setting desktopmode");
2020 UInt32 msg = kIOPMSetDesktopMode | kIOPMSetValue;
2021 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2022 } else if (key->isEqualTo(desktopmode_remove_string.get())) {
2023 DLOG("SetProperties: removing desktopmode\n");
2024 UInt32 msg = kIOPMSetDesktopMode;
2025 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
2026 }
2027 #endif
2028 // Relay our allowed PM settings onto our registered PM clients
2029 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1)) {
2030 return_value = setPMSetting(key, obj);
2031 if (kIOReturnSuccess != return_value) {
2032 break;
2033 }
2034 } else {
2035 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
2036 }
2037 }
2038
2039 exit:
2040 return return_value;
2041 }
2042
2043 // MARK: -
2044 // MARK: Aggressiveness
2045
2046 //******************************************************************************
2047 // setAggressiveness
2048 //
2049 // Override IOService::setAggressiveness()
2050 //******************************************************************************
2051
2052 IOReturn
setAggressiveness(unsigned long type,unsigned long value)2053 IOPMrootDomain::setAggressiveness(
2054 unsigned long type,
2055 unsigned long value )
2056 {
2057 return setAggressiveness( type, value, 0 );
2058 }
2059
2060 /*
2061 * Private setAggressiveness() with an internal options argument.
2062 */
2063 IOReturn
setAggressiveness(unsigned long type,unsigned long value,IOOptionBits options)2064 IOPMrootDomain::setAggressiveness(
2065 unsigned long type,
2066 unsigned long value,
2067 IOOptionBits options )
2068 {
2069 AggressivesRequest * entry;
2070 AggressivesRequest * request;
2071 bool found = false;
2072
2073 if ((type > UINT_MAX) || (value > UINT_MAX)) {
2074 return kIOReturnBadArgument;
2075 }
2076
2077 if (type == kPMMinutesToDim || type == kPMMinutesToSleep) {
2078 DLOG("setAggressiveness(%x) %s = %u\n",
2079 (uint32_t) options, getAggressivenessTypeString((uint32_t) type), (uint32_t) value);
2080 } else {
2081 DEBUG_LOG("setAggressiveness(%x) %s = %u\n",
2082 (uint32_t) options, getAggressivenessTypeString((uint32_t) type), (uint32_t) value);
2083 }
2084
2085 request = IOMallocType(AggressivesRequest);
2086 request->options = options;
2087 request->dataType = kAggressivesRequestTypeRecord;
2088 request->data.record.type = (uint32_t) type;
2089 request->data.record.value = (uint32_t) value;
2090
2091 AGGRESSIVES_LOCK();
2092
2093 // Update disk quick spindown flag used by getAggressiveness().
2094 // Never merge requests with quick spindown flags set.
2095
2096 if (options & kAggressivesOptionQuickSpindownEnable) {
2097 gAggressivesState |= kAggressivesStateQuickSpindown;
2098 } else if (options & kAggressivesOptionQuickSpindownDisable) {
2099 gAggressivesState &= ~kAggressivesStateQuickSpindown;
2100 } else {
2101 // Coalesce requests with identical aggressives types.
2102 // Deal with callers that calls us too "aggressively".
2103
2104 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
2105 {
2106 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
2107 (entry->data.record.type == type) &&
2108 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) {
2109 entry->data.record.value = (uint32_t) value;
2110 found = true;
2111 break;
2112 }
2113 }
2114 }
2115
2116 if (!found) {
2117 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
2118 }
2119
2120 AGGRESSIVES_UNLOCK();
2121
2122 if (found) {
2123 IOFreeType(request, AggressivesRequest);
2124 }
2125
2126 if (options & kAggressivesOptionSynchronous) {
2127 handleAggressivesRequests(); // not truly synchronous
2128 } else {
2129 thread_call_enter(aggressivesThreadCall);
2130 }
2131
2132 return kIOReturnSuccess;
2133 }
2134
2135 //******************************************************************************
2136 // getAggressiveness
2137 //
2138 // Override IOService::setAggressiveness()
2139 // Fetch the aggressiveness factor with the given type.
2140 //******************************************************************************
2141
2142 IOReturn
getAggressiveness(unsigned long type,unsigned long * outLevel)2143 IOPMrootDomain::getAggressiveness(
2144 unsigned long type,
2145 unsigned long * outLevel )
2146 {
2147 uint32_t value = 0;
2148 int source = 0;
2149
2150 if (!outLevel || (type > UINT_MAX)) {
2151 return kIOReturnBadArgument;
2152 }
2153
2154 AGGRESSIVES_LOCK();
2155
2156 // Disk quick spindown in effect, report value = 1
2157
2158 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
2159 (type == kPMMinutesToSpinDown)) {
2160 value = kAggressivesMinValue;
2161 source = 1;
2162 }
2163
2164 // Consult the pending request queue.
2165
2166 if (!source) {
2167 AggressivesRequest * entry;
2168
2169 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
2170 {
2171 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
2172 (entry->data.record.type == type) &&
2173 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) {
2174 value = entry->data.record.value;
2175 source = 2;
2176 break;
2177 }
2178 }
2179 }
2180
2181 // Consult the backend records.
2182
2183 if (!source && aggressivesData) {
2184 AggressivesRecord * record;
2185 int i, count;
2186
2187 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2188 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2189
2190 for (i = 0; i < count; i++, record++) {
2191 if (record->type == type) {
2192 value = record->value;
2193 source = 3;
2194 break;
2195 }
2196 }
2197 }
2198
2199 AGGRESSIVES_UNLOCK();
2200
2201 if (source) {
2202 *outLevel = (unsigned long) value;
2203 return kIOReturnSuccess;
2204 } else {
2205 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
2206 *outLevel = 0; // default return = 0, driver may not check for error
2207 return kIOReturnInvalid;
2208 }
2209 }
2210
2211 //******************************************************************************
2212 // joinAggressiveness
2213 //
2214 // Request from IOService to join future aggressiveness broadcasts.
2215 //******************************************************************************
2216
2217 IOReturn
joinAggressiveness(IOService * service)2218 IOPMrootDomain::joinAggressiveness(
2219 IOService * service )
2220 {
2221 AggressivesRequest * request;
2222
2223 if (!service || (service == this)) {
2224 return kIOReturnBadArgument;
2225 }
2226
2227 DEBUG_LOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
2228
2229 request = IOMallocType(AggressivesRequest);
2230 request->dataType = kAggressivesRequestTypeService;
2231 request->data.service.reset(service, OSRetain); // released by synchronizeAggressives()
2232
2233 AGGRESSIVES_LOCK();
2234 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
2235 AGGRESSIVES_UNLOCK();
2236
2237 thread_call_enter(aggressivesThreadCall);
2238
2239 return kIOReturnSuccess;
2240 }
2241
2242 //******************************************************************************
2243 // handleAggressivesRequests
2244 //
2245 // Backend thread processes all incoming aggressiveness requests in the queue.
2246 //******************************************************************************
2247
2248 static void
handleAggressivesFunction(thread_call_param_t param1,thread_call_param_t param2)2249 handleAggressivesFunction(
2250 thread_call_param_t param1,
2251 thread_call_param_t param2 )
2252 {
2253 if (param1) {
2254 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
2255 }
2256 }
2257
2258 void
handleAggressivesRequests(void)2259 IOPMrootDomain::handleAggressivesRequests( void )
2260 {
2261 AggressivesRecord * start;
2262 AggressivesRecord * record;
2263 AggressivesRequest * request;
2264 queue_head_t joinedQueue;
2265 int i, count;
2266 bool broadcast;
2267 bool found;
2268 bool pingSelf = false;
2269
2270 AGGRESSIVES_LOCK();
2271
2272 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
2273 queue_empty(&aggressivesQueue)) {
2274 goto unlock_done;
2275 }
2276
2277 gAggressivesState |= kAggressivesStateBusy;
2278 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2279 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2280
2281 do{
2282 broadcast = false;
2283 queue_init(&joinedQueue);
2284
2285 do{
2286 // Remove request from the incoming queue in FIFO order.
2287 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
2288 switch (request->dataType) {
2289 case kAggressivesRequestTypeRecord:
2290 // Update existing record if found.
2291 found = false;
2292 for (i = 0, record = start; i < count; i++, record++) {
2293 if (record->type == request->data.record.type) {
2294 found = true;
2295
2296 if (request->options & kAggressivesOptionQuickSpindownEnable) {
2297 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) {
2298 broadcast = true;
2299 record->flags |= (kAggressivesRecordFlagMinValue |
2300 kAggressivesRecordFlagModified);
2301 DLOG("disk spindown accelerated, was %u min\n",
2302 record->value);
2303 }
2304 } else if (request->options & kAggressivesOptionQuickSpindownDisable) {
2305 if (record->flags & kAggressivesRecordFlagMinValue) {
2306 broadcast = true;
2307 record->flags |= kAggressivesRecordFlagModified;
2308 record->flags &= ~kAggressivesRecordFlagMinValue;
2309 DLOG("disk spindown restored to %u min\n",
2310 record->value);
2311 }
2312 } else if (record->value != request->data.record.value) {
2313 record->value = request->data.record.value;
2314 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) {
2315 broadcast = true;
2316 record->flags |= kAggressivesRecordFlagModified;
2317 }
2318 }
2319 break;
2320 }
2321 }
2322
2323 // No matching record, append a new record.
2324 if (!found &&
2325 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0)) {
2326 AggressivesRecord newRecord;
2327
2328 newRecord.flags = kAggressivesRecordFlagModified;
2329 newRecord.type = request->data.record.type;
2330 newRecord.value = request->data.record.value;
2331 if (request->options & kAggressivesOptionQuickSpindownEnable) {
2332 newRecord.flags |= kAggressivesRecordFlagMinValue;
2333 DLOG("disk spindown accelerated\n");
2334 }
2335
2336 aggressivesData->appendValue(newRecord);
2337
2338 // OSData may have switched to another (larger) buffer.
2339 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2340 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2341 broadcast = true;
2342 }
2343
2344 // Finished processing the request, release it.
2345 IOFreeType(request, AggressivesRequest);
2346 break;
2347
2348 case kAggressivesRequestTypeService:
2349 // synchronizeAggressives() will free request.
2350 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
2351 break;
2352
2353 default:
2354 panic("bad aggressives request type %x", request->dataType);
2355 break;
2356 }
2357 } while (!queue_empty(&aggressivesQueue));
2358
2359 // Release the lock to perform work, with busy flag set.
2360 if (!queue_empty(&joinedQueue) || broadcast) {
2361 AGGRESSIVES_UNLOCK();
2362 if (!queue_empty(&joinedQueue)) {
2363 synchronizeAggressives(&joinedQueue, start, count);
2364 }
2365 if (broadcast) {
2366 broadcastAggressives(start, count);
2367 }
2368 AGGRESSIVES_LOCK();
2369 }
2370
2371 // Remove the modified flag from all records.
2372 for (i = 0, record = start; i < count; i++, record++) {
2373 if ((record->flags & kAggressivesRecordFlagModified) &&
2374 ((record->type == kPMMinutesToDim) ||
2375 (record->type == kPMMinutesToSleep))) {
2376 pingSelf = true;
2377 }
2378
2379 record->flags &= ~kAggressivesRecordFlagModified;
2380 }
2381
2382 // Check the incoming queue again since new entries may have been
2383 // added while lock was released above.
2384 } while (!queue_empty(&aggressivesQueue));
2385
2386 gAggressivesState &= ~kAggressivesStateBusy;
2387
2388 unlock_done:
2389 AGGRESSIVES_UNLOCK();
2390
2391 // Root domain is interested in system and display sleep slider changes.
2392 // Submit a power event to handle those changes on the PM work loop.
2393
2394 if (pingSelf && pmPowerStateQueue) {
2395 pmPowerStateQueue->submitPowerEvent(
2396 kPowerEventPolicyStimulus,
2397 (void *) kStimulusAggressivenessChanged );
2398 }
2399 }
2400
2401 //******************************************************************************
2402 // synchronizeAggressives
2403 //
2404 // Push all known aggressiveness records to one or more IOService.
2405 //******************************************************************************
2406
2407 void
synchronizeAggressives(queue_head_t * joinedQueue,const AggressivesRecord * array,int count)2408 IOPMrootDomain::synchronizeAggressives(
2409 queue_head_t * joinedQueue,
2410 const AggressivesRecord * array,
2411 int count )
2412 {
2413 OSSharedPtr<IOService> service;
2414 AggressivesRequest * request;
2415 const AggressivesRecord * record;
2416 IOPMDriverCallEntry callEntry;
2417 uint32_t value;
2418 int i;
2419
2420 while (!queue_empty(joinedQueue)) {
2421 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
2422 if (request->dataType == kAggressivesRequestTypeService) {
2423 // retained by joinAggressiveness(), so take ownership
2424 service = os::move(request->data.service);
2425 } else {
2426 service.reset();
2427 }
2428
2429 IOFreeType(request, AggressivesRequest);
2430 request = NULL;
2431
2432 if (service) {
2433 if (service->assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetAggressive)) {
2434 for (i = 0, record = array; i < count; i++, record++) {
2435 value = record->value;
2436 if (record->flags & kAggressivesRecordFlagMinValue) {
2437 value = kAggressivesMinValue;
2438 }
2439
2440 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2441 record->type, value, service->getName());
2442 service->setAggressiveness(record->type, value);
2443 }
2444 service->deassertPMDriverCall(&callEntry);
2445 }
2446 }
2447 }
2448 }
2449
2450 //******************************************************************************
2451 // broadcastAggressives
2452 //
2453 // Traverse PM tree and call setAggressiveness() for records that have changed.
2454 //******************************************************************************
2455
2456 void
broadcastAggressives(const AggressivesRecord * array,int count)2457 IOPMrootDomain::broadcastAggressives(
2458 const AggressivesRecord * array,
2459 int count )
2460 {
2461 OSSharedPtr<IORegistryIterator> iter;
2462 IORegistryEntry *entry;
2463 OSSharedPtr<IORegistryEntry> child;
2464 IOPowerConnection *connect;
2465 IOService *service;
2466 const AggressivesRecord *record;
2467 IOPMDriverCallEntry callEntry;
2468 uint32_t value;
2469 int i;
2470
2471 iter = IORegistryIterator::iterateOver(
2472 this, gIOPowerPlane, kIORegistryIterateRecursively);
2473 if (iter) {
2474 do{
2475 // !! reset the iterator
2476 iter->reset();
2477 while ((entry = iter->getNextObject())) {
2478 connect = OSDynamicCast(IOPowerConnection, entry);
2479 if (!connect || !connect->getReadyFlag()) {
2480 continue;
2481 }
2482
2483 child = connect->copyChildEntry(gIOPowerPlane);
2484 if (child) {
2485 if ((service = OSDynamicCast(IOService, child.get()))) {
2486 if (service->assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetAggressive)) {
2487 for (i = 0, record = array; i < count; i++, record++) {
2488 if (record->flags & kAggressivesRecordFlagModified) {
2489 value = record->value;
2490 if (record->flags & kAggressivesRecordFlagMinValue) {
2491 value = kAggressivesMinValue;
2492 }
2493 _LOG("broadcastAggressives %x = %u to %s\n",
2494 record->type, value, service->getName());
2495 service->setAggressiveness(record->type, value);
2496 }
2497 }
2498 service->deassertPMDriverCall(&callEntry);
2499 }
2500 }
2501 }
2502 }
2503 }while (!entry && !iter->isValid());
2504 }
2505 }
2506
2507 //*****************************************
2508 // stackshot on power button press
2509 // ***************************************
2510 static void
powerButtonDownCallout(thread_call_param_t us,thread_call_param_t)2511 powerButtonDownCallout(thread_call_param_t us, thread_call_param_t )
2512 {
2513 /* Power button pressed during wake
2514 * Take a stackshot
2515 */
2516 DEBUG_LOG("Powerbutton: down. Taking stackshot\n");
2517 ((IOPMrootDomain *)us)->takeStackshot(false);
2518 }
2519
2520 static void
powerButtonUpCallout(thread_call_param_t us,thread_call_param_t)2521 powerButtonUpCallout(thread_call_param_t us, thread_call_param_t)
2522 {
2523 /* Power button released.
2524 * Delete any stackshot data
2525 */
2526 DEBUG_LOG("PowerButton: up callout. Delete stackshot\n");
2527 ((IOPMrootDomain *)us)->deleteStackshot();
2528 }
2529 //*************************************************************************
2530 //
2531
2532 // MARK: -
2533 // MARK: System Sleep
2534
2535 //******************************************************************************
2536 // startIdleSleepTimer
2537 //
2538 //******************************************************************************
2539
2540 void
startIdleSleepTimer(uint32_t inMilliSeconds)2541 IOPMrootDomain::startIdleSleepTimer( uint32_t inMilliSeconds )
2542 {
2543 AbsoluteTime deadline;
2544
2545 ASSERT_GATED();
2546 if (gNoIdleFlag) {
2547 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
2548 return;
2549 }
2550 if (inMilliSeconds) {
2551 if (inMilliSeconds < kMinimumTimeBeforeIdleSleep) {
2552 AbsoluteTime now;
2553 uint64_t nsec_since_wake;
2554 uint64_t msec_since_wake;
2555
2556 // Adjust idle timer so it will not expire until atleast kMinimumTimeBeforeIdleSleep milliseconds
2557 // after the most recent AP wake.
2558 clock_get_uptime(&now);
2559 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2560 absolutetime_to_nanoseconds(now, &nsec_since_wake);
2561 msec_since_wake = nsec_since_wake / NSEC_PER_MSEC;
2562
2563 if (msec_since_wake < kMinimumTimeBeforeIdleSleep) {
2564 uint32_t newIdleTimer = kMinimumTimeBeforeIdleSleep - (uint32_t)msec_since_wake;
2565
2566 // Ensure that our new idle timer is not less than inMilliSeconds,
2567 // as we should only be increasing the timer duration, not decreasing it
2568 if (newIdleTimer > inMilliSeconds) {
2569 DLOG("startIdleSleepTimer increasing timeout from %u to %u\n", inMilliSeconds, newIdleTimer);
2570 inMilliSeconds = newIdleTimer;
2571 }
2572 }
2573 }
2574 clock_interval_to_deadline(inMilliSeconds, kMillisecondScale, &deadline);
2575 thread_call_enter_delayed(extraSleepTimer, deadline);
2576 idleSleepTimerPending = true;
2577 } else {
2578 thread_call_enter(extraSleepTimer);
2579 }
2580 DLOG("idle timer set for %u milliseconds\n", inMilliSeconds);
2581 }
2582
2583 //******************************************************************************
2584 // cancelIdleSleepTimer
2585 //
2586 //******************************************************************************
2587
2588 void
cancelIdleSleepTimer(void)2589 IOPMrootDomain::cancelIdleSleepTimer( void )
2590 {
2591 ASSERT_GATED();
2592 if (idleSleepTimerPending) {
2593 DLOG("idle timer cancelled\n");
2594 thread_call_cancel(extraSleepTimer);
2595 idleSleepTimerPending = false;
2596
2597 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
2598 AbsoluteTime now;
2599 clock_usec_t microsecs;
2600 clock_get_uptime(&now);
2601 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2602 absolutetime_to_microtime(now, &assertOnWakeSecs, µsecs);
2603 if (assertOnWakeReport) {
2604 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2605 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2606 }
2607 }
2608 }
2609 }
2610
2611 //******************************************************************************
2612 // idleSleepTimerExpired
2613 //
2614 //******************************************************************************
2615
2616 static void
idleSleepTimerExpired(thread_call_param_t us,thread_call_param_t)2617 idleSleepTimerExpired(
2618 thread_call_param_t us, thread_call_param_t )
2619 {
2620 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
2621 }
2622
2623 //******************************************************************************
2624 // handleSleepTimerExpiration
2625 //
2626 // The time between the sleep idle timeout and the next longest one has elapsed.
2627 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2628 //******************************************************************************
2629
2630 void
handleSleepTimerExpiration(void)2631 IOPMrootDomain::handleSleepTimerExpiration( void )
2632 {
2633 if (!gIOPMWorkLoop->inGate()) {
2634 gIOPMWorkLoop->runAction(
2635 OSMemberFunctionCast(IOWorkLoop::Action, this,
2636 &IOPMrootDomain::handleSleepTimerExpiration),
2637 this);
2638 return;
2639 }
2640
2641 DLOG("sleep timer expired\n");
2642 ASSERT_GATED();
2643
2644 idleSleepTimerPending = false;
2645 setQuickSpinDownTimeout();
2646 adjustPowerState(true);
2647 }
2648
2649 //******************************************************************************
2650 // getTimeToIdleSleep
2651 //
2652 // Returns number of milliseconds left before going into idle sleep.
2653 // Caller has to make sure that idle sleep is allowed at the time of calling
2654 // this function
2655 //******************************************************************************
2656
2657 uint32_t
getTimeToIdleSleep(void)2658 IOPMrootDomain::getTimeToIdleSleep( void )
2659 {
2660 AbsoluteTime now, lastActivityTime;
2661 uint64_t nanos;
2662 uint32_t minutesSinceUserInactive = 0;
2663 uint32_t sleepDelay = 0;
2664
2665 if (!idleSleepEnabled) {
2666 return 0xffffffff;
2667 }
2668
2669 if (userActivityTime) {
2670 lastActivityTime = userActivityTime;
2671 } else {
2672 lastActivityTime = userBecameInactiveTime;
2673 }
2674
2675 // Ignore any lastActivityTime that predates the last system wake.
2676 // The goal is to avoid a sudden idle sleep right after a dark wake
2677 // due to sleepDelay=0 computed below. The alternative 60s minimum
2678 // timeout should be large enough to allow dark wake to complete,
2679 // at which point the idle timer will be promptly cancelled.
2680 clock_get_uptime(&now);
2681 if ((CMP_ABSOLUTETIME(&lastActivityTime, &gIOLastWakeAbsTime) >= 0) &&
2682 (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)) {
2683 SUB_ABSOLUTETIME(&now, &lastActivityTime);
2684 absolutetime_to_nanoseconds(now, &nanos);
2685 minutesSinceUserInactive = nanos / (60000000000ULL);
2686
2687 if (minutesSinceUserInactive >= sleepSlider) {
2688 sleepDelay = 0;
2689 } else {
2690 sleepDelay = sleepSlider - minutesSinceUserInactive;
2691 }
2692 } else {
2693 DLOG("ignoring lastActivityTime 0x%qx, now 0x%qx, wake 0x%qx\n",
2694 lastActivityTime, now, gIOLastWakeAbsTime);
2695 sleepDelay = sleepSlider;
2696 }
2697
2698 DLOG("user inactive %u min, time to idle sleep %u min\n",
2699 minutesSinceUserInactive, sleepDelay);
2700
2701 return sleepDelay * 60 * 1000;
2702 }
2703
2704 //******************************************************************************
2705 // setQuickSpinDownTimeout
2706 //
2707 //******************************************************************************
2708
2709 void
setQuickSpinDownTimeout(void)2710 IOPMrootDomain::setQuickSpinDownTimeout( void )
2711 {
2712 ASSERT_GATED();
2713 setAggressiveness(
2714 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
2715 }
2716
2717 //******************************************************************************
2718 // restoreUserSpinDownTimeout
2719 //
2720 //******************************************************************************
2721
2722 void
restoreUserSpinDownTimeout(void)2723 IOPMrootDomain::restoreUserSpinDownTimeout( void )
2724 {
2725 ASSERT_GATED();
2726 setAggressiveness(
2727 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
2728 }
2729
2730 //******************************************************************************
2731 // sleepSystem
2732 //
2733 //******************************************************************************
2734
2735 /* public */
2736 IOReturn
sleepSystem(void)2737 IOPMrootDomain::sleepSystem( void )
2738 {
2739 return sleepSystemOptions(NULL);
2740 }
2741
2742 /* private */
2743 IOReturn
sleepSystemOptions(OSDictionary * options)2744 IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2745 {
2746 OSObject *obj = NULL;
2747 OSString *reason = NULL;
2748 /* sleepSystem is a public function, and may be called by any kernel driver.
2749 * And that's bad - drivers should sleep the system by calling
2750 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2751 *
2752 * Note that user space app calls to IOPMSleepSystem() will also travel
2753 * this code path and thus be correctly identified as software sleeps.
2754 */
2755
2756 if (options && options->getObject("OSSwitch")) {
2757 // Log specific sleep cause for OS Switch hibernation
2758 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2759 }
2760
2761 if (options && (obj = options->getObject("Sleep Reason"))) {
2762 reason = OSDynamicCast(OSString, obj);
2763 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey)) {
2764 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
2765 }
2766 if (reason && reason->isEqualTo(kIOPMNotificationWakeExitKey)) {
2767 return privateSleepSystem(kIOPMSleepReasonNotificationWakeExit);
2768 }
2769 }
2770
2771 return privateSleepSystem( kIOPMSleepReasonSoftware);
2772 }
2773
2774 /* private */
2775 IOReturn
privateSleepSystem(uint32_t sleepReason)2776 IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2777 {
2778 /* Called from both gated and non-gated context */
2779
2780 if (!checkSystemSleepEnabled() || !pmPowerStateQueue) {
2781 return kIOReturnNotPermitted;
2782 }
2783
2784 pmPowerStateQueue->submitPowerEvent(
2785 kPowerEventPolicyStimulus,
2786 (void *) kStimulusDemandSystemSleep,
2787 sleepReason);
2788
2789 return kIOReturnSuccess;
2790 }
2791
2792 //******************************************************************************
2793 // powerChangeDone
2794 //
2795 // This overrides powerChangeDone in IOService.
2796 //******************************************************************************
2797 void
powerChangeDone(unsigned long previousPowerState)2798 IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
2799 {
2800 #if !__i386__ && !__x86_64__
2801 uint64_t timeSinceReset = 0;
2802 #endif
2803 uint64_t now;
2804 unsigned long newState;
2805 clock_sec_t secs;
2806 clock_usec_t microsecs;
2807 uint32_t lastDebugWakeSeconds;
2808 clock_sec_t adjWakeTime;
2809 IOPMCalendarStruct nowCalendar;
2810
2811 ASSERT_GATED();
2812 newState = getPowerState();
2813 DLOG("PowerChangeDone: %s->%s\n",
2814 getPowerStateString((uint32_t) previousPowerState), getPowerStateString((uint32_t) getPowerState()));
2815
2816 if (previousPowerState == newState) {
2817 return;
2818 }
2819
2820 notifierThread = current_thread();
2821 switch (getPowerState()) {
2822 case SLEEP_STATE: {
2823 if (kPMCalendarTypeInvalid != _aotWakeTimeCalendar.selector) {
2824 secs = 0;
2825 microsecs = 0;
2826 PEGetUTCTimeOfDay(&secs, µsecs);
2827
2828 adjWakeTime = 0;
2829 if ((kIOPMAOTModeRespectTimers & _aotMode) && (_calendarWakeAlarmUTC < _aotWakeTimeUTC)) {
2830 IOLog("use _calendarWakeAlarmUTC\n");
2831 adjWakeTime = _calendarWakeAlarmUTC;
2832 } else if (kIOPMWakeEventAOTExitFlags & _aotPendingFlags) {
2833 IOLog("accelerate _aotWakeTime for exit\n");
2834 adjWakeTime = secs;
2835 } else if (kIOPMDriverAssertionLevelOn == getPMAssertionLevel(kIOPMDriverAssertionCPUBit)) {
2836 IOLog("accelerate _aotWakeTime for assertion\n");
2837 adjWakeTime = secs;
2838 }
2839 if (adjWakeTime) {
2840 IOPMConvertSecondsToCalendar(adjWakeTime, &_aotWakeTimeCalendar);
2841 }
2842
2843 IOPMConvertSecondsToCalendar(secs, &nowCalendar);
2844 IOLog("aotSleep at " YMDTF " sched: " YMDTF "\n", YMDT(&nowCalendar), YMDT(&_aotWakeTimeCalendar));
2845
2846 IOReturn __unused ret = setMaintenanceWakeCalendar(&_aotWakeTimeCalendar);
2847 assert(kIOReturnSuccess == ret);
2848 }
2849 if (_aotLastWakeTime) {
2850 _aotMetrics->totalTime += mach_absolute_time() - _aotLastWakeTime;
2851 if (_aotMetrics->sleepCount && (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax)) {
2852 strlcpy(&_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount - 1][0],
2853 gWakeReasonString,
2854 sizeof(_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount]));
2855 }
2856 }
2857 _aotPendingFlags &= ~kIOPMWakeEventAOTPerCycleFlags;
2858 if (_aotTimerScheduled) {
2859 _aotTimerES->cancelTimeout();
2860 _aotTimerScheduled = false;
2861 }
2862 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Enable);
2863
2864 // re-enable this timer for next sleep
2865 cancelIdleSleepTimer();
2866
2867 if (clamshellExists) {
2868 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
2869 if (gClamshellFlags & kClamshell_WAR_58009435) {
2870 // Disable clamshell sleep until system has completed full wake.
2871 // This prevents a system sleep request (due to a clamshell close)
2872 // from being queued until the end of system full wake - even if
2873 // other clamshell disable bits outside of our control is wrong.
2874 setClamShellSleepDisable(true, kClamshellSleepDisableInternal);
2875 }
2876 #endif
2877
2878 // Log the last known clamshell state before system sleep
2879 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
2880 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask,
2881 desktopMode, acAdaptorConnected);
2882 }
2883
2884 clock_get_calendar_absolute_and_microtime(&secs, µsecs, &now);
2885 logtime(secs);
2886 gIOLastSleepTime.tv_sec = secs;
2887 gIOLastSleepTime.tv_usec = microsecs;
2888 if (!_aotLastWakeTime) {
2889 gIOLastUserSleepTime = gIOLastSleepTime;
2890 }
2891
2892 gIOLastWakeTime.tv_sec = 0;
2893 gIOLastWakeTime.tv_usec = 0;
2894 gIOLastSleepAbsTime = now;
2895
2896 if (wake2DarkwakeDelay && sleepDelaysReport) {
2897 clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
2898 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2899
2900 SUB_ABSOLUTETIME(&now, &ts_sleepStart);
2901 absolutetime_to_microtime(now, &darkwake2SleepSecs, µsecs);
2902 absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, µsecs);
2903 HISTREPORT_TALLYVALUE(sleepDelaysReport,
2904 (int64_t)(wake2DarkwakeSecs + darkwake2SleepSecs));
2905
2906 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
2907 wake2DarkwakeDelay = 0;
2908 }
2909 #if HIBERNATION
2910 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2911 #if (DEVELOPMENT || DEBUG)
2912 record_system_event(SYSTEM_EVENT_TYPE_INFO,
2913 SYSTEM_EVENT_SUBSYSTEM_PMRD,
2914 "System State",
2915 gIOHibernateState ? "Enter Hibernate" : "Enter Sleep"
2916 );
2917 #endif /* DEVELOPMENT || DEBUG */
2918 IOHibernateSystemHasSlept();
2919
2920 evaluateSystemSleepPolicyFinal();
2921 #else
2922 LOG("System Sleep\n");
2923 #if (DEVELOPMENT || DEBUG)
2924 record_system_event(SYSTEM_EVENT_TYPE_INFO,
2925 SYSTEM_EVENT_SUBSYSTEM_PMRD,
2926 "System State", "Enter Sleep");
2927 #endif /* DEVELOPMENT || DEBUG */
2928 #endif
2929 if (thermalWarningState) {
2930 OSSharedPtr<const OSSymbol> event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
2931 if (event) {
2932 systemPowerEventOccurred(event.get(), kIOPMThermalLevelUnknown);
2933 }
2934 }
2935 assertOnWakeSecs = 0;
2936 lowBatteryCondition = false;
2937 thermalEmergencyState = false;
2938
2939 #if DEVELOPMENT || DEBUG
2940 extern int g_should_log_clock_adjustments;
2941 if (g_should_log_clock_adjustments) {
2942 clock_sec_t secs = 0;
2943 clock_usec_t microsecs = 0;
2944 uint64_t now_b = mach_absolute_time();
2945
2946 secs = 0;
2947 microsecs = 0;
2948 PEGetUTCTimeOfDay(&secs, µsecs);
2949
2950 uint64_t now_a = mach_absolute_time();
2951 os_log(OS_LOG_DEFAULT, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2952 __func__, (unsigned long)secs, microsecs, now_b, now_a);
2953 }
2954 #endif
2955
2956 getPlatform()->sleepKernel();
2957
2958 // The CPU(s) are off at this point,
2959 // Code will resume execution here upon wake.
2960
2961 clock_get_uptime(&gIOLastWakeAbsTime);
2962 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
2963 #if DEVELOPMENT || DEBUG
2964 record_system_event(SYSTEM_EVENT_TYPE_INFO,
2965 SYSTEM_EVENT_SUBSYSTEM_PMRD,
2966 "System State", "Waking Up"
2967 );
2968 #endif /* DEVELOPMENT || DEBUG */
2969 _highestCapability = 0;
2970
2971 #if HIBERNATION
2972 IOHibernateSystemWake();
2973 #endif
2974
2975 // sleep transition complete
2976 gSleepOrShutdownPending = 0;
2977
2978 // trip the reset of the calendar clock
2979 clock_wakeup_calendar();
2980 clock_get_calendar_microtime(&secs, µsecs);
2981 gIOLastWakeTime.tv_sec = secs;
2982 gIOLastWakeTime.tv_usec = microsecs;
2983
2984 // aot
2985 if (_aotWakeTimeCalendar.selector != kPMCalendarTypeInvalid) {
2986 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
2987 secs = 0;
2988 microsecs = 0;
2989 PEGetUTCTimeOfDay(&secs, µsecs);
2990 IOPMConvertSecondsToCalendar(secs, &nowCalendar);
2991 IOLog("aotWake at " YMDTF " sched: " YMDTF "\n", YMDT(&nowCalendar), YMDT(&_aotWakeTimeCalendar));
2992 _aotMetrics->sleepCount++;
2993 _aotLastWakeTime = gIOLastWakeAbsTime;
2994 if (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax) {
2995 _aotMetrics->kernelSleepTime[_aotMetrics->sleepCount - 1]
2996 = (((uint64_t) gIOLastSleepTime.tv_sec) << 10) + (gIOLastSleepTime.tv_usec / 1000);
2997 _aotMetrics->kernelWakeTime[_aotMetrics->sleepCount - 1]
2998 = (((uint64_t) gIOLastWakeTime.tv_sec) << 10) + (gIOLastWakeTime.tv_usec / 1000);
2999 }
3000
3001 if (_aotTestTime) {
3002 if (_aotWakeTimeUTC <= secs) {
3003 _aotTestTime = _aotTestTime + _aotTestInterval;
3004 }
3005 setWakeTime(_aotTestTime);
3006 }
3007 }
3008
3009 #if HIBERNATION
3010 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
3011 #endif
3012
3013 lastSleepReason = 0;
3014
3015 lastDebugWakeSeconds = _debugWakeSeconds;
3016 _debugWakeSeconds = 0;
3017 _scheduledAlarmMask = 0;
3018 _nextScheduledAlarmType = NULL;
3019
3020 darkWakeExit = false;
3021 darkWakePowerClamped = false;
3022 darkWakePostTickle = false;
3023 darkWakeHibernateError = false;
3024 darkWakeToSleepASAP = true;
3025 darkWakeLogClamp = true;
3026 sleepTimerMaintenance = false;
3027 sleepToStandby = false;
3028 wranglerTickled = false;
3029 userWasActive = false;
3030 isRTCAlarmWake = false;
3031 clamshellIgnoreClose = false;
3032 fullWakeReason = kFullWakeReasonNone;
3033
3034 #if defined(__i386__) || defined(__x86_64__)
3035 kdebugTrace(kPMLogSystemWake, 0, 0, 0);
3036
3037 OSSharedPtr<OSObject> wakeTypeProp = copyProperty(kIOPMRootDomainWakeTypeKey);
3038 OSSharedPtr<OSObject> wakeReasonProp = copyProperty(kIOPMRootDomainWakeReasonKey);
3039 OSString * wakeType = OSDynamicCast(OSString, wakeTypeProp.get());
3040 OSString * wakeReason = OSDynamicCast(OSString, wakeReasonProp.get());
3041
3042 if (wakeReason && (wakeReason->getLength() >= 2) &&
3043 gWakeReasonString[0] == '\0') {
3044 WAKEEVENT_LOCK();
3045 // Until the platform driver can claim its wake reasons
3046 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
3047 sizeof(gWakeReasonString));
3048 if (!gWakeReasonSysctlRegistered) {
3049 gWakeReasonSysctlRegistered = true;
3050 }
3051 WAKEEVENT_UNLOCK();
3052 }
3053
3054 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery)) {
3055 lowBatteryCondition = true;
3056 darkWakeMaintenance = true;
3057 } else {
3058 #if HIBERNATION
3059 OSSharedPtr<OSObject> hibOptionsProp = copyProperty(kIOHibernateOptionsKey);
3060 OSNumber * hibOptions = OSDynamicCast( OSNumber, hibOptionsProp.get());
3061 if (hibernateAborted || ((hibOptions &&
3062 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)))) {
3063 // Hibernate aborted, or EFI brought up graphics
3064 darkWakeExit = true;
3065 if (hibernateAborted) {
3066 DLOG("Hibernation aborted\n");
3067 } else {
3068 DLOG("EFI brought up graphics. Going to full wake. HibOptions: 0x%x\n", hibOptions->unsigned32BitValue());
3069 }
3070 } else
3071 #endif
3072 if (wakeType && (
3073 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
3074 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))) {
3075 // User wake or RTC alarm
3076 darkWakeExit = true;
3077 if (wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)) {
3078 isRTCAlarmWake = true;
3079 }
3080 } else if (wakeType &&
3081 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer)) {
3082 // SMC standby timer trumps SleepX
3083 darkWakeMaintenance = true;
3084 sleepTimerMaintenance = true;
3085 } else if ((lastDebugWakeSeconds != 0) &&
3086 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) {
3087 // SleepX before maintenance
3088 darkWakeExit = true;
3089 } else if (wakeType &&
3090 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance)) {
3091 darkWakeMaintenance = true;
3092 } else if (wakeType &&
3093 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService)) {
3094 darkWakeMaintenance = true;
3095 darkWakeSleepService = true;
3096 #if HIBERNATION
3097 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
3098 sleepToStandby = true;
3099 }
3100 #endif
3101 } else if (wakeType &&
3102 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError)) {
3103 darkWakeMaintenance = true;
3104 darkWakeHibernateError = true;
3105 } else {
3106 // Unidentified wake source, resume to full wake if debug
3107 // alarm is pending.
3108
3109 if (lastDebugWakeSeconds &&
3110 (!wakeReason || wakeReason->isEqualTo(""))) {
3111 darkWakeExit = true;
3112 }
3113 }
3114 }
3115
3116 if (darkWakeExit) {
3117 darkWakeToSleepASAP = false;
3118 fullWakeReason = kFullWakeReasonLocalUser;
3119 reportUserInput();
3120 } else if (displayPowerOnRequested && checkSystemCanSustainFullWake()) {
3121 handleSetDisplayPowerOn(true);
3122 } else if (!darkWakeMaintenance) {
3123 // Early/late tickle for non-maintenance wake.
3124 if ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) != kDarkWakeFlagPromotionNone) {
3125 darkWakePostTickle = true;
3126 }
3127 }
3128 #else /* !__i386__ && !__x86_64__ */
3129 timeSinceReset = ml_get_time_since_reset();
3130 kdebugTrace(kPMLogSystemWake, 0, (uintptr_t)(timeSinceReset >> 32), (uintptr_t) timeSinceReset);
3131
3132 if ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) == kDarkWakeFlagPromotionEarly) {
3133 wranglerTickled = true;
3134 fullWakeReason = kFullWakeReasonLocalUser;
3135 requestUserActive(this, "Full wake on dark wake promotion boot-arg");
3136 } else if ((lastDebugWakeSeconds != 0) && !(gDarkWakeFlags & kDarkWakeFlagAlarmIsDark)) {
3137 isRTCAlarmWake = true;
3138 fullWakeReason = kFullWakeReasonLocalUser;
3139 requestUserActive(this, "RTC debug alarm");
3140 } else {
3141 #if HIBERNATION
3142 OSSharedPtr<OSObject> hibOptionsProp = copyProperty(kIOHibernateOptionsKey);
3143 OSNumber * hibOptions = OSDynamicCast(OSNumber, hibOptionsProp.get());
3144 if (hibOptions && !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)) {
3145 fullWakeReason = kFullWakeReasonLocalUser;
3146 requestUserActive(this, "hibernate user wake");
3147 }
3148 #endif
3149 }
3150
3151 // stay awake for at least 30 seconds
3152 startIdleSleepTimer(30 * 1000);
3153 #endif
3154 sleepCnt++;
3155
3156 thread_call_enter(updateConsoleUsersEntry);
3157
3158 // Skip AOT_STATE if we are waking up from an RTC timer.
3159 // This check needs to be done after the epoch change is processed
3160 // and before the changePowerStateWithTagToPriv() call below.
3161 WAKEEVENT_LOCK();
3162 aotShouldExit(false, false);
3163 WAKEEVENT_UNLOCK();
3164
3165 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonWake);
3166 break;
3167 }
3168 #if !__i386__ && !__x86_64__
3169 case ON_STATE:
3170 case AOT_STATE:
3171 {
3172 DLOG("Force re-evaluating aggressiveness\n");
3173 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
3174 pmPowerStateQueue->submitPowerEvent(
3175 kPowerEventPolicyStimulus,
3176 (void *) kStimulusNoIdleSleepPreventers );
3177
3178 // After changing to ON_STATE, invalidate any previously queued
3179 // request to change to a state less than ON_STATE. This isn't
3180 // necessary for AOT_STATE or if the device has only one running
3181 // state since the changePowerStateToPriv() issued at the tail
3182 // end of SLEEP_STATE case should take care of that.
3183 if (getPowerState() == ON_STATE) {
3184 changePowerStateWithTagToPriv(ON_STATE, kCPSReasonWake);
3185 }
3186 break;
3187 }
3188 #endif /* !__i386__ && !__x86_64__ */
3189 }
3190 notifierThread = NULL;
3191 }
3192
3193 //******************************************************************************
3194 // requestPowerDomainState
3195 //
3196 // Extend implementation in IOService. Running on PM work loop thread.
3197 //******************************************************************************
3198
3199 IOReturn
requestPowerDomainState(IOPMPowerFlags childDesire,IOPowerConnection * childConnection,unsigned long specification)3200 IOPMrootDomain::requestPowerDomainState(
3201 IOPMPowerFlags childDesire,
3202 IOPowerConnection * childConnection,
3203 unsigned long specification )
3204 {
3205 // Idle and system sleep prevention flags affects driver desire.
3206 // Children desire are irrelevant so they are cleared.
3207
3208 return super::requestPowerDomainState(0, childConnection, specification);
3209 }
3210
3211
3212 static void
makeSleepPreventersListLog(const OSSharedPtr<OSSet> & preventers,char * buf,size_t buf_size)3213 makeSleepPreventersListLog(const OSSharedPtr<OSSet> &preventers, char *buf, size_t buf_size)
3214 {
3215 if (!preventers->getCount()) {
3216 return;
3217 }
3218
3219 char *buf_iter = buf + strlen(buf);
3220 char *buf_end = buf + buf_size;
3221
3222 OSSharedPtr<OSCollectionIterator> iterator = OSCollectionIterator::withCollection(preventers.get());
3223 OSObject *obj = NULL;
3224
3225 while ((obj = iterator->getNextObject())) {
3226 IOService *srv = OSDynamicCast(IOService, obj);
3227 if (buf_iter < buf_end) {
3228 buf_iter += snprintf(buf_iter, buf_end - buf_iter, " %s", srv->getName());
3229 } else {
3230 DLOG("Print buffer exhausted for sleep preventers list\n");
3231 break;
3232 }
3233 }
3234 }
3235
3236 //******************************************************************************
3237 // updatePreventIdleSleepList
3238 //
3239 // Called by IOService on PM work loop.
3240 // Returns true if PM policy recognized the driver's desire to prevent idle
3241 // sleep and updated the list of idle sleep preventers. Returns false otherwise
3242 //******************************************************************************
3243
3244 bool
updatePreventIdleSleepList(IOService * service,bool addNotRemove)3245 IOPMrootDomain::updatePreventIdleSleepList(
3246 IOService * service, bool addNotRemove)
3247 {
3248 unsigned int oldCount;
3249
3250 oldCount = idleSleepPreventersCount();
3251 return updatePreventIdleSleepListInternal(service, addNotRemove, oldCount);
3252 }
3253
3254 bool
updatePreventIdleSleepListInternal(IOService * service,bool addNotRemove,unsigned int oldCount)3255 IOPMrootDomain::updatePreventIdleSleepListInternal(
3256 IOService * service, bool addNotRemove, unsigned int oldCount)
3257 {
3258 unsigned int newCount;
3259
3260 ASSERT_GATED();
3261
3262 #if defined(XNU_TARGET_OS_OSX)
3263 // Only the display wrangler and no-idle-sleep kernel assertions
3264 // can prevent idle sleep. The kIOPMPreventIdleSleep capability flag
3265 // reported by drivers in their power state table is ignored.
3266 if (service && (service != wrangler) && (service != this)) {
3267 return false;
3268 }
3269 #endif
3270
3271 if (service) {
3272 if (addNotRemove) {
3273 preventIdleSleepList->setObject(service);
3274 DLOG("Added %s to idle sleep preventers list (Total %u)\n",
3275 service->getName(), preventIdleSleepList->getCount());
3276 } else if (preventIdleSleepList->member(service)) {
3277 preventIdleSleepList->removeObject(service);
3278 DLOG("Removed %s from idle sleep preventers list (Total %u)\n",
3279 service->getName(), preventIdleSleepList->getCount());
3280 }
3281
3282 if (preventIdleSleepList->getCount()) {
3283 char buf[256] = "Idle Sleep Preventers:";
3284 makeSleepPreventersListLog(preventIdleSleepList, buf, sizeof(buf));
3285 DLOG("%s\n", buf);
3286 }
3287 }
3288
3289 newCount = idleSleepPreventersCount();
3290
3291 if ((oldCount == 0) && (newCount != 0)) {
3292 // Driver added to empty prevent list.
3293 // Update the driver desire to prevent idle sleep.
3294 // Driver desire does not prevent demand sleep.
3295
3296 changePowerStateWithTagTo(getRUN_STATE(), kCPSReasonIdleSleepPrevent);
3297 } else if ((oldCount != 0) && (newCount == 0)) {
3298 // Last driver removed from prevent list.
3299 // Drop the driver clamp to allow idle sleep.
3300
3301 changePowerStateWithTagTo(SLEEP_STATE, kCPSReasonIdleSleepAllow);
3302 evaluatePolicy( kStimulusNoIdleSleepPreventers );
3303 }
3304 messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier.get(),
3305 &newCount, sizeof(newCount));
3306
3307 #if defined(XNU_TARGET_OS_OSX)
3308 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake()) {
3309 DLOG("Cannot cancel idle sleep\n");
3310 return false; // do not idle-cancel
3311 }
3312 #endif
3313
3314 return true;
3315 }
3316
3317 //******************************************************************************
3318 // startSpinDump
3319 //******************************************************************************
3320
3321 void
startSpinDump(uint32_t spindumpKind)3322 IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
3323 {
3324 messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
3325 }
3326
3327 //******************************************************************************
3328 // preventSystemSleepListUpdate
3329 //
3330 // Called by IOService on PM work loop.
3331 //******************************************************************************
3332
3333 void
updatePreventSystemSleepList(IOService * service,bool addNotRemove)3334 IOPMrootDomain::updatePreventSystemSleepList(
3335 IOService * service, bool addNotRemove )
3336 {
3337 unsigned int oldCount, newCount;
3338
3339 ASSERT_GATED();
3340 if (this == service) {
3341 return;
3342 }
3343
3344 oldCount = preventSystemSleepList->getCount();
3345 if (addNotRemove) {
3346 preventSystemSleepList->setObject(service);
3347 DLOG("Added %s to system sleep preventers list (Total %u)\n",
3348 service->getName(), preventSystemSleepList->getCount());
3349 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3350 AbsoluteTime now;
3351 clock_usec_t microsecs;
3352 clock_get_uptime(&now);
3353 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3354 absolutetime_to_microtime(now, &assertOnWakeSecs, µsecs);
3355 if (assertOnWakeReport) {
3356 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
3357 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
3358 }
3359 }
3360 } else if (preventSystemSleepList->member(service)) {
3361 preventSystemSleepList->removeObject(service);
3362 DLOG("Removed %s from system sleep preventers list (Total %u)\n",
3363 service->getName(), preventSystemSleepList->getCount());
3364
3365 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0)) {
3366 // Lost all system sleep preventers.
3367 // Send stimulus if system sleep was blocked, and is in dark wake.
3368 evaluatePolicy( kStimulusDarkWakeEvaluate );
3369 }
3370 }
3371
3372 newCount = preventSystemSleepList->getCount();
3373 if (newCount) {
3374 char buf[256] = "System Sleep Preventers:";
3375 makeSleepPreventersListLog(preventSystemSleepList, buf, sizeof(buf));
3376 DLOG("%s\n", buf);
3377 }
3378
3379 messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier.get(),
3380 &newCount, sizeof(newCount));
3381 }
3382
3383 void
copySleepPreventersList(OSArray ** idleSleepList,OSArray ** systemSleepList)3384 IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
3385 {
3386 OSSharedPtr<OSCollectionIterator> iterator;
3387 OSObject *object = NULL;
3388 OSSharedPtr<OSArray> array;
3389
3390 if (!gIOPMWorkLoop->inGate()) {
3391 gIOPMWorkLoop->runAction(
3392 OSMemberFunctionCast(IOWorkLoop::Action, this,
3393 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
3394 this, (void *)idleSleepList, (void *)systemSleepList);
3395 return;
3396 }
3397
3398 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0)) {
3399 iterator = OSCollectionIterator::withCollection(preventIdleSleepList.get());
3400 array = OSArray::withCapacity(5);
3401
3402 if (iterator && array) {
3403 while ((object = iterator->getNextObject())) {
3404 IOService *service = OSDynamicCast(IOService, object);
3405 if (service) {
3406 OSSharedPtr<const OSSymbol> name = service->copyName();
3407 if (name) {
3408 array->setObject(name.get());
3409 }
3410 }
3411 }
3412 }
3413 *idleSleepList = array.detach();
3414 }
3415
3416 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0)) {
3417 iterator = OSCollectionIterator::withCollection(preventSystemSleepList.get());
3418 array = OSArray::withCapacity(5);
3419
3420 if (iterator && array) {
3421 while ((object = iterator->getNextObject())) {
3422 IOService *service = OSDynamicCast(IOService, object);
3423 if (service) {
3424 OSSharedPtr<const OSSymbol> name = service->copyName();
3425 if (name) {
3426 array->setObject(name.get());
3427 }
3428 }
3429 }
3430 }
3431 *systemSleepList = array.detach();
3432 }
3433 }
3434
3435 void
copySleepPreventersListWithID(OSArray ** idleSleepList,OSArray ** systemSleepList)3436 IOPMrootDomain::copySleepPreventersListWithID(OSArray **idleSleepList, OSArray **systemSleepList)
3437 {
3438 OSSharedPtr<OSCollectionIterator> iterator;
3439 OSObject *object = NULL;
3440 OSSharedPtr<OSArray> array;
3441
3442 if (!gIOPMWorkLoop->inGate()) {
3443 gIOPMWorkLoop->runAction(
3444 OSMemberFunctionCast(IOWorkLoop::Action, this,
3445 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersListWithID),
3446 this, (void *)idleSleepList, (void *)systemSleepList);
3447 return;
3448 }
3449
3450 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0)) {
3451 iterator = OSCollectionIterator::withCollection(preventIdleSleepList.get());
3452 array = OSArray::withCapacity(5);
3453
3454 if (iterator && array) {
3455 while ((object = iterator->getNextObject())) {
3456 IOService *service = OSDynamicCast(IOService, object);
3457 if (service) {
3458 OSSharedPtr<OSDictionary> dict = OSDictionary::withCapacity(2);
3459 OSSharedPtr<const OSSymbol> name = service->copyName();
3460 OSSharedPtr<OSNumber> id = OSNumber::withNumber(service->getRegistryEntryID(), 64);
3461 if (dict && name && id) {
3462 dict->setObject(kIOPMDriverAssertionRegistryEntryIDKey, id.get());
3463 dict->setObject(kIOPMDriverAssertionOwnerStringKey, name.get());
3464 array->setObject(dict.get());
3465 }
3466 }
3467 }
3468 }
3469 *idleSleepList = array.detach();
3470 }
3471
3472 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0)) {
3473 iterator = OSCollectionIterator::withCollection(preventSystemSleepList.get());
3474 array = OSArray::withCapacity(5);
3475
3476 if (iterator && array) {
3477 while ((object = iterator->getNextObject())) {
3478 IOService *service = OSDynamicCast(IOService, object);
3479 if (service) {
3480 OSSharedPtr<OSDictionary> dict = OSDictionary::withCapacity(2);
3481 OSSharedPtr<const OSSymbol> name = service->copyName();
3482 OSSharedPtr<OSNumber> id = OSNumber::withNumber(service->getRegistryEntryID(), 64);
3483 if (dict && name && id) {
3484 dict->setObject(kIOPMDriverAssertionRegistryEntryIDKey, id.get());
3485 dict->setObject(kIOPMDriverAssertionOwnerStringKey, name.get());
3486 array->setObject(dict.get());
3487 }
3488 }
3489 }
3490 }
3491 *systemSleepList = array.detach();
3492 }
3493 }
3494
3495 //******************************************************************************
3496 // tellChangeDown
3497 //
3498 // Override the superclass implementation to send a different message type.
3499 //******************************************************************************
3500
3501 bool
tellChangeDown(unsigned long stateNum)3502 IOPMrootDomain::tellChangeDown( unsigned long stateNum )
3503 {
3504 DLOG("tellChangeDown %s->%s\n",
3505 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3506
3507 if (SLEEP_STATE == stateNum) {
3508 // Legacy apps were already told in the full->dark transition
3509 if (!ignoreTellChangeDown) {
3510 tracePoint( kIOPMTracePointSleepApplications );
3511 } else {
3512 tracePoint( kIOPMTracePointSleepPriorityClients );
3513 }
3514 }
3515
3516 if (!ignoreTellChangeDown) {
3517 userActivityAtSleep = userActivityCount;
3518 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
3519
3520 if (SLEEP_STATE == stateNum) {
3521 hibernateAborted = false;
3522
3523 // Direct callout into OSKext so it can disable kext unloads
3524 // during sleep/wake to prevent deadlocks.
3525 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
3526
3527 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
3528
3529 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3530 // But tellClientsWithResponse() must be called for both.
3531 ignoreTellChangeDown = true;
3532 }
3533 }
3534
3535 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
3536 }
3537
3538 //******************************************************************************
3539 // askChangeDown
3540 //
3541 // Override the superclass implementation to send a different message type.
3542 // This must be idle sleep since we don't ask during any other power change.
3543 //******************************************************************************
3544
3545 bool
askChangeDown(unsigned long stateNum)3546 IOPMrootDomain::askChangeDown( unsigned long stateNum )
3547 {
3548 DLOG("askChangeDown %s->%s\n",
3549 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3550
3551 // Don't log for dark wake entry
3552 if (kSystemTransitionSleep == _systemTransitionType) {
3553 tracePoint( kIOPMTracePointSleepApplications );
3554 }
3555
3556 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
3557 }
3558
3559 //******************************************************************************
3560 // askChangeDownDone
3561 //
3562 // An opportunity for root domain to cancel the power transition,
3563 // possibily due to an assertion created by powerd in response to
3564 // kIOMessageCanSystemSleep.
3565 //
3566 // Idle sleep:
3567 // full -> dark wake transition
3568 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
3569 // 2. askChangeDownDone()
3570 // dark -> sleep transition
3571 // 1. Notify powerd with kIOMessageCanSystemSleep
3572 // 2. askChangeDownDone()
3573 //
3574 // Demand sleep:
3575 // full -> dark wake transition
3576 // 1. Notify powerd with kIOMessageCanSystemSleep
3577 // 2. askChangeDownDone()
3578 // dark -> sleep transition
3579 // 1. Notify powerd with kIOMessageCanSystemSleep
3580 // 2. askChangeDownDone()
3581 //******************************************************************************
3582
3583 void
askChangeDownDone(IOPMPowerChangeFlags * inOutChangeFlags,bool * cancel)3584 IOPMrootDomain::askChangeDownDone(
3585 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
3586 {
3587 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
3588 *inOutChangeFlags, *cancel,
3589 _systemTransitionType,
3590 _currentCapability, _pendingCapability);
3591
3592 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType)) {
3593 // Dark->Sleep transition.
3594 // Check if there are any deny sleep assertions.
3595 // lastSleepReason already set by handleOurPowerChangeStart()
3596
3597 if (!checkSystemCanSleep(lastSleepReason)) {
3598 // Cancel dark wake to sleep transition.
3599 // Must re-scan assertions upon entering dark wake.
3600
3601 *cancel = true;
3602 DLOG("cancel dark->sleep\n");
3603 }
3604 if (_aotMode && (kPMCalendarTypeInvalid != _aotWakeTimeCalendar.selector)) {
3605 uint64_t now = mach_continuous_time();
3606 if (((now + _aotWakePreWindow) >= _aotWakeTimeContinuous)
3607 && (now < (_aotWakeTimeContinuous + _aotWakePostWindow))) {
3608 *cancel = true;
3609 IOLog("AOT wake window cancel: %qd, %qd\n", now, _aotWakeTimeContinuous);
3610 }
3611 }
3612 }
3613 }
3614
3615 //******************************************************************************
3616 // systemDidNotSleep
3617 //
3618 // Work common to both canceled or aborted sleep.
3619 //******************************************************************************
3620
3621 void
systemDidNotSleep(void)3622 IOPMrootDomain::systemDidNotSleep( void )
3623 {
3624 // reset console lock state
3625 thread_call_enter(updateConsoleUsersEntry);
3626
3627 if (idleSleepEnabled) {
3628 if (!wrangler) {
3629 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
3630 startIdleSleepTimer(kIdleSleepRetryInterval);
3631 #else
3632 startIdleSleepTimer(idleMilliSeconds);
3633 #endif
3634 } else if (!userIsActive) {
3635 // Manually start the idle sleep timer besides waiting for
3636 // the user to become inactive.
3637 startIdleSleepTimer(kIdleSleepRetryInterval);
3638 }
3639 }
3640
3641 preventTransitionToUserActive(false);
3642 IOService::setAdvisoryTickleEnable( true );
3643
3644 // After idle revert and cancel, send a did-change message to powerd
3645 // to balance the previous will-change message. Kernel clients do not
3646 // need this since sleep cannot be canceled once they are notified.
3647
3648 if (toldPowerdCapWillChange && systemCapabilityNotifier &&
3649 (_pendingCapability != _currentCapability) &&
3650 ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0)) {
3651 // Differs from a real capability gain change where notifyRef != 0,
3652 // but it is zero here since no response is expected.
3653
3654 IOPMSystemCapabilityChangeParameters params;
3655
3656 bzero(¶ms, sizeof(params));
3657 params.fromCapabilities = _pendingCapability;
3658 params.toCapabilities = _currentCapability;
3659 params.changeFlags = kIOPMSystemCapabilityDidChange;
3660
3661 DLOG("MESG cap %x->%x did change\n",
3662 params.fromCapabilities, params.toCapabilities);
3663 messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier.get(),
3664 ¶ms, sizeof(params));
3665 }
3666 }
3667
3668 //******************************************************************************
3669 // tellNoChangeDown
3670 //
3671 // Notify registered applications and kernel clients that we are not dropping
3672 // power.
3673 //
3674 // We override the superclass implementation so we can send a different message
3675 // type to the client or application being notified.
3676 //
3677 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3678 //******************************************************************************
3679
3680 void
tellNoChangeDown(unsigned long stateNum)3681 IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
3682 {
3683 DLOG("tellNoChangeDown %s->%s\n",
3684 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3685
3686 // Sleep canceled, clear the sleep trace point.
3687 tracePoint(kIOPMTracePointSystemUp);
3688
3689 systemDidNotSleep();
3690 return tellClients( kIOMessageSystemWillNotSleep );
3691 }
3692
3693 //******************************************************************************
3694 // tellChangeUp
3695 //
3696 // Notify registered applications and kernel clients that we are raising power.
3697 //
3698 // We override the superclass implementation so we can send a different message
3699 // type to the client or application being notified.
3700 //******************************************************************************
3701
3702 void
tellChangeUp(unsigned long stateNum)3703 IOPMrootDomain::tellChangeUp( unsigned long stateNum )
3704 {
3705 DLOG("tellChangeUp %s->%s\n",
3706 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
3707
3708 ignoreTellChangeDown = false;
3709
3710 if (stateNum == ON_STATE) {
3711 // Direct callout into OSKext so it can disable kext unloads
3712 // during sleep/wake to prevent deadlocks.
3713 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
3714
3715 // Notify platform that sleep was cancelled or resumed.
3716 getPlatform()->callPlatformFunction(
3717 sleepMessagePEFunction.get(), false,
3718 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
3719 NULL, NULL, NULL);
3720
3721 if (getPowerState() == ON_STATE) {
3722 // Sleep was cancelled by idle cancel or revert
3723 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
3724 // rdar://problem/50363791
3725 // If system is in dark wake and sleep is cancelled, do not
3726 // send SystemWillPowerOn/HasPoweredOn messages to kernel
3727 // priority clients. They haven't yet seen a SystemWillSleep
3728 // message before the cancellation. So make sure the kernel
3729 // client bit is cleared in _systemMessageClientMask before
3730 // invoking the tellClients() below. This bit may have been
3731 // set by handleOurPowerChangeStart() anticipating a successful
3732 // sleep and setting the filter mask ahead of time allows the
3733 // SystemWillSleep message to go through.
3734 _systemMessageClientMask &= ~kSystemMessageClientKernel;
3735 }
3736
3737 systemDidNotSleep();
3738 tellClients( kIOMessageSystemWillPowerOn );
3739 }
3740
3741 tracePoint( kIOPMTracePointWakeApplications );
3742 tellClients( kIOMessageSystemHasPoweredOn );
3743 } else if (stateNum == AOT_STATE) {
3744 if (getPowerState() == AOT_STATE) {
3745 // Sleep was cancelled by idle cancel or revert
3746 startIdleSleepTimer(idleMilliSeconds);
3747 }
3748 }
3749 }
3750
3751 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3752 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3753 ((params)->fromCapabilities & (flag)) && \
3754 (((params)->toCapabilities & (flag)) == 0))
3755
3756 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3757 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3758 ((params)->toCapabilities & (flag)) && \
3759 (((params)->fromCapabilities & (flag)) == 0))
3760
3761 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3762 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3763 ((params)->fromCapabilities & (flag)) && \
3764 (((params)->toCapabilities & (flag)) == 0))
3765
3766 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3767 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3768 ((params)->toCapabilities & (flag)) && \
3769 (((params)->fromCapabilities & (flag)) == 0))
3770
3771 //******************************************************************************
3772 // sysPowerDownHandler
3773 //
3774 // Perform a vfs sync before system sleep.
3775 //******************************************************************************
3776
3777 IOReturn
sysPowerDownHandler(void * target,void * refCon,UInt32 messageType,IOService * service,void * messageArgs,vm_size_t argSize)3778 IOPMrootDomain::sysPowerDownHandler(
3779 void * target, void * refCon,
3780 UInt32 messageType, IOService * service,
3781 void * messageArgs, vm_size_t argSize )
3782 {
3783 static UInt32 lastSystemMessageType = 0;
3784 IOReturn ret = 0;
3785
3786 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
3787
3788 // rdar://problem/50363791
3789 // Sanity check to make sure the SystemWill/Has message types are
3790 // received in the expected order for all kernel priority clients.
3791 if (messageType == kIOMessageSystemWillSleep ||
3792 messageType == kIOMessageSystemWillPowerOn ||
3793 messageType == kIOMessageSystemHasPoweredOn) {
3794 switch (messageType) {
3795 case kIOMessageSystemWillPowerOn:
3796 assert(lastSystemMessageType == kIOMessageSystemWillSleep);
3797 break;
3798 case kIOMessageSystemHasPoweredOn:
3799 assert(lastSystemMessageType == kIOMessageSystemWillPowerOn);
3800 break;
3801 }
3802
3803 lastSystemMessageType = messageType;
3804 }
3805
3806 if (!gRootDomain) {
3807 return kIOReturnUnsupported;
3808 }
3809
3810 if (messageType == kIOMessageSystemCapabilityChange) {
3811 IOPMSystemCapabilityChangeParameters * params =
3812 (IOPMSystemCapabilityChangeParameters *) messageArgs;
3813
3814 // Interested applications have been notified of an impending power
3815 // change and have acked (when applicable).
3816 // This is our chance to save whatever state we can before powering
3817 // down.
3818 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3819 // via callout
3820
3821 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3822 params->fromCapabilities, params->toCapabilities,
3823 params->changeFlags);
3824
3825 if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU)) {
3826 // We will ack within 20 seconds
3827 params->maxWaitForReply = 20 * 1000 * 1000;
3828
3829 #if HIBERNATION
3830 gRootDomain->evaluateSystemSleepPolicyEarly();
3831
3832 // add in time we could spend freeing pages
3833 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled) {
3834 params->maxWaitForReply = kCapabilityClientMaxWait;
3835 }
3836 DLOG("sysPowerDownHandler max wait %d s\n",
3837 (int) (params->maxWaitForReply / 1000 / 1000));
3838 #endif
3839
3840 // Notify platform that sleep has begun, after the early
3841 // sleep policy evaluation.
3842 getPlatform()->callPlatformFunction(
3843 sleepMessagePEFunction.get(), false,
3844 (void *)(uintptr_t) kIOMessageSystemWillSleep,
3845 NULL, NULL, NULL);
3846
3847 if (!OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending )) {
3848 // Purposely delay the ack and hope that shutdown occurs quickly.
3849 // Another option is not to schedule the thread and wait for
3850 // ack timeout...
3851 AbsoluteTime deadline;
3852 clock_interval_to_deadline( 30, kSecondScale, &deadline );
3853 thread_call_enter1_delayed(
3854 gRootDomain->diskSyncCalloutEntry,
3855 (thread_call_param_t)(uintptr_t) params->notifyRef,
3856 deadline );
3857 } else {
3858 thread_call_enter1(
3859 gRootDomain->diskSyncCalloutEntry,
3860 (thread_call_param_t)(uintptr_t) params->notifyRef);
3861 }
3862 }
3863 #if HIBERNATION
3864 else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU)) {
3865 // We will ack within 110 seconds
3866 params->maxWaitForReply = 110 * 1000 * 1000;
3867
3868 thread_call_enter1(
3869 gRootDomain->diskSyncCalloutEntry,
3870 (thread_call_param_t)(uintptr_t) params->notifyRef);
3871 }
3872 #endif
3873 ret = kIOReturnSuccess;
3874 }
3875
3876 return ret;
3877 }
3878
3879 //******************************************************************************
3880 // handleQueueSleepWakeUUID
3881 //
3882 // Called from IOPMrootDomain when we're initiating a sleep,
3883 // or indirectly from PM configd when PM decides to clear the UUID.
3884 // PM clears the UUID several minutes after successful wake from sleep,
3885 // so that we might associate App spindumps with the immediately previous
3886 // sleep/wake.
3887 //
3888 // @param obj has a retain on it. We're responsible for releasing that retain.
3889 //******************************************************************************
3890
3891 void
handleQueueSleepWakeUUID(OSObject * obj)3892 IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
3893 {
3894 OSSharedPtr<OSString> str;
3895
3896 if (kOSBooleanFalse == obj) {
3897 handlePublishSleepWakeUUID(false);
3898 } else {
3899 str.reset(OSDynamicCast(OSString, obj), OSNoRetain);
3900 if (str) {
3901 // This branch caches the UUID for an upcoming sleep/wake
3902 queuedSleepWakeUUIDString = str;
3903 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
3904 }
3905 }
3906 }
3907 //******************************************************************************
3908 // handlePublishSleepWakeUUID
3909 //
3910 // Called from IOPMrootDomain when we're initiating a sleep,
3911 // or indirectly from PM configd when PM decides to clear the UUID.
3912 // PM clears the UUID several minutes after successful wake from sleep,
3913 // so that we might associate App spindumps with the immediately previous
3914 // sleep/wake.
3915 //******************************************************************************
3916
3917 void
handlePublishSleepWakeUUID(bool shouldPublish)3918 IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
3919 {
3920 ASSERT_GATED();
3921
3922 /*
3923 * Clear the current UUID
3924 */
3925 if (gSleepWakeUUIDIsSet) {
3926 DLOG("SleepWake UUID cleared\n");
3927
3928 gSleepWakeUUIDIsSet = false;
3929
3930 removeProperty(kIOPMSleepWakeUUIDKey);
3931 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
3932 }
3933
3934 /*
3935 * Optionally, publish a new UUID
3936 */
3937 if (queuedSleepWakeUUIDString && shouldPublish) {
3938 OSSharedPtr<OSString> publishThisUUID;
3939
3940 publishThisUUID = queuedSleepWakeUUIDString;
3941
3942 if (publishThisUUID) {
3943 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID.get());
3944 }
3945
3946 gSleepWakeUUIDIsSet = true;
3947 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
3948
3949 queuedSleepWakeUUIDString.reset();
3950 }
3951 }
3952
3953 //******************************************************************************
3954 // IOPMGetSleepWakeUUIDKey
3955 //
3956 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3957 // To get the full key -- a C string -- the buffer must large enough for
3958 // the end-of-string character.
3959 // The key is expected to be an UUID string
3960 //******************************************************************************
3961
3962 extern "C" bool
IOPMCopySleepWakeUUIDKey(char * buffer,size_t buf_len)3963 IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len)
3964 {
3965 if (!gSleepWakeUUIDIsSet) {
3966 return false;
3967 }
3968
3969 if (buffer != NULL) {
3970 OSSharedPtr<OSString> string =
3971 OSDynamicPtrCast<OSString>(gRootDomain->copyProperty(kIOPMSleepWakeUUIDKey));
3972
3973 if (!string) {
3974 *buffer = '\0';
3975 } else {
3976 strlcpy(buffer, string->getCStringNoCopy(), buf_len);
3977 }
3978 }
3979
3980 return true;
3981 }
3982
3983 //******************************************************************************
3984 // lowLatencyAudioNotify
3985 //
3986 // Used to send an update about low latency audio activity to interested
3987 // clients. To keep the overhead minimal the OSDictionary used here
3988 // is initialized at boot.
3989 //******************************************************************************
3990
3991 void
lowLatencyAudioNotify(uint64_t time,boolean_t state)3992 IOPMrootDomain::lowLatencyAudioNotify(uint64_t time, boolean_t state)
3993 {
3994 if (lowLatencyAudioNotifierDict && lowLatencyAudioNotifyStateSym && lowLatencyAudioNotifyTimestampSym &&
3995 lowLatencyAudioNotifyStateVal && lowLatencyAudioNotifyTimestampVal) {
3996 lowLatencyAudioNotifyTimestampVal->setValue(time);
3997 lowLatencyAudioNotifyStateVal->setValue(state);
3998 setPMSetting(gIOPMSettingLowLatencyAudioModeKey.get(), lowLatencyAudioNotifierDict.get());
3999 } else {
4000 DLOG("LowLatencyAudioNotify error\n");
4001 }
4002 return;
4003 }
4004
4005 //******************************************************************************
4006 // IOPMrootDomainRTNotifier
4007 //
4008 // Used by performance controller to update the timestamp and state associated
4009 // with low latency audio activity in the system.
4010 //******************************************************************************
4011
4012 extern "C" void
IOPMrootDomainRTNotifier(uint64_t time,boolean_t state)4013 IOPMrootDomainRTNotifier(uint64_t time, boolean_t state)
4014 {
4015 gRootDomain->lowLatencyAudioNotify(time, state);
4016 return;
4017 }
4018
4019 //******************************************************************************
4020 // initializeBootSessionUUID
4021 //
4022 // Initialize the boot session uuid at boot up and sets it into registry.
4023 //******************************************************************************
4024
4025 void
initializeBootSessionUUID(void)4026 IOPMrootDomain::initializeBootSessionUUID(void)
4027 {
4028 uuid_t new_uuid;
4029 uuid_string_t new_uuid_string;
4030
4031 uuid_generate(new_uuid);
4032 uuid_unparse_upper(new_uuid, new_uuid_string);
4033 memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
4034
4035 setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
4036 }
4037
4038 //******************************************************************************
4039 // Root domain uses the private and tagged changePowerState methods for
4040 // tracking and logging purposes.
4041 //******************************************************************************
4042
4043 #define REQUEST_TAG_TO_REASON(x) ((uint16_t)x)
4044
4045 static uint32_t
nextRequestTag(IOPMRequestTag tag)4046 nextRequestTag( IOPMRequestTag tag )
4047 {
4048 static SInt16 msb16 = 1;
4049 uint16_t id = OSAddAtomic16(1, &msb16);
4050 return ((uint32_t)id << 16) | REQUEST_TAG_TO_REASON(tag);
4051 }
4052
4053 // TODO: remove this shim function and exported symbol
4054 IOReturn
changePowerStateTo(unsigned long ordinal)4055 IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
4056 {
4057 return changePowerStateWithTagTo(ordinal, kCPSReasonNone);
4058 }
4059
4060 // TODO: remove this shim function and exported symbol
4061 IOReturn
changePowerStateToPriv(unsigned long ordinal)4062 IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
4063 {
4064 return changePowerStateWithTagToPriv(ordinal, kCPSReasonNone);
4065 }
4066
4067 IOReturn
changePowerStateWithOverrideTo(IOPMPowerStateIndex ordinal,IOPMRequestTag reason)4068 IOPMrootDomain::changePowerStateWithOverrideTo(
4069 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
4070 {
4071 uint32_t tag = nextRequestTag(reason);
4072 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
4073
4074 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
4075 return kIOReturnUnsupported;
4076 }
4077
4078 return super::changePowerStateWithOverrideTo(ordinal, tag);
4079 }
4080
4081 IOReturn
changePowerStateWithTagTo(IOPMPowerStateIndex ordinal,IOPMRequestTag reason)4082 IOPMrootDomain::changePowerStateWithTagTo(
4083 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
4084 {
4085 uint32_t tag = nextRequestTag(reason);
4086 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
4087
4088 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
4089 return kIOReturnUnsupported;
4090 }
4091
4092 return super::changePowerStateWithTagTo(ordinal, tag);
4093 }
4094
4095 IOReturn
changePowerStateWithTagToPriv(IOPMPowerStateIndex ordinal,IOPMRequestTag reason)4096 IOPMrootDomain::changePowerStateWithTagToPriv(
4097 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
4098 {
4099 uint32_t tag = nextRequestTag(reason);
4100 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
4101
4102 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
4103 return kIOReturnUnsupported;
4104 }
4105
4106 return super::changePowerStateWithTagToPriv(ordinal, tag);
4107 }
4108
4109 //******************************************************************************
4110 // activity detect
4111 //
4112 //******************************************************************************
4113
4114 bool
activitySinceSleep(void)4115 IOPMrootDomain::activitySinceSleep(void)
4116 {
4117 return userActivityCount != userActivityAtSleep;
4118 }
4119
4120 bool
abortHibernation(void)4121 IOPMrootDomain::abortHibernation(void)
4122 {
4123 #if __arm64__
4124 // don't allow hibernation to be aborted on ARM due to user activity
4125 // since once ApplePMGR decides we're hibernating, we can't turn back
4126 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
4127 return false;
4128 #else
4129 bool ret = activitySinceSleep();
4130
4131 if (ret && !hibernateAborted && checkSystemCanSustainFullWake()) {
4132 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
4133 hibernateAborted = true;
4134 }
4135 return ret;
4136 #endif
4137 }
4138
4139 extern "C" int
hibernate_should_abort(void)4140 hibernate_should_abort(void)
4141 {
4142 if (gRootDomain) {
4143 return gRootDomain->abortHibernation();
4144 } else {
4145 return 0;
4146 }
4147 }
4148
4149 //******************************************************************************
4150 // willNotifyPowerChildren
4151 //
4152 // Called after all interested drivers have all acknowledged the power change,
4153 // but before any power children is informed. Dispatched though a thread call,
4154 // so it is safe to perform work that might block on a sleeping disk. PM state
4155 // machine (not thread) will block w/o timeout until this function returns.
4156 //******************************************************************************
4157
4158 void
willNotifyPowerChildren(IOPMPowerStateIndex newPowerState)4159 IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
4160 {
4161 OSSharedPtr<OSDictionary> dict;
4162 OSSharedPtr<OSNumber> secs;
4163
4164 if (SLEEP_STATE == newPowerState) {
4165 notifierThread = current_thread();
4166 if (updateTasksSuspend(kTasksSuspendSuspended, kTasksSuspendNoChange)) {
4167 AbsoluteTime deadline;
4168
4169 clock_interval_to_deadline(10, kSecondScale, &deadline);
4170 #if defined(XNU_TARGET_OS_OSX)
4171 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
4172 #endif /* defined(XNU_TARGET_OS_OSX) */
4173 }
4174
4175 _aotReadyToFullWake = false;
4176 #if 0
4177 if (_aotLingerTime) {
4178 uint64_t deadline;
4179 IOLog("aot linger no return\n");
4180 clock_absolutetime_interval_to_deadline(_aotLingerTime, &deadline);
4181 clock_delay_until(deadline);
4182 }
4183 #endif
4184 if (!_aotMode) {
4185 _aotTestTime = 0;
4186 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
4187 _aotLastWakeTime = 0;
4188 if (_aotMetrics) {
4189 bzero(_aotMetrics, sizeof(IOPMAOTMetrics));
4190 }
4191 } else if (!_aotNow && !_debugWakeSeconds) {
4192 _aotNow = true;
4193 _aotPendingFlags = 0;
4194 _aotTasksSuspended = true;
4195 _aotLastWakeTime = 0;
4196 bzero(_aotMetrics, sizeof(IOPMAOTMetrics));
4197 if (kIOPMAOTModeCycle & _aotMode) {
4198 clock_interval_to_absolutetime_interval(60, kSecondScale, &_aotTestInterval);
4199 _aotTestTime = mach_continuous_time() + _aotTestInterval;
4200 setWakeTime(_aotTestTime);
4201 }
4202 uint32_t lingerSecs;
4203 if (!PE_parse_boot_argn("aotlinger", &lingerSecs, sizeof(lingerSecs))) {
4204 lingerSecs = 0;
4205 }
4206 clock_interval_to_absolutetime_interval(lingerSecs, kSecondScale, &_aotLingerTime);
4207 clock_interval_to_absolutetime_interval(2000, kMillisecondScale, &_aotWakePreWindow);
4208 clock_interval_to_absolutetime_interval(1100, kMillisecondScale, &_aotWakePostWindow);
4209 }
4210
4211 #if HIBERNATION
4212 IOHibernateSystemSleep();
4213 IOHibernateIOKitSleep();
4214 #endif
4215 if (gRootDomain->activitySinceSleep()) {
4216 dict = OSDictionary::withCapacity(1);
4217 secs = OSNumber::withNumber(1, 32);
4218
4219 if (dict && secs) {
4220 dict->setObject(gIOPMSettingDebugWakeRelativeKey.get(), secs.get());
4221 gRootDomain->setProperties(dict.get());
4222 MSG("Reverting sleep with relative wake\n");
4223 }
4224 }
4225
4226 notifierThread = NULL;
4227 }
4228 }
4229
4230 //******************************************************************************
4231 // willTellSystemCapabilityDidChange
4232 //
4233 // IOServicePM calls this from OurChangeTellCapabilityDidChange() when root
4234 // domain is raising its power state, immediately after notifying interested
4235 // drivers and power children.
4236 //******************************************************************************
4237
4238 void
willTellSystemCapabilityDidChange(void)4239 IOPMrootDomain::willTellSystemCapabilityDidChange( void )
4240 {
4241 if ((_systemTransitionType == kSystemTransitionWake) &&
4242 !CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
4243 // After powering up drivers, dark->full promotion on the current wake
4244 // transition is no longer possible. That is because the next machine
4245 // state will issue the system capability change messages.
4246 // The darkWakePowerClamped flag may already be set if the system has
4247 // at least one driver that was power clamped due to dark wake.
4248 // This function sets the darkWakePowerClamped flag in case there
4249 // is no power-clamped driver in the system.
4250 //
4251 // Last opportunity to exit dark wake using:
4252 // requestFullWake( kFullWakeReasonLocalUser );
4253
4254 if (!darkWakePowerClamped) {
4255 if (darkWakeLogClamp) {
4256 AbsoluteTime now;
4257 uint64_t nsec;
4258
4259 clock_get_uptime(&now);
4260 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
4261 absolutetime_to_nanoseconds(now, &nsec);
4262 DLOG("dark wake promotion disabled at %u ms\n",
4263 ((int)((nsec) / NSEC_PER_MSEC)));
4264 }
4265 darkWakePowerClamped = true;
4266 }
4267 }
4268 }
4269
4270 //******************************************************************************
4271 // sleepOnClamshellClosed
4272 //
4273 // contains the logic to determine if the system should sleep when the clamshell
4274 // is closed.
4275 //******************************************************************************
4276
4277 bool
shouldSleepOnClamshellClosed(void)4278 IOPMrootDomain::shouldSleepOnClamshellClosed( void )
4279 {
4280 if (!clamshellExists) {
4281 return false;
4282 }
4283
4284 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4285 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
4286
4287 return !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisableMask;
4288 }
4289
4290 bool
shouldSleepOnRTCAlarmWake(void)4291 IOPMrootDomain::shouldSleepOnRTCAlarmWake( void )
4292 {
4293 // Called once every RTC/Alarm wake. Device should go to sleep if on clamshell
4294 // closed && battery
4295 if (!clamshellExists) {
4296 return false;
4297 }
4298
4299 DLOG("shouldSleepOnRTCAlarmWake: clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4300 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
4301
4302 return !acAdaptorConnected && !clamshellSleepDisableMask;
4303 }
4304
4305 void
sendClientClamshellNotification(void)4306 IOPMrootDomain::sendClientClamshellNotification( void )
4307 {
4308 /* Only broadcast clamshell alert if clamshell exists. */
4309 if (!clamshellExists) {
4310 return;
4311 }
4312
4313 setProperty(kAppleClamshellStateKey,
4314 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
4315
4316 setProperty(kAppleClamshellCausesSleepKey,
4317 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
4318
4319 /* Argument to message is a bitfiel of
4320 * ( kClamshellStateBit | kClamshellSleepBit )
4321 */
4322 messageClients(kIOPMMessageClamshellStateChange,
4323 (void *)(uintptr_t) ((clamshellClosed ? kClamshellStateBit : 0)
4324 | (shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)));
4325 }
4326
4327 //******************************************************************************
4328 // getSleepSupported
4329 //
4330 // Deprecated
4331 //******************************************************************************
4332
4333 IOOptionBits
getSleepSupported(void)4334 IOPMrootDomain::getSleepSupported( void )
4335 {
4336 return platformSleepSupport;
4337 }
4338
4339 //******************************************************************************
4340 // setSleepSupported
4341 //
4342 // Deprecated
4343 //******************************************************************************
4344
4345 void
setSleepSupported(IOOptionBits flags)4346 IOPMrootDomain::setSleepSupported( IOOptionBits flags )
4347 {
4348 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
4349 OSBitOrAtomic(flags, &platformSleepSupport);
4350 }
4351
4352 //******************************************************************************
4353 // setClamShellSleepDisable
4354 //
4355 //******************************************************************************
4356
4357 void
setClamShellSleepDisable(bool disable,uint32_t bitmask)4358 IOPMrootDomain::setClamShellSleepDisable( bool disable, uint32_t bitmask )
4359 {
4360 uint32_t oldMask;
4361
4362 // User client calls this in non-gated context
4363 if (gIOPMWorkLoop->inGate() == false) {
4364 gIOPMWorkLoop->runAction(
4365 OSMemberFunctionCast(IOWorkLoop::Action, this,
4366 &IOPMrootDomain::setClamShellSleepDisable),
4367 (OSObject *) this,
4368 (void *) disable, (void *)(uintptr_t) bitmask);
4369 return;
4370 }
4371
4372 oldMask = clamshellSleepDisableMask;
4373 if (disable) {
4374 clamshellSleepDisableMask |= bitmask;
4375 } else {
4376 clamshellSleepDisableMask &= ~bitmask;
4377 }
4378 DLOG("setClamShellSleepDisable(%x->%x)\n", oldMask, clamshellSleepDisableMask);
4379
4380 if (clamshellExists && clamshellClosed &&
4381 (clamshellSleepDisableMask != oldMask) &&
4382 (clamshellSleepDisableMask == 0)) {
4383 handlePowerNotification(kLocalEvalClamshellCommand);
4384 }
4385 }
4386
4387 //******************************************************************************
4388 // wakeFromDoze
4389 //
4390 // Deprecated.
4391 //******************************************************************************
4392
4393 void
wakeFromDoze(void)4394 IOPMrootDomain::wakeFromDoze( void )
4395 {
4396 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
4397 }
4398
4399 //******************************************************************************
4400 // recordRTCAlarm
4401 //
4402 // Record the earliest scheduled RTC alarm to determine whether a RTC wake
4403 // should be a dark wake or a full wake. Both Maintenance and SleepService
4404 // alarms are dark wake, while AutoWake (WakeByCalendarDate) and DebugWake
4405 // (WakeRelativeToSleep) should trigger a full wake. Scheduled power-on
4406 // PMSettings are ignored.
4407 //
4408 // Caller serialized using settingsCtrlLock.
4409 //******************************************************************************
4410
4411 void
recordRTCAlarm(const OSSymbol * type,OSObject * object)4412 IOPMrootDomain::recordRTCAlarm(
4413 const OSSymbol *type,
4414 OSObject *object )
4415 {
4416 uint32_t previousAlarmMask = _scheduledAlarmMask;
4417
4418 if (type == gIOPMSettingDebugWakeRelativeKey) {
4419 OSNumber * n = OSDynamicCast(OSNumber, object);
4420 if (n) {
4421 // Debug wake has highest scheduling priority so it overrides any
4422 // pre-existing alarm.
4423 uint32_t debugSecs = n->unsigned32BitValue();
4424 _nextScheduledAlarmType.reset(type, OSRetain);
4425 _nextScheduledAlarmUTC = debugSecs;
4426
4427 _debugWakeSeconds = debugSecs;
4428 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarmMask);
4429 DLOG("next alarm (%s) in %u secs\n",
4430 type->getCStringNoCopy(), debugSecs);
4431 }
4432 } else if ((type == gIOPMSettingAutoWakeCalendarKey.get()) ||
4433 (type == gIOPMSettingMaintenanceWakeCalendarKey.get()) ||
4434 (type == gIOPMSettingSleepServiceWakeCalendarKey.get())) {
4435 OSData * data = OSDynamicCast(OSData, object);
4436 if (data && (data->getLength() == sizeof(IOPMCalendarStruct))) {
4437 const IOPMCalendarStruct * cs;
4438 bool replaceNextAlarm = false;
4439 clock_sec_t secs;
4440
4441 cs = (const IOPMCalendarStruct *) data->getBytesNoCopy();
4442 secs = IOPMConvertCalendarToSeconds(cs);
4443 DLOG("%s " YMDTF "\n", type->getCStringNoCopy(), YMDT(cs));
4444
4445 // Update the next scheduled alarm type
4446 if ((_nextScheduledAlarmType == NULL) ||
4447 ((_nextScheduledAlarmType != gIOPMSettingDebugWakeRelativeKey) &&
4448 (secs < _nextScheduledAlarmUTC))) {
4449 replaceNextAlarm = true;
4450 }
4451
4452 if (type == gIOPMSettingAutoWakeCalendarKey.get()) {
4453 if (cs->year) {
4454 _calendarWakeAlarmUTC = IOPMConvertCalendarToSeconds(cs);
4455 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarmMask);
4456 } else {
4457 // TODO: can this else-block be removed?
4458 _calendarWakeAlarmUTC = 0;
4459 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarmMask);
4460 }
4461 }
4462 if (type == gIOPMSettingMaintenanceWakeCalendarKey.get()) {
4463 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarmMask);
4464 }
4465 if (type == gIOPMSettingSleepServiceWakeCalendarKey.get()) {
4466 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarmMask);
4467 }
4468
4469 if (replaceNextAlarm) {
4470 _nextScheduledAlarmType.reset(type, OSRetain);
4471 _nextScheduledAlarmUTC = secs;
4472 DLOG("next alarm (%s) " YMDTF "\n", type->getCStringNoCopy(), YMDT(cs));
4473 }
4474 }
4475 }
4476
4477 if (_scheduledAlarmMask != previousAlarmMask) {
4478 DLOG("scheduled alarm mask 0x%x\n", (uint32_t) _scheduledAlarmMask);
4479 }
4480 }
4481
4482 // MARK: -
4483 // MARK: Features
4484
4485 //******************************************************************************
4486 // publishFeature
4487 //
4488 // Adds a new feature to the supported features dictionary
4489 //******************************************************************************
4490
4491 void
publishFeature(const char * feature)4492 IOPMrootDomain::publishFeature( const char * feature )
4493 {
4494 publishFeature(feature, kRD_AllPowerSources, NULL);
4495 }
4496
4497 //******************************************************************************
4498 // publishFeature (with supported power source specified)
4499 //
4500 // Adds a new feature to the supported features dictionary
4501 //******************************************************************************
4502
4503 void
publishFeature(const char * feature,uint32_t supportedWhere,uint32_t * uniqueFeatureID)4504 IOPMrootDomain::publishFeature(
4505 const char *feature,
4506 uint32_t supportedWhere,
4507 uint32_t *uniqueFeatureID)
4508 {
4509 static uint16_t next_feature_id = 500;
4510
4511 OSSharedPtr<OSNumber> new_feature_data;
4512 OSNumber *existing_feature = NULL;
4513 OSArray *existing_feature_arr_raw = NULL;
4514 OSSharedPtr<OSArray> existing_feature_arr;
4515 OSObject *osObj = NULL;
4516 uint32_t feature_value = 0;
4517
4518 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
4519
4520 if (!supportedWhere) {
4521 // Feature isn't supported anywhere!
4522 return;
4523 }
4524
4525 if (next_feature_id > 5000) {
4526 // Far, far too many features!
4527 return;
4528 }
4529
4530 if (featuresDictLock) {
4531 IOLockLock(featuresDictLock);
4532 }
4533
4534 OSSharedPtr<OSObject> origFeaturesProp = copyProperty(kRootDomainSupportedFeatures);
4535 OSDictionary *origFeatures = OSDynamicCast(OSDictionary, origFeaturesProp.get());
4536 OSSharedPtr<OSDictionary> features;
4537
4538 // Create new features dict if necessary
4539 if (origFeatures) {
4540 features = OSDictionary::withDictionary(origFeatures);
4541 } else {
4542 features = OSDictionary::withCapacity(1);
4543 }
4544
4545 // Create OSNumber to track new feature
4546
4547 next_feature_id += 1;
4548 if (uniqueFeatureID) {
4549 // We don't really mind if the calling kext didn't give us a place
4550 // to stash their unique id. Many kexts don't plan to unload, and thus
4551 // have no need to remove themselves later.
4552 *uniqueFeatureID = next_feature_id;
4553 }
4554
4555 feature_value = (uint32_t)next_feature_id;
4556 feature_value <<= 16;
4557 feature_value += supportedWhere;
4558
4559 new_feature_data = OSNumber::withNumber(
4560 (unsigned long long)feature_value, 32);
4561
4562 // Does features object already exist?
4563 if ((osObj = features->getObject(feature))) {
4564 if ((existing_feature = OSDynamicCast(OSNumber, osObj))) {
4565 // We need to create an OSArray to hold the now 2 elements.
4566 existing_feature_arr = OSArray::withObjects(
4567 (const OSObject **)&existing_feature, 1, 2);
4568 } else if ((existing_feature_arr_raw = OSDynamicCast(OSArray, osObj))) {
4569 // Add object to existing array
4570 existing_feature_arr = OSArray::withArray(
4571 existing_feature_arr_raw,
4572 existing_feature_arr_raw->getCount() + 1);
4573 }
4574
4575 if (existing_feature_arr) {
4576 existing_feature_arr->setObject(new_feature_data.get());
4577 features->setObject(feature, existing_feature_arr.get());
4578 }
4579 } else {
4580 // The easy case: no previously existing features listed. We simply
4581 // set the OSNumber at key 'feature' and we're on our way.
4582 features->setObject(feature, new_feature_data.get());
4583 }
4584
4585 setProperty(kRootDomainSupportedFeatures, features.get());
4586
4587 if (featuresDictLock) {
4588 IOLockUnlock(featuresDictLock);
4589 }
4590
4591 // Notify EnergySaver and all those in user space so they might
4592 // re-populate their feature specific UI
4593 if (pmPowerStateQueue) {
4594 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
4595 }
4596 }
4597
4598 //******************************************************************************
4599 // removePublishedFeature
4600 //
4601 // Removes previously published feature
4602 //******************************************************************************
4603
4604 IOReturn
removePublishedFeature(uint32_t removeFeatureID)4605 IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
4606 {
4607 IOReturn ret = kIOReturnError;
4608 uint32_t feature_value = 0;
4609 uint16_t feature_id = 0;
4610 bool madeAChange = false;
4611
4612 OSSymbol *dictKey = NULL;
4613 OSSharedPtr<OSCollectionIterator> dictIterator;
4614 OSArray *arrayMember = NULL;
4615 OSNumber *numberMember = NULL;
4616 OSObject *osObj = NULL;
4617 OSNumber *osNum = NULL;
4618 OSSharedPtr<OSArray> arrayMemberCopy;
4619
4620 if (kBadPMFeatureID == removeFeatureID) {
4621 return kIOReturnNotFound;
4622 }
4623
4624 if (featuresDictLock) {
4625 IOLockLock(featuresDictLock);
4626 }
4627
4628 OSSharedPtr<OSObject> origFeaturesProp = copyProperty(kRootDomainSupportedFeatures);
4629 OSDictionary *origFeatures = OSDynamicCast(OSDictionary, origFeaturesProp.get());
4630 OSSharedPtr<OSDictionary> features;
4631
4632 if (origFeatures) {
4633 // Any modifications to the dictionary are made to the copy to prevent
4634 // races & crashes with userland clients. Dictionary updated
4635 // automically later.
4636 features = OSDictionary::withDictionary(origFeatures);
4637 } else {
4638 features = NULL;
4639 ret = kIOReturnNotFound;
4640 goto exit;
4641 }
4642
4643 // We iterate 'features' dictionary looking for an entry tagged
4644 // with 'removeFeatureID'. If found, we remove it from our tracking
4645 // structures and notify the OS via a general interest message.
4646
4647 dictIterator = OSCollectionIterator::withCollection(features.get());
4648 if (!dictIterator) {
4649 goto exit;
4650 }
4651
4652 while ((dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject()))) {
4653 osObj = features->getObject(dictKey);
4654
4655 // Each Feature is either tracked by an OSNumber
4656 if (osObj && (numberMember = OSDynamicCast(OSNumber, osObj))) {
4657 feature_value = numberMember->unsigned32BitValue();
4658 feature_id = (uint16_t)(feature_value >> 16);
4659
4660 if (feature_id == (uint16_t)removeFeatureID) {
4661 // Remove this node
4662 features->removeObject(dictKey);
4663 madeAChange = true;
4664 break;
4665 }
4666
4667 // Or tracked by an OSArray of OSNumbers
4668 } else if (osObj && (arrayMember = OSDynamicCast(OSArray, osObj))) {
4669 unsigned int arrayCount = arrayMember->getCount();
4670
4671 for (unsigned int i = 0; i < arrayCount; i++) {
4672 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
4673 if (!osNum) {
4674 continue;
4675 }
4676
4677 feature_value = osNum->unsigned32BitValue();
4678 feature_id = (uint16_t)(feature_value >> 16);
4679
4680 if (feature_id == (uint16_t)removeFeatureID) {
4681 // Remove this node
4682 if (1 == arrayCount) {
4683 // If the array only contains one element, remove
4684 // the whole thing.
4685 features->removeObject(dictKey);
4686 } else {
4687 // Otherwise remove the element from a copy of the array.
4688 arrayMemberCopy = OSArray::withArray(arrayMember);
4689 if (arrayMemberCopy) {
4690 arrayMemberCopy->removeObject(i);
4691 features->setObject(dictKey, arrayMemberCopy.get());
4692 }
4693 }
4694
4695 madeAChange = true;
4696 break;
4697 }
4698 }
4699 }
4700 }
4701
4702 if (madeAChange) {
4703 ret = kIOReturnSuccess;
4704
4705 setProperty(kRootDomainSupportedFeatures, features.get());
4706
4707 // Notify EnergySaver and all those in user space so they might
4708 // re-populate their feature specific UI
4709 if (pmPowerStateQueue) {
4710 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
4711 }
4712 } else {
4713 ret = kIOReturnNotFound;
4714 }
4715
4716 exit:
4717 if (featuresDictLock) {
4718 IOLockUnlock(featuresDictLock);
4719 }
4720 return ret;
4721 }
4722
4723 //******************************************************************************
4724 // publishPMSetting (private)
4725 //
4726 // Should only be called by PMSettingObject to publish a PM Setting as a
4727 // supported feature.
4728 //******************************************************************************
4729
4730 void
publishPMSetting(const OSSymbol * feature,uint32_t where,uint32_t * featureID)4731 IOPMrootDomain::publishPMSetting(
4732 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
4733 {
4734 if (noPublishPMSettings &&
4735 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1)) {
4736 // Setting found in noPublishPMSettings array
4737 *featureID = kBadPMFeatureID;
4738 return;
4739 }
4740
4741 publishFeature(
4742 feature->getCStringNoCopy(), where, featureID);
4743 }
4744
4745 //******************************************************************************
4746 // setPMSetting (private)
4747 //
4748 // Internal helper to relay PM settings changes from user space to individual
4749 // drivers. Should be called only by IOPMrootDomain::setProperties.
4750 //******************************************************************************
4751
4752 IOReturn
setPMSetting(const OSSymbol * type,OSObject * object)4753 IOPMrootDomain::setPMSetting(
4754 const OSSymbol *type,
4755 OSObject *object )
4756 {
4757 PMSettingCallEntry *entries = NULL;
4758 OSSharedPtr<OSArray> chosen;
4759 const OSArray *array;
4760 PMSettingObject *pmso;
4761 thread_t thisThread;
4762 int i, j, count, capacity;
4763 bool ok = false;
4764 IOReturn ret;
4765
4766 if (NULL == type) {
4767 return kIOReturnBadArgument;
4768 }
4769
4770 PMSETTING_LOCK();
4771
4772 // Update settings dict so changes are visible from copyPMSetting().
4773 fPMSettingsDict->setObject(type, object);
4774
4775 // Prep all PMSetting objects with the given 'type' for callout.
4776 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
4777 if (!array || ((capacity = array->getCount()) == 0)) {
4778 goto unlock_exit;
4779 }
4780
4781 // Array to retain PMSetting objects targeted for callout.
4782 chosen = OSArray::withCapacity(capacity);
4783 if (!chosen) {
4784 goto unlock_exit; // error
4785 }
4786 entries = IONew(PMSettingCallEntry, capacity);
4787 if (!entries) {
4788 goto unlock_exit; // error
4789 }
4790 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
4791
4792 thisThread = current_thread();
4793
4794 for (i = 0, j = 0; i < capacity; i++) {
4795 pmso = (PMSettingObject *) array->getObject(i);
4796 if (pmso->disabled) {
4797 continue;
4798 }
4799 entries[j].thread = thisThread;
4800 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
4801 chosen->setObject(pmso);
4802 j++;
4803 }
4804 count = j;
4805 if (!count) {
4806 goto unlock_exit;
4807 }
4808
4809 PMSETTING_UNLOCK();
4810
4811 // Call each pmso in the chosen array.
4812 for (i = 0; i < count; i++) {
4813 pmso = (PMSettingObject *) chosen->getObject(i);
4814 ret = pmso->dispatchPMSetting(type, object);
4815 if (ret == kIOReturnSuccess) {
4816 // At least one setting handler was successful
4817 ok = true;
4818 #if DEVELOPMENT || DEBUG
4819 } else {
4820 // Log the handler and kext that failed
4821 OSSharedPtr<const OSSymbol> kextName = copyKextIdentifierWithAddress((vm_address_t) pmso->func);
4822 if (kextName) {
4823 DLOG("PMSetting(%s) error 0x%x from %s\n",
4824 type->getCStringNoCopy(), ret, kextName->getCStringNoCopy());
4825 }
4826 #endif
4827 }
4828 }
4829
4830 PMSETTING_LOCK();
4831 for (i = 0; i < count; i++) {
4832 pmso = (PMSettingObject *) chosen->getObject(i);
4833 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
4834 if (pmso->waitThread) {
4835 PMSETTING_WAKEUP(pmso);
4836 }
4837 }
4838
4839 if (ok) {
4840 recordRTCAlarm(type, object);
4841 }
4842 unlock_exit:
4843 PMSETTING_UNLOCK();
4844
4845 if (entries) {
4846 IODelete(entries, PMSettingCallEntry, capacity);
4847 }
4848
4849 return kIOReturnSuccess;
4850 }
4851
4852 //******************************************************************************
4853 // copyPMSetting (public)
4854 //
4855 // Allows kexts to safely read setting values, without being subscribed to
4856 // notifications.
4857 //******************************************************************************
4858
4859 OSSharedPtr<OSObject>
copyPMSetting(OSSymbol * whichSetting)4860 IOPMrootDomain::copyPMSetting(
4861 OSSymbol *whichSetting)
4862 {
4863 OSSharedPtr<OSObject> obj;
4864
4865 if (!whichSetting) {
4866 return NULL;
4867 }
4868
4869 PMSETTING_LOCK();
4870 obj.reset(fPMSettingsDict->getObject(whichSetting), OSRetain);
4871 PMSETTING_UNLOCK();
4872
4873 return obj;
4874 }
4875
4876 //******************************************************************************
4877 // registerPMSettingController (public)
4878 //
4879 // direct wrapper to registerPMSettingController with uint32_t power source arg
4880 //******************************************************************************
4881
4882 IOReturn
registerPMSettingController(const OSSymbol * settings[],IOPMSettingControllerCallback func,OSObject * target,uintptr_t refcon,OSObject ** handle)4883 IOPMrootDomain::registerPMSettingController(
4884 const OSSymbol * settings[],
4885 IOPMSettingControllerCallback func,
4886 OSObject *target,
4887 uintptr_t refcon,
4888 OSObject **handle)
4889 {
4890 return registerPMSettingController(
4891 settings,
4892 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
4893 func, target, refcon, handle);
4894 }
4895
4896 //******************************************************************************
4897 // registerPMSettingController (public)
4898 //
4899 // Kexts may register for notifications when a particular setting is changed.
4900 // A list of settings is available in IOPM.h.
4901 // Arguments:
4902 // * settings - An OSArray containing OSSymbols. Caller should populate this
4903 // array with a list of settings caller wants notifications from.
4904 // * func - A C function callback of the type IOPMSettingControllerCallback
4905 // * target - caller may provide an OSObject *, which PM will pass as an
4906 // target to calls to "func"
4907 // * refcon - caller may provide an void *, which PM will pass as an
4908 // argument to calls to "func"
4909 // * handle - This is a return argument. We will populate this pointer upon
4910 // call success. Hold onto this and pass this argument to
4911 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
4912 // Returns:
4913 // kIOReturnSuccess on success
4914 //******************************************************************************
4915
4916 IOReturn
registerPMSettingController(const OSSymbol * settings[],uint32_t supportedPowerSources,IOPMSettingControllerCallback func,OSObject * target,uintptr_t refcon,OSObject ** handle)4917 IOPMrootDomain::registerPMSettingController(
4918 const OSSymbol * settings[],
4919 uint32_t supportedPowerSources,
4920 IOPMSettingControllerCallback func,
4921 OSObject *target,
4922 uintptr_t refcon,
4923 OSObject **handle)
4924 {
4925 PMSettingObject *pmso = NULL;
4926 OSObject *pmsh = NULL;
4927 int i;
4928
4929 if (NULL == settings ||
4930 NULL == func ||
4931 NULL == handle) {
4932 return kIOReturnBadArgument;
4933 }
4934
4935 pmso = PMSettingObject::pmSettingObject(
4936 (IOPMrootDomain *) this, func, target,
4937 refcon, supportedPowerSources, settings, &pmsh);
4938
4939 if (!pmso) {
4940 *handle = NULL;
4941 return kIOReturnInternalError;
4942 }
4943
4944 PMSETTING_LOCK();
4945 for (i = 0; settings[i]; i++) {
4946 OSSharedPtr<OSArray> newList;
4947 OSArray *list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
4948 if (!list) {
4949 // New array of callbacks for this setting
4950 newList = OSArray::withCapacity(1);
4951 settingsCallbacks->setObject(settings[i], newList.get());
4952 list = newList.get();
4953 }
4954
4955 // Add caller to the callback list
4956 list->setObject(pmso);
4957 }
4958 PMSETTING_UNLOCK();
4959
4960 // Return handle to the caller, the setting object is private.
4961 *handle = pmsh;
4962
4963 return kIOReturnSuccess;
4964 }
4965
4966 //******************************************************************************
4967 // deregisterPMSettingObject (private)
4968 //
4969 // Only called from PMSettingObject.
4970 //******************************************************************************
4971
4972 void
deregisterPMSettingObject(PMSettingObject * pmso)4973 IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
4974 {
4975 thread_t thisThread = current_thread();
4976 PMSettingCallEntry *callEntry;
4977 OSSharedPtr<OSCollectionIterator> iter;
4978 OSSymbol *sym;
4979 OSArray *array;
4980 int index;
4981 bool wait;
4982
4983 PMSETTING_LOCK();
4984
4985 pmso->disabled = true;
4986
4987 // Wait for all callout threads to finish.
4988 do {
4989 wait = false;
4990 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
4991 {
4992 if (callEntry->thread != thisThread) {
4993 wait = true;
4994 break;
4995 }
4996 }
4997 if (wait) {
4998 assert(NULL == pmso->waitThread);
4999 pmso->waitThread = thisThread;
5000 PMSETTING_WAIT(pmso);
5001 pmso->waitThread = NULL;
5002 }
5003 } while (wait);
5004
5005 // Search each PM settings array in the kernel.
5006 iter = OSCollectionIterator::withCollection(settingsCallbacks.get());
5007 if (iter) {
5008 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
5009 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
5010 index = array->getNextIndexOfObject(pmso, 0);
5011 if (-1 != index) {
5012 array->removeObject(index);
5013 }
5014 }
5015 }
5016
5017 PMSETTING_UNLOCK();
5018
5019 pmso->release();
5020 }
5021
5022 //******************************************************************************
5023 // informCPUStateChange
5024 //
5025 // Call into PM CPU code so that CPU power savings may dynamically adjust for
5026 // running on battery, with the lid closed, etc.
5027 //
5028 // informCPUStateChange is a no-op on non x86 systems
5029 // only x86 has explicit support in the IntelCPUPowerManagement kext
5030 //******************************************************************************
5031
5032 void
informCPUStateChange(uint32_t type,uint32_t value)5033 IOPMrootDomain::informCPUStateChange(
5034 uint32_t type,
5035 uint32_t value )
5036 {
5037 #if defined(__i386__) || defined(__x86_64__)
5038
5039 pmioctlVariableInfo_t varInfoStruct;
5040 int pmCPUret = 0;
5041 const char *varNameStr = NULL;
5042 int32_t *varIndex = NULL;
5043
5044 if (kInformAC == type) {
5045 varNameStr = kIOPMRootDomainBatPowerCString;
5046 varIndex = &idxPMCPULimitedPower;
5047 } else if (kInformLid == type) {
5048 varNameStr = kIOPMRootDomainLidCloseCString;
5049 varIndex = &idxPMCPUClamshell;
5050 } else {
5051 return;
5052 }
5053
5054 // Set the new value!
5055 // pmCPUControl will assign us a new ID if one doesn't exist yet
5056 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
5057 varInfoStruct.varID = *varIndex;
5058 varInfoStruct.varType = vBool;
5059 varInfoStruct.varInitValue = value;
5060 varInfoStruct.varCurValue = value;
5061 strlcpy((char *)varInfoStruct.varName,
5062 (const char *)varNameStr,
5063 sizeof(varInfoStruct.varName));
5064
5065 // Set!
5066 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
5067
5068 // pmCPU only assigns numerical id's when a new varName is specified
5069 if ((0 == pmCPUret)
5070 && (*varIndex == kCPUUnknownIndex)) {
5071 // pmCPUControl has assigned us a new variable ID.
5072 // Let's re-read the structure we just SET to learn that ID.
5073 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
5074
5075 if (0 == pmCPUret) {
5076 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
5077 *varIndex = varInfoStruct.varID;
5078 }
5079 }
5080
5081 return;
5082
5083 #endif /* __i386__ || __x86_64__ */
5084 }
5085
5086 // MARK: -
5087 // MARK: Deep Sleep Policy
5088
5089 #if HIBERNATION
5090
5091 //******************************************************************************
5092 // evaluateSystemSleepPolicy
5093 //******************************************************************************
5094
5095 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
5096
5097 // Sleep flags
5098 enum {
5099 kIOPMSleepFlagHibernate = 0x00000001,
5100 kIOPMSleepFlagSleepTimerEnable = 0x00000002
5101 };
5102
5103 struct IOPMSystemSleepPolicyEntry {
5104 uint32_t factorMask;
5105 uint32_t factorBits;
5106 uint32_t sleepFlags;
5107 uint32_t wakeEvents;
5108 } __attribute__((packed));
5109
5110 struct IOPMSystemSleepPolicyTable {
5111 uint32_t signature;
5112 uint16_t version;
5113 uint16_t entryCount;
5114 IOPMSystemSleepPolicyEntry entries[];
5115 } __attribute__((packed));
5116
5117 enum {
5118 kIOPMSleepAttributeHibernateSetup = 0x00000001,
5119 kIOPMSleepAttributeHibernateSleep = 0x00000002
5120 };
5121
5122 static uint32_t
getSleepTypeAttributes(uint32_t sleepType)5123 getSleepTypeAttributes( uint32_t sleepType )
5124 {
5125 static const uint32_t sleepTypeAttributes[kIOPMSleepTypeLast] =
5126 {
5127 /* invalid */ 0,
5128 /* abort */ 0,
5129 /* normal */ 0,
5130 /* safesleep */ kIOPMSleepAttributeHibernateSetup,
5131 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5132 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5133 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5134 /* deepidle */ 0
5135 };
5136
5137 if (sleepType >= kIOPMSleepTypeLast) {
5138 return 0;
5139 }
5140
5141 return sleepTypeAttributes[sleepType];
5142 }
5143
5144 bool
evaluateSystemSleepPolicy(IOPMSystemSleepParameters * params,int sleepPhase,uint32_t * hibMode)5145 IOPMrootDomain::evaluateSystemSleepPolicy(
5146 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
5147 {
5148 #define SLEEP_FACTOR(x) {(uint32_t) kIOPMSleepFactor ## x, #x}
5149
5150 static const IONamedValue factorValues[] = {
5151 SLEEP_FACTOR( SleepTimerWake ),
5152 SLEEP_FACTOR( LidOpen ),
5153 SLEEP_FACTOR( ACPower ),
5154 SLEEP_FACTOR( BatteryLow ),
5155 SLEEP_FACTOR( StandbyNoDelay ),
5156 SLEEP_FACTOR( StandbyForced ),
5157 SLEEP_FACTOR( StandbyDisabled ),
5158 SLEEP_FACTOR( USBExternalDevice ),
5159 SLEEP_FACTOR( BluetoothHIDDevice ),
5160 SLEEP_FACTOR( ExternalMediaMounted ),
5161 SLEEP_FACTOR( ThunderboltDevice ),
5162 SLEEP_FACTOR( RTCAlarmScheduled ),
5163 SLEEP_FACTOR( MagicPacketWakeEnabled ),
5164 SLEEP_FACTOR( HibernateForced ),
5165 SLEEP_FACTOR( AutoPowerOffDisabled ),
5166 SLEEP_FACTOR( AutoPowerOffForced ),
5167 SLEEP_FACTOR( ExternalDisplay ),
5168 SLEEP_FACTOR( NetworkKeepAliveActive ),
5169 SLEEP_FACTOR( LocalUserActivity ),
5170 SLEEP_FACTOR( HibernateFailed ),
5171 SLEEP_FACTOR( ThermalWarning ),
5172 SLEEP_FACTOR( DisplayCaptured ),
5173 { 0, NULL }
5174 };
5175
5176 const IOPMSystemSleepPolicyTable * pt;
5177 OSSharedPtr<OSObject> prop;
5178 OSData * policyData;
5179 uint64_t currentFactors = 0;
5180 char currentFactorsBuf[512];
5181 uint32_t standbyDelay = 0;
5182 uint32_t powerOffDelay = 0;
5183 uint32_t powerOffTimer = 0;
5184 uint32_t standbyTimer = 0;
5185 uint32_t mismatch;
5186 bool standbyEnabled;
5187 bool powerOffEnabled;
5188 bool found = false;
5189
5190 // Get platform's sleep policy table
5191 if (!gSleepPolicyHandler) {
5192 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
5193 if (!prop) {
5194 goto done;
5195 }
5196 }
5197
5198 // Fetch additional settings
5199 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
5200 && propertyHasValue(kIOPMDeepSleepEnabledKey, kOSBooleanTrue));
5201 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
5202 && propertyHasValue(kIOPMAutoPowerOffEnabledKey, kOSBooleanTrue));
5203 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer)) {
5204 powerOffTimer = powerOffDelay;
5205 }
5206 if (!getSleepOption(kIOPMDeepSleepTimerKey, &standbyTimer)) {
5207 standbyTimer = standbyDelay;
5208 }
5209
5210 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
5211 sleepPhase, standbyEnabled, standbyDelay, standbyTimer,
5212 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
5213
5214 currentFactorsBuf[0] = 0;
5215 // pmset level overrides
5216 if ((*hibMode & kIOHibernateModeOn) == 0) {
5217 if (!gSleepPolicyHandler) {
5218 standbyEnabled = false;
5219 powerOffEnabled = false;
5220 }
5221 } else if (!(*hibMode & kIOHibernateModeSleep)) {
5222 // Force hibernate (i.e. mode 25)
5223 // If standby is enabled, force standy.
5224 // If poweroff is enabled, force poweroff.
5225 if (standbyEnabled) {
5226 currentFactors |= kIOPMSleepFactorStandbyForced;
5227 } else if (powerOffEnabled) {
5228 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
5229 } else {
5230 currentFactors |= kIOPMSleepFactorHibernateForced;
5231 }
5232 }
5233
5234 // Current factors based on environment and assertions
5235 if (sleepTimerMaintenance) {
5236 currentFactors |= kIOPMSleepFactorSleepTimerWake;
5237 }
5238 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler) {
5239 currentFactors |= kIOPMSleepFactorSleepTimerWake;
5240 }
5241 if (!clamshellClosed) {
5242 currentFactors |= kIOPMSleepFactorLidOpen;
5243 }
5244 if (acAdaptorConnected) {
5245 currentFactors |= kIOPMSleepFactorACPower;
5246 }
5247 if (lowBatteryCondition) {
5248 hibernateMode = 0;
5249 getSleepOption(kIOHibernateModeKey, &hibernateMode);
5250 if ((hibernateMode & kIOHibernateModeOn) == 0) {
5251 DLOG("HibernateMode is 0. Not sending LowBattery factor to IOPPF\n");
5252 } else {
5253 currentFactors |= kIOPMSleepFactorBatteryLow;
5254 }
5255 }
5256 if (!standbyDelay || !standbyTimer) {
5257 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
5258 }
5259 if (standbyNixed || !standbyEnabled) {
5260 currentFactors |= kIOPMSleepFactorStandbyDisabled;
5261 }
5262 if (resetTimers) {
5263 currentFactors |= kIOPMSleepFactorLocalUserActivity;
5264 currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
5265 }
5266 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
5267 kIOPMDriverAssertionLevelOff) {
5268 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
5269 }
5270 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
5271 kIOPMDriverAssertionLevelOff) {
5272 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
5273 }
5274 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
5275 kIOPMDriverAssertionLevelOff) {
5276 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
5277 }
5278 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
5279 kIOPMDriverAssertionLevelOff) {
5280 currentFactors |= kIOPMSleepFactorThunderboltDevice;
5281 }
5282 if (_scheduledAlarmMask != 0) {
5283 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
5284 }
5285 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
5286 kIOPMDriverAssertionLevelOff) {
5287 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
5288 }
5289 #define TCPKEEPALIVE 1
5290 #if TCPKEEPALIVE
5291 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
5292 kIOPMDriverAssertionLevelOff) {
5293 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
5294 }
5295 #endif
5296 if (!powerOffEnabled) {
5297 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
5298 }
5299 if (desktopMode) {
5300 currentFactors |= kIOPMSleepFactorExternalDisplay;
5301 }
5302 if (userWasActive) {
5303 currentFactors |= kIOPMSleepFactorLocalUserActivity;
5304 }
5305 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
5306 currentFactors |= kIOPMSleepFactorHibernateFailed;
5307 }
5308 if (thermalWarningState) {
5309 currentFactors |= kIOPMSleepFactorThermalWarning;
5310 }
5311
5312 for (int factorBit = 0; factorBit < (8 * sizeof(uint32_t)); factorBit++) {
5313 uint32_t factor = 1 << factorBit;
5314 if (factor & currentFactors) {
5315 strlcat(currentFactorsBuf, ", ", sizeof(currentFactorsBuf));
5316 strlcat(currentFactorsBuf, IOFindNameForValue(factor, factorValues), sizeof(currentFactorsBuf));
5317 }
5318 }
5319 DLOG("sleep factors 0x%llx%s\n", currentFactors, currentFactorsBuf);
5320
5321 if (gSleepPolicyHandler) {
5322 uint32_t savedHibernateMode;
5323 IOReturn result;
5324
5325 if (!gSleepPolicyVars) {
5326 gSleepPolicyVars = IOMallocType(IOPMSystemSleepPolicyVariables);
5327 }
5328 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
5329 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
5330 gSleepPolicyVars->currentCapability = _currentCapability;
5331 gSleepPolicyVars->highestCapability = _highestCapability;
5332 gSleepPolicyVars->sleepFactors = currentFactors;
5333 gSleepPolicyVars->sleepReason = lastSleepReason;
5334 gSleepPolicyVars->sleepPhase = sleepPhase;
5335 gSleepPolicyVars->standbyDelay = standbyDelay;
5336 gSleepPolicyVars->standbyTimer = standbyTimer;
5337 gSleepPolicyVars->poweroffDelay = powerOffDelay;
5338 gSleepPolicyVars->scheduledAlarms = _scheduledAlarmMask | _userScheduledAlarmMask;
5339 gSleepPolicyVars->poweroffTimer = powerOffTimer;
5340
5341 if (kIOPMSleepPhase0 == sleepPhase) {
5342 // preserve hibernateMode
5343 savedHibernateMode = gSleepPolicyVars->hibernateMode;
5344 gSleepPolicyVars->hibernateMode = *hibMode;
5345 } else if (kIOPMSleepPhase1 == sleepPhase) {
5346 // use original hibernateMode for phase2
5347 gSleepPolicyVars->hibernateMode = *hibMode;
5348 }
5349
5350 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
5351
5352 if (kIOPMSleepPhase0 == sleepPhase) {
5353 // restore hibernateMode
5354 gSleepPolicyVars->hibernateMode = savedHibernateMode;
5355 }
5356
5357 if ((result != kIOReturnSuccess) ||
5358 (kIOPMSleepTypeInvalid == params->sleepType) ||
5359 (params->sleepType >= kIOPMSleepTypeLast) ||
5360 (kIOPMSystemSleepParametersVersion != params->version)) {
5361 MSG("sleep policy handler error\n");
5362 goto done;
5363 }
5364
5365 if ((getSleepTypeAttributes(params->sleepType) &
5366 kIOPMSleepAttributeHibernateSetup) &&
5367 ((*hibMode & kIOHibernateModeOn) == 0)) {
5368 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
5369 }
5370
5371 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
5372 params->version, params->sleepType, params->sleepFlags,
5373 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
5374 found = true;
5375 goto done;
5376 }
5377
5378 // Policy table is meaningless without standby enabled
5379 if (!standbyEnabled) {
5380 goto done;
5381 }
5382
5383 // Validate the sleep policy table
5384 policyData = OSDynamicCast(OSData, prop.get());
5385 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable))) {
5386 goto done;
5387 }
5388
5389 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
5390 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
5391 (pt->version != 1) || (0 == pt->entryCount)) {
5392 goto done;
5393 }
5394
5395 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
5396 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))) {
5397 goto done;
5398 }
5399
5400 for (uint32_t i = 0; i < pt->entryCount; i++) {
5401 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
5402 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
5403
5404 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
5405 entry->factorMask, entry->factorBits,
5406 entry->sleepFlags, entry->wakeEvents, mismatch);
5407 if (mismatch) {
5408 continue;
5409 }
5410
5411 DLOG("^ found match\n");
5412 found = true;
5413
5414 params->version = kIOPMSystemSleepParametersVersion;
5415 params->reserved1 = 1;
5416 if (entry->sleepFlags & kIOPMSleepFlagHibernate) {
5417 params->sleepType = kIOPMSleepTypeStandby;
5418 } else {
5419 params->sleepType = kIOPMSleepTypeNormalSleep;
5420 }
5421
5422 params->ecWakeEvents = entry->wakeEvents;
5423 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable) {
5424 if (kIOPMSleepPhase2 == sleepPhase) {
5425 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
5426
5427 if (!_standbyTimerResetSeconds ||
5428 (now_secs <= _standbyTimerResetSeconds)) {
5429 // Reset standby timer adjustment
5430 _standbyTimerResetSeconds = now_secs;
5431 DLOG("standby delay %u, reset %u\n",
5432 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
5433 } else if (standbyDelay) {
5434 // Shorten the standby delay timer
5435 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
5436 if (standbyDelay > elapsed) {
5437 standbyDelay -= elapsed;
5438 } else {
5439 standbyDelay = 1; // must be > 0
5440 }
5441 DLOG("standby delay %u, elapsed %u\n",
5442 standbyDelay, (uint32_t) elapsed);
5443 }
5444 }
5445 params->ecWakeTimer = standbyDelay;
5446 } else if (kIOPMSleepPhase2 == sleepPhase) {
5447 // A sleep that does not enable the sleep timer will reset
5448 // the standby delay adjustment.
5449 _standbyTimerResetSeconds = 0;
5450 }
5451 break;
5452 }
5453
5454 done:
5455 return found;
5456 }
5457
5458 static IOPMSystemSleepParameters gEarlySystemSleepParams;
5459
5460 void
evaluateSystemSleepPolicyEarly(void)5461 IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
5462 {
5463 // Evaluate early (priority interest phase), before drivers sleep.
5464
5465 DLOG("%s\n", __FUNCTION__);
5466 removeProperty(kIOPMSystemSleepParametersKey);
5467
5468 // Full wake resets the standby timer delay adjustment
5469 if (_highestCapability & kIOPMSystemCapabilityGraphics) {
5470 _standbyTimerResetSeconds = 0;
5471 }
5472
5473 hibernateDisabled = false;
5474 hibernateMode = 0;
5475 getSleepOption(kIOHibernateModeKey, &hibernateMode);
5476
5477 // Save for late evaluation if sleep is aborted
5478 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
5479
5480 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
5481 &hibernateMode)) {
5482 if (!hibernateRetry &&
5483 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
5484 kIOPMSleepAttributeHibernateSetup) == 0)) {
5485 // skip hibernate setup
5486 hibernateDisabled = true;
5487 }
5488 }
5489
5490 // Publish IOPMSystemSleepType
5491 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
5492 if (sleepType == kIOPMSleepTypeInvalid) {
5493 // no sleep policy
5494 sleepType = kIOPMSleepTypeNormalSleep;
5495 if (hibernateMode & kIOHibernateModeOn) {
5496 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
5497 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
5498 }
5499 } else if ((sleepType == kIOPMSleepTypeStandby) &&
5500 (gEarlySystemSleepParams.ecPoweroffTimer)) {
5501 // report the lowest possible sleep state
5502 sleepType = kIOPMSleepTypePowerOff;
5503 }
5504
5505 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
5506 }
5507
5508 void
evaluateSystemSleepPolicyFinal(void)5509 IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
5510 {
5511 IOPMSystemSleepParameters params;
5512 OSSharedPtr<OSData> paramsData;
5513 bool wakeNow;
5514 // Evaluate sleep policy after sleeping drivers but before platform sleep.
5515
5516 DLOG("%s\n", __FUNCTION__);
5517
5518 bzero(¶ms, sizeof(params));
5519 wakeNow = false;
5520 if (evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase2, &hibernateMode)) {
5521 if ((kIOPMSleepTypeStandby == params.sleepType)
5522 && gIOHibernateStandbyDisabled && gSleepPolicyVars
5523 && (!((kIOPMSleepFactorStandbyForced | kIOPMSleepFactorAutoPowerOffForced | kIOPMSleepFactorHibernateForced)
5524 & gSleepPolicyVars->sleepFactors))) {
5525 standbyNixed = true;
5526 wakeNow = true;
5527 }
5528 if (wakeNow
5529 || ((hibernateDisabled || hibernateAborted) &&
5530 (getSleepTypeAttributes(params.sleepType) &
5531 kIOPMSleepAttributeHibernateSetup))) {
5532 // Final evaluation picked a state requiring hibernation,
5533 // but hibernate isn't going to proceed. Arm a short sleep using
5534 // the early non-hibernate sleep parameters.
5535 bcopy(&gEarlySystemSleepParams, ¶ms, sizeof(params));
5536 params.sleepType = kIOPMSleepTypeAbortedSleep;
5537 params.ecWakeTimer = 1;
5538 if (standbyNixed) {
5539 resetTimers = true;
5540 } else {
5541 // Set hibernateRetry flag to force hibernate setup on the
5542 // next sleep.
5543 hibernateRetry = true;
5544 }
5545 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
5546 params.ecWakeTimer, hibernateDisabled, hibernateAborted, standbyNixed);
5547 } else {
5548 hibernateRetry = false;
5549 }
5550
5551 if (kIOPMSleepTypeAbortedSleep != params.sleepType) {
5552 resetTimers = false;
5553 }
5554
5555 paramsData = OSData::withValue(params);
5556 if (paramsData) {
5557 setProperty(kIOPMSystemSleepParametersKey, paramsData.get());
5558 }
5559
5560 if (getSleepTypeAttributes(params.sleepType) &
5561 kIOPMSleepAttributeHibernateSleep) {
5562 // Disable sleep to force hibernation
5563 gIOHibernateMode &= ~kIOHibernateModeSleep;
5564 }
5565 }
5566 }
5567
5568 bool
getHibernateSettings(uint32_t * hibernateModePtr,uint32_t * hibernateFreeRatio,uint32_t * hibernateFreeTime)5569 IOPMrootDomain::getHibernateSettings(
5570 uint32_t * hibernateModePtr,
5571 uint32_t * hibernateFreeRatio,
5572 uint32_t * hibernateFreeTime )
5573 {
5574 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
5575 // has updated the hibernateDisabled flag.
5576
5577 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
5578 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
5579 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
5580 if (hibernateDisabled) {
5581 *hibernateModePtr = 0;
5582 } else if (gSleepPolicyHandler) {
5583 *hibernateModePtr = hibernateMode;
5584 }
5585 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
5586 return ok;
5587 }
5588
5589 bool
getSleepOption(const char * key,uint32_t * option)5590 IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
5591 {
5592 OSSharedPtr<OSObject> optionsProp;
5593 OSDictionary * optionsDict;
5594 OSSharedPtr<OSObject> obj;
5595 OSNumber * num;
5596 bool ok = false;
5597
5598 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
5599 optionsDict = OSDynamicCast(OSDictionary, optionsProp.get());
5600
5601 if (optionsDict) {
5602 obj.reset(optionsDict->getObject(key), OSRetain);
5603 }
5604 if (!obj) {
5605 obj = copyProperty(key);
5606 }
5607 if (obj) {
5608 if ((num = OSDynamicCast(OSNumber, obj.get()))) {
5609 *option = num->unsigned32BitValue();
5610 ok = true;
5611 } else if (OSDynamicCast(OSBoolean, obj.get())) {
5612 *option = (obj == kOSBooleanTrue) ? 1 : 0;
5613 ok = true;
5614 }
5615 }
5616
5617 return ok;
5618 }
5619 #endif /* HIBERNATION */
5620
5621 IOReturn
getSystemSleepType(uint32_t * sleepType,uint32_t * standbyTimer)5622 IOPMrootDomain::getSystemSleepType( uint32_t * sleepType, uint32_t * standbyTimer )
5623 {
5624 #if HIBERNATION
5625 IOPMSystemSleepParameters params;
5626 uint32_t hibMode = 0;
5627 bool ok;
5628
5629 if (gIOPMWorkLoop->inGate() == false) {
5630 IOReturn ret = gIOPMWorkLoop->runAction(
5631 OSMemberFunctionCast(IOWorkLoop::Action, this,
5632 &IOPMrootDomain::getSystemSleepType),
5633 (OSObject *) this,
5634 (void *) sleepType, (void *) standbyTimer);
5635 return ret;
5636 }
5637
5638 getSleepOption(kIOHibernateModeKey, &hibMode);
5639 bzero(¶ms, sizeof(params));
5640
5641 ok = evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase0, &hibMode);
5642 if (ok) {
5643 *sleepType = params.sleepType;
5644 if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer) &&
5645 !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
5646 DLOG("Standby delay is not set\n");
5647 *standbyTimer = 0;
5648 }
5649 return kIOReturnSuccess;
5650 }
5651 #endif
5652
5653 return kIOReturnUnsupported;
5654 }
5655
5656 // MARK: -
5657 // MARK: Shutdown and Restart
5658
5659 //******************************************************************************
5660 // handlePlatformHaltRestart
5661 //
5662 //******************************************************************************
5663
5664 // Phases while performing shutdown/restart
5665 typedef enum {
5666 kNotifyDone = 0x00,
5667 kNotifyPriorityClients = 0x10,
5668 kNotifyPowerPlaneDrivers = 0x20,
5669 kNotifyHaltRestartAction = 0x30,
5670 kQuiescePM = 0x40,
5671 } shutdownPhase_t;
5672
5673
5674 struct HaltRestartApplierContext {
5675 IOPMrootDomain * RootDomain;
5676 unsigned long PowerState;
5677 IOPMPowerFlags PowerFlags;
5678 UInt32 MessageType;
5679 UInt32 Counter;
5680 const char * LogString;
5681 shutdownPhase_t phase;
5682
5683 IOServiceInterestHandler handler;
5684 } gHaltRestartCtx;
5685
5686 const char *
shutdownPhase2String(shutdownPhase_t phase)5687 shutdownPhase2String(shutdownPhase_t phase)
5688 {
5689 switch (phase) {
5690 case kNotifyDone:
5691 return "Notifications completed";
5692 case kNotifyPriorityClients:
5693 return "Notifying priority clients";
5694 case kNotifyPowerPlaneDrivers:
5695 return "Notifying power plane drivers";
5696 case kNotifyHaltRestartAction:
5697 return "Notifying HaltRestart action handlers";
5698 case kQuiescePM:
5699 return "Quiescing PM";
5700 default:
5701 return "Unknown";
5702 }
5703 }
5704
5705 static void
platformHaltRestartApplier(OSObject * object,void * context)5706 platformHaltRestartApplier( OSObject * object, void * context )
5707 {
5708 IOPowerStateChangeNotification notify;
5709 HaltRestartApplierContext * ctx;
5710 AbsoluteTime startTime, elapsedTime;
5711 uint32_t deltaTime;
5712
5713 ctx = (HaltRestartApplierContext *) context;
5714
5715 _IOServiceInterestNotifier * notifier;
5716 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5717 memset(¬ify, 0, sizeof(notify));
5718 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
5719 notify.returnValue = 0;
5720 notify.stateNumber = ctx->PowerState;
5721 notify.stateFlags = ctx->PowerFlags;
5722
5723 if (notifier) {
5724 ctx->handler = notifier->handler;
5725 }
5726
5727 clock_get_uptime(&startTime);
5728 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)¬ify );
5729 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5730
5731 if ((deltaTime > kPMHaltTimeoutMS) && notifier) {
5732 LOG("%s handler %p took %u ms\n",
5733 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
5734 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier->handler, elapsedTime);
5735 }
5736
5737 ctx->handler = NULL;
5738 ctx->Counter++;
5739 }
5740
5741 static void
quiescePowerTreeCallback(void * target,void * param)5742 quiescePowerTreeCallback( void * target, void * param )
5743 {
5744 IOLockLock(gPMHaltLock);
5745 gPMQuiesced = true;
5746 thread_wakeup(param);
5747 IOLockUnlock(gPMHaltLock);
5748 }
5749
5750 void
handlePlatformHaltRestart(UInt32 pe_type)5751 IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
5752 {
5753 AbsoluteTime startTime, elapsedTime;
5754 uint32_t deltaTime;
5755 bool nvramSync = false;
5756
5757 memset(&gHaltRestartCtx, 0, sizeof(gHaltRestartCtx));
5758 gHaltRestartCtx.RootDomain = this;
5759
5760 clock_get_uptime(&startTime);
5761 switch (pe_type) {
5762 case kPEHaltCPU:
5763 case kPEUPSDelayHaltCPU:
5764 gHaltRestartCtx.PowerState = OFF_STATE;
5765 gHaltRestartCtx.MessageType = kIOMessageSystemWillPowerOff;
5766 gHaltRestartCtx.LogString = "PowerOff";
5767 nvramSync = true;
5768 break;
5769
5770 case kPERestartCPU:
5771 gHaltRestartCtx.PowerState = RESTART_STATE;
5772 gHaltRestartCtx.MessageType = kIOMessageSystemWillRestart;
5773 gHaltRestartCtx.LogString = "Restart";
5774 nvramSync = true;
5775 break;
5776
5777 case kPEPagingOff:
5778 gHaltRestartCtx.PowerState = ON_STATE;
5779 gHaltRestartCtx.MessageType = kIOMessageSystemPagingOff;
5780 gHaltRestartCtx.LogString = "PagingOff";
5781 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
5782 #if HIBERNATION
5783 IOHibernateSystemRestart();
5784 #endif
5785 break;
5786
5787 default:
5788 return;
5789 }
5790
5791 if (nvramSync) {
5792 PESyncNVRAM();
5793 }
5794
5795 gHaltRestartCtx.phase = kNotifyPriorityClients;
5796 // Notify legacy clients
5797 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &gHaltRestartCtx);
5798
5799 // For normal shutdown, turn off File Server Mode.
5800 if (kPEHaltCPU == pe_type) {
5801 OSSharedPtr<const OSSymbol> setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
5802 OSSharedPtr<OSNumber> num = OSNumber::withNumber((unsigned long long) 0, 32);
5803 if (setting && num) {
5804 setPMSetting(setting.get(), num.get());
5805 }
5806 }
5807
5808 if (kPEPagingOff != pe_type) {
5809 gHaltRestartCtx.phase = kNotifyPowerPlaneDrivers;
5810 // Notify in power tree order
5811 notifySystemShutdown(this, gHaltRestartCtx.MessageType);
5812 }
5813
5814 gHaltRestartCtx.phase = kNotifyHaltRestartAction;
5815 #if defined(XNU_TARGET_OS_OSX)
5816 IOCPURunPlatformHaltRestartActions(pe_type);
5817 #else /* !defined(XNU_TARGET_OS_OSX) */
5818 if (kPEPagingOff != pe_type) {
5819 IOCPURunPlatformHaltRestartActions(pe_type);
5820 }
5821 #endif /* !defined(XNU_TARGET_OS_OSX) */
5822
5823 // Wait for PM to quiesce
5824 if ((kPEPagingOff != pe_type) && gPMHaltLock) {
5825 gHaltRestartCtx.phase = kQuiescePM;
5826 AbsoluteTime quiesceTime = mach_absolute_time();
5827
5828 IOLockLock(gPMHaltLock);
5829 gPMQuiesced = false;
5830 if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
5831 kIOReturnSuccess) {
5832 while (!gPMQuiesced) {
5833 IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
5834 }
5835 }
5836 IOLockUnlock(gPMHaltLock);
5837 deltaTime = computeDeltaTimeMS(&quiesceTime, &elapsedTime);
5838 DLOG("PM quiesce took %u ms\n", deltaTime);
5839 halt_log_enter("Quiesce", NULL, elapsedTime);
5840 }
5841 gHaltRestartCtx.phase = kNotifyDone;
5842
5843 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5844 LOG("%s all drivers took %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5845
5846 halt_log_enter(gHaltRestartCtx.LogString, NULL, elapsedTime);
5847
5848 deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
5849 LOG("%s total %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5850
5851 if (gHaltLog && gHaltTimeMaxLog && (deltaTime >= gHaltTimeMaxLog)) {
5852 printf("%s total %d ms:%s\n", gHaltRestartCtx.LogString, deltaTime, gHaltLog);
5853 }
5854
5855 checkShutdownTimeout();
5856 }
5857
5858 bool
checkShutdownTimeout()5859 IOPMrootDomain::checkShutdownTimeout()
5860 {
5861 AbsoluteTime elapsedTime;
5862 uint32_t deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
5863
5864 if (gHaltTimeMaxPanic && (deltaTime >= gHaltTimeMaxPanic)) {
5865 return true;
5866 }
5867 return false;
5868 }
5869
5870 void
panicWithShutdownLog(uint32_t timeoutInMs)5871 IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs)
5872 {
5873 if (gHaltLog) {
5874 if ((gHaltRestartCtx.phase == kNotifyPriorityClients) && gHaltRestartCtx.handler) {
5875 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx.handler, mach_absolute_time() - gHaltStartTime);
5876 }
5877 panic("%s timed out in phase '%s'. Total %d ms:%s",
5878 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs, gHaltLog);
5879 } else {
5880 panic("%s timed out in phase \'%s\'. Total %d ms",
5881 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs);
5882 }
5883 }
5884
5885 //******************************************************************************
5886 // shutdownSystem
5887 //
5888 //******************************************************************************
5889
5890 IOReturn
shutdownSystem(void)5891 IOPMrootDomain::shutdownSystem( void )
5892 {
5893 return kIOReturnUnsupported;
5894 }
5895
5896 //******************************************************************************
5897 // restartSystem
5898 //
5899 //******************************************************************************
5900
5901 IOReturn
restartSystem(void)5902 IOPMrootDomain::restartSystem( void )
5903 {
5904 return kIOReturnUnsupported;
5905 }
5906
5907 // MARK: -
5908 // MARK: System Capability
5909
5910 //******************************************************************************
5911 // tagPowerPlaneService
5912 //
5913 // Running on PM work loop thread.
5914 //******************************************************************************
5915
5916 void
tagPowerPlaneService(IOService * service,IOPMActions * actions,IOPMPowerStateIndex maxPowerState)5917 IOPMrootDomain::tagPowerPlaneService(
5918 IOService * service,
5919 IOPMActions * actions,
5920 IOPMPowerStateIndex maxPowerState )
5921 {
5922 uint32_t flags = 0;
5923
5924 memset(actions, 0, sizeof(*actions));
5925 actions->target = this;
5926
5927 if (service == this) {
5928 actions->actionPowerChangeStart =
5929 OSMemberFunctionCast(
5930 IOPMActionPowerChangeStart, this,
5931 &IOPMrootDomain::handleOurPowerChangeStart);
5932
5933 actions->actionPowerChangeDone =
5934 OSMemberFunctionCast(
5935 IOPMActionPowerChangeDone, this,
5936 &IOPMrootDomain::handleOurPowerChangeDone);
5937
5938 actions->actionPowerChangeOverride =
5939 OSMemberFunctionCast(
5940 IOPMActionPowerChangeOverride, this,
5941 &IOPMrootDomain::overrideOurPowerChange);
5942 return;
5943 }
5944
5945 #if DISPLAY_WRANGLER_PRESENT
5946 if (NULL != service->metaCast("IODisplayWrangler")) {
5947 // XXX should this really retain?
5948 wrangler.reset(service, OSRetain);
5949 wrangler->registerInterest(gIOGeneralInterest,
5950 &displayWranglerNotification, this, NULL);
5951
5952 // found the display wrangler, check for any display assertions already created
5953 if (pmAssertions->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit) {
5954 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
5955 wrangler->setIgnoreIdleTimer( true );
5956 }
5957 flags |= kPMActionsFlagIsDisplayWrangler;
5958 }
5959 #endif /* DISPLAY_WRANGLER_PRESENT */
5960
5961 if (service->propertyExists("IOPMStrictTreeOrder")) {
5962 flags |= kPMActionsFlagIsGraphicsDriver;
5963 }
5964 if (service->propertyExists("IOPMUnattendedWakePowerState")) {
5965 flags |= kPMActionsFlagIsAudioDriver;
5966 }
5967
5968 // Find the power connection object that is a child of the PCI host
5969 // bridge, and has a graphics/audio device attached below. Mark the
5970 // power branch for delayed child notifications.
5971
5972 if (flags) {
5973 IORegistryEntry * child = service;
5974 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
5975
5976 while (child != this) {
5977 if (child->propertyHasValue("IOPCITunnelled", kOSBooleanTrue)) {
5978 // Skip delaying notifications and clamping power on external graphics and audio devices.
5979 DLOG("Avoiding delayChildNotification on object 0x%llx. flags: 0x%x\n", service->getRegistryEntryID(), flags);
5980 flags = 0;
5981 break;
5982 }
5983 if ((parent == pciHostBridgeDriver) ||
5984 (parent == this)) {
5985 if (OSDynamicCast(IOPowerConnection, child)) {
5986 IOPowerConnection * conn = (IOPowerConnection *) child;
5987 conn->delayChildNotification = true;
5988 DLOG("delayChildNotification for 0x%llx\n", conn->getRegistryEntryID());
5989 }
5990 break;
5991 }
5992 child = parent;
5993 parent = child->getParentEntry(gIOPowerPlane);
5994 }
5995 }
5996
5997 OSSharedPtr<OSObject> prop = service->copyProperty(kIOPMDarkWakeMaxPowerStateKey);
5998 if (prop) {
5999 OSNumber * num = OSDynamicCast(OSNumber, prop.get());
6000 if (num) {
6001 actions->darkWakePowerState = num->unsigned32BitValue();
6002 if (actions->darkWakePowerState < maxPowerState) {
6003 flags |= kPMActionsFlagHasDarkWakePowerState;
6004 }
6005 }
6006 }
6007
6008
6009 if (flags) {
6010 DLOG("%s tag flags %x\n", service->getName(), flags);
6011 actions->flags |= flags;
6012 actions->actionPowerChangeOverride =
6013 OSMemberFunctionCast(
6014 IOPMActionPowerChangeOverride, this,
6015 &IOPMrootDomain::overridePowerChangeForService);
6016
6017 if (flags & kPMActionsFlagIsDisplayWrangler) {
6018 actions->actionActivityTickle =
6019 OSMemberFunctionCast(
6020 IOPMActionActivityTickle, this,
6021 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
6022
6023 actions->actionUpdatePowerClient =
6024 OSMemberFunctionCast(
6025 IOPMActionUpdatePowerClient, this,
6026 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
6027 }
6028 return;
6029 }
6030
6031 // Locate the first PCI host bridge for PMTrace.
6032 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge")) {
6033 IOService * provider = service->getProvider();
6034 if (OSDynamicCast(IOPlatformDevice, provider) &&
6035 provider->inPlane(gIODTPlane)) {
6036 pciHostBridgeDevice.reset(provider, OSNoRetain);
6037 pciHostBridgeDriver.reset(service, OSNoRetain);
6038 DLOG("PMTrace found PCI host bridge %s->%s\n",
6039 provider->getName(), service->getName());
6040 }
6041 }
6042
6043 // Tag top-level PCI devices. The order of PMinit() call does not
6044 // change across boots and is used as the PCI bit number.
6045 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice")) {
6046 // Would prefer to check built-in property, but tagPowerPlaneService()
6047 // is called before pciDevice->registerService().
6048 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
6049 if ((parent == pciHostBridgeDevice) && service->propertyExists("acpi-device")) {
6050 int bit = pmTracer->recordTopLevelPCIDevice( service );
6051 if (bit >= 0) {
6052 // Save the assigned bit for fast lookup.
6053 actions->flags |= (bit & kPMActionsPCIBitNumberMask);
6054
6055 actions->actionPowerChangeStart =
6056 OSMemberFunctionCast(
6057 IOPMActionPowerChangeStart, this,
6058 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
6059
6060 actions->actionPowerChangeDone =
6061 OSMemberFunctionCast(
6062 IOPMActionPowerChangeDone, this,
6063 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
6064 }
6065 }
6066 }
6067 }
6068
6069 //******************************************************************************
6070 // PM actions for root domain
6071 //******************************************************************************
6072
6073 void
overrideOurPowerChange(IOService * service,IOPMActions * actions,const IOPMRequest * request,IOPMPowerStateIndex * inOutPowerState,IOPMPowerChangeFlags * inOutChangeFlags)6074 IOPMrootDomain::overrideOurPowerChange(
6075 IOService * service,
6076 IOPMActions * actions,
6077 const IOPMRequest * request,
6078 IOPMPowerStateIndex * inOutPowerState,
6079 IOPMPowerChangeFlags * inOutChangeFlags )
6080 {
6081 uint32_t changeFlags = *inOutChangeFlags;
6082 uint32_t desiredPowerState = (uint32_t) *inOutPowerState;
6083 uint32_t currentPowerState = (uint32_t) getPowerState();
6084
6085 if (request->getTag() == 0) {
6086 // Set a tag for any request that originates from IOServicePM
6087 (const_cast<IOPMRequest *>(request))->fTag = nextRequestTag(kCPSReasonPMInternals);
6088 }
6089
6090 DLOG("PowerChangeOverride (%s->%s, %x, 0x%x) tag 0x%x\n",
6091 getPowerStateString(currentPowerState),
6092 getPowerStateString(desiredPowerState),
6093 _currentCapability, changeFlags,
6094 request->getTag());
6095
6096
6097 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6098 /*
6099 * ASBM send lowBattery notifications every 1 second until the device
6100 * enters hibernation. This queues up multiple sleep requests.
6101 * After the device wakes from hibernation, none of these previously
6102 * queued sleep requests are valid.
6103 * lowBattteryCondition variable is set when ASBM notifies rootDomain
6104 * and is cleared at the very last point in sleep.
6105 * Any attempt to sleep with reason kIOPMSleepReasonLowPower without
6106 * lowBatteryCondition is invalid
6107 */
6108 if (REQUEST_TAG_TO_REASON(request->getTag()) == kIOPMSleepReasonLowPower) {
6109 if (!lowBatteryCondition) {
6110 DLOG("Duplicate lowBattery sleep");
6111 *inOutChangeFlags |= kIOPMNotDone;
6112 return;
6113 }
6114 }
6115 #endif
6116
6117 if ((AOT_STATE == desiredPowerState) && (ON_STATE == currentPowerState)) {
6118 // Assertion may have been taken in AOT leading to changePowerStateTo(AOT)
6119 *inOutChangeFlags |= kIOPMNotDone;
6120 return;
6121 }
6122
6123 if (changeFlags & kIOPMParentInitiated) {
6124 // Root parent is permanently pegged at max power,
6125 // a parent initiated power change is unexpected.
6126 *inOutChangeFlags |= kIOPMNotDone;
6127 return;
6128 }
6129
6130 if (desiredPowerState < currentPowerState) {
6131 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
6132 // Root domain is dropping power state from ON->SLEEP.
6133 // If system is in full wake, first enter dark wake by
6134 // converting the power drop to a capability change.
6135 // Once in dark wake, transition to sleep state ASAP.
6136
6137 darkWakeToSleepASAP = true;
6138
6139 // Drop graphics and audio capability
6140 _desiredCapability &= ~(
6141 kIOPMSystemCapabilityGraphics |
6142 kIOPMSystemCapabilityAudio);
6143
6144 // Convert to capability change (ON->ON)
6145 *inOutPowerState = getRUN_STATE();
6146 *inOutChangeFlags |= kIOPMSynchronize;
6147
6148 // Revert device desire from SLEEP to ON
6149 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerOverride);
6150 } else {
6151 // System is already in dark wake, ok to drop power state.
6152 // Broadcast root power down to entire tree.
6153 *inOutChangeFlags |= kIOPMRootChangeDown;
6154 }
6155 } else if (desiredPowerState > currentPowerState) {
6156 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0) {
6157 // Broadcast power up when waking from sleep, but not for the
6158 // initial power change at boot by checking for cpu capability.
6159 *inOutChangeFlags |= kIOPMRootChangeUp;
6160 }
6161 }
6162 }
6163
6164 void
handleOurPowerChangeStart(IOService * service,IOPMActions * actions,const IOPMRequest * request,IOPMPowerStateIndex newPowerState,IOPMPowerChangeFlags * inOutChangeFlags)6165 IOPMrootDomain::handleOurPowerChangeStart(
6166 IOService * service,
6167 IOPMActions * actions,
6168 const IOPMRequest * request,
6169 IOPMPowerStateIndex newPowerState,
6170 IOPMPowerChangeFlags * inOutChangeFlags )
6171 {
6172 IOPMRequestTag requestTag = request->getTag();
6173 IOPMRequestTag sleepReason;
6174
6175 uint32_t changeFlags = *inOutChangeFlags;
6176 uint32_t currentPowerState = (uint32_t) getPowerState();
6177 bool publishSleepReason = false;
6178
6179 // Check if request has a valid sleep reason
6180 sleepReason = REQUEST_TAG_TO_REASON(requestTag);
6181 if (sleepReason < kIOPMSleepReasonClamshell) {
6182 sleepReason = kIOPMSleepReasonIdle;
6183 }
6184
6185 _systemTransitionType = kSystemTransitionNone;
6186 _systemMessageClientMask = 0;
6187 capabilityLoss = false;
6188 toldPowerdCapWillChange = false;
6189
6190 // Emergency notifications may arrive after the initial sleep request
6191 // has been queued. Override the sleep reason so powerd and others can
6192 // treat this as an emergency sleep.
6193 if (lowBatteryCondition) {
6194 sleepReason = kIOPMSleepReasonLowPower;
6195 } else if (thermalEmergencyState) {
6196 sleepReason = kIOPMSleepReasonThermalEmergency;
6197 }
6198
6199 // 1. Explicit capability change.
6200 if (changeFlags & kIOPMSynchronize) {
6201 if (newPowerState == ON_STATE) {
6202 if (changeFlags & kIOPMSyncNoChildNotify) {
6203 _systemTransitionType = kSystemTransitionNewCapClient;
6204 } else {
6205 _systemTransitionType = kSystemTransitionCapability;
6206 }
6207 }
6208 }
6209 // 2. Going to sleep (cancellation still possible).
6210 else if (newPowerState < currentPowerState) {
6211 _systemTransitionType = kSystemTransitionSleep;
6212 }
6213 // 3. Woke from (idle or demand) sleep.
6214 else if (!systemBooting &&
6215 (changeFlags & kIOPMSelfInitiated) &&
6216 (newPowerState > currentPowerState)) {
6217 _systemTransitionType = kSystemTransitionWake;
6218 _desiredCapability = kIOPMSystemCapabilityCPU | kIOPMSystemCapabilityNetwork;
6219
6220 // Early exit from dark wake to full (e.g. LID open)
6221 if (kFullWakeReasonNone != fullWakeReason) {
6222 _desiredCapability |= (
6223 kIOPMSystemCapabilityGraphics |
6224 kIOPMSystemCapabilityAudio);
6225
6226 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6227 if (fullWakeReason == kFullWakeReasonLocalUser) {
6228 darkWakeExit = true;
6229 darkWakeToSleepASAP = false;
6230 setProperty(kIOPMRootDomainWakeTypeKey, isRTCAlarmWake ?
6231 kIOPMRootDomainWakeTypeAlarm : kIOPMRootDomainWakeTypeUser);
6232 }
6233 #endif
6234 }
6235 #if HIBERNATION
6236 IOHibernateSetWakeCapabilities(_desiredCapability);
6237 #endif
6238 }
6239
6240 // Update pending wake capability at the beginning of every
6241 // state transition (including synchronize). This will become
6242 // the current capability at the end of the transition.
6243
6244 if (kSystemTransitionSleep == _systemTransitionType) {
6245 _pendingCapability = 0;
6246 capabilityLoss = true;
6247 } else if (kSystemTransitionNewCapClient != _systemTransitionType) {
6248 _pendingCapability = _desiredCapability |
6249 kIOPMSystemCapabilityCPU |
6250 kIOPMSystemCapabilityNetwork;
6251
6252 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6253 _pendingCapability |= kIOPMSystemCapabilityAudio;
6254 }
6255
6256 if ((kSystemTransitionCapability == _systemTransitionType) &&
6257 (_pendingCapability == _currentCapability)) {
6258 // Cancel the PM state change.
6259 _systemTransitionType = kSystemTransitionNone;
6260 *inOutChangeFlags |= kIOPMNotDone;
6261 }
6262 if (__builtin_popcount(_pendingCapability) <
6263 __builtin_popcount(_currentCapability)) {
6264 capabilityLoss = true;
6265 }
6266 }
6267
6268 // 1. Capability change.
6269 if (kSystemTransitionCapability == _systemTransitionType) {
6270 // Dark to Full transition.
6271 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
6272 tracePoint( kIOPMTracePointDarkWakeExit );
6273
6274 #if defined(XNU_TARGET_OS_OSX)
6275 // rdar://problem/65627936
6276 // When a dark->full wake promotion is scheduled before an ON->SLEEP
6277 // power state drop, invalidate any request to drop power state already
6278 // in the queue, including the override variant, unless full wake cannot
6279 // be sustained. Any power state drop queued after this SustainFullWake
6280 // request will not be affected.
6281 if (checkSystemCanSustainFullWake()) {
6282 changePowerStateWithOverrideTo(getRUN_STATE(), kCPSReasonSustainFullWake);
6283 }
6284 #endif
6285
6286 willEnterFullWake();
6287 }
6288
6289 // Full to Dark transition.
6290 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
6291 // Clear previous stats
6292 IOLockLock(pmStatsLock);
6293 if (pmStatsAppResponses) {
6294 pmStatsAppResponses = OSArray::withCapacity(5);
6295 }
6296 IOLockUnlock(pmStatsLock);
6297
6298 tracePoint( kIOPMTracePointDarkWakeEntry );
6299 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
6300 _systemMessageClientMask = kSystemMessageClientPowerd |
6301 kSystemMessageClientLegacyApp;
6302
6303 // rdar://15971327
6304 // Prevent user active transitions before notifying clients
6305 // that system will sleep.
6306 preventTransitionToUserActive(true);
6307
6308 IOService::setAdvisoryTickleEnable( false );
6309
6310 // Publish the sleep reason for full to dark wake
6311 publishSleepReason = true;
6312 lastSleepReason = fullToDarkReason = sleepReason;
6313
6314 // Publish a UUID for the Sleep --> Wake cycle
6315 handlePublishSleepWakeUUID(true);
6316 if (sleepDelaysReport) {
6317 clock_get_uptime(&ts_sleepStart);
6318 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
6319 }
6320
6321 darkWakeExit = false;
6322 }
6323 }
6324 // 2. System sleep.
6325 else if (kSystemTransitionSleep == _systemTransitionType) {
6326 // Beginning of a system sleep transition.
6327 // Cancellation is still possible.
6328 tracePoint( kIOPMTracePointSleepStarted );
6329
6330 _systemMessageClientMask = kSystemMessageClientAll;
6331 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) {
6332 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
6333 }
6334 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) {
6335 // Kernel priority clients are only notified on the initial
6336 // transition to full wake, so don't notify them unless system
6337 // has gained graphics capability since the last system wake.
6338 _systemMessageClientMask &= ~kSystemMessageClientKernel;
6339 } else {
6340 // System was in full wake, but the downwards power transition is driven
6341 // by a request that originates from IOServicePM, so it isn't tagged with
6342 // a valid system sleep reason.
6343 if (REQUEST_TAG_TO_REASON(requestTag) == kCPSReasonPMInternals) {
6344 // Publish the same reason for full to dark
6345 sleepReason = fullToDarkReason;
6346 }
6347 }
6348 #if HIBERNATION
6349 gIOHibernateState = 0;
6350 #endif
6351
6352 // Record the reason for dark wake back to sleep
6353 // System may not have ever achieved full wake
6354
6355 publishSleepReason = true;
6356 lastSleepReason = sleepReason;
6357 if (sleepDelaysReport) {
6358 clock_get_uptime(&ts_sleepStart);
6359 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
6360 }
6361 }
6362 // 3. System wake.
6363 else if (kSystemTransitionWake == _systemTransitionType) {
6364 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
6365 // Clear stats about sleep
6366
6367 if (AOT_STATE == newPowerState) {
6368 _pendingCapability = 0;
6369 }
6370
6371 if (AOT_STATE == currentPowerState) {
6372 // Wake events are no longer accepted after waking to AOT_STATE.
6373 // Re-enable wake event acceptance to append wake events claimed
6374 // during the AOT to ON_STATE transition.
6375 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Reenable);
6376 }
6377
6378 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6379 willEnterFullWake();
6380 }
6381 }
6382
6383 // The only location where the sleep reason is published. At this point
6384 // sleep can still be cancelled, but sleep reason should be published
6385 // early for logging purposes.
6386
6387 if (publishSleepReason) {
6388 static const char * IOPMSleepReasons[] =
6389 {
6390 kIOPMClamshellSleepKey,
6391 kIOPMPowerButtonSleepKey,
6392 kIOPMSoftwareSleepKey,
6393 kIOPMOSSwitchHibernationKey,
6394 kIOPMIdleSleepKey,
6395 kIOPMLowPowerSleepKey,
6396 kIOPMThermalEmergencySleepKey,
6397 kIOPMMaintenanceSleepKey,
6398 kIOPMSleepServiceExitKey,
6399 kIOPMDarkWakeThermalEmergencyKey,
6400 kIOPMNotificationWakeExitKey
6401 };
6402
6403 // Record sleep cause in IORegistry
6404 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
6405 if (reasonIndex < sizeof(IOPMSleepReasons) / sizeof(IOPMSleepReasons[0])) {
6406 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
6407 #if DEVELOPMENT || DEBUG
6408 record_system_event(SYSTEM_EVENT_TYPE_INFO,
6409 SYSTEM_EVENT_SUBSYSTEM_PMRD,
6410 "Sleep Reason", "%s\n", IOPMSleepReasons[reasonIndex]
6411 );
6412 #endif /* DEVELOPMENT || DEBUG */
6413 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
6414 }
6415 }
6416
6417 if ((kSystemTransitionNone != _systemTransitionType) &&
6418 (kSystemTransitionNewCapClient != _systemTransitionType)) {
6419 _systemStateGeneration++;
6420 systemDarkWake = false;
6421
6422 DLOG("=== START (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6423 getPowerStateString(currentPowerState),
6424 getPowerStateString((uint32_t) newPowerState),
6425 _currentCapability, _pendingCapability,
6426 *inOutChangeFlags, _systemStateGeneration, _systemMessageClientMask,
6427 requestTag);
6428 #if DEVELOPMENT || DEBUG
6429 if (currentPowerState != (uint32_t) newPowerState) {
6430 record_system_event(SYSTEM_EVENT_TYPE_INFO,
6431 SYSTEM_EVENT_SUBSYSTEM_PMRD,
6432 "Start Power State Trans.",
6433 "(%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6434 getPowerStateString(currentPowerState),
6435 getPowerStateString((uint32_t) newPowerState),
6436 _currentCapability,
6437 _pendingCapability,
6438 *inOutChangeFlags,
6439 _systemStateGeneration,
6440 _systemMessageClientMask,
6441 requestTag
6442 );
6443 }
6444 #endif /* DEVELOPMENT || DEBUG */
6445 }
6446
6447 if ((AOT_STATE == newPowerState) && (SLEEP_STATE != currentPowerState)) {
6448 panic("illegal AOT entry from %s", getPowerStateString(currentPowerState));
6449 }
6450 if (_aotNow && (ON_STATE == newPowerState)) {
6451 WAKEEVENT_LOCK();
6452 aotShouldExit(false, true);
6453 WAKEEVENT_UNLOCK();
6454 aotExit(false);
6455 }
6456 }
6457
6458 void
handleOurPowerChangeDone(IOService * service,IOPMActions * actions,const IOPMRequest * request,IOPMPowerStateIndex oldPowerState,IOPMPowerChangeFlags changeFlags)6459 IOPMrootDomain::handleOurPowerChangeDone(
6460 IOService * service,
6461 IOPMActions * actions,
6462 const IOPMRequest * request,
6463 IOPMPowerStateIndex oldPowerState,
6464 IOPMPowerChangeFlags changeFlags )
6465 {
6466 if (kSystemTransitionNewCapClient == _systemTransitionType) {
6467 _systemTransitionType = kSystemTransitionNone;
6468 return;
6469 }
6470
6471 if (_systemTransitionType != kSystemTransitionNone) {
6472 uint32_t currentPowerState = (uint32_t) getPowerState();
6473
6474 if (changeFlags & kIOPMNotDone) {
6475 // Power down was cancelled or vetoed.
6476 _pendingCapability = _currentCapability;
6477 lastSleepReason = 0;
6478
6479 // When sleep is cancelled or reverted, don't report
6480 // the target (lower) power state as the previous state.
6481 oldPowerState = currentPowerState;
6482
6483 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
6484 CAP_CURRENT(kIOPMSystemCapabilityCPU)) {
6485 #if defined(XNU_TARGET_OS_OSX)
6486 pmPowerStateQueue->submitPowerEvent(
6487 kPowerEventPolicyStimulus,
6488 (void *) kStimulusDarkWakeReentry,
6489 _systemStateGeneration );
6490 #else /* !defined(XNU_TARGET_OS_OSX) */
6491 // On embedded, there are no factors that can prolong a
6492 // "darkWake" when a power down is vetoed. We need to
6493 // promote to "fullWake" at least once so that factors
6494 // that prevent idle sleep can assert themselves if required
6495 pmPowerStateQueue->submitPowerEvent(
6496 kPowerEventPolicyStimulus,
6497 (void *) kStimulusDarkWakeActivityTickle);
6498 #endif /* !defined(XNU_TARGET_OS_OSX) */
6499 }
6500
6501 // Revert device desire to max.
6502 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerDownCancel);
6503 } else {
6504 // Send message on dark wake to full wake promotion.
6505 // tellChangeUp() handles the normal SLEEP->ON case.
6506
6507 if (kSystemTransitionCapability == _systemTransitionType) {
6508 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
6509 lastSleepReason = 0; // stop logging wrangler tickles
6510 tellClients(kIOMessageSystemHasPoweredOn);
6511 }
6512 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
6513 // Going dark, reset full wake state
6514 // userIsActive will be cleared by wrangler powering down
6515 fullWakeReason = kFullWakeReasonNone;
6516
6517 if (ts_sleepStart) {
6518 clock_get_uptime(&wake2DarkwakeDelay);
6519 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
6520 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
6521 ts_sleepStart = 0;
6522 }
6523 }
6524 }
6525
6526 // Reset state after exiting from dark wake.
6527
6528 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
6529 CAP_LOSS(kIOPMSystemCapabilityCPU)) {
6530 darkWakeMaintenance = false;
6531 darkWakeToSleepASAP = false;
6532 pciCantSleepValid = false;
6533 darkWakeSleepService = false;
6534
6535 if (CAP_LOSS(kIOPMSystemCapabilityCPU)) {
6536 // Remove the influence of display power assertion
6537 // before next system wake.
6538 if (wrangler) {
6539 wrangler->changePowerStateForRootDomain(
6540 kWranglerPowerStateMin );
6541 }
6542 removeProperty(gIOPMUserTriggeredFullWakeKey.get());
6543 }
6544 }
6545
6546 // Entered dark mode.
6547
6548 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6549 (_pendingCapability & kIOPMSystemCapabilityCPU)) {
6550 // Queue an evaluation of whether to remain in dark wake,
6551 // and for how long. This serves the purpose of draining
6552 // any assertions from the queue.
6553
6554 pmPowerStateQueue->submitPowerEvent(
6555 kPowerEventPolicyStimulus,
6556 (void *) kStimulusDarkWakeEntry,
6557 _systemStateGeneration );
6558 }
6559 }
6560
6561 #if DEVELOPMENT || DEBUG
6562 if (currentPowerState != (uint32_t) oldPowerState) {
6563 record_system_event(SYSTEM_EVENT_TYPE_INFO,
6564 SYSTEM_EVENT_SUBSYSTEM_PMRD,
6565 "Finish Power State Trans.",
6566 "(%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6567 getPowerStateString((uint32_t)oldPowerState),
6568 getPowerStateString(currentPowerState),
6569 _currentCapability,
6570 _pendingCapability,
6571 changeFlags,
6572 _systemStateGeneration,
6573 _systemMessageClientMask,
6574 request->getTag()
6575 );
6576 }
6577 #endif /* DEVELOPMENT || DEBUG */
6578
6579 DLOG("=== FINISH (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6580 getPowerStateString((uint32_t) oldPowerState), getPowerStateString(currentPowerState),
6581 _currentCapability, _pendingCapability,
6582 changeFlags, _systemStateGeneration, _systemMessageClientMask,
6583 request->getTag());
6584
6585 if ((currentPowerState == ON_STATE) && pmAssertions) {
6586 pmAssertions->reportCPUBitAccounting();
6587 }
6588
6589 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6590 displayWakeCnt++;
6591 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
6592 if (clamshellExists && fullWakeThreadCall) {
6593 AbsoluteTime deadline;
6594 clock_interval_to_deadline(DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY, kSecondScale, &deadline);
6595 thread_call_enter_delayed(fullWakeThreadCall, deadline);
6596 }
6597 #endif
6598 } else if (CAP_GAIN(kIOPMSystemCapabilityCPU)) {
6599 darkWakeCnt++;
6600 }
6601
6602 // Update current system capability.
6603 if (_currentCapability != _pendingCapability) {
6604 _currentCapability = _pendingCapability;
6605 }
6606
6607 // Update highest system capability.
6608
6609 _highestCapability |= _currentCapability;
6610
6611 if (darkWakePostTickle &&
6612 (kSystemTransitionWake == _systemTransitionType) &&
6613 (gDarkWakeFlags & kDarkWakeFlagPromotionMask) ==
6614 kDarkWakeFlagPromotionLate) {
6615 darkWakePostTickle = false;
6616 reportUserInput();
6617 } else if (darkWakeExit) {
6618 requestFullWake( kFullWakeReasonLocalUser );
6619 }
6620
6621 // Reset tracepoint at completion of capability change,
6622 // completion of wake transition, and aborted sleep transition.
6623
6624 if ((_systemTransitionType == kSystemTransitionCapability) ||
6625 (_systemTransitionType == kSystemTransitionWake) ||
6626 ((_systemTransitionType == kSystemTransitionSleep) &&
6627 (changeFlags & kIOPMNotDone))) {
6628 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
6629 tracePoint( kIOPMTracePointSystemUp );
6630 }
6631
6632 _systemTransitionType = kSystemTransitionNone;
6633 _systemMessageClientMask = 0;
6634 toldPowerdCapWillChange = false;
6635
6636 darkWakeLogClamp = false;
6637
6638 if (lowBatteryCondition) {
6639 privateSleepSystem(kIOPMSleepReasonLowPower);
6640 } else if (thermalEmergencyState) {
6641 privateSleepSystem(kIOPMSleepReasonThermalEmergency);
6642 } else if ((fullWakeReason == kFullWakeReasonDisplayOn) && !displayPowerOnRequested) {
6643 // Request for full wake is removed while system is waking up to full wake
6644 DLOG("DisplayOn fullwake request is removed\n");
6645 handleSetDisplayPowerOn(false);
6646 }
6647
6648 if ((gClamshellFlags & kClamshell_WAR_47715679) && isRTCAlarmWake) {
6649 pmPowerStateQueue->submitPowerEvent(
6650 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) kLocalEvalClamshellCommand );
6651 }
6652 }
6653 }
6654
6655 //******************************************************************************
6656 // PM actions for graphics and audio.
6657 //******************************************************************************
6658
6659 void
overridePowerChangeForService(IOService * service,IOPMActions * actions,const IOPMRequest * request,IOPMPowerStateIndex * inOutPowerState,IOPMPowerChangeFlags * inOutChangeFlags)6660 IOPMrootDomain::overridePowerChangeForService(
6661 IOService * service,
6662 IOPMActions * actions,
6663 const IOPMRequest * request,
6664 IOPMPowerStateIndex * inOutPowerState,
6665 IOPMPowerChangeFlags * inOutChangeFlags )
6666 {
6667 uint32_t powerState = (uint32_t) *inOutPowerState;
6668 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
6669 const uint32_t actionFlags = actions->flags;
6670
6671 if (kSystemTransitionNone == _systemTransitionType) {
6672 // Not in midst of a system transition.
6673 // Do not set kPMActionsStatePowerClamped.
6674 } else if ((actions->state & kPMActionsStatePowerClamped) == 0) {
6675 bool enableClamp = false;
6676
6677 // For most drivers, enable the clamp during ON->Dark transition
6678 // which has the kIOPMSynchronize flag set in changeFlags.
6679 if ((actionFlags & kPMActionsFlagIsDisplayWrangler) &&
6680 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6681 (changeFlags & kIOPMSynchronize)) {
6682 enableClamp = true;
6683 } else if ((actionFlags & kPMActionsFlagIsAudioDriver) &&
6684 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
6685 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
6686 (changeFlags & kIOPMSynchronize)) {
6687 enableClamp = true;
6688 } else if ((actionFlags & kPMActionsFlagHasDarkWakePowerState) &&
6689 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6690 (changeFlags & kIOPMSynchronize)) {
6691 enableClamp = true;
6692 } else if ((actionFlags & kPMActionsFlagIsGraphicsDriver) &&
6693 (_systemTransitionType == kSystemTransitionSleep)) {
6694 // For graphics drivers, clamp power when entering
6695 // system sleep. Not when dropping to dark wake.
6696 enableClamp = true;
6697 }
6698
6699 if (enableClamp) {
6700 actions->state |= kPMActionsStatePowerClamped;
6701 DLOG("power clamp enabled %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6702 service->getName(), service->getRegistryEntryID(),
6703 _pendingCapability, powerState, changeFlags);
6704 }
6705 } else if ((actions->state & kPMActionsStatePowerClamped) != 0) {
6706 bool disableClamp = false;
6707
6708 if ((actionFlags & (
6709 kPMActionsFlagIsDisplayWrangler |
6710 kPMActionsFlagIsGraphicsDriver)) &&
6711 (_pendingCapability & kIOPMSystemCapabilityGraphics)) {
6712 disableClamp = true;
6713 } else if ((actionFlags & kPMActionsFlagIsAudioDriver) &&
6714 (_pendingCapability & kIOPMSystemCapabilityAudio)) {
6715 disableClamp = true;
6716 } else if ((actionFlags & kPMActionsFlagHasDarkWakePowerState) &&
6717 (_pendingCapability & kIOPMSystemCapabilityGraphics)) {
6718 disableClamp = true;
6719 }
6720
6721 if (disableClamp) {
6722 actions->state &= ~kPMActionsStatePowerClamped;
6723 DLOG("power clamp removed %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6724 service->getName(), service->getRegistryEntryID(),
6725 _pendingCapability, powerState, changeFlags);
6726 }
6727 }
6728
6729 if (actions->state & kPMActionsStatePowerClamped) {
6730 uint32_t maxPowerState = 0;
6731
6732 // Determine the max power state allowed when clamp is enabled
6733 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange)) {
6734 // Parent intiated power state changes
6735 if ((service->getPowerState() > maxPowerState) &&
6736 (actionFlags & kPMActionsFlagIsDisplayWrangler)) {
6737 maxPowerState++;
6738
6739 // Remove lingering effects of any tickle before entering
6740 // dark wake. It will take a new tickle to return to full
6741 // wake, so the existing tickle state is useless.
6742
6743 if (changeFlags & kIOPMDomainDidChange) {
6744 *inOutChangeFlags |= kIOPMExpireIdleTimer;
6745 }
6746 } else if (actionFlags & kPMActionsFlagIsGraphicsDriver) {
6747 maxPowerState++;
6748 } else if (actionFlags & kPMActionsFlagHasDarkWakePowerState) {
6749 maxPowerState = actions->darkWakePowerState;
6750 }
6751 } else {
6752 // Deny all self-initiated changes when power is limited.
6753 // Wrangler tickle should never defeat the limiter.
6754 maxPowerState = service->getPowerState();
6755 }
6756
6757 if (powerState > maxPowerState) {
6758 DLOG("power clamped %s %qx, ps %u->%u, cflags 0x%x)\n",
6759 service->getName(), service->getRegistryEntryID(),
6760 powerState, maxPowerState, changeFlags);
6761 *inOutPowerState = maxPowerState;
6762
6763 if (darkWakePostTickle &&
6764 (actionFlags & kPMActionsFlagIsDisplayWrangler) &&
6765 (changeFlags & kIOPMDomainWillChange) &&
6766 ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) ==
6767 kDarkWakeFlagPromotionEarly)) {
6768 darkWakePostTickle = false;
6769 reportUserInput();
6770 }
6771 }
6772
6773 if (!darkWakePowerClamped && (changeFlags & kIOPMDomainDidChange)) {
6774 if (darkWakeLogClamp) {
6775 AbsoluteTime now;
6776 uint64_t nsec;
6777
6778 clock_get_uptime(&now);
6779 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
6780 absolutetime_to_nanoseconds(now, &nsec);
6781 DLOG("dark wake power clamped after %u ms\n",
6782 ((int)((nsec) / NSEC_PER_MSEC)));
6783 }
6784 darkWakePowerClamped = true;
6785 }
6786 }
6787 }
6788
6789 void
handleActivityTickleForDisplayWrangler(IOService * service,IOPMActions * actions)6790 IOPMrootDomain::handleActivityTickleForDisplayWrangler(
6791 IOService * service,
6792 IOPMActions * actions )
6793 {
6794 #if DISPLAY_WRANGLER_PRESENT
6795 // Warning: Not running in PM work loop context - don't modify state !!!
6796 // Trap tickle directed to IODisplayWrangler while running with graphics
6797 // capability suppressed.
6798
6799 assert(service == wrangler);
6800
6801 clock_get_uptime(&userActivityTime);
6802 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
6803 || (lastSleepReason == kIOPMSleepReasonMaintenance)
6804 || (lastSleepReason == kIOPMSleepReasonSoftware));
6805 if (aborting) {
6806 userActivityCount++;
6807 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
6808 userActivityCount, lastSleepReason);
6809 }
6810
6811 if (!darkWakeExit && ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0)) {
6812 DLOG("display wrangler tickled\n");
6813 if (kIOLogPMRootDomain & gIOKitDebug) {
6814 OSReportWithBacktrace("Dark wake display tickle");
6815 }
6816 if (pmPowerStateQueue) {
6817 pmPowerStateQueue->submitPowerEvent(
6818 kPowerEventPolicyStimulus,
6819 (void *) kStimulusDarkWakeActivityTickle,
6820 true /* set wake type */ );
6821 }
6822 }
6823 #endif /* DISPLAY_WRANGLER_PRESENT */
6824 }
6825
6826 void
handleUpdatePowerClientForDisplayWrangler(IOService * service,IOPMActions * actions,const OSSymbol * powerClient,IOPMPowerStateIndex oldPowerState,IOPMPowerStateIndex newPowerState)6827 IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
6828 IOService * service,
6829 IOPMActions * actions,
6830 const OSSymbol * powerClient,
6831 IOPMPowerStateIndex oldPowerState,
6832 IOPMPowerStateIndex newPowerState )
6833 {
6834 #if DISPLAY_WRANGLER_PRESENT
6835 assert(service == wrangler);
6836
6837 // This function implements half of the user active detection
6838 // by monitoring changes to the display wrangler's device desire.
6839 //
6840 // User becomes active when either:
6841 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
6842 // in max power state. This desire change in absence of a power state
6843 // change is detected within. This handles the case when user becomes
6844 // active while the display is already lit by setDisplayPowerOn().
6845 //
6846 // 2. Power state change to max, and DeviceDesire is also at max.
6847 // Handled by displayWranglerNotification().
6848 //
6849 // User becomes inactive when DeviceDesire drops to sleep state or below.
6850
6851 DLOG("wrangler %s (ps %u, %u->%u)\n",
6852 powerClient->getCStringNoCopy(),
6853 (uint32_t) service->getPowerState(),
6854 (uint32_t) oldPowerState, (uint32_t) newPowerState);
6855
6856 if (powerClient == gIOPMPowerClientDevice) {
6857 if ((newPowerState > oldPowerState) &&
6858 (newPowerState == kWranglerPowerStateMax) &&
6859 (service->getPowerState() == kWranglerPowerStateMax)) {
6860 evaluatePolicy( kStimulusEnterUserActiveState );
6861 } else if ((newPowerState < oldPowerState) &&
6862 (newPowerState <= kWranglerPowerStateSleep)) {
6863 evaluatePolicy( kStimulusLeaveUserActiveState );
6864 }
6865 }
6866
6867 if (newPowerState <= kWranglerPowerStateSleep) {
6868 evaluatePolicy( kStimulusDisplayWranglerSleep );
6869 } else if (newPowerState == kWranglerPowerStateMax) {
6870 evaluatePolicy( kStimulusDisplayWranglerWake );
6871 }
6872 #endif /* DISPLAY_WRANGLER_PRESENT */
6873 }
6874
6875 //******************************************************************************
6876 // User active state management
6877 //******************************************************************************
6878
6879 void
preventTransitionToUserActive(bool prevent)6880 IOPMrootDomain::preventTransitionToUserActive( bool prevent )
6881 {
6882 #if DISPLAY_WRANGLER_PRESENT
6883 _preventUserActive = prevent;
6884 if (wrangler && !_preventUserActive) {
6885 // Allowing transition to user active, but the wrangler may have
6886 // already powered ON in case of sleep cancel/revert. Poll the
6887 // same conditions checked for in displayWranglerNotification()
6888 // to bring the user active state up to date.
6889
6890 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
6891 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
6892 kWranglerPowerStateMax)) {
6893 evaluatePolicy( kStimulusEnterUserActiveState );
6894 }
6895 }
6896 #endif /* DISPLAY_WRANGLER_PRESENT */
6897 }
6898
6899 //******************************************************************************
6900 // Approve usage of delayed child notification by PM.
6901 //******************************************************************************
6902
6903 bool
shouldDelayChildNotification(IOService * service)6904 IOPMrootDomain::shouldDelayChildNotification(
6905 IOService * service )
6906 {
6907 if ((kFullWakeReasonNone == fullWakeReason) &&
6908 (kSystemTransitionWake == _systemTransitionType)) {
6909 DLOG("%s: delay child notify\n", service->getName());
6910 return true;
6911 }
6912 return false;
6913 }
6914
6915 //******************************************************************************
6916 // PM actions for PCI device.
6917 //******************************************************************************
6918
6919 void
handlePowerChangeStartForPCIDevice(IOService * service,IOPMActions * actions,const IOPMRequest * request,IOPMPowerStateIndex powerState,IOPMPowerChangeFlags * inOutChangeFlags)6920 IOPMrootDomain::handlePowerChangeStartForPCIDevice(
6921 IOService * service,
6922 IOPMActions * actions,
6923 const IOPMRequest * request,
6924 IOPMPowerStateIndex powerState,
6925 IOPMPowerChangeFlags * inOutChangeFlags )
6926 {
6927 pmTracer->tracePCIPowerChange(
6928 PMTraceWorker::kPowerChangeStart,
6929 service, *inOutChangeFlags,
6930 (actions->flags & kPMActionsPCIBitNumberMask));
6931 }
6932
6933 void
handlePowerChangeDoneForPCIDevice(IOService * service,IOPMActions * actions,const IOPMRequest * request,IOPMPowerStateIndex powerState,IOPMPowerChangeFlags changeFlags)6934 IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
6935 IOService * service,
6936 IOPMActions * actions,
6937 const IOPMRequest * request,
6938 IOPMPowerStateIndex powerState,
6939 IOPMPowerChangeFlags changeFlags )
6940 {
6941 pmTracer->tracePCIPowerChange(
6942 PMTraceWorker::kPowerChangeCompleted,
6943 service, changeFlags,
6944 (actions->flags & kPMActionsPCIBitNumberMask));
6945 }
6946
6947 //******************************************************************************
6948 // registerInterest
6949 //
6950 // Override IOService::registerInterest() for root domain clients.
6951 //******************************************************************************
6952
6953 class IOPMServiceInterestNotifier : public _IOServiceInterestNotifier
6954 {
6955 friend class IOPMrootDomain;
6956 OSDeclareDefaultStructors(IOPMServiceInterestNotifier);
6957
6958 protected:
6959 uint32_t ackTimeoutCnt;
6960 uint32_t msgType; // Last type seen by the message filter
6961 uint32_t lastSleepWakeMsgType;
6962 uint32_t msgIndex;
6963 uint32_t maxMsgDelayMS;
6964 uint32_t maxAckDelayMS;
6965 uint64_t msgAbsTime;
6966 uint64_t uuid0;
6967 uint64_t uuid1;
6968 OSSharedPtr<const OSSymbol> identifier;
6969 OSSharedPtr<const OSSymbol> clientName;
6970 };
6971
OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier,_IOServiceInterestNotifier)6972 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
6973
6974 OSSharedPtr<IONotifier>
6975 IOPMrootDomain::registerInterest(
6976 const OSSymbol * typeOfInterest,
6977 IOServiceInterestHandler handler,
6978 void * target, void * ref )
6979 {
6980 IOPMServiceInterestNotifier* notifier;
6981 bool isSystemCapabilityClient;
6982 bool isKernelCapabilityClient;
6983 IOReturn rc = kIOReturnError;
6984
6985 isSystemCapabilityClient = typeOfInterest &&
6986 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
6987
6988 isKernelCapabilityClient = typeOfInterest &&
6989 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
6990
6991 if (isSystemCapabilityClient) {
6992 typeOfInterest = gIOAppPowerStateInterest;
6993 }
6994
6995 notifier = new IOPMServiceInterestNotifier;
6996 if (!notifier) {
6997 return NULL;
6998 }
6999
7000 if (notifier->init()) {
7001 rc = super::registerInterestForNotifier(notifier, typeOfInterest, handler, target, ref);
7002 }
7003 if (rc != kIOReturnSuccess) {
7004 OSSafeReleaseNULL(notifier);
7005 return NULL;
7006 }
7007
7008 notifier->ackTimeoutCnt = 0;
7009
7010 if (pmPowerStateQueue) {
7011 if (isSystemCapabilityClient) {
7012 notifier->retain();
7013 if (pmPowerStateQueue->submitPowerEvent(
7014 kPowerEventRegisterSystemCapabilityClient, notifier) == false) {
7015 notifier->release();
7016 }
7017 }
7018
7019 if (isKernelCapabilityClient) {
7020 notifier->retain();
7021 if (pmPowerStateQueue->submitPowerEvent(
7022 kPowerEventRegisterKernelCapabilityClient, notifier) == false) {
7023 notifier->release();
7024 }
7025 }
7026 }
7027
7028 OSSharedPtr<OSData> data;
7029 uint8_t *uuid = NULL;
7030 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithAddress((vm_address_t)handler);
7031 if (kext) {
7032 data = kext->copyUUID();
7033 }
7034 if (data && (data->getLength() == sizeof(uuid_t))) {
7035 uuid = (uint8_t *)(data->getBytesNoCopy());
7036
7037 notifier->uuid0 = ((uint64_t)(uuid[0]) << 56) | ((uint64_t)(uuid[1]) << 48) | ((uint64_t)(uuid[2]) << 40) |
7038 ((uint64_t)(uuid[3]) << 32) | ((uint64_t)(uuid[4]) << 24) | ((uint64_t)(uuid[5]) << 16) |
7039 ((uint64_t)(uuid[6]) << 8) | (uuid[7]);
7040 notifier->uuid1 = ((uint64_t)(uuid[8]) << 56) | ((uint64_t)(uuid[9]) << 48) | ((uint64_t)(uuid[10]) << 40) |
7041 ((uint64_t)(uuid[11]) << 32) | ((uint64_t)(uuid[12]) << 24) | ((uint64_t)(uuid[13]) << 16) |
7042 ((uint64_t)(uuid[14]) << 8) | (uuid[15]);
7043
7044 notifier->identifier = copyKextIdentifierWithAddress((vm_address_t) handler);
7045 }
7046 return OSSharedPtr<IOPMServiceInterestNotifier>(notifier, OSNoRetain);
7047 }
7048
7049 //******************************************************************************
7050 // systemMessageFilter
7051 //
7052 //******************************************************************************
7053
7054 bool
systemMessageFilter(void * object,void * arg1,void * arg2,void * arg3)7055 IOPMrootDomain::systemMessageFilter(
7056 void * object, void * arg1, void * arg2, void * arg3 )
7057 {
7058 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
7059 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
7060 bool isCapPowerd = (object == (void *) systemCapabilityNotifier.get());
7061 bool isCapClient = false;
7062 bool allow = false;
7063 OSBoolean **waitForReply = (typeof(waitForReply))arg3;
7064 IOPMServiceInterestNotifier *notifier;
7065
7066 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
7067
7068 do {
7069 // When powerd and kernel priority clients register capability interest,
7070 // the power tree is sync'ed to inform those clients about the current
7071 // system capability. Only allow capability change messages during sync.
7072 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
7073 (!isCapMsg || !_joinedCapabilityClients ||
7074 !_joinedCapabilityClients->containsObject((OSObject *) object))) {
7075 break;
7076 }
7077
7078 // Capability change message for powerd and kernel clients
7079 if (isCapMsg) {
7080 // Kernel priority clients
7081 if ((context->notifyType == kNotifyPriority) ||
7082 (context->notifyType == kNotifyCapabilityChangePriority)) {
7083 isCapClient = true;
7084 }
7085
7086 // powerd will maintain two client registrations with root domain.
7087 // isCapPowerd will be TRUE for any message targeting the powerd
7088 // exclusive (capability change) interest registration.
7089 if (isCapPowerd && (context->notifyType == kNotifyCapabilityChangeApps)) {
7090 isCapClient = true;
7091 }
7092 }
7093
7094 if (isCapClient) {
7095 IOPMSystemCapabilityChangeParameters * capArgs =
7096 (IOPMSystemCapabilityChangeParameters *) arg2;
7097
7098 if (kSystemTransitionNewCapClient == _systemTransitionType) {
7099 capArgs->fromCapabilities = 0;
7100 capArgs->toCapabilities = _currentCapability;
7101 capArgs->changeFlags = 0;
7102 } else {
7103 capArgs->fromCapabilities = _currentCapability;
7104 capArgs->toCapabilities = _pendingCapability;
7105
7106 if (context->isPreChange) {
7107 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
7108 } else {
7109 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
7110 }
7111
7112 if (isCapPowerd && context->isPreChange) {
7113 toldPowerdCapWillChange = true;
7114 }
7115 }
7116
7117 // App level capability change messages must only go to powerd.
7118 // Wait for response post-change if capabilitiy is increasing.
7119 // Wait for response pre-change if capability is decreasing.
7120
7121 if ((context->notifyType == kNotifyCapabilityChangeApps) && waitForReply &&
7122 ((capabilityLoss && context->isPreChange) ||
7123 (!capabilityLoss && !context->isPreChange))) {
7124 *waitForReply = kOSBooleanTrue;
7125 }
7126
7127 allow = true;
7128 break;
7129 }
7130
7131 // powerd will always receive CanSystemSleep, even for a demand sleep.
7132 // It will also have a final chance to veto sleep after all clients
7133 // have responded to SystemWillSleep
7134
7135 if ((kIOMessageCanSystemSleep == context->messageType) ||
7136 (kIOMessageSystemWillNotSleep == context->messageType)) {
7137 if (isCapPowerd) {
7138 allow = true;
7139 break;
7140 }
7141
7142 // Demand sleep, don't ask apps for permission
7143 if (context->changeFlags & kIOPMSkipAskPowerDown) {
7144 break;
7145 }
7146 }
7147
7148 if (kIOPMMessageLastCallBeforeSleep == context->messageType) {
7149 if (isCapPowerd && CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
7150 (fullToDarkReason == kIOPMSleepReasonIdle)) {
7151 allow = true;
7152 }
7153 break;
7154 }
7155
7156 // Drop capability change messages for legacy clients.
7157 // Drop legacy system sleep messages for powerd capability interest.
7158 if (isCapMsg || isCapPowerd) {
7159 break;
7160 }
7161
7162 // Not a capability change message.
7163 // Perform message filtering based on _systemMessageClientMask.
7164
7165 if ((context->notifyType == kNotifyApps) &&
7166 (_systemMessageClientMask & kSystemMessageClientLegacyApp)) {
7167 if (!notifier) {
7168 break;
7169 }
7170
7171 if ((notifier->lastSleepWakeMsgType == context->messageType) &&
7172 (notifier->lastSleepWakeMsgType == kIOMessageSystemWillPowerOn)) {
7173 break; // drop any duplicate WillPowerOn for AOT devices
7174 }
7175
7176 allow = true;
7177
7178 if (waitForReply) {
7179 if (notifier->ackTimeoutCnt >= 3) {
7180 *waitForReply = kOSBooleanFalse;
7181 } else {
7182 *waitForReply = kOSBooleanTrue;
7183 }
7184 }
7185 } else if ((context->notifyType == kNotifyPriority) &&
7186 (_systemMessageClientMask & kSystemMessageClientKernel)) {
7187 allow = true;
7188 }
7189
7190 // Check sleep/wake message ordering
7191 if (allow) {
7192 if (context->messageType == kIOMessageSystemWillSleep ||
7193 context->messageType == kIOMessageSystemWillPowerOn ||
7194 context->messageType == kIOMessageSystemHasPoweredOn) {
7195 notifier->lastSleepWakeMsgType = context->messageType;
7196 }
7197 }
7198 } while (false);
7199
7200 if (allow && isCapMsg && _joinedCapabilityClients) {
7201 _joinedCapabilityClients->removeObject((OSObject *) object);
7202 if (_joinedCapabilityClients->getCount() == 0) {
7203 DMSG("destroyed capability client set %p\n",
7204 OBFUSCATE(_joinedCapabilityClients.get()));
7205 _joinedCapabilityClients.reset();
7206 }
7207 }
7208 if (notifier) {
7209 // Record the last seen message type even if the message is dropped
7210 // for traceFilteredNotification().
7211 notifier->msgType = context->messageType;
7212 }
7213
7214 return allow;
7215 }
7216
7217 //******************************************************************************
7218 // setMaintenanceWakeCalendar
7219 //
7220 //******************************************************************************
7221
7222 IOReturn
setMaintenanceWakeCalendar(const IOPMCalendarStruct * calendar)7223 IOPMrootDomain::setMaintenanceWakeCalendar(
7224 const IOPMCalendarStruct * calendar )
7225 {
7226 OSSharedPtr<OSData> data;
7227 IOReturn ret = 0;
7228
7229 if (!calendar) {
7230 return kIOReturnBadArgument;
7231 }
7232
7233 data = OSData::withValue(*calendar);
7234 if (!data) {
7235 return kIOReturnNoMemory;
7236 }
7237
7238 if (kPMCalendarTypeMaintenance == calendar->selector) {
7239 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey.get(), data.get());
7240 } else if (kPMCalendarTypeSleepService == calendar->selector) {
7241 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey.get(), data.get());
7242 }
7243
7244 return ret;
7245 }
7246
7247 // MARK: -
7248 // MARK: Display Wrangler
7249
7250 //******************************************************************************
7251 // displayWranglerNotification
7252 //
7253 // Handle the notification when the IODisplayWrangler changes power state.
7254 //******************************************************************************
7255
7256 IOReturn
displayWranglerNotification(void * target,void * refCon,UInt32 messageType,IOService * service,void * messageArgument,vm_size_t argSize)7257 IOPMrootDomain::displayWranglerNotification(
7258 void * target, void * refCon,
7259 UInt32 messageType, IOService * service,
7260 void * messageArgument, vm_size_t argSize )
7261 {
7262 #if DISPLAY_WRANGLER_PRESENT
7263 IOPMPowerStateIndex displayPowerState;
7264 IOPowerStateChangeNotification * params =
7265 (IOPowerStateChangeNotification *) messageArgument;
7266
7267 if ((messageType != kIOMessageDeviceWillPowerOff) &&
7268 (messageType != kIOMessageDeviceHasPoweredOn)) {
7269 return kIOReturnUnsupported;
7270 }
7271
7272 ASSERT_GATED();
7273 if (!gRootDomain) {
7274 return kIOReturnUnsupported;
7275 }
7276
7277 displayPowerState = params->stateNumber;
7278 DLOG("wrangler %s ps %d\n",
7279 getIOMessageString(messageType), (uint32_t) displayPowerState);
7280
7281 switch (messageType) {
7282 case kIOMessageDeviceWillPowerOff:
7283 // Display wrangler has dropped power due to display idle
7284 // or force system sleep.
7285 //
7286 // 4 Display ON kWranglerPowerStateMax
7287 // 3 Display Dim kWranglerPowerStateDim
7288 // 2 Display Sleep kWranglerPowerStateSleep
7289 // 1 Not visible to user
7290 // 0 Not visible to user kWranglerPowerStateMin
7291
7292 if (displayPowerState <= kWranglerPowerStateSleep) {
7293 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
7294 }
7295 break;
7296
7297 case kIOMessageDeviceHasPoweredOn:
7298 // Display wrangler has powered on due to user activity
7299 // or wake from sleep.
7300
7301 if (kWranglerPowerStateMax == displayPowerState) {
7302 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
7303
7304 // See comment in handleUpdatePowerClientForDisplayWrangler
7305 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
7306 kWranglerPowerStateMax) {
7307 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
7308 }
7309 }
7310 break;
7311 }
7312 #endif /* DISPLAY_WRANGLER_PRESENT */
7313 return kIOReturnUnsupported;
7314 }
7315
7316 //******************************************************************************
7317 // reportUserInput
7318 //
7319 //******************************************************************************
7320
7321 void
updateUserActivity(void)7322 IOPMrootDomain::updateUserActivity( void )
7323 {
7324 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7325 clock_get_uptime(&userActivityTime);
7326 bool aborting = ((lastSleepReason == kIOPMSleepReasonSoftware)
7327 || (lastSleepReason == kIOPMSleepReasonIdle)
7328 || (lastSleepReason == kIOPMSleepReasonMaintenance));
7329 if (aborting) {
7330 userActivityCount++;
7331 DLOG("user activity reported %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
7332 }
7333 #endif
7334 }
7335 void
reportUserInput(void)7336 IOPMrootDomain::reportUserInput( void )
7337 {
7338 if (wrangler) {
7339 wrangler->activityTickle(0, 0);
7340 }
7341 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7342 // Update user activity
7343 updateUserActivity();
7344
7345 if (!darkWakeExit && ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0)) {
7346 // update user active abs time
7347 clock_get_uptime(&gUserActiveAbsTime);
7348 pmPowerStateQueue->submitPowerEvent(
7349 kPowerEventPolicyStimulus,
7350 (void *) kStimulusDarkWakeActivityTickle,
7351 true /* set wake type */ );
7352 }
7353 #endif
7354 }
7355
7356 void
requestUserActive(IOService * device,const char * reason)7357 IOPMrootDomain::requestUserActive(IOService *device, const char *reason)
7358 {
7359 #if DISPLAY_WRANGLER_PRESENT
7360 if (wrangler) {
7361 wrangler->activityTickle(0, 0);
7362 }
7363 #else
7364 if (!device) {
7365 DLOG("requestUserActive: device is null\n");
7366 return;
7367 }
7368 OSSharedPtr<const OSSymbol> deviceName = device->copyName();
7369 uint64_t registryID = device->getRegistryEntryID();
7370
7371 if (!deviceName || !registryID) {
7372 DLOG("requestUserActive: no device name or registry entry\n");
7373 return;
7374 }
7375 const char *name = deviceName->getCStringNoCopy();
7376 char payload[128];
7377 snprintf(payload, sizeof(payload), "%s:%s", name, reason);
7378 DLOG("requestUserActive from %s (0x%llx) for %s\n", name, registryID, reason);
7379 messageClient(kIOPMMessageRequestUserActive, systemCapabilityNotifier.get(), (void *)payload, sizeof(payload));
7380 #endif
7381 }
7382
7383 //******************************************************************************
7384 // latchDisplayWranglerTickle
7385 //******************************************************************************
7386
7387 bool
latchDisplayWranglerTickle(bool latch)7388 IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
7389 {
7390 #if DISPLAY_WRANGLER_PRESENT
7391 if (latch) {
7392 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
7393 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7394 !checkSystemCanSustainFullWake()) {
7395 // Currently in dark wake, and not transitioning to full wake.
7396 // Full wake is unsustainable, so latch the tickle to prevent
7397 // the display from lighting up momentarily.
7398 wranglerTickled = true;
7399 } else {
7400 wranglerTickled = false;
7401 }
7402 } else if (wranglerTickled && checkSystemCanSustainFullWake()) {
7403 wranglerTickled = false;
7404
7405 pmPowerStateQueue->submitPowerEvent(
7406 kPowerEventPolicyStimulus,
7407 (void *) kStimulusDarkWakeActivityTickle );
7408 }
7409
7410 return wranglerTickled;
7411 #else /* ! DISPLAY_WRANGLER_PRESENT */
7412 return false;
7413 #endif /* ! DISPLAY_WRANGLER_PRESENT */
7414 }
7415
7416 //******************************************************************************
7417 // setDisplayPowerOn
7418 //
7419 // For root domain user client
7420 //******************************************************************************
7421
7422 void
setDisplayPowerOn(uint32_t options)7423 IOPMrootDomain::setDisplayPowerOn( uint32_t options )
7424 {
7425 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
7426 (void *) NULL, options );
7427 }
7428
7429 // MARK: -
7430 // MARK: System PM Policy
7431
7432 //******************************************************************************
7433 // checkSystemSleepAllowed
7434 //
7435 //******************************************************************************
7436
7437 bool
checkSystemSleepAllowed(IOOptionBits options,uint32_t sleepReason)7438 IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
7439 uint32_t sleepReason )
7440 {
7441 uint32_t err = 0;
7442
7443 // Conditions that prevent idle and demand system sleep.
7444
7445 do {
7446 if (gSleepDisabledFlag) {
7447 err = kPMConfigPreventSystemSleep;
7448 break;
7449 }
7450
7451 if (userDisabledAllSleep) {
7452 err = kPMUserDisabledAllSleep; // 1. user-space sleep kill switch
7453 break;
7454 }
7455
7456 if (systemBooting || systemShutdown || gWillShutdown) {
7457 err = kPMSystemRestartBootingInProgress; // 2. restart or shutdown in progress
7458 break;
7459 }
7460
7461 if (options == 0) {
7462 break;
7463 }
7464
7465 // Conditions above pegs the system at full wake.
7466 // Conditions below prevent system sleep but does not prevent
7467 // dark wake, and must be called from gated context.
7468
7469 #if !CONFIG_SLEEP
7470 err = kPMConfigPreventSystemSleep; // 3. config does not support sleep
7471 break;
7472 #endif
7473
7474 if (lowBatteryCondition || thermalWarningState || thermalEmergencyState) {
7475 break; // always sleep on low battery or when in thermal warning/emergency state
7476 }
7477
7478 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency) {
7479 break; // always sleep on dark wake thermal emergencies
7480 }
7481
7482 if (preventSystemSleepList->getCount() != 0) {
7483 err = kPMChildPreventSystemSleep; // 4. child prevent system sleep clamp
7484 break;
7485 }
7486
7487 if (_driverKitMatchingAssertionCount != 0) {
7488 err = kPMCPUAssertion;
7489 break;
7490 }
7491
7492 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
7493 kIOPMDriverAssertionLevelOn) {
7494 err = kPMCPUAssertion; // 5. CPU assertion
7495 break;
7496 }
7497
7498 if (pciCantSleepValid) {
7499 if (pciCantSleepFlag) {
7500 err = kPMPCIUnsupported; // 6. PCI card does not support PM (cached)
7501 }
7502 break;
7503 } else if (sleepSupportedPEFunction &&
7504 CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
7505 IOReturn ret;
7506 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
7507 ret = getPlatform()->callPlatformFunction(
7508 sleepSupportedPEFunction.get(), false,
7509 NULL, NULL, NULL, NULL);
7510 pciCantSleepValid = true;
7511 pciCantSleepFlag = false;
7512 if ((platformSleepSupport & kPCICantSleep) ||
7513 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported))) {
7514 err = 6; // 6. PCI card does not support PM
7515 pciCantSleepFlag = true;
7516 break;
7517 }
7518 }
7519 }while (false);
7520
7521 if (err) {
7522 DLOG("System sleep prevented by %s\n", getSystemSleepPreventerString(err));
7523 return false;
7524 }
7525 return true;
7526 }
7527
7528 bool
checkSystemSleepEnabled(void)7529 IOPMrootDomain::checkSystemSleepEnabled( void )
7530 {
7531 return checkSystemSleepAllowed(0, 0);
7532 }
7533
7534 bool
checkSystemCanSleep(uint32_t sleepReason)7535 IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
7536 {
7537 ASSERT_GATED();
7538 return checkSystemSleepAllowed(1, sleepReason);
7539 }
7540
7541 //******************************************************************************
7542 // checkSystemCanSustainFullWake
7543 //******************************************************************************
7544
7545 bool
checkSystemCanSustainFullWake(void)7546 IOPMrootDomain::checkSystemCanSustainFullWake( void )
7547 {
7548 if (lowBatteryCondition || thermalWarningState || thermalEmergencyState) {
7549 // Low battery wake, or received a low battery notification
7550 // while system is awake. This condition will persist until
7551 // the following wake.
7552 return false;
7553 }
7554
7555 if (clamshellExists && clamshellClosed && !clamshellSleepDisableMask) {
7556 // Graphics state is unknown and external display might not be probed.
7557 // Do not incorporate state that requires graphics to be in max power
7558 // such as desktopMode or clamshellDisabled.
7559
7560 if (!acAdaptorConnected) {
7561 DLOG("full wake check: no AC\n");
7562 return false;
7563 }
7564 }
7565 return true;
7566 }
7567
7568 //******************************************************************************
7569 // mustHibernate
7570 //******************************************************************************
7571
7572 #if HIBERNATION
7573
7574 bool
mustHibernate(void)7575 IOPMrootDomain::mustHibernate( void )
7576 {
7577 return lowBatteryCondition || thermalWarningState;
7578 }
7579
7580 #endif /* HIBERNATION */
7581
7582 //******************************************************************************
7583 // AOT
7584 //******************************************************************************
7585
7586 // Tables for accumulated days in year by month, latter used for leap years
7587
7588 static const unsigned int daysbymonth[] =
7589 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
7590
7591 static const unsigned int lydaysbymonth[] =
7592 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
7593
7594 static int __unused
IOPMConvertSecondsToCalendar(clock_sec_t secs,IOPMCalendarStruct * dt)7595 IOPMConvertSecondsToCalendar(clock_sec_t secs, IOPMCalendarStruct * dt)
7596 {
7597 const unsigned int * dbm = daysbymonth;
7598 clock_sec_t n, x, y, z;
7599
7600 // Calculate seconds, minutes and hours
7601
7602 n = secs % (24 * 3600);
7603 dt->second = n % 60;
7604 n /= 60;
7605 dt->minute = n % 60;
7606 dt->hour = (typeof(dt->hour))(n / 60);
7607
7608 // Calculate day of week
7609
7610 n = secs / (24 * 3600);
7611 // dt->dayWeek = (n + 4) % 7;
7612
7613 // Calculate year
7614 // Rebase from days since Unix epoch (1/1/1970) store in 'n',
7615 // to days since 1/1/1968 to start on 4 year cycle, beginning
7616 // on a leap year.
7617
7618 n += (366 + 365);
7619
7620 // Every 4 year cycle will be exactly (366 + 365 * 3) = 1461 days.
7621 // Valid before 2100, since 2100 is not a leap year.
7622
7623 x = n / 1461; // number of 4 year cycles
7624 y = n % 1461; // days into current 4 year cycle
7625 z = 1968 + (4 * x);
7626
7627 // Add in years in the current 4 year cycle
7628
7629 if (y >= 366) {
7630 y -= 366; // days after the leap year
7631 n = y % 365; // days into the current year
7632 z += (1 + y / 365); // years after the past 4-yr cycle
7633 } else {
7634 n = y;
7635 dbm = lydaysbymonth;
7636 }
7637 if (z > 2099) {
7638 return 0;
7639 }
7640
7641 dt->year = (typeof(dt->year))z;
7642
7643 // Adjust remaining days value to start at 1
7644
7645 n += 1;
7646
7647 // Calculate month
7648
7649 for (x = 1; (n > dbm[x]) && (x < 12); x++) {
7650 continue;
7651 }
7652 dt->month = (typeof(dt->month))x;
7653
7654 // Calculate day of month
7655
7656 dt->day = (typeof(dt->day))(n - dbm[x - 1]);
7657
7658 return 1;
7659 }
7660
7661 static clock_sec_t
IOPMConvertCalendarToSeconds(const IOPMCalendarStruct * dt)7662 IOPMConvertCalendarToSeconds(const IOPMCalendarStruct * dt)
7663 {
7664 const unsigned int * dbm = daysbymonth;
7665 long y, secs, days;
7666
7667 if (dt->year < 1970 || dt->month > 12) {
7668 return 0;
7669 }
7670
7671 // Seconds elapsed in the current day
7672
7673 secs = dt->second + 60 * dt->minute + 3600 * dt->hour;
7674
7675 // Number of days from 1/1/70 to beginning of current year
7676 // Account for extra day every 4 years starting at 1973
7677
7678 y = dt->year - 1970;
7679 days = (y * 365) + ((y + 1) / 4);
7680
7681 // Change table if current year is a leap year
7682
7683 if ((dt->year % 4) == 0) {
7684 dbm = lydaysbymonth;
7685 }
7686
7687 // Add in days elapsed in the current year
7688
7689 days += (dt->day - 1) + dbm[dt->month - 1];
7690
7691 // Add accumulated days to accumulated seconds
7692
7693 secs += 24 * 3600 * days;
7694
7695 return secs;
7696 }
7697
7698 unsigned long
getRUN_STATE(void)7699 IOPMrootDomain::getRUN_STATE(void)
7700 {
7701 return (_aotNow && !(kIOPMWakeEventAOTExitFlags & _aotPendingFlags)) ? AOT_STATE : ON_STATE;
7702 }
7703
7704 bool
isAOTMode()7705 IOPMrootDomain::isAOTMode()
7706 {
7707 return _aotNow;
7708 }
7709
7710 IOReturn
setWakeTime(uint64_t wakeContinuousTime)7711 IOPMrootDomain::setWakeTime(uint64_t wakeContinuousTime)
7712 {
7713 clock_sec_t nowsecs, wakesecs;
7714 clock_usec_t nowmicrosecs, wakemicrosecs;
7715 uint64_t nowAbs, wakeAbs;
7716
7717 if (!_aotMode) {
7718 return kIOReturnNotReady;
7719 }
7720
7721 clock_gettimeofday_and_absolute_time(&nowsecs, &nowmicrosecs, &nowAbs);
7722 wakeAbs = continuoustime_to_absolutetime(wakeContinuousTime);
7723 if (wakeAbs < nowAbs) {
7724 printf(LOG_PREFIX "wakeAbs %qd < nowAbs %qd\n", wakeAbs, nowAbs);
7725 wakeAbs = nowAbs;
7726 }
7727 wakeAbs -= nowAbs;
7728 absolutetime_to_microtime(wakeAbs, &wakesecs, &wakemicrosecs);
7729
7730 wakesecs += nowsecs;
7731 wakemicrosecs += nowmicrosecs;
7732 if (wakemicrosecs >= USEC_PER_SEC) {
7733 wakesecs++;
7734 wakemicrosecs -= USEC_PER_SEC;
7735 }
7736 if (wakemicrosecs >= (USEC_PER_SEC / 10)) {
7737 wakesecs++;
7738 }
7739
7740 IOPMConvertSecondsToCalendar(wakesecs, &_aotWakeTimeCalendar);
7741
7742 if (_aotWakeTimeContinuous != wakeContinuousTime) {
7743 _aotWakeTimeContinuous = wakeContinuousTime;
7744 IOLog(LOG_PREFIX "setWakeTime: " YMDTF "\n", YMDT(&_aotWakeTimeCalendar));
7745 }
7746 _aotWakeTimeCalendar.selector = kPMCalendarTypeMaintenance;
7747 _aotWakeTimeUTC = wakesecs;
7748
7749 return kIOReturnSuccess;
7750 }
7751
7752 // assumes WAKEEVENT_LOCK
7753 bool
aotShouldExit(bool checkTimeSet,bool software)7754 IOPMrootDomain::aotShouldExit(bool checkTimeSet, bool software)
7755 {
7756 bool exitNow = false;
7757 const char * reason = "";
7758
7759 if (!_aotNow) {
7760 return false;
7761 }
7762
7763 if (software) {
7764 exitNow = true;
7765 _aotMetrics->softwareRequestCount++;
7766 reason = "software request";
7767 } else if (kIOPMWakeEventAOTExitFlags & _aotPendingFlags) {
7768 exitNow = true;
7769 reason = gWakeReasonString;
7770 } else if (checkTimeSet && (kPMCalendarTypeInvalid == _aotWakeTimeCalendar.selector)) {
7771 exitNow = true;
7772 _aotMetrics->noTimeSetCount++;
7773 reason = "flipbook expired";
7774 } else if ((kIOPMAOTModeRespectTimers & _aotMode) && _calendarWakeAlarmUTC) {
7775 clock_sec_t sec;
7776 clock_usec_t usec;
7777 clock_get_calendar_microtime(&sec, &usec);
7778 if (_calendarWakeAlarmUTC <= sec) {
7779 exitNow = true;
7780 _aotMetrics->rtcAlarmsCount++;
7781 reason = "user alarm";
7782 }
7783 }
7784 if (exitNow) {
7785 _aotPendingFlags |= kIOPMWakeEventAOTExit;
7786 IOLog(LOG_PREFIX "AOT exit for %s, sc %d po %d, cp %d, rj %d, ex %d, nt %d, rt %d\n",
7787 reason,
7788 _aotMetrics->sleepCount,
7789 _aotMetrics->possibleCount,
7790 _aotMetrics->confirmedPossibleCount,
7791 _aotMetrics->rejectedPossibleCount,
7792 _aotMetrics->expiredPossibleCount,
7793 _aotMetrics->noTimeSetCount,
7794 _aotMetrics->rtcAlarmsCount);
7795 }
7796 return exitNow;
7797 }
7798
7799 void
aotExit(bool cps)7800 IOPMrootDomain::aotExit(bool cps)
7801 {
7802 uint32_t savedMessageMask;
7803
7804 ASSERT_GATED();
7805 _aotNow = false;
7806 _aotReadyToFullWake = false;
7807 if (_aotTimerScheduled) {
7808 _aotTimerES->cancelTimeout();
7809 _aotTimerScheduled = false;
7810 }
7811 updateTasksSuspend(kTasksSuspendNoChange, kTasksSuspendUnsuspended);
7812
7813 _aotMetrics->totalTime += mach_absolute_time() - _aotLastWakeTime;
7814 _aotLastWakeTime = 0;
7815 if (_aotMetrics->sleepCount && (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax)) {
7816 WAKEEVENT_LOCK();
7817 strlcpy(&_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount - 1][0],
7818 gWakeReasonString,
7819 sizeof(_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount]));
7820 WAKEEVENT_UNLOCK();
7821 }
7822
7823 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
7824
7825 // Preserve the message mask since a system wake transition
7826 // may have already started and initialized the mask.
7827 savedMessageMask = _systemMessageClientMask;
7828 _systemMessageClientMask = kSystemMessageClientLegacyApp;
7829 tellClients(kIOMessageSystemWillPowerOn);
7830 _systemMessageClientMask = savedMessageMask | kSystemMessageClientLegacyApp;
7831
7832 if (cps) {
7833 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAOTExit);
7834 }
7835 }
7836
7837 void
aotEvaluate(IOTimerEventSource * timer)7838 IOPMrootDomain::aotEvaluate(IOTimerEventSource * timer)
7839 {
7840 bool exitNow;
7841
7842 IOLog("aotEvaluate(%d) 0x%x\n", (timer != NULL), _aotPendingFlags);
7843
7844 WAKEEVENT_LOCK();
7845 exitNow = aotShouldExit(false, false);
7846 if (timer != NULL) {
7847 _aotTimerScheduled = false;
7848 }
7849 WAKEEVENT_UNLOCK();
7850 if (exitNow) {
7851 aotExit(true);
7852 } else {
7853 #if 0
7854 if (_aotLingerTime) {
7855 uint64_t deadline;
7856 IOLog("aot linger before sleep\n");
7857 clock_absolutetime_interval_to_deadline(_aotLingerTime, &deadline);
7858 clock_delay_until(deadline);
7859 }
7860 #endif
7861 privateSleepSystem(kIOPMSleepReasonSoftware);
7862 }
7863 }
7864
7865 //******************************************************************************
7866 // adjustPowerState
7867 //
7868 // Conditions that affect our wake/sleep decision has changed.
7869 // If conditions dictate that the system must remain awake, clamp power
7870 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
7871 // is TRUE, then remove the power clamp and allow the power state to drop
7872 // to SLEEP_STATE.
7873 //******************************************************************************
7874
7875 void
adjustPowerState(bool sleepASAP)7876 IOPMrootDomain::adjustPowerState( bool sleepASAP )
7877 {
7878 DEBUG_LOG("adjustPowerState %s, asap %d, idleSleepEnabled %d\n",
7879 getPowerStateString((uint32_t) getPowerState()), sleepASAP, idleSleepEnabled);
7880
7881 ASSERT_GATED();
7882
7883 if (_aotNow) {
7884 bool exitNow;
7885
7886 if (AOT_STATE != getPowerState()) {
7887 return;
7888 }
7889 WAKEEVENT_LOCK();
7890 exitNow = aotShouldExit(true, false);
7891 if (!exitNow
7892 && !_aotTimerScheduled
7893 && (kIOPMWakeEventAOTPossibleExit == (kIOPMWakeEventAOTPossibleFlags & _aotPendingFlags))) {
7894 _aotTimerScheduled = true;
7895 if (_aotLingerTime) {
7896 _aotTimerES->setTimeout(_aotLingerTime);
7897 } else {
7898 _aotTimerES->setTimeout(800, kMillisecondScale);
7899 }
7900 }
7901 WAKEEVENT_UNLOCK();
7902 if (exitNow) {
7903 aotExit(true);
7904 } else {
7905 _aotReadyToFullWake = true;
7906 if (!_aotTimerScheduled) {
7907 if (kIOPMDriverAssertionLevelOn == getPMAssertionLevel(kIOPMDriverAssertionCPUBit)) {
7908 // Don't try to force sleep during AOT while IOMobileFramebuffer is holding a power assertion.
7909 // Doing so will result in the sleep being cancelled anyway,
7910 // but this check avoids unnecessary thrashing in the power state engine.
7911 return;
7912 }
7913 privateSleepSystem(kIOPMSleepReasonSoftware);
7914 }
7915 }
7916 return;
7917 }
7918
7919 if ((!idleSleepEnabled) || !checkSystemSleepEnabled()) {
7920 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAdjustPowerState);
7921 } else if (sleepASAP) {
7922 changePowerStateWithTagToPriv(SLEEP_STATE, kCPSReasonAdjustPowerState);
7923 }
7924 }
7925
7926 void
handleSetDisplayPowerOn(bool powerOn)7927 IOPMrootDomain::handleSetDisplayPowerOn(bool powerOn)
7928 {
7929 if (powerOn) {
7930 if (!checkSystemCanSustainFullWake()) {
7931 DLOG("System cannot sustain full wake\n");
7932 return;
7933 }
7934
7935 // Force wrangler to max power state. If system is in dark wake
7936 // this alone won't raise the wrangler's power state.
7937 if (wrangler) {
7938 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
7939 }
7940
7941 // System in dark wake, always requesting full wake should
7942 // not have any bad side-effects, even if the request fails.
7943
7944 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
7945 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
7946 requestFullWake( kFullWakeReasonDisplayOn );
7947 }
7948 } else {
7949 // Relenquish desire to power up display.
7950 // Must first transition to state 1 since wrangler doesn't
7951 // power off the displays at state 0. At state 0 the root
7952 // domain is removed from the wrangler's power client list.
7953 if (wrangler) {
7954 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
7955 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
7956 }
7957 }
7958 }
7959
7960 //******************************************************************************
7961 // dispatchPowerEvent
7962 //
7963 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
7964 //******************************************************************************
7965
7966 void
dispatchPowerEvent(uint32_t event,void * arg0,uint64_t arg1)7967 IOPMrootDomain::dispatchPowerEvent(
7968 uint32_t event, void * arg0, uint64_t arg1 )
7969 {
7970 ASSERT_GATED();
7971
7972 switch (event) {
7973 case kPowerEventFeatureChanged:
7974 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7975 messageClients(kIOPMMessageFeatureChange, this);
7976 break;
7977
7978 case kPowerEventReceivedPowerNotification:
7979 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7980 handlePowerNotification((UInt32)(uintptr_t) arg0 );
7981 break;
7982
7983 case kPowerEventSystemBootCompleted:
7984 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7985 if (systemBooting) {
7986 systemBooting = false;
7987
7988 if (PE_get_default("sleep-disabled", &gSleepDisabledFlag, sizeof(gSleepDisabledFlag))) {
7989 DLOG("Setting gSleepDisabledFlag to %u from device tree\n", gSleepDisabledFlag);
7990 }
7991 if (lowBatteryCondition || thermalEmergencyState) {
7992 if (lowBatteryCondition) {
7993 privateSleepSystem(kIOPMSleepReasonLowPower);
7994 } else {
7995 privateSleepSystem(kIOPMSleepReasonThermalEmergency);
7996 }
7997 // The rest is unnecessary since the system is expected
7998 // to sleep immediately. The following wake will update
7999 // everything.
8000 break;
8001 }
8002
8003 sleepWakeDebugMemAlloc();
8004 saveFailureData2File();
8005
8006 // If lid is closed, re-send lid closed notification
8007 // now that booting is complete.
8008 if (clamshellClosed) {
8009 handlePowerNotification(kLocalEvalClamshellCommand);
8010 }
8011 evaluatePolicy( kStimulusAllowSystemSleepChanged );
8012 }
8013 break;
8014
8015 case kPowerEventSystemShutdown:
8016 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8017 if (kOSBooleanTrue == (OSBoolean *) arg0) {
8018 /* We set systemShutdown = true during shutdown
8019 * to prevent sleep at unexpected times while loginwindow is trying
8020 * to shutdown apps and while the OS is trying to transition to
8021 * complete power of.
8022 *
8023 * Set to true during shutdown, as soon as loginwindow shows
8024 * the "shutdown countdown dialog", through individual app
8025 * termination, and through black screen kernel shutdown.
8026 */
8027 systemShutdown = true;
8028 } else {
8029 /*
8030 * A shutdown was initiated, but then the shutdown
8031 * was cancelled, clearing systemShutdown to false here.
8032 */
8033 systemShutdown = false;
8034 }
8035 break;
8036
8037 case kPowerEventUserDisabledSleep:
8038 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8039 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
8040 break;
8041
8042 case kPowerEventRegisterSystemCapabilityClient:
8043 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8044
8045 // reset() handles the arg0 == nullptr case for us
8046 systemCapabilityNotifier.reset((IONotifier *) arg0, OSRetain);
8047 /* intentional fall-through */
8048 [[clang::fallthrough]];
8049
8050 case kPowerEventRegisterKernelCapabilityClient:
8051 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8052 if (!_joinedCapabilityClients) {
8053 _joinedCapabilityClients = OSSet::withCapacity(8);
8054 }
8055 if (arg0) {
8056 OSSharedPtr<IONotifier> notify((IONotifier *) arg0, OSNoRetain);
8057 if (_joinedCapabilityClients) {
8058 _joinedCapabilityClients->setObject(notify.get());
8059 synchronizePowerTree( kIOPMSyncNoChildNotify );
8060 }
8061 }
8062 break;
8063
8064 case kPowerEventPolicyStimulus:
8065 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8066 if (arg0) {
8067 int stimulus = (int)(uintptr_t) arg0;
8068 evaluatePolicy(stimulus, (uint32_t) arg1);
8069 }
8070 break;
8071
8072 case kPowerEventAssertionCreate:
8073 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8074 if (pmAssertions) {
8075 pmAssertions->handleCreateAssertion((OSValueObject<PMAssertStruct> *)arg0);
8076 }
8077 break;
8078
8079
8080 case kPowerEventAssertionRelease:
8081 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8082 if (pmAssertions) {
8083 pmAssertions->handleReleaseAssertion(arg1);
8084 }
8085 break;
8086
8087 case kPowerEventAssertionSetLevel:
8088 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8089 if (pmAssertions) {
8090 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
8091 }
8092 break;
8093
8094 case kPowerEventQueueSleepWakeUUID:
8095 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8096 handleQueueSleepWakeUUID((OSObject *)arg0);
8097 break;
8098 case kPowerEventPublishSleepWakeUUID:
8099 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8100 handlePublishSleepWakeUUID((bool)arg0);
8101 break;
8102
8103 case kPowerEventSetDisplayPowerOn:
8104 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8105 if (arg1 != 0) {
8106 displayPowerOnRequested = true;
8107 } else {
8108 displayPowerOnRequested = false;
8109 }
8110 handleSetDisplayPowerOn(displayPowerOnRequested);
8111 break;
8112
8113 case kPowerEventPublishWakeType:
8114 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8115
8116 // Don't replace wake type property if already set
8117 if ((arg0 == gIOPMWakeTypeUserKey) ||
8118 !propertyExists(kIOPMRootDomainWakeTypeKey)) {
8119 const char * wakeType = NULL;
8120
8121 if (arg0 == gIOPMWakeTypeUserKey) {
8122 requestUserActive(this, "WakeTypeUser");
8123 wakeType = kIOPMRootDomainWakeTypeUser;
8124 } else if (arg0 == gIOPMSettingDebugWakeRelativeKey) {
8125 if (!(gDarkWakeFlags & kDarkWakeFlagAlarmIsDark)) {
8126 requestUserActive(this, "WakeTypeAlarm");
8127 }
8128 wakeType = kIOPMRootDomainWakeTypeAlarm;
8129 } else if (arg0 == gIOPMSettingSleepServiceWakeCalendarKey) {
8130 darkWakeSleepService = true;
8131 wakeType = kIOPMRootDomainWakeTypeSleepService;
8132 } else if (arg0 == gIOPMSettingMaintenanceWakeCalendarKey) {
8133 wakeType = kIOPMRootDomainWakeTypeMaintenance;
8134 }
8135
8136 if (wakeType) {
8137 setProperty(kIOPMRootDomainWakeTypeKey, wakeType);
8138 }
8139 }
8140 break;
8141
8142 case kPowerEventAOTEvaluate:
8143 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
8144 if (_aotReadyToFullWake) {
8145 aotEvaluate(NULL);
8146 }
8147 break;
8148 }
8149 }
8150
8151 //******************************************************************************
8152 // systemPowerEventOccurred
8153 //
8154 // The power controller is notifying us of a hardware-related power management
8155 // event that we must handle.
8156 //
8157 // systemPowerEventOccurred covers the same functionality that
8158 // receivePowerNotification does; it simply provides a richer API for conveying
8159 // more information.
8160 //******************************************************************************
8161
8162 IOReturn
systemPowerEventOccurred(const OSSymbol * event,uint32_t intValue)8163 IOPMrootDomain::systemPowerEventOccurred(
8164 const OSSymbol *event,
8165 uint32_t intValue)
8166 {
8167 IOReturn attempt = kIOReturnSuccess;
8168 OSSharedPtr<OSNumber> newNumber;
8169
8170 if (!event) {
8171 return kIOReturnBadArgument;
8172 }
8173
8174 newNumber = OSNumber::withNumber(intValue, 8 * sizeof(intValue));
8175 if (!newNumber) {
8176 return kIOReturnInternalError;
8177 }
8178
8179 attempt = systemPowerEventOccurred(event, static_cast<OSObject *>(newNumber.get()));
8180
8181 return attempt;
8182 }
8183
8184 void
setThermalState(OSObject * value)8185 IOPMrootDomain::setThermalState(OSObject *value)
8186 {
8187 OSNumber * num;
8188
8189 if (gIOPMWorkLoop->inGate() == false) {
8190 gIOPMWorkLoop->runAction(
8191 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
8192 (OSObject *)this,
8193 (void *)value);
8194
8195 return;
8196 }
8197 if (value && (num = OSDynamicCast(OSNumber, value))) {
8198 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
8199 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
8200 }
8201 }
8202
8203 IOReturn
systemPowerEventOccurred(const OSSymbol * event,OSObject * value)8204 IOPMrootDomain::systemPowerEventOccurred(
8205 const OSSymbol *event,
8206 OSObject *value)
8207 {
8208 OSSharedPtr<OSDictionary> thermalsDict;
8209 bool shouldUpdate = true;
8210
8211 if (!event || !value) {
8212 return kIOReturnBadArgument;
8213 }
8214
8215 // LOCK
8216 // We reuse featuresDict Lock because it already exists and guards
8217 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
8218 // of stepping on that lock.
8219 if (featuresDictLock) {
8220 IOLockLock(featuresDictLock);
8221 }
8222
8223 OSSharedPtr<OSObject> origThermalsProp = copyProperty(kIOPMRootDomainPowerStatusKey);
8224 OSDictionary * origThermalsDict = OSDynamicCast(OSDictionary, origThermalsProp.get());
8225
8226 if (origThermalsDict) {
8227 thermalsDict = OSDictionary::withDictionary(origThermalsDict);
8228 } else {
8229 thermalsDict = OSDictionary::withCapacity(1);
8230 }
8231
8232 if (!thermalsDict) {
8233 shouldUpdate = false;
8234 goto exit;
8235 }
8236
8237 thermalsDict->setObject(event, value);
8238
8239 setProperty(kIOPMRootDomainPowerStatusKey, thermalsDict.get());
8240
8241 exit:
8242 // UNLOCK
8243 if (featuresDictLock) {
8244 IOLockUnlock(featuresDictLock);
8245 }
8246
8247 if (shouldUpdate) {
8248 if (event &&
8249 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
8250 setThermalState(value);
8251 }
8252 messageClients(kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
8253 }
8254
8255 return kIOReturnSuccess;
8256 }
8257
8258 //******************************************************************************
8259 // receivePowerNotification
8260 //
8261 // The power controller is notifying us of a hardware-related power management
8262 // event that we must handle. This may be a result of an 'environment' interrupt
8263 // from the power mgt micro.
8264 //******************************************************************************
8265
8266 IOReturn
receivePowerNotification(UInt32 msg)8267 IOPMrootDomain::receivePowerNotification( UInt32 msg )
8268 {
8269 if (msg & kIOPMPowerButton) {
8270 uint32_t currentPhase = pmTracer->getTracePhase();
8271 if (currentPhase != kIOPMTracePointSystemUp && currentPhase > kIOPMTracePointSystemSleep) {
8272 DEBUG_LOG("power button pressed during wake. phase = %u\n", currentPhase);
8273 swd_flags |= SWD_PWR_BTN_STACKSHOT;
8274 thread_call_enter(powerButtonDown);
8275 } else {
8276 DEBUG_LOG("power button pressed when system is up\n");
8277 }
8278 } else if (msg & kIOPMPowerButtonUp) {
8279 if (swd_flags & SWD_PWR_BTN_STACKSHOT) {
8280 swd_flags &= ~SWD_PWR_BTN_STACKSHOT;
8281 thread_call_enter(powerButtonUp);
8282 }
8283 } else {
8284 pmPowerStateQueue->submitPowerEvent(
8285 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
8286 }
8287 return kIOReturnSuccess;
8288 }
8289
8290 void
handlePowerNotification(UInt32 msg)8291 IOPMrootDomain::handlePowerNotification( UInt32 msg )
8292 {
8293 bool eval_clamshell = false;
8294 bool eval_clamshell_alarm = false;
8295
8296 ASSERT_GATED();
8297
8298 /*
8299 * Local (IOPMrootDomain only) eval clamshell command
8300 */
8301 if (msg & kLocalEvalClamshellCommand) {
8302 if ((gClamshellFlags & kClamshell_WAR_47715679) && isRTCAlarmWake) {
8303 eval_clamshell_alarm = true;
8304
8305 // reset isRTCAlarmWake. This evaluation should happen only once
8306 // on RTC/Alarm wake. Any clamshell events after wake should follow
8307 // the regular evaluation
8308 isRTCAlarmWake = false;
8309 } else {
8310 eval_clamshell = true;
8311 }
8312 }
8313
8314 /*
8315 * Overtemp
8316 */
8317 if (msg & kIOPMOverTemp) {
8318 DLOG("Thermal overtemp message received!\n");
8319 thermalEmergencyState = true;
8320 privateSleepSystem(kIOPMSleepReasonThermalEmergency);
8321 }
8322
8323 /*
8324 * Forward DW thermal notification to client, if system is not going to sleep
8325 */
8326 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep)) {
8327 DLOG("DarkWake thermal limits message received!\n");
8328 messageClients(kIOPMMessageDarkWakeThermalEmergency);
8329 }
8330
8331 /*
8332 * Sleep Now!
8333 */
8334 if (msg & kIOPMSleepNow) {
8335 privateSleepSystem(kIOPMSleepReasonSoftware);
8336 }
8337
8338 /*
8339 * Power Emergency
8340 */
8341 if (msg & kIOPMPowerEmergency) {
8342 DLOG("Received kIOPMPowerEmergency");
8343 lowBatteryCondition = true;
8344 privateSleepSystem(kIOPMSleepReasonLowPower);
8345 }
8346
8347 /*
8348 * Clamshell OPEN
8349 */
8350 if (msg & kIOPMClamshellOpened) {
8351 DLOG("Clamshell opened\n");
8352 // Received clamshel open message from clamshell controlling driver
8353 // Update our internal state and tell general interest clients
8354 clamshellClosed = false;
8355 clamshellExists = true;
8356
8357 // Don't issue a hid tickle when lid is open and polled on wake
8358 if (msg & kIOPMSetValue) {
8359 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
8360 reportUserInput();
8361 }
8362
8363 // Tell PMCPU
8364 informCPUStateChange(kInformLid, 0);
8365
8366 // Tell general interest clients
8367 sendClientClamshellNotification();
8368
8369 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
8370 || (lastSleepReason == kIOPMSleepReasonIdle)
8371 || (lastSleepReason == kIOPMSleepReasonMaintenance));
8372 if (aborting) {
8373 userActivityCount++;
8374 }
8375 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
8376 }
8377
8378 /*
8379 * Clamshell CLOSED
8380 * Send the clamshell interest notification since the lid is closing.
8381 */
8382 if (msg & kIOPMClamshellClosed) {
8383 if ((clamshellIgnoreClose || (gClamshellFlags & kClamshell_WAR_38378787)) &&
8384 clamshellClosed && clamshellExists) {
8385 DLOG("Ignoring redundant Clamshell close event\n");
8386 } else {
8387 DLOG("Clamshell closed\n");
8388 // Received clamshel open message from clamshell controlling driver
8389 // Update our internal state and tell general interest clients
8390 clamshellClosed = true;
8391 clamshellExists = true;
8392
8393 // Ignore all following clamshell close events until the clamshell
8394 // is opened or the system sleeps. When a clamshell close triggers
8395 // a system wake, the lid driver may send us two clamshell close
8396 // events, one for the clamshell close event itself, and a second
8397 // close event when the driver polls the lid state on wake.
8398 clamshellIgnoreClose = true;
8399
8400 // Tell PMCPU
8401 informCPUStateChange(kInformLid, 1);
8402
8403 // Tell general interest clients
8404 sendClientClamshellNotification();
8405
8406 // And set eval_clamshell = so we can attempt
8407 eval_clamshell = true;
8408 }
8409 }
8410
8411 /*
8412 * Set Desktop mode (sent from graphics)
8413 *
8414 * -> reevaluate lid state
8415 */
8416 if (msg & kIOPMSetDesktopMode) {
8417 desktopMode = (0 != (msg & kIOPMSetValue));
8418 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
8419 DLOG("Desktop mode %d\n", desktopMode);
8420
8421 sendClientClamshellNotification();
8422
8423 // Re-evaluate the lid state
8424 eval_clamshell = true;
8425 }
8426
8427 /*
8428 * AC Adaptor connected
8429 *
8430 * -> reevaluate lid state
8431 */
8432 if (msg & kIOPMSetACAdaptorConnected) {
8433 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
8434 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
8435
8436 // Tell CPU PM
8437 informCPUStateChange(kInformAC, !acAdaptorConnected);
8438
8439 // Tell BSD if AC is connected
8440 // 0 == external power source; 1 == on battery
8441 post_sys_powersource(acAdaptorConnected ? 0:1);
8442
8443 sendClientClamshellNotification();
8444
8445 IOUserServer::powerSourceChanged(acAdaptorConnected);
8446
8447 // Re-evaluate the lid state
8448 eval_clamshell = true;
8449
8450 // Lack of AC may have latched a display wrangler tickle.
8451 // This mirrors the hardware's USB wake event latch, where a latched
8452 // USB wake event followed by an AC attach will trigger a full wake.
8453 latchDisplayWranglerTickle( false );
8454
8455 #if HIBERNATION
8456 // AC presence will reset the standy timer delay adjustment.
8457 _standbyTimerResetSeconds = 0;
8458 #endif
8459 if (!userIsActive) {
8460 // Reset userActivityTime when power supply is changed(rdr 13789330)
8461 clock_get_uptime(&userActivityTime);
8462 }
8463 }
8464
8465 /*
8466 * Enable Clamshell (external display disappear)
8467 *
8468 * -> reevaluate lid state
8469 */
8470 if (msg & kIOPMEnableClamshell) {
8471 DLOG("Clamshell enabled\n");
8472
8473 // Re-evaluate the lid state
8474 // System should sleep on external display disappearance
8475 // in lid closed operation.
8476 if (true == clamshellDisabled) {
8477 eval_clamshell = true;
8478
8479 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8480 // Also clear kClamshellSleepDisableInternal when graphics enables
8481 // the clamshell during a full wake. When graphics is behaving as
8482 // expected, this will allow clamshell close to be honored earlier
8483 // rather than waiting for the delayed evaluation.
8484 if ((clamshellSleepDisableMask & kClamshellSleepDisableInternal) &&
8485 (CAP_PENDING(kIOPMSystemCapabilityGraphics) ||
8486 CAP_CURRENT(kIOPMSystemCapabilityGraphics))) {
8487 setClamShellSleepDisable(false, kClamshellSleepDisableInternal);
8488
8489 // Cancel the TC to avoid an extra kLocalEvalClamshellCommand
8490 // when timer expires which is harmless but useless.
8491 thread_call_cancel(fullWakeThreadCall);
8492 }
8493 #endif
8494 }
8495
8496 clamshellDisabled = false;
8497 sendClientClamshellNotification();
8498 }
8499
8500 /*
8501 * Disable Clamshell (external display appeared)
8502 * We don't bother re-evaluating clamshell state. If the system is awake,
8503 * the lid is probably open.
8504 */
8505 if (msg & kIOPMDisableClamshell) {
8506 DLOG("Clamshell disabled\n");
8507 clamshellDisabled = true;
8508 sendClientClamshellNotification();
8509 }
8510
8511 /*
8512 * Evaluate clamshell and SLEEP if appropriate
8513 */
8514 if (eval_clamshell_alarm && clamshellClosed) {
8515 if (shouldSleepOnRTCAlarmWake()) {
8516 privateSleepSystem(kIOPMSleepReasonClamshell);
8517 }
8518 } else if (eval_clamshell && clamshellClosed) {
8519 if (shouldSleepOnClamshellClosed()) {
8520 privateSleepSystem(kIOPMSleepReasonClamshell);
8521 } else {
8522 evaluatePolicy( kStimulusDarkWakeEvaluate );
8523 }
8524 }
8525
8526 if (msg & kIOPMProModeEngaged) {
8527 int newState = 1;
8528 DLOG("ProModeEngaged\n");
8529 messageClient(kIOPMMessageProModeStateChange, systemCapabilityNotifier.get(), &newState, sizeof(newState));
8530 }
8531
8532 if (msg & kIOPMProModeDisengaged) {
8533 int newState = 0;
8534 DLOG("ProModeDisengaged\n");
8535 messageClient(kIOPMMessageProModeStateChange, systemCapabilityNotifier.get(), &newState, sizeof(newState));
8536 }
8537 }
8538
8539 //******************************************************************************
8540 // evaluatePolicy
8541 //
8542 // Evaluate root-domain policy in response to external changes.
8543 //******************************************************************************
8544
8545 void
evaluatePolicy(int stimulus,uint32_t arg)8546 IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
8547 {
8548 union {
8549 struct {
8550 int idleSleepEnabled : 1;
8551 int idleSleepDisabled : 1;
8552 int displaySleep : 1;
8553 int sleepDelayChanged : 1;
8554 int evaluateDarkWake : 1;
8555 int adjustPowerState : 1;
8556 int userBecameInactive : 1;
8557 int displaySleepEntry : 1;
8558 } bit;
8559 uint32_t u32;
8560 } flags;
8561
8562
8563 ASSERT_GATED();
8564 flags.u32 = 0;
8565
8566 switch (stimulus) {
8567 case kStimulusDisplayWranglerSleep:
8568 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8569 if (!wranglerPowerOff) {
8570 // wrangler is in sleep state or lower
8571 flags.bit.displaySleep = true;
8572 }
8573 if (!wranglerAsleep) {
8574 // transition from wrangler wake to wrangler sleep
8575 flags.bit.displaySleepEntry = true;
8576 wranglerAsleep = true;
8577 }
8578 break;
8579
8580 case kStimulusDisplayWranglerWake:
8581 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8582 displayIdleForDemandSleep = false;
8583 wranglerPowerOff = false;
8584 wranglerAsleep = false;
8585 break;
8586
8587 case kStimulusEnterUserActiveState:
8588 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8589 if (_preventUserActive) {
8590 DLOG("user active dropped\n");
8591 break;
8592 }
8593 if (!userIsActive) {
8594 userIsActive = true;
8595 userWasActive = true;
8596 clock_get_uptime(&gUserActiveAbsTime);
8597
8598 // Stay awake after dropping demand for display power on
8599 if (kFullWakeReasonDisplayOn == fullWakeReason) {
8600 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
8601 DLOG("User activity while in notification wake\n");
8602 changePowerStateWithOverrideTo( getRUN_STATE(), 0);
8603 }
8604
8605 kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
8606 setProperty(gIOPMUserIsActiveKey.get(), kOSBooleanTrue);
8607 messageClients(kIOPMMessageUserIsActiveChanged);
8608 }
8609 flags.bit.idleSleepDisabled = true;
8610 break;
8611
8612 case kStimulusLeaveUserActiveState:
8613 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8614 if (userIsActive) {
8615 clock_get_uptime(&gUserInactiveAbsTime);
8616 userIsActive = false;
8617 clock_get_uptime(&userBecameInactiveTime);
8618 flags.bit.userBecameInactive = true;
8619
8620 kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
8621 setProperty(gIOPMUserIsActiveKey.get(), kOSBooleanFalse);
8622 messageClients(kIOPMMessageUserIsActiveChanged);
8623 }
8624 break;
8625
8626 case kStimulusAggressivenessChanged:
8627 {
8628 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8629 unsigned long aggressiveValue;
8630 uint32_t minutesToIdleSleep = 0;
8631 uint32_t minutesToDisplayDim = 0;
8632 uint32_t minutesDelta = 0;
8633
8634 // Fetch latest display and system sleep slider values.
8635 aggressiveValue = 0;
8636 getAggressiveness(kPMMinutesToSleep, &aggressiveValue);
8637 minutesToIdleSleep = (uint32_t) aggressiveValue;
8638
8639 aggressiveValue = 0;
8640 getAggressiveness(kPMMinutesToDim, &aggressiveValue);
8641 minutesToDisplayDim = (uint32_t) aggressiveValue;
8642 DLOG("aggressiveness changed: system %u->%u, display %u\n",
8643 sleepSlider, minutesToIdleSleep, minutesToDisplayDim);
8644
8645 DLOG("idle time -> %d ms (ena %d)\n",
8646 idleMilliSeconds, (minutesToIdleSleep != 0));
8647
8648 // How long to wait before sleeping the system once
8649 // the displays turns off is indicated by 'extraSleepDelay'.
8650
8651 if (minutesToIdleSleep > minutesToDisplayDim) {
8652 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
8653 } else if (minutesToIdleSleep == minutesToDisplayDim) {
8654 minutesDelta = 1;
8655 }
8656
8657 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0)) {
8658 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
8659 }
8660
8661 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
8662 flags.bit.idleSleepDisabled = true;
8663 idleSleepEnabled = false;
8664 }
8665 #if !defined(XNU_TARGET_OS_OSX)
8666 if (0x7fffffff == minutesToIdleSleep) {
8667 minutesToIdleSleep = idleMilliSeconds / 1000;
8668 }
8669 #endif /* !defined(XNU_TARGET_OS_OSX) */
8670
8671 if (((minutesDelta != extraSleepDelay) ||
8672 (userActivityTime != userActivityTime_prev)) &&
8673 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled) {
8674 flags.bit.sleepDelayChanged = true;
8675 }
8676
8677 if (systemDarkWake && !darkWakeToSleepASAP &&
8678 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled)) {
8679 // Reconsider decision to remain in dark wake
8680 flags.bit.evaluateDarkWake = true;
8681 }
8682
8683 sleepSlider = minutesToIdleSleep;
8684 extraSleepDelay = minutesDelta;
8685 userActivityTime_prev = userActivityTime;
8686 } break;
8687
8688 case kStimulusDemandSystemSleep:
8689 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8690 displayIdleForDemandSleep = true;
8691 if (wrangler && wranglerIdleSettings) {
8692 // Request wrangler idle only when demand sleep is triggered
8693 // from full wake.
8694 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
8695 wrangler->setProperties(wranglerIdleSettings.get());
8696 DLOG("Requested wrangler idle\n");
8697 }
8698 }
8699 // arg = sleepReason
8700 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
8701 break;
8702
8703 case kStimulusAllowSystemSleepChanged:
8704 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8705 flags.bit.adjustPowerState = true;
8706 break;
8707
8708 case kStimulusDarkWakeActivityTickle:
8709 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8710 // arg == true implies real and not self generated wrangler tickle.
8711 // Update wake type on PM work loop instead of the tickle thread to
8712 // eliminate the possibility of an early tickle clobbering the wake
8713 // type set by the platform driver.
8714 if (arg == true) {
8715 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
8716 }
8717
8718 if (!darkWakeExit) {
8719 if (latchDisplayWranglerTickle(true)) {
8720 DLOG("latched tickle\n");
8721 break;
8722 }
8723
8724 darkWakeExit = true;
8725 DLOG("Requesting full wake due to dark wake activity tickle\n");
8726 requestFullWake( kFullWakeReasonLocalUser );
8727 }
8728 break;
8729
8730 case kStimulusDarkWakeEntry:
8731 case kStimulusDarkWakeReentry:
8732 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8733 // Any system transitions since the last dark wake transition
8734 // will invalid the stimulus.
8735
8736 if (arg == _systemStateGeneration) {
8737 DLOG("dark wake entry\n");
8738 systemDarkWake = true;
8739
8740 // Keep wranglerPowerOff an invariant when wrangler is absent
8741 if (wrangler) {
8742 wranglerPowerOff = true;
8743 }
8744
8745 if (kStimulusDarkWakeEntry == stimulus) {
8746 clock_get_uptime(&userBecameInactiveTime);
8747 flags.bit.evaluateDarkWake = true;
8748 if (activitySinceSleep()) {
8749 DLOG("User activity recorded while going to darkwake\n");
8750 reportUserInput();
8751 }
8752 }
8753
8754 // Always accelerate disk spindown while in dark wake,
8755 // even if system does not support/allow sleep.
8756
8757 cancelIdleSleepTimer();
8758 setQuickSpinDownTimeout();
8759 }
8760 break;
8761
8762 case kStimulusDarkWakeEvaluate:
8763 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8764 if (systemDarkWake) {
8765 flags.bit.evaluateDarkWake = true;
8766 }
8767 break;
8768
8769 case kStimulusNoIdleSleepPreventers:
8770 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8771 flags.bit.adjustPowerState = true;
8772 break;
8773 } /* switch(stimulus) */
8774
8775 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason)) {
8776 DLOG("DarkWake: sleepASAP %d, clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
8777 darkWakeToSleepASAP, clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
8778 if (darkWakeToSleepASAP ||
8779 (clamshellClosed && !(desktopMode && acAdaptorConnected))) {
8780 uint32_t newSleepReason;
8781
8782 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
8783 // System was previously in full wake. Sleep reason from
8784 // full to dark already recorded in fullToDarkReason.
8785
8786 if (lowBatteryCondition) {
8787 newSleepReason = kIOPMSleepReasonLowPower;
8788 } else if (thermalEmergencyState) {
8789 newSleepReason = kIOPMSleepReasonThermalEmergency;
8790 } else {
8791 newSleepReason = fullToDarkReason;
8792 }
8793 } else {
8794 // In dark wake from system sleep.
8795
8796 if (darkWakeSleepService) {
8797 newSleepReason = kIOPMSleepReasonSleepServiceExit;
8798 } else {
8799 newSleepReason = kIOPMSleepReasonMaintenance;
8800 }
8801 }
8802
8803 if (checkSystemCanSleep(newSleepReason)) {
8804 privateSleepSystem(newSleepReason);
8805 }
8806 } else { // non-maintenance (network) dark wake
8807 if (checkSystemCanSleep(kIOPMSleepReasonIdle)) {
8808 // Release power clamp, and wait for children idle.
8809 adjustPowerState(true);
8810 } else {
8811 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonDarkWakeCannotSleep);
8812 }
8813 }
8814 }
8815
8816 if (systemDarkWake) {
8817 // The rest are irrelevant while system is in dark wake.
8818 flags.u32 = 0;
8819 }
8820
8821 if ((flags.bit.displaySleepEntry) &&
8822 (kFullWakeReasonDisplayOn == fullWakeReason)) {
8823 // kIOPMSleepReasonNotificationWakeExit
8824 DLOG("Display sleep while in notification wake\n");
8825 changePowerStateWithOverrideTo(SLEEP_STATE, kIOPMSleepReasonNotificationWakeExit);
8826 }
8827
8828 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged) {
8829 bool cancelQuickSpindown = false;
8830
8831 if (flags.bit.sleepDelayChanged) {
8832 // Cancel existing idle sleep timer and quick disk spindown.
8833 // New settings will be applied by the idleSleepEnabled flag
8834 // handler below if idle sleep is enabled.
8835
8836 DLOG("extra sleep timer changed\n");
8837 cancelIdleSleepTimer();
8838 cancelQuickSpindown = true;
8839 } else {
8840 DLOG("user inactive\n");
8841 }
8842
8843 if (!userIsActive && idleSleepEnabled) {
8844 startIdleSleepTimer(getTimeToIdleSleep());
8845 }
8846
8847 if (cancelQuickSpindown) {
8848 restoreUserSpinDownTimeout();
8849 }
8850 }
8851
8852 if (flags.bit.idleSleepEnabled) {
8853 DLOG("idle sleep timer enabled\n");
8854 if (!wrangler) {
8855 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8856 startIdleSleepTimer(getTimeToIdleSleep());
8857 #else
8858 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonIdleSleepEnabled);
8859 startIdleSleepTimer( idleMilliSeconds );
8860 #endif
8861 } else {
8862 // Start idle timer if prefs now allow system sleep
8863 // and user is already inactive. Disk spindown is
8864 // accelerated upon timer expiration.
8865
8866 if (!userIsActive) {
8867 startIdleSleepTimer(getTimeToIdleSleep());
8868 }
8869 }
8870 }
8871
8872 if (flags.bit.idleSleepDisabled) {
8873 DLOG("idle sleep timer disabled\n");
8874 cancelIdleSleepTimer();
8875 restoreUserSpinDownTimeout();
8876 adjustPowerState();
8877 }
8878
8879 if (flags.bit.adjustPowerState) {
8880 bool sleepASAP = false;
8881
8882 if (!systemBooting && (0 == idleSleepPreventersCount())) {
8883 if (!wrangler) {
8884 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonEvaluatePolicy);
8885 if (idleSleepEnabled) {
8886 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8887 if (!extraSleepDelay && !idleSleepTimerPending && !gNoIdleFlag) {
8888 sleepASAP = true;
8889 }
8890 #else
8891 // stay awake for at least idleMilliSeconds
8892 startIdleSleepTimer(idleMilliSeconds);
8893 #endif
8894 }
8895 } else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake && !gNoIdleFlag) {
8896 sleepASAP = true;
8897 }
8898 }
8899
8900 adjustPowerState(sleepASAP);
8901 }
8902 }
8903
8904 //******************************************************************************
8905
8906 unsigned int
idleSleepPreventersCount()8907 IOPMrootDomain::idleSleepPreventersCount()
8908 {
8909 if (_aotMode) {
8910 unsigned int count __block;
8911 count = 0;
8912 preventIdleSleepList->iterateObjects(^bool (OSObject * obj)
8913 {
8914 count += (NULL == obj->metaCast("AppleARMBacklight"));
8915 return false;
8916 });
8917 return count;
8918 }
8919
8920 return preventIdleSleepList->getCount();
8921 }
8922
8923
8924 //******************************************************************************
8925 // requestFullWake
8926 //
8927 // Request transition from dark wake to full wake
8928 //******************************************************************************
8929
8930 void
requestFullWake(FullWakeReason reason)8931 IOPMrootDomain::requestFullWake( FullWakeReason reason )
8932 {
8933 uint32_t options = 0;
8934 IOService * pciRoot = NULL;
8935 bool promotion = false;
8936
8937 // System must be in dark wake and a valid reason for entering full wake
8938 if ((kFullWakeReasonNone == reason) ||
8939 (kFullWakeReasonNone != fullWakeReason) ||
8940 (CAP_CURRENT(kIOPMSystemCapabilityGraphics))) {
8941 return;
8942 }
8943
8944 // Will clear reason upon exit from full wake
8945 fullWakeReason = reason;
8946
8947 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
8948 kIOPMSystemCapabilityAudio);
8949
8950 if ((kSystemTransitionWake == _systemTransitionType) &&
8951 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
8952 !darkWakePowerClamped) {
8953 // Promote to full wake while waking up to dark wake due to tickle.
8954 // PM will hold off notifying the graphics subsystem about system wake
8955 // as late as possible, so if a HID tickle does arrive, graphics can
8956 // power up from this same wake transition. Otherwise, the latency to
8957 // power up graphics on the following transition can be huge on certain
8958 // systems. However, once any power clamping has taken effect, it is
8959 // too late to promote the current dark wake transition to a full wake.
8960 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
8961 kIOPMSystemCapabilityAudio);
8962
8963 // Tell the PCI parent of audio and graphics drivers to stop
8964 // delaying the child notifications. Same for root domain.
8965 pciRoot = pciHostBridgeDriver.get();
8966 willEnterFullWake();
8967 promotion = true;
8968 }
8969
8970 // Unsafe to cancel once graphics was powered.
8971 // If system woke from dark wake, the return to sleep can
8972 // be cancelled. "awake -> dark -> sleep" transition
8973 // can be cancelled also, during the "dark -> sleep" phase
8974 // *prior* to driver power down.
8975 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
8976 _pendingCapability == 0) {
8977 options |= kIOPMSyncCancelPowerDown;
8978 }
8979
8980 synchronizePowerTree(options, pciRoot);
8981
8982 if (kFullWakeReasonLocalUser == fullWakeReason) {
8983 // IOGraphics doesn't light the display even though graphics is
8984 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
8985 // So, do an explicit activity tickle
8986 if (wrangler) {
8987 wrangler->activityTickle(0, 0);
8988 }
8989 }
8990
8991 // Log a timestamp for the initial full wake request.
8992 // System may not always honor this full wake request.
8993 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
8994 AbsoluteTime now;
8995 uint64_t nsec;
8996
8997 clock_get_uptime(&now);
8998 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
8999 absolutetime_to_nanoseconds(now, &nsec);
9000 MSG("full wake %s (reason %u) %u ms\n",
9001 promotion ? "promotion" : "request",
9002 fullWakeReason, ((int)((nsec) / NSEC_PER_MSEC)));
9003 }
9004 }
9005
9006 //******************************************************************************
9007 // willEnterFullWake
9008 //
9009 // System will enter full wake from sleep, from dark wake, or from dark
9010 // wake promotion. This function aggregate things that are in common to
9011 // all three full wake transitions.
9012 //
9013 // Assumptions: fullWakeReason was updated
9014 //******************************************************************************
9015
9016 void
willEnterFullWake(void)9017 IOPMrootDomain::willEnterFullWake( void )
9018 {
9019 hibernateRetry = false;
9020 sleepToStandby = false;
9021 standbyNixed = false;
9022 resetTimers = false;
9023 sleepTimerMaintenance = false;
9024
9025 assert(!CAP_CURRENT(kIOPMSystemCapabilityGraphics));
9026
9027 _systemMessageClientMask = kSystemMessageClientPowerd |
9028 kSystemMessageClientLegacyApp;
9029
9030 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) {
9031 // First time to attain full wake capability since the last wake
9032 _systemMessageClientMask |= kSystemMessageClientKernel;
9033
9034 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
9035 setProperty(gIOPMUserTriggeredFullWakeKey.get(),
9036 (kFullWakeReasonLocalUser == fullWakeReason) ?
9037 kOSBooleanTrue : kOSBooleanFalse);
9038 }
9039 #if HIBERNATION
9040 IOHibernateSetWakeCapabilities(_pendingCapability);
9041 #endif
9042
9043 IOService::setAdvisoryTickleEnable( true );
9044 tellClients(kIOMessageSystemWillPowerOn);
9045 preventTransitionToUserActive(false);
9046 }
9047
9048 //******************************************************************************
9049 // fullWakeDelayedWork
9050 //
9051 // System has already entered full wake. Invoked by a delayed thread call.
9052 //******************************************************************************
9053
9054 void
fullWakeDelayedWork(void)9055 IOPMrootDomain::fullWakeDelayedWork( void )
9056 {
9057 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
9058 if (!gIOPMWorkLoop->inGate()) {
9059 gIOPMWorkLoop->runAction(
9060 OSMemberFunctionCast(IOWorkLoop::Action, this,
9061 &IOPMrootDomain::fullWakeDelayedWork), this);
9062 return;
9063 }
9064
9065 DLOG("fullWakeDelayedWork cap cur %x pend %x high %x, clamshell disable %x/%x\n",
9066 _currentCapability, _pendingCapability, _highestCapability,
9067 clamshellDisabled, clamshellSleepDisableMask);
9068
9069 if (clamshellExists &&
9070 CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
9071 !CAP_CHANGE(kIOPMSystemCapabilityGraphics)) {
9072 if (clamshellSleepDisableMask & kClamshellSleepDisableInternal) {
9073 setClamShellSleepDisable(false, kClamshellSleepDisableInternal);
9074 } else {
9075 // Not the initial full wake after waking from sleep.
9076 // Evaluate the clamshell for rdar://problem/9157444.
9077 receivePowerNotification(kLocalEvalClamshellCommand);
9078 }
9079 }
9080 #endif
9081 }
9082
9083 //******************************************************************************
9084 // evaluateAssertions
9085 //
9086 //******************************************************************************
9087
9088 // Bitmask of all kernel assertions that prevent system idle sleep.
9089 // kIOPMDriverAssertionReservedBit7 is reserved for IOMediaBSDClient.
9090 #define NO_IDLE_SLEEP_ASSERTIONS_MASK \
9091 (kIOPMDriverAssertionReservedBit7 | \
9092 kIOPMDriverAssertionPreventSystemIdleSleepBit)
9093
9094 void
evaluateAssertions(IOPMDriverAssertionType newAssertions,IOPMDriverAssertionType oldAssertions)9095 IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
9096 {
9097 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
9098
9099 messageClients(kIOPMMessageDriverAssertionsChanged);
9100
9101 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
9102 if (wrangler) {
9103 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
9104
9105 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
9106 wrangler->setIgnoreIdleTimer( value );
9107 }
9108 }
9109
9110 if (changedBits & kIOPMDriverAssertionCPUBit) {
9111 if (_aotNow) {
9112 IOLog("CPU assertions %d\n", (0 != (kIOPMDriverAssertionCPUBit & newAssertions)));
9113 }
9114 evaluatePolicy(_aotNow ? kStimulusNoIdleSleepPreventers : kStimulusDarkWakeEvaluate);
9115 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
9116 AbsoluteTime now;
9117 clock_usec_t microsecs;
9118 clock_get_uptime(&now);
9119 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
9120 absolutetime_to_microtime(now, &assertOnWakeSecs, µsecs);
9121 if (assertOnWakeReport) {
9122 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
9123 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
9124 }
9125 }
9126 }
9127
9128 if (changedBits & NO_IDLE_SLEEP_ASSERTIONS_MASK) {
9129 if ((newAssertions & NO_IDLE_SLEEP_ASSERTIONS_MASK) != 0) {
9130 if ((oldAssertions & NO_IDLE_SLEEP_ASSERTIONS_MASK) == 0) {
9131 DLOG("PreventIdleSleep driver assertion raised\n");
9132 bool ok = updatePreventIdleSleepList(this, true);
9133 if (ok && (changedBits & kIOPMDriverAssertionPreventSystemIdleSleepBit)) {
9134 // Cancel idle sleep if there is one in progress
9135 cancelIdlePowerDown(this);
9136 }
9137 }
9138 } else {
9139 DLOG("PreventIdleSleep driver assertion dropped\n");
9140 updatePreventIdleSleepList(this, false);
9141 }
9142 }
9143 }
9144
9145 // MARK: -
9146 // MARK: Statistics
9147
9148 //******************************************************************************
9149 // pmStats
9150 //
9151 //******************************************************************************
9152
9153 void
pmStatsRecordEvent(int eventIndex,AbsoluteTime timestamp)9154 IOPMrootDomain::pmStatsRecordEvent(
9155 int eventIndex,
9156 AbsoluteTime timestamp)
9157 {
9158 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
9159 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
9160 uint64_t delta;
9161 uint64_t nsec;
9162 OSSharedPtr<OSData> publishPMStats;
9163
9164 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
9165
9166 absolutetime_to_nanoseconds(timestamp, &nsec);
9167
9168 switch (eventIndex) {
9169 case kIOPMStatsHibernateImageWrite:
9170 if (starting) {
9171 gPMStats.hibWrite.start = nsec;
9172 } else if (stopping) {
9173 gPMStats.hibWrite.stop = nsec;
9174 }
9175
9176 if (stopping) {
9177 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
9178 IOLog("PMStats: Hibernate write took %qd ms\n", delta / NSEC_PER_MSEC);
9179 }
9180 break;
9181 case kIOPMStatsHibernateImageRead:
9182 if (starting) {
9183 gPMStats.hibRead.start = nsec;
9184 } else if (stopping) {
9185 gPMStats.hibRead.stop = nsec;
9186 }
9187
9188 if (stopping) {
9189 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
9190 IOLog("PMStats: Hibernate read took %qd ms\n", delta / NSEC_PER_MSEC);
9191
9192 publishPMStats = OSData::withValue(gPMStats);
9193 setProperty(kIOPMSleepStatisticsKey, publishPMStats.get());
9194 bzero(&gPMStats, sizeof(gPMStats));
9195 }
9196 break;
9197 }
9198 }
9199
9200 /*
9201 * Appends a record of the application response to
9202 * IOPMrootDomain::pmStatsAppResponses
9203 */
9204 void
pmStatsRecordApplicationResponse(const OSSymbol * response,const char * name,int messageType,uint32_t delay_ms,uint64_t id,OSObject * object,IOPMPowerStateIndex powerState,bool async)9205 IOPMrootDomain::pmStatsRecordApplicationResponse(
9206 const OSSymbol *response,
9207 const char *name,
9208 int messageType,
9209 uint32_t delay_ms,
9210 uint64_t id,
9211 OSObject *object,
9212 IOPMPowerStateIndex powerState,
9213 bool async)
9214 {
9215 OSSharedPtr<OSDictionary> responseDescription;
9216 OSSharedPtr<OSNumber> delayNum;
9217 OSSharedPtr<OSNumber> powerCaps;
9218 OSSharedPtr<OSNumber> pidNum;
9219 OSSharedPtr<OSNumber> msgNum;
9220 OSSharedPtr<const OSSymbol> appname;
9221 OSSharedPtr<const OSSymbol> sleep;
9222 OSSharedPtr<const OSSymbol> wake;
9223 IOPMServiceInterestNotifier *notify = NULL;
9224
9225 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object))) {
9226 if (response->isEqualTo(gIOPMStatsResponseTimedOut.get())) {
9227 notify->ackTimeoutCnt++;
9228 } else {
9229 notify->ackTimeoutCnt = 0;
9230 }
9231 }
9232
9233 if (response->isEqualTo(gIOPMStatsResponsePrompt.get()) ||
9234 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient)) {
9235 return;
9236 }
9237
9238
9239 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow.get())) {
9240 kdebugTrace(kPMLogDrvPSChangeDelay, id, messageType, delay_ms);
9241 } else if (notify) {
9242 // User space app or kernel capability client
9243 if (id) {
9244 kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
9245 } else {
9246 kdebugTrace(kPMLogDrvResponseDelay, notify->uuid0, messageType, delay_ms);
9247 }
9248 notify->msgType = 0;
9249 }
9250
9251 responseDescription = OSDictionary::withCapacity(5);
9252 if (responseDescription) {
9253 if (response) {
9254 responseDescription->setObject(_statsResponseTypeKey.get(), response);
9255 }
9256
9257 msgNum = OSNumber::withNumber(messageType, 32);
9258 if (msgNum) {
9259 responseDescription->setObject(_statsMessageTypeKey.get(), msgNum.get());
9260 }
9261
9262 if (!name && notify && notify->identifier) {
9263 name = notify->identifier->getCStringNoCopy();
9264 }
9265
9266 if (name && (strlen(name) > 0)) {
9267 appname = OSSymbol::withCString(name);
9268 if (appname) {
9269 responseDescription->setObject(_statsNameKey.get(), appname.get());
9270 }
9271 }
9272
9273 if (!id && notify) {
9274 id = notify->uuid0;
9275 }
9276 pidNum = OSNumber::withNumber(id, 64);
9277 if (pidNum) {
9278 responseDescription->setObject(_statsPIDKey.get(), pidNum.get());
9279 }
9280
9281 delayNum = OSNumber::withNumber(delay_ms, 32);
9282 if (delayNum) {
9283 responseDescription->setObject(_statsTimeMSKey.get(), delayNum.get());
9284 }
9285
9286 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow.get())) {
9287 powerCaps = OSNumber::withNumber(powerState, 32);
9288
9289 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
9290 static const char * driverCallTypes[] = {
9291 [kDriverCallInformPreChange] = "powerStateWillChangeTo",
9292 [kDriverCallInformPostChange] = "powerStateDidChangeTo",
9293 [kDriverCallSetPowerState] = "setPowerState"
9294 };
9295
9296 if (messageType < (sizeof(driverCallTypes) / sizeof(driverCallTypes[0]))) {
9297 DLOG("%s[0x%qx]::%s(%u) %stook %d ms\n",
9298 name, id, driverCallTypes[messageType], (uint32_t) powerState,
9299 async ? "async " : "", delay_ms);
9300 }
9301 #endif
9302 } else {
9303 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
9304 }
9305 if (powerCaps) {
9306 responseDescription->setObject(_statsPowerCapsKey.get(), powerCaps.get());
9307 }
9308
9309 sleep = OSSymbol::withCString("Sleep");
9310 wake = OSSymbol::withCString("Wake");
9311 if (_systemTransitionType == kSystemTransitionSleep) {
9312 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep.get());
9313 } else if (_systemTransitionType == kSystemTransitionWake) {
9314 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake.get());
9315 } else if (_systemTransitionType == kSystemTransitionCapability) {
9316 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
9317 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep.get());
9318 } else if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
9319 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake.get());
9320 }
9321 }
9322
9323 IOLockLock(pmStatsLock);
9324 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
9325 pmStatsAppResponses->setObject(responseDescription.get());
9326 }
9327 IOLockUnlock(pmStatsLock);
9328 }
9329
9330 return;
9331 }
9332
9333 // MARK: -
9334 // MARK: PMTraceWorker
9335
9336 //******************************************************************************
9337 // TracePoint support
9338 //
9339 //******************************************************************************
9340
9341 #define kIOPMRegisterNVRAMTracePointHandlerKey \
9342 "IOPMRegisterNVRAMTracePointHandler"
9343
9344 IOReturn
callPlatformFunction(const OSSymbol * functionName,bool waitForFunction,void * param1,void * param2,void * param3,void * param4)9345 IOPMrootDomain::callPlatformFunction(
9346 const OSSymbol * functionName,
9347 bool waitForFunction,
9348 void * param1, void * param2,
9349 void * param3, void * param4 )
9350 {
9351 if (pmTracer && functionName &&
9352 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
9353 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget) {
9354 uint32_t tracePointPhases, tracePointPCI;
9355 uint64_t statusCode;
9356
9357 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
9358 pmTracer->tracePointTarget = (void *) param2;
9359 tracePointPCI = (uint32_t)(uintptr_t) param3;
9360 tracePointPhases = (uint32_t)(uintptr_t) param4;
9361 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
9362 OSSharedPtr<IORegistryEntry> node = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
9363 if (node) {
9364 OSSharedPtr<OSObject> bootRomFailureProp;
9365 bootRomFailureProp = node->copyProperty(kIOEFIBootRomFailureKey);
9366 OSData *data = OSDynamicCast(OSData, bootRomFailureProp.get());
9367 uint32_t bootFailureCode;
9368 if (data && data->getLength() == sizeof(bootFailureCode)) {
9369 // Failure code from EFI/BootRom is a four byte structure
9370 memcpy(&bootFailureCode, data->getBytesNoCopy(), sizeof(bootFailureCode));
9371 tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
9372 }
9373 }
9374 }
9375 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
9376 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
9377 MSG("Sleep failure code 0x%08x 0x%08x\n",
9378 tracePointPCI, tracePointPhases);
9379 }
9380 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
9381 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
9382
9383 return kIOReturnSuccess;
9384 }
9385 #if HIBERNATION
9386 else if (functionName &&
9387 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey)) {
9388 if (gSleepPolicyHandler) {
9389 return kIOReturnExclusiveAccess;
9390 }
9391 if (!param1) {
9392 return kIOReturnBadArgument;
9393 }
9394 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
9395 gSleepPolicyTarget = (void *) param2;
9396 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
9397 return kIOReturnSuccess;
9398 }
9399 #endif
9400
9401 return super::callPlatformFunction(
9402 functionName, waitForFunction, param1, param2, param3, param4);
9403 }
9404
9405 void
kdebugTrace(uint32_t event,uint64_t id,uintptr_t param1,uintptr_t param2,uintptr_t param3)9406 IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
9407 uintptr_t param1, uintptr_t param2, uintptr_t param3)
9408 {
9409 uint32_t code = IODBG_POWER(event);
9410 uint64_t regId = id;
9411 if (regId == 0) {
9412 regId = getRegistryEntryID();
9413 }
9414 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, code, (uintptr_t) regId, param1, param2, param3, 0);
9415 }
9416
9417 void
tracePoint(uint8_t point)9418 IOPMrootDomain::tracePoint( uint8_t point )
9419 {
9420 if (systemBooting) {
9421 return;
9422 }
9423
9424 if (kIOPMTracePointWakeCapabilityClients == point) {
9425 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Disable);
9426 }
9427
9428 kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
9429 pmTracer->tracePoint(point);
9430 }
9431
9432 static void
kext_log_putc(char c)9433 kext_log_putc(char c)
9434 {
9435 if (gKextNameEnd || gKextNamePos >= (sizeof(gKextNameBuf) - 1)) {
9436 return;
9437 }
9438 if (c == '(' || c == '[' || c == ' ') {
9439 c = 0;
9440 gKextNameEnd = true;
9441 }
9442
9443 gKextNameBuf[gKextNamePos++] = c;
9444 }
9445
9446 static int
kext_log(const char * fmt,...)9447 kext_log(const char *fmt, ...)
9448 {
9449 va_list listp;
9450
9451 va_start(listp, fmt);
9452 _doprnt(fmt, &listp, &kext_log_putc, 16);
9453 va_end(listp);
9454
9455 return 0;
9456 }
9457
9458 static OSPtr<const OSSymbol>
copyKextIdentifierWithAddress(vm_address_t address)9459 copyKextIdentifierWithAddress(vm_address_t address)
9460 {
9461 OSSharedPtr<const OSSymbol> identifer;
9462
9463 IOLockLock(gHaltLogLock);
9464
9465 gKextNameEnd = false;
9466 gKextNamePos = 0;
9467 gKextNameBuf[0] = 0;
9468
9469 OSKext::printKextsInBacktrace(&address, 1, kext_log, OSKext::kPrintKextsLock | OSKext::kPrintKextsTerse);
9470 gKextNameBuf[sizeof(gKextNameBuf) - 1] = 0;
9471 identifer = OSSymbol::withCString((gKextNameBuf[0] != 0) ? gKextNameBuf : kOSKextKernelIdentifier);
9472
9473 IOLockUnlock(gHaltLogLock);
9474
9475 return identifer;
9476 }
9477
9478 // Caller serialized using PM workloop
9479 const char *
getNotificationClientName(OSObject * object)9480 IOPMrootDomain::getNotificationClientName(OSObject *object)
9481 {
9482 IOPMServiceInterestNotifier *notifier = (typeof(notifier))object;
9483 const char *clientName = "UNKNOWN";
9484
9485 if (!notifier->clientName) {
9486 // Check for user client
9487 if (systemCapabilityNotifier && (((IOPMServiceInterestNotifier *) systemCapabilityNotifier.get())->handler == notifier->handler)) {
9488 OSNumber *clientID = NULL;
9489 messageClient(kIOMessageCopyClientID, object, &clientID);
9490 if (clientID) {
9491 OSSharedPtr<OSString> string(IOCopyLogNameForPID(clientID->unsigned32BitValue()), OSNoRetain);
9492 if (string) {
9493 notifier->clientName = OSSymbol::withString(string.get());
9494 }
9495 clientID->release();
9496 }
9497 } else if (notifier->identifier) {
9498 notifier->clientName.reset(notifier->identifier.get(), OSRetain);
9499 }
9500 }
9501
9502 if (notifier->clientName) {
9503 clientName = notifier->clientName->getCStringNoCopy();
9504 }
9505
9506 return clientName;
9507 }
9508
9509 void
traceNotification(OSObject * object,bool start,uint64_t timestamp,uint32_t msgIndex)9510 IOPMrootDomain::traceNotification(OSObject *object, bool start, uint64_t timestamp, uint32_t msgIndex)
9511 {
9512 IOPMServiceInterestNotifier *notifier;
9513
9514 if (systemBooting) {
9515 return;
9516 }
9517 notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9518 if (!notifier) {
9519 return;
9520 }
9521
9522 if (start) {
9523 pmTracer->traceDetail(notifier->uuid0 >> 32);
9524 kdebugTrace(kPMLogSleepWakeMessage, pmTracer->getTracePhase(),
9525 (uintptr_t) notifier->msgType, (uintptr_t) notifier->uuid0, (uintptr_t) notifier->uuid1);
9526
9527 // Update notifier state used for response/ack logging
9528 notifier->msgIndex = msgIndex;
9529 notifier->msgAbsTime = timestamp;
9530
9531 if (msgIndex != UINT_MAX) {
9532 DLOG("%s[%u] to %s\n", getIOMessageString(notifier->msgType), msgIndex, getNotificationClientName(notifier));
9533 } else {
9534 DLOG("%s to %s\n", getIOMessageString(notifier->msgType), getNotificationClientName(notifier));
9535 }
9536
9537 assert(notifierObject == NULL);
9538 notifierThread = current_thread();
9539 notifierObject.reset(notifier, OSRetain);
9540 } else {
9541 uint64_t nsec;
9542 uint32_t delayMS;
9543
9544 SUB_ABSOLUTETIME(×tamp, ¬ifier->msgAbsTime);
9545 absolutetime_to_nanoseconds(timestamp, &nsec);
9546 delayMS = (uint32_t)(nsec / 1000000ULL);
9547 if (delayMS > notifier->maxMsgDelayMS) {
9548 notifier->maxMsgDelayMS = delayMS;
9549 }
9550
9551 assert(notifierObject == notifier);
9552 notifierObject.reset();
9553 notifierThread = NULL;
9554 }
9555 }
9556
9557 void
traceNotificationAck(OSObject * object,uint32_t delay_ms)9558 IOPMrootDomain::traceNotificationAck(OSObject *object, uint32_t delay_ms)
9559 {
9560 if (systemBooting) {
9561 return;
9562 }
9563 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9564 if (!notifier) {
9565 return;
9566 }
9567
9568 kdebugTrace(kPMLogDrvResponseDelay, notifier->uuid0,
9569 (uintptr_t) notifier->uuid1, (uintptr_t) 0, (uintptr_t) delay_ms);
9570
9571 DLOG("%s[%u] ack from %s took %d ms\n",
9572 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms);
9573 if (delay_ms > notifier->maxAckDelayMS) {
9574 notifier->maxAckDelayMS = delay_ms;
9575 }
9576 }
9577
9578 void
traceNotificationResponse(OSObject * object,uint32_t delay_ms,uint32_t ack_time_us)9579 IOPMrootDomain::traceNotificationResponse(OSObject *object, uint32_t delay_ms, uint32_t ack_time_us)
9580 {
9581 if (systemBooting) {
9582 return;
9583 }
9584 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9585 if (!notifier) {
9586 return;
9587 }
9588
9589 kdebugTrace(kPMLogDrvResponseDelay, notifier->uuid0,
9590 (uintptr_t) notifier->uuid1, (uintptr_t)(ack_time_us / 1000), (uintptr_t) delay_ms);
9591
9592 if (ack_time_us == 0) {
9593 // Client work is done and ack will not be forthcoming
9594 DLOG("%s[%u] response from %s took %d ms\n",
9595 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms);
9596 } else {
9597 // Client needs more time and it must ack within ack_time_us
9598 DLOG("%s[%u] response from %s took %d ms (ack in %d us)\n",
9599 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms, ack_time_us);
9600 }
9601 }
9602
9603 void
traceFilteredNotification(OSObject * object)9604 IOPMrootDomain::traceFilteredNotification(OSObject *object)
9605 {
9606 if ((kIOLogDebugPower & gIOKitDebug) == 0) {
9607 return;
9608 }
9609 if (systemBooting) {
9610 return;
9611 }
9612 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9613 if (!notifier) {
9614 return;
9615 }
9616
9617 DLOG("%s to %s dropped\n", getIOMessageString(notifier->msgType), getNotificationClientName(notifier));
9618 }
9619
9620 void
traceDetail(uint32_t msgType,uint32_t msgIndex,uint32_t delay)9621 IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uint32_t delay)
9622 {
9623 if (!systemBooting) {
9624 uint32_t detail = ((msgType & 0xffff) << 16) | (delay & 0xffff);
9625 pmTracer->traceDetail( detail );
9626 kdebugTrace(kPMLogSleepWakeTracePoint, pmTracer->getTracePhase(), msgType, delay);
9627 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
9628 }
9629 }
9630
9631 void
configureReportGated(uint64_t channel_id,uint64_t action,void * result)9632 IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
9633 {
9634 size_t reportSize;
9635 void **report = NULL;
9636 uint32_t bktCnt;
9637 uint32_t bktSize;
9638 uint32_t *clientCnt;
9639
9640 ASSERT_GATED();
9641
9642 report = NULL;
9643 if (channel_id == kAssertDelayChID) {
9644 report = &assertOnWakeReport;
9645 bktCnt = kAssertDelayBcktCnt;
9646 bktSize = kAssertDelayBcktSize;
9647 clientCnt = &assertOnWakeClientCnt;
9648 } else if (channel_id == kSleepDelaysChID) {
9649 report = &sleepDelaysReport;
9650 bktCnt = kSleepDelaysBcktCnt;
9651 bktSize = kSleepDelaysBcktSize;
9652 clientCnt = &sleepDelaysClientCnt;
9653 } else {
9654 assert(false);
9655 return;
9656 }
9657
9658 switch (action) {
9659 case kIOReportEnable:
9660
9661 if (*report) {
9662 (*clientCnt)++;
9663 break;
9664 }
9665
9666 reportSize = HISTREPORT_BUFSIZE(bktCnt);
9667 *report = IOMallocZeroData(reportSize);
9668 if (*report == NULL) {
9669 break;
9670 }
9671 HISTREPORT_INIT((uint16_t)bktCnt, bktSize, *report, reportSize,
9672 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
9673
9674 if (channel_id == kAssertDelayChID) {
9675 assertOnWakeSecs = 0;
9676 }
9677
9678 break;
9679
9680 case kIOReportDisable:
9681 if (*clientCnt == 0) {
9682 break;
9683 }
9684 if (*clientCnt == 1) {
9685 IOFreeData(*report, HISTREPORT_BUFSIZE(bktCnt));
9686 *report = NULL;
9687 }
9688 (*clientCnt)--;
9689
9690 if (channel_id == kAssertDelayChID) {
9691 assertOnWakeSecs = -1; // Invalid value to prevent updates
9692 }
9693 break;
9694
9695 case kIOReportGetDimensions:
9696 if (*report) {
9697 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
9698 }
9699 break;
9700 }
9701
9702 return;
9703 }
9704
9705 IOReturn
configureReport(IOReportChannelList * channelList,IOReportConfigureAction action,void * result,void * destination)9706 IOPMrootDomain::configureReport(IOReportChannelList *channelList,
9707 IOReportConfigureAction action,
9708 void *result,
9709 void *destination)
9710 {
9711 unsigned cnt;
9712 uint64_t configAction = (uint64_t)action;
9713
9714 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9715 if ((channelList->channels[cnt].channel_id == kSleepCntChID) ||
9716 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
9717 (channelList->channels[cnt].channel_id == kUserWkCntChID)) {
9718 if (action != kIOReportGetDimensions) {
9719 continue;
9720 }
9721 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
9722 } else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
9723 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
9724 gIOPMWorkLoop->runAction(
9725 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
9726 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
9727 (void *)configAction, (void *)result);
9728 }
9729 }
9730
9731 return super::configureReport(channelList, action, result, destination);
9732 }
9733
9734 IOReturn
updateReportGated(uint64_t ch_id,void * result,IOBufferMemoryDescriptor * dest)9735 IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
9736 {
9737 uint32_t size2cpy;
9738 void *data2cpy;
9739 void **report;
9740
9741 ASSERT_GATED();
9742
9743 report = NULL;
9744 if (ch_id == kAssertDelayChID) {
9745 report = &assertOnWakeReport;
9746 } else if (ch_id == kSleepDelaysChID) {
9747 report = &sleepDelaysReport;
9748 } else {
9749 assert(false);
9750 return kIOReturnBadArgument;
9751 }
9752
9753 if (*report == NULL) {
9754 return kIOReturnNotOpen;
9755 }
9756
9757 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
9758 if (size2cpy > (dest->getCapacity() - dest->getLength())) {
9759 return kIOReturnOverrun;
9760 }
9761
9762 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
9763 dest->appendBytes(data2cpy, size2cpy);
9764
9765 return kIOReturnSuccess;
9766 }
9767
9768 IOReturn
updateReport(IOReportChannelList * channelList,IOReportUpdateAction action,void * result,void * destination)9769 IOPMrootDomain::updateReport(IOReportChannelList *channelList,
9770 IOReportUpdateAction action,
9771 void *result,
9772 void *destination)
9773 {
9774 uint32_t size2cpy;
9775 void *data2cpy;
9776 uint8_t buf[SIMPLEREPORT_BUFSIZE];
9777 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
9778 unsigned cnt;
9779 uint64_t ch_id;
9780
9781 if (action != kIOReportCopyChannelData) {
9782 goto exit;
9783 }
9784
9785 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9786 ch_id = channelList->channels[cnt].channel_id;
9787
9788 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
9789 gIOPMWorkLoop->runAction(
9790 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
9791 (OSObject *)this, (void *)ch_id,
9792 (void *)result, (void *)dest);
9793 continue;
9794 } else if ((ch_id == kSleepCntChID) ||
9795 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
9796 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
9797 } else {
9798 continue;
9799 }
9800
9801 if (ch_id == kSleepCntChID) {
9802 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
9803 } else if (ch_id == kDarkWkCntChID) {
9804 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
9805 } else if (ch_id == kUserWkCntChID) {
9806 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
9807 }
9808
9809 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
9810 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
9811 dest->appendBytes(data2cpy, size2cpy);
9812 }
9813
9814 exit:
9815 return super::updateReport(channelList, action, result, destination);
9816 }
9817
9818
9819 //******************************************************************************
9820 // PMTraceWorker Class
9821 //
9822 //******************************************************************************
9823
9824 #undef super
9825 #define super OSObject
OSDefineMetaClassAndStructors(PMTraceWorker,OSObject)9826 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
9827
9828 #define kPMBestGuessPCIDevicesCount 25
9829 #define kPMMaxRTCBitfieldSize 32
9830
9831 OSPtr<PMTraceWorker>
9832 PMTraceWorker::tracer(IOPMrootDomain * owner)
9833 {
9834 OSSharedPtr<PMTraceWorker> me = OSMakeShared<PMTraceWorker>();
9835 if (!me || !me->init()) {
9836 return NULL;
9837 }
9838
9839 DLOG("PMTraceWorker %p\n", OBFUSCATE(me.get()));
9840
9841 // Note that we cannot instantiate the PCI device -> bit mappings here, since
9842 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
9843 // this dictionary lazily.
9844 me->owner = owner;
9845 me->pciDeviceBitMappings = NULL;
9846 me->pmTraceWorkerLock = IOLockAlloc();
9847 me->tracePhase = kIOPMTracePointSystemUp;
9848 me->traceData32 = 0;
9849 me->loginWindowData = 0;
9850 me->coreDisplayData = 0;
9851 me->coreGraphicsData = 0;
9852 return me;
9853 }
9854
9855 void
RTC_TRACE(void)9856 PMTraceWorker::RTC_TRACE(void)
9857 {
9858 if (tracePointHandler && tracePointTarget) {
9859 uint32_t wordA;
9860
9861 IOLockLock(pmTraceWorkerLock);
9862 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
9863 (coreGraphicsData << 8) | tracePhase;
9864 IOLockUnlock(pmTraceWorkerLock);
9865
9866 tracePointHandler( tracePointTarget, traceData32, wordA );
9867 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
9868 }
9869 #if DEVELOPMENT || DEBUG
9870 if ((swd_panic_phase != 0) && (swd_panic_phase == tracePhase)) {
9871 DEBUG_LOG("Causing sleep wake failure in phase 0x%08x\n", tracePhase);
9872 IOLock *l = IOLockAlloc();
9873 IOLockLock(l);
9874 IOLockLock(l);
9875 }
9876 #endif /* DEVELOPMENT || DEBUG */
9877 }
9878
9879 int
recordTopLevelPCIDevice(IOService * pciDevice)9880 PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
9881 {
9882 OSSharedPtr<const OSSymbol> deviceName;
9883 int index = -1;
9884
9885 IOLockLock(pmTraceWorkerLock);
9886
9887 if (!pciDeviceBitMappings) {
9888 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
9889 if (!pciDeviceBitMappings) {
9890 goto exit;
9891 }
9892 }
9893
9894 // Check for bitmask overflow.
9895 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize) {
9896 goto exit;
9897 }
9898
9899 if ((deviceName = pciDevice->copyName()) &&
9900 (pciDeviceBitMappings->getNextIndexOfObject(deviceName.get(), 0) == (unsigned int)-1) &&
9901 pciDeviceBitMappings->setObject(deviceName.get())) {
9902 index = pciDeviceBitMappings->getCount() - 1;
9903 _LOG("PMTrace PCI array: set object %s => %d\n",
9904 deviceName->getCStringNoCopy(), index);
9905 }
9906
9907 if (!addedToRegistry && (index >= 0)) {
9908 addedToRegistry = owner->setProperty("PCITopLevel", this);
9909 }
9910
9911 exit:
9912 IOLockUnlock(pmTraceWorkerLock);
9913 return index;
9914 }
9915
9916 bool
serialize(OSSerialize * s) const9917 PMTraceWorker::serialize(OSSerialize *s) const
9918 {
9919 bool ok = false;
9920 if (pciDeviceBitMappings) {
9921 IOLockLock(pmTraceWorkerLock);
9922 ok = pciDeviceBitMappings->serialize(s);
9923 IOLockUnlock(pmTraceWorkerLock);
9924 }
9925 return ok;
9926 }
9927
9928 void
tracePoint(uint8_t phase)9929 PMTraceWorker::tracePoint(uint8_t phase)
9930 {
9931 // clear trace detail when phase begins
9932 if (tracePhase != phase) {
9933 traceData32 = 0;
9934 }
9935
9936 tracePhase = phase;
9937
9938 DLOG("trace point 0x%02x\n", tracePhase);
9939 RTC_TRACE();
9940 }
9941
9942 void
traceDetail(uint32_t detail)9943 PMTraceWorker::traceDetail(uint32_t detail)
9944 {
9945 if (detail == traceData32) {
9946 return;
9947 }
9948 traceData32 = detail;
9949 RTC_TRACE();
9950 }
9951
9952 void
traceComponentWakeProgress(uint32_t component,uint32_t data)9953 PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
9954 {
9955 switch (component) {
9956 case kIOPMLoginWindowProgress:
9957 loginWindowData = data & kIOPMLoginWindowProgressMask;
9958 break;
9959 case kIOPMCoreDisplayProgress:
9960 coreDisplayData = data & kIOPMCoreDisplayProgressMask;
9961 break;
9962 case kIOPMCoreGraphicsProgress:
9963 coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
9964 break;
9965 default:
9966 return;
9967 }
9968
9969 DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
9970 RTC_TRACE();
9971 }
9972
9973 void
tracePCIPowerChange(change_t type,IOService * service,uint32_t changeFlags,uint32_t bitNum)9974 PMTraceWorker::tracePCIPowerChange(
9975 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
9976 {
9977 uint32_t bitMask;
9978 uint32_t expectedFlag;
9979
9980 // Ignore PCI changes outside of system sleep/wake.
9981 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
9982 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase)) {
9983 return;
9984 }
9985
9986 // Only record the WillChange transition when going to sleep,
9987 // and the DidChange on the way up.
9988 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
9989 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
9990 kIOPMDomainWillChange : kIOPMDomainDidChange;
9991 if (changeFlags != expectedFlag) {
9992 return;
9993 }
9994
9995 // Mark this device off in our bitfield
9996 if (bitNum < kPMMaxRTCBitfieldSize) {
9997 bitMask = (1 << bitNum);
9998
9999 if (kPowerChangeStart == type) {
10000 traceData32 |= bitMask;
10001 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
10002 service->getName(), bitNum, bitMask, traceData32);
10003 owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
10004 } else {
10005 traceData32 &= ~bitMask;
10006 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
10007 service->getName(), bitNum, bitMask, traceData32);
10008 owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
10009 }
10010
10011 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
10012 RTC_TRACE();
10013 }
10014 }
10015
10016 uint64_t
getPMStatusCode()10017 PMTraceWorker::getPMStatusCode()
10018 {
10019 return ((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase);
10020 }
10021
10022 uint8_t
getTracePhase()10023 PMTraceWorker::getTracePhase()
10024 {
10025 return tracePhase;
10026 }
10027
10028 uint32_t
getTraceData()10029 PMTraceWorker::getTraceData()
10030 {
10031 return traceData32;
10032 }
10033
10034 // MARK: -
10035 // MARK: PMHaltWorker
10036
10037 //******************************************************************************
10038 // PMHaltWorker Class
10039 //
10040 //******************************************************************************
10041
10042 PMHaltWorker *
worker(void)10043 PMHaltWorker::worker( void )
10044 {
10045 PMHaltWorker * me;
10046 IOThread thread;
10047
10048 do {
10049 me = OSTypeAlloc( PMHaltWorker );
10050 if (!me || !me->init()) {
10051 break;
10052 }
10053
10054 me->lock = IOLockAlloc();
10055 if (!me->lock) {
10056 break;
10057 }
10058
10059 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
10060 me->retain(); // thread holds extra retain
10061 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread)) {
10062 me->release();
10063 break;
10064 }
10065 thread_deallocate(thread);
10066 return me;
10067 } while (false);
10068
10069 if (me) {
10070 me->release();
10071 }
10072 return NULL;
10073 }
10074
10075 void
free(void)10076 PMHaltWorker::free( void )
10077 {
10078 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
10079 if (lock) {
10080 IOLockFree(lock);
10081 lock = NULL;
10082 }
10083 return OSObject::free();
10084 }
10085
10086 void
main(void * arg,wait_result_t waitResult)10087 PMHaltWorker::main( void * arg, wait_result_t waitResult )
10088 {
10089 PMHaltWorker * me = (PMHaltWorker *) arg;
10090
10091 IOLockLock( gPMHaltLock );
10092 gPMHaltBusyCount++;
10093 me->depth = gPMHaltDepth;
10094 IOLockUnlock( gPMHaltLock );
10095
10096 while (me->depth >= 0) {
10097 PMHaltWorker::work( me );
10098
10099 IOLockLock( gPMHaltLock );
10100 if (++gPMHaltIdleCount >= gPMHaltBusyCount) {
10101 // This is the last thread to finish work on this level,
10102 // inform everyone to start working on next lower level.
10103 gPMHaltDepth--;
10104 me->depth = gPMHaltDepth;
10105 gPMHaltIdleCount = 0;
10106 thread_wakeup((event_t) &gPMHaltIdleCount);
10107 } else {
10108 // One or more threads are still working on this level,
10109 // this thread must wait.
10110 me->depth = gPMHaltDepth - 1;
10111 do {
10112 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
10113 } while (me->depth != gPMHaltDepth);
10114 }
10115 IOLockUnlock( gPMHaltLock );
10116 }
10117
10118 // No more work to do, terminate thread
10119 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
10120 thread_wakeup( &gPMHaltDepth );
10121 me->release();
10122 }
10123
10124 void
work(PMHaltWorker * me)10125 PMHaltWorker::work( PMHaltWorker * me )
10126 {
10127 OSSharedPtr<IOService> service;
10128 OSSet * inner;
10129 AbsoluteTime startTime, elapsedTime;
10130 UInt32 deltaTime;
10131 bool timeout;
10132
10133 while (true) {
10134 timeout = false;
10135
10136 // Claim an unit of work from the shared pool
10137 IOLockLock( gPMHaltLock );
10138 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
10139 if (inner) {
10140 service.reset(OSDynamicCast(IOService, inner->getAnyObject()), OSRetain);
10141 if (service) {
10142 inner->removeObject(service.get());
10143 }
10144 }
10145 IOLockUnlock( gPMHaltLock );
10146 if (!service) {
10147 break; // no more work at this depth
10148 }
10149 clock_get_uptime(&startTime);
10150
10151 if (!service->isInactive() &&
10152 service->setProperty(gPMHaltClientAcknowledgeKey.get(), me)) {
10153 IOLockLock(me->lock);
10154 me->startTime = startTime;
10155 me->service = service.get();
10156 me->timeout = false;
10157 IOLockUnlock(me->lock);
10158
10159 service->systemWillShutdown( gPMHaltMessageType);
10160
10161 // Wait for driver acknowledgement
10162 IOLockLock(me->lock);
10163 while (service->propertyExists(gPMHaltClientAcknowledgeKey.get())) {
10164 IOLockSleep(me->lock, me, THREAD_UNINT);
10165 }
10166 me->service = NULL;
10167 timeout = me->timeout;
10168 IOLockUnlock(me->lock);
10169 }
10170
10171 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
10172 if ((deltaTime > kPMHaltTimeoutMS) || timeout) {
10173 LOG("%s driver %s (0x%llx) took %u ms\n",
10174 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
10175 "PowerOff" : "Restart",
10176 service->getName(), service->getRegistryEntryID(),
10177 (uint32_t) deltaTime );
10178 halt_log_enter("PowerOff/Restart handler completed",
10179 OSMemberFunctionCast(const void *, service.get(), &IOService::systemWillShutdown),
10180 elapsedTime);
10181 }
10182
10183 me->visits++;
10184 }
10185 }
10186
10187 void
checkTimeout(PMHaltWorker * me,AbsoluteTime * now)10188 PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
10189 {
10190 UInt64 nano;
10191 AbsoluteTime startTime;
10192 AbsoluteTime endTime;
10193
10194 endTime = *now;
10195
10196 IOLockLock(me->lock);
10197 if (me->service && !me->timeout) {
10198 startTime = me->startTime;
10199 nano = 0;
10200 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
10201 SUB_ABSOLUTETIME(&endTime, &startTime);
10202 absolutetime_to_nanoseconds(endTime, &nano);
10203 }
10204 if (nano > 3000000000ULL) {
10205 me->timeout = true;
10206
10207 halt_log_enter("PowerOff/Restart still waiting on handler",
10208 OSMemberFunctionCast(const void *, me->service, &IOService::systemWillShutdown),
10209 endTime);
10210 MSG("%s still waiting on %s\n",
10211 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
10212 me->service->getName());
10213 }
10214 }
10215 IOLockUnlock(me->lock);
10216 }
10217
10218 //******************************************************************************
10219 // acknowledgeSystemWillShutdown
10220 //
10221 // Acknowledgement from drivers that they have prepared for shutdown/restart.
10222 //******************************************************************************
10223
10224 void
acknowledgeSystemWillShutdown(IOService * from)10225 IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
10226 {
10227 PMHaltWorker * worker;
10228 OSSharedPtr<OSObject> prop;
10229
10230 if (!from) {
10231 return;
10232 }
10233
10234 //DLOG("%s acknowledged\n", from->getName());
10235 prop = from->copyProperty( gPMHaltClientAcknowledgeKey.get());
10236 if (prop) {
10237 worker = (PMHaltWorker *) prop.get();
10238 IOLockLock(worker->lock);
10239 from->removeProperty( gPMHaltClientAcknowledgeKey.get());
10240 thread_wakeup((event_t) worker);
10241 IOLockUnlock(worker->lock);
10242 } else {
10243 DLOG("%s acknowledged without worker property\n",
10244 from->getName());
10245 }
10246 }
10247
10248
10249 //******************************************************************************
10250 // notifySystemShutdown
10251 //
10252 // Notify all objects in PM tree that system will shutdown or restart
10253 //******************************************************************************
10254
10255 static void
notifySystemShutdown(IOService * root,uint32_t messageType)10256 notifySystemShutdown( IOService * root, uint32_t messageType )
10257 {
10258 #define PLACEHOLDER ((OSSet *)gPMHaltArray.get())
10259 OSSharedPtr<IORegistryIterator> iter;
10260 IORegistryEntry * entry;
10261 IOService * node;
10262 OSSet * inner;
10263 OSSharedPtr<OSSet> newInner;
10264 PMHaltWorker * workers[kPMHaltMaxWorkers];
10265 AbsoluteTime deadline;
10266 unsigned int totalNodes = 0;
10267 unsigned int depth;
10268 unsigned int rootDepth;
10269 unsigned int numWorkers;
10270 unsigned int count;
10271 int waitResult;
10272 void * baseFunc;
10273 bool ok;
10274
10275 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
10276
10277 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
10278
10279 // Iterate the entire PM tree starting from root
10280
10281 rootDepth = root->getDepth( gIOPowerPlane );
10282 if (!rootDepth) {
10283 goto done;
10284 }
10285
10286 // debug - for repeated test runs
10287 while (PMHaltWorker::metaClass->getInstanceCount()) {
10288 IOSleep(1);
10289 }
10290
10291 if (!gPMHaltArray) {
10292 gPMHaltArray = OSArray::withCapacity(40);
10293 if (!gPMHaltArray) {
10294 goto done;
10295 }
10296 } else { // debug
10297 gPMHaltArray->flushCollection();
10298 }
10299
10300 if (!gPMHaltLock) {
10301 gPMHaltLock = IOLockAlloc();
10302 if (!gPMHaltLock) {
10303 goto done;
10304 }
10305 }
10306
10307 if (!gPMHaltClientAcknowledgeKey) {
10308 gPMHaltClientAcknowledgeKey =
10309 OSSymbol::withCStringNoCopy("PMShutdown");
10310 if (!gPMHaltClientAcknowledgeKey) {
10311 goto done;
10312 }
10313 }
10314
10315 gPMHaltMessageType = messageType;
10316
10317 // Depth-first walk of PM plane
10318
10319 iter = IORegistryIterator::iterateOver(
10320 root, gIOPowerPlane, kIORegistryIterateRecursively);
10321
10322 if (iter) {
10323 while ((entry = iter->getNextObject())) {
10324 node = OSDynamicCast(IOService, entry);
10325 if (!node) {
10326 continue;
10327 }
10328
10329 if (baseFunc ==
10330 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown)) {
10331 continue;
10332 }
10333
10334 depth = node->getDepth( gIOPowerPlane );
10335 if (depth <= rootDepth) {
10336 continue;
10337 }
10338
10339 ok = false;
10340
10341 // adjust to zero based depth
10342 depth -= (rootDepth + 1);
10343
10344 // gPMHaltArray is an array of containers, each container
10345 // refers to nodes with the same depth.
10346
10347 count = gPMHaltArray->getCount();
10348 while (depth >= count) {
10349 // expand array and insert placeholders
10350 gPMHaltArray->setObject(PLACEHOLDER);
10351 count++;
10352 }
10353 count = gPMHaltArray->getCount();
10354 if (depth < count) {
10355 inner = (OSSet *)gPMHaltArray->getObject(depth);
10356 if (inner == PLACEHOLDER) {
10357 newInner = OSSet::withCapacity(40);
10358 if (newInner) {
10359 gPMHaltArray->replaceObject(depth, newInner.get());
10360 inner = newInner.get();
10361 }
10362 }
10363
10364 // PM nodes that appear more than once in the tree will have
10365 // the same depth, OSSet will refuse to add the node twice.
10366 if (inner) {
10367 ok = inner->setObject(node);
10368 }
10369 }
10370 if (!ok) {
10371 DLOG("Skipped PM node %s\n", node->getName());
10372 }
10373 }
10374 }
10375
10376 // debug only
10377 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++) {
10378 count = 0;
10379 if (inner != PLACEHOLDER) {
10380 count = inner->getCount();
10381 }
10382 DLOG("Nodes at depth %u = %u\n", i, count);
10383 }
10384
10385 // strip placeholders (not all depths are populated)
10386 numWorkers = 0;
10387 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i));) {
10388 if (inner == PLACEHOLDER) {
10389 gPMHaltArray->removeObject(i);
10390 continue;
10391 }
10392 count = inner->getCount();
10393 if (count > numWorkers) {
10394 numWorkers = count;
10395 }
10396 totalNodes += count;
10397 i++;
10398 }
10399
10400 if (gPMHaltArray->getCount() == 0 || !numWorkers) {
10401 goto done;
10402 }
10403
10404 gPMHaltBusyCount = 0;
10405 gPMHaltIdleCount = 0;
10406 gPMHaltDepth = gPMHaltArray->getCount() - 1;
10407
10408 // Create multiple workers (and threads)
10409
10410 if (numWorkers > kPMHaltMaxWorkers) {
10411 numWorkers = kPMHaltMaxWorkers;
10412 }
10413
10414 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
10415 totalNodes, gPMHaltArray->getCount(), numWorkers);
10416
10417 for (unsigned int i = 0; i < numWorkers; i++) {
10418 workers[i] = PMHaltWorker::worker();
10419 }
10420
10421 // Wait for workers to exhaust all available work
10422
10423 IOLockLock(gPMHaltLock);
10424 while (gPMHaltDepth >= 0) {
10425 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
10426
10427 waitResult = IOLockSleepDeadline(
10428 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
10429 if (THREAD_TIMED_OUT == waitResult) {
10430 AbsoluteTime now;
10431 clock_get_uptime(&now);
10432
10433 IOLockUnlock(gPMHaltLock);
10434 for (unsigned int i = 0; i < numWorkers; i++) {
10435 if (workers[i]) {
10436 PMHaltWorker::checkTimeout(workers[i], &now);
10437 }
10438 }
10439 IOLockLock(gPMHaltLock);
10440 }
10441 }
10442 IOLockUnlock(gPMHaltLock);
10443
10444 // Release all workers
10445
10446 for (unsigned int i = 0; i < numWorkers; i++) {
10447 if (workers[i]) {
10448 workers[i]->release();
10449 }
10450 // worker also retained by it's own thread
10451 }
10452
10453 done:
10454 DLOG("%s done\n", __FUNCTION__);
10455 return;
10456 }
10457
10458 // MARK: -
10459 // MARK: Kernel Assertion
10460
10461 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10462
10463 IOPMDriverAssertionID
createPMAssertion(IOPMDriverAssertionType whichAssertionBits,IOPMDriverAssertionLevel assertionLevel,IOService * ownerService,const char * ownerDescription)10464 IOPMrootDomain::createPMAssertion(
10465 IOPMDriverAssertionType whichAssertionBits,
10466 IOPMDriverAssertionLevel assertionLevel,
10467 IOService *ownerService,
10468 const char *ownerDescription)
10469 {
10470 IOReturn ret;
10471 IOPMDriverAssertionID newAssertion;
10472
10473 if (!pmAssertions) {
10474 return 0;
10475 }
10476
10477 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
10478
10479 if (kIOReturnSuccess == ret) {
10480 #if (DEVELOPMENT || DEBUG)
10481 if (_aotNow) {
10482 OSReportWithBacktrace("IOPMrootDomain::createPMAssertion(0x%qx)", newAssertion);
10483 }
10484 #endif /* (DEVELOPMENT || DEBUG) */
10485 return newAssertion;
10486 } else {
10487 return 0;
10488 }
10489 }
10490
10491 IOReturn
releasePMAssertion(IOPMDriverAssertionID releaseAssertion)10492 IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
10493 {
10494 #if (DEVELOPMENT || DEBUG)
10495 if (_aotNow) {
10496 OSReportWithBacktrace("IOPMrootDomain::releasePMAssertion(0x%qx)", releaseAssertion);
10497 }
10498 #endif /* (DEVELOPMENT || DEBUG) */
10499 if (!pmAssertions) {
10500 return kIOReturnInternalError;
10501 }
10502 return pmAssertions->releaseAssertion(releaseAssertion);
10503 }
10504
10505
10506 IOReturn
setPMAssertionLevel(IOPMDriverAssertionID assertionID,IOPMDriverAssertionLevel assertionLevel)10507 IOPMrootDomain::setPMAssertionLevel(
10508 IOPMDriverAssertionID assertionID,
10509 IOPMDriverAssertionLevel assertionLevel)
10510 {
10511 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
10512 }
10513
10514 IOPMDriverAssertionLevel
getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)10515 IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
10516 {
10517 IOPMDriverAssertionType sysLevels;
10518
10519 if (!pmAssertions || whichAssertion == 0) {
10520 return kIOPMDriverAssertionLevelOff;
10521 }
10522
10523 sysLevels = pmAssertions->getActivatedAssertions();
10524
10525 // Check that every bit set in argument 'whichAssertion' is asserted
10526 // in the aggregate bits.
10527 if ((sysLevels & whichAssertion) == whichAssertion) {
10528 return kIOPMDriverAssertionLevelOn;
10529 } else {
10530 return kIOPMDriverAssertionLevelOff;
10531 }
10532 }
10533
10534 IOReturn
setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)10535 IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
10536 {
10537 if (!pmAssertions) {
10538 return kIOReturnNotFound;
10539 }
10540
10541 return pmAssertions->setUserAssertionLevels(inLevels);
10542 }
10543
10544 IOReturn
acquireDriverKitMatchingAssertion()10545 IOPMrootDomain::acquireDriverKitMatchingAssertion()
10546 {
10547 return gIOPMWorkLoop->runActionBlock(^{
10548 if (_driverKitMatchingAssertionCount != 0) {
10549 _driverKitMatchingAssertionCount++;
10550 return kIOReturnSuccess;
10551 } else {
10552 if (kSystemTransitionSleep == _systemTransitionType) {
10553 // system going to sleep
10554 return kIOReturnBusy;
10555 } else {
10556 // createPMAssertion is asynchronous.
10557 // we must also set _driverKitMatchingAssertionCount under the PM workloop lock so that we can cancel sleep immediately
10558 // The assertion is used so that on release, we reevaluate all assertions
10559 _driverKitMatchingAssertion = createPMAssertion(kIOPMDriverAssertionCPUBit, kIOPMDriverAssertionLevelOn, this, "DK matching");
10560 if (_driverKitMatchingAssertion != kIOPMUndefinedDriverAssertionID) {
10561 _driverKitMatchingAssertionCount = 1;
10562 return kIOReturnSuccess;
10563 } else {
10564 return kIOReturnBusy;
10565 }
10566 }
10567 }
10568 });
10569 }
10570
10571 void
releaseDriverKitMatchingAssertion()10572 IOPMrootDomain::releaseDriverKitMatchingAssertion()
10573 {
10574 gIOPMWorkLoop->runActionBlock(^{
10575 if (_driverKitMatchingAssertionCount != 0) {
10576 _driverKitMatchingAssertionCount--;
10577 if (_driverKitMatchingAssertionCount == 0) {
10578 releasePMAssertion(_driverKitMatchingAssertion);
10579 _driverKitMatchingAssertion = kIOPMUndefinedDriverAssertionID;
10580 }
10581 } else {
10582 panic("Over-release of driverkit matching assertion");
10583 }
10584 return kIOReturnSuccess;
10585 });
10586 }
10587
10588 bool
serializeProperties(OSSerialize * s) const10589 IOPMrootDomain::serializeProperties( OSSerialize * s ) const
10590 {
10591 if (pmAssertions) {
10592 pmAssertions->publishProperties();
10593 }
10594 return IOService::serializeProperties(s);
10595 }
10596
10597 OSSharedPtr<OSObject>
copyProperty(const char * aKey) const10598 IOPMrootDomain::copyProperty( const char * aKey) const
10599 {
10600 OSSharedPtr<OSObject> obj;
10601 obj = IOService::copyProperty(aKey);
10602
10603 if (obj) {
10604 return obj;
10605 }
10606
10607 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
10608 sizeof(kIOPMSleepWakeWdogRebootKey))) {
10609 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
10610 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10611 } else {
10612 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10613 }
10614 }
10615
10616 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
10617 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
10618 if (swd_flags & SWD_VALID_LOGS) {
10619 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10620 } else {
10621 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10622 }
10623 }
10624
10625 /*
10626 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
10627 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
10628 * issued by DisplayWrangler on darkwake.
10629 */
10630 if (!strcmp(aKey, "DesktopMode")) {
10631 if (desktopMode) {
10632 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10633 } else {
10634 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10635 }
10636 }
10637 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
10638 if (displayIdleForDemandSleep) {
10639 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
10640 } else {
10641 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
10642 }
10643 }
10644
10645 if (!strcmp(aKey, kIOPMDriverWakeEventsKey)) {
10646 OSSharedPtr<OSArray> array;
10647 WAKEEVENT_LOCK();
10648 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
10649 OSSharedPtr<OSCollection> collection = _systemWakeEventsArray->copyCollection();
10650 if (collection) {
10651 array = OSDynamicPtrCast<OSArray>(collection);
10652 }
10653 }
10654 WAKEEVENT_UNLOCK();
10655 return os::move(array);
10656 }
10657
10658 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey)) {
10659 OSSharedPtr<OSArray> array;
10660 IOLockLock(pmStatsLock);
10661 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
10662 OSSharedPtr<OSCollection> collection = pmStatsAppResponses->copyCollection();
10663 if (collection) {
10664 array = OSDynamicPtrCast<OSArray>(collection);
10665 }
10666 }
10667 IOLockUnlock(pmStatsLock);
10668 return os::move(array);
10669 }
10670
10671 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey)) {
10672 OSArray *idleSleepList = NULL;
10673 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
10674 return OSSharedPtr<OSArray>(idleSleepList, OSNoRetain);
10675 }
10676
10677 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey)) {
10678 OSArray *systemSleepList = NULL;
10679 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
10680 return OSSharedPtr<OSArray>(systemSleepList, OSNoRetain);
10681 }
10682
10683 if (!strcmp(aKey, kIOPMIdleSleepPreventersWithIDKey)) {
10684 OSArray *idleSleepList = NULL;
10685 gRootDomain->copySleepPreventersListWithID(&idleSleepList, NULL);
10686 return OSSharedPtr<OSArray>(idleSleepList, OSNoRetain);
10687 }
10688
10689 if (!strcmp(aKey, kIOPMSystemSleepPreventersWithIDKey)) {
10690 OSArray *systemSleepList = NULL;
10691 gRootDomain->copySleepPreventersListWithID(NULL, &systemSleepList);
10692 return OSSharedPtr<OSArray>(systemSleepList, OSNoRetain);
10693 }
10694 return NULL;
10695 }
10696
10697 // MARK: -
10698 // MARK: Wake Event Reporting
10699
10700 void
copyWakeReasonString(char * outBuf,size_t bufSize)10701 IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
10702 {
10703 WAKEEVENT_LOCK();
10704 strlcpy(outBuf, gWakeReasonString, bufSize);
10705 WAKEEVENT_UNLOCK();
10706 }
10707
10708 void
copyShutdownReasonString(char * outBuf,size_t bufSize)10709 IOPMrootDomain::copyShutdownReasonString( char * outBuf, size_t bufSize )
10710 {
10711 WAKEEVENT_LOCK();
10712 strlcpy(outBuf, gShutdownReasonString, bufSize);
10713 WAKEEVENT_UNLOCK();
10714 }
10715
10716 //******************************************************************************
10717 // acceptSystemWakeEvents
10718 //
10719 // Private control for the acceptance of driver wake event claims.
10720 //******************************************************************************
10721
10722 void
acceptSystemWakeEvents(uint32_t control)10723 IOPMrootDomain::acceptSystemWakeEvents( uint32_t control )
10724 {
10725 bool logWakeReason = false;
10726
10727 WAKEEVENT_LOCK();
10728 switch (control) {
10729 case kAcceptSystemWakeEvents_Enable:
10730 assert(_acceptSystemWakeEvents == false);
10731 if (!_systemWakeEventsArray) {
10732 _systemWakeEventsArray = OSArray::withCapacity(4);
10733 }
10734 _acceptSystemWakeEvents = (_systemWakeEventsArray != NULL);
10735 if (!(_aotNow && (kIOPMWakeEventAOTExitFlags & _aotPendingFlags))) {
10736 gWakeReasonString[0] = '\0';
10737 if (_systemWakeEventsArray) {
10738 _systemWakeEventsArray->flushCollection();
10739 }
10740 }
10741
10742 // Remove stale WakeType property before system sleep
10743 removeProperty(kIOPMRootDomainWakeTypeKey);
10744 removeProperty(kIOPMRootDomainWakeReasonKey);
10745 break;
10746
10747 case kAcceptSystemWakeEvents_Disable:
10748 _acceptSystemWakeEvents = false;
10749 #if defined(XNU_TARGET_OS_OSX)
10750 logWakeReason = (gWakeReasonString[0] != '\0');
10751 #else /* !defined(XNU_TARGET_OS_OSX) */
10752 logWakeReason = gWakeReasonSysctlRegistered;
10753 #if DEVELOPMENT
10754 static int panic_allowed = -1;
10755
10756 if ((panic_allowed == -1) &&
10757 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed, sizeof(panic_allowed)) == false)) {
10758 panic_allowed = 0;
10759 }
10760
10761 if (panic_allowed) {
10762 size_t i = 0;
10763 // Panic if wake reason is null or empty
10764 for (i = 0; (i < strlen(gWakeReasonString)); i++) {
10765 if ((gWakeReasonString[i] != ' ') && (gWakeReasonString[i] != '\t')) {
10766 break;
10767 }
10768 }
10769 if (i >= strlen(gWakeReasonString)) {
10770 panic("Wake reason is empty");
10771 }
10772 }
10773 #endif /* DEVELOPMENT */
10774 #endif /* !defined(XNU_TARGET_OS_OSX) */
10775
10776 // publish kIOPMRootDomainWakeReasonKey if not already set
10777 if (!propertyExists(kIOPMRootDomainWakeReasonKey)) {
10778 setProperty(kIOPMRootDomainWakeReasonKey, gWakeReasonString);
10779 }
10780 break;
10781
10782 case kAcceptSystemWakeEvents_Reenable:
10783 assert(_acceptSystemWakeEvents == false);
10784 _acceptSystemWakeEvents = (_systemWakeEventsArray != NULL);
10785 removeProperty(kIOPMRootDomainWakeReasonKey);
10786 break;
10787 }
10788 WAKEEVENT_UNLOCK();
10789
10790 if (logWakeReason) {
10791 MSG("system wake events: %s\n", gWakeReasonString);
10792 }
10793 }
10794
10795 //******************************************************************************
10796 // claimSystemWakeEvent
10797 //
10798 // For a driver to claim a device is the source/conduit of a system wake event.
10799 //******************************************************************************
10800
10801 void
claimSystemWakeEvent(IOService * device,IOOptionBits flags,const char * reason,OSObject * details)10802 IOPMrootDomain::claimSystemWakeEvent(
10803 IOService * device,
10804 IOOptionBits flags,
10805 const char * reason,
10806 OSObject * details )
10807 {
10808 OSSharedPtr<const OSSymbol> deviceName;
10809 OSSharedPtr<OSNumber> deviceRegId;
10810 OSSharedPtr<OSNumber> claimTime;
10811 OSSharedPtr<OSData> flagsData;
10812 OSSharedPtr<OSString> reasonString;
10813 OSSharedPtr<OSDictionary> dict;
10814 uint64_t timestamp;
10815 bool addWakeReason;
10816
10817 if (!device || !reason) {
10818 return;
10819 }
10820
10821 pmEventTimeStamp(×tamp);
10822
10823 IOOptionBits aotFlags = 0;
10824 bool needAOTEvaluate = FALSE;
10825
10826 if (kIOPMAOTModeAddEventFlags & _aotMode) {
10827 if (!strcmp("hold", reason)
10828 || !strcmp("help", reason)
10829 || !strcmp("menu", reason)
10830 || !strcmp("stockholm", reason)
10831 || !strcmp("ringer", reason)
10832 || !strcmp("ringerab", reason)
10833 || !strcmp("smc0", reason)
10834 || !strcmp("AOP.RTPWakeupAP", reason)
10835 || !strcmp("AOP.RTP_AP_IRQ", reason)
10836 || !strcmp("BT.OutboxNotEmpty", reason)
10837 || !strcmp("WL.OutboxNotEmpty", reason)) {
10838 flags |= kIOPMWakeEventAOTExit;
10839 }
10840 }
10841
10842 #if DEVELOPMENT || DEBUG
10843 if (_aotLingerTime && !strcmp("rtc", reason)) {
10844 flags |= kIOPMWakeEventAOTPossibleExit;
10845 }
10846 #endif /* DEVELOPMENT || DEBUG */
10847
10848 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
10849 // Publishing the WakeType is serialized by the PM work loop
10850 if (!strcmp("rtc", reason) && (_nextScheduledAlarmType != NULL)) {
10851 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishWakeType,
10852 (void *) _nextScheduledAlarmType.get());
10853 }
10854
10855 // Workaround for the missing wake HID event
10856 if (gDarkWakeFlags & kDarkWakeFlagUserWakeWorkaround) {
10857 if (!strcmp("trackpadkeyboard", reason)) {
10858 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishWakeType,
10859 (void *) gIOPMWakeTypeUserKey.get());
10860 }
10861 }
10862 #endif
10863
10864 deviceName = device->copyName(gIOServicePlane);
10865 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
10866 claimTime = OSNumber::withNumber(timestamp, 64);
10867 flagsData = OSData::withValue(flags);
10868 reasonString = OSString::withCString(reason);
10869 dict = OSDictionary::withCapacity(5 + (details ? 1 : 0));
10870 if (!dict || !deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString) {
10871 goto done;
10872 }
10873
10874 dict->setObject(gIONameKey, deviceName.get());
10875 dict->setObject(gIORegistryEntryIDKey, deviceRegId.get());
10876 dict->setObject(kIOPMWakeEventTimeKey, claimTime.get());
10877 dict->setObject(kIOPMWakeEventFlagsKey, flagsData.get());
10878 dict->setObject(kIOPMWakeEventReasonKey, reasonString.get());
10879 if (details) {
10880 dict->setObject(kIOPMWakeEventDetailsKey, details);
10881 }
10882
10883 WAKEEVENT_LOCK();
10884 addWakeReason = _acceptSystemWakeEvents;
10885 if (_aotMode) {
10886 IOLog("claimSystemWakeEvent(%s, %s, 0x%x) 0x%x %d\n", reason, deviceName->getCStringNoCopy(), (int)flags, _aotPendingFlags, _aotReadyToFullWake);
10887 }
10888 aotFlags = (kIOPMWakeEventAOTFlags & flags);
10889 aotFlags = (aotFlags & ~_aotPendingFlags);
10890 needAOTEvaluate = false;
10891 if (_aotNow && aotFlags) {
10892 if (kIOPMWakeEventAOTPossibleExit & flags) {
10893 _aotMetrics->possibleCount++;
10894 }
10895 if (kIOPMWakeEventAOTConfirmedPossibleExit & flags) {
10896 _aotMetrics->confirmedPossibleCount++;
10897 }
10898 if (kIOPMWakeEventAOTRejectedPossibleExit & flags) {
10899 _aotMetrics->rejectedPossibleCount++;
10900 }
10901 if (kIOPMWakeEventAOTExpiredPossibleExit & flags) {
10902 _aotMetrics->expiredPossibleCount++;
10903 }
10904
10905 _aotPendingFlags |= aotFlags;
10906 addWakeReason = _aotNow && _systemWakeEventsArray && ((kIOPMWakeEventAOTExitFlags & aotFlags));
10907 needAOTEvaluate = _aotReadyToFullWake;
10908 }
10909 DMSG("claimSystemWakeEvent(%s, 0x%x, %s, 0x%llx) aot %d phase 0x%x add %d\n",
10910 reason, (int)flags, deviceName->getCStringNoCopy(), device->getRegistryEntryID(),
10911 _aotNow, pmTracer->getTracePhase(), addWakeReason);
10912
10913 #if DEVELOPMENT || DEBUG
10914 if (addWakeReason) {
10915 record_system_event(SYSTEM_EVENT_TYPE_INFO,
10916 SYSTEM_EVENT_SUBSYSTEM_PMRD,
10917 "Report System Wake Event",
10918 "Reason: %s Flags: 0x%x Device: %s, DeviceRegEntry: 0x%llx\n",
10919 reason,
10920 (int)flags,
10921 deviceName->getCStringNoCopy(),
10922 device->getRegistryEntryID()
10923 );
10924 }
10925 #endif /* DEVELOPMENT || DEBUG */
10926
10927 if (!gWakeReasonSysctlRegistered) {
10928 // Lazy registration until the platform driver stops registering
10929 // the same name.
10930 gWakeReasonSysctlRegistered = true;
10931 }
10932 if (addWakeReason) {
10933 _systemWakeEventsArray->setObject(dict.get());
10934 if (gWakeReasonString[0] != '\0') {
10935 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
10936 }
10937 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
10938 }
10939
10940 WAKEEVENT_UNLOCK();
10941 if (needAOTEvaluate) {
10942 // Call aotEvaluate() on PM work loop since it may call
10943 // aotExit() which accesses PM state.
10944 pmPowerStateQueue->submitPowerEvent(kPowerEventAOTEvaluate);
10945 }
10946
10947 done:
10948 return;
10949 }
10950
10951 //******************************************************************************
10952 // claimSystemBootEvent
10953 //
10954 // For a driver to claim a device is the source/conduit of a system boot event.
10955 //******************************************************************************
10956
10957 void
claimSystemBootEvent(IOService * device,IOOptionBits flags,const char * reason,__unused OSObject * details)10958 IOPMrootDomain::claimSystemBootEvent(
10959 IOService * device,
10960 IOOptionBits flags,
10961 const char * reason,
10962 __unused OSObject * details )
10963 {
10964 if (!device || !reason) {
10965 return;
10966 }
10967
10968 DEBUG_LOG("claimSystemBootEvent(%s, %s, 0x%x)\n", reason, device->getName(), (uint32_t) flags);
10969 #if DEVELOPMENT || DEBUG
10970 record_system_event(SYSTEM_EVENT_TYPE_INFO,
10971 SYSTEM_EVENT_SUBSYSTEM_PMRD,
10972 "Report System Boot Device",
10973 "Reason: %s Flags: 0x%x Device: %s",
10974 reason,
10975 (int)flags,
10976 device->getName()
10977 );
10978 #endif /* DEVELOPMENT || DEBUG */
10979 WAKEEVENT_LOCK();
10980 if (!gBootReasonSysctlRegistered) {
10981 // Lazy sysctl registration after setting gBootReasonString
10982 strlcat(gBootReasonString, reason, sizeof(gBootReasonString));
10983 os_atomic_store(&gBootReasonSysctlRegistered, true, release);
10984 }
10985 WAKEEVENT_UNLOCK();
10986 }
10987
10988 //******************************************************************************
10989 // claimSystemShutdownEvent
10990 //
10991 // For drivers to claim a system shutdown event on the ensuing boot.
10992 //******************************************************************************
10993
10994 void
claimSystemShutdownEvent(IOService * device,IOOptionBits flags,const char * reason,__unused OSObject * details)10995 IOPMrootDomain::claimSystemShutdownEvent(
10996 IOService * device,
10997 IOOptionBits flags,
10998 const char * reason,
10999 __unused OSObject * details )
11000 {
11001 if (!device || !reason) {
11002 return;
11003 }
11004
11005 DEBUG_LOG("claimSystemShutdownEvent(%s, %s, 0x%x)\n", reason, device->getName(), (uint32_t) flags);
11006 #if DEVELOPMENT || DEBUG
11007 record_system_event(SYSTEM_EVENT_TYPE_INFO,
11008 SYSTEM_EVENT_SUBSYSTEM_PMRD,
11009 "Report System Shutdown Cause From Previous Boot",
11010 "Reason: %s Flags: 0x%x Device: %s",
11011 reason,
11012 (int)flags,
11013 device->getName()
11014 );
11015 #endif /* DEVELOPMENT || DEBUG */
11016 WAKEEVENT_LOCK();
11017 if (gShutdownReasonString[0] != '\0') {
11018 strlcat(gShutdownReasonString, " ", sizeof(gShutdownReasonString));
11019 }
11020 strlcat(gShutdownReasonString, reason, sizeof(gShutdownReasonString));
11021
11022 gShutdownReasonSysctlRegistered = true;
11023 WAKEEVENT_UNLOCK();
11024 }
11025
11026 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11027
11028 // MARK: -
11029 // MARK: PMSettingHandle
11030
OSDefineMetaClassAndStructors(PMSettingHandle,OSObject)11031 OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
11032
11033 void
11034 PMSettingHandle::free( void )
11035 {
11036 if (pmso) {
11037 pmso->clientHandleFreed();
11038 pmso->release();
11039 pmso = NULL;
11040 }
11041
11042 OSObject::free();
11043 }
11044
11045 // MARK: -
11046 // MARK: PMSettingObject
11047
11048 #undef super
11049 #define super OSObject
OSDefineMetaClassAndFinalStructors(PMSettingObject,OSObject)11050 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
11051
11052 /*
11053 * Static constructor/initializer for PMSettingObject
11054 */
11055 PMSettingObject *PMSettingObject::pmSettingObject(
11056 IOPMrootDomain * parent_arg,
11057 IOPMSettingControllerCallback handler_arg,
11058 OSObject * target_arg,
11059 uintptr_t refcon_arg,
11060 uint32_t supportedPowerSources,
11061 const OSSymbol * settings[],
11062 OSObject * *handle_obj)
11063 {
11064 uint32_t settingCount = 0;
11065 PMSettingObject *pmso = NULL;
11066 PMSettingHandle *pmsh = NULL;
11067
11068 if (!parent_arg || !handler_arg || !settings || !handle_obj) {
11069 return NULL;
11070 }
11071
11072 // count OSSymbol entries in NULL terminated settings array
11073 while (settings[settingCount]) {
11074 settingCount++;
11075 }
11076 if (0 == settingCount) {
11077 return NULL;
11078 }
11079
11080 pmso = new PMSettingObject;
11081 if (!pmso || !pmso->init()) {
11082 goto fail;
11083 }
11084
11085 pmsh = new PMSettingHandle;
11086 if (!pmsh || !pmsh->init()) {
11087 goto fail;
11088 }
11089
11090 queue_init(&pmso->calloutQueue);
11091 pmso->parent = parent_arg;
11092 pmso->func = handler_arg;
11093 pmso->target = target_arg;
11094 pmso->refcon = refcon_arg;
11095 pmso->settingCount = settingCount;
11096
11097 pmso->retain(); // handle holds a retain on pmso
11098 pmsh->pmso = pmso;
11099 pmso->pmsh = pmsh;
11100
11101 pmso->publishedFeatureID = OSDataAllocation<uint32_t>(settingCount, OSAllocateMemory);
11102 if (pmso->publishedFeatureID) {
11103 for (unsigned int i = 0; i < settingCount; i++) {
11104 // Since there is now at least one listener to this setting, publish
11105 // PM root domain support for it.
11106 parent_arg->publishPMSetting( settings[i],
11107 supportedPowerSources, &pmso->publishedFeatureID[i] );
11108 }
11109 }
11110
11111 *handle_obj = pmsh;
11112 return pmso;
11113
11114 fail:
11115 if (pmso) {
11116 pmso->release();
11117 }
11118 if (pmsh) {
11119 pmsh->release();
11120 }
11121 return NULL;
11122 }
11123
11124 void
free(void)11125 PMSettingObject::free( void )
11126 {
11127 if (publishedFeatureID) {
11128 for (const auto& featureID : publishedFeatureID) {
11129 if (featureID) {
11130 parent->removePublishedFeature( featureID );
11131 }
11132 }
11133
11134 publishedFeatureID = {};
11135 }
11136
11137 super::free();
11138 }
11139
11140 IOReturn
dispatchPMSetting(const OSSymbol * type,OSObject * object)11141 PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
11142 {
11143 return (*func)(target, type, object, refcon);
11144 }
11145
11146 void
clientHandleFreed(void)11147 PMSettingObject::clientHandleFreed( void )
11148 {
11149 parent->deregisterPMSettingObject(this);
11150 }
11151
11152 // MARK: -
11153 // MARK: PMAssertionsTracker
11154
11155 //*********************************************************************************
11156 //*********************************************************************************
11157 //*********************************************************************************
11158 // class PMAssertionsTracker Implementation
11159
11160 #define kAssertUniqueIDStart 500
11161
11162 PMAssertionsTracker *
pmAssertionsTracker(IOPMrootDomain * rootDomain)11163 PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
11164 {
11165 PMAssertionsTracker *me;
11166
11167 me = new PMAssertionsTracker;
11168 if (!me || !me->init()) {
11169 if (me) {
11170 me->release();
11171 }
11172 return NULL;
11173 }
11174
11175 me->owner = rootDomain;
11176 me->issuingUniqueID = kAssertUniqueIDStart;
11177 me->assertionsArray = OSArray::withCapacity(5);
11178 me->assertionsKernel = 0;
11179 me->assertionsUser = 0;
11180 me->assertionsCombined = 0;
11181 me->assertionsArrayLock = IOLockAlloc();
11182 me->tabulateProducerCount = me->tabulateConsumerCount = 0;
11183
11184 assert(me->assertionsArray);
11185 assert(me->assertionsArrayLock);
11186
11187 return me;
11188 }
11189
11190 /* tabulate
11191 * - Update assertionsKernel to reflect the state of all
11192 * assertions in the kernel.
11193 * - Update assertionsCombined to reflect both kernel & user space.
11194 */
11195 void
tabulate(void)11196 PMAssertionsTracker::tabulate(void)
11197 {
11198 int i;
11199 int count;
11200 const PMAssertStruct *_a = nullptr;
11201 OSValueObject<PMAssertStruct> *_d = nullptr;
11202
11203 IOPMDriverAssertionType oldKernel = assertionsKernel;
11204 IOPMDriverAssertionType oldCombined = assertionsCombined;
11205
11206 ASSERT_GATED();
11207
11208 assertionsKernel = 0;
11209 assertionsCombined = 0;
11210
11211 if (!assertionsArray) {
11212 return;
11213 }
11214
11215 if ((count = assertionsArray->getCount())) {
11216 for (i = 0; i < count; i++) {
11217 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11218 if (_d) {
11219 _a = _d->getBytesNoCopy();
11220 if (_a && (kIOPMDriverAssertionLevelOn == _a->level)) {
11221 assertionsKernel |= _a->assertionBits;
11222 }
11223 }
11224 }
11225 }
11226
11227 tabulateProducerCount++;
11228 assertionsCombined = assertionsKernel | assertionsUser;
11229
11230 if ((assertionsKernel != oldKernel) ||
11231 (assertionsCombined != oldCombined)) {
11232 owner->evaluateAssertions(assertionsCombined, oldCombined);
11233 }
11234 }
11235
11236 void
updateCPUBitAccounting(PMAssertStruct * assertStruct)11237 PMAssertionsTracker::updateCPUBitAccounting( PMAssertStruct *assertStruct )
11238 {
11239 AbsoluteTime now;
11240 uint64_t nsec;
11241
11242 if (((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) == 0) ||
11243 (assertStruct->assertCPUStartTime == 0)) {
11244 return;
11245 }
11246
11247 now = mach_absolute_time();
11248 SUB_ABSOLUTETIME(&now, &assertStruct->assertCPUStartTime);
11249 absolutetime_to_nanoseconds(now, &nsec);
11250 assertStruct->assertCPUDuration += nsec;
11251 assertStruct->assertCPUStartTime = 0;
11252
11253 if (assertStruct->assertCPUDuration > maxAssertCPUDuration) {
11254 maxAssertCPUDuration = assertStruct->assertCPUDuration;
11255 maxAssertCPUEntryId = assertStruct->registryEntryID;
11256 }
11257 }
11258
11259 void
reportCPUBitAccounting(void)11260 PMAssertionsTracker::reportCPUBitAccounting( void )
11261 {
11262 const PMAssertStruct *_a = nullptr;
11263 OSValueObject<PMAssertStruct> *_d = nullptr;
11264 int i, count;
11265 AbsoluteTime now;
11266 uint64_t nsec;
11267
11268 ASSERT_GATED();
11269
11270 // Account for drivers that are still holding the CPU assertion
11271 if (assertionsKernel & kIOPMDriverAssertionCPUBit) {
11272 now = mach_absolute_time();
11273 if ((count = assertionsArray->getCount())) {
11274 for (i = 0; i < count; i++) {
11275 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11276 if (_d) {
11277 _a = _d->getBytesNoCopy();
11278 if ((_a->assertionBits & kIOPMDriverAssertionCPUBit) &&
11279 (_a->level == kIOPMDriverAssertionLevelOn) &&
11280 (_a->assertCPUStartTime != 0)) {
11281 // Don't modify PMAssertStruct, leave that
11282 // for updateCPUBitAccounting()
11283 SUB_ABSOLUTETIME(&now, &_a->assertCPUStartTime);
11284 absolutetime_to_nanoseconds(now, &nsec);
11285 nsec += _a->assertCPUDuration;
11286 if (nsec > maxAssertCPUDuration) {
11287 maxAssertCPUDuration = nsec;
11288 maxAssertCPUEntryId = _a->registryEntryID;
11289 }
11290 }
11291 }
11292 }
11293 }
11294 }
11295
11296 if (maxAssertCPUDuration) {
11297 DLOG("cpu assertion held for %llu ms by 0x%llx\n",
11298 (maxAssertCPUDuration / NSEC_PER_MSEC), maxAssertCPUEntryId);
11299 }
11300
11301 maxAssertCPUDuration = 0;
11302 maxAssertCPUEntryId = 0;
11303 }
11304
11305 void
publishProperties(void)11306 PMAssertionsTracker::publishProperties( void )
11307 {
11308 OSSharedPtr<OSArray> assertionsSummary;
11309
11310 if (tabulateConsumerCount != tabulateProducerCount) {
11311 IOLockLock(assertionsArrayLock);
11312
11313 tabulateConsumerCount = tabulateProducerCount;
11314
11315 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
11316 */
11317 assertionsSummary = copyAssertionsArray();
11318 if (assertionsSummary) {
11319 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary.get());
11320 } else {
11321 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
11322 }
11323
11324 /* Publish the IOPMrootDomain property "DriverPMAssertions"
11325 */
11326 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
11327
11328 IOLockUnlock(assertionsArrayLock);
11329 }
11330 }
11331
11332 PMAssertStruct *
detailsForID(IOPMDriverAssertionID _id,int * index)11333 PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
11334 {
11335 PMAssertStruct *_a = NULL;
11336 OSValueObject<PMAssertStruct> *_d = nullptr;
11337 int found = -1;
11338 int count = 0;
11339 int i = 0;
11340
11341 if (assertionsArray
11342 && (count = assertionsArray->getCount())) {
11343 for (i = 0; i < count; i++) {
11344 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11345 if (_d) {
11346 _a = _d->getMutableBytesNoCopy();
11347 if (_a && (_id == _a->id)) {
11348 found = i;
11349 break;
11350 }
11351 }
11352 }
11353 }
11354
11355 if (-1 == found) {
11356 return NULL;
11357 } else {
11358 if (index) {
11359 *index = found;
11360 }
11361 return _a;
11362 }
11363 }
11364
11365 /* PMAssertionsTracker::handleCreateAssertion
11366 * Perform assertion work on the PM workloop. Do not call directly.
11367 */
11368 IOReturn
handleCreateAssertion(OSValueObject<PMAssertStruct> * newAssertion)11369 PMAssertionsTracker::handleCreateAssertion(OSValueObject<PMAssertStruct> *newAssertion)
11370 {
11371 PMAssertStruct *assertStruct = nullptr;
11372
11373 ASSERT_GATED();
11374
11375 if (newAssertion) {
11376 IOLockLock(assertionsArrayLock);
11377 assertStruct = newAssertion->getMutableBytesNoCopy();
11378 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11379 (assertStruct->level == kIOPMDriverAssertionLevelOn)) {
11380 assertStruct->assertCPUStartTime = mach_absolute_time();
11381 }
11382 assertionsArray->setObject(newAssertion);
11383 IOLockUnlock(assertionsArrayLock);
11384 newAssertion->release();
11385
11386 tabulate();
11387 }
11388 return kIOReturnSuccess;
11389 }
11390
11391 /* PMAssertionsTracker::createAssertion
11392 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
11393 * appropiate.
11394 */
11395 IOReturn
createAssertion(IOPMDriverAssertionType which,IOPMDriverAssertionLevel level,IOService * serviceID,const char * whoItIs,IOPMDriverAssertionID * outID)11396 PMAssertionsTracker::createAssertion(
11397 IOPMDriverAssertionType which,
11398 IOPMDriverAssertionLevel level,
11399 IOService *serviceID,
11400 const char *whoItIs,
11401 IOPMDriverAssertionID *outID)
11402 {
11403 OSSharedPtr<OSValueObject<PMAssertStruct> > dataStore;
11404 PMAssertStruct track;
11405
11406 // Warning: trillions and trillions of created assertions may overflow the unique ID.
11407 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
11408 track.level = level;
11409 track.assertionBits = which;
11410
11411 // NB: ownerString is explicitly managed by PMAssertStruct
11412 // it will be released in `handleReleaseAssertion' below
11413 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs).detach():nullptr;
11414 track.ownerService = serviceID;
11415 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
11416 track.modifiedTime = 0;
11417 pmEventTimeStamp(&track.createdTime);
11418 track.assertCPUStartTime = 0;
11419 track.assertCPUDuration = 0;
11420
11421 dataStore = OSValueObjectWithValue(track);
11422 if (!dataStore) {
11423 if (track.ownerString) {
11424 track.ownerString->release();
11425 track.ownerString = NULL;
11426 }
11427 return kIOReturnNoMemory;
11428 }
11429
11430 *outID = track.id;
11431
11432 if (owner && owner->pmPowerStateQueue) {
11433 // queue action is responsible for releasing dataStore
11434 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore.detach());
11435 }
11436
11437 return kIOReturnSuccess;
11438 }
11439
11440 /* PMAssertionsTracker::handleReleaseAssertion
11441 * Runs in PM workloop. Do not call directly.
11442 */
11443 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID _id)11444 PMAssertionsTracker::handleReleaseAssertion(
11445 IOPMDriverAssertionID _id)
11446 {
11447 ASSERT_GATED();
11448
11449 int index;
11450 PMAssertStruct *assertStruct = detailsForID(_id, &index);
11451
11452 if (!assertStruct) {
11453 return kIOReturnNotFound;
11454 }
11455
11456 IOLockLock(assertionsArrayLock);
11457
11458 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11459 (assertStruct->level == kIOPMDriverAssertionLevelOn)) {
11460 updateCPUBitAccounting(assertStruct);
11461 }
11462
11463 if (assertStruct->ownerString) {
11464 assertStruct->ownerString->release();
11465 assertStruct->ownerString = NULL;
11466 }
11467
11468 assertionsArray->removeObject(index);
11469 IOLockUnlock(assertionsArrayLock);
11470
11471 tabulate();
11472 return kIOReturnSuccess;
11473 }
11474
11475 /* PMAssertionsTracker::releaseAssertion
11476 * Releases an assertion and affects system behavior if appropiate.
11477 * Actual work happens on PM workloop.
11478 */
11479 IOReturn
releaseAssertion(IOPMDriverAssertionID _id)11480 PMAssertionsTracker::releaseAssertion(
11481 IOPMDriverAssertionID _id)
11482 {
11483 if (owner && owner->pmPowerStateQueue) {
11484 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, NULL, _id);
11485 }
11486 return kIOReturnSuccess;
11487 }
11488
11489 /* PMAssertionsTracker::handleSetAssertionLevel
11490 * Runs in PM workloop. Do not call directly.
11491 */
11492 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID _id,IOPMDriverAssertionLevel _level)11493 PMAssertionsTracker::handleSetAssertionLevel(
11494 IOPMDriverAssertionID _id,
11495 IOPMDriverAssertionLevel _level)
11496 {
11497 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
11498
11499 ASSERT_GATED();
11500
11501 if (!assertStruct) {
11502 return kIOReturnNotFound;
11503 }
11504
11505 IOLockLock(assertionsArrayLock);
11506 pmEventTimeStamp(&assertStruct->modifiedTime);
11507 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11508 (assertStruct->level != _level)) {
11509 if (_level == kIOPMDriverAssertionLevelOn) {
11510 assertStruct->assertCPUStartTime = mach_absolute_time();
11511 } else {
11512 updateCPUBitAccounting(assertStruct);
11513 }
11514 }
11515 assertStruct->level = _level;
11516 IOLockUnlock(assertionsArrayLock);
11517
11518 tabulate();
11519 return kIOReturnSuccess;
11520 }
11521
11522 /* PMAssertionsTracker::setAssertionLevel
11523 */
11524 IOReturn
setAssertionLevel(IOPMDriverAssertionID _id,IOPMDriverAssertionLevel _level)11525 PMAssertionsTracker::setAssertionLevel(
11526 IOPMDriverAssertionID _id,
11527 IOPMDriverAssertionLevel _level)
11528 {
11529 if (owner && owner->pmPowerStateQueue) {
11530 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
11531 (void *)(uintptr_t)_level, _id);
11532 }
11533
11534 return kIOReturnSuccess;
11535 }
11536
11537 IOReturn
handleSetUserAssertionLevels(void * arg0)11538 PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
11539 {
11540 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
11541
11542 ASSERT_GATED();
11543
11544 if (new_user_levels != assertionsUser) {
11545 DLOG("assertionsUser 0x%llx->0x%llx\n", assertionsUser, new_user_levels);
11546 assertionsUser = new_user_levels;
11547 }
11548
11549 tabulate();
11550 return kIOReturnSuccess;
11551 }
11552
11553 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType new_user_levels)11554 PMAssertionsTracker::setUserAssertionLevels(
11555 IOPMDriverAssertionType new_user_levels)
11556 {
11557 if (gIOPMWorkLoop) {
11558 gIOPMWorkLoop->runAction(
11559 OSMemberFunctionCast(
11560 IOWorkLoop::Action,
11561 this,
11562 &PMAssertionsTracker::handleSetUserAssertionLevels),
11563 this,
11564 (void *) &new_user_levels, NULL, NULL, NULL);
11565 }
11566
11567 return kIOReturnSuccess;
11568 }
11569
11570
11571 OSSharedPtr<OSArray>
copyAssertionsArray(void)11572 PMAssertionsTracker::copyAssertionsArray(void)
11573 {
11574 int count;
11575 int i;
11576 OSSharedPtr<OSArray> outArray = NULL;
11577
11578 if (!assertionsArray || (0 == (count = assertionsArray->getCount()))) {
11579 goto exit;
11580 }
11581 outArray = OSArray::withCapacity(count);
11582 if (!outArray) {
11583 goto exit;
11584 }
11585
11586 for (i = 0; i < count; i++) {
11587 const PMAssertStruct *_a = nullptr;
11588 OSValueObject<PMAssertStruct> *_d = nullptr;
11589 OSSharedPtr<OSDictionary> details;
11590
11591 _d = OSDynamicCast(OSValueObject<PMAssertStruct>, assertionsArray->getObject(i));
11592 if (_d && (_a = _d->getBytesNoCopy())) {
11593 OSSharedPtr<OSNumber> _n;
11594
11595 details = OSDictionary::withCapacity(7);
11596 if (!details) {
11597 continue;
11598 }
11599
11600 outArray->setObject(details.get());
11601
11602 _n = OSNumber::withNumber(_a->id, 64);
11603 if (_n) {
11604 details->setObject(kIOPMDriverAssertionIDKey, _n.get());
11605 }
11606 _n = OSNumber::withNumber(_a->createdTime, 64);
11607 if (_n) {
11608 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n.get());
11609 }
11610 _n = OSNumber::withNumber(_a->modifiedTime, 64);
11611 if (_n) {
11612 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n.get());
11613 }
11614 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
11615 if (_n) {
11616 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n.get());
11617 }
11618 _n = OSNumber::withNumber(_a->level, 64);
11619 if (_n) {
11620 details->setObject(kIOPMDriverAssertionLevelKey, _n.get());
11621 }
11622 _n = OSNumber::withNumber(_a->assertionBits, 64);
11623 if (_n) {
11624 details->setObject(kIOPMDriverAssertionAssertedKey, _n.get());
11625 }
11626
11627 if (_a->ownerString) {
11628 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
11629 }
11630 }
11631 }
11632
11633 exit:
11634 return os::move(outArray);
11635 }
11636
11637 IOPMDriverAssertionType
getActivatedAssertions(void)11638 PMAssertionsTracker::getActivatedAssertions(void)
11639 {
11640 return assertionsCombined;
11641 }
11642
11643 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType type)11644 PMAssertionsTracker::getAssertionLevel(
11645 IOPMDriverAssertionType type)
11646 {
11647 // FIXME: unused and also wrong
11648 if (type && ((type & assertionsKernel) == assertionsKernel)) {
11649 return kIOPMDriverAssertionLevelOn;
11650 } else {
11651 return kIOPMDriverAssertionLevelOff;
11652 }
11653 }
11654
11655 //*********************************************************************************
11656 //*********************************************************************************
11657 //*********************************************************************************
11658
11659
11660 static void
pmEventTimeStamp(uint64_t * recordTS)11661 pmEventTimeStamp(uint64_t *recordTS)
11662 {
11663 clock_sec_t tsec;
11664 clock_usec_t tusec;
11665
11666 if (!recordTS) {
11667 return;
11668 }
11669
11670 // We assume tsec fits into 32 bits; 32 bits holds enough
11671 // seconds for 136 years since the epoch in 1970.
11672 clock_get_calendar_microtime(&tsec, &tusec);
11673
11674
11675 // Pack the sec & microsec calendar time into a uint64_t, for fun.
11676 *recordTS = 0;
11677 *recordTS |= (uint32_t)tusec;
11678 *recordTS |= ((uint64_t)tsec << 32);
11679
11680 return;
11681 }
11682
11683 // MARK: -
11684 // MARK: IORootParent
11685
11686 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11687
11688 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
11689
11690 // The reason that root domain needs a root parent is to facilitate demand
11691 // sleep, since a power change from the root parent cannot be vetoed.
11692 //
11693 // The above statement is no longer true since root domain now performs
11694 // demand sleep using overrides. But root parent remains to avoid changing
11695 // the power tree stacking. Root parent is parked at the max power state.
11696
11697
11698 static IOPMPowerState patriarchPowerStates[2] =
11699 {
11700 {1, 0, ON_POWER, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11701 {1, 0, ON_POWER, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11702 };
11703
11704 void
initialize(void)11705 IORootParent::initialize( void )
11706 {
11707
11708 gIOPMPSExternalConnectedKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey);
11709 gIOPMPSExternalChargeCapableKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey);
11710 gIOPMPSBatteryInstalledKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey);
11711 gIOPMPSIsChargingKey = OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey);
11712 gIOPMPSAtWarnLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey);
11713 gIOPMPSAtCriticalLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey);
11714 gIOPMPSCurrentCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey);
11715 gIOPMPSMaxCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey);
11716 gIOPMPSDesignCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey);
11717 gIOPMPSTimeRemainingKey = OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey);
11718 gIOPMPSAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey);
11719 gIOPMPSVoltageKey = OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey);
11720 gIOPMPSCycleCountKey = OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey);
11721 gIOPMPSMaxErrKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey);
11722 gIOPMPSAdapterInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey);
11723 gIOPMPSLocationKey = OSSymbol::withCStringNoCopy(kIOPMPSLocationKey);
11724 gIOPMPSErrorConditionKey = OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey);
11725 gIOPMPSManufacturerKey = OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey);
11726 gIOPMPSManufactureDateKey = OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey);
11727 gIOPMPSModelKey = OSSymbol::withCStringNoCopy(kIOPMPSModelKey);
11728 gIOPMPSSerialKey = OSSymbol::withCStringNoCopy(kIOPMPSSerialKey);
11729 gIOPMPSLegacyBatteryInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey);
11730 gIOPMPSBatteryHealthKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey);
11731 gIOPMPSHealthConfidenceKey = OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey);
11732 gIOPMPSCapacityEstimatedKey = OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey);
11733 gIOPMPSBatteryChargeStatusKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey);
11734 gIOPMPSBatteryTemperatureKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey);
11735 gIOPMPSAdapterDetailsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey);
11736 gIOPMPSChargerConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey);
11737 gIOPMPSAdapterDetailsIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey);
11738 gIOPMPSAdapterDetailsWattsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey);
11739 gIOPMPSAdapterDetailsRevisionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey);
11740 gIOPMPSAdapterDetailsSerialNumberKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey);
11741 gIOPMPSAdapterDetailsFamilyKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey);
11742 gIOPMPSAdapterDetailsAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey);
11743 gIOPMPSAdapterDetailsDescriptionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey);
11744 gIOPMPSAdapterDetailsPMUConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey);
11745 gIOPMPSAdapterDetailsSourceIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey);
11746 gIOPMPSAdapterDetailsErrorFlagsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey);
11747 gIOPMPSAdapterDetailsSharedSourceKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey);
11748 gIOPMPSAdapterDetailsCloakedKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey);
11749 gIOPMPSInvalidWakeSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey);
11750 gIOPMPSPostChargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey);
11751 gIOPMPSPostDishargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey);
11752 }
11753
11754 bool
start(IOService * nub)11755 IORootParent::start( IOService * nub )
11756 {
11757 IOService::start(nub);
11758 attachToParent( getRegistryRoot(), gIOPowerPlane );
11759 PMinit();
11760 registerPowerDriver(this, patriarchPowerStates, 2);
11761 makeUsable();
11762 return true;
11763 }
11764
11765 void
shutDownSystem(void)11766 IORootParent::shutDownSystem( void )
11767 {
11768 }
11769
11770 void
restartSystem(void)11771 IORootParent::restartSystem( void )
11772 {
11773 }
11774
11775 void
sleepSystem(void)11776 IORootParent::sleepSystem( void )
11777 {
11778 }
11779
11780 void
dozeSystem(void)11781 IORootParent::dozeSystem( void )
11782 {
11783 }
11784
11785 void
sleepToDoze(void)11786 IORootParent::sleepToDoze( void )
11787 {
11788 }
11789
11790 void
wakeSystem(void)11791 IORootParent::wakeSystem( void )
11792 {
11793 }
11794
11795 OSSharedPtr<OSObject>
copyProperty(const char * aKey) const11796 IORootParent::copyProperty( const char * aKey) const
11797 {
11798 return IOService::copyProperty(aKey);
11799 }
11800
11801 uint32_t
getWatchdogTimeout()11802 IOPMrootDomain::getWatchdogTimeout()
11803 {
11804 if (gSwdSleepWakeTimeout) {
11805 gSwdSleepTimeout = gSwdWakeTimeout = gSwdSleepWakeTimeout;
11806 }
11807 if ((pmTracer->getTracePhase() < kIOPMTracePointSystemSleep) ||
11808 (pmTracer->getTracePhase() == kIOPMTracePointDarkWakeEntry)) {
11809 return gSwdSleepTimeout ? gSwdSleepTimeout : WATCHDOG_SLEEP_TIMEOUT;
11810 } else {
11811 return gSwdWakeTimeout ? gSwdWakeTimeout : WATCHDOG_WAKE_TIMEOUT;
11812 }
11813 }
11814
11815
11816 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
11817 IOReturn
restartWithStackshot()11818 IOPMrootDomain::restartWithStackshot()
11819 {
11820 takeStackshot(true);
11821
11822 return kIOReturnSuccess;
11823 }
11824
11825 void
sleepWakeDebugTrig(bool wdogTrigger)11826 IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
11827 {
11828 takeStackshot(wdogTrigger);
11829 }
11830
11831 void
tracePhase2String(uint32_t tracePhase,const char ** phaseString,const char ** description)11832 IOPMrootDomain::tracePhase2String(uint32_t tracePhase, const char **phaseString, const char **description)
11833 {
11834 switch (tracePhase) {
11835 case kIOPMTracePointSleepStarted:
11836 *phaseString = "kIOPMTracePointSleepStarted";
11837 *description = "starting sleep";
11838 break;
11839
11840 case kIOPMTracePointSleepApplications:
11841 *phaseString = "kIOPMTracePointSleepApplications";
11842 *description = "notifying applications";
11843 break;
11844
11845 case kIOPMTracePointSleepPriorityClients:
11846 *phaseString = "kIOPMTracePointSleepPriorityClients";
11847 *description = "notifying clients about upcoming system capability changes";
11848 break;
11849
11850 case kIOPMTracePointSleepWillChangeInterests:
11851 *phaseString = "kIOPMTracePointSleepWillChangeInterests";
11852 *description = "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
11853 break;
11854
11855 case kIOPMTracePointSleepPowerPlaneDrivers:
11856 *phaseString = "kIOPMTracePointSleepPowerPlaneDrivers";
11857 *description = "calling power state change callbacks";
11858 break;
11859
11860 case kIOPMTracePointSleepDidChangeInterests:
11861 *phaseString = "kIOPMTracePointSleepDidChangeInterests";
11862 *description = "calling rootDomain's clients about rootDomain's state changes";
11863 break;
11864
11865 case kIOPMTracePointSleepCapabilityClients:
11866 *phaseString = "kIOPMTracePointSleepCapabilityClients";
11867 *description = "notifying clients about current system capabilities";
11868 break;
11869
11870 case kIOPMTracePointSleepPlatformActions:
11871 *phaseString = "kIOPMTracePointSleepPlatformActions";
11872 *description = "calling Quiesce/Sleep action callbacks";
11873 break;
11874
11875 case kIOPMTracePointSleepCPUs:
11876 {
11877 *phaseString = "kIOPMTracePointSleepCPUs";
11878 #if defined(__i386__) || defined(__x86_64__)
11879 /*
11880 * We cannot use the getCPUNumber() method to get the cpu number, since
11881 * that cpu number is unrelated to the cpu number we need (we need the cpu
11882 * number as enumerated by the scheduler, NOT the CPU number enumerated
11883 * by ACPIPlatform as the CPUs are enumerated in MADT order).
11884 * Instead, pass the Mach processor pointer associated with the current
11885 * shutdown target so its associated cpu_id can be used in
11886 * processor_to_datastring.
11887 */
11888 if (currentShutdownTarget != NULL &&
11889 currentShutdownTarget->getMachProcessor() != NULL) {
11890 const char *sbuf = processor_to_datastring("halting all non-boot CPUs",
11891 currentShutdownTarget->getMachProcessor());
11892 *description = sbuf;
11893 } else {
11894 *description = "halting all non-boot CPUs";
11895 }
11896 #else
11897 *description = "halting all non-boot CPUs";
11898 #endif
11899 break;
11900 }
11901 case kIOPMTracePointSleepPlatformDriver:
11902 *phaseString = "kIOPMTracePointSleepPlatformDriver";
11903 *description = "executing platform specific code";
11904 break;
11905
11906 case kIOPMTracePointHibernate:
11907 *phaseString = "kIOPMTracePointHibernate";
11908 *description = "writing the hibernation image";
11909 break;
11910
11911 case kIOPMTracePointSystemSleep:
11912 *phaseString = "kIOPMTracePointSystemSleep";
11913 *description = "in EFI/Bootrom after last point of entry to sleep";
11914 break;
11915
11916 case kIOPMTracePointWakePlatformDriver:
11917 *phaseString = "kIOPMTracePointWakePlatformDriver";
11918 *description = "executing platform specific code";
11919 break;
11920
11921
11922 case kIOPMTracePointWakePlatformActions:
11923 *phaseString = "kIOPMTracePointWakePlatformActions";
11924 *description = "calling Wake action callbacks";
11925 break;
11926
11927 case kIOPMTracePointWakeCPUs:
11928 *phaseString = "kIOPMTracePointWakeCPUs";
11929 *description = "starting non-boot CPUs";
11930 break;
11931
11932 case kIOPMTracePointWakeWillPowerOnClients:
11933 *phaseString = "kIOPMTracePointWakeWillPowerOnClients";
11934 *description = "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
11935 break;
11936
11937 case kIOPMTracePointWakeWillChangeInterests:
11938 *phaseString = "kIOPMTracePointWakeWillChangeInterests";
11939 *description = "calling rootDomain's clients about upcoming rootDomain's state changes";
11940 break;
11941
11942 case kIOPMTracePointWakeDidChangeInterests:
11943 *phaseString = "kIOPMTracePointWakeDidChangeInterests";
11944 *description = "calling rootDomain's clients about completed rootDomain's state changes";
11945 break;
11946
11947 case kIOPMTracePointWakePowerPlaneDrivers:
11948 *phaseString = "kIOPMTracePointWakePowerPlaneDrivers";
11949 *description = "calling power state change callbacks";
11950 break;
11951
11952 case kIOPMTracePointWakeCapabilityClients:
11953 *phaseString = "kIOPMTracePointWakeCapabilityClients";
11954 *description = "informing clients about current system capabilities";
11955 break;
11956
11957 case kIOPMTracePointWakeApplications:
11958 *phaseString = "kIOPMTracePointWakeApplications";
11959 *description = "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
11960 break;
11961
11962 case kIOPMTracePointDarkWakeEntry:
11963 *phaseString = "kIOPMTracePointDarkWakeEntry";
11964 *description = "entering darkwake on way to sleep";
11965 break;
11966
11967 case kIOPMTracePointDarkWakeExit:
11968 *phaseString = "kIOPMTracePointDarkWakeExit";
11969 *description = "entering fullwake from darkwake";
11970 break;
11971
11972 default:
11973 *phaseString = NULL;
11974 *description = NULL;
11975 }
11976 }
11977
11978 void
saveFailureData2File()11979 IOPMrootDomain::saveFailureData2File()
11980 {
11981 unsigned int len = 0;
11982 char failureStr[512];
11983 errno_t error;
11984 char *outbuf;
11985 OSNumber *statusCode;
11986 uint64_t pmStatusCode = 0;
11987 uint32_t phaseData = 0;
11988 uint32_t phaseDetail = 0;
11989 bool efiFailure = false;
11990
11991 OSSharedPtr<OSObject> statusCodeProp = copyProperty(kIOPMSleepWakeFailureCodeKey);
11992 statusCode = OSDynamicCast(OSNumber, statusCodeProp.get());
11993 if (statusCode) {
11994 pmStatusCode = statusCode->unsigned64BitValue();
11995 phaseData = pmStatusCode & 0xFFFFFFFF;
11996 phaseDetail = (pmStatusCode >> 32) & 0xFFFFFFFF;
11997 if ((phaseData & 0xFF) == kIOPMTracePointSystemSleep) {
11998 LOG("Sleep Wake failure in EFI\n");
11999 efiFailure = true;
12000 failureStr[0] = 0;
12001 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);
12002 len = (typeof(len))strnlen(failureStr, sizeof(failureStr));
12003 }
12004 }
12005
12006 if (!efiFailure) {
12007 if (PEReadNVRAMProperty(kIOSleepWakeFailurePanic, NULL, &len)) {
12008 swd_flags |= SWD_BOOT_BY_SW_WDOG;
12009 PERemoveNVRAMProperty(kIOSleepWakeFailurePanic);
12010 // dump panic will handle saving nvram data
12011 return;
12012 }
12013
12014 /* Keeping this around for capturing data during power
12015 * button press */
12016
12017 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString, NULL, &len)) {
12018 DLOG("No sleep wake failure string\n");
12019 return;
12020 }
12021 if (len == 0) {
12022 DLOG("Ignoring zero byte SleepWake failure string\n");
12023 goto exit;
12024 }
12025
12026 // if PMStatus code is zero, delete stackshot and return
12027 if (statusCode) {
12028 if (((pmStatusCode & 0xFFFFFFFF) & 0xFF) == 0) {
12029 // there was no sleep wake failure
12030 // this can happen if delete stackshot was called
12031 // before take stackshot completed. Let us delete any
12032 // sleep wake failure data in nvram
12033 DLOG("Deleting stackshot on successful wake\n");
12034 deleteStackshot();
12035 return;
12036 }
12037 }
12038
12039 if (len > sizeof(failureStr)) {
12040 len = sizeof(failureStr);
12041 }
12042 failureStr[0] = 0;
12043 PEReadNVRAMProperty(kIOSleepWakeFailureString, failureStr, &len);
12044 }
12045 if (failureStr[0] != 0) {
12046 error = sleepWakeDebugSaveFile(kSleepWakeFailureStringFile, failureStr, len);
12047 if (error) {
12048 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error);
12049 } else {
12050 DLOG("Saved SleepWake failure string to file.\n");
12051 }
12052 }
12053
12054 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12055 goto exit;
12056 }
12057
12058 if (swd_buffer) {
12059 unsigned int len = 0;
12060 errno_t error;
12061 char nvram_var_name_buffer[20];
12062 unsigned int concat_len = 0;
12063 swd_hdr *hdr = NULL;
12064
12065
12066 hdr = (swd_hdr *)swd_buffer;
12067 outbuf = (char *)hdr + hdr->spindump_offset;
12068 OSBoundedArrayRef<char> boundedOutBuf(outbuf, hdr->alloc_size - hdr->spindump_offset);
12069
12070 for (int i = 0; i < 8; i++) {
12071 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i + 1);
12072 if (!PEReadNVRAMProperty(nvram_var_name_buffer, NULL, &len)) {
12073 LOG("No SleepWake blob to read beyond chunk %d\n", i);
12074 break;
12075 }
12076 if (PEReadNVRAMProperty(nvram_var_name_buffer, boundedOutBuf.slice(concat_len, len).data(), &len) == FALSE) {
12077 PERemoveNVRAMProperty(nvram_var_name_buffer);
12078 LOG("Could not read the property :-(\n");
12079 break;
12080 }
12081 PERemoveNVRAMProperty(nvram_var_name_buffer);
12082 concat_len += len;
12083 }
12084 LOG("Concatenated length for the SWD blob %d\n", concat_len);
12085
12086 if (concat_len) {
12087 error = sleepWakeDebugSaveFile(kSleepWakeStacksFilename, outbuf, concat_len);
12088 if (error) {
12089 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
12090 } else {
12091 LOG("Saved SleepWake zipped data to file.\n");
12092 }
12093 } else {
12094 // There is a sleep wake failure string but no stackshot
12095 // Write a placeholder stacks file so that swd runs
12096 snprintf(outbuf, 20, "%s", "No stackshot data\n");
12097 error = sleepWakeDebugSaveFile(kSleepWakeStacksFilename, outbuf, 20);
12098 if (error) {
12099 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
12100 } else {
12101 LOG("Saved SleepWake zipped data to file.\n");
12102 }
12103 }
12104 } else {
12105 LOG("No buffer allocated to save failure stackshot\n");
12106 }
12107
12108
12109 gRootDomain->swd_lock = 0;
12110 exit:
12111 PERemoveNVRAMProperty(kIOSleepWakeFailureString);
12112 return;
12113 }
12114
12115
12116 void
getFailureData(thread_t * thread,char * failureStr,size_t strLen)12117 IOPMrootDomain::getFailureData(thread_t *thread, char *failureStr, size_t strLen)
12118 {
12119 OSSharedPtr<IORegistryIterator> iter;
12120 OSSharedPtr<const OSSymbol> kextName = NULL;
12121 IORegistryEntry * entry;
12122 IOService * node;
12123 bool nodeFound = false;
12124
12125 const void * callMethod = NULL;
12126 const char * objectName = NULL;
12127 uint32_t timeout = getWatchdogTimeout();
12128 const char * phaseString = NULL;
12129 const char * phaseDescription = NULL;
12130
12131 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, notifierObject.get());
12132 uint32_t tracePhase = pmTracer->getTracePhase();
12133
12134 *thread = NULL;
12135 if ((tracePhase < kIOPMTracePointSystemSleep) || (tracePhase == kIOPMTracePointDarkWakeEntry)) {
12136 snprintf(failureStr, strLen, "Sleep transition timed out after %d seconds", timeout);
12137 } else {
12138 snprintf(failureStr, strLen, "Wake transition timed out after %d seconds", timeout);
12139 }
12140 tracePhase2String(tracePhase, &phaseString, &phaseDescription);
12141
12142 if (notifierThread) {
12143 if (notifier && (notifier->identifier)) {
12144 objectName = notifier->identifier->getCStringNoCopy();
12145 }
12146 *thread = notifierThread;
12147 } else {
12148 iter = IORegistryIterator::iterateOver(
12149 getPMRootDomain(), gIOPowerPlane, kIORegistryIterateRecursively);
12150
12151 if (iter) {
12152 while ((entry = iter->getNextObject())) {
12153 node = OSDynamicCast(IOService, entry);
12154 if (!node) {
12155 continue;
12156 }
12157 if (OSDynamicCast(IOPowerConnection, node)) {
12158 continue;
12159 }
12160
12161 if (node->getBlockingDriverCall(thread, &callMethod)) {
12162 nodeFound = true;
12163 break;
12164 }
12165 }
12166 }
12167 if (nodeFound) {
12168 kextName = copyKextIdentifierWithAddress((vm_address_t) callMethod);
12169 if (kextName) {
12170 objectName = kextName->getCStringNoCopy();
12171 }
12172 }
12173 }
12174 if (phaseDescription) {
12175 strlcat(failureStr, " while ", strLen);
12176 strlcat(failureStr, phaseDescription, strLen);
12177 strlcat(failureStr, ".", strLen);
12178 }
12179 if (objectName) {
12180 strlcat(failureStr, " Suspected bundle: ", strLen);
12181 strlcat(failureStr, objectName, strLen);
12182 strlcat(failureStr, ".", strLen);
12183 }
12184 if (*thread) {
12185 char threadName[40];
12186 snprintf(threadName, sizeof(threadName), " Thread 0x%llx.", thread_tid(*thread));
12187 strlcat(failureStr, threadName, strLen);
12188 }
12189
12190 DLOG("%s\n", failureStr);
12191 }
12192
12193 struct swd_stackshot_compressed_data {
12194 z_output_func zoutput;
12195 size_t zipped;
12196 uint64_t totalbytes;
12197 uint64_t lastpercent;
12198 IOReturn error;
12199 unsigned outremain;
12200 unsigned outlen;
12201 unsigned writes;
12202 Bytef * outbuf;
12203 };
12204 struct swd_stackshot_compressed_data swd_zip_var = { };
12205
12206 static void *
swd_zs_alloc(void * __unused ref,u_int items,u_int size)12207 swd_zs_alloc(void *__unused ref, u_int items, u_int size)
12208 {
12209 void *result;
12210 LOG("Alloc in zipping %d items of size %d\n", items, size);
12211
12212 result = (void *)(swd_zs_zmem + swd_zs_zoffset);
12213 swd_zs_zoffset += ~31L & (31 + (items * size)); // 32b align for vector crc
12214 LOG("Offset %zu\n", swd_zs_zoffset);
12215 return result;
12216 }
12217
12218 static int
swd_zinput(z_streamp strm,Bytef * buf,unsigned size)12219 swd_zinput(z_streamp strm, Bytef *buf, unsigned size)
12220 {
12221 unsigned len;
12222
12223 len = strm->avail_in;
12224
12225 if (len > size) {
12226 len = size;
12227 }
12228 if (len == 0) {
12229 return 0;
12230 }
12231
12232 if (strm->next_in != (Bytef *) strm) {
12233 memcpy(buf, strm->next_in, len);
12234 } else {
12235 bzero(buf, len);
12236 }
12237
12238 strm->adler = z_crc32(strm->adler, buf, len);
12239
12240 strm->avail_in -= len;
12241 strm->next_in += len;
12242 strm->total_in += len;
12243
12244 return (int)len;
12245 }
12246
12247 static int
swd_zoutput(z_streamp strm,Bytef * buf,unsigned len)12248 swd_zoutput(z_streamp strm, Bytef *buf, unsigned len)
12249 {
12250 unsigned int i = 0;
12251 // if outlen > max size don't add to the buffer
12252 assert(buf != NULL);
12253 if (strm && buf) {
12254 if (swd_zip_var.outlen + len > SWD_COMPRESSED_BUFSIZE) {
12255 LOG("No space to GZIP... not writing to NVRAM\n");
12256 return len;
12257 }
12258 }
12259 for (i = 0; i < len; i++) {
12260 *(swd_zip_var.outbuf + swd_zip_var.outlen + i) = *(buf + i);
12261 }
12262 swd_zip_var.outlen += len;
12263 return len;
12264 }
12265
12266 static void
swd_zs_free(void * __unused ref,void * __unused ptr)12267 swd_zs_free(void * __unused ref, void * __unused ptr)
12268 {
12269 }
12270
12271 static int
swd_compress(char * inPtr,char * outPtr,size_t numBytes)12272 swd_compress(char *inPtr, char *outPtr, size_t numBytes)
12273 {
12274 int wbits = 12;
12275 int memlevel = 3;
12276
12277 if (((unsigned int) numBytes) != numBytes) {
12278 return 0;
12279 }
12280
12281 if (!swd_zs.zalloc) {
12282 swd_zs.zalloc = swd_zs_alloc;
12283 swd_zs.zfree = swd_zs_free;
12284 if (deflateInit2(&swd_zs, Z_BEST_SPEED, Z_DEFLATED, wbits + 16, memlevel, Z_DEFAULT_STRATEGY)) {
12285 // allocation failed
12286 bzero(&swd_zs, sizeof(swd_zs));
12287 // swd_zs_zoffset = 0;
12288 } else {
12289 LOG("PMRD inited the zlib allocation routines\n");
12290 }
12291 }
12292
12293 swd_zip_var.zipped = 0;
12294 swd_zip_var.totalbytes = 0; // should this be the max that we have?
12295 swd_zip_var.lastpercent = 0;
12296 swd_zip_var.error = kIOReturnSuccess;
12297 swd_zip_var.outremain = 0;
12298 swd_zip_var.outlen = 0;
12299 swd_zip_var.writes = 0;
12300 swd_zip_var.outbuf = (Bytef *)outPtr;
12301
12302 swd_zip_var.totalbytes = numBytes;
12303
12304 swd_zs.avail_in = 0;
12305 swd_zs.next_in = NULL;
12306 swd_zs.avail_out = 0;
12307 swd_zs.next_out = NULL;
12308
12309 deflateResetWithIO(&swd_zs, swd_zinput, swd_zoutput);
12310
12311 z_stream *zs;
12312 int zr;
12313 zs = &swd_zs;
12314
12315 while (swd_zip_var.error >= 0) {
12316 if (!zs->avail_in) {
12317 zs->next_in = (unsigned char *)inPtr ? (Bytef *)inPtr : (Bytef *)zs; /* zero marker? */
12318 zs->avail_in = (unsigned int) numBytes;
12319 }
12320 if (!zs->avail_out) {
12321 zs->next_out = (Bytef *)zs;
12322 zs->avail_out = UINT32_MAX;
12323 }
12324 zr = deflate(zs, Z_NO_FLUSH);
12325 if (Z_STREAM_END == zr) {
12326 break;
12327 }
12328 if (zr != Z_OK) {
12329 LOG("ZERR %d\n", zr);
12330 swd_zip_var.error = zr;
12331 } else {
12332 if (zs->total_in == numBytes) {
12333 break;
12334 }
12335 }
12336 }
12337
12338 //now flush the stream
12339 while (swd_zip_var.error >= 0) {
12340 if (!zs->avail_out) {
12341 zs->next_out = (Bytef *)zs;
12342 zs->avail_out = UINT32_MAX;
12343 }
12344 zr = deflate(zs, Z_FINISH);
12345 if (Z_STREAM_END == zr) {
12346 break;
12347 }
12348 if (zr != Z_OK) {
12349 LOG("ZERR %d\n", zr);
12350 swd_zip_var.error = zr;
12351 } else {
12352 if (zs->total_in == numBytes) {
12353 LOG("Total output size %d\n", swd_zip_var.outlen);
12354 break;
12355 }
12356 }
12357 }
12358
12359 return swd_zip_var.outlen;
12360 }
12361
12362 void
deleteStackshot()12363 IOPMrootDomain::deleteStackshot()
12364 {
12365 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12366 // takeStackshot hasn't completed
12367 return;
12368 }
12369 LOG("Deleting any sleepwake failure data in nvram\n");
12370
12371 PERemoveNVRAMProperty(kIOSleepWakeFailureString);
12372 char nvram_var_name_buf[20];
12373 for (int i = 0; i < 8; i++) {
12374 snprintf(nvram_var_name_buf, sizeof(nvram_var_name_buf), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i + 1);
12375 if (PERemoveNVRAMProperty(nvram_var_name_buf) == false) {
12376 LOG("Removing %s returned false\n", nvram_var_name_buf);
12377 }
12378 }
12379 // force NVRAM sync
12380 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey)) == false) {
12381 DLOG("Failed to force nvram sync\n");
12382 }
12383 gRootDomain->swd_lock = 0;
12384 }
12385
12386 void
takeStackshot(bool wdogTrigger)12387 IOPMrootDomain::takeStackshot(bool wdogTrigger)
12388 {
12389 swd_hdr * hdr = NULL;
12390 int cnt = 0;
12391 int max_cnt;
12392 pid_t pid = 0;
12393 kern_return_t kr = KERN_SUCCESS;
12394 uint64_t flags;
12395
12396 char * dstAddr;
12397 uint32_t size;
12398 uint32_t bytesRemaining;
12399 unsigned bytesWritten = 0;
12400
12401 char failureStr[512];
12402 thread_t thread = NULL;
12403 const char * swfPanic = "swfPanic";
12404
12405 uint32_t bufSize;
12406 int success = 0;
12407
12408 #if defined(__i386__) || defined(__x86_64__)
12409 const bool concise = false;
12410 #else
12411 const bool concise = true;
12412 #endif
12413
12414 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12415 return;
12416 }
12417
12418 failureStr[0] = 0;
12419 if ((kIOSleepWakeWdogOff & gIOKitDebug) || systemBooting || systemShutdown || gWillShutdown) {
12420 return;
12421 }
12422
12423 if (wdogTrigger) {
12424 getFailureData(&thread, failureStr, sizeof(failureStr));
12425
12426 if (concise || (PEGetCoprocessorVersion() >= kCoprocessorVersion2)) {
12427 goto skip_stackshot;
12428 }
12429 } else {
12430 AbsoluteTime now;
12431 uint64_t nsec;
12432 clock_get_uptime(&now);
12433 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
12434 absolutetime_to_nanoseconds(now, &nsec);
12435 snprintf(failureStr, sizeof(failureStr), "Power button pressed during wake transition after %u ms.\n", ((int)((nsec) / NSEC_PER_MSEC)));
12436 }
12437
12438 if (swd_buffer == NULL) {
12439 sleepWakeDebugMemAlloc();
12440 if (swd_buffer == NULL) {
12441 return;
12442 }
12443 }
12444 hdr = (swd_hdr *)swd_buffer;
12445 bufSize = hdr->alloc_size;
12446
12447 dstAddr = (char*)hdr + hdr->spindump_offset;
12448 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;
12449
12450 /* If not wdogTrigger only take kernel tasks stackshot
12451 */
12452 if (wdogTrigger) {
12453 pid = -1;
12454 max_cnt = 3;
12455 } else {
12456 pid = 0;
12457 max_cnt = 2;
12458 }
12459
12460 /* Attempt to take stackshot with all ACTIVE_KERNEL_THREADS
12461 * If we run out of space, take stackshot with only kernel task
12462 */
12463 while (success == 0 && cnt < max_cnt) {
12464 bytesRemaining = bufSize - hdr->spindump_offset;
12465 cnt++;
12466 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
12467
12468 size = bytesRemaining;
12469 kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, 0, &bytesWritten);
12470 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%llx bytesWritten: %d\n",
12471 kr, pid, size, flags, bytesWritten);
12472 if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
12473 if (pid == -1) {
12474 pid = 0;
12475 } else if (flags & STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL) {
12476 flags = flags & ~STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL;
12477 } else {
12478 LOG("Insufficient buffer size for only kernel task\n");
12479 break;
12480 }
12481 }
12482 if (kr == KERN_SUCCESS) {
12483 if (bytesWritten == 0) {
12484 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%llx\n", kr, size, flags);
12485 continue;
12486 }
12487 bytesRemaining -= bytesWritten;
12488 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
12489
12490 memset(hdr->reason, 0x20, sizeof(hdr->reason));
12491
12492 // Compress stackshot and save to NVRAM
12493 {
12494 char *outbuf = (char *)swd_compressed_buffer;
12495 int outlen = 0;
12496 int num_chunks = 0;
12497 int max_chunks = 0;
12498 int leftover = 0;
12499 char nvram_var_name_buffer[20];
12500
12501 outlen = swd_compress((char*)hdr + hdr->spindump_offset, outbuf, bytesWritten);
12502
12503 if (outlen) {
12504 max_chunks = outlen / (2096 - 200);
12505 leftover = outlen % (2096 - 200);
12506
12507 if (max_chunks < 8) {
12508 for (num_chunks = 0; num_chunks < max_chunks; num_chunks++) {
12509 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks + 1);
12510 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer, (outbuf + (num_chunks * (2096 - 200))), (2096 - 200)) == FALSE) {
12511 LOG("Failed to update NVRAM %d\n", num_chunks);
12512 break;
12513 }
12514 }
12515 if (leftover) {
12516 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks + 1);
12517 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer, (outbuf + (num_chunks * (2096 - 200))), leftover) == FALSE) {
12518 LOG("Failed to update NVRAM with leftovers\n");
12519 }
12520 }
12521 success = 1;
12522 LOG("Successfully saved stackshot to NVRAM\n");
12523 } else {
12524 if (pid == -1) {
12525 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen);
12526 pid = 0;
12527 } else if (flags & STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL) {
12528 LOG("Compressed failure stackshot of kernel+dexts is too large size=%d bytes\n", outlen);
12529 flags = flags & ~STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL;
12530 } else {
12531 LOG("Compressed failure stackshot of only kernel is too large size=%d bytes\n", outlen);
12532 break;
12533 }
12534 }
12535 }
12536 }
12537 }
12538 }
12539
12540 if (failureStr[0]) {
12541 // append sleep-wake failure code
12542 char traceCode[80];
12543 snprintf(traceCode, sizeof(traceCode), "\nFailure code:: 0x%08x %08x\n",
12544 pmTracer->getTraceData(), pmTracer->getTracePhase());
12545 strlcat(failureStr, traceCode, sizeof(failureStr));
12546 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString, failureStr, (unsigned int) strnlen(failureStr, sizeof(failureStr))) == false) {
12547 DLOG("Failed to write SleepWake failure string\n");
12548 }
12549 }
12550
12551 // force NVRAM sync
12552 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey)) == false) {
12553 DLOG("Failed to force nvram sync\n");
12554 }
12555
12556 skip_stackshot:
12557 if (wdogTrigger) {
12558 if (PEGetCoprocessorVersion() < kCoprocessorVersion2) {
12559 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
12560 // If current boot is due to this watch dog trigger restart in previous boot,
12561 // then don't trigger again until at least 1 successful sleep & wake.
12562 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
12563 LOG("Shutting down due to repeated Sleep/Wake failures\n");
12564 updateTasksSuspend(kTasksSuspendSuspended, kTasksSuspendNoChange);
12565 PEHaltRestart(kPEHaltCPU);
12566 return;
12567 }
12568 }
12569 if (gSwdPanic == 0) {
12570 LOG("Calling panic prevented by swd_panic boot-args. Calling restart");
12571 updateTasksSuspend(kTasksSuspendSuspended, kTasksSuspendNoChange);
12572 PEHaltRestart(kPERestartCPU);
12573 }
12574 }
12575 if (!concise && (PEWriteNVRAMProperty(kIOSleepWakeFailurePanic, swfPanic, (unsigned int) strlen(swfPanic)) == false)) {
12576 DLOG("Failed to write SleepWake failure panic key\n");
12577 }
12578 #if defined(__x86_64__)
12579 if (thread) {
12580 panic_with_thread_context(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, thread, "%s", failureStr);
12581 } else
12582 #endif /* defined(__x86_64__) */
12583 {
12584 panic_with_options(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, "%s", failureStr);
12585 }
12586 } else {
12587 gRootDomain->swd_lock = 0;
12588 return;
12589 }
12590 }
12591
12592 void
sleepWakeDebugMemAlloc()12593 IOPMrootDomain::sleepWakeDebugMemAlloc()
12594 {
12595 vm_size_t size = SWD_STACKSHOT_SIZE + SWD_COMPRESSED_BUFSIZE + SWD_ZLIB_BUFSIZE;
12596
12597 swd_hdr *hdr = NULL;
12598 void *bufPtr = NULL;
12599
12600 OSSharedPtr<IOBufferMemoryDescriptor> memDesc;
12601
12602
12603 if (kIOSleepWakeWdogOff & gIOKitDebug) {
12604 return;
12605 }
12606
12607 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12608 return;
12609 }
12610
12611 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
12612 kernel_task, kIODirectionIn | kIOMemoryMapperNone,
12613 size);
12614 if (memDesc == NULL) {
12615 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
12616 goto exit;
12617 }
12618
12619 bufPtr = memDesc->getBytesNoCopy();
12620
12621 // Carve out memory for zlib routines
12622 swd_zs_zmem = (vm_offset_t)bufPtr;
12623 bufPtr = (char *)bufPtr + SWD_ZLIB_BUFSIZE;
12624
12625 // Carve out memory for compressed stackshots
12626 swd_compressed_buffer = bufPtr;
12627 bufPtr = (char *)bufPtr + SWD_COMPRESSED_BUFSIZE;
12628
12629 // Remaining is used for holding stackshot
12630 hdr = (swd_hdr *)bufPtr;
12631 memset(hdr, 0, sizeof(swd_hdr));
12632
12633 hdr->signature = SWD_HDR_SIGNATURE;
12634 hdr->alloc_size = SWD_STACKSHOT_SIZE;
12635
12636 hdr->spindump_offset = sizeof(swd_hdr);
12637 swd_buffer = (void *)hdr;
12638 swd_memDesc = os::move(memDesc);
12639 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
12640
12641 exit:
12642 gRootDomain->swd_lock = 0;
12643 }
12644
12645 void
sleepWakeDebugSpinDumpMemAlloc()12646 IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc()
12647 {
12648 #if UNUSED
12649 vm_size_t size = SWD_SPINDUMP_SIZE;
12650
12651 swd_hdr *hdr = NULL;
12652
12653 OSSharedPtr<IOBufferMemoryDescriptor> memDesc;
12654
12655 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12656 return;
12657 }
12658
12659 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
12660 kernel_task, kIODirectionIn | kIOMemoryMapperNone,
12661 SWD_SPINDUMP_SIZE);
12662
12663 if (memDesc == NULL) {
12664 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
12665 goto exit;
12666 }
12667
12668
12669 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
12670 memset(hdr, 0, sizeof(swd_hdr));
12671
12672 hdr->signature = SWD_HDR_SIGNATURE;
12673 hdr->alloc_size = size;
12674
12675 hdr->spindump_offset = sizeof(swd_hdr);
12676 swd_spindump_buffer = (void *)hdr;
12677 swd_spindump_memDesc = os::move(memDesc);
12678
12679 exit:
12680 gRootDomain->swd_lock = 0;
12681 #endif /* UNUSED */
12682 }
12683
12684 void
sleepWakeDebugEnableWdog()12685 IOPMrootDomain::sleepWakeDebugEnableWdog()
12686 {
12687 }
12688
12689 bool
sleepWakeDebugIsWdogEnabled()12690 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12691 {
12692 return !systemBooting && !systemShutdown && !gWillShutdown;
12693 }
12694
12695 void
sleepWakeDebugSaveSpinDumpFile()12696 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12697 {
12698 swd_hdr *hdr = NULL;
12699 errno_t error = EIO;
12700
12701 if (swd_spindump_buffer && gSpinDumpBufferFull) {
12702 hdr = (swd_hdr *)swd_spindump_buffer;
12703
12704 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
12705 (char*)hdr + hdr->spindump_offset, hdr->spindump_size);
12706
12707 if (error) {
12708 return;
12709 }
12710
12711 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
12712 (char*)hdr + offsetof(swd_hdr, UUID),
12713 sizeof(swd_hdr) - offsetof(swd_hdr, UUID));
12714
12715 gSpinDumpBufferFull = false;
12716 }
12717 }
12718
12719 errno_t
sleepWakeDebugSaveFile(const char * name,char * buf,int len)12720 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
12721 {
12722 struct vnode *vp = NULL;
12723 vfs_context_t ctx = vfs_context_create(vfs_context_current());
12724 kauth_cred_t cred = vfs_context_ucred(ctx);
12725 struct vnode_attr va;
12726 errno_t error = EIO;
12727
12728 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
12729 S_IRUSR | S_IRGRP | S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0) {
12730 LOG("Failed to open the file %s\n", name);
12731 swd_flags |= SWD_FILEOP_ERROR;
12732 goto exit;
12733 }
12734 VATTR_INIT(&va);
12735 VATTR_WANTED(&va, va_nlink);
12736 /* Don't dump to non-regular files or files with links. */
12737 if (vp->v_type != VREG ||
12738 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
12739 LOG("Bailing as this is not a regular file\n");
12740 swd_flags |= SWD_FILEOP_ERROR;
12741 goto exit;
12742 }
12743 VATTR_INIT(&va);
12744 VATTR_SET(&va, va_data_size, 0);
12745 vnode_setattr(vp, &va, ctx);
12746
12747
12748 if (buf != NULL) {
12749 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
12750 UIO_SYSSPACE, IO_NODELOCKED | IO_UNIT, cred, (int *) NULL, vfs_context_proc(ctx));
12751 if (error != 0) {
12752 LOG("Failed to save sleep wake log. err 0x%x\n", error);
12753 swd_flags |= SWD_FILEOP_ERROR;
12754 } else {
12755 DLOG("Saved %d bytes to file %s\n", len, name);
12756 }
12757 }
12758
12759 exit:
12760 if (vp) {
12761 vnode_close(vp, FWRITE, ctx);
12762 }
12763 if (ctx) {
12764 vfs_context_rele(ctx);
12765 }
12766
12767 return error;
12768 }
12769
12770 #else /* defined(__i386__) || defined(__x86_64__) */
12771
12772 void
sleepWakeDebugTrig(bool restart)12773 IOPMrootDomain::sleepWakeDebugTrig(bool restart)
12774 {
12775 if (restart) {
12776 if (gSwdPanic == 0) {
12777 return;
12778 }
12779 panic("Sleep/Wake hang detected");
12780 return;
12781 }
12782 }
12783
12784 void
takeStackshot(bool restart)12785 IOPMrootDomain::takeStackshot(bool restart)
12786 {
12787 #pragma unused(restart)
12788 }
12789
12790 void
deleteStackshot()12791 IOPMrootDomain::deleteStackshot()
12792 {
12793 }
12794
12795 void
sleepWakeDebugMemAlloc()12796 IOPMrootDomain::sleepWakeDebugMemAlloc()
12797 {
12798 }
12799
12800 void
saveFailureData2File()12801 IOPMrootDomain::saveFailureData2File()
12802 {
12803 }
12804
12805 void
sleepWakeDebugEnableWdog()12806 IOPMrootDomain::sleepWakeDebugEnableWdog()
12807 {
12808 }
12809
12810 bool
sleepWakeDebugIsWdogEnabled()12811 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12812 {
12813 return false;
12814 }
12815
12816 void
sleepWakeDebugSaveSpinDumpFile()12817 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12818 {
12819 }
12820
12821 errno_t
sleepWakeDebugSaveFile(const char * name,char * buf,int len)12822 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
12823 {
12824 return 0;
12825 }
12826
12827 #endif /* defined(__i386__) || defined(__x86_64__) */
12828
12829