]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPMrootDomain.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
CommitLineData
91447636 1/*
f427ee49 2 * Copyright (c) 1998-2020 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
f427ee49
A
28
29#define IOKIT_ENABLE_SHARED_PTR
30
b0d623f7
A
31#include <libkern/c++/OSKext.h>
32#include <libkern/c++/OSMetaClass.h>
6d2010ae 33#include <libkern/OSAtomic.h>
0b4c1975 34#include <libkern/OSDebug.h>
1c79356b 35#include <IOKit/IOWorkLoop.h>
9bccf70c 36#include <IOKit/IOCommandGate.h>
cb323159 37#include <IOKit/IOTimerEventSource.h>
1c79356b 38#include <IOKit/IOPlatformExpert.h>
fe8ab488 39#include <IOKit/IOCPU.h>
f427ee49 40#include <IOKit/IOPlatformActions.h>
9bccf70c
A
41#include <IOKit/IOKitDebug.h>
42#include <IOKit/IOTimeStamp.h>
b0d623f7 43#include <IOKit/pwr_mgt/IOPMlog.h>
1c79356b 44#include <IOKit/pwr_mgt/RootDomain.h>
d52fe63f 45#include <IOKit/pwr_mgt/IOPMPrivate.h>
91447636 46#include <IOKit/IODeviceTreeSupport.h>
1c79356b 47#include <IOKit/IOMessage.h>
0c530ab8 48#include <IOKit/IOReturn.h>
39236c6e 49#include <IOKit/IONVRAM.h>
1c79356b 50#include "RootDomainUserClient.h"
0b4e3aa0 51#include "IOKit/pwr_mgt/IOPowerConnection.h"
55e303ae 52#include "IOPMPowerStateQueue.h"
91447636 53#include <IOKit/IOCatalogue.h>
39236c6e 54#include <IOKit/IOReportMacros.h>
cb323159
A
55#include <IOKit/IOLib.h>
56#include <IOKit/IOKitKeys.h>
c3c9b80d 57#include <IOKit/IOUserServer.h>
3e170ce0 58#include "IOKitKernelInternal.h"
2d21ac55 59#if HIBERNATION
3a60a9f5 60#include <IOKit/IOHibernatePrivate.h>
f427ee49 61#endif /* HIBERNATION */
13f56ec4 62#include <console/video_console.h>
2d21ac55
A
63#include <sys/syslog.h>
64#include <sys/sysctl.h>
39236c6e
A
65#include <sys/vnode.h>
66#include <sys/vnode_internal.h>
67#include <sys/fcntl.h>
5ba3f43e
A
68#include <os/log.h>
69#include <pexpert/protos.h>
d9a64523 70#include <AssertMacros.h>
39236c6e 71
2d21ac55 72#include <sys/time.h>
fe8ab488 73#include "IOServicePrivate.h" // _IOServiceInterestNotifier
b0d623f7 74#include "IOServicePMPrivate.h"
2d21ac55 75
d9a64523 76#include <libkern/zlib.h>
f427ee49
A
77#include <os/cpp_util.h>
78#include <libkern/c++/OSBoundedArrayRef.h>
d9a64523 79
b0d623f7
A
80__BEGIN_DECLS
81#include <mach/shared_region.h>
3e170ce0 82#include <kern/clock.h>
b0d623f7 83__END_DECLS
2d21ac55 84
b0d623f7 85#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
86__BEGIN_DECLS
87#include "IOPMrootDomainInternal.h"
0a7de745 88const char *processor_to_datastring(const char *prefix, processor_t target_processor);
2d21ac55
A
89__END_DECLS
90#endif
91
b0d623f7 92#define kIOPMrootDomainClass "IOPMrootDomain"
6d2010ae 93#define LOG_PREFIX "PMRD: "
b0d623f7 94
39236c6e 95
6d2010ae
A
96#define MSG(x...) \
97 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
b0d623f7 98
6d2010ae
A
99#define LOG(x...) \
100 do { kprintf(LOG_PREFIX x); } while (false)
b0d623f7 101
cb323159
A
102#if DEVELOPMENT || DEBUG
103#define DEBUG_LOG(x...) do { \
fe8ab488 104 if (kIOLogPMRootDomain & gIOKitDebug) \
cb323159
A
105 kprintf(LOG_PREFIX x); \
106 os_log_debug(OS_LOG_DEFAULT, LOG_PREFIX x); \
fe8ab488 107} while (false)
5ba3f43e 108#else
cb323159
A
109#define DEBUG_LOG(x...)
110#endif
111
5ba3f43e
A
112#define DLOG(x...) do { \
113 if (kIOLogPMRootDomain & gIOKitDebug) \
0a7de745 114 kprintf(LOG_PREFIX x); \
cb323159
A
115 else \
116 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
5ba3f43e 117} while (false)
fe8ab488
A
118
119#define DMSG(x...) do { \
120 if (kIOLogPMRootDomain & gIOKitDebug) { \
0a7de745 121 kprintf(LOG_PREFIX x); \
fe8ab488
A
122 } \
123} while (false)
b0d623f7 124
6d2010ae 125
fe8ab488 126#define _LOG(x...)
316670eb 127
b0d623f7
A
128#define CHECK_THREAD_CONTEXT
129#ifdef CHECK_THREAD_CONTEXT
cb323159 130static IOWorkLoop * gIOPMWorkLoop = NULL;
6d2010ae 131#define ASSERT_GATED() \
b0d623f7
A
132do { \
133 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
0a7de745 134 panic("RootDomain: not inside PM gate"); \
b0d623f7
A
135 } \
136} while(false)
2d21ac55 137#else
6d2010ae 138#define ASSERT_GATED()
b0d623f7
A
139#endif /* CHECK_THREAD_CONTEXT */
140
6d2010ae 141#define CAP_LOSS(c) \
0a7de745
A
142 (((_pendingCapability & (c)) == 0) && \
143 ((_currentCapability & (c)) != 0))
6d2010ae
A
144
145#define CAP_GAIN(c) \
0a7de745
A
146 (((_currentCapability & (c)) == 0) && \
147 ((_pendingCapability & (c)) != 0))
6d2010ae
A
148
149#define CAP_CHANGE(c) \
0a7de745 150 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
6d2010ae
A
151
152#define CAP_CURRENT(c) \
0a7de745 153 ((_currentCapability & (c)) != 0)
6d2010ae
A
154
155#define CAP_HIGHEST(c) \
0a7de745 156 ((_highestCapability & (c)) != 0)
6d2010ae 157
f427ee49
A
158#define CAP_PENDING(c) \
159 ((_pendingCapability & (c)) != 0)
160
161// rdar://problem/9157444
39236c6e 162#if defined(__i386__) || defined(__x86_64__)
f427ee49 163#define DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY 20
39236c6e 164#endif
6d2010ae 165
b0d623f7
A
166// Event types for IOPMPowerStateQueue::submitPowerEvent()
167enum {
f427ee49
A
168 kPowerEventFeatureChanged = 1, // 1
169 kPowerEventReceivedPowerNotification, // 2
170 kPowerEventSystemBootCompleted, // 3
171 kPowerEventSystemShutdown, // 4
172 kPowerEventUserDisabledSleep, // 5
0a7de745
A
173 kPowerEventRegisterSystemCapabilityClient, // 6
174 kPowerEventRegisterKernelCapabilityClient, // 7
f427ee49
A
175 kPowerEventPolicyStimulus, // 8
176 kPowerEventAssertionCreate, // 9
177 kPowerEventAssertionRelease, // 10
178 kPowerEventAssertionSetLevel, // 11
179 kPowerEventQueueSleepWakeUUID, // 12
180 kPowerEventPublishSleepWakeUUID, // 13
181 kPowerEventSetDisplayPowerOn, // 14
182 kPowerEventPublishWakeType, // 15
183 kPowerEventAOTEvaluate // 16
6d2010ae
A
184};
185
186// For evaluatePolicy()
187// List of stimuli that affects the root domain policy.
188enum {
f427ee49
A
189 kStimulusDisplayWranglerSleep, // 0
190 kStimulusDisplayWranglerWake, // 1
191 kStimulusAggressivenessChanged, // 2
192 kStimulusDemandSystemSleep, // 3
193 kStimulusAllowSystemSleepChanged, // 4
194 kStimulusDarkWakeActivityTickle, // 5
195 kStimulusDarkWakeEntry, // 6
196 kStimulusDarkWakeReentry, // 7
197 kStimulusDarkWakeEvaluate, // 8
198 kStimulusNoIdleSleepPreventers, // 9
199 kStimulusEnterUserActiveState, // 10
200 kStimulusLeaveUserActiveState // 11
201};
202
203// Internal power state change reasons
204// Must be less than kIOPMSleepReasonClamshell=101
205enum {
206 kCPSReasonNone = 0, // 0
207 kCPSReasonInit, // 1
208 kCPSReasonWake, // 2
209 kCPSReasonIdleSleepPrevent, // 3
210 kCPSReasonIdleSleepAllow, // 4
211 kCPSReasonPowerOverride, // 5
212 kCPSReasonPowerDownCancel, // 6
213 kCPSReasonAOTExit, // 7
214 kCPSReasonAdjustPowerState, // 8
215 kCPSReasonDarkWakeCannotSleep, // 9
216 kCPSReasonIdleSleepEnabled, // 10
217 kCPSReasonEvaluatePolicy, // 11
218 kCPSReasonSustainFullWake, // 12
219 kCPSReasonPMInternals = (kIOPMSleepReasonClamshell - 1)
b0d623f7 220};
1c79356b 221
0c530ab8 222extern "C" {
b0d623f7 223IOReturn OSKextSystemSleepOrWake( UInt32 );
0c530ab8 224}
fe8ab488
A
225extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
226extern "C" addr64_t kvtophys(vm_offset_t va);
d9a64523 227extern "C" boolean_t kdp_has_polled_corefile();
1c79356b 228
b0d623f7 229static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
3e170ce0 230static void notifySystemShutdown( IOService * root, uint32_t messageType );
6d2010ae 231static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
0b4c1975 232static void pmEventTimeStamp(uint64_t *recordTS);
cb323159
A
233static void powerButtonUpCallout( thread_call_param_t, thread_call_param_t );
234static void powerButtonDownCallout( thread_call_param_t, thread_call_param_t );
f427ee49 235static OSPtr<const OSSymbol> copyKextIdentifierWithAddress(vm_address_t address);
cb323159 236
f427ee49
A
237static int IOPMConvertSecondsToCalendar(clock_sec_t secs, IOPMCalendarStruct * dt);
238static clock_sec_t IOPMConvertCalendarToSeconds(const IOPMCalendarStruct * dt);
cb323159
A
239#define YMDTF "%04d/%02d/%d %02d:%02d:%02d"
240#define YMDT(cal) ((int)(cal)->year), (cal)->month, (cal)->day, (cal)->hour, (cal)->minute, (cal)->second
1c79356b 241
0c530ab8 242// "IOPMSetSleepSupported" callPlatformFunction name
f427ee49
A
243static OSSharedPtr<const OSSymbol> sleepSupportedPEFunction;
244static OSSharedPtr<const OSSymbol> sleepMessagePEFunction;
245static OSSharedPtr<const OSSymbol> gIOPMWakeTypeUserKey;
246
247static OSSharedPtr<const OSSymbol> gIOPMPSExternalConnectedKey;
248static OSSharedPtr<const OSSymbol> gIOPMPSExternalChargeCapableKey;
249static OSSharedPtr<const OSSymbol> gIOPMPSBatteryInstalledKey;
250static OSSharedPtr<const OSSymbol> gIOPMPSIsChargingKey;
251static OSSharedPtr<const OSSymbol> gIOPMPSAtWarnLevelKey;
252static OSSharedPtr<const OSSymbol> gIOPMPSAtCriticalLevelKey;
253static OSSharedPtr<const OSSymbol> gIOPMPSCurrentCapacityKey;
254static OSSharedPtr<const OSSymbol> gIOPMPSMaxCapacityKey;
255static OSSharedPtr<const OSSymbol> gIOPMPSDesignCapacityKey;
256static OSSharedPtr<const OSSymbol> gIOPMPSTimeRemainingKey;
257static OSSharedPtr<const OSSymbol> gIOPMPSAmperageKey;
258static OSSharedPtr<const OSSymbol> gIOPMPSVoltageKey;
259static OSSharedPtr<const OSSymbol> gIOPMPSCycleCountKey;
260static OSSharedPtr<const OSSymbol> gIOPMPSMaxErrKey;
261static OSSharedPtr<const OSSymbol> gIOPMPSAdapterInfoKey;
262static OSSharedPtr<const OSSymbol> gIOPMPSLocationKey;
263static OSSharedPtr<const OSSymbol> gIOPMPSErrorConditionKey;
264static OSSharedPtr<const OSSymbol> gIOPMPSManufacturerKey;
265static OSSharedPtr<const OSSymbol> gIOPMPSManufactureDateKey;
266static OSSharedPtr<const OSSymbol> gIOPMPSModelKey;
267static OSSharedPtr<const OSSymbol> gIOPMPSSerialKey;
268static OSSharedPtr<const OSSymbol> gIOPMPSLegacyBatteryInfoKey;
269static OSSharedPtr<const OSSymbol> gIOPMPSBatteryHealthKey;
270static OSSharedPtr<const OSSymbol> gIOPMPSHealthConfidenceKey;
271static OSSharedPtr<const OSSymbol> gIOPMPSCapacityEstimatedKey;
272static OSSharedPtr<const OSSymbol> gIOPMPSBatteryChargeStatusKey;
273static OSSharedPtr<const OSSymbol> gIOPMPSBatteryTemperatureKey;
274static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsKey;
275static OSSharedPtr<const OSSymbol> gIOPMPSChargerConfigurationKey;
276static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsIDKey;
277static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsWattsKey;
278static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsRevisionKey;
279static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSerialNumberKey;
280static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsFamilyKey;
281static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsAmperageKey;
282static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsDescriptionKey;
283static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsPMUConfigurationKey;
284static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSourceIDKey;
285static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsErrorFlagsKey;
286static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsSharedSourceKey;
287static OSSharedPtr<const OSSymbol> gIOPMPSAdapterDetailsCloakedKey;
288static OSSharedPtr<const OSSymbol> gIOPMPSInvalidWakeSecondsKey;
289static OSSharedPtr<const OSSymbol> gIOPMPSPostChargeWaitSecondsKey;
290static OSSharedPtr<const OSSymbol> gIOPMPSPostDishargeWaitSecondsKey;
e8c3f781 291
6d2010ae
A
292#define kIOSleepSupportedKey "IOSleepSupported"
293#define kIOPMSystemCapabilitiesKey "System Capabilities"
f427ee49 294#define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict"
0c530ab8 295
39236c6e 296#define kIORequestWranglerIdleKey "IORequestIdle"
5ba3f43e 297#define kDefaultWranglerIdlePeriod 1000 // in milliseconds
39236c6e 298
d9a64523 299#define kIOSleepWakeFailureString "SleepWakeFailureString"
39037602 300#define kIOEFIBootRomFailureKey "wake-failure"
cb323159 301#define kIOSleepWakeFailurePanic "SleepWakeFailurePanic"
39236c6e 302
0c530ab8 303#define kRD_AllPowerSources (kIOPMSupportedOnAC \
0a7de745
A
304 | kIOPMSupportedOnBatt \
305 | kIOPMSupportedOnUPS)
1c79356b 306
99c3a104
A
307#define kLocalEvalClamshellCommand (1 << 15)
308#define kIdleSleepRetryInterval (3 * 60)
0c530ab8 309
f427ee49
A
310#define DISPLAY_WRANGLER_PRESENT (!NO_KERNEL_HID)
311
39236c6e 312enum {
0a7de745
A
313 kWranglerPowerStateMin = 0,
314 kWranglerPowerStateSleep = 2,
315 kWranglerPowerStateDim = 3,
316 kWranglerPowerStateMax = 4
39236c6e
A
317};
318
b0d623f7 319enum {
0a7de745
A
320 OFF_STATE = 0,
321 RESTART_STATE = 1,
322 SLEEP_STATE = 2,
cb323159
A
323 AOT_STATE = 3,
324 ON_STATE = 4,
0a7de745 325 NUM_POWER_STATES
b0d623f7
A
326};
327
cb323159
A
328const char *
329getPowerStateString( uint32_t state )
330{
331#define POWER_STATE(x) {(uint32_t) x, #x}
332
333 static const IONamedValue powerStates[] = {
334 POWER_STATE( OFF_STATE ),
335 POWER_STATE( RESTART_STATE ),
336 POWER_STATE( SLEEP_STATE ),
337 POWER_STATE( AOT_STATE ),
338 POWER_STATE( ON_STATE ),
339 { 0, NULL }
340 };
341 return IOFindNameForValue(state, powerStates);
342}
343
b0d623f7
A
344#define ON_POWER kIOPMPowerOn
345#define RESTART_POWER kIOPMRestart
346#define SLEEP_POWER kIOPMAuxPowerOn
b0d623f7 347
cb323159
A
348static IOPMPowerState
349 ourPowerStates[NUM_POWER_STATES] =
350{
351 { .version = 1,
352 .capabilityFlags = 0,
353 .outputPowerCharacter = 0,
354 .inputPowerRequirement = 0 },
355 { .version = 1,
356 .capabilityFlags = kIOPMRestartCapability,
357 .outputPowerCharacter = kIOPMRestart,
358 .inputPowerRequirement = RESTART_POWER },
359 { .version = 1,
360 .capabilityFlags = kIOPMSleepCapability,
361 .outputPowerCharacter = kIOPMSleep,
362 .inputPowerRequirement = SLEEP_POWER },
363 { .version = 1,
cb323159
A
364 .capabilityFlags = kIOPMAOTCapability,
365 .outputPowerCharacter = kIOPMAOTPower,
366 .inputPowerRequirement = ON_POWER },
cb323159
A
367 { .version = 1,
368 .capabilityFlags = kIOPMPowerOn,
369 .outputPowerCharacter = kIOPMPowerOn,
370 .inputPowerRequirement = ON_POWER },
b0d623f7
A
371};
372
fe8ab488
A
373#define kIOPMRootDomainWakeTypeSleepService "SleepService"
374#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
375#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
376#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
377#define kIOPMRootDomainWakeTypeUser "User"
378#define kIOPMRootDomainWakeTypeAlarm "Alarm"
379#define kIOPMRootDomainWakeTypeNetwork "Network"
380#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
381#define kIOPMRootDomainWakeTypeNotification "Notification"
382#define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
b0d623f7
A
383
384// Special interest that entitles the interested client from receiving
6d2010ae 385// all system messages. Only used by powerd.
b0d623f7 386//
6d2010ae 387#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
b0d623f7 388
cb323159
A
389// Entitlement required for root domain clients
390#define kRootDomainEntitlementSetProperty "com.apple.private.iokit.rootdomain-set-property"
391
fe8ab488
A
392#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
393#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
316670eb 394
b0d623f7
A
395/*
396 * Aggressiveness
397 */
398#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
399#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
400
401#define kAggressivesMinValue 1
402
cb323159
A
403const char *
404getAggressivenessTypeString( uint32_t type )
405{
406#define AGGRESSIVENESS_TYPE(x) {(uint32_t) x, #x}
407
408 static const IONamedValue aggressivenessTypes[] = {
409 AGGRESSIVENESS_TYPE( kPMGeneralAggressiveness ),
410 AGGRESSIVENESS_TYPE( kPMMinutesToDim ),
411 AGGRESSIVENESS_TYPE( kPMMinutesToSpinDown ),
412 AGGRESSIVENESS_TYPE( kPMMinutesToSleep ),
413 AGGRESSIVENESS_TYPE( kPMEthernetWakeOnLANSettings ),
414 AGGRESSIVENESS_TYPE( kPMSetProcessorSpeed ),
415 AGGRESSIVENESS_TYPE( kPMPowerSource),
416 AGGRESSIVENESS_TYPE( kPMMotionSensor ),
417 AGGRESSIVENESS_TYPE( kPMLastAggressivenessType ),
418 { 0, NULL }
419 };
420 return IOFindNameForValue(type, aggressivenessTypes);
421}
422
b0d623f7 423enum {
0a7de745
A
424 kAggressivesStateBusy = 0x01,
425 kAggressivesStateQuickSpindown = 0x02
b0d623f7
A
426};
427
428struct AggressivesRecord {
0a7de745
A
429 uint32_t flags;
430 uint32_t type;
431 uint32_t value;
b0d623f7
A
432};
433
434struct AggressivesRequest {
0a7de745
A
435 queue_chain_t chain;
436 uint32_t options;
437 uint32_t dataType;
438 union {
f427ee49
A
439 OSSharedPtr<IOService> service;
440 AggressivesRecord record;
0a7de745 441 } data;
b0d623f7
A
442};
443
444enum {
0a7de745
A
445 kAggressivesRequestTypeService = 1,
446 kAggressivesRequestTypeRecord
b0d623f7
A
447};
448
449enum {
0a7de745
A
450 kAggressivesOptionSynchronous = 0x00000001,
451 kAggressivesOptionQuickSpindownEnable = 0x00000100,
452 kAggressivesOptionQuickSpindownDisable = 0x00000200,
453 kAggressivesOptionQuickSpindownMask = 0x00000300
b0d623f7
A
454};
455
456enum {
0a7de745
A
457 kAggressivesRecordFlagModified = 0x00000001,
458 kAggressivesRecordFlagMinValue = 0x00000002
6d2010ae
A
459};
460
cb323159
A
461// System Sleep Preventers
462
463enum {
464 kPMUserDisabledAllSleep = 1,
465 kPMSystemRestartBootingInProgress,
466 kPMConfigPreventSystemSleep,
467 kPMChildPreventSystemSleep,
468 kPMCPUAssertion,
469 kPMPCIUnsupported,
470};
471
472const char *
473getSystemSleepPreventerString( uint32_t preventer )
474{
475#define SYSTEM_SLEEP_PREVENTER(x) {(int) x, #x}
476 static const IONamedValue systemSleepPreventers[] = {
477 SYSTEM_SLEEP_PREVENTER( kPMUserDisabledAllSleep ),
478 SYSTEM_SLEEP_PREVENTER( kPMSystemRestartBootingInProgress ),
479 SYSTEM_SLEEP_PREVENTER( kPMConfigPreventSystemSleep ),
480 SYSTEM_SLEEP_PREVENTER( kPMChildPreventSystemSleep ),
481 SYSTEM_SLEEP_PREVENTER( kPMCPUAssertion ),
482 SYSTEM_SLEEP_PREVENTER( kPMPCIUnsupported ),
483 { 0, NULL }
484 };
485 return IOFindNameForValue(preventer, systemSleepPreventers);
486}
487
6d2010ae
A
488// gDarkWakeFlags
489enum {
f427ee49
A
490 kDarkWakeFlagPromotionNone = 0x0000,
491 kDarkWakeFlagPromotionEarly = 0x0001, // promote before gfx clamp
492 kDarkWakeFlagPromotionLate = 0x0002, // promote after gfx clamp
493 kDarkWakeFlagPromotionMask = 0x0003,
0a7de745 494 kDarkWakeFlagAlarmIsDark = 0x0100,
f427ee49
A
495 kDarkWakeFlagAudioNotSuppressed = 0x0200,
496 kDarkWakeFlagUserWakeWorkaround = 0x1000
497};
498
499// gClamshellFlags
500// The workaround for 9157444 is enabled at compile time using the
501// DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY macro and is not represented below.
502enum {
503 kClamshell_WAR_38378787 = 0x00000001,
504 kClamshell_WAR_47715679 = 0x00000002,
505 kClamshell_WAR_58009435 = 0x00000004
506};
507
508// acceptSystemWakeEvents()
509enum {
510 kAcceptSystemWakeEvents_Disable = 0,
511 kAcceptSystemWakeEvents_Enable,
512 kAcceptSystemWakeEvents_Reenable
1c79356b
A
513};
514
6601e61a 515static IOPMrootDomain * gRootDomain;
f427ee49 516static IORootParent * gPatriarch;
cb323159 517static IONotifier * gSysPowerDownNotifier = NULL;
6601e61a 518static UInt32 gSleepOrShutdownPending = 0;
b0d623f7 519static UInt32 gWillShutdown = 0;
6d2010ae 520static UInt32 gPagingOff = 0;
b0d623f7 521static UInt32 gSleepWakeUUIDIsSet = false;
6d2010ae 522static uint32_t gAggressivesState = 0;
c3c9b80d
A
523uint32_t gHaltTimeMaxLog;
524uint32_t gHaltTimeMaxPanic;
5ba3f43e
A
525IOLock * gHaltLogLock;
526static char * gHaltLog;
527enum { kHaltLogSize = 2048 };
528static size_t gHaltLogPos;
529static uint64_t gHaltStartTime;
f427ee49
A
530static char gKextNameBuf[64];
531static size_t gKextNamePos;
532static bool gKextNameEnd;
39236c6e
A
533
534uuid_string_t bootsessionuuid_string;
535
f427ee49
A
536#if defined(XNU_TARGET_OS_OSX)
537#if DISPLAY_WRANGLER_PRESENT
538static uint32_t gDarkWakeFlags = kDarkWakeFlagPromotionNone;
539#elif CONFIG_ARROW
540// Enable temporary full wake promotion workarounds
541static uint32_t gDarkWakeFlags = kDarkWakeFlagUserWakeWorkaround;
542#else
543// Enable full wake promotion workarounds
544static uint32_t gDarkWakeFlags = kDarkWakeFlagUserWakeWorkaround;
545#endif
546#else /* !defined(XNU_TARGET_OS_OSX) */
547static uint32_t gDarkWakeFlags = kDarkWakeFlagPromotionEarly;
548#endif /* !defined(XNU_TARGET_OS_OSX) */
549
3e170ce0 550static uint32_t gNoIdleFlag = 0;
cb323159 551static uint32_t gSwdPanic = 1;
d9a64523
A
552static uint32_t gSwdSleepTimeout = 0;
553static uint32_t gSwdWakeTimeout = 0;
554static uint32_t gSwdSleepWakeTimeout = 0;
316670eb 555static PMStatsStruct gPMStats;
cb323159
A
556#if DEVELOPMENT || DEBUG
557static uint32_t swd_panic_phase;
558#endif
4452a7af 559
f427ee49
A
560static uint32_t gClamshellFlags = 0
561#if defined(__i386__) || defined(__x86_64__)
562 | kClamshell_WAR_58009435
563#endif
564;
d9a64523 565
99c3a104 566#if HIBERNATION
f427ee49
A
567
568#if defined(__arm64__)
569static IOReturn
570defaultSleepPolicyHandler(void *ctx, const IOPMSystemSleepPolicyVariables *vars, IOPMSystemSleepParameters *params)
571{
572 uint32_t sleepType = kIOPMSleepTypeDeepIdle;
573
574 assert(vars->signature == kIOPMSystemSleepPolicySignature);
575 assert(vars->version == kIOPMSystemSleepPolicyVersion);
576
577 // Hibernation enabled and either user forced hibernate or low battery sleep
578 if ((vars->hibernateMode & kIOHibernateModeOn) &&
f427ee49
A
579 (((vars->hibernateMode & kIOHibernateModeSleep) == 0) ||
580 (vars->sleepFactors & kIOPMSleepFactorBatteryLow))) {
581 sleepType = kIOPMSleepTypeHibernate;
582 }
583 params->version = kIOPMSystemSleepParametersVersion;
584 params->sleepType = sleepType;
585 return kIOReturnSuccess;
586}
587static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = &defaultSleepPolicyHandler;
588#else /* defined(__arm64__) */
cb323159 589static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = NULL;
f427ee49
A
590#endif /* defined(__arm64__) */
591
cb323159 592static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = NULL;
99c3a104
A
593static void * gSleepPolicyTarget;
594#endif
595
2d21ac55
A
596struct timeval gIOLastSleepTime;
597struct timeval gIOLastWakeTime;
f427ee49
A
598AbsoluteTime gIOLastWakeAbsTime;
599AbsoluteTime gIOLastSleepAbsTime;
2d21ac55 600
cb323159
A
601struct timeval gIOLastUserSleepTime;
602
fe8ab488 603static char gWakeReasonString[128];
f427ee49
A
604static char gBootReasonString[80];
605static char gShutdownReasonString[80];
fe8ab488 606static bool gWakeReasonSysctlRegistered = false;
f427ee49
A
607static bool gBootReasonSysctlRegistered = false;
608static bool gShutdownReasonSysctlRegistered = false;
c3c9b80d 609static bool gWillShutdownSysctlRegistered = false;
d9a64523
A
610static AbsoluteTime gUserActiveAbsTime;
611static AbsoluteTime gUserInactiveAbsTime;
fe8ab488 612
f427ee49 613#if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
3e170ce0
A
614static bool gSpinDumpBufferFull = false;
615#endif
616
d9a64523
A
617z_stream swd_zs;
618vm_offset_t swd_zs_zmem;
619//size_t swd_zs_zsize;
620size_t swd_zs_zoffset;
0a7de745
A
621#if defined(__i386__) || defined(__x86_64__)
622IOCPU *currentShutdownTarget = NULL;
623#endif
d9a64523 624
3e170ce0
A
625static unsigned int gPMHaltBusyCount;
626static unsigned int gPMHaltIdleCount;
627static int gPMHaltDepth;
628static uint32_t gPMHaltMessageType;
cb323159 629static IOLock * gPMHaltLock = NULL;
f427ee49
A
630static OSSharedPtr<OSArray> gPMHaltArray;
631static OSSharedPtr<const OSSymbol> gPMHaltClientAcknowledgeKey;
3e170ce0
A
632static bool gPMQuiesced;
633
2d21ac55
A
634// Constants used as arguments to IOPMrootDomain::informCPUStateChange
635#define kCPUUnknownIndex 9999999
636enum {
0a7de745
A
637 kInformAC = 0,
638 kInformLid = 1,
639 kInformableCount = 2
2d21ac55 640};
4452a7af 641
f427ee49
A
642OSSharedPtr<const OSSymbol> gIOPMStatsResponseTimedOut;
643OSSharedPtr<const OSSymbol> gIOPMStatsResponseCancel;
644OSSharedPtr<const OSSymbol> gIOPMStatsResponseSlow;
645OSSharedPtr<const OSSymbol> gIOPMStatsResponsePrompt;
646OSSharedPtr<const OSSymbol> gIOPMStatsDriverPSChangeSlow;
b0d623f7 647
7ddcb079
A
648#define kBadPMFeatureID 0
649
6d2010ae
A
650/*
651 * PMSettingHandle
652 * Opaque handle passed to clients of registerPMSettingController()
653 */
654class PMSettingHandle : public OSObject
655{
cb323159 656 OSDeclareFinalStructors( PMSettingHandle );
0a7de745 657 friend class PMSettingObject;
6d2010ae
A
658
659private:
0a7de745
A
660 PMSettingObject *pmso;
661 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae
A
662};
663
664/*
665 * PMSettingObject
666 * Internal object to track each PM setting controller
667 */
0c530ab8
A
668class PMSettingObject : public OSObject
669{
cb323159 670 OSDeclareFinalStructors( PMSettingObject );
0a7de745 671 friend class IOPMrootDomain;
6d2010ae 672
0c530ab8 673private:
0a7de745
A
674 queue_head_t calloutQueue;
675 thread_t waitThread;
676 IOPMrootDomain *parent;
677 PMSettingHandle *pmsh;
678 IOPMSettingControllerCallback func;
679 OSObject *target;
680 uintptr_t refcon;
681 uint32_t *publishedFeatureID;
682 uint32_t settingCount;
683 bool disabled;
684
685 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae 686
0c530ab8 687public:
0a7de745
A
688 static PMSettingObject *pmSettingObject(
689 IOPMrootDomain *parent_arg,
690 IOPMSettingControllerCallback handler_arg,
691 OSObject *target_arg,
692 uintptr_t refcon_arg,
693 uint32_t supportedPowerSources,
694 const OSSymbol *settings[],
695 OSObject **handle_obj);
696
f427ee49 697 IOReturn dispatchPMSetting(const OSSymbol *type, OSObject *object);
0a7de745 698 void clientHandleFreed(void);
6d2010ae
A
699};
700
701struct PMSettingCallEntry {
0a7de745
A
702 queue_chain_t link;
703 thread_t thread;
6d2010ae 704};
0c530ab8 705
6d2010ae
A
706#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
707#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
708#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
709#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
0c530ab8 710
6d2010ae
A
711/*
712 * PMTraceWorker
713 * Internal helper object for logging trace points to RTC
714 * IOPMrootDomain and only IOPMrootDomain should instantiate
715 * exactly one of these.
716 */
717
718typedef void (*IOPMTracePointHandler)(
0a7de745 719 void * target, uint32_t code, uint32_t data );
6d2010ae
A
720
721class PMTraceWorker : public OSObject
722{
cb323159 723 OSDeclareDefaultStructors(PMTraceWorker);
6d2010ae 724public:
0a7de745
A
725 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
726
f427ee49 727 static OSPtr<PMTraceWorker> tracer( IOPMrootDomain * );
0a7de745
A
728 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
729 void tracePoint(uint8_t phase);
730 void traceDetail(uint32_t detail);
731 void traceComponentWakeProgress(uint32_t component, uint32_t data);
732 int recordTopLevelPCIDevice(IOService *);
733 void RTC_TRACE(void);
734 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
735
736 IOPMTracePointHandler tracePointHandler;
737 void * tracePointTarget;
738 uint64_t getPMStatusCode();
739 uint8_t getTracePhase();
740 uint32_t getTraceData();
6d2010ae 741private:
0a7de745
A
742 IOPMrootDomain *owner;
743 IOLock *pmTraceWorkerLock;
f427ee49 744 OSSharedPtr<OSArray> pciDeviceBitMappings;
0a7de745
A
745
746 uint8_t addedToRegistry;
747 uint8_t tracePhase;
748 uint32_t traceData32;
749 uint8_t loginWindowData;
750 uint8_t coreDisplayData;
751 uint8_t coreGraphicsData;
0c530ab8
A
752};
753
0b4c1975
A
754/*
755 * PMAssertionsTracker
756 * Tracks kernel and user space PM assertions
757 */
758class PMAssertionsTracker : public OSObject
759{
cb323159 760 OSDeclareFinalStructors(PMAssertionsTracker);
0b4c1975 761public:
0a7de745 762 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
fe8ab488 763
0a7de745
A
764 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
765 IOReturn releaseAssertion(IOPMDriverAssertionID);
766 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
767 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
0b4c1975 768
f427ee49 769 OSSharedPtr<OSArray> copyAssertionsArray(void);
0a7de745
A
770 IOPMDriverAssertionType getActivatedAssertions(void);
771 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
0b4c1975 772
0a7de745
A
773 IOReturn handleCreateAssertion(OSData *);
774 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
775 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
776 IOReturn handleSetUserAssertionLevels(void * arg0);
777 void publishProperties(void);
f427ee49 778 void reportCPUBitAccounting(void);
0b4c1975
A
779
780private:
f427ee49
A
781 /*
782 * this should be treated as POD, as it's byte-copied around
783 * and we cannot rely on d'tor firing at the right time
784 */
0a7de745
A
785 typedef struct {
786 IOPMDriverAssertionID id;
787 IOPMDriverAssertionType assertionBits;
788 uint64_t createdTime;
789 uint64_t modifiedTime;
790 const OSSymbol *ownerString;
791 IOService *ownerService;
792 uint64_t registryEntryID;
793 IOPMDriverAssertionLevel level;
f427ee49
A
794 uint64_t assertCPUStartTime;
795 uint64_t assertCPUDuration;
0a7de745
A
796 } PMAssertStruct;
797
798 uint32_t tabulateProducerCount;
799 uint32_t tabulateConsumerCount;
800
f427ee49
A
801 uint64_t maxAssertCPUDuration;
802 uint64_t maxAssertCPUEntryId;
803
0a7de745
A
804 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
805 void tabulate(void);
f427ee49 806 void updateCPUBitAccounting(PMAssertStruct * assertStruct);
0a7de745
A
807
808 IOPMrootDomain *owner;
f427ee49 809 OSSharedPtr<OSArray> assertionsArray;
0a7de745
A
810 IOLock *assertionsArrayLock;
811 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8)));/* aligned for atomic access */
812 IOPMDriverAssertionType assertionsKernel;
813 IOPMDriverAssertionType assertionsUser;
814 IOPMDriverAssertionType assertionsCombined;
0b4c1975 815};
fe8ab488 816
0b4c1975 817OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
fe8ab488 818
2d21ac55 819/*
b0d623f7 820 * PMHaltWorker
2d21ac55
A
821 * Internal helper object for Shutdown/Restart notifications.
822 */
823#define kPMHaltMaxWorkers 8
824#define kPMHaltTimeoutMS 100
825
826class PMHaltWorker : public OSObject
827{
cb323159 828 OSDeclareFinalStructors( PMHaltWorker );
2d21ac55
A
829
830public:
0a7de745
A
831 IOService * service;// service being worked on
832 AbsoluteTime startTime; // time when work started
833 int depth; // work on nubs at this PM-tree depth
834 int visits; // number of nodes visited (debug)
835 IOLock * lock;
836 bool timeout;// service took too long
837
838 static PMHaltWorker * worker( void );
839 static void main( void * arg, wait_result_t waitResult );
840 static void work( PMHaltWorker * me );
841 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
842 virtual void free( void ) APPLE_KEXT_OVERRIDE;
2d21ac55
A
843};
844
b0d623f7 845OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
0c530ab8
A
846
847
1c79356b 848#define super IOService
b0d623f7 849OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
1c79356b 850
cb323159
A
851boolean_t
852IOPMRootDomainGetWillShutdown(void)
853{
854 return gWillShutdown != 0;
855}
856
0a7de745
A
857static void
858IOPMRootDomainWillShutdown(void)
6d2010ae 859{
0a7de745 860 if (OSCompareAndSwap(0, 1, &gWillShutdown)) {
cb323159 861 IOService::willShutdown();
0a7de745
A
862 for (int i = 0; i < 100; i++) {
863 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) {
864 break;
865 }
866 IOSleep( 100 );
867 }
868 }
6d2010ae
A
869}
870
0a7de745
A
871extern "C" IONotifier *
872registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
1c79356b 873{
f427ee49 874 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref ).detach();
5ba3f43e 875}
1c79356b 876
0a7de745
A
877extern "C" IONotifier *
878registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
5ba3f43e 879{
f427ee49 880 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref ).detach();
5ba3f43e 881}
0b4e3aa0 882
0a7de745
A
883extern "C" IOReturn
884acknowledgeSleepWakeNotification(void * PMrefcon)
5ba3f43e 885{
0a7de745 886 return gRootDomain->allowPowerChange((unsigned long)PMrefcon );
5ba3f43e 887}
1c79356b 888
0a7de745
A
889extern "C" IOReturn
890vetoSleepWakeNotification(void * PMrefcon)
5ba3f43e 891{
0a7de745 892 return gRootDomain->cancelPowerChange((unsigned long)PMrefcon );
5ba3f43e 893}
fe8ab488 894
0a7de745
A
895extern "C" IOReturn
896rootDomainRestart( void )
5ba3f43e 897{
0a7de745 898 return gRootDomain->restartSystem();
5ba3f43e
A
899}
900
0a7de745
A
901extern "C" IOReturn
902rootDomainShutdown( void )
5ba3f43e 903{
0a7de745 904 return gRootDomain->shutdownSystem();
5ba3f43e
A
905}
906
0a7de745
A
907static void
908halt_log_putc(char c)
5ba3f43e 909{
0a7de745
A
910 if (gHaltLogPos >= (kHaltLogSize - 2)) {
911 return;
912 }
913 gHaltLog[gHaltLogPos++] = c;
5ba3f43e
A
914}
915
916extern "C" void
917_doprnt_log(const char *fmt,
0a7de745
A
918 va_list *argp,
919 void (*putc)(char),
920 int radix);
5ba3f43e
A
921
922static int
923halt_log(const char *fmt, ...)
924{
0a7de745 925 va_list listp;
5ba3f43e 926
0a7de745
A
927 va_start(listp, fmt);
928 _doprnt_log(fmt, &listp, &halt_log_putc, 16);
929 va_end(listp);
5ba3f43e 930
0a7de745 931 return 0;
5ba3f43e
A
932}
933
934extern "C" void
935halt_log_enter(const char * what, const void * pc, uint64_t time)
936{
0a7de745 937 uint64_t nano, millis;
5ba3f43e 938
0a7de745
A
939 if (!gHaltLog) {
940 return;
941 }
942 absolutetime_to_nanoseconds(time, &nano);
943 millis = nano / NSEC_PER_MSEC;
944 if (millis < 100) {
945 return;
946 }
5ba3f43e 947
0a7de745
A
948 IOLockLock(gHaltLogLock);
949 if (pc) {
950 halt_log("%s: %qd ms @ 0x%lx, ", what, millis, VM_KERNEL_UNSLIDE(pc));
951 OSKext::printKextsInBacktrace((vm_offset_t *) &pc, 1, &halt_log,
952 OSKext::kPrintKextsLock | OSKext::kPrintKextsUnslide | OSKext::kPrintKextsTerse);
953 } else {
954 halt_log("%s: %qd ms\n", what, millis);
955 }
5c9f4661 956
0a7de745
A
957 gHaltLog[gHaltLogPos] = 0;
958 IOLockUnlock(gHaltLogLock);
5ba3f43e 959}
fe8ab488 960
5ba3f43e
A
961extern uint32_t gFSState;
962
0a7de745
A
963extern "C" void
964IOSystemShutdownNotification(int stage)
5ba3f43e 965{
0a7de745 966 uint64_t startTime;
5ba3f43e 967
0a7de745 968 if (kIOSystemShutdownNotificationStageRootUnmount == stage) {
f427ee49 969#if defined(XNU_TARGET_OS_OSX)
0a7de745
A
970 uint64_t nano, millis;
971 startTime = mach_absolute_time();
972 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC);
973 absolutetime_to_nanoseconds(mach_absolute_time() - startTime, &nano);
974 millis = nano / NSEC_PER_MSEC;
975 if (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog)) {
976 printf("waitQuiet() for unmount %qd ms\n", millis);
977 }
f427ee49 978#endif /* defined(XNU_TARGET_OS_OSX) */
0a7de745
A
979 return;
980 }
981
c3c9b80d
A
982 if (kIOSystemShutdownNotificationTerminateDEXTs == stage) {
983 uint64_t nano, millis;
984 startTime = mach_absolute_time();
985 IOServicePH::systemHalt();
986 absolutetime_to_nanoseconds(mach_absolute_time() - startTime, &nano);
987 millis = nano / NSEC_PER_MSEC;
988 if (true || (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog))) {
989 printf("IOServicePH::systemHalt took %qd ms\n", millis);
990 }
991 return;
992 }
993
0a7de745
A
994 assert(kIOSystemShutdownNotificationStageProcessExit == stage);
995
996 IOLockLock(gHaltLogLock);
997 if (!gHaltLog) {
998 gHaltLog = IONew(char, kHaltLogSize);
999 gHaltStartTime = mach_absolute_time();
1000 if (gHaltLog) {
1001 halt_log_putc('\n');
1002 }
1003 }
1004 IOLockUnlock(gHaltLogLock);
1005
1006 startTime = mach_absolute_time();
1007 IOPMRootDomainWillShutdown();
cb323159 1008 halt_log_enter("IOPMRootDomainWillShutdown", NULL, mach_absolute_time() - startTime);
3e170ce0 1009#if HIBERNATION
0a7de745
A
1010 startTime = mach_absolute_time();
1011 IOHibernateSystemPostWake(true);
cb323159 1012 halt_log_enter("IOHibernateSystemPostWake", NULL, mach_absolute_time() - startTime);
5ba3f43e 1013#endif
0a7de745 1014 if (OSCompareAndSwap(0, 1, &gPagingOff)) {
0a7de745 1015 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
0a7de745 1016 }
1c79356b
A
1017}
1018
5ba3f43e
A
1019extern "C" int sync_internal(void);
1020
0b4e3aa0 1021/*
0a7de745
A
1022 * A device is always in the highest power state which satisfies its driver,
1023 * its policy-maker, and any power children it has, but within the constraint
1024 * of the power state provided by its parent. The driver expresses its desire by
1025 * calling changePowerStateTo(), the policy-maker expresses its desire by calling
1026 * changePowerStateToPriv(), and the children express their desires by calling
1027 * requestPowerDomainState().
1028 *
1029 * The Root Power Domain owns the policy for idle and demand sleep for the system.
1030 * It is a power-managed IOService just like the others in the system.
1031 * It implements several power states which map to what we see as Sleep and On.
1032 *
1033 * The sleep policy is as follows:
1034 * 1. Sleep is prevented if the case is open so that nobody will think the machine
1035 * is off and plug/unplug cards.
1036 * 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
1037 * 3. System cannot Sleep if some object in the tree is in a power state marked
1038 * kIOPMPreventSystemSleep.
1039 *
1040 * These three conditions are enforced using the "driver clamp" by calling
1041 * changePowerStateTo(). For example, if the case is opened,
1042 * changePowerStateTo(ON_STATE) is called to hold the system on regardless
1043 * of the desires of the children of the root or the state of the other clamp.
1044 *
1045 * Demand Sleep is initiated by pressing the front panel power button, closing
1046 * the clamshell, or selecting the menu item. In this case the root's parent
1047 * actually initiates the power state change so that the root domain has no
1048 * choice and does not give applications the opportunity to veto the change.
1049 *
1050 * Idle Sleep occurs if no objects in the tree are in a state marked
1051 * kIOPMPreventIdleSleep. When this is true, the root's children are not holding
1052 * the root on, so it sets the "policy-maker clamp" by calling
1053 * changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
1054 * This timer is set for the difference between the sleep timeout slider and the
1055 * display dim timeout slider. When the timer expires, it releases its clamp and
1056 * now nothing is holding it awake, so it falls asleep.
1057 *
1058 * Demand sleep is prevented when the system is booting. When preferences are
1059 * transmitted by the loginwindow at the end of boot, a flag is cleared,
1060 * and this allows subsequent Demand Sleep.
1061 */
2d21ac55 1062
b0d623f7 1063//******************************************************************************
0b4e3aa0 1064
0a7de745
A
1065IOPMrootDomain *
1066IOPMrootDomain::construct( void )
0b4e3aa0 1067{
0a7de745 1068 IOPMrootDomain *root;
0b4e3aa0 1069
0a7de745
A
1070 root = new IOPMrootDomain;
1071 if (root) {
1072 root->init();
1073 }
0b4e3aa0 1074
0a7de745 1075 return root;
0b4e3aa0
A
1076}
1077
3e170ce0
A
1078//******************************************************************************
1079// updateConsoleUsersCallout
1080//
1081//******************************************************************************
1082
0a7de745
A
1083static void
1084updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
4bd07ac2 1085{
0a7de745
A
1086 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
1087 rootDomain->updateConsoleUsers();
4bd07ac2
A
1088}
1089
0a7de745
A
1090void
1091IOPMrootDomain::updateConsoleUsers(void)
3e170ce0 1092{
0a7de745
A
1093 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
1094 if (tasksSuspended) {
1095 tasksSuspended = FALSE;
cb323159 1096 updateTasksSuspend();
0a7de745 1097 }
3e170ce0
A
1098}
1099
cb323159
A
1100void
1101IOPMrootDomain::updateTasksSuspend(void)
1102{
1103 bool newSuspend;
1104
cb323159 1105 newSuspend = (tasksSuspended || _aotTasksSuspended);
cb323159
A
1106 if (newSuspend == tasksSuspendState) {
1107 return;
1108 }
1109 tasksSuspendState = newSuspend;
1110 tasks_system_suspend(newSuspend);
1111}
1112
b0d623f7 1113//******************************************************************************
0b4e3aa0 1114
0a7de745
A
1115static void
1116disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
0b4e3aa0 1117{
f427ee49 1118 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
0a7de745
A
1119 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
1120 uint32_t powerState = rootDomain->getPowerState();
2d21ac55 1121
0a7de745 1122 DLOG("disk_sync_callout ps=%u\n", powerState);
0b4e3aa0 1123
0a7de745
A
1124 if (ON_STATE == powerState) {
1125 sync_internal();
5c9f4661
A
1126
1127#if HIBERNATION
0a7de745
A
1128 // Block sleep until trim issued on previous wake path is completed.
1129 IOHibernateSystemPostWake(true);
5c9f4661 1130#endif
0a7de745 1131 }
fe8ab488 1132#if HIBERNATION
0a7de745
A
1133 else {
1134 IOHibernateSystemPostWake(false);
3e170ce0 1135
f427ee49 1136 rootDomain->sleepWakeDebugSaveSpinDumpFile();
0a7de745 1137 }
6d2010ae
A
1138#endif
1139
0a7de745
A
1140 rootDomain->allowPowerChange(notifyRef);
1141 DLOG("disk_sync_callout finish\n");
0b4e3aa0 1142}
1c79356b 1143
b0d623f7 1144//******************************************************************************
0a7de745
A
1145static UInt32
1146computeDeltaTimeMS( const AbsoluteTime * startTime, AbsoluteTime * elapsedTime )
0c530ab8 1147{
0a7de745
A
1148 AbsoluteTime endTime;
1149 UInt64 nano = 0;
2d21ac55 1150
0a7de745
A
1151 clock_get_uptime(&endTime);
1152 if (CMP_ABSOLUTETIME(&endTime, startTime) <= 0) {
1153 *elapsedTime = 0;
1154 } else {
1155 SUB_ABSOLUTETIME(&endTime, startTime);
1156 absolutetime_to_nanoseconds(endTime, &nano);
1157 *elapsedTime = endTime;
1158 }
0c530ab8 1159
0a7de745 1160 return (UInt32)(nano / NSEC_PER_MSEC);
2d21ac55 1161}
0c530ab8 1162
b0d623f7 1163//******************************************************************************
0b4e3aa0 1164
b0d623f7
A
1165static int
1166sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
1167{
0a7de745
A
1168 struct timeval *swt = (struct timeval *)arg1;
1169 struct proc *p = req->p;
1170
1171 if (p == kernproc) {
1172 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
1173 } else if (proc_is64bit(p)) {
1174 struct user64_timeval t = {};
1175 t.tv_sec = swt->tv_sec;
1176 t.tv_usec = swt->tv_usec;
1177 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
1178 } else {
1179 struct user32_timeval t = {};
f427ee49 1180 t.tv_sec = (typeof(t.tv_sec))swt->tv_sec;
0a7de745
A
1181 t.tv_usec = swt->tv_usec;
1182 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
1183 }
b0d623f7
A
1184}
1185
1186static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
c3c9b80d 1187 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 1188 &gIOLastUserSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7
A
1189
1190static SYSCTL_PROC(_kern, OID_AUTO, waketime,
c3c9b80d 1191 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
0a7de745 1192 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7 1193
0a7de745
A
1194SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
1195SYSCTL_QUAD(_kern, OID_AUTO, sleep_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gIOLastSleepAbsTime, "");
1196SYSCTL_QUAD(_kern, OID_AUTO, useractive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gUserActiveAbsTime, "");
1197SYSCTL_QUAD(_kern, OID_AUTO, userinactive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gUserInactiveAbsTime, "");
b0d623f7
A
1198
1199static int
c3c9b80d 1200sysctl_willshutdown SYSCTL_HANDLER_ARGS
b0d623f7 1201{
c3c9b80d
A
1202 int new_value, changed, error;
1203
1204 if (!gWillShutdownSysctlRegistered) {
1205 return ENOENT;
1206 }
1207
1208 error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
0a7de745
A
1209 if (changed) {
1210 if (!gWillShutdown && (new_value == 1)) {
1211 IOPMRootDomainWillShutdown();
1212 } else {
1213 error = EINVAL;
1214 }
1215 }
1216 return error;
b0d623f7
A
1217}
1218
1219static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
c3c9b80d 1220 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 1221 NULL, 0, sysctl_willshutdown, "I", "");
b0d623f7 1222
f427ee49 1223#if defined(XNU_TARGET_OS_OSX)
b0d623f7
A
1224
1225static int
1226sysctl_progressmeterenable
1227(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1228{
0a7de745
A
1229 int error;
1230 int new_value, changed;
b0d623f7 1231
0a7de745 1232 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
b0d623f7 1233
0a7de745
A
1234 if (changed) {
1235 vc_enable_progressmeter(new_value);
1236 }
b0d623f7 1237
0a7de745 1238 return error;
b0d623f7
A
1239}
1240
1241static int
1242sysctl_progressmeter
1243(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1244{
0a7de745
A
1245 int error;
1246 int new_value, changed;
b0d623f7 1247
0a7de745 1248 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
b0d623f7 1249
0a7de745
A
1250 if (changed) {
1251 vc_set_progressmeter(new_value);
1252 }
b0d623f7 1253
0a7de745 1254 return error;
b0d623f7
A
1255}
1256
1257static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
c3c9b80d 1258 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 1259 NULL, 0, sysctl_progressmeterenable, "I", "");
2d21ac55 1260
b0d623f7 1261static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
c3c9b80d 1262 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 1263 NULL, 0, sysctl_progressmeter, "I", "");
fe8ab488 1264
f427ee49 1265#endif /* defined(XNU_TARGET_OS_OSX) */
2d21ac55 1266
3e170ce0
A
1267
1268
1269static int
1270sysctl_consoleoptions
1271(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1272{
0a7de745
A
1273 int error, changed;
1274 uint32_t new_value;
3e170ce0 1275
0a7de745 1276 error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
3e170ce0 1277
0a7de745
A
1278 if (changed) {
1279 vc_user_options.options = new_value;
1280 }
3e170ce0 1281
0a7de745 1282 return error;
3e170ce0
A
1283}
1284
1285static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
c3c9b80d 1286 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 1287 NULL, 0, sysctl_consoleoptions, "I", "");
3e170ce0 1288
490019cf
A
1289
1290static int
1291sysctl_progressoptions SYSCTL_HANDLER_ARGS
1292{
0a7de745 1293 return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
490019cf
A
1294}
1295
1296static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
c3c9b80d 1297 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
0a7de745 1298 NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
490019cf
A
1299
1300
fe8ab488
A
1301static int
1302sysctl_wakereason SYSCTL_HANDLER_ARGS
1303{
0a7de745 1304 char wr[sizeof(gWakeReasonString)];
fe8ab488 1305
0a7de745 1306 wr[0] = '\0';
c3c9b80d 1307 if (gRootDomain && gWakeReasonSysctlRegistered) {
0a7de745 1308 gRootDomain->copyWakeReasonString(wr, sizeof(wr));
c3c9b80d
A
1309 } else {
1310 return ENOENT;
0a7de745 1311 }
fe8ab488 1312
0a7de745 1313 return sysctl_io_string(req, wr, 0, 0, NULL);
fe8ab488
A
1314}
1315
1316SYSCTL_PROC(_kern, OID_AUTO, wakereason,
c3c9b80d 1317 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
fe8ab488 1318 NULL, 0, sysctl_wakereason, "A", "wakereason");
2d21ac55 1319
c3c9b80d
A
1320static int
1321sysctl_bootreason SYSCTL_HANDLER_ARGS
1322{
1323 if (!os_atomic_load(&gBootReasonSysctlRegistered, acquire)) {
1324 return ENOENT;
1325 }
1326
1327 return sysctl_io_string(req, gBootReasonString, 0, 0, NULL);
1328}
1329
1330SYSCTL_PROC(_kern, OID_AUTO, bootreason,
1331 CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1332 NULL, 0, sysctl_bootreason, "A", "");
f427ee49
A
1333
1334static int
1335sysctl_shutdownreason SYSCTL_HANDLER_ARGS
1336{
1337 char sr[sizeof(gShutdownReasonString)];
1338
1339 sr[0] = '\0';
c3c9b80d 1340 if (gRootDomain && gShutdownReasonSysctlRegistered) {
f427ee49 1341 gRootDomain->copyShutdownReasonString(sr, sizeof(sr));
c3c9b80d
A
1342 } else {
1343 return ENOENT;
f427ee49
A
1344 }
1345
1346 return sysctl_io_string(req, sr, 0, 0, NULL);
1347}
1348
1349SYSCTL_PROC(_kern, OID_AUTO, shutdownreason,
c3c9b80d 1350 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
f427ee49
A
1351 NULL, 0, sysctl_shutdownreason, "A", "shutdownreason");
1352
3e170ce0
A
1353static int
1354sysctl_targettype SYSCTL_HANDLER_ARGS
1355{
0a7de745 1356 IOService * root;
f427ee49 1357 OSSharedPtr<OSObject> obj;
0a7de745
A
1358 OSData * data;
1359 char tt[32];
3e170ce0 1360
0a7de745
A
1361 tt[0] = '\0';
1362 root = IOService::getServiceRoot();
1363 if (root && (obj = root->copyProperty(gIODTTargetTypeKey))) {
f427ee49 1364 if ((data = OSDynamicCast(OSData, obj.get()))) {
0a7de745
A
1365 strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
1366 }
3e170ce0 1367 }
0a7de745 1368 return sysctl_io_string(req, tt, 0, 0, NULL);
3e170ce0
A
1369}
1370
1371SYSCTL_PROC(_hw, OID_AUTO, targettype,
c3c9b80d 1372 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
3e170ce0
A
1373 NULL, 0, sysctl_targettype, "A", "targettype");
1374
3e170ce0 1375static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
d9a64523
A
1376static SYSCTL_INT(_debug, OID_AUTO, swd_sleep_timeout, CTLFLAG_RW, &gSwdSleepTimeout, 0, "");
1377static SYSCTL_INT(_debug, OID_AUTO, swd_wake_timeout, CTLFLAG_RW, &gSwdWakeTimeout, 0, "");
1378static SYSCTL_INT(_debug, OID_AUTO, swd_timeout, CTLFLAG_RW, &gSwdSleepWakeTimeout, 0, "");
1379static SYSCTL_INT(_debug, OID_AUTO, swd_panic, CTLFLAG_RW, &gSwdPanic, 0, "");
cb323159
A
1380#if DEVELOPMENT || DEBUG
1381static SYSCTL_INT(_debug, OID_AUTO, swd_panic_phase, CTLFLAG_RW, &swd_panic_phase, 0, "");
f427ee49
A
1382#if defined(XNU_TARGET_OS_OSX)
1383static SYSCTL_INT(_debug, OID_AUTO, clamshell, CTLFLAG_RW, &gClamshellFlags, 0, "");
1384static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
1385#endif /* defined(XNU_TARGET_OS_OSX) */
1386#endif /* DEVELOPMENT || DEBUG */
cb323159 1387
cb323159
A
1388//******************************************************************************
1389// AOT
1390
1391static int
1392sysctl_aotmetrics SYSCTL_HANDLER_ARGS
1393{
1394 if (NULL == gRootDomain) {
1395 return ENOENT;
1396 }
1397 if (NULL == gRootDomain->_aotMetrics) {
1398 return ENOENT;
1399 }
1400 return sysctl_io_opaque(req, gRootDomain->_aotMetrics, sizeof(IOPMAOTMetrics), NULL);
1401}
1402
1403static SYSCTL_PROC(_kern, OID_AUTO, aotmetrics,
c3c9b80d 1404 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
cb323159
A
1405 NULL, 0, sysctl_aotmetrics, "S,IOPMAOTMetrics", "");
1406
1407
1408static int
1409update_aotmode(uint32_t mode)
1410{
1411 int result;
1412
1413 if (!gIOPMWorkLoop) {
1414 return ENOENT;
1415 }
1416 result = gIOPMWorkLoop->runActionBlock(^IOReturn (void) {
1417 unsigned int oldCount;
1418
1419 if (mode && !gRootDomain->_aotMetrics) {
1420 gRootDomain->_aotMetrics = IONewZero(IOPMAOTMetrics, 1);
1421 if (!gRootDomain->_aotMetrics) {
1422 return ENOMEM;
1423 }
1424 }
1425
1426 oldCount = gRootDomain->idleSleepPreventersCount();
f427ee49 1427 gRootDomain->_aotMode = (mode & kIOPMAOTModeMask);
cb323159
A
1428 gRootDomain->updatePreventIdleSleepListInternal(NULL, false, oldCount);
1429 return 0;
1430 });
1431 return result;
1432}
1433
1434static int
1435sysctl_aotmodebits
1436(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1437{
1438 int error, changed;
1439 uint32_t new_value;
1440
1441 if (NULL == gRootDomain) {
1442 return ENOENT;
1443 }
1444 error = sysctl_io_number(req, gRootDomain->_aotMode, sizeof(uint32_t), &new_value, &changed);
1445 if (changed && gIOPMWorkLoop) {
1446 error = update_aotmode(new_value);
1447 }
1448
1449 return error;
1450}
1451
1452static SYSCTL_PROC(_kern, OID_AUTO, aotmodebits,
c3c9b80d 1453 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159
A
1454 NULL, 0, sysctl_aotmodebits, "I", "");
1455
1456static int
1457sysctl_aotmode
1458(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1459{
1460 int error, changed;
1461 uint32_t new_value;
1462
1463 if (NULL == gRootDomain) {
1464 return ENOENT;
1465 }
1466 error = sysctl_io_number(req, gRootDomain->_aotMode, sizeof(uint32_t), &new_value, &changed);
1467 if (changed && gIOPMWorkLoop) {
1468 if (new_value) {
1469 new_value = kIOPMAOTModeDefault; // & ~kIOPMAOTModeRespectTimers;
1470 }
1471 error = update_aotmode(new_value);
1472 }
1473
1474 return error;
1475}
1476
1477static SYSCTL_PROC(_kern, OID_AUTO, aotmode,
c3c9b80d 1478 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
cb323159
A
1479 NULL, 0, sysctl_aotmode, "I", "");
1480
1481//******************************************************************************
6d2010ae 1482
f427ee49
A
1483static OSSharedPtr<const OSSymbol> gIOPMSettingAutoWakeCalendarKey;
1484static OSSharedPtr<const OSSymbol> gIOPMSettingAutoWakeSecondsKey;
1485static OSSharedPtr<const OSSymbol> gIOPMSettingAutoPowerCalendarKey;
1486static OSSharedPtr<const OSSymbol> gIOPMSettingAutoPowerSecondsKey;
1487static OSSharedPtr<const OSSymbol> gIOPMSettingDebugWakeRelativeKey;
1488static OSSharedPtr<const OSSymbol> gIOPMSettingDebugPowerRelativeKey;
1489static OSSharedPtr<const OSSymbol> gIOPMSettingMaintenanceWakeCalendarKey;
1490static OSSharedPtr<const OSSymbol> gIOPMSettingSleepServiceWakeCalendarKey;
1491static OSSharedPtr<const OSSymbol> gIOPMSettingSilentRunningKey;
1492static OSSharedPtr<const OSSymbol> gIOPMUserTriggeredFullWakeKey;
1493static OSSharedPtr<const OSSymbol> gIOPMUserIsActiveKey;
1494static OSSharedPtr<const OSSymbol> gIOPMSettingLowLatencyAudioModeKey;
b0d623f7
A
1495
1496//******************************************************************************
1497// start
1498//
1499//******************************************************************************
1500
f427ee49
A
1501#define kRootDomainSettingsCount 20
1502#define kRootDomainNoPublishSettingsCount 4
0b4e3aa0 1503
0a7de745
A
1504bool
1505IOPMrootDomain::start( IOService * nub )
1506{
f427ee49
A
1507 OSSharedPtr<OSIterator> psIterator;
1508 OSSharedPtr<OSDictionary> tmpDict;
0a7de745
A
1509
1510 super::start(nub);
1511
1512 gRootDomain = this;
1513 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
1514 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
cb323159
A
1515 gIOPMSettingAutoPowerCalendarKey = OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey);
1516 gIOPMSettingAutoPowerSecondsKey = OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey);
0a7de745 1517 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
cb323159 1518 gIOPMSettingDebugPowerRelativeKey = OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey);
0a7de745
A
1519 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
1520 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
1521 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
1522 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
1523 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
f427ee49 1524 gIOPMSettingLowLatencyAudioModeKey = OSSymbol::withCStringNoCopy(kIOPMSettingLowLatencyAudioModeKey);
0a7de745
A
1525
1526 gIOPMStatsResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
1527 gIOPMStatsResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
1528 gIOPMStatsResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
1529 gIOPMStatsResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
1530 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
1531
1532 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
1533 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
f427ee49 1534 gIOPMWakeTypeUserKey = OSSymbol::withCStringNoCopy(kIOPMRootDomainWakeTypeUser);
0a7de745 1535
f427ee49 1536 OSSharedPtr<const OSSymbol> settingsArr[kRootDomainSettingsCount] =
0a7de745
A
1537 {
1538 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
1539 gIOPMSettingAutoWakeSecondsKey,
cb323159 1540 gIOPMSettingAutoPowerSecondsKey,
0a7de745 1541 gIOPMSettingAutoWakeCalendarKey,
cb323159 1542 gIOPMSettingAutoPowerCalendarKey,
0a7de745 1543 gIOPMSettingDebugWakeRelativeKey,
cb323159 1544 gIOPMSettingDebugPowerRelativeKey,
0a7de745
A
1545 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
1546 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
1547 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
1548 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
1549 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
1550 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
1551 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
1552 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
1553 OSSymbol::withCString(kIOPMStateConsoleShutdown),
94ff46dc
A
1554 OSSymbol::withCString(kIOPMSettingProModeControl),
1555 OSSymbol::withCString(kIOPMSettingProModeDefer),
1556 gIOPMSettingSilentRunningKey,
f427ee49 1557 gIOPMSettingLowLatencyAudioModeKey,
94ff46dc
A
1558 };
1559
f427ee49 1560 OSSharedPtr<const OSSymbol> noPublishSettingsArr[kRootDomainNoPublishSettingsCount] =
94ff46dc
A
1561 {
1562 OSSymbol::withCString(kIOPMSettingProModeControl),
1563 OSSymbol::withCString(kIOPMSettingProModeDefer),
1564 gIOPMSettingSilentRunningKey,
f427ee49 1565 gIOPMSettingLowLatencyAudioModeKey,
0a7de745
A
1566 };
1567
f427ee49
A
1568#if DEVELOPMENT || DEBUG
1569#if defined(XNU_TARGET_OS_OSX)
0a7de745 1570 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
f427ee49
A
1571 PE_parse_boot_argn("clamshell", &gClamshellFlags, sizeof(gClamshellFlags));
1572#endif /* defined(XNU_TARGET_OS_OSX) */
1573#endif /* DEVELOPMENT || DEBUG */
1574
0a7de745
A
1575 PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
1576 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout, sizeof(gSwdSleepTimeout));
1577 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout, sizeof(gSwdWakeTimeout));
1578 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout, sizeof(gSwdSleepWakeTimeout));
1579 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic, sizeof(gHaltTimeMaxPanic));
1580 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog, sizeof(gHaltTimeMaxLog));
1581
1582 queue_init(&aggressivesQueue);
1583 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
1584 aggressivesData = OSData::withCapacity(
1585 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
1586
1587 featuresDictLock = IOLockAlloc();
1588 settingsCtrlLock = IOLockAlloc();
1589 wakeEventLock = IOLockAlloc();
1590 gHaltLogLock = IOLockAlloc();
1591 setPMRootDomain(this);
1592
1593 extraSleepTimer = thread_call_allocate(
1594 idleSleepTimerExpired,
1595 (thread_call_param_t) this);
1596
cb323159
A
1597 powerButtonDown = thread_call_allocate(
1598 powerButtonDownCallout,
1599 (thread_call_param_t) this);
1600
1601 powerButtonUp = thread_call_allocate(
1602 powerButtonUpCallout,
1603 (thread_call_param_t) this);
1604
0a7de745
A
1605 diskSyncCalloutEntry = thread_call_allocate(
1606 &disk_sync_callout,
1607 (thread_call_param_t) this);
1608 updateConsoleUsersEntry = thread_call_allocate(
1609 &updateConsoleUsersCallout,
1610 (thread_call_param_t) this);
3e170ce0 1611
f427ee49
A
1612#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
1613 fullWakeThreadCall = thread_call_allocate_with_options(
0a7de745
A
1614 OSMemberFunctionCast(thread_call_func_t, this,
1615 &IOPMrootDomain::fullWakeDelayedWork),
f427ee49
A
1616 (thread_call_param_t) this, THREAD_CALL_PRIORITY_KERNEL,
1617 THREAD_CALL_OPTIONS_ONCE);
39236c6e
A
1618#endif
1619
0a7de745
A
1620 setProperty(kIOSleepSupportedKey, true);
1621
1622 bzero(&gPMStats, sizeof(gPMStats));
1623
1624 pmTracer = PMTraceWorker::tracer(this);
1625
1626 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1627
1628 userDisabledAllSleep = false;
1629 systemBooting = true;
1630 idleSleepEnabled = false;
1631 sleepSlider = 0;
1632 idleSleepTimerPending = false;
1633 wrangler = NULL;
f427ee49
A
1634 clamshellClosed = false;
1635 clamshellExists = false;
1636#if DISPLAY_WRANGLER_PRESENT
1637 clamshellDisabled = true;
1638#else
1639 clamshellDisabled = false;
1640#endif
1641 clamshellIgnoreClose = false;
0a7de745 1642 acAdaptorConnected = true;
f427ee49 1643 clamshellSleepDisableMask = 0;
0a7de745
A
1644 gWakeReasonString[0] = '\0';
1645
1646 // Initialize to user active.
1647 // Will never transition to user inactive w/o wrangler.
1648 fullWakeReason = kFullWakeReasonLocalUser;
1649 userIsActive = userWasActive = true;
1650 clock_get_uptime(&gUserActiveAbsTime);
f427ee49 1651 setProperty(gIOPMUserIsActiveKey.get(), kOSBooleanTrue);
0a7de745
A
1652
1653 // Set the default system capabilities at boot.
1654 _currentCapability = kIOPMSystemCapabilityCPU |
1655 kIOPMSystemCapabilityGraphics |
1656 kIOPMSystemCapabilityAudio |
1657 kIOPMSystemCapabilityNetwork;
1658
1659 _pendingCapability = _currentCapability;
1660 _desiredCapability = _currentCapability;
1661 _highestCapability = _currentCapability;
1662 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
1663
1664 queuedSleepWakeUUIDString = NULL;
1665 initializeBootSessionUUID();
1666 pmStatsAppResponses = OSArray::withCapacity(5);
1667 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
1668 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
1669 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
1670 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
1671 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
1672 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
1673 assertOnWakeSecs = -1;// Invalid value to prevent updates
1674
1675 pmStatsLock = IOLockAlloc();
1676 idxPMCPUClamshell = kCPUUnknownIndex;
1677 idxPMCPULimitedPower = kCPUUnknownIndex;
1678
1679 tmpDict = OSDictionary::withCapacity(1);
f427ee49
A
1680 setProperty(kRootDomainSupportedFeatures, tmpDict.get());
1681
1682 // Set a default "SystemPowerProfileOverrideDict" for platform
1683 // drivers without any overrides.
1684 if (!propertyExists(kIOPMSystemDefaultOverrideKey)) {
1685 tmpDict = OSDictionary::withCapacity(1);
1686 setProperty(kIOPMSystemDefaultOverrideKey, tmpDict.get());
1687 }
0a7de745
A
1688
1689 settingsCallbacks = OSDictionary::withCapacity(1);
1690
1691 // Create a list of the valid PM settings that we'll relay to
1692 // interested clients in setProperties() => setPMSetting()
1693 allowedPMSettings = OSArray::withObjects(
1694 (const OSObject **)settingsArr,
1695 kRootDomainSettingsCount,
1696 0);
1697
1698 // List of PM settings that should not automatically publish itself
1699 // as a feature when registered by a listener.
1700 noPublishPMSettings = OSArray::withObjects(
94ff46dc
A
1701 (const OSObject **)noPublishSettingsArr,
1702 kRootDomainNoPublishSettingsCount,
1703 0);
0a7de745
A
1704
1705 fPMSettingsDict = OSDictionary::withCapacity(5);
1706 preventIdleSleepList = OSSet::withCapacity(8);
1707 preventSystemSleepList = OSSet::withCapacity(2);
1708
1709 PMinit(); // creates gIOPMWorkLoop
1710 gIOPMWorkLoop = getIOPMWorkloop();
1711
1712 // Create IOPMPowerStateQueue used to queue external power
1713 // events, and to handle those events on the PM work loop.
1714 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
1715 this, OSMemberFunctionCast(IOEventSource::Action, this,
1716 &IOPMrootDomain::dispatchPowerEvent));
1717 gIOPMWorkLoop->addEventSource(pmPowerStateQueue);
1718
cb323159
A
1719 _aotMode = 0;
1720 _aotTimerES = IOTimerEventSource::timerEventSource(this,
1721 OSMemberFunctionCast(IOTimerEventSource::Action,
1722 this, &IOPMrootDomain::aotEvaluate));
f427ee49 1723 gIOPMWorkLoop->addEventSource(_aotTimerES.get());
cb323159 1724
0a7de745 1725 // create our power parent
f427ee49
A
1726 gPatriarch = new IORootParent;
1727 gPatriarch->init();
1728 gPatriarch->attach(this);
1729 gPatriarch->start(this);
1730 gPatriarch->addPowerChild(this);
0a7de745
A
1731
1732 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
f427ee49 1733 changePowerStateWithTagToPriv(ON_STATE, kCPSReasonInit);
0a7de745
A
1734
1735 // install power change handler
cb323159 1736 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, NULL);
0b4e3aa0 1737
f427ee49 1738#if DISPLAY_WRANGLER_PRESENT
0a7de745 1739 wranglerIdleSettings = OSDictionary::withCapacity(1);
f427ee49 1740 OSSharedPtr<OSNumber> wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
39236c6e 1741
0a7de745
A
1742 if (wranglerIdleSettings && wranglerIdlePeriod) {
1743 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
f427ee49 1744 wranglerIdlePeriod.get());
0a7de745 1745 }
39236c6e 1746
f427ee49
A
1747#endif /* DISPLAY_WRANGLER_PRESENT */
1748
1749 lowLatencyAudioNotifierDict = OSDictionary::withCapacity(2);
1750 lowLatencyAudioNotifyStateSym = OSSymbol::withCString("LowLatencyAudioNotifyState");
1751 lowLatencyAudioNotifyTimestampSym = OSSymbol::withCString("LowLatencyAudioNotifyTimestamp");
1752 lowLatencyAudioNotifyStateVal = OSNumber::withNumber(0ull, 32);
1753 lowLatencyAudioNotifyTimestampVal = OSNumber::withNumber(0ull, 64);
1754
1755 if (lowLatencyAudioNotifierDict && lowLatencyAudioNotifyStateSym && lowLatencyAudioNotifyTimestampSym &&
1756 lowLatencyAudioNotifyStateVal && lowLatencyAudioNotifyTimestampVal) {
1757 lowLatencyAudioNotifierDict->setObject(lowLatencyAudioNotifyStateSym.get(), lowLatencyAudioNotifyStateVal.get());
1758 lowLatencyAudioNotifierDict->setObject(lowLatencyAudioNotifyTimestampSym.get(), lowLatencyAudioNotifyTimestampVal.get());
0a7de745 1759 }
39236c6e 1760
f427ee49
A
1761 OSSharedPtr<const OSSymbol> ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
1762 setProperty(gIOUserClientClassKey, const_cast<OSObject *>(static_cast<const OSObject *>(ucClassName.get())));
0a7de745
A
1763
1764 // IOBacklightDisplay can take a long time to load at boot, or it may
1765 // not load at all if you're booting with clamshell closed. We publish
1766 // 'DisplayDims' here redundantly to get it published early and at all.
f427ee49 1767 OSSharedPtr<OSDictionary> matching;
0a7de745 1768 matching = serviceMatching("IOPMPowerSource");
f427ee49
A
1769 psIterator = getMatchingServices(matching.get());
1770
0a7de745
A
1771 if (psIterator && psIterator->getNextObject()) {
1772 // There's at least one battery on the system, so we publish
1773 // 'DisplayDims' support for the LCD.
1774 publishFeature("DisplayDims");
1775 }
0a7de745 1776
cb323159
A
1777 // read swd_panic boot-arg
1778 PE_parse_boot_argn("swd_panic", &gSwdPanic, sizeof(gSwdPanic));
c3c9b80d 1779 gWillShutdownSysctlRegistered = true;
cb323159 1780
fe8ab488 1781#if HIBERNATION
f427ee49 1782#if defined(__arm64__)
f427ee49 1783#endif /* defined(__arm64__) */
0a7de745 1784 IOHibernateSystemInit(this);
2d21ac55 1785#endif
91447636 1786
0a7de745 1787 registerService(); // let clients find us
1c79356b 1788
0a7de745 1789 return true;
1c79356b
A
1790}
1791
b0d623f7 1792//******************************************************************************
9bccf70c
A
1793// setProperties
1794//
1795// Receive a setProperty call
1796// The "System Boot" property means the system is completely booted.
b0d623f7
A
1797//******************************************************************************
1798
0a7de745
A
1799IOReturn
1800IOPMrootDomain::setProperties( OSObject * props_obj )
1801{
1802 IOReturn return_value = kIOReturnSuccess;
1803 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
f427ee49
A
1804 OSBoolean *b = NULL;
1805 OSNumber *n = NULL;
1806 const OSSymbol *key = NULL;
1807 OSObject *obj = NULL;
1808 OSSharedPtr<OSCollectionIterator> iter;
cb323159
A
1809
1810 if (!dict) {
1811 return kIOReturnBadArgument;
1812 }
1813
1814 bool clientEntitled = false;
f427ee49
A
1815 {
1816 OSSharedPtr<OSObject> obj = IOUserClient::copyClientEntitlement(current_task(), kRootDomainEntitlementSetProperty);
1817 clientEntitled = (obj == kOSBooleanTrue);
1818 }
cb323159
A
1819
1820 if (!clientEntitled) {
1821 const char * errorSuffix = NULL;
1822
1823 // IOPMSchedulePowerEvent() clients may not be entitled, but must be root.
1824 // That API can set 6 possible keys that are checked below.
1825 if ((dict->getCount() == 1) &&
f427ee49
A
1826 (dict->getObject(gIOPMSettingAutoWakeSecondsKey.get()) ||
1827 dict->getObject(gIOPMSettingAutoPowerSecondsKey.get()) ||
1828 dict->getObject(gIOPMSettingAutoWakeCalendarKey.get()) ||
1829 dict->getObject(gIOPMSettingAutoPowerCalendarKey.get()) ||
1830 dict->getObject(gIOPMSettingDebugWakeRelativeKey.get()) ||
1831 dict->getObject(gIOPMSettingDebugPowerRelativeKey.get()))) {
cb323159
A
1832 return_value = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
1833 if (return_value != kIOReturnSuccess) {
1834 errorSuffix = "privileged";
1835 }
1836 } else {
1837 return_value = kIOReturnNotPermitted;
1838 errorSuffix = "entitled";
1839 }
1840
1841 if (return_value != kIOReturnSuccess) {
f427ee49 1842 OSSharedPtr<OSString> procName(IOCopyLogNameForPID(proc_selfpid()), OSNoRetain);
cb323159
A
1843 DLOG("%s failed, process %s is not %s\n", __func__,
1844 procName ? procName->getCStringNoCopy() : "", errorSuffix);
cb323159
A
1845 return return_value;
1846 }
1847 }
0a7de745 1848
f427ee49
A
1849 OSSharedPtr<const OSSymbol> publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1850 OSSharedPtr<const OSSymbol> boot_complete_string = OSSymbol::withCString("System Boot Complete");
1851 OSSharedPtr<const OSSymbol> sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1852 OSSharedPtr<const OSSymbol> stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1853 OSSharedPtr<const OSSymbol> battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1854 OSSharedPtr<const OSSymbol> idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1855 OSSharedPtr<const OSSymbol> sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1856 OSSharedPtr<const OSSymbol> ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1857 OSSharedPtr<const OSSymbol> loginwindow_progress_string = OSSymbol::withCString(kIOPMLoginWindowProgressKey);
1858 OSSharedPtr<const OSSymbol> coredisplay_progress_string = OSSymbol::withCString(kIOPMCoreDisplayProgressKey);
1859 OSSharedPtr<const OSSymbol> coregraphics_progress_string = OSSymbol::withCString(kIOPMCoreGraphicsProgressKey);
1860#if DEBUG || DEVELOPMENT
1861 OSSharedPtr<const OSSymbol> clamshell_close_string = OSSymbol::withCString("IOPMTestClamshellClose");
1862 OSSharedPtr<const OSSymbol> clamshell_open_string = OSSymbol::withCString("IOPMTestClamshellOpen");
1863 OSSharedPtr<const OSSymbol> ac_detach_string = OSSymbol::withCString("IOPMTestACDetach");
1864 OSSharedPtr<const OSSymbol> ac_attach_string = OSSymbol::withCString("IOPMTestACAttach");
1865 OSSharedPtr<const OSSymbol> desktopmode_set_string = OSSymbol::withCString("IOPMTestDesktopModeSet");
1866 OSSharedPtr<const OSSymbol> desktopmode_remove_string = OSSymbol::withCString("IOPMTestDesktopModeRemove");
1867#endif
1868
fe8ab488 1869#if HIBERNATION
f427ee49
A
1870 OSSharedPtr<const OSSymbol> hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1871 OSSharedPtr<const OSSymbol> hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1872 OSSharedPtr<const OSSymbol> hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1873 OSSharedPtr<const OSSymbol> hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
1874 OSSharedPtr<const OSSymbol> hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1875 OSSharedPtr<const OSSymbol> hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
2d21ac55 1876#endif
fe8ab488 1877
0a7de745
A
1878 iter = OSCollectionIterator::withCollection(dict);
1879 if (!iter) {
1880 return_value = kIOReturnNoMemory;
1881 goto exit;
1882 }
1883
1884 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1885 (obj = dict->getObject(key))) {
f427ee49 1886 if (key->isEqualTo(publish_simulated_battery_string.get())) {
0a7de745
A
1887 if (OSDynamicCast(OSBoolean, obj)) {
1888 publishResource(key, kOSBooleanTrue);
1889 }
f427ee49 1890 } else if (key->isEqualTo(idle_seconds_string.get())) {
0a7de745
A
1891 if ((n = OSDynamicCast(OSNumber, obj))) {
1892 setProperty(key, n);
1893 idleSeconds = n->unsigned32BitValue();
1894 }
f427ee49 1895 } else if (key->isEqualTo(boot_complete_string.get())) {
0a7de745 1896 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
f427ee49 1897 } else if (key->isEqualTo(sys_shutdown_string.get())) {
0a7de745
A
1898 if ((b = OSDynamicCast(OSBoolean, obj))) {
1899 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1900 }
f427ee49 1901 } else if (key->isEqualTo(battery_warning_disabled_string.get())) {
0a7de745
A
1902 setProperty(key, obj);
1903 }
fe8ab488 1904#if HIBERNATION
f427ee49
A
1905 else if (key->isEqualTo(hibernatemode_string.get()) ||
1906 key->isEqualTo(hibernatefilemin_string.get()) ||
1907 key->isEqualTo(hibernatefilemax_string.get()) ||
1908 key->isEqualTo(hibernatefreeratio_string.get()) ||
1909 key->isEqualTo(hibernatefreetime_string.get())) {
0a7de745
A
1910 if ((n = OSDynamicCast(OSNumber, obj))) {
1911 setProperty(key, n);
1912 }
f427ee49 1913 } else if (key->isEqualTo(hibernatefile_string.get())) {
0a7de745
A
1914 OSString * str = OSDynamicCast(OSString, obj);
1915 if (str) {
1916 setProperty(key, str);
1917 }
1918 }
fe8ab488 1919#endif
f427ee49 1920 else if (key->isEqualTo(sleepdisabled_string.get())) {
0a7de745
A
1921 if ((b = OSDynamicCast(OSBoolean, obj))) {
1922 setProperty(key, b);
1923 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1924 }
f427ee49 1925 } else if (key->isEqualTo(ondeck_sleepwake_uuid_string.get())) {
0a7de745
A
1926 obj->retain();
1927 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
f427ee49 1928 } else if (key->isEqualTo(loginwindow_progress_string.get())) {
0a7de745
A
1929 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1930 uint32_t data = n->unsigned32BitValue();
1931 pmTracer->traceComponentWakeProgress(kIOPMLoginWindowProgress, data);
1932 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMLoginWindowProgress, data);
1933 }
f427ee49 1934 } else if (key->isEqualTo(coredisplay_progress_string.get())) {
0a7de745
A
1935 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1936 uint32_t data = n->unsigned32BitValue();
1937 pmTracer->traceComponentWakeProgress(kIOPMCoreDisplayProgress, data);
1938 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreDisplayProgress, data);
1939 }
f427ee49 1940 } else if (key->isEqualTo(coregraphics_progress_string.get())) {
0a7de745
A
1941 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1942 uint32_t data = n->unsigned32BitValue();
1943 pmTracer->traceComponentWakeProgress(kIOPMCoreGraphicsProgress, data);
1944 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreGraphicsProgress, data);
1945 }
1946 } else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1947 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1948 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
f427ee49 1949 key->isEqualTo(stall_halt_string.get())) {
0a7de745
A
1950 if ((b = OSDynamicCast(OSBoolean, obj))) {
1951 setProperty(key, b);
1952 }
1953 } else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
1954 key->isEqualTo(kIOPMDeepSleepTimerKey) ||
1955 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1956 key->isEqualTo(kIOPMAutoPowerOffTimerKey)) {
1957 if ((n = OSDynamicCast(OSNumber, obj))) {
1958 setProperty(key, n);
1959 }
1960 } else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey)) {
1961 if (kOSBooleanTrue == obj) {
f427ee49 1962 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarmMask);
0a7de745 1963 } else {
f427ee49
A
1964 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarmMask);
1965 }
1966 DLOG("_userScheduledAlarmMask 0x%x\n", (uint32_t) _userScheduledAlarmMask);
1967 }
1968#if DEBUG || DEVELOPMENT
1969 else if (key->isEqualTo(clamshell_close_string.get())) {
1970 DLOG("SetProperties: setting clamshell close\n");
1971 UInt32 msg = kIOPMClamshellClosed;
1972 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
1973 } else if (key->isEqualTo(clamshell_open_string.get())) {
1974 DLOG("SetProperties: setting clamshell open\n");
1975 UInt32 msg = kIOPMClamshellOpened;
1976 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
1977 } else if (key->isEqualTo(ac_detach_string.get())) {
1978 DLOG("SetProperties: setting ac detach\n");
1979 UInt32 msg = kIOPMSetACAdaptorConnected;
1980 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
1981 } else if (key->isEqualTo(ac_attach_string.get())) {
1982 DLOG("SetProperties: setting ac attach\n");
1983 UInt32 msg = kIOPMSetACAdaptorConnected | kIOPMSetValue;
1984 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
1985 } else if (key->isEqualTo(desktopmode_set_string.get())) {
1986 DLOG("SetProperties: setting desktopmode");
1987 UInt32 msg = kIOPMSetDesktopMode | kIOPMSetValue;
1988 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
1989 } else if (key->isEqualTo(desktopmode_remove_string.get())) {
1990 DLOG("SetProperties: removing desktopmode\n");
1991 UInt32 msg = kIOPMSetDesktopMode;
1992 pmPowerStateQueue->submitPowerEvent(kPowerEventReceivedPowerNotification, (void *)(uintptr_t)msg);
0a7de745 1993 }
f427ee49 1994#endif
0a7de745
A
1995 // Relay our allowed PM settings onto our registered PM clients
1996 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1)) {
1997 return_value = setPMSetting(key, obj);
1998 if (kIOReturnSuccess != return_value) {
1999 break;
2000 }
0a7de745
A
2001 } else {
2002 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
2003 }
2004 }
6601e61a 2005
2d21ac55 2006exit:
0a7de745 2007 return return_value;
9bccf70c
A
2008}
2009
6d2010ae
A
2010// MARK: -
2011// MARK: Aggressiveness
1c79356b 2012
b0d623f7 2013//******************************************************************************
6d2010ae 2014// setAggressiveness
1c79356b 2015//
6d2010ae 2016// Override IOService::setAggressiveness()
b0d623f7 2017//******************************************************************************
1c79356b 2018
0a7de745
A
2019IOReturn
2020IOPMrootDomain::setAggressiveness(
2021 unsigned long type,
2022 unsigned long value )
1c79356b 2023{
0a7de745 2024 return setAggressiveness( type, value, 0 );
6d2010ae 2025}
d52fe63f 2026
b0d623f7
A
2027/*
2028 * Private setAggressiveness() with an internal options argument.
2029 */
0a7de745
A
2030IOReturn
2031IOPMrootDomain::setAggressiveness(
2032 unsigned long type,
2033 unsigned long value,
2034 IOOptionBits options )
2035{
2036 AggressivesRequest * entry;
2037 AggressivesRequest * request;
2038 bool found = false;
2039
f427ee49
A
2040 if ((type > UINT_MAX) || (value > UINT_MAX)) {
2041 return kIOReturnBadArgument;
2042 }
2043
cb323159
A
2044 if (type == kPMMinutesToDim || type == kPMMinutesToSleep) {
2045 DLOG("setAggressiveness(%x) %s = %u\n",
2046 (uint32_t) options, getAggressivenessTypeString((uint32_t) type), (uint32_t) value);
2047 } else {
2048 DEBUG_LOG("setAggressiveness(%x) %s = %u\n",
2049 (uint32_t) options, getAggressivenessTypeString((uint32_t) type), (uint32_t) value);
2050 }
0a7de745
A
2051
2052 request = IONew(AggressivesRequest, 1);
2053 if (!request) {
2054 return kIOReturnNoMemory;
2055 }
2056
2057 memset(request, 0, sizeof(*request));
2058 request->options = options;
2059 request->dataType = kAggressivesRequestTypeRecord;
2060 request->data.record.type = (uint32_t) type;
2061 request->data.record.value = (uint32_t) value;
2062
2063 AGGRESSIVES_LOCK();
2064
2065 // Update disk quick spindown flag used by getAggressiveness().
2066 // Never merge requests with quick spindown flags set.
2067
2068 if (options & kAggressivesOptionQuickSpindownEnable) {
2069 gAggressivesState |= kAggressivesStateQuickSpindown;
2070 } else if (options & kAggressivesOptionQuickSpindownDisable) {
2071 gAggressivesState &= ~kAggressivesStateQuickSpindown;
2072 } else {
2073 // Coalesce requests with identical aggressives types.
2074 // Deal with callers that calls us too "aggressively".
2075
2076 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
2077 {
2078 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
2079 (entry->data.record.type == type) &&
2080 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) {
f427ee49 2081 entry->data.record.value = (uint32_t) value;
0a7de745
A
2082 found = true;
2083 break;
2084 }
2085 }
2086 }
2087
2088 if (!found) {
2089 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
2090 }
2091
2092 AGGRESSIVES_UNLOCK();
2093
2094 if (found) {
2095 IODelete(request, AggressivesRequest, 1);
2096 }
2097
2098 if (options & kAggressivesOptionSynchronous) {
2099 handleAggressivesRequests(); // not truly synchronous
2100 } else {
2101 thread_call_enter(aggressivesThreadCall);
2102 }
2103
2104 return kIOReturnSuccess;
0b4e3aa0
A
2105}
2106
b0d623f7
A
2107//******************************************************************************
2108// getAggressiveness
2109//
2110// Override IOService::setAggressiveness()
2111// Fetch the aggressiveness factor with the given type.
2112//******************************************************************************
2113
0a7de745
A
2114IOReturn
2115IOPMrootDomain::getAggressiveness(
2116 unsigned long type,
2117 unsigned long * outLevel )
2118{
2119 uint32_t value = 0;
2120 int source = 0;
2121
f427ee49 2122 if (!outLevel || (type > UINT_MAX)) {
0a7de745
A
2123 return kIOReturnBadArgument;
2124 }
2125
2126 AGGRESSIVES_LOCK();
2127
2128 // Disk quick spindown in effect, report value = 1
2129
2130 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
2131 (type == kPMMinutesToSpinDown)) {
2132 value = kAggressivesMinValue;
2133 source = 1;
2134 }
2135
2136 // Consult the pending request queue.
2137
2138 if (!source) {
2139 AggressivesRequest * entry;
2140
2141 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
2142 {
2143 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
2144 (entry->data.record.type == type) &&
2145 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) {
2146 value = entry->data.record.value;
2147 source = 2;
2148 break;
2149 }
2150 }
2151 }
2152
2153 // Consult the backend records.
2154
2155 if (!source && aggressivesData) {
2156 AggressivesRecord * record;
2157 int i, count;
2158
2159 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2160 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2161
2162 for (i = 0; i < count; i++, record++) {
2163 if (record->type == type) {
2164 value = record->value;
2165 source = 3;
2166 break;
2167 }
2168 }
2169 }
2170
2171 AGGRESSIVES_UNLOCK();
2172
2173 if (source) {
0a7de745
A
2174 *outLevel = (unsigned long) value;
2175 return kIOReturnSuccess;
2176 } else {
2177 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
2178 *outLevel = 0; // default return = 0, driver may not check for error
2179 return kIOReturnInvalid;
2180 }
d52fe63f
A
2181}
2182
b0d623f7
A
2183//******************************************************************************
2184// joinAggressiveness
1c79356b 2185//
b0d623f7
A
2186// Request from IOService to join future aggressiveness broadcasts.
2187//******************************************************************************
1c79356b 2188
0a7de745
A
2189IOReturn
2190IOPMrootDomain::joinAggressiveness(
2191 IOService * service )
1c79356b 2192{
0a7de745 2193 AggressivesRequest * request;
b0d623f7 2194
0a7de745
A
2195 if (!service || (service == this)) {
2196 return kIOReturnBadArgument;
2197 }
b0d623f7 2198
cb323159 2199 DEBUG_LOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
b0d623f7 2200
0a7de745
A
2201 request = IONew(AggressivesRequest, 1);
2202 if (!request) {
2203 return kIOReturnNoMemory;
2204 }
b0d623f7 2205
0a7de745
A
2206 memset(request, 0, sizeof(*request));
2207 request->dataType = kAggressivesRequestTypeService;
f427ee49 2208 request->data.service.reset(service, OSRetain); // released by synchronizeAggressives()
b0d623f7 2209
0a7de745
A
2210 AGGRESSIVES_LOCK();
2211 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
2212 AGGRESSIVES_UNLOCK();
b0d623f7 2213
0a7de745 2214 thread_call_enter(aggressivesThreadCall);
3a60a9f5 2215
0a7de745 2216 return kIOReturnSuccess;
1c79356b
A
2217}
2218
b0d623f7
A
2219//******************************************************************************
2220// handleAggressivesRequests
2221//
2222// Backend thread processes all incoming aggressiveness requests in the queue.
2223//******************************************************************************
2224
2225static void
2226handleAggressivesFunction(
0a7de745
A
2227 thread_call_param_t param1,
2228 thread_call_param_t param2 )
2229{
2230 if (param1) {
2231 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
2232 }
2233}
2234
2235void
2236IOPMrootDomain::handleAggressivesRequests( void )
2237{
2238 AggressivesRecord * start;
2239 AggressivesRecord * record;
2240 AggressivesRequest * request;
2241 queue_head_t joinedQueue;
2242 int i, count;
2243 bool broadcast;
2244 bool found;
2245 bool pingSelf = false;
2246
2247 AGGRESSIVES_LOCK();
2248
2249 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
2250 queue_empty(&aggressivesQueue)) {
2251 goto unlock_done;
2252 }
2253
2254 gAggressivesState |= kAggressivesStateBusy;
2255 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2256 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2257
2258 do{
2259 broadcast = false;
2260 queue_init(&joinedQueue);
2261
2262 do{
2263 // Remove request from the incoming queue in FIFO order.
2264 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
2265 switch (request->dataType) {
2266 case kAggressivesRequestTypeRecord:
2267 // Update existing record if found.
2268 found = false;
2269 for (i = 0, record = start; i < count; i++, record++) {
2270 if (record->type == request->data.record.type) {
2271 found = true;
2272
2273 if (request->options & kAggressivesOptionQuickSpindownEnable) {
2274 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) {
2275 broadcast = true;
2276 record->flags |= (kAggressivesRecordFlagMinValue |
2277 kAggressivesRecordFlagModified);
2278 DLOG("disk spindown accelerated, was %u min\n",
2279 record->value);
2280 }
2281 } else if (request->options & kAggressivesOptionQuickSpindownDisable) {
2282 if (record->flags & kAggressivesRecordFlagMinValue) {
2283 broadcast = true;
2284 record->flags |= kAggressivesRecordFlagModified;
2285 record->flags &= ~kAggressivesRecordFlagMinValue;
2286 DLOG("disk spindown restored to %u min\n",
2287 record->value);
2288 }
2289 } else if (record->value != request->data.record.value) {
2290 record->value = request->data.record.value;
2291 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) {
2292 broadcast = true;
2293 record->flags |= kAggressivesRecordFlagModified;
2294 }
2295 }
2296 break;
2297 }
2298 }
2299
2300 // No matching record, append a new record.
2301 if (!found &&
2302 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0)) {
2303 AggressivesRecord newRecord;
2304
2305 newRecord.flags = kAggressivesRecordFlagModified;
2306 newRecord.type = request->data.record.type;
2307 newRecord.value = request->data.record.value;
2308 if (request->options & kAggressivesOptionQuickSpindownEnable) {
2309 newRecord.flags |= kAggressivesRecordFlagMinValue;
2310 DLOG("disk spindown accelerated\n");
2311 }
2312
2313 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
2314
2315 // OSData may have switched to another (larger) buffer.
2316 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
2317 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
2318 broadcast = true;
2319 }
2320
2321 // Finished processing the request, release it.
2322 IODelete(request, AggressivesRequest, 1);
2323 break;
2324
2325 case kAggressivesRequestTypeService:
2326 // synchronizeAggressives() will free request.
2327 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
2328 break;
2329
2330 default:
2331 panic("bad aggressives request type %x\n", request->dataType);
2332 break;
2333 }
2334 } while (!queue_empty(&aggressivesQueue));
2335
2336 // Release the lock to perform work, with busy flag set.
2337 if (!queue_empty(&joinedQueue) || broadcast) {
2338 AGGRESSIVES_UNLOCK();
2339 if (!queue_empty(&joinedQueue)) {
2340 synchronizeAggressives(&joinedQueue, start, count);
2341 }
2342 if (broadcast) {
2343 broadcastAggressives(start, count);
2344 }
2345 AGGRESSIVES_LOCK();
2346 }
2347
2348 // Remove the modified flag from all records.
2349 for (i = 0, record = start; i < count; i++, record++) {
2350 if ((record->flags & kAggressivesRecordFlagModified) &&
2351 ((record->type == kPMMinutesToDim) ||
2352 (record->type == kPMMinutesToSleep))) {
2353 pingSelf = true;
2354 }
2355
2356 record->flags &= ~kAggressivesRecordFlagModified;
2357 }
2358
2359 // Check the incoming queue again since new entries may have been
2360 // added while lock was released above.
2361 } while (!queue_empty(&aggressivesQueue));
2362
2363 gAggressivesState &= ~kAggressivesStateBusy;
b0d623f7
A
2364
2365unlock_done:
0a7de745 2366 AGGRESSIVES_UNLOCK();
b0d623f7 2367
0a7de745
A
2368 // Root domain is interested in system and display sleep slider changes.
2369 // Submit a power event to handle those changes on the PM work loop.
b0d623f7 2370
0a7de745
A
2371 if (pingSelf && pmPowerStateQueue) {
2372 pmPowerStateQueue->submitPowerEvent(
2373 kPowerEventPolicyStimulus,
2374 (void *) kStimulusAggressivenessChanged );
2375 }
b0d623f7
A
2376}
2377
b0d623f7
A
2378//******************************************************************************
2379// synchronizeAggressives
2380//
2381// Push all known aggressiveness records to one or more IOService.
2382//******************************************************************************
2383
0a7de745
A
2384void
2385IOPMrootDomain::synchronizeAggressives(
2386 queue_head_t * joinedQueue,
2387 const AggressivesRecord * array,
2388 int count )
2389{
f427ee49 2390 OSSharedPtr<IOService> service;
0a7de745
A
2391 AggressivesRequest * request;
2392 const AggressivesRecord * record;
2393 IOPMDriverCallEntry callEntry;
2394 uint32_t value;
2395 int i;
2396
2397 while (!queue_empty(joinedQueue)) {
2398 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
2399 if (request->dataType == kAggressivesRequestTypeService) {
f427ee49
A
2400 // retained by joinAggressiveness(), so take ownership
2401 service = os::move(request->data.service);
0a7de745 2402 } else {
f427ee49 2403 service.reset();
0a7de745
A
2404 }
2405
2406 IODelete(request, AggressivesRequest, 1);
cb323159 2407 request = NULL;
0a7de745
A
2408
2409 if (service) {
cb323159 2410 if (service->assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetAggressive)) {
0a7de745
A
2411 for (i = 0, record = array; i < count; i++, record++) {
2412 value = record->value;
2413 if (record->flags & kAggressivesRecordFlagMinValue) {
2414 value = kAggressivesMinValue;
2415 }
2416
2417 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2418 record->type, value, service->getName());
2419 service->setAggressiveness(record->type, value);
2420 }
2421 service->deassertPMDriverCall(&callEntry);
2422 }
0a7de745
A
2423 }
2424 }
b0d623f7
A
2425}
2426
b0d623f7
A
2427//******************************************************************************
2428// broadcastAggressives
2429//
2430// Traverse PM tree and call setAggressiveness() for records that have changed.
2431//******************************************************************************
2432
0a7de745
A
2433void
2434IOPMrootDomain::broadcastAggressives(
2435 const AggressivesRecord * array,
2436 int count )
2437{
f427ee49
A
2438 OSSharedPtr<IORegistryIterator> iter;
2439 IORegistryEntry *entry;
2440 OSSharedPtr<IORegistryEntry> child;
2441 IOPowerConnection *connect;
2442 IOService *service;
2443 const AggressivesRecord *record;
2444 IOPMDriverCallEntry callEntry;
2445 uint32_t value;
2446 int i;
0a7de745
A
2447
2448 iter = IORegistryIterator::iterateOver(
2449 this, gIOPowerPlane, kIORegistryIterateRecursively);
2450 if (iter) {
2451 do{
f427ee49 2452 // !! reset the iterator
0a7de745
A
2453 iter->reset();
2454 while ((entry = iter->getNextObject())) {
2455 connect = OSDynamicCast(IOPowerConnection, entry);
2456 if (!connect || !connect->getReadyFlag()) {
2457 continue;
2458 }
2459
f427ee49
A
2460 child = connect->copyChildEntry(gIOPowerPlane);
2461 if (child) {
2462 if ((service = OSDynamicCast(IOService, child.get()))) {
2463 if (service->assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetAggressive)) {
2464 for (i = 0, record = array; i < count; i++, record++) {
2465 if (record->flags & kAggressivesRecordFlagModified) {
2466 value = record->value;
2467 if (record->flags & kAggressivesRecordFlagMinValue) {
2468 value = kAggressivesMinValue;
2469 }
2470 _LOG("broadcastAggressives %x = %u to %s\n",
2471 record->type, value, service->getName());
2472 service->setAggressiveness(record->type, value);
0a7de745 2473 }
0a7de745 2474 }
f427ee49 2475 service->deassertPMDriverCall(&callEntry);
0a7de745 2476 }
0a7de745 2477 }
0a7de745
A
2478 }
2479 }
2480 }while (!entry && !iter->isValid());
0a7de745 2481 }
b0d623f7
A
2482}
2483
cb323159
A
2484//*****************************************
2485// stackshot on power button press
2486// ***************************************
2487static void
2488powerButtonDownCallout(thread_call_param_t us, thread_call_param_t )
2489{
2490 /* Power button pressed during wake
2491 * Take a stackshot
2492 */
2493 DEBUG_LOG("Powerbutton: down. Taking stackshot\n");
2494 ((IOPMrootDomain *)us)->takeStackshot(false);
2495}
2496
2497static void
2498powerButtonUpCallout(thread_call_param_t us, thread_call_param_t)
2499{
2500 /* Power button released.
2501 * Delete any stackshot data
2502 */
2503 DEBUG_LOG("PowerButton: up callout. Delete stackshot\n");
2504 ((IOPMrootDomain *)us)->deleteStackshot();
2505}
2506//*************************************************************************
2507//
2508
6d2010ae
A
2509// MARK: -
2510// MARK: System Sleep
b0d623f7
A
2511
2512//******************************************************************************
2513// startIdleSleepTimer
2514//
2515//******************************************************************************
2516
0a7de745
A
2517void
2518IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
b0d623f7 2519{
0a7de745 2520 AbsoluteTime deadline;
b0d623f7 2521
0a7de745
A
2522 ASSERT_GATED();
2523 if (gNoIdleFlag) {
2524 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
2525 return;
2526 }
2527 if (inSeconds) {
2528 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
2529 thread_call_enter_delayed(extraSleepTimer, deadline);
2530 idleSleepTimerPending = true;
2531 } else {
2532 thread_call_enter(extraSleepTimer);
2533 }
2534 DLOG("idle timer set for %u seconds\n", inSeconds);
b0d623f7
A
2535}
2536
b0d623f7
A
2537//******************************************************************************
2538// cancelIdleSleepTimer
2539//
2540//******************************************************************************
2541
0a7de745
A
2542void
2543IOPMrootDomain::cancelIdleSleepTimer( void )
2544{
2545 ASSERT_GATED();
2546 if (idleSleepTimerPending) {
2547 DLOG("idle timer cancelled\n");
2548 thread_call_cancel(extraSleepTimer);
2549 idleSleepTimerPending = false;
2550
2551 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
2552 AbsoluteTime now;
2553 clock_usec_t microsecs;
2554 clock_get_uptime(&now);
2555 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2556 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2557 if (assertOnWakeReport) {
2558 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2559 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2560 }
2561 }
2562 }
b0d623f7
A
2563}
2564
b0d623f7
A
2565//******************************************************************************
2566// idleSleepTimerExpired
2567//
2568//******************************************************************************
2569
0a7de745
A
2570static void
2571idleSleepTimerExpired(
2572 thread_call_param_t us, thread_call_param_t )
b0d623f7 2573{
0a7de745 2574 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
b0d623f7
A
2575}
2576
b0d623f7
A
2577//******************************************************************************
2578// handleSleepTimerExpiration
2579//
2580// The time between the sleep idle timeout and the next longest one has elapsed.
2581// It's time to sleep. Start that by removing the clamp that's holding us awake.
2582//******************************************************************************
2583
0a7de745
A
2584void
2585IOPMrootDomain::handleSleepTimerExpiration( void )
b0d623f7 2586{
0a7de745
A
2587 if (!gIOPMWorkLoop->inGate()) {
2588 gIOPMWorkLoop->runAction(
2589 OSMemberFunctionCast(IOWorkLoop::Action, this,
2590 &IOPMrootDomain::handleSleepTimerExpiration),
2591 this);
2592 return;
2593 }
b0d623f7 2594
0a7de745
A
2595 DLOG("sleep timer expired\n");
2596 ASSERT_GATED();
b0d623f7 2597
0a7de745 2598 idleSleepTimerPending = false;
0a7de745
A
2599 setQuickSpinDownTimeout();
2600 adjustPowerState(true);
b0d623f7
A
2601}
2602
39236c6e
A
2603//******************************************************************************
2604// getTimeToIdleSleep
2605//
2606// Returns number of seconds left before going into idle sleep.
fe8ab488 2607// Caller has to make sure that idle sleep is allowed at the time of calling
39236c6e
A
2608// this function
2609//******************************************************************************
2610
0a7de745
A
2611uint32_t
2612IOPMrootDomain::getTimeToIdleSleep( void )
39236c6e 2613{
0a7de745
A
2614 AbsoluteTime now, lastActivityTime;
2615 uint64_t nanos;
2616 uint32_t minutesSinceUserInactive = 0;
f427ee49 2617 uint32_t sleepDelay = 0;
39236c6e 2618
0a7de745
A
2619 if (!idleSleepEnabled) {
2620 return 0xffffffff;
2621 }
39236c6e 2622
0a7de745
A
2623 if (userActivityTime) {
2624 lastActivityTime = userActivityTime;
2625 } else {
2626 lastActivityTime = userBecameInactiveTime;
2627 }
39236c6e 2628
f427ee49
A
2629 // Ignore any lastActivityTime that predates the last system wake.
2630 // The goal is to avoid a sudden idle sleep right after a dark wake
2631 // due to sleepDelay=0 computed below. The alternative 60s minimum
2632 // timeout should be large enough to allow dark wake to complete,
2633 // at which point the idle timer will be promptly cancelled.
0a7de745 2634 clock_get_uptime(&now);
f427ee49
A
2635 if ((CMP_ABSOLUTETIME(&lastActivityTime, &gIOLastWakeAbsTime) >= 0) &&
2636 (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)) {
0a7de745
A
2637 SUB_ABSOLUTETIME(&now, &lastActivityTime);
2638 absolutetime_to_nanoseconds(now, &nanos);
2639 minutesSinceUserInactive = nanos / (60000000000ULL);
fe8ab488 2640
0a7de745
A
2641 if (minutesSinceUserInactive >= sleepSlider) {
2642 sleepDelay = 0;
2643 } else {
2644 sleepDelay = sleepSlider - minutesSinceUserInactive;
2645 }
2646 } else {
f427ee49
A
2647 DLOG("ignoring lastActivityTime 0x%qx, now 0x%qx, wake 0x%qx\n",
2648 lastActivityTime, now, gIOLastWakeAbsTime);
0a7de745
A
2649 sleepDelay = sleepSlider;
2650 }
39236c6e 2651
0a7de745
A
2652 DLOG("user inactive %u min, time to idle sleep %u min\n",
2653 minutesSinceUserInactive, sleepDelay);
39236c6e 2654
0a7de745 2655 return sleepDelay * 60;
39236c6e
A
2656}
2657
b0d623f7 2658//******************************************************************************
6d2010ae 2659// setQuickSpinDownTimeout
b0d623f7
A
2660//
2661//******************************************************************************
2662
0a7de745
A
2663void
2664IOPMrootDomain::setQuickSpinDownTimeout( void )
b0d623f7 2665{
0a7de745
A
2666 ASSERT_GATED();
2667 setAggressiveness(
2668 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
6d2010ae 2669}
b0d623f7 2670
6d2010ae
A
2671//******************************************************************************
2672// restoreUserSpinDownTimeout
2673//
2674//******************************************************************************
b0d623f7 2675
0a7de745
A
2676void
2677IOPMrootDomain::restoreUserSpinDownTimeout( void )
6d2010ae 2678{
0a7de745
A
2679 ASSERT_GATED();
2680 setAggressiveness(
2681 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
b0d623f7
A
2682}
2683
b0d623f7 2684//******************************************************************************
1c79356b
A
2685// sleepSystem
2686//
b0d623f7
A
2687//******************************************************************************
2688
2d21ac55 2689/* public */
0a7de745
A
2690IOReturn
2691IOPMrootDomain::sleepSystem( void )
1c79356b 2692{
0a7de745 2693 return sleepSystemOptions(NULL);
2d21ac55
A
2694}
2695
2696/* private */
0a7de745
A
2697IOReturn
2698IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2699{
2700 OSObject *obj = NULL;
2701 OSString *reason = NULL;
2702 /* sleepSystem is a public function, and may be called by any kernel driver.
2703 * And that's bad - drivers should sleep the system by calling
2704 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2705 *
2706 * Note that user space app calls to IOPMSleepSystem() will also travel
2707 * this code path and thus be correctly identified as software sleeps.
2708 */
2709
2710 if (options && options->getObject("OSSwitch")) {
2711 // Log specific sleep cause for OS Switch hibernation
2712 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2713 }
2714
2715 if (options && (obj = options->getObject("Sleep Reason"))) {
2716 reason = OSDynamicCast(OSString, obj);
2717 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey)) {
2718 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
2719 }
f427ee49
A
2720 if (reason && reason->isEqualTo(kIOPMNotificationWakeExitKey)) {
2721 return privateSleepSystem(kIOPMSleepReasonNotificationWakeExit);
2722 }
0a7de745
A
2723 }
2724
2725 return privateSleepSystem( kIOPMSleepReasonSoftware);
2d21ac55
A
2726}
2727
2728/* private */
0a7de745
A
2729IOReturn
2730IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2d21ac55 2731{
0a7de745 2732 /* Called from both gated and non-gated context */
0c530ab8 2733
0a7de745
A
2734 if (!checkSystemSleepEnabled() || !pmPowerStateQueue) {
2735 return kIOReturnNotPermitted;
2736 }
b0d623f7 2737
0a7de745
A
2738 pmPowerStateQueue->submitPowerEvent(
2739 kPowerEventPolicyStimulus,
2740 (void *) kStimulusDemandSystemSleep,
2741 sleepReason);
0b4e3aa0 2742
0a7de745 2743 return kIOReturnSuccess;
6d2010ae 2744}
1c79356b 2745
b0d623f7 2746//******************************************************************************
1c79356b
A
2747// powerChangeDone
2748//
2749// This overrides powerChangeDone in IOService.
b0d623f7 2750//******************************************************************************
0a7de745
A
2751void
2752IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
b0d623f7 2753{
5ba3f43e 2754#if !__i386__ && !__x86_64__
0a7de745 2755 uint64_t timeSinceReset = 0;
5ba3f43e 2756#endif
f427ee49
A
2757 uint64_t now;
2758 unsigned long newState;
cb323159
A
2759 clock_sec_t secs;
2760 clock_usec_t microsecs;
f427ee49 2761 uint32_t lastDebugWakeSeconds;
cb323159
A
2762 clock_sec_t adjWakeTime;
2763 IOPMCalendarStruct nowCalendar;
cb323159 2764
0a7de745 2765 ASSERT_GATED();
cb323159
A
2766 newState = getPowerState();
2767 DLOG("PowerChangeDone: %s->%s\n",
2768 getPowerStateString((uint32_t) previousPowerState), getPowerStateString((uint32_t) getPowerState()));
2769
2770 if (previousPowerState == newState) {
2771 return;
2772 }
0a7de745
A
2773
2774 notifierThread = current_thread();
2775 switch (getPowerState()) {
2776 case SLEEP_STATE: {
cb323159
A
2777 if (kPMCalendarTypeInvalid != _aotWakeTimeCalendar.selector) {
2778 secs = 0;
2779 microsecs = 0;
2780 PEGetUTCTimeOfDay(&secs, &microsecs);
2781
2782 adjWakeTime = 0;
f427ee49
A
2783 if ((kIOPMAOTModeRespectTimers & _aotMode) && (_calendarWakeAlarmUTC < _aotWakeTimeUTC)) {
2784 IOLog("use _calendarWakeAlarmUTC\n");
2785 adjWakeTime = _calendarWakeAlarmUTC;
cb323159
A
2786 } else if (_aotExit || (kIOPMWakeEventAOTExitFlags & _aotPendingFlags)) {
2787 IOLog("accelerate _aotWakeTime for exit\n");
2788 adjWakeTime = secs;
2789 } else if (kIOPMDriverAssertionLevelOn == getPMAssertionLevel(kIOPMDriverAssertionCPUBit)) {
2790 IOLog("accelerate _aotWakeTime for assertion\n");
2791 adjWakeTime = secs;
2792 }
2793 if (adjWakeTime) {
2794 IOPMConvertSecondsToCalendar(adjWakeTime, &_aotWakeTimeCalendar);
2795 }
2796
2797 IOPMConvertSecondsToCalendar(secs, &nowCalendar);
2798 IOLog("aotSleep at " YMDTF " sched: " YMDTF "\n", YMDT(&nowCalendar), YMDT(&_aotWakeTimeCalendar));
0a7de745 2799
cb323159
A
2800 IOReturn __unused ret = setMaintenanceWakeCalendar(&_aotWakeTimeCalendar);
2801 assert(kIOReturnSuccess == ret);
2802 }
2803 if (_aotLastWakeTime) {
2804 _aotMetrics->totalTime += mach_absolute_time() - _aotLastWakeTime;
2805 if (_aotMetrics->sleepCount && (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax)) {
2806 strlcpy(&_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount - 1][0],
2807 gWakeReasonString,
2808 sizeof(_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount]));
2809 }
2810 }
2811 _aotPendingFlags &= ~kIOPMWakeEventAOTPerCycleFlags;
f427ee49
A
2812 if (_aotTimerScheduled) {
2813 _aotTimerES->cancelTimeout();
2814 _aotTimerScheduled = false;
2815 }
2816 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Enable);
0a7de745
A
2817
2818 // re-enable this timer for next sleep
2819 cancelIdleSleepTimer();
2820
f427ee49
A
2821 if (clamshellExists) {
2822#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
2823 if (gClamshellFlags & kClamshell_WAR_58009435) {
2824 // Disable clamshell sleep until system has completed full wake.
2825 // This prevents a system sleep request (due to a clamshell close)
2826 // from being queued until the end of system full wake - even if
2827 // other clamshell disable bits outside of our control is wrong.
2828 setClamShellSleepDisable(true, kClamshellSleepDisableInternal);
2829 }
2830#endif
2831
2832 // Log the last known clamshell state before system sleep
2833 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
2834 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask,
2835 desktopMode, acAdaptorConnected);
2836 }
2837
0a7de745
A
2838 clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &now);
2839 logtime(secs);
2840 gIOLastSleepTime.tv_sec = secs;
2841 gIOLastSleepTime.tv_usec = microsecs;
cb323159
A
2842 if (!_aotLastWakeTime) {
2843 gIOLastUserSleepTime = gIOLastSleepTime;
2844 }
cb323159 2845
0a7de745
A
2846 gIOLastWakeTime.tv_sec = 0;
2847 gIOLastWakeTime.tv_usec = 0;
2848 gIOLastSleepAbsTime = now;
2849
2850 if (wake2DarkwakeDelay && sleepDelaysReport) {
0a7de745
A
2851 clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
2852 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2853
2854 SUB_ABSOLUTETIME(&now, &ts_sleepStart);
2855 absolutetime_to_microtime(now, &darkwake2SleepSecs, &microsecs);
2856 absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, &microsecs);
2857 HISTREPORT_TALLYVALUE(sleepDelaysReport,
2858 (int64_t)(wake2DarkwakeSecs + darkwake2SleepSecs));
2859
2860 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
2861 wake2DarkwakeDelay = 0;
2862 }
fe8ab488 2863#if HIBERNATION
0a7de745 2864 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
3a60a9f5 2865
0a7de745 2866 IOHibernateSystemHasSlept();
0b4c1975 2867
0a7de745 2868 evaluateSystemSleepPolicyFinal();
2d21ac55 2869#else
0a7de745 2870 LOG("System Sleep\n");
2d21ac55 2871#endif
0a7de745 2872 if (thermalWarningState) {
f427ee49 2873 OSSharedPtr<const OSSymbol> event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
0a7de745 2874 if (event) {
f427ee49 2875 systemPowerEventOccurred(event.get(), kIOPMThermalLevelUnknown);
0a7de745
A
2876 }
2877 }
2878 assertOnWakeSecs = 0;
2879 lowBatteryCondition = false;
f427ee49 2880 thermalEmergencyState = false;
39037602 2881
cc8bc92a 2882#if DEVELOPMENT || DEBUG
0a7de745
A
2883 extern int g_should_log_clock_adjustments;
2884 if (g_should_log_clock_adjustments) {
2885 clock_sec_t secs = 0;
2886 clock_usec_t microsecs = 0;
2887 uint64_t now_b = mach_absolute_time();
2888
cb323159
A
2889 secs = 0;
2890 microsecs = 0;
0a7de745
A
2891 PEGetUTCTimeOfDay(&secs, &microsecs);
2892
2893 uint64_t now_a = mach_absolute_time();
2894 os_log(OS_LOG_DEFAULT, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2895 __func__, (unsigned long)secs, microsecs, now_b, now_a);
2896 }
cc8bc92a
A
2897#endif
2898
0a7de745 2899 getPlatform()->sleepKernel();
b0d623f7 2900
0a7de745
A
2901 // The CPU(s) are off at this point,
2902 // Code will resume execution here upon wake.
9bccf70c 2903
0a7de745
A
2904 clock_get_uptime(&gIOLastWakeAbsTime);
2905 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
2906 _highestCapability = 0;
91447636 2907
fe8ab488 2908#if HIBERNATION
0a7de745 2909 IOHibernateSystemWake();
2d21ac55 2910#endif
9bccf70c 2911
0a7de745
A
2912 // sleep transition complete
2913 gSleepOrShutdownPending = 0;
b0d623f7 2914
0a7de745 2915 // trip the reset of the calendar clock
cb323159
A
2916 clock_wakeup_calendar();
2917 clock_get_calendar_microtime(&secs, &microsecs);
2918 gIOLastWakeTime.tv_sec = secs;
2919 gIOLastWakeTime.tv_usec = microsecs;
2920
cb323159
A
2921 // aot
2922 if (_aotWakeTimeCalendar.selector != kPMCalendarTypeInvalid) {
2923 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
2924 secs = 0;
2925 microsecs = 0;
2926 PEGetUTCTimeOfDay(&secs, &microsecs);
2927 IOPMConvertSecondsToCalendar(secs, &nowCalendar);
2928 IOLog("aotWake at " YMDTF " sched: " YMDTF "\n", YMDT(&nowCalendar), YMDT(&_aotWakeTimeCalendar));
2929 _aotMetrics->sleepCount++;
2930 _aotLastWakeTime = gIOLastWakeAbsTime;
2931 if (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax) {
2932 _aotMetrics->kernelSleepTime[_aotMetrics->sleepCount - 1]
2933 = (((uint64_t) gIOLastSleepTime.tv_sec) << 10) + (gIOLastSleepTime.tv_usec / 1000);
2934 _aotMetrics->kernelWakeTime[_aotMetrics->sleepCount - 1]
2935 = (((uint64_t) gIOLastWakeTime.tv_sec) << 10) + (gIOLastWakeTime.tv_usec / 1000);
2936 }
2937
2938 if (_aotTestTime) {
2939 if (_aotWakeTimeUTC <= secs) {
2940 _aotTestTime = _aotTestTime + _aotTestInterval;
2941 }
2942 setWakeTime(_aotTestTime);
2943 }
0a7de745 2944 }
b0d623f7 2945
fe8ab488 2946#if HIBERNATION
0a7de745 2947 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2d21ac55 2948#endif
b0d623f7 2949
0a7de745 2950 lastSleepReason = 0;
fe8ab488 2951
f427ee49
A
2952 lastDebugWakeSeconds = _debugWakeSeconds;
2953 _debugWakeSeconds = 0;
2954 _scheduledAlarmMask = 0;
2955 _nextScheduledAlarmType = NULL;
6d2010ae 2956
f427ee49
A
2957 darkWakeExit = false;
2958 darkWakePowerClamped = false;
0a7de745
A
2959 darkWakePostTickle = false;
2960 darkWakeHibernateError = false;
2961 darkWakeToSleepASAP = true;
f427ee49 2962 darkWakeLogClamp = true;
0a7de745
A
2963 sleepTimerMaintenance = false;
2964 sleepToStandby = false;
f427ee49 2965 wranglerTickled = false;
0a7de745 2966 userWasActive = false;
cb323159 2967 isRTCAlarmWake = false;
f427ee49 2968 clamshellIgnoreClose = false;
0a7de745
A
2969 fullWakeReason = kFullWakeReasonNone;
2970
f427ee49
A
2971#if defined(__i386__) || defined(__x86_64__)
2972 kdebugTrace(kPMLogSystemWake, 0, 0, 0);
2973
2974 OSSharedPtr<OSObject> wakeTypeProp = copyProperty(kIOPMRootDomainWakeTypeKey);
2975 OSSharedPtr<OSObject> wakeReasonProp = copyProperty(kIOPMRootDomainWakeReasonKey);
2976 OSString * wakeType = OSDynamicCast(OSString, wakeTypeProp.get());
2977 OSString * wakeReason = OSDynamicCast(OSString, wakeReasonProp.get());
0a7de745
A
2978
2979 if (wakeReason && (wakeReason->getLength() >= 2) &&
2980 gWakeReasonString[0] == '\0') {
f427ee49 2981 WAKEEVENT_LOCK();
0a7de745
A
2982 // Until the platform driver can claim its wake reasons
2983 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
2984 sizeof(gWakeReasonString));
c3c9b80d
A
2985 if (!gWakeReasonSysctlRegistered) {
2986 gWakeReasonSysctlRegistered = true;
2987 }
f427ee49 2988 WAKEEVENT_UNLOCK();
0a7de745
A
2989 }
2990
2991 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery)) {
2992 lowBatteryCondition = true;
2993 darkWakeMaintenance = true;
f427ee49 2994 } else {
3e170ce0 2995#if HIBERNATION
f427ee49
A
2996 OSSharedPtr<OSObject> hibOptionsProp = copyProperty(kIOHibernateOptionsKey);
2997 OSNumber * hibOptions = OSDynamicCast( OSNumber, hibOptionsProp.get());
0a7de745
A
2998 if (hibernateAborted || ((hibOptions &&
2999 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)))) {
3000 // Hibernate aborted, or EFI brought up graphics
f427ee49 3001 darkWakeExit = true;
cb323159
A
3002 if (hibernateAborted) {
3003 DLOG("Hibernation aborted\n");
3004 } else {
3005 DLOG("EFI brought up graphics. Going to full wake. HibOptions: 0x%x\n", hibOptions->unsigned32BitValue());
3006 }
0a7de745 3007 } else
3e170ce0 3008#endif
0a7de745
A
3009 if (wakeType && (
3010 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
3011 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))) {
3012 // User wake or RTC alarm
f427ee49 3013 darkWakeExit = true;
cb323159
A
3014 if (wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)) {
3015 isRTCAlarmWake = true;
3016 }
0a7de745
A
3017 } else if (wakeType &&
3018 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer)) {
3019 // SMC standby timer trumps SleepX
3020 darkWakeMaintenance = true;
3021 sleepTimerMaintenance = true;
f427ee49 3022 } else if ((lastDebugWakeSeconds != 0) &&
0a7de745
A
3023 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) {
3024 // SleepX before maintenance
f427ee49 3025 darkWakeExit = true;
0a7de745
A
3026 } else if (wakeType &&
3027 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance)) {
3028 darkWakeMaintenance = true;
3029 } else if (wakeType &&
3030 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService)) {
3031 darkWakeMaintenance = true;
3032 darkWakeSleepService = true;
3e170ce0 3033#if HIBERNATION
0a7de745
A
3034 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
3035 sleepToStandby = true;
3036 }
3e170ce0 3037#endif
0a7de745
A
3038 } else if (wakeType &&
3039 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError)) {
3040 darkWakeMaintenance = true;
3041 darkWakeHibernateError = true;
3042 } else {
3043 // Unidentified wake source, resume to full wake if debug
3044 // alarm is pending.
3045
f427ee49 3046 if (lastDebugWakeSeconds &&
0a7de745 3047 (!wakeReason || wakeReason->isEqualTo(""))) {
f427ee49 3048 darkWakeExit = true;
0a7de745
A
3049 }
3050 }
0a7de745
A
3051 }
3052
f427ee49 3053 if (darkWakeExit) {
0a7de745
A
3054 darkWakeToSleepASAP = false;
3055 fullWakeReason = kFullWakeReasonLocalUser;
3056 reportUserInput();
3057 } else if (displayPowerOnRequested && checkSystemCanSustainFullWake()) {
f427ee49 3058 handleSetDisplayPowerOn(true);
0a7de745
A
3059 } else if (!darkWakeMaintenance) {
3060 // Early/late tickle for non-maintenance wake.
f427ee49 3061 if ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) != kDarkWakeFlagPromotionNone) {
0a7de745
A
3062 darkWakePostTickle = true;
3063 }
3064 }
6d2010ae 3065#else /* !__i386__ && !__x86_64__ */
0a7de745 3066 timeSinceReset = ml_get_time_since_reset();
f427ee49
A
3067 kdebugTrace(kPMLogSystemWake, 0, (uintptr_t)(timeSinceReset >> 32), (uintptr_t) timeSinceReset);
3068
3069 if ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) == kDarkWakeFlagPromotionEarly) {
3070 wranglerTickled = true;
3071 fullWakeReason = kFullWakeReasonLocalUser;
3072 requestUserActive(this, "Full wake on dark wake promotion boot-arg");
3073 } else if ((lastDebugWakeSeconds != 0) && !(gDarkWakeFlags & kDarkWakeFlagAlarmIsDark)) {
3074 isRTCAlarmWake = true;
3075 fullWakeReason = kFullWakeReasonLocalUser;
3076 requestUserActive(this, "RTC debug alarm");
a991bd8d
A
3077 } else {
3078#if HIBERNATION
3079 OSSharedPtr<OSObject> hibOptionsProp = copyProperty(kIOHibernateOptionsKey);
3080 OSNumber * hibOptions = OSDynamicCast(OSNumber, hibOptionsProp.get());
3081 if (hibOptions && !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)) {
3082 fullWakeReason = kFullWakeReasonLocalUser;
3083 requestUserActive(this, "hibernate user wake");
3084 }
3085#endif
f427ee49 3086 }
5ba3f43e 3087
0a7de745 3088 // stay awake for at least 30 seconds
0a7de745 3089 startIdleSleepTimer(30);
6d2010ae 3090#endif
0a7de745 3091 sleepCnt++;
6d2010ae 3092
0a7de745 3093 thread_call_enter(updateConsoleUsersEntry);
3e170ce0 3094
f427ee49 3095 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonWake);
cb323159
A
3096 break;
3097 }
3e170ce0 3098#if !__i386__ && !__x86_64__
cb323159
A
3099 case ON_STATE:
3100 case AOT_STATE:
3101 {
3102 DLOG("Force re-evaluating aggressiveness\n");
3103 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
3104 pmPowerStateQueue->submitPowerEvent(
3105 kPowerEventPolicyStimulus,
3106 (void *) kStimulusNoIdleSleepPreventers );
3107
3108 // After changing to ON_STATE, invalidate any previously queued
3109 // request to change to a state less than ON_STATE. This isn't
3110 // necessary for AOT_STATE or if the device has only one running
3111 // state since the changePowerStateToPriv() issued at the tail
3112 // end of SLEEP_STATE case should take care of that.
3113 if (getPowerState() == ON_STATE) {
f427ee49 3114 changePowerStateWithTagToPriv(ON_STATE, kCPSReasonWake);
0a7de745
A
3115 }
3116 break;
3117 }
cb323159 3118#endif /* !__i386__ && !__x86_64__ */
0a7de745
A
3119 }
3120 notifierThread = NULL;
0b4e3aa0
A
3121}
3122
b0d623f7 3123//******************************************************************************
6d2010ae 3124// requestPowerDomainState
0b4e3aa0 3125//
6d2010ae 3126// Extend implementation in IOService. Running on PM work loop thread.
b0d623f7
A
3127//******************************************************************************
3128
0a7de745
A
3129IOReturn
3130IOPMrootDomain::requestPowerDomainState(
3131 IOPMPowerFlags childDesire,
3132 IOPowerConnection * childConnection,
3133 unsigned long specification )
1c79356b 3134{
0a7de745
A
3135 // Idle and system sleep prevention flags affects driver desire.
3136 // Children desire are irrelevant so they are cleared.
316670eb 3137
0a7de745 3138 return super::requestPowerDomainState(0, childConnection, specification);
316670eb
A
3139}
3140
3e170ce0 3141
f427ee49
A
3142static void
3143makeSleepPreventersListLog(const OSSharedPtr<OSSet> &preventers, char *buf, size_t buf_size)
3144{
3145 if (!preventers->getCount()) {
3146 return;
3147 }
3148
3149 char *buf_iter = buf + strlen(buf);
3150 char *buf_end = buf + buf_size;
3151
3152 OSSharedPtr<OSCollectionIterator> iterator = OSCollectionIterator::withCollection(preventers.get());
3153 OSObject *obj = NULL;
3154
3155 while ((obj = iterator->getNextObject())) {
3156 IOService *srv = OSDynamicCast(IOService, obj);
3157 if (buf_iter < buf_end) {
3158 buf_iter += snprintf(buf_iter, buf_end - buf_iter, " %s", srv->getName());
3159 } else {
3160 DLOG("Print buffer exhausted for sleep preventers list\n");
3161 break;
3162 }
3163 }
3164}
3165
316670eb
A
3166//******************************************************************************
3167// updatePreventIdleSleepList
3168//
3169// Called by IOService on PM work loop.
39236c6e
A
3170// Returns true if PM policy recognized the driver's desire to prevent idle
3171// sleep and updated the list of idle sleep preventers. Returns false otherwise
316670eb
A
3172//******************************************************************************
3173
0a7de745
A
3174bool
3175IOPMrootDomain::updatePreventIdleSleepList(
cb323159 3176 IOService * service, bool addNotRemove)
316670eb 3177{
cb323159
A
3178 unsigned int oldCount;
3179
3180 oldCount = idleSleepPreventersCount();
3181 return updatePreventIdleSleepListInternal(service, addNotRemove, oldCount);
3182}
3183
3184bool
3185IOPMrootDomain::updatePreventIdleSleepListInternal(
3186 IOService * service, bool addNotRemove, unsigned int oldCount)
3187{
3188 unsigned int newCount;
6d2010ae 3189
0a7de745 3190 ASSERT_GATED();
6d2010ae 3191
f427ee49
A
3192#if defined(XNU_TARGET_OS_OSX)
3193 // Only the display wrangler and no-idle-sleep kernel assertions
3194 // can prevent idle sleep. The kIOPMPreventIdleSleep capability flag
3195 // reported by drivers in their power state table is ignored.
cb323159 3196 if (service && (service != wrangler) && (service != this)) {
0a7de745
A
3197 return false;
3198 }
39236c6e 3199#endif
fe8ab488 3200
cb323159
A
3201 if (service) {
3202 if (addNotRemove) {
3203 preventIdleSleepList->setObject(service);
f427ee49 3204 DLOG("Added %s to idle sleep preventers list (Total %u)\n",
cb323159
A
3205 service->getName(), preventIdleSleepList->getCount());
3206 } else if (preventIdleSleepList->member(service)) {
3207 preventIdleSleepList->removeObject(service);
f427ee49 3208 DLOG("Removed %s from idle sleep preventers list (Total %u)\n",
cb323159
A
3209 service->getName(), preventIdleSleepList->getCount());
3210 }
f427ee49
A
3211
3212 if (preventIdleSleepList->getCount()) {
3213 char buf[256] = "Idle Sleep Preventers:";
3214 makeSleepPreventersListLog(preventIdleSleepList, buf, sizeof(buf));
3215 DLOG("%s\n", buf);
3216 }
0a7de745 3217 }
f427ee49 3218
cb323159 3219 newCount = idleSleepPreventersCount();
0a7de745
A
3220
3221 if ((oldCount == 0) && (newCount != 0)) {
3222 // Driver added to empty prevent list.
3223 // Update the driver desire to prevent idle sleep.
3224 // Driver desire does not prevent demand sleep.
3225
f427ee49 3226 changePowerStateWithTagTo(getRUN_STATE(), kCPSReasonIdleSleepPrevent);
0a7de745
A
3227 } else if ((oldCount != 0) && (newCount == 0)) {
3228 // Last driver removed from prevent list.
3229 // Drop the driver clamp to allow idle sleep.
3230
f427ee49 3231 changePowerStateWithTagTo(SLEEP_STATE, kCPSReasonIdleSleepAllow);
0a7de745
A
3232 evaluatePolicy( kStimulusNoIdleSleepPreventers );
3233 }
f427ee49 3234 messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier.get(),
0a7de745 3235 &newCount, sizeof(newCount));
39236c6e 3236
f427ee49 3237#if defined(XNU_TARGET_OS_OSX)
0a7de745
A
3238 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake()) {
3239 DLOG("Cannot cancel idle sleep\n");
3240 return false; // do not idle-cancel
3241 }
39236c6e
A
3242#endif
3243
0a7de745 3244 return true;
316670eb 3245}
0c530ab8 3246
5ba3f43e
A
3247//******************************************************************************
3248// startSpinDump
3249//******************************************************************************
3250
0a7de745
A
3251void
3252IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
5ba3f43e 3253{
0a7de745 3254 messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
5ba3f43e
A
3255}
3256
316670eb
A
3257//******************************************************************************
3258// preventSystemSleepListUpdate
3259//
3260// Called by IOService on PM work loop.
3261//******************************************************************************
0c530ab8 3262
0a7de745
A
3263void
3264IOPMrootDomain::updatePreventSystemSleepList(
3265 IOService * service, bool addNotRemove )
3266{
3267 unsigned int oldCount, newCount;
0c530ab8 3268
0a7de745
A
3269 ASSERT_GATED();
3270 if (this == service) {
3271 return;
3272 }
3273
3274 oldCount = preventSystemSleepList->getCount();
3275 if (addNotRemove) {
3276 preventSystemSleepList->setObject(service);
f427ee49 3277 DLOG("Added %s to system sleep preventers list (Total %u)\n",
0a7de745
A
3278 service->getName(), preventSystemSleepList->getCount());
3279 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3280 AbsoluteTime now;
3281 clock_usec_t microsecs;
3282 clock_get_uptime(&now);
3283 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3284 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
3285 if (assertOnWakeReport) {
3286 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
3287 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
3288 }
3289 }
3290 } else if (preventSystemSleepList->member(service)) {
3291 preventSystemSleepList->removeObject(service);
f427ee49 3292 DLOG("Removed %s from system sleep preventers list (Total %u)\n",
0a7de745
A
3293 service->getName(), preventSystemSleepList->getCount());
3294
3295 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0)) {
3296 // Lost all system sleep preventers.
3297 // Send stimulus if system sleep was blocked, and is in dark wake.
3298 evaluatePolicy( kStimulusDarkWakeEvaluate );
3299 }
3300 }
f427ee49 3301
0a7de745 3302 newCount = preventSystemSleepList->getCount();
f427ee49
A
3303 if (newCount) {
3304 char buf[256] = "System Sleep Preventers:";
3305 makeSleepPreventersListLog(preventSystemSleepList, buf, sizeof(buf));
3306 DLOG("%s\n", buf);
3307 }
3308
3309 messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier.get(),
0a7de745
A
3310 &newCount, sizeof(newCount));
3311}
b0d623f7 3312
0a7de745
A
3313void
3314IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
0c530ab8 3315{
f427ee49 3316 OSSharedPtr<OSCollectionIterator> iterator;
0a7de745 3317 OSObject *object = NULL;
f427ee49 3318 OSSharedPtr<OSArray> array;
0c530ab8 3319
0a7de745
A
3320 if (!gIOPMWorkLoop->inGate()) {
3321 gIOPMWorkLoop->runAction(
3322 OSMemberFunctionCast(IOWorkLoop::Action, this,
3323 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
3324 this, (void *)idleSleepList, (void *)systemSleepList);
3325 return;
3326 }
6d2010ae 3327
0a7de745 3328 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0)) {
f427ee49 3329 iterator = OSCollectionIterator::withCollection(preventIdleSleepList.get());
0a7de745 3330 array = OSArray::withCapacity(5);
0c530ab8 3331
f427ee49
A
3332 if (iterator && array) {
3333 while ((object = iterator->getNextObject())) {
3334 IOService *service = OSDynamicCast(IOService, object);
3335 if (service) {
3336 OSSharedPtr<const OSSymbol> name = service->copyName();
3337 if (name) {
3338 array->setObject(name.get());
3339 }
3340 }
0a7de745
A
3341 }
3342 }
f427ee49 3343 *idleSleepList = array.detach();
0a7de745 3344 }
0c530ab8 3345
0a7de745 3346 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0)) {
f427ee49 3347 iterator = OSCollectionIterator::withCollection(preventSystemSleepList.get());
0a7de745 3348 array = OSArray::withCapacity(5);
5ba3f43e 3349
f427ee49
A
3350 if (iterator && array) {
3351 while ((object = iterator->getNextObject())) {
3352 IOService *service = OSDynamicCast(IOService, object);
3353 if (service) {
3354 OSSharedPtr<const OSSymbol> name = service->copyName();
3355 if (name) {
3356 array->setObject(name.get());
3357 }
3358 }
0a7de745
A
3359 }
3360 }
f427ee49 3361 *systemSleepList = array.detach();
0a7de745 3362 }
6d2010ae 3363}
5d5c5d0d 3364
cb323159
A
3365void
3366IOPMrootDomain::copySleepPreventersListWithID(OSArray **idleSleepList, OSArray **systemSleepList)
3367{
f427ee49 3368 OSSharedPtr<OSCollectionIterator> iterator;
cb323159 3369 OSObject *object = NULL;
f427ee49 3370 OSSharedPtr<OSArray> array;
cb323159
A
3371
3372 if (!gIOPMWorkLoop->inGate()) {
3373 gIOPMWorkLoop->runAction(
3374 OSMemberFunctionCast(IOWorkLoop::Action, this,
3375 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersListWithID),
3376 this, (void *)idleSleepList, (void *)systemSleepList);
3377 return;
3378 }
3379
3380 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0)) {
f427ee49 3381 iterator = OSCollectionIterator::withCollection(preventIdleSleepList.get());
cb323159
A
3382 array = OSArray::withCapacity(5);
3383
f427ee49
A
3384 if (iterator && array) {
3385 while ((object = iterator->getNextObject())) {
3386 IOService *service = OSDynamicCast(IOService, object);
3387 if (service) {
3388 OSSharedPtr<OSDictionary> dict = OSDictionary::withCapacity(2);
3389 OSSharedPtr<const OSSymbol> name = service->copyName();
3390 OSSharedPtr<OSNumber> id = OSNumber::withNumber(service->getRegistryEntryID(), 64);
3391 if (dict && name && id) {
3392 dict->setObject(kIOPMDriverAssertionRegistryEntryIDKey, id.get());
3393 dict->setObject(kIOPMDriverAssertionOwnerStringKey, name.get());
3394 array->setObject(dict.get());
3395 }
cb323159
A
3396 }
3397 }
3398 }
f427ee49 3399 *idleSleepList = array.detach();
cb323159
A
3400 }
3401
3402 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0)) {
f427ee49 3403 iterator = OSCollectionIterator::withCollection(preventSystemSleepList.get());
cb323159
A
3404 array = OSArray::withCapacity(5);
3405
f427ee49
A
3406 if (iterator && array) {
3407 while ((object = iterator->getNextObject())) {
3408 IOService *service = OSDynamicCast(IOService, object);
3409 if (service) {
3410 OSSharedPtr<OSDictionary> dict = OSDictionary::withCapacity(2);
3411 OSSharedPtr<const OSSymbol> name = service->copyName();
3412 OSSharedPtr<OSNumber> id = OSNumber::withNumber(service->getRegistryEntryID(), 64);
3413 if (dict && name && id) {
3414 dict->setObject(kIOPMDriverAssertionRegistryEntryIDKey, id.get());
3415 dict->setObject(kIOPMDriverAssertionOwnerStringKey, name.get());
3416 array->setObject(dict.get());
3417 }
cb323159
A
3418 }
3419 }
3420 }
f427ee49 3421 *systemSleepList = array.detach();
cb323159
A
3422 }
3423}
3424
b0d623f7 3425//******************************************************************************
0a7de745 3426// tellChangeDown
0c530ab8 3427//
6d2010ae 3428// Override the superclass implementation to send a different message type.
b0d623f7
A
3429//******************************************************************************
3430
0a7de745
A
3431bool
3432IOPMrootDomain::tellChangeDown( unsigned long stateNum )
55e303ae 3433{
cb323159
A
3434 DLOG("tellChangeDown %s->%s\n",
3435 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
0c530ab8 3436
0a7de745
A
3437 if (SLEEP_STATE == stateNum) {
3438 // Legacy apps were already told in the full->dark transition
3439 if (!ignoreTellChangeDown) {
3440 tracePoint( kIOPMTracePointSleepApplications );
3441 } else {
3442 tracePoint( kIOPMTracePointSleepPriorityClients );
3443 }
3444 }
3445
3446 if (!ignoreTellChangeDown) {
3447 userActivityAtSleep = userActivityCount;
3448 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
3449
3450 if (SLEEP_STATE == stateNum) {
3451 hibernateAborted = false;
3452
3453 // Direct callout into OSKext so it can disable kext unloads
3454 // during sleep/wake to prevent deadlocks.
3455 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
3456
3457 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
3458
3459 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3460 // But tellClientsWithResponse() must be called for both.
3461 ignoreTellChangeDown = true;
3462 }
3463 }
3464
3465 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
3466}
3467
3468//******************************************************************************
3469// askChangeDown
3470//
3471// Override the superclass implementation to send a different message type.
3472// This must be idle sleep since we don't ask during any other power change.
3473//******************************************************************************
3474
3475bool
3476IOPMrootDomain::askChangeDown( unsigned long stateNum )
3477{
cb323159
A
3478 DLOG("askChangeDown %s->%s\n",
3479 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
0a7de745
A
3480
3481 // Don't log for dark wake entry
3482 if (kSystemTransitionSleep == _systemTransitionType) {
3483 tracePoint( kIOPMTracePointSleepApplications );
3484 }
3485
3486 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
3487}
1c79356b 3488
b0d623f7 3489//******************************************************************************
6d2010ae 3490// askChangeDownDone
0c530ab8 3491//
39236c6e
A
3492// An opportunity for root domain to cancel the power transition,
3493// possibily due to an assertion created by powerd in response to
3494// kIOMessageCanSystemSleep.
3495//
3496// Idle sleep:
3497// full -> dark wake transition
3498// 1. Notify apps and powerd with kIOMessageCanSystemSleep
3499// 2. askChangeDownDone()
3500// dark -> sleep transition
3501// 1. Notify powerd with kIOMessageCanSystemSleep
3502// 2. askChangeDownDone()
3503//
3504// Demand sleep:
3505// full -> dark wake transition
3506// 1. Notify powerd with kIOMessageCanSystemSleep
3507// 2. askChangeDownDone()
3508// dark -> sleep transition
3509// 1. Notify powerd with kIOMessageCanSystemSleep
3510// 2. askChangeDownDone()
b0d623f7
A
3511//******************************************************************************
3512
0a7de745
A
3513void
3514IOPMrootDomain::askChangeDownDone(
3515 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
e5568f75 3516{
0a7de745
A
3517 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
3518 *inOutChangeFlags, *cancel,
3519 _systemTransitionType,
3520 _currentCapability, _pendingCapability);
0c530ab8 3521
0a7de745
A
3522 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType)) {
3523 // Dark->Sleep transition.
3524 // Check if there are any deny sleep assertions.
3525 // lastSleepReason already set by handleOurPowerChangeStart()
0c530ab8 3526
0a7de745
A
3527 if (!checkSystemCanSleep(lastSleepReason)) {
3528 // Cancel dark wake to sleep transition.
3529 // Must re-scan assertions upon entering dark wake.
0c530ab8 3530
0a7de745
A
3531 *cancel = true;
3532 DLOG("cancel dark->sleep\n");
3533 }
cb323159
A
3534 if (_aotMode && (kPMCalendarTypeInvalid != _aotWakeTimeCalendar.selector)) {
3535 uint64_t now = mach_continuous_time();
3536 if (((now + _aotWakePreWindow) >= _aotWakeTimeContinuous)
3537 && (now < (_aotWakeTimeContinuous + _aotWakePostWindow))) {
3538 *cancel = true;
3539 IOLog("AOT wake window cancel: %qd, %qd\n", now, _aotWakeTimeContinuous);
3540 }
3541 }
0a7de745 3542 }
e5568f75
A
3543}
3544
22ba694c
A
3545//******************************************************************************
3546// systemDidNotSleep
3547//
3548// Work common to both canceled or aborted sleep.
3549//******************************************************************************
3550
0a7de745
A
3551void
3552IOPMrootDomain::systemDidNotSleep( void )
22ba694c 3553{
0a7de745
A
3554 // reset console lock state
3555 thread_call_enter(updateConsoleUsersEntry);
3e170ce0 3556
f427ee49
A
3557 if (idleSleepEnabled) {
3558 if (!wrangler) {
3559#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
3560 startIdleSleepTimer(kIdleSleepRetryInterval);
3561#else
0a7de745 3562 startIdleSleepTimer(idleSeconds);
f427ee49
A
3563#endif
3564 } else if (!userIsActive) {
0a7de745
A
3565 // Manually start the idle sleep timer besides waiting for
3566 // the user to become inactive.
f427ee49 3567 startIdleSleepTimer(kIdleSleepRetryInterval);
0a7de745
A
3568 }
3569 }
22ba694c 3570
0a7de745
A
3571 preventTransitionToUserActive(false);
3572 IOService::setAdvisoryTickleEnable( true );
3e170ce0 3573
0a7de745
A
3574 // After idle revert and cancel, send a did-change message to powerd
3575 // to balance the previous will-change message. Kernel clients do not
3576 // need this since sleep cannot be canceled once they are notified.
3e170ce0 3577
0a7de745
A
3578 if (toldPowerdCapWillChange && systemCapabilityNotifier &&
3579 (_pendingCapability != _currentCapability) &&
3580 ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0)) {
3581 // Differs from a real capability gain change where notifyRef != 0,
3582 // but it is zero here since no response is expected.
3e170ce0 3583
0a7de745 3584 IOPMSystemCapabilityChangeParameters params;
3e170ce0 3585
0a7de745
A
3586 bzero(&params, sizeof(params));
3587 params.fromCapabilities = _pendingCapability;
3588 params.toCapabilities = _currentCapability;
3589 params.changeFlags = kIOPMSystemCapabilityDidChange;
3e170ce0 3590
0a7de745
A
3591 DLOG("MESG cap %x->%x did change\n",
3592 params.fromCapabilities, params.toCapabilities);
f427ee49 3593 messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier.get(),
0a7de745
A
3594 &params, sizeof(params));
3595 }
22ba694c
A
3596}
3597
b0d623f7 3598//******************************************************************************
6d2010ae 3599// tellNoChangeDown
0c530ab8 3600//
6d2010ae
A
3601// Notify registered applications and kernel clients that we are not dropping
3602// power.
3603//
3604// We override the superclass implementation so we can send a different message
3605// type to the client or application being notified.
3606//
3607// This must be a vetoed idle sleep, since no other power change can be vetoed.
3608//******************************************************************************
4452a7af 3609
0a7de745
A
3610void
3611IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
6d2010ae 3612{
cb323159
A
3613 DLOG("tellNoChangeDown %s->%s\n",
3614 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
0c530ab8 3615
0a7de745
A
3616 // Sleep canceled, clear the sleep trace point.
3617 tracePoint(kIOPMTracePointSystemUp);
316670eb 3618
0a7de745
A
3619 systemDidNotSleep();
3620 return tellClients( kIOMessageSystemWillNotSleep );
0c530ab8
A
3621}
3622
b0d623f7 3623//******************************************************************************
6d2010ae 3624// tellChangeUp
1c79356b 3625//
6d2010ae
A
3626// Notify registered applications and kernel clients that we are raising power.
3627//
3628// We override the superclass implementation so we can send a different message
3629// type to the client or application being notified.
b0d623f7
A
3630//******************************************************************************
3631
0a7de745
A
3632void
3633IOPMrootDomain::tellChangeUp( unsigned long stateNum )
0c530ab8 3634{
cb323159
A
3635 DLOG("tellChangeUp %s->%s\n",
3636 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum));
6d2010ae 3637
0a7de745 3638 ignoreTellChangeDown = false;
6d2010ae 3639
0a7de745
A
3640 if (stateNum == ON_STATE) {
3641 // Direct callout into OSKext so it can disable kext unloads
3642 // during sleep/wake to prevent deadlocks.
3643 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
6d2010ae 3644
0a7de745
A
3645 // Notify platform that sleep was cancelled or resumed.
3646 getPlatform()->callPlatformFunction(
f427ee49 3647 sleepMessagePEFunction.get(), false,
0a7de745
A
3648 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
3649 NULL, NULL, NULL);
6d2010ae 3650
0a7de745 3651 if (getPowerState() == ON_STATE) {
cb323159
A
3652 // Sleep was cancelled by idle cancel or revert
3653 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
3654 // rdar://problem/50363791
3655 // If system is in dark wake and sleep is cancelled, do not
3656 // send SystemWillPowerOn/HasPoweredOn messages to kernel
3657 // priority clients. They haven't yet seen a SystemWillSleep
3658 // message before the cancellation. So make sure the kernel
3659 // client bit is cleared in _systemMessageClientMask before
3660 // invoking the tellClients() below. This bit may have been
3661 // set by handleOurPowerChangeStart() anticipating a successful
3662 // sleep and setting the filter mask ahead of time allows the
3663 // SystemWillSleep message to go through.
3664 _systemMessageClientMask &= ~kSystemMessageClientKernel;
3665 }
3666
0a7de745
A
3667 systemDidNotSleep();
3668 tellClients( kIOMessageSystemWillPowerOn );
3669 }
6d2010ae 3670
0a7de745
A
3671 tracePoint( kIOPMTracePointWakeApplications );
3672 tellClients( kIOMessageSystemHasPoweredOn );
3673 }
6d2010ae 3674}
b0d623f7 3675
39037602
A
3676#define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3677 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3678 ((params)->fromCapabilities & (flag)) && \
3679 (((params)->toCapabilities & (flag)) == 0))
3680
3681#define CAP_DID_CHANGE_TO_ON(params, flag) \
3682 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3683 ((params)->toCapabilities & (flag)) && \
3684 (((params)->fromCapabilities & (flag)) == 0))
3685
3686#define CAP_DID_CHANGE_TO_OFF(params, flag) \
3687 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3688 ((params)->fromCapabilities & (flag)) && \
3689 (((params)->toCapabilities & (flag)) == 0))
3690
3691#define CAP_WILL_CHANGE_TO_ON(params, flag) \
3692 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3693 ((params)->toCapabilities & (flag)) && \
3694 (((params)->fromCapabilities & (flag)) == 0))
3695
b0d623f7 3696//******************************************************************************
6d2010ae 3697// sysPowerDownHandler
0c530ab8 3698//
6d2010ae 3699// Perform a vfs sync before system sleep.
b0d623f7
A
3700//******************************************************************************
3701
0a7de745
A
3702IOReturn
3703IOPMrootDomain::sysPowerDownHandler(
3704 void * target, void * refCon,
3705 UInt32 messageType, IOService * service,
3706 void * messageArgs, vm_size_t argSize )
1c79356b 3707{
cb323159 3708 static UInt32 lastSystemMessageType = 0;
0a7de745 3709 IOReturn ret = 0;
0c530ab8 3710
0a7de745 3711 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
6d2010ae 3712
cb323159
A
3713 // rdar://problem/50363791
3714 // Sanity check to make sure the SystemWill/Has message types are
3715 // received in the expected order for all kernel priority clients.
3716 if (messageType == kIOMessageSystemWillSleep ||
3717 messageType == kIOMessageSystemWillPowerOn ||
3718 messageType == kIOMessageSystemHasPoweredOn) {
3719 switch (messageType) {
3720 case kIOMessageSystemWillPowerOn:
3721 assert(lastSystemMessageType == kIOMessageSystemWillSleep);
3722 break;
3723 case kIOMessageSystemHasPoweredOn:
3724 assert(lastSystemMessageType == kIOMessageSystemWillPowerOn);
3725 break;
3726 }
3727
3728 lastSystemMessageType = messageType;
3729 }
3730
0a7de745
A
3731 if (!gRootDomain) {
3732 return kIOReturnUnsupported;
3733 }
6d2010ae 3734
0a7de745
A
3735 if (messageType == kIOMessageSystemCapabilityChange) {
3736 IOPMSystemCapabilityChangeParameters * params =
3737 (IOPMSystemCapabilityChangeParameters *) messageArgs;
6d2010ae 3738
0a7de745
A
3739 // Interested applications have been notified of an impending power
3740 // change and have acked (when applicable).
3741 // This is our chance to save whatever state we can before powering
3742 // down.
3743 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3744 // via callout
6d2010ae 3745
0a7de745
A
3746 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3747 params->fromCapabilities, params->toCapabilities,
3748 params->changeFlags);
6d2010ae 3749
0a7de745
A
3750 if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU)) {
3751 // We will ack within 20 seconds
3752 params->maxWaitForReply = 20 * 1000 * 1000;
39037602 3753
fe8ab488 3754#if HIBERNATION
0a7de745
A
3755 gRootDomain->evaluateSystemSleepPolicyEarly();
3756
3757 // add in time we could spend freeing pages
3758 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled) {
3759 params->maxWaitForReply = kCapabilityClientMaxWait;
3760 }
3761 DLOG("sysPowerDownHandler max wait %d s\n",
3762 (int) (params->maxWaitForReply / 1000 / 1000));
6d2010ae
A
3763#endif
3764
0a7de745
A
3765 // Notify platform that sleep has begun, after the early
3766 // sleep policy evaluation.
3767 getPlatform()->callPlatformFunction(
f427ee49 3768 sleepMessagePEFunction.get(), false,
0a7de745
A
3769 (void *)(uintptr_t) kIOMessageSystemWillSleep,
3770 NULL, NULL, NULL);
3771
3772 if (!OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending )) {
3773 // Purposely delay the ack and hope that shutdown occurs quickly.
3774 // Another option is not to schedule the thread and wait for
3775 // ack timeout...
3776 AbsoluteTime deadline;
3777 clock_interval_to_deadline( 30, kSecondScale, &deadline );
3778 thread_call_enter1_delayed(
3779 gRootDomain->diskSyncCalloutEntry,
3780 (thread_call_param_t)(uintptr_t) params->notifyRef,
3781 deadline );
3782 } else {
3783 thread_call_enter1(
3784 gRootDomain->diskSyncCalloutEntry,
3785 (thread_call_param_t)(uintptr_t) params->notifyRef);
3786 }
3787 }
fe8ab488 3788#if HIBERNATION
0a7de745
A
3789 else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU)) {
3790 // We will ack within 110 seconds
3791 params->maxWaitForReply = 110 * 1000 * 1000;
3792
3793 thread_call_enter1(
3794 gRootDomain->diskSyncCalloutEntry,
3795 (thread_call_param_t)(uintptr_t) params->notifyRef);
3796 }
39037602 3797#endif
0a7de745
A
3798 ret = kIOReturnSuccess;
3799 }
0c530ab8 3800
0a7de745 3801 return ret;
6d2010ae
A
3802}
3803
3804//******************************************************************************
3805// handleQueueSleepWakeUUID
3806//
3807// Called from IOPMrootDomain when we're initiating a sleep,
3808// or indirectly from PM configd when PM decides to clear the UUID.
3809// PM clears the UUID several minutes after successful wake from sleep,
3810// so that we might associate App spindumps with the immediately previous
3811// sleep/wake.
3812//
3813// @param obj has a retain on it. We're responsible for releasing that retain.
3814//******************************************************************************
3815
0a7de745
A
3816void
3817IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
fe8ab488 3818{
f427ee49 3819 OSSharedPtr<OSString> str;
0c530ab8 3820
0a7de745 3821 if (kOSBooleanFalse == obj) {
f427ee49
A
3822 handlePublishSleepWakeUUID(false);
3823 } else {
3824 str.reset(OSDynamicCast(OSString, obj), OSNoRetain);
3825 if (str) {
3826 // This branch caches the UUID for an upcoming sleep/wake
3827 queuedSleepWakeUUIDString = str;
3828 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
0a7de745 3829 }
0a7de745 3830 }
6d2010ae
A
3831}
3832//******************************************************************************
3833// handlePublishSleepWakeUUID
3834//
3835// Called from IOPMrootDomain when we're initiating a sleep,
3836// or indirectly from PM configd when PM decides to clear the UUID.
3837// PM clears the UUID several minutes after successful wake from sleep,
3838// so that we might associate App spindumps with the immediately previous
3839// sleep/wake.
3840//******************************************************************************
3841
0a7de745
A
3842void
3843IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
6d2010ae 3844{
0a7de745 3845 ASSERT_GATED();
6d2010ae 3846
0a7de745
A
3847 /*
3848 * Clear the current UUID
3849 */
3850 if (gSleepWakeUUIDIsSet) {
3851 DLOG("SleepWake UUID cleared\n");
6d2010ae 3852
0a7de745 3853 gSleepWakeUUIDIsSet = false;
6d2010ae 3854
0a7de745
A
3855 removeProperty(kIOPMSleepWakeUUIDKey);
3856 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
3857 }
6d2010ae 3858
0a7de745
A
3859 /*
3860 * Optionally, publish a new UUID
3861 */
3862 if (queuedSleepWakeUUIDString && shouldPublish) {
f427ee49 3863 OSSharedPtr<OSString> publishThisUUID;
6d2010ae 3864
0a7de745 3865 publishThisUUID = queuedSleepWakeUUIDString;
6d2010ae 3866
0a7de745 3867 if (publishThisUUID) {
f427ee49 3868 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID.get());
0a7de745 3869 }
fe8ab488 3870
0a7de745
A
3871 gSleepWakeUUIDIsSet = true;
3872 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
6d2010ae 3873
f427ee49 3874 queuedSleepWakeUUIDString.reset();
0a7de745 3875 }
6d2010ae
A
3876}
3877
a39ff7e2
A
3878//******************************************************************************
3879// IOPMGetSleepWakeUUIDKey
3880//
3881// Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3882// To get the full key -- a C string -- the buffer must large enough for
3883// the end-of-string character.
3884// The key is expected to be an UUID string
3885//******************************************************************************
3886
3887extern "C" bool
3888IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len)
3889{
3890 if (!gSleepWakeUUIDIsSet) {
0a7de745 3891 return false;
a39ff7e2
A
3892 }
3893
3894 if (buffer != NULL) {
f427ee49
A
3895 OSSharedPtr<OSString> string =
3896 OSDynamicPtrCast<OSString>(gRootDomain->copyProperty(kIOPMSleepWakeUUIDKey));
a39ff7e2 3897
f427ee49 3898 if (!string) {
a39ff7e2
A
3899 *buffer = '\0';
3900 } else {
3901 strlcpy(buffer, string->getCStringNoCopy(), buf_len);
a39ff7e2
A
3902 }
3903 }
3904
0a7de745 3905 return true;
a39ff7e2
A
3906}
3907
f427ee49
A
3908//******************************************************************************
3909// lowLatencyAudioNotify
3910//
3911// Used to send an update about low latency audio activity to interested
3912// clients. To keep the overhead minimal the OSDictionary used here
3913// is initialized at boot.
3914//******************************************************************************
3915
3916void
3917IOPMrootDomain::lowLatencyAudioNotify(uint64_t time, boolean_t state)
3918{
3919 if (lowLatencyAudioNotifierDict && lowLatencyAudioNotifyStateSym && lowLatencyAudioNotifyTimestampSym &&
3920 lowLatencyAudioNotifyStateVal && lowLatencyAudioNotifyTimestampVal) {
3921 lowLatencyAudioNotifyTimestampVal->setValue(time);
3922 lowLatencyAudioNotifyStateVal->setValue(state);
3923 setPMSetting(gIOPMSettingLowLatencyAudioModeKey.get(), lowLatencyAudioNotifierDict.get());
3924 } else {
3925 DLOG("LowLatencyAudioNotify error\n");
3926 }
3927 return;
3928}
3929
3930//******************************************************************************
3931// IOPMrootDomainRTNotifier
3932//
3933// Used by performance controller to update the timestamp and state associated
3934// with low latency audio activity in the system.
3935//******************************************************************************
3936
3937extern "C" void
3938IOPMrootDomainRTNotifier(uint64_t time, boolean_t state)
3939{
3940 gRootDomain->lowLatencyAudioNotify(time, state);
3941 return;
3942}
3943
39236c6e
A
3944//******************************************************************************
3945// initializeBootSessionUUID
3946//
3947// Initialize the boot session uuid at boot up and sets it into registry.
3948//******************************************************************************
3949
0a7de745
A
3950void
3951IOPMrootDomain::initializeBootSessionUUID(void)
39236c6e 3952{
0a7de745
A
3953 uuid_t new_uuid;
3954 uuid_string_t new_uuid_string;
39236c6e 3955
0a7de745
A
3956 uuid_generate(new_uuid);
3957 uuid_unparse_upper(new_uuid, new_uuid_string);
3958 memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
39236c6e 3959
0a7de745 3960 setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
39236c6e
A
3961}
3962
6d2010ae 3963//******************************************************************************
f427ee49
A
3964// Root domain uses the private and tagged changePowerState methods for
3965// tracking and logging purposes.
6d2010ae
A
3966//******************************************************************************
3967
f427ee49
A
3968#define REQUEST_TAG_TO_REASON(x) ((uint16_t)x)
3969
3970static uint32_t
3971nextRequestTag( IOPMRequestTag tag )
3972{
3973 static SInt16 msb16 = 1;
3974 uint16_t id = OSAddAtomic16(1, &msb16);
3975 return ((uint32_t)id << 16) | REQUEST_TAG_TO_REASON(tag);
3976}
3977
3978// TODO: remove this shim function and exported symbol
0a7de745
A
3979IOReturn
3980IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
6d2010ae 3981{
f427ee49
A
3982 return changePowerStateWithTagTo(ordinal, kCPSReasonNone);
3983}
3984
3985// TODO: remove this shim function and exported symbol
3986IOReturn
3987IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
3988{
3989 return changePowerStateWithTagToPriv(ordinal, kCPSReasonNone);
3990}
3991
3992IOReturn
3993IOPMrootDomain::changePowerStateWithOverrideTo(
3994 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
3995{
3996 uint32_t tag = nextRequestTag(reason);
3997 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
316670eb 3998
cb323159 3999 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
0a7de745
A
4000 return kIOReturnUnsupported;
4001 }
316670eb 4002
f427ee49 4003 return super::changePowerStateWithOverrideTo(ordinal, tag);
6d2010ae
A
4004}
4005
0a7de745 4006IOReturn
f427ee49
A
4007IOPMrootDomain::changePowerStateWithTagTo(
4008 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
4009{
4010 uint32_t tag = nextRequestTag(reason);
4011 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
4012
4013 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
4014 return kIOReturnUnsupported;
4015 }
4016
4017 return super::changePowerStateWithTagTo(ordinal, tag);
4018}
4019
4020IOReturn
4021IOPMrootDomain::changePowerStateWithTagToPriv(
4022 IOPMPowerStateIndex ordinal, IOPMRequestTag reason )
6d2010ae 4023{
f427ee49
A
4024 uint32_t tag = nextRequestTag(reason);
4025 DLOG("%s(%s, %x)\n", __FUNCTION__, getPowerStateString((uint32_t) ordinal), tag);
6d2010ae 4026
cb323159 4027 if ((ordinal != ON_STATE) && (ordinal != AOT_STATE) && (ordinal != SLEEP_STATE)) {
0a7de745
A
4028 return kIOReturnUnsupported;
4029 }
0c530ab8 4030
f427ee49 4031 return super::changePowerStateWithTagToPriv(ordinal, tag);
6d2010ae
A
4032}
4033
4034//******************************************************************************
4035// activity detect
4036//
4037//******************************************************************************
4038
0a7de745
A
4039bool
4040IOPMrootDomain::activitySinceSleep(void)
6d2010ae 4041{
0a7de745 4042 return userActivityCount != userActivityAtSleep;
6d2010ae
A
4043}
4044
0a7de745
A
4045bool
4046IOPMrootDomain::abortHibernation(void)
6d2010ae 4047{
f427ee49
A
4048#if __arm64__
4049 // don't allow hibernation to be aborted on ARM due to user activity
4050 // since once ApplePMGR decides we're hibernating, we can't turn back
4051 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
4052 return false;
4053#else
0a7de745 4054 bool ret = activitySinceSleep();
0c530ab8 4055
0a7de745
A
4056 if (ret && !hibernateAborted && checkSystemCanSustainFullWake()) {
4057 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
4058 hibernateAborted = true;
4059 }
4060 return ret;
f427ee49 4061#endif
0c530ab8
A
4062}
4063
6d2010ae
A
4064extern "C" int
4065hibernate_should_abort(void)
4066{
0a7de745
A
4067 if (gRootDomain) {
4068 return gRootDomain->abortHibernation();
4069 } else {
4070 return 0;
4071 }
6d2010ae 4072}
2d21ac55 4073
39236c6e
A
4074//******************************************************************************
4075// willNotifyPowerChildren
4076//
4077// Called after all interested drivers have all acknowledged the power change,
4078// but before any power children is informed. Dispatched though a thread call,
4079// so it is safe to perform work that might block on a sleeping disk. PM state
4080// machine (not thread) will block w/o timeout until this function returns.
4081//******************************************************************************
4082
0a7de745
A
4083void
4084IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
39236c6e 4085{
f427ee49
A
4086 OSSharedPtr<OSDictionary> dict;
4087 OSSharedPtr<OSNumber> secs;
3e170ce0 4088
0a7de745
A
4089 if (SLEEP_STATE == newPowerState) {
4090 notifierThread = current_thread();
4091 if (!tasksSuspended) {
4092 AbsoluteTime deadline;
4093 tasksSuspended = TRUE;
cb323159 4094 updateTasksSuspend();
4bd07ac2 4095
0a7de745 4096 clock_interval_to_deadline(10, kSecondScale, &deadline);
f427ee49 4097#if defined(XNU_TARGET_OS_OSX)
0a7de745 4098 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
f427ee49 4099#endif /* defined(XNU_TARGET_OS_OSX) */
0a7de745 4100 }
4bd07ac2 4101
cb323159
A
4102 _aotReadyToFullWake = false;
4103#if 0
4104 if (_aotLingerTime) {
4105 uint64_t deadline;
4106 IOLog("aot linger no return\n");
4107 clock_absolutetime_interval_to_deadline(_aotLingerTime, &deadline);
4108 clock_delay_until(deadline);
4109 }
4110#endif
4111 if (!_aotMode) {
4112 _aotTestTime = 0;
4113 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
4114 if (_aotMetrics) {
4115 bzero(_aotMetrics, sizeof(IOPMAOTMetrics));
4116 }
4117 } else if (!_aotNow && !_debugWakeSeconds) {
4118 _aotNow = true;
4119 _aotExit = false;
4120 _aotPendingFlags = 0;
4121 _aotTasksSuspended = true;
4122 _aotLastWakeTime = 0;
4123 bzero(_aotMetrics, sizeof(IOPMAOTMetrics));
4124 if (kIOPMAOTModeCycle & _aotMode) {
4125 clock_interval_to_absolutetime_interval(60, kSecondScale, &_aotTestInterval);
4126 _aotTestTime = mach_continuous_time() + _aotTestInterval;
4127 setWakeTime(_aotTestTime);
4128 }
4129 uint32_t lingerSecs;
4130 if (!PE_parse_boot_argn("aotlinger", &lingerSecs, sizeof(lingerSecs))) {
4131 lingerSecs = 0;
4132 }
4133 clock_interval_to_absolutetime_interval(lingerSecs, kSecondScale, &_aotLingerTime);
4134 clock_interval_to_absolutetime_interval(2000, kMillisecondScale, &_aotWakePreWindow);
4135 clock_interval_to_absolutetime_interval(1100, kMillisecondScale, &_aotWakePostWindow);
4136 }
cb323159 4137
3e170ce0 4138#if HIBERNATION
0a7de745
A
4139 IOHibernateSystemSleep();
4140 IOHibernateIOKitSleep();
39236c6e 4141#endif
0a7de745
A
4142 if (gRootDomain->activitySinceSleep()) {
4143 dict = OSDictionary::withCapacity(1);
4144 secs = OSNumber::withNumber(1, 32);
4145
4146 if (dict && secs) {
f427ee49
A
4147 dict->setObject(gIOPMSettingDebugWakeRelativeKey.get(), secs.get());
4148 gRootDomain->setProperties(dict.get());
0a7de745
A
4149 MSG("Reverting sleep with relative wake\n");
4150 }
0a7de745 4151 }
3e170ce0 4152
0a7de745
A
4153 notifierThread = NULL;
4154 }
39236c6e
A
4155}
4156
f427ee49
A
4157//******************************************************************************
4158// willTellSystemCapabilityDidChange
4159//
4160// IOServicePM calls this from OurChangeTellCapabilityDidChange() when root
4161// domain is raising its power state, immediately after notifying interested
4162// drivers and power children.
4163//******************************************************************************
4164
4165void
4166IOPMrootDomain::willTellSystemCapabilityDidChange( void )
4167{
4168 if ((_systemTransitionType == kSystemTransitionWake) &&
4169 !CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
4170 // After powering up drivers, dark->full promotion on the current wake
4171 // transition is no longer possible. That is because the next machine
4172 // state will issue the system capability change messages.
4173 // The darkWakePowerClamped flag may already be set if the system has
4174 // at least one driver that was power clamped due to dark wake.
4175 // This function sets the darkWakePowerClamped flag in case there
4176 // is no power-clamped driver in the system.
4177 //
4178 // Last opportunity to exit dark wake using:
4179 // requestFullWake( kFullWakeReasonLocalUser );
4180
4181 if (!darkWakePowerClamped) {
4182 if (darkWakeLogClamp) {
4183 AbsoluteTime now;
4184 uint64_t nsec;
4185
4186 clock_get_uptime(&now);
4187 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
4188 absolutetime_to_nanoseconds(now, &nsec);
4189 DLOG("dark wake promotion disabled at %u ms\n",
4190 ((int)((nsec) / NSEC_PER_MSEC)));
4191 }
4192 darkWakePowerClamped = true;
4193 }
4194 }
4195}
4196
0c530ab8
A
4197//******************************************************************************
4198// sleepOnClamshellClosed
4199//
4200// contains the logic to determine if the system should sleep when the clamshell
4201// is closed.
4202//******************************************************************************
4203
0a7de745
A
4204bool
4205IOPMrootDomain::shouldSleepOnClamshellClosed( void )
0c530ab8 4206{
0a7de745
A
4207 if (!clamshellExists) {
4208 return false;
4209 }
6d2010ae 4210
f427ee49
A
4211 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4212 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
b0d623f7 4213
f427ee49 4214 return !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisableMask;
0c530ab8
A
4215}
4216
cb323159
A
4217bool
4218IOPMrootDomain::shouldSleepOnRTCAlarmWake( void )
4219{
4220 // Called once every RTC/Alarm wake. Device should go to sleep if on clamshell
4221 // closed && battery
4222 if (!clamshellExists) {
4223 return false;
4224 }
4225
f427ee49
A
4226 DLOG("shouldSleepOnRTCAlarmWake: clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4227 clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
cb323159 4228
f427ee49 4229 return !acAdaptorConnected && !clamshellSleepDisableMask;
cb323159
A
4230}
4231
0a7de745
A
4232void
4233IOPMrootDomain::sendClientClamshellNotification( void )
0c530ab8 4234{
0a7de745
A
4235 /* Only broadcast clamshell alert if clamshell exists. */
4236 if (!clamshellExists) {
4237 return;
4238 }
b0d623f7 4239
0a7de745
A
4240 setProperty(kAppleClamshellStateKey,
4241 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 4242
0a7de745
A
4243 setProperty(kAppleClamshellCausesSleepKey,
4244 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 4245
0a7de745
A
4246 /* Argument to message is a bitfiel of
4247 * ( kClamshellStateBit | kClamshellSleepBit )
4248 */
4249 messageClients(kIOPMMessageClamshellStateChange,
4250 (void *)(uintptr_t) ((clamshellClosed ? kClamshellStateBit : 0)
4251 | (shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)));
0c530ab8
A
4252}
4253
2d21ac55 4254//******************************************************************************
6d2010ae 4255// getSleepSupported
2d21ac55 4256//
6d2010ae 4257// Deprecated
2d21ac55
A
4258//******************************************************************************
4259
0a7de745
A
4260IOOptionBits
4261IOPMrootDomain::getSleepSupported( void )
2d21ac55 4262{
0a7de745 4263 return platformSleepSupport;
6d2010ae 4264}
2d21ac55 4265
6d2010ae
A
4266//******************************************************************************
4267// setSleepSupported
4268//
4269// Deprecated
4270//******************************************************************************
4271
0a7de745
A
4272void
4273IOPMrootDomain::setSleepSupported( IOOptionBits flags )
6d2010ae 4274{
0a7de745
A
4275 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
4276 OSBitOrAtomic(flags, &platformSleepSupport);
6d2010ae
A
4277}
4278
db609669 4279//******************************************************************************
f427ee49 4280// setClamShellSleepDisable
db609669
A
4281//
4282//******************************************************************************
4283
0a7de745 4284void
f427ee49 4285IOPMrootDomain::setClamShellSleepDisable( bool disable, uint32_t bitmask )
0a7de745 4286{
f427ee49
A
4287 uint32_t oldMask;
4288
4289 // User client calls this in non-gated context
0a7de745
A
4290 if (gIOPMWorkLoop->inGate() == false) {
4291 gIOPMWorkLoop->runAction(
f427ee49
A
4292 OSMemberFunctionCast(IOWorkLoop::Action, this,
4293 &IOPMrootDomain::setClamShellSleepDisable),
4294 (OSObject *) this,
4295 (void *) disable, (void *)(uintptr_t) bitmask);
0a7de745 4296 return;
f427ee49
A
4297 }
4298
4299 oldMask = clamshellSleepDisableMask;
4300 if (disable) {
4301 clamshellSleepDisableMask |= bitmask;
0a7de745 4302 } else {
f427ee49
A
4303 clamshellSleepDisableMask &= ~bitmask;
4304 }
4305 DLOG("setClamShellSleepDisable(%x->%x)\n", oldMask, clamshellSleepDisableMask);
4306
4307 if (clamshellExists && clamshellClosed &&
4308 (clamshellSleepDisableMask != oldMask) &&
4309 (clamshellSleepDisableMask == 0)) {
4310 handlePowerNotification(kLocalEvalClamshellCommand);
0a7de745 4311 }
db609669
A
4312}
4313
6d2010ae
A
4314//******************************************************************************
4315// wakeFromDoze
4316//
4317// Deprecated.
4318//******************************************************************************
4319
0a7de745
A
4320void
4321IOPMrootDomain::wakeFromDoze( void )
6d2010ae 4322{
0a7de745 4323 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
6d2010ae
A
4324}
4325
f427ee49
A
4326//******************************************************************************
4327// recordRTCAlarm
4328//
4329// Record the earliest scheduled RTC alarm to determine whether a RTC wake
4330// should be a dark wake or a full wake. Both Maintenance and SleepService
4331// alarms are dark wake, while AutoWake (WakeByCalendarDate) and DebugWake
4332// (WakeRelativeToSleep) should trigger a full wake. Scheduled power-on
4333// PMSettings are ignored.
4334//
4335// Caller serialized using settingsCtrlLock.
4336//******************************************************************************
4337
4338void
4339IOPMrootDomain::recordRTCAlarm(
4340 const OSSymbol *type,
4341 OSObject *object )
4342{
4343 uint32_t previousAlarmMask = _scheduledAlarmMask;
4344
4345 if (type == gIOPMSettingDebugWakeRelativeKey) {
4346 OSNumber * n = OSDynamicCast(OSNumber, object);
4347 if (n) {
4348 // Debug wake has highest scheduling priority so it overrides any
4349 // pre-existing alarm.
4350 uint32_t debugSecs = n->unsigned32BitValue();
4351 _nextScheduledAlarmType.reset(type, OSRetain);
4352 _nextScheduledAlarmUTC = debugSecs;
4353
4354 _debugWakeSeconds = debugSecs;
4355 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarmMask);
4356 DLOG("next alarm (%s) in %u secs\n",
4357 type->getCStringNoCopy(), debugSecs);
4358 }
4359 } else if ((type == gIOPMSettingAutoWakeCalendarKey.get()) ||
4360 (type == gIOPMSettingMaintenanceWakeCalendarKey.get()) ||
4361 (type == gIOPMSettingSleepServiceWakeCalendarKey.get())) {
4362 OSData * data = OSDynamicCast(OSData, object);
4363 if (data && (data->getLength() == sizeof(IOPMCalendarStruct))) {
4364 const IOPMCalendarStruct * cs;
4365 bool replaceNextAlarm = false;
4366 clock_sec_t secs;
4367
4368 cs = (const IOPMCalendarStruct *) data->getBytesNoCopy();
4369 secs = IOPMConvertCalendarToSeconds(cs);
4370 DLOG("%s " YMDTF "\n", type->getCStringNoCopy(), YMDT(cs));
4371
4372 // Update the next scheduled alarm type
4373 if ((_nextScheduledAlarmType == NULL) ||
4374 ((_nextScheduledAlarmType != gIOPMSettingDebugWakeRelativeKey) &&
4375 (secs < _nextScheduledAlarmUTC))) {
4376 replaceNextAlarm = true;
4377 }
4378
4379 if (type == gIOPMSettingAutoWakeCalendarKey.get()) {
4380 if (cs->year) {
4381 _calendarWakeAlarmUTC = IOPMConvertCalendarToSeconds(cs);
4382 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarmMask);
4383 } else {
4384 // TODO: can this else-block be removed?
4385 _calendarWakeAlarmUTC = 0;
4386 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarmMask);
4387 }
4388 }
4389 if (type == gIOPMSettingMaintenanceWakeCalendarKey.get()) {
4390 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarmMask);
4391 }
4392 if (type == gIOPMSettingSleepServiceWakeCalendarKey.get()) {
4393 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarmMask);
4394 }
4395
4396 if (replaceNextAlarm) {
4397 _nextScheduledAlarmType.reset(type, OSRetain);
4398 _nextScheduledAlarmUTC = secs;
4399 DLOG("next alarm (%s) " YMDTF "\n", type->getCStringNoCopy(), YMDT(cs));
4400 }
4401 }
4402 }
4403
4404 if (_scheduledAlarmMask != previousAlarmMask) {
4405 DLOG("scheduled alarm mask 0x%x\n", (uint32_t) _scheduledAlarmMask);
4406 }
4407}
4408
6d2010ae
A
4409// MARK: -
4410// MARK: Features
4411
4412//******************************************************************************
4413// publishFeature
4414//
4415// Adds a new feature to the supported features dictionary
4416//******************************************************************************
4417
0a7de745
A
4418void
4419IOPMrootDomain::publishFeature( const char * feature )
6d2010ae 4420{
0a7de745 4421 publishFeature(feature, kRD_AllPowerSources, NULL);
6d2010ae
A
4422}
4423
4424//******************************************************************************
4425// publishFeature (with supported power source specified)
4426//
4427// Adds a new feature to the supported features dictionary
4428//******************************************************************************
4429
0a7de745
A
4430void
4431IOPMrootDomain::publishFeature(
4432 const char *feature,
4433 uint32_t supportedWhere,
4434 uint32_t *uniqueFeatureID)
4435{
f427ee49 4436 static uint16_t next_feature_id = 500;
0a7de745 4437
f427ee49
A
4438 OSSharedPtr<OSNumber> new_feature_data;
4439 OSNumber *existing_feature = NULL;
4440 OSArray *existing_feature_arr_raw = NULL;
4441 OSSharedPtr<OSArray> existing_feature_arr;
4442 OSObject *osObj = NULL;
4443 uint32_t feature_value = 0;
0a7de745
A
4444
4445 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
4446
4447 if (!supportedWhere) {
4448 // Feature isn't supported anywhere!
4449 return;
4450 }
4451
4452 if (next_feature_id > 5000) {
4453 // Far, far too many features!
4454 return;
4455 }
4456
4457 if (featuresDictLock) {
4458 IOLockLock(featuresDictLock);
4459 }
4460
f427ee49
A
4461 OSSharedPtr<OSObject> origFeaturesProp = copyProperty(kRootDomainSupportedFeatures);
4462 OSDictionary *origFeatures = OSDynamicCast(OSDictionary, origFeaturesProp.get());
4463 OSSharedPtr<OSDictionary> features;
0a7de745
A
4464
4465 // Create new features dict if necessary
f427ee49
A
4466 if (origFeatures) {
4467 features = OSDictionary::withDictionary(origFeatures);
0a7de745
A
4468 } else {
4469 features = OSDictionary::withCapacity(1);
4470 }
4471
4472 // Create OSNumber to track new feature
4473
4474 next_feature_id += 1;
4475 if (uniqueFeatureID) {
4476 // We don't really mind if the calling kext didn't give us a place
4477 // to stash their unique id. Many kexts don't plan to unload, and thus
4478 // have no need to remove themselves later.
4479 *uniqueFeatureID = next_feature_id;
4480 }
4481
4482 feature_value = (uint32_t)next_feature_id;
4483 feature_value <<= 16;
4484 feature_value += supportedWhere;
4485
4486 new_feature_data = OSNumber::withNumber(
4487 (unsigned long long)feature_value, 32);
4488
4489 // Does features object already exist?
4490 if ((osObj = features->getObject(feature))) {
4491 if ((existing_feature = OSDynamicCast(OSNumber, osObj))) {
4492 // We need to create an OSArray to hold the now 2 elements.
4493 existing_feature_arr = OSArray::withObjects(
4494 (const OSObject **)&existing_feature, 1, 2);
f427ee49 4495 } else if ((existing_feature_arr_raw = OSDynamicCast(OSArray, osObj))) {
0a7de745
A
4496 // Add object to existing array
4497 existing_feature_arr = OSArray::withArray(
f427ee49
A
4498 existing_feature_arr_raw,
4499 existing_feature_arr_raw->getCount() + 1);
0a7de745
A
4500 }
4501
4502 if (existing_feature_arr) {
f427ee49
A
4503 existing_feature_arr->setObject(new_feature_data.get());
4504 features->setObject(feature, existing_feature_arr.get());
0a7de745
A
4505 }
4506 } else {
4507 // The easy case: no previously existing features listed. We simply
4508 // set the OSNumber at key 'feature' and we're on our way.
f427ee49 4509 features->setObject(feature, new_feature_data.get());
0a7de745
A
4510 }
4511
f427ee49 4512 setProperty(kRootDomainSupportedFeatures, features.get());
0a7de745
A
4513
4514 if (featuresDictLock) {
4515 IOLockUnlock(featuresDictLock);
4516 }
4517
4518 // Notify EnergySaver and all those in user space so they might
4519 // re-populate their feature specific UI
4520 if (pmPowerStateQueue) {
4521 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
4522 }
6d2010ae
A
4523}
4524
4525//******************************************************************************
4526// removePublishedFeature
4527//
4528// Removes previously published feature
4529//******************************************************************************
4530
0a7de745
A
4531IOReturn
4532IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
4533{
4534 IOReturn ret = kIOReturnError;
4535 uint32_t feature_value = 0;
4536 uint16_t feature_id = 0;
4537 bool madeAChange = false;
4538
4539 OSSymbol *dictKey = NULL;
f427ee49 4540 OSSharedPtr<OSCollectionIterator> dictIterator;
0a7de745
A
4541 OSArray *arrayMember = NULL;
4542 OSNumber *numberMember = NULL;
4543 OSObject *osObj = NULL;
4544 OSNumber *osNum = NULL;
f427ee49 4545 OSSharedPtr<OSArray> arrayMemberCopy;
0a7de745
A
4546
4547 if (kBadPMFeatureID == removeFeatureID) {
4548 return kIOReturnNotFound;
4549 }
4550
4551 if (featuresDictLock) {
4552 IOLockLock(featuresDictLock);
4553 }
4554
f427ee49
A
4555 OSSharedPtr<OSObject> origFeaturesProp = copyProperty(kRootDomainSupportedFeatures);
4556 OSDictionary *origFeatures = OSDynamicCast(OSDictionary, origFeaturesProp.get());
4557 OSSharedPtr<OSDictionary> features;
0a7de745 4558
f427ee49 4559 if (origFeatures) {
0a7de745
A
4560 // Any modifications to the dictionary are made to the copy to prevent
4561 // races & crashes with userland clients. Dictionary updated
4562 // automically later.
f427ee49 4563 features = OSDictionary::withDictionary(origFeatures);
0a7de745
A
4564 } else {
4565 features = NULL;
4566 ret = kIOReturnNotFound;
4567 goto exit;
4568 }
4569
4570 // We iterate 'features' dictionary looking for an entry tagged
4571 // with 'removeFeatureID'. If found, we remove it from our tracking
4572 // structures and notify the OS via a general interest message.
4573
f427ee49 4574 dictIterator = OSCollectionIterator::withCollection(features.get());
0a7de745
A
4575 if (!dictIterator) {
4576 goto exit;
4577 }
4578
4579 while ((dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject()))) {
4580 osObj = features->getObject(dictKey);
4581
4582 // Each Feature is either tracked by an OSNumber
4583 if (osObj && (numberMember = OSDynamicCast(OSNumber, osObj))) {
4584 feature_value = numberMember->unsigned32BitValue();
4585 feature_id = (uint16_t)(feature_value >> 16);
4586
4587 if (feature_id == (uint16_t)removeFeatureID) {
4588 // Remove this node
4589 features->removeObject(dictKey);
4590 madeAChange = true;
4591 break;
4592 }
4593
4594 // Or tracked by an OSArray of OSNumbers
4595 } else if (osObj && (arrayMember = OSDynamicCast(OSArray, osObj))) {
4596 unsigned int arrayCount = arrayMember->getCount();
4597
4598 for (unsigned int i = 0; i < arrayCount; i++) {
4599 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
4600 if (!osNum) {
4601 continue;
4602 }
4603
4604 feature_value = osNum->unsigned32BitValue();
4605 feature_id = (uint16_t)(feature_value >> 16);
4606
4607 if (feature_id == (uint16_t)removeFeatureID) {
4608 // Remove this node
4609 if (1 == arrayCount) {
4610 // If the array only contains one element, remove
4611 // the whole thing.
4612 features->removeObject(dictKey);
4613 } else {
4614 // Otherwise remove the element from a copy of the array.
4615 arrayMemberCopy = OSArray::withArray(arrayMember);
4616 if (arrayMemberCopy) {
4617 arrayMemberCopy->removeObject(i);
f427ee49 4618 features->setObject(dictKey, arrayMemberCopy.get());
0a7de745
A
4619 }
4620 }
4621
4622 madeAChange = true;
4623 break;
4624 }
4625 }
4626 }
4627 }
4628
0a7de745
A
4629 if (madeAChange) {
4630 ret = kIOReturnSuccess;
4631
f427ee49 4632 setProperty(kRootDomainSupportedFeatures, features.get());
0a7de745
A
4633
4634 // Notify EnergySaver and all those in user space so they might
4635 // re-populate their feature specific UI
4636 if (pmPowerStateQueue) {
4637 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
4638 }
4639 } else {
4640 ret = kIOReturnNotFound;
4641 }
fe8ab488 4642
6d2010ae 4643exit:
0a7de745
A
4644 if (featuresDictLock) {
4645 IOLockUnlock(featuresDictLock);
4646 }
4647 return ret;
6d2010ae
A
4648}
4649
7ddcb079
A
4650//******************************************************************************
4651// publishPMSetting (private)
4652//
4653// Should only be called by PMSettingObject to publish a PM Setting as a
4654// supported feature.
4655//******************************************************************************
4656
0a7de745
A
4657void
4658IOPMrootDomain::publishPMSetting(
4659 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
7ddcb079 4660{
0a7de745
A
4661 if (noPublishPMSettings &&
4662 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1)) {
4663 // Setting found in noPublishPMSettings array
4664 *featureID = kBadPMFeatureID;
4665 return;
4666 }
7ddcb079 4667
0a7de745
A
4668 publishFeature(
4669 feature->getCStringNoCopy(), where, featureID);
7ddcb079
A
4670}
4671
6d2010ae
A
4672//******************************************************************************
4673// setPMSetting (private)
4674//
4675// Internal helper to relay PM settings changes from user space to individual
4676// drivers. Should be called only by IOPMrootDomain::setProperties.
4677//******************************************************************************
4678
0a7de745
A
4679IOReturn
4680IOPMrootDomain::setPMSetting(
4681 const OSSymbol *type,
4682 OSObject *object )
4683{
cb323159 4684 PMSettingCallEntry *entries = NULL;
f427ee49 4685 OSSharedPtr<OSArray> chosen;
0a7de745
A
4686 const OSArray *array;
4687 PMSettingObject *pmso;
4688 thread_t thisThread;
4689 int i, j, count, capacity;
f427ee49
A
4690 bool ok = false;
4691 IOReturn ret;
0a7de745
A
4692
4693 if (NULL == type) {
4694 return kIOReturnBadArgument;
4695 }
4696
4697 PMSETTING_LOCK();
4698
4699 // Update settings dict so changes are visible from copyPMSetting().
4700 fPMSettingsDict->setObject(type, object);
4701
4702 // Prep all PMSetting objects with the given 'type' for callout.
4703 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
4704 if (!array || ((capacity = array->getCount()) == 0)) {
4705 goto unlock_exit;
4706 }
4707
4708 // Array to retain PMSetting objects targeted for callout.
4709 chosen = OSArray::withCapacity(capacity);
4710 if (!chosen) {
4711 goto unlock_exit; // error
4712 }
4713 entries = IONew(PMSettingCallEntry, capacity);
4714 if (!entries) {
4715 goto unlock_exit; // error
4716 }
4717 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
4718
4719 thisThread = current_thread();
4720
4721 for (i = 0, j = 0; i < capacity; i++) {
4722 pmso = (PMSettingObject *) array->getObject(i);
4723 if (pmso->disabled) {
4724 continue;
4725 }
4726 entries[j].thread = thisThread;
4727 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
4728 chosen->setObject(pmso);
4729 j++;
4730 }
4731 count = j;
4732 if (!count) {
4733 goto unlock_exit;
4734 }
4735
4736 PMSETTING_UNLOCK();
4737
4738 // Call each pmso in the chosen array.
4739 for (i = 0; i < count; i++) {
4740 pmso = (PMSettingObject *) chosen->getObject(i);
f427ee49
A
4741 ret = pmso->dispatchPMSetting(type, object);
4742 if (ret == kIOReturnSuccess) {
4743 // At least one setting handler was successful
4744 ok = true;
4745#if DEVELOPMENT || DEBUG
4746 } else {
4747 // Log the handler and kext that failed
4748 OSSharedPtr<const OSSymbol> kextName = copyKextIdentifierWithAddress((vm_address_t) pmso->func);
4749 if (kextName) {
4750 DLOG("PMSetting(%s) error 0x%x from %s\n",
4751 type->getCStringNoCopy(), ret, kextName->getCStringNoCopy());
4752 }
4753#endif
4754 }
0a7de745
A
4755 }
4756
4757 PMSETTING_LOCK();
4758 for (i = 0; i < count; i++) {
4759 pmso = (PMSettingObject *) chosen->getObject(i);
4760 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
4761 if (pmso->waitThread) {
4762 PMSETTING_WAKEUP(pmso);
4763 }
4764 }
f427ee49
A
4765
4766 if (ok) {
4767 recordRTCAlarm(type, object);
4768 }
6d2010ae 4769unlock_exit:
0a7de745 4770 PMSETTING_UNLOCK();
6d2010ae 4771
0a7de745
A
4772 if (entries) {
4773 IODelete(entries, PMSettingCallEntry, capacity);
4774 }
6d2010ae 4775
0a7de745 4776 return kIOReturnSuccess;
6d2010ae
A
4777}
4778
4779//******************************************************************************
4780// copyPMSetting (public)
4781//
4782// Allows kexts to safely read setting values, without being subscribed to
4783// notifications.
4784//******************************************************************************
4785
f427ee49 4786OSSharedPtr<OSObject>
0a7de745
A
4787IOPMrootDomain::copyPMSetting(
4788 OSSymbol *whichSetting)
6d2010ae 4789{
f427ee49 4790 OSSharedPtr<OSObject> obj;
6d2010ae 4791
0a7de745
A
4792 if (!whichSetting) {
4793 return NULL;
4794 }
6d2010ae 4795
0a7de745 4796 PMSETTING_LOCK();
f427ee49 4797 obj.reset(fPMSettingsDict->getObject(whichSetting), OSRetain);
0a7de745 4798 PMSETTING_UNLOCK();
fe8ab488 4799
0a7de745 4800 return obj;
6d2010ae
A
4801}
4802
4803//******************************************************************************
4804// registerPMSettingController (public)
4805//
4806// direct wrapper to registerPMSettingController with uint32_t power source arg
4807//******************************************************************************
4808
0a7de745
A
4809IOReturn
4810IOPMrootDomain::registerPMSettingController(
4811 const OSSymbol * settings[],
4812 IOPMSettingControllerCallback func,
4813 OSObject *target,
4814 uintptr_t refcon,
4815 OSObject **handle)
6d2010ae 4816{
0a7de745
A
4817 return registerPMSettingController(
4818 settings,
4819 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
4820 func, target, refcon, handle);
6d2010ae
A
4821}
4822
4823//******************************************************************************
4824// registerPMSettingController (public)
4825//
4826// Kexts may register for notifications when a particular setting is changed.
4827// A list of settings is available in IOPM.h.
4828// Arguments:
4829// * settings - An OSArray containing OSSymbols. Caller should populate this
4830// array with a list of settings caller wants notifications from.
4831// * func - A C function callback of the type IOPMSettingControllerCallback
fe8ab488 4832// * target - caller may provide an OSObject *, which PM will pass as an
6d2010ae 4833// target to calls to "func"
fe8ab488 4834// * refcon - caller may provide an void *, which PM will pass as an
6d2010ae
A
4835// argument to calls to "func"
4836// * handle - This is a return argument. We will populate this pointer upon
4837// call success. Hold onto this and pass this argument to
4838// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
4839// Returns:
4840// kIOReturnSuccess on success
4841//******************************************************************************
4842
0a7de745
A
4843IOReturn
4844IOPMrootDomain::registerPMSettingController(
4845 const OSSymbol * settings[],
4846 uint32_t supportedPowerSources,
4847 IOPMSettingControllerCallback func,
4848 OSObject *target,
4849 uintptr_t refcon,
4850 OSObject **handle)
4851{
4852 PMSettingObject *pmso = NULL;
4853 OSObject *pmsh = NULL;
0a7de745
A
4854 int i;
4855
4856 if (NULL == settings ||
4857 NULL == func ||
4858 NULL == handle) {
4859 return kIOReturnBadArgument;
4860 }
6d2010ae 4861
0a7de745
A
4862 pmso = PMSettingObject::pmSettingObject(
4863 (IOPMrootDomain *) this, func, target,
4864 refcon, supportedPowerSources, settings, &pmsh);
6d2010ae 4865
0a7de745
A
4866 if (!pmso) {
4867 *handle = NULL;
4868 return kIOReturnInternalError;
4869 }
6d2010ae 4870
0a7de745
A
4871 PMSETTING_LOCK();
4872 for (i = 0; settings[i]; i++) {
f427ee49
A
4873 OSSharedPtr<OSArray> newList;
4874 OSArray *list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
0a7de745
A
4875 if (!list) {
4876 // New array of callbacks for this setting
f427ee49
A
4877 newList = OSArray::withCapacity(1);
4878 settingsCallbacks->setObject(settings[i], newList.get());
4879 list = newList.get();
0a7de745 4880 }
6d2010ae 4881
0a7de745
A
4882 // Add caller to the callback list
4883 list->setObject(pmso);
4884 }
4885 PMSETTING_UNLOCK();
6d2010ae 4886
0a7de745
A
4887 // Return handle to the caller, the setting object is private.
4888 *handle = pmsh;
6d2010ae 4889
0a7de745 4890 return kIOReturnSuccess;
6d2010ae
A
4891}
4892
4893//******************************************************************************
4894// deregisterPMSettingObject (private)
4895//
4896// Only called from PMSettingObject.
4897//******************************************************************************
4898
0a7de745
A
4899void
4900IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
4901{
4902 thread_t thisThread = current_thread();
4903 PMSettingCallEntry *callEntry;
f427ee49 4904 OSSharedPtr<OSCollectionIterator> iter;
0a7de745
A
4905 OSSymbol *sym;
4906 OSArray *array;
4907 int index;
4908 bool wait;
4909
4910 PMSETTING_LOCK();
4911
4912 pmso->disabled = true;
4913
4914 // Wait for all callout threads to finish.
4915 do {
4916 wait = false;
4917 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
4918 {
4919 if (callEntry->thread != thisThread) {
4920 wait = true;
4921 break;
4922 }
4923 }
4924 if (wait) {
cb323159 4925 assert(NULL == pmso->waitThread);
0a7de745
A
4926 pmso->waitThread = thisThread;
4927 PMSETTING_WAIT(pmso);
cb323159 4928 pmso->waitThread = NULL;
0a7de745
A
4929 }
4930 } while (wait);
4931
4932 // Search each PM settings array in the kernel.
f427ee49 4933 iter = OSCollectionIterator::withCollection(settingsCallbacks.get());
0a7de745
A
4934 if (iter) {
4935 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
4936 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
4937 index = array->getNextIndexOfObject(pmso, 0);
4938 if (-1 != index) {
4939 array->removeObject(index);
4940 }
4941 }
0a7de745
A
4942 }
4943
4944 PMSETTING_UNLOCK();
4945
4946 pmso->release();
6d2010ae
A
4947}
4948
4949//******************************************************************************
4950// informCPUStateChange
4951//
4952// Call into PM CPU code so that CPU power savings may dynamically adjust for
4953// running on battery, with the lid closed, etc.
4954//
4955// informCPUStateChange is a no-op on non x86 systems
4956// only x86 has explicit support in the IntelCPUPowerManagement kext
4957//******************************************************************************
4958
0a7de745
A
4959void
4960IOPMrootDomain::informCPUStateChange(
4961 uint32_t type,
4962 uint32_t value )
6d2010ae
A
4963{
4964#if defined(__i386__) || defined(__x86_64__)
4965
0a7de745
A
4966 pmioctlVariableInfo_t varInfoStruct;
4967 int pmCPUret = 0;
4968 const char *varNameStr = NULL;
4969 int32_t *varIndex = NULL;
4970
4971 if (kInformAC == type) {
4972 varNameStr = kIOPMRootDomainBatPowerCString;
4973 varIndex = &idxPMCPULimitedPower;
4974 } else if (kInformLid == type) {
4975 varNameStr = kIOPMRootDomainLidCloseCString;
4976 varIndex = &idxPMCPUClamshell;
4977 } else {
4978 return;
4979 }
4980
4981 // Set the new value!
4982 // pmCPUControl will assign us a new ID if one doesn't exist yet
4983 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
4984 varInfoStruct.varID = *varIndex;
4985 varInfoStruct.varType = vBool;
4986 varInfoStruct.varInitValue = value;
4987 varInfoStruct.varCurValue = value;
4988 strlcpy((char *)varInfoStruct.varName,
4989 (const char *)varNameStr,
4990 sizeof(varInfoStruct.varName));
4991
4992 // Set!
4993 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
4994
4995 // pmCPU only assigns numerical id's when a new varName is specified
4996 if ((0 == pmCPUret)
4997 && (*varIndex == kCPUUnknownIndex)) {
4998 // pmCPUControl has assigned us a new variable ID.
4999 // Let's re-read the structure we just SET to learn that ID.
5000 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
5001
5002 if (0 == pmCPUret) {
5003 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
5004 *varIndex = varInfoStruct.varID;
5005 }
5006 }
5007
5008 return;
fe8ab488 5009
b0d623f7 5010#endif /* __i386__ || __x86_64__ */
2d21ac55
A
5011}
5012
6d2010ae
A
5013// MARK: -
5014// MARK: Deep Sleep Policy
b0d623f7 5015
0b4c1975
A
5016#if HIBERNATION
5017
5018//******************************************************************************
5019// evaluateSystemSleepPolicy
5020//******************************************************************************
5021
99c3a104
A
5022#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
5023
5024// Sleep flags
5025enum {
0a7de745
A
5026 kIOPMSleepFlagHibernate = 0x00000001,
5027 kIOPMSleepFlagSleepTimerEnable = 0x00000002
99c3a104
A
5028};
5029
0a7de745
A
5030struct IOPMSystemSleepPolicyEntry {
5031 uint32_t factorMask;
5032 uint32_t factorBits;
5033 uint32_t sleepFlags;
5034 uint32_t wakeEvents;
99c3a104 5035} __attribute__((packed));
0b4c1975 5036
0a7de745
A
5037struct IOPMSystemSleepPolicyTable {
5038 uint32_t signature;
5039 uint16_t version;
5040 uint16_t entryCount;
5041 IOPMSystemSleepPolicyEntry entries[];
99c3a104 5042} __attribute__((packed));
316670eb 5043
bd504ef0 5044enum {
0a7de745
A
5045 kIOPMSleepAttributeHibernateSetup = 0x00000001,
5046 kIOPMSleepAttributeHibernateSleep = 0x00000002
bd504ef0
A
5047};
5048
5049static uint32_t
5050getSleepTypeAttributes( uint32_t sleepType )
5051{
0a7de745
A
5052 static const uint32_t sleepTypeAttributes[kIOPMSleepTypeLast] =
5053 {
5054 /* invalid */ 0,
5055 /* abort */ 0,
5056 /* normal */ 0,
5057 /* safesleep */ kIOPMSleepAttributeHibernateSetup,
5058 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5059 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5060 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
5061 /* deepidle */ 0
5062 };
5063
5064 if (sleepType >= kIOPMSleepTypeLast) {
5065 return 0;
5066 }
0b4c1975 5067
0a7de745
A
5068 return sleepTypeAttributes[sleepType];
5069}
5070
5071bool
5072IOPMrootDomain::evaluateSystemSleepPolicy(
5073 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
5074{
f427ee49
A
5075#define SLEEP_FACTOR(x) {(uint32_t) kIOPMSleepFactor ## x, #x}
5076
5077 static const IONamedValue factorValues[] = {
5078 SLEEP_FACTOR( SleepTimerWake ),
5079 SLEEP_FACTOR( LidOpen ),
5080 SLEEP_FACTOR( ACPower ),
5081 SLEEP_FACTOR( BatteryLow ),
5082 SLEEP_FACTOR( StandbyNoDelay ),
5083 SLEEP_FACTOR( StandbyForced ),
5084 SLEEP_FACTOR( StandbyDisabled ),
5085 SLEEP_FACTOR( USBExternalDevice ),
5086 SLEEP_FACTOR( BluetoothHIDDevice ),
5087 SLEEP_FACTOR( ExternalMediaMounted ),
5088 SLEEP_FACTOR( ThunderboltDevice ),
5089 SLEEP_FACTOR( RTCAlarmScheduled ),
5090 SLEEP_FACTOR( MagicPacketWakeEnabled ),
5091 SLEEP_FACTOR( HibernateForced ),
5092 SLEEP_FACTOR( AutoPowerOffDisabled ),
5093 SLEEP_FACTOR( AutoPowerOffForced ),
5094 SLEEP_FACTOR( ExternalDisplay ),
5095 SLEEP_FACTOR( NetworkKeepAliveActive ),
5096 SLEEP_FACTOR( LocalUserActivity ),
5097 SLEEP_FACTOR( HibernateFailed ),
5098 SLEEP_FACTOR( ThermalWarning ),
5099 SLEEP_FACTOR( DisplayCaptured ),
5100 { 0, NULL }
5101 };
5102
0a7de745 5103 const IOPMSystemSleepPolicyTable * pt;
f427ee49 5104 OSSharedPtr<OSObject> prop;
0a7de745
A
5105 OSData * policyData;
5106 uint64_t currentFactors = 0;
cb323159 5107 char currentFactorsBuf[512];
0a7de745
A
5108 uint32_t standbyDelay = 0;
5109 uint32_t powerOffDelay = 0;
5110 uint32_t powerOffTimer = 0;
5111 uint32_t standbyTimer = 0;
5112 uint32_t mismatch;
5113 bool standbyEnabled;
5114 bool powerOffEnabled;
5115 bool found = false;
5116
5117 // Get platform's sleep policy table
5118 if (!gSleepPolicyHandler) {
5119 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
5120 if (!prop) {
5121 goto done;
5122 }
5123 }
0b4c1975 5124
0a7de745
A
5125 // Fetch additional settings
5126 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
f427ee49 5127 && propertyHasValue(kIOPMDeepSleepEnabledKey, kOSBooleanTrue));
0a7de745 5128 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
f427ee49 5129 && propertyHasValue(kIOPMAutoPowerOffEnabledKey, kOSBooleanTrue));
0a7de745
A
5130 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer)) {
5131 powerOffTimer = powerOffDelay;
5132 }
5133 if (!getSleepOption(kIOPMDeepSleepTimerKey, &standbyTimer)) {
5134 standbyTimer = standbyDelay;
5135 }
0b4c1975 5136
0a7de745
A
5137 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
5138 sleepPhase, standbyEnabled, standbyDelay, standbyTimer,
5139 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
99c3a104 5140
cb323159 5141 currentFactorsBuf[0] = 0;
0a7de745
A
5142 // pmset level overrides
5143 if ((*hibMode & kIOHibernateModeOn) == 0) {
5144 if (!gSleepPolicyHandler) {
5145 standbyEnabled = false;
5146 powerOffEnabled = false;
5147 }
5148 } else if (!(*hibMode & kIOHibernateModeSleep)) {
5149 // Force hibernate (i.e. mode 25)
5150 // If standby is enabled, force standy.
5151 // If poweroff is enabled, force poweroff.
5152 if (standbyEnabled) {
5153 currentFactors |= kIOPMSleepFactorStandbyForced;
5154 } else if (powerOffEnabled) {
5155 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
5156 } else {
5157 currentFactors |= kIOPMSleepFactorHibernateForced;
5158 }
5159 }
6d2010ae 5160
0a7de745
A
5161 // Current factors based on environment and assertions
5162 if (sleepTimerMaintenance) {
5163 currentFactors |= kIOPMSleepFactorSleepTimerWake;
5164 }
5165 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler) {
5166 currentFactors |= kIOPMSleepFactorSleepTimerWake;
5167 }
5168 if (!clamshellClosed) {
5169 currentFactors |= kIOPMSleepFactorLidOpen;
5170 }
5171 if (acAdaptorConnected) {
5172 currentFactors |= kIOPMSleepFactorACPower;
5173 }
5174 if (lowBatteryCondition) {
f427ee49
A
5175 hibernateMode = 0;
5176 getSleepOption(kIOHibernateModeKey, &hibernateMode);
5177 if ((hibernateMode & kIOHibernateModeOn) == 0) {
5178 DLOG("HibernateMode is 0. Not sending LowBattery factor to IOPPF\n");
5179 } else {
5180 currentFactors |= kIOPMSleepFactorBatteryLow;
5181 }
0a7de745
A
5182 }
5183 if (!standbyDelay || !standbyTimer) {
5184 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
5185 }
5186 if (standbyNixed || !standbyEnabled) {
5187 currentFactors |= kIOPMSleepFactorStandbyDisabled;
5188 }
5189 if (resetTimers) {
5190 currentFactors |= kIOPMSleepFactorLocalUserActivity;
5191 currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
5192 }
5193 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
5194 kIOPMDriverAssertionLevelOff) {
5195 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
5196 }
5197 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
5198 kIOPMDriverAssertionLevelOff) {
5199 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
5200 }
5201 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
5202 kIOPMDriverAssertionLevelOff) {
5203 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
5204 }
5205 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
5206 kIOPMDriverAssertionLevelOff) {
5207 currentFactors |= kIOPMSleepFactorThunderboltDevice;
5208 }
f427ee49 5209 if (_scheduledAlarmMask != 0) {
0a7de745
A
5210 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
5211 }
5212 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
5213 kIOPMDriverAssertionLevelOff) {
5214 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
5215 }
5216#define TCPKEEPALIVE 1
5217#if TCPKEEPALIVE
5218 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
5219 kIOPMDriverAssertionLevelOff) {
5220 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
5221 }
db609669 5222#endif
0a7de745
A
5223 if (!powerOffEnabled) {
5224 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
5225 }
5226 if (desktopMode) {
5227 currentFactors |= kIOPMSleepFactorExternalDisplay;
5228 }
5229 if (userWasActive) {
5230 currentFactors |= kIOPMSleepFactorLocalUserActivity;
5231 }
5232 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
5233 currentFactors |= kIOPMSleepFactorHibernateFailed;
5234 }
5235 if (thermalWarningState) {
5236 currentFactors |= kIOPMSleepFactorThermalWarning;
5237 }
db609669 5238
f427ee49
A
5239 for (int factorBit = 0; factorBit < (8 * sizeof(uint32_t)); factorBit++) {
5240 uint32_t factor = 1 << factorBit;
5241 if (factor & currentFactors) {
5242 strlcat(currentFactorsBuf, ", ", sizeof(currentFactorsBuf));
5243 strlcat(currentFactorsBuf, IOFindNameForValue(factor, factorValues), sizeof(currentFactorsBuf));
5244 }
5245 }
5246 DLOG("sleep factors 0x%llx%s\n", currentFactors, currentFactorsBuf);
6d2010ae 5247
0a7de745
A
5248 if (gSleepPolicyHandler) {
5249 uint32_t savedHibernateMode;
5250 IOReturn result;
6d2010ae 5251
0a7de745
A
5252 if (!gSleepPolicyVars) {
5253 gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
5254 if (!gSleepPolicyVars) {
5255 goto done;
5256 }
5257 bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
5258 }
5259 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
5260 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
5261 gSleepPolicyVars->currentCapability = _currentCapability;
5262 gSleepPolicyVars->highestCapability = _highestCapability;
5263 gSleepPolicyVars->sleepFactors = currentFactors;
5264 gSleepPolicyVars->sleepReason = lastSleepReason;
5265 gSleepPolicyVars->sleepPhase = sleepPhase;
5266 gSleepPolicyVars->standbyDelay = standbyDelay;
5267 gSleepPolicyVars->standbyTimer = standbyTimer;
5268 gSleepPolicyVars->poweroffDelay = powerOffDelay;
f427ee49 5269 gSleepPolicyVars->scheduledAlarms = _scheduledAlarmMask | _userScheduledAlarmMask;
0a7de745
A
5270 gSleepPolicyVars->poweroffTimer = powerOffTimer;
5271
5272 if (kIOPMSleepPhase0 == sleepPhase) {
5273 // preserve hibernateMode
5274 savedHibernateMode = gSleepPolicyVars->hibernateMode;
5275 gSleepPolicyVars->hibernateMode = *hibMode;
5276 } else if (kIOPMSleepPhase1 == sleepPhase) {
5277 // use original hibernateMode for phase2
5278 gSleepPolicyVars->hibernateMode = *hibMode;
5279 }
5c9f4661 5280
0a7de745 5281 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
5c9f4661 5282
0a7de745
A
5283 if (kIOPMSleepPhase0 == sleepPhase) {
5284 // restore hibernateMode
5285 gSleepPolicyVars->hibernateMode = savedHibernateMode;
5286 }
5c9f4661 5287
0a7de745
A
5288 if ((result != kIOReturnSuccess) ||
5289 (kIOPMSleepTypeInvalid == params->sleepType) ||
5290 (params->sleepType >= kIOPMSleepTypeLast) ||
5291 (kIOPMSystemSleepParametersVersion != params->version)) {
5292 MSG("sleep policy handler error\n");
5293 goto done;
5294 }
5c9f4661 5295
0a7de745
A
5296 if ((getSleepTypeAttributes(params->sleepType) &
5297 kIOPMSleepAttributeHibernateSetup) &&
5298 ((*hibMode & kIOHibernateModeOn) == 0)) {
5299 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
5300 }
6d2010ae 5301
0a7de745
A
5302 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
5303 params->version, params->sleepType, params->sleepFlags,
5304 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
5305 found = true;
5306 goto done;
5307 }
6d2010ae 5308
0a7de745
A
5309 // Policy table is meaningless without standby enabled
5310 if (!standbyEnabled) {
5311 goto done;
5312 }
fe8ab488 5313
0a7de745 5314 // Validate the sleep policy table
f427ee49 5315 policyData = OSDynamicCast(OSData, prop.get());
0a7de745
A
5316 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable))) {
5317 goto done;
5318 }
6d2010ae 5319
0a7de745
A
5320 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
5321 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
5322 (pt->version != 1) || (0 == pt->entryCount)) {
5323 goto done;
5324 }
5c9f4661 5325
0a7de745
A
5326 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
5327 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))) {
5328 goto done;
5329 }
6d2010ae 5330
0a7de745
A
5331 for (uint32_t i = 0; i < pt->entryCount; i++) {
5332 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
5333 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
fe8ab488 5334
0a7de745
A
5335 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
5336 entry->factorMask, entry->factorBits,
5337 entry->sleepFlags, entry->wakeEvents, mismatch);
5338 if (mismatch) {
5339 continue;
5340 }
6d2010ae 5341
0a7de745
A
5342 DLOG("^ found match\n");
5343 found = true;
6d2010ae 5344
0a7de745
A
5345 params->version = kIOPMSystemSleepParametersVersion;
5346 params->reserved1 = 1;
5347 if (entry->sleepFlags & kIOPMSleepFlagHibernate) {
5348 params->sleepType = kIOPMSleepTypeStandby;
5349 } else {
5350 params->sleepType = kIOPMSleepTypeNormalSleep;
5351 }
3e170ce0 5352
0a7de745
A
5353 params->ecWakeEvents = entry->wakeEvents;
5354 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable) {
5355 if (kIOPMSleepPhase2 == sleepPhase) {
5356 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
5357
5358 if (!_standbyTimerResetSeconds ||
5359 (now_secs <= _standbyTimerResetSeconds)) {
5360 // Reset standby timer adjustment
5361 _standbyTimerResetSeconds = now_secs;
5362 DLOG("standby delay %u, reset %u\n",
5363 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
5364 } else if (standbyDelay) {
5365 // Shorten the standby delay timer
5366 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
5367 if (standbyDelay > elapsed) {
5368 standbyDelay -= elapsed;
5369 } else {
5370 standbyDelay = 1; // must be > 0
5371 }
5372 DLOG("standby delay %u, elapsed %u\n",
5373 standbyDelay, (uint32_t) elapsed);
5374 }
5375 }
5376 params->ecWakeTimer = standbyDelay;
5377 } else if (kIOPMSleepPhase2 == sleepPhase) {
5378 // A sleep that does not enable the sleep timer will reset
5379 // the standby delay adjustment.
5380 _standbyTimerResetSeconds = 0;
5381 }
5382 break;
5383 }
6d2010ae 5384
0a7de745 5385done:
0a7de745
A
5386 return found;
5387}
5388
5389static IOPMSystemSleepParameters gEarlySystemSleepParams;
5390
5391void
5392IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
5393{
5394 // Evaluate early (priority interest phase), before drivers sleep.
5395
5396 DLOG("%s\n", __FUNCTION__);
5397 removeProperty(kIOPMSystemSleepParametersKey);
5398
5399 // Full wake resets the standby timer delay adjustment
5400 if (_highestCapability & kIOPMSystemCapabilityGraphics) {
5401 _standbyTimerResetSeconds = 0;
5402 }
5403
5404 hibernateDisabled = false;
5405 hibernateMode = 0;
5406 getSleepOption(kIOHibernateModeKey, &hibernateMode);
5407
5408 // Save for late evaluation if sleep is aborted
5409 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
5410
5411 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
5412 &hibernateMode)) {
5413 if (!hibernateRetry &&
5414 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
5415 kIOPMSleepAttributeHibernateSetup) == 0)) {
5416 // skip hibernate setup
5417 hibernateDisabled = true;
5418 }
5419 }
5420
5421 // Publish IOPMSystemSleepType
5422 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
5423 if (sleepType == kIOPMSleepTypeInvalid) {
5424 // no sleep policy
5425 sleepType = kIOPMSleepTypeNormalSleep;
5426 if (hibernateMode & kIOHibernateModeOn) {
5427 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
5428 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
5429 }
5430 } else if ((sleepType == kIOPMSleepTypeStandby) &&
5431 (gEarlySystemSleepParams.ecPoweroffTimer)) {
5432 // report the lowest possible sleep state
5433 sleepType = kIOPMSleepTypePowerOff;
5434 }
5435
5436 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
5437}
5438
5439void
5440IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
5441{
5442 IOPMSystemSleepParameters params;
f427ee49 5443 OSSharedPtr<OSData> paramsData;
0a7de745
A
5444 bool wakeNow;
5445 // Evaluate sleep policy after sleeping drivers but before platform sleep.
5446
5447 DLOG("%s\n", __FUNCTION__);
5448
5449 bzero(&params, sizeof(params));
5450 wakeNow = false;
5451 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode)) {
5452 if ((kIOPMSleepTypeStandby == params.sleepType)
5453 && gIOHibernateStandbyDisabled && gSleepPolicyVars
5454 && (!((kIOPMSleepFactorStandbyForced | kIOPMSleepFactorAutoPowerOffForced | kIOPMSleepFactorHibernateForced)
5455 & gSleepPolicyVars->sleepFactors))) {
5456 standbyNixed = true;
5457 wakeNow = true;
5458 }
5459 if (wakeNow
5460 || ((hibernateDisabled || hibernateAborted) &&
5461 (getSleepTypeAttributes(params.sleepType) &
5462 kIOPMSleepAttributeHibernateSetup))) {
5463 // Final evaluation picked a state requiring hibernation,
5464 // but hibernate isn't going to proceed. Arm a short sleep using
5465 // the early non-hibernate sleep parameters.
5466 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
5467 params.sleepType = kIOPMSleepTypeAbortedSleep;
5468 params.ecWakeTimer = 1;
5469 if (standbyNixed) {
5470 resetTimers = true;
5471 } else {
5472 // Set hibernateRetry flag to force hibernate setup on the
5473 // next sleep.
5474 hibernateRetry = true;
5475 }
5476 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
5477 params.ecWakeTimer, hibernateDisabled, hibernateAborted, standbyNixed);
5478 } else {
5479 hibernateRetry = false;
5480 }
5481
5482 if (kIOPMSleepTypeAbortedSleep != params.sleepType) {
5483 resetTimers = false;
5484 }
5485
5486 paramsData = OSData::withBytes(&params, sizeof(params));
5487 if (paramsData) {
f427ee49 5488 setProperty(kIOPMSystemSleepParametersKey, paramsData.get());
0a7de745
A
5489 }
5490
5491 if (getSleepTypeAttributes(params.sleepType) &
5492 kIOPMSleepAttributeHibernateSleep) {
5493 // Disable sleep to force hibernation
5494 gIOHibernateMode &= ~kIOHibernateModeSleep;
5495 }
5496 }
5497}
5498
5499bool
5500IOPMrootDomain::getHibernateSettings(
5501 uint32_t * hibernateModePtr,
5502 uint32_t * hibernateFreeRatio,
5503 uint32_t * hibernateFreeTime )
5504{
5505 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
5506 // has updated the hibernateDisabled flag.
5507
5508 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
5509 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
5510 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
5511 if (hibernateDisabled) {
5512 *hibernateModePtr = 0;
5513 } else if (gSleepPolicyHandler) {
5514 *hibernateModePtr = hibernateMode;
5515 }
5516 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
5517 return ok;
5518}
5519
5520bool
5521IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
5522{
f427ee49
A
5523 OSSharedPtr<OSObject> optionsProp;
5524 OSDictionary * optionsDict;
5525 OSSharedPtr<OSObject> obj;
5526 OSNumber * num;
5527 bool ok = false;
0a7de745
A
5528
5529 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
f427ee49 5530 optionsDict = OSDynamicCast(OSDictionary, optionsProp.get());
0a7de745
A
5531
5532 if (optionsDict) {
f427ee49 5533 obj.reset(optionsDict->getObject(key), OSRetain);
0a7de745
A
5534 }
5535 if (!obj) {
5536 obj = copyProperty(key);
5537 }
5538 if (obj) {
f427ee49 5539 if ((num = OSDynamicCast(OSNumber, obj.get()))) {
0a7de745
A
5540 *option = num->unsigned32BitValue();
5541 ok = true;
f427ee49 5542 } else if (OSDynamicCast(OSBoolean, obj.get())) {
0a7de745
A
5543 *option = (obj == kOSBooleanTrue) ? 1 : 0;
5544 ok = true;
5545 }
5546 }
6d2010ae 5547
0a7de745
A
5548 return ok;
5549}
5550#endif /* HIBERNATION */
fe8ab488 5551
0a7de745
A
5552IOReturn
5553IOPMrootDomain::getSystemSleepType( uint32_t * sleepType, uint32_t * standbyTimer )
5554{
fe8ab488 5555#if HIBERNATION
0a7de745
A
5556 IOPMSystemSleepParameters params;
5557 uint32_t hibMode = 0;
5558 bool ok;
5559
5560 if (gIOPMWorkLoop->inGate() == false) {
5561 IOReturn ret = gIOPMWorkLoop->runAction(
5562 OSMemberFunctionCast(IOWorkLoop::Action, this,
5563 &IOPMrootDomain::getSystemSleepType),
5564 (OSObject *) this,
5565 (void *) sleepType, (void *) standbyTimer);
5566 return ret;
5567 }
5568
5569 getSleepOption(kIOHibernateModeKey, &hibMode);
5570 bzero(&params, sizeof(params));
5571
5572 ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
5573 if (ok) {
5574 *sleepType = params.sleepType;
5575 if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer) &&
5576 !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
5577 DLOG("Standby delay is not set\n");
5578 *standbyTimer = 0;
5579 }
5580 return kIOReturnSuccess;
5581 }
db609669 5582#endif
0a7de745
A
5583
5584 return kIOReturnUnsupported;
5585}
5586
5587// MARK: -
5588// MARK: Shutdown and Restart
5589
5590//******************************************************************************
5591// handlePlatformHaltRestart
5592//
5593//******************************************************************************
5594
5595// Phases while performing shutdown/restart
5596typedef enum {
5597 kNotifyDone = 0x00,
5598 kNotifyPriorityClients = 0x10,
5599 kNotifyPowerPlaneDrivers = 0x20,
5600 kNotifyHaltRestartAction = 0x30,
5601 kQuiescePM = 0x40,
5602} shutdownPhase_t;
5603
5604
5605struct HaltRestartApplierContext {
5606 IOPMrootDomain * RootDomain;
5607 unsigned long PowerState;
5608 IOPMPowerFlags PowerFlags;
5609 UInt32 MessageType;
5610 UInt32 Counter;
5611 const char * LogString;
5612 shutdownPhase_t phase;
5613
5614 IOServiceInterestHandler handler;
5615} gHaltRestartCtx;
5616
5617const char *
5618shutdownPhase2String(shutdownPhase_t phase)
5619{
5620 switch (phase) {
5621 case kNotifyDone:
5622 return "Notifications completed";
5623 case kNotifyPriorityClients:
5624 return "Notifying priority clients";
5625 case kNotifyPowerPlaneDrivers:
5626 return "Notifying power plane drivers";
5627 case kNotifyHaltRestartAction:
5628 return "Notifying HaltRestart action handlers";
5629 case kQuiescePM:
5630 return "Quiescing PM";
5631 default:
5632 return "Unknown";
5633 }
5634}
5635
5636static void
5637platformHaltRestartApplier( OSObject * object, void * context )
5638{
5639 IOPowerStateChangeNotification notify;
5640 HaltRestartApplierContext * ctx;
5641 AbsoluteTime startTime, elapsedTime;
5642 uint32_t deltaTime;
5643
5644 ctx = (HaltRestartApplierContext *) context;
5645
5646 _IOServiceInterestNotifier * notifier;
5647 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5648 memset(&notify, 0, sizeof(notify));
5649 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
5650 notify.returnValue = 0;
5651 notify.stateNumber = ctx->PowerState;
5652 notify.stateFlags = ctx->PowerFlags;
5653
5654 if (notifier) {
5655 ctx->handler = notifier->handler;
5656 }
5657
5658 clock_get_uptime(&startTime);
5659 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
5660 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5661
5662 if ((deltaTime > kPMHaltTimeoutMS) && notifier) {
5663 LOG("%s handler %p took %u ms\n",
5664 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
5665 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier->handler, elapsedTime);
5666 }
5667
cb323159 5668 ctx->handler = NULL;
0a7de745
A
5669 ctx->Counter++;
5670}
5671
5672static void
5673quiescePowerTreeCallback( void * target, void * param )
5674{
5675 IOLockLock(gPMHaltLock);
5676 gPMQuiesced = true;
5677 thread_wakeup(param);
5678 IOLockUnlock(gPMHaltLock);
5679}
5680
5681void
5682IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
5683{
5684 AbsoluteTime startTime, elapsedTime;
5685 uint32_t deltaTime;
5686
5687 memset(&gHaltRestartCtx, 0, sizeof(gHaltRestartCtx));
5688 gHaltRestartCtx.RootDomain = this;
5689
5690 clock_get_uptime(&startTime);
5691 switch (pe_type) {
5692 case kPEHaltCPU:
5693 case kPEUPSDelayHaltCPU:
5694 gHaltRestartCtx.PowerState = OFF_STATE;
5695 gHaltRestartCtx.MessageType = kIOMessageSystemWillPowerOff;
5696 gHaltRestartCtx.LogString = "PowerOff";
5697 break;
5698
5699 case kPERestartCPU:
5700 gHaltRestartCtx.PowerState = RESTART_STATE;
5701 gHaltRestartCtx.MessageType = kIOMessageSystemWillRestart;
5702 gHaltRestartCtx.LogString = "Restart";
5703 break;
5704
5705 case kPEPagingOff:
5706 gHaltRestartCtx.PowerState = ON_STATE;
5707 gHaltRestartCtx.MessageType = kIOMessageSystemPagingOff;
5708 gHaltRestartCtx.LogString = "PagingOff";
5709 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
5710#if HIBERNATION
5711 IOHibernateSystemRestart();
5712#endif
5713 break;
5714
5715 default:
5716 return;
5717 }
5718
5719 gHaltRestartCtx.phase = kNotifyPriorityClients;
5720 // Notify legacy clients
5721 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &gHaltRestartCtx);
5722
5723 // For normal shutdown, turn off File Server Mode.
5724 if (kPEHaltCPU == pe_type) {
f427ee49
A
5725 OSSharedPtr<const OSSymbol> setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
5726 OSSharedPtr<OSNumber> num = OSNumber::withNumber((unsigned long long) 0, 32);
0a7de745 5727 if (setting && num) {
f427ee49 5728 setPMSetting(setting.get(), num.get());
0a7de745
A
5729 }
5730 }
5731
0a7de745
A
5732 if (kPEPagingOff != pe_type) {
5733 gHaltRestartCtx.phase = kNotifyPowerPlaneDrivers;
5734 // Notify in power tree order
5735 notifySystemShutdown(this, gHaltRestartCtx.MessageType);
5736 }
5737
5738 gHaltRestartCtx.phase = kNotifyHaltRestartAction;
f427ee49 5739#if defined(XNU_TARGET_OS_OSX)
0a7de745 5740 IOCPURunPlatformHaltRestartActions(pe_type);
f427ee49 5741#else /* !defined(XNU_TARGET_OS_OSX) */
cb323159
A
5742 if (kPEPagingOff != pe_type) {
5743 IOCPURunPlatformHaltRestartActions(pe_type);
5744 }
f427ee49 5745#endif /* !defined(XNU_TARGET_OS_OSX) */
0a7de745
A
5746
5747 // Wait for PM to quiesce
5748 if ((kPEPagingOff != pe_type) && gPMHaltLock) {
5749 gHaltRestartCtx.phase = kQuiescePM;
5750 AbsoluteTime quiesceTime = mach_absolute_time();
5751
5752 IOLockLock(gPMHaltLock);
5753 gPMQuiesced = false;
5754 if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
5755 kIOReturnSuccess) {
5756 while (!gPMQuiesced) {
5757 IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
5758 }
5759 }
5760 IOLockUnlock(gPMHaltLock);
5761 deltaTime = computeDeltaTimeMS(&quiesceTime, &elapsedTime);
5762 DLOG("PM quiesce took %u ms\n", deltaTime);
5763 halt_log_enter("Quiesce", NULL, elapsedTime);
5764 }
5765 gHaltRestartCtx.phase = kNotifyDone;
5766
5767 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5768 LOG("%s all drivers took %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5769
5770 halt_log_enter(gHaltRestartCtx.LogString, NULL, elapsedTime);
5771
5772 deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
5773 LOG("%s total %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5774
5775 if (gHaltLog && gHaltTimeMaxLog && (deltaTime >= gHaltTimeMaxLog)) {
5776 printf("%s total %d ms:%s\n", gHaltRestartCtx.LogString, deltaTime, gHaltLog);
5777 }
5778
5779 checkShutdownTimeout();
5780}
5781
5782bool
5783IOPMrootDomain::checkShutdownTimeout()
5784{
5785 AbsoluteTime elapsedTime;
5786 uint32_t deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
5787
5788 if (gHaltTimeMaxPanic && (deltaTime >= gHaltTimeMaxPanic)) {
5789 return true;
5790 }
5791 return false;
5792}
5793
5794void
5795IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs)
5796{
5797 if (gHaltLog) {
5798 if ((gHaltRestartCtx.phase == kNotifyPriorityClients) && gHaltRestartCtx.handler) {
5799 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx.handler, mach_absolute_time() - gHaltStartTime);
5800 }
5801 panic("%s timed out in phase '%s'. Total %d ms:%s",
5802 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs, gHaltLog);
5803 } else {
5804 panic("%s timed out in phase \'%s\'. Total %d ms",
5805 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs);
5806 }
0b4c1975 5807}
0b4c1975 5808
b0d623f7 5809//******************************************************************************
6d2010ae 5810// shutdownSystem
b0d623f7 5811//
b0d623f7
A
5812//******************************************************************************
5813
0a7de745
A
5814IOReturn
5815IOPMrootDomain::shutdownSystem( void )
b0d623f7 5816{
0a7de745 5817 return kIOReturnUnsupported;
6d2010ae 5818}
0b4c1975 5819
6d2010ae
A
5820//******************************************************************************
5821// restartSystem
5822//
5823//******************************************************************************
0b4c1975 5824
0a7de745
A
5825IOReturn
5826IOPMrootDomain::restartSystem( void )
6d2010ae 5827{
0a7de745 5828 return kIOReturnUnsupported;
b0d623f7
A
5829}
5830
6d2010ae
A
5831// MARK: -
5832// MARK: System Capability
b0d623f7 5833
4a3eedf9 5834//******************************************************************************
6d2010ae 5835// tagPowerPlaneService
4a3eedf9 5836//
6d2010ae 5837// Running on PM work loop thread.
4a3eedf9 5838//******************************************************************************
b0d623f7 5839
0a7de745
A
5840void
5841IOPMrootDomain::tagPowerPlaneService(
f427ee49
A
5842 IOService * service,
5843 IOPMActions * actions,
5844 IOPMPowerStateIndex maxPowerState )
4a3eedf9 5845{
0a7de745 5846 uint32_t flags = 0;
4a3eedf9 5847
0a7de745
A
5848 memset(actions, 0, sizeof(*actions));
5849 actions->target = this;
4a3eedf9 5850
0a7de745
A
5851 if (service == this) {
5852 actions->actionPowerChangeStart =
5853 OSMemberFunctionCast(
5854 IOPMActionPowerChangeStart, this,
5855 &IOPMrootDomain::handleOurPowerChangeStart);
4a3eedf9 5856
0a7de745
A
5857 actions->actionPowerChangeDone =
5858 OSMemberFunctionCast(
5859 IOPMActionPowerChangeDone, this,
5860 &IOPMrootDomain::handleOurPowerChangeDone);
4a3eedf9 5861
0a7de745
A
5862 actions->actionPowerChangeOverride =
5863 OSMemberFunctionCast(
5864 IOPMActionPowerChangeOverride, this,
5865 &IOPMrootDomain::overrideOurPowerChange);
5866 return;
5867 }
4a3eedf9 5868
f427ee49
A
5869#if DISPLAY_WRANGLER_PRESENT
5870 if (NULL != service->metaCast("IODisplayWrangler")) {
5871 // XXX should this really retain?
5872 wrangler.reset(service, OSRetain);
5873 wrangler->registerInterest(gIOGeneralInterest,
5874 &displayWranglerNotification, this, NULL);
5875
d26ffc64
A
5876 // found the display wrangler, check for any display assertions already created
5877 if (pmAssertions->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit) {
5878 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
5879 wrangler->setIgnoreIdleTimer( true );
5880 }
f427ee49 5881 flags |= kPMActionsFlagIsDisplayWrangler;
0a7de745 5882 }
f427ee49 5883#endif /* DISPLAY_WRANGLER_PRESENT */
4a3eedf9 5884
f427ee49
A
5885 if (service->propertyExists("IOPMStrictTreeOrder")) {
5886 flags |= kPMActionsFlagIsGraphicsDriver;
0a7de745 5887 }
f427ee49
A
5888 if (service->propertyExists("IOPMUnattendedWakePowerState")) {
5889 flags |= kPMActionsFlagIsAudioDriver;
0a7de745 5890 }
f427ee49
A
5891
5892 OSSharedPtr<OSObject> prop = service->copyProperty(kIOPMDarkWakeMaxPowerStateKey);
5893 if (prop) {
5894 OSNumber * num = OSDynamicCast(OSNumber, prop.get());
5895 if (num) {
5896 actions->darkWakePowerState = num->unsigned32BitValue();
5897 if (actions->darkWakePowerState < maxPowerState) {
5898 flags |= kPMActionsFlagHasDarkWakePowerState;
5899 }
5900 }
0a7de745 5901 }
4a3eedf9 5902
0a7de745
A
5903 // Find the power connection object that is a child of the PCI host
5904 // bridge, and has a graphics/audio device attached below. Mark the
5905 // power branch for delayed child notifications.
5906
5907 if (flags) {
5908 IORegistryEntry * child = service;
5909 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
5910
5911 while (child != this) {
f427ee49 5912 if (child->propertyHasValue("IOPCITunnelled", kOSBooleanTrue)) {
0a7de745
A
5913 // Skip delaying notifications and clamping power on external graphics and audio devices.
5914 DLOG("Avoiding delayChildNotification on object 0x%llx. flags: 0x%x\n", service->getRegistryEntryID(), flags);
5915 flags = 0;
5916 break;
5917 }
5918 if ((parent == pciHostBridgeDriver) ||
5919 (parent == this)) {
5920 if (OSDynamicCast(IOPowerConnection, child)) {
5921 IOPowerConnection * conn = (IOPowerConnection *) child;
5922 conn->delayChildNotification = true;
5923 DLOG("delayChildNotification for 0x%llx\n", conn->getRegistryEntryID());
5924 }
5925 break;
5926 }
5927 child = parent;
5928 parent = child->getParentEntry(gIOPowerPlane);
5929 }
5930 }
5931
5932 if (flags) {
5933 DLOG("%s tag flags %x\n", service->getName(), flags);
f427ee49 5934 actions->flags |= flags;
0a7de745
A
5935 actions->actionPowerChangeOverride =
5936 OSMemberFunctionCast(
5937 IOPMActionPowerChangeOverride, this,
f427ee49 5938 &IOPMrootDomain::overridePowerChangeForService);
0a7de745
A
5939
5940 if (flags & kPMActionsFlagIsDisplayWrangler) {
5941 actions->actionActivityTickle =
5942 OSMemberFunctionCast(
5943 IOPMActionActivityTickle, this,
5944 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
5945
5946 actions->actionUpdatePowerClient =
5947 OSMemberFunctionCast(
5948 IOPMActionUpdatePowerClient, this,
5949 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
5950 }
5951 return;
5952 }
5953
5954 // Locate the first PCI host bridge for PMTrace.
5955 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge")) {
5956 IOService * provider = service->getProvider();
5957 if (OSDynamicCast(IOPlatformDevice, provider) &&
5958 provider->inPlane(gIODTPlane)) {
f427ee49
A
5959 pciHostBridgeDevice.reset(provider, OSNoRetain);
5960 pciHostBridgeDriver.reset(service, OSNoRetain);
0a7de745
A
5961 DLOG("PMTrace found PCI host bridge %s->%s\n",
5962 provider->getName(), service->getName());
5963 }
5964 }
5965
5966 // Tag top-level PCI devices. The order of PMinit() call does not
5967 // change across boots and is used as the PCI bit number.
5968 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice")) {
5969 // Would prefer to check built-in property, but tagPowerPlaneService()
5970 // is called before pciDevice->registerService().
5971 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
f427ee49 5972 if ((parent == pciHostBridgeDevice) && service->propertyExists("acpi-device")) {
0a7de745
A
5973 int bit = pmTracer->recordTopLevelPCIDevice( service );
5974 if (bit >= 0) {
5975 // Save the assigned bit for fast lookup.
f427ee49 5976 actions->flags |= (bit & kPMActionsPCIBitNumberMask);
0a7de745
A
5977
5978 actions->actionPowerChangeStart =
5979 OSMemberFunctionCast(
5980 IOPMActionPowerChangeStart, this,
5981 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
5982
5983 actions->actionPowerChangeDone =
5984 OSMemberFunctionCast(
5985 IOPMActionPowerChangeDone, this,
5986 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
5987 }
5988 }
5989 }
4a3eedf9
A
5990}
5991
0c530ab8 5992//******************************************************************************
6d2010ae 5993// PM actions for root domain
0c530ab8
A
5994//******************************************************************************
5995
0a7de745
A
5996void
5997IOPMrootDomain::overrideOurPowerChange(
5998 IOService * service,
5999 IOPMActions * actions,
f427ee49 6000 const IOPMRequest * request,
0a7de745 6001 IOPMPowerStateIndex * inOutPowerState,
f427ee49 6002 IOPMPowerChangeFlags * inOutChangeFlags )
0a7de745 6003{
0a7de745 6004 uint32_t changeFlags = *inOutChangeFlags;
f427ee49 6005 uint32_t desiredPowerState = (uint32_t) *inOutPowerState;
0a7de745
A
6006 uint32_t currentPowerState = (uint32_t) getPowerState();
6007
f427ee49
A
6008 if (request->getTag() == 0) {
6009 // Set a tag for any request that originates from IOServicePM
6010 (const_cast<IOPMRequest *>(request))->fTag = nextRequestTag(kCPSReasonPMInternals);
6011 }
6012
6013 DLOG("PowerChangeOverride (%s->%s, %x, 0x%x) tag 0x%x\n",
6014 getPowerStateString(currentPowerState),
6015 getPowerStateString(desiredPowerState),
6016 _currentCapability, changeFlags,
6017 request->getTag());
6018
c3c9b80d
A
6019
6020#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6021 /*
6022 * ASBM send lowBattery notifications every 1 second until the device
6023 * enters hibernation. This queues up multiple sleep requests.
6024 * After the device wakes from hibernation, none of these previously
6025 * queued sleep requests are valid.
6026 * lowBattteryCondition variable is set when ASBM notifies rootDomain
6027 * and is cleared at the very last point in sleep.
6028 * Any attempt to sleep with reason kIOPMSleepReasonLowPower without
6029 * lowBatteryCondition is invalid
6030 */
6031 if (REQUEST_TAG_TO_REASON(request->getTag()) == kIOPMSleepReasonLowPower) {
6032 if (!lowBatteryCondition) {
6033 DLOG("Duplicate lowBattery sleep");
6034 *inOutChangeFlags |= kIOPMNotDone;
6035 return;
6036 }
6037 }
6038#endif
6039
f427ee49 6040 if ((AOT_STATE == desiredPowerState) && (ON_STATE == currentPowerState)) {
cb323159
A
6041 // Assertion may have been taken in AOT leading to changePowerStateTo(AOT)
6042 *inOutChangeFlags |= kIOPMNotDone;
6043 return;
6044 }
cb323159 6045
0a7de745
A
6046 if (changeFlags & kIOPMParentInitiated) {
6047 // Root parent is permanently pegged at max power,
6048 // a parent initiated power change is unexpected.
6049 *inOutChangeFlags |= kIOPMNotDone;
6050 return;
6051 }
6052
f427ee49 6053 if (desiredPowerState < currentPowerState) {
0a7de745 6054 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
f427ee49 6055 // Root domain is dropping power state from ON->SLEEP.
0a7de745
A
6056 // If system is in full wake, first enter dark wake by
6057 // converting the power drop to a capability change.
6058 // Once in dark wake, transition to sleep state ASAP.
6059
6060 darkWakeToSleepASAP = true;
6061
6062 // Drop graphics and audio capability
6063 _desiredCapability &= ~(
6064 kIOPMSystemCapabilityGraphics |
6065 kIOPMSystemCapabilityAudio);
6066
6067 // Convert to capability change (ON->ON)
cb323159 6068 *inOutPowerState = getRUN_STATE();
0a7de745
A
6069 *inOutChangeFlags |= kIOPMSynchronize;
6070
6071 // Revert device desire from SLEEP to ON
f427ee49 6072 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerOverride);
0a7de745 6073 } else {
f427ee49
A
6074 // System is already in dark wake, ok to drop power state.
6075 // Broadcast root power down to entire tree.
0a7de745
A
6076 *inOutChangeFlags |= kIOPMRootChangeDown;
6077 }
f427ee49 6078 } else if (desiredPowerState > currentPowerState) {
0a7de745
A
6079 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0) {
6080 // Broadcast power up when waking from sleep, but not for the
6081 // initial power change at boot by checking for cpu capability.
6082 *inOutChangeFlags |= kIOPMRootChangeUp;
6083 }
6084 }
6085}
6086
6087void
6088IOPMrootDomain::handleOurPowerChangeStart(
6089 IOService * service,
6090 IOPMActions * actions,
f427ee49
A
6091 const IOPMRequest * request,
6092 IOPMPowerStateIndex newPowerState,
6093 IOPMPowerChangeFlags * inOutChangeFlags )
0a7de745 6094{
f427ee49
A
6095 IOPMRequestTag requestTag = request->getTag();
6096 IOPMRequestTag sleepReason;
6097
0a7de745
A
6098 uint32_t changeFlags = *inOutChangeFlags;
6099 uint32_t currentPowerState = (uint32_t) getPowerState();
0a7de745
A
6100 bool publishSleepReason = false;
6101
f427ee49
A
6102 // Check if request has a valid sleep reason
6103 sleepReason = REQUEST_TAG_TO_REASON(requestTag);
6104 if (sleepReason < kIOPMSleepReasonClamshell) {
6105 sleepReason = kIOPMSleepReasonIdle;
6106 }
6107
0a7de745
A
6108 _systemTransitionType = kSystemTransitionNone;
6109 _systemMessageClientMask = 0;
6110 capabilityLoss = false;
6111 toldPowerdCapWillChange = false;
6112
f427ee49
A
6113 // Emergency notifications may arrive after the initial sleep request
6114 // has been queued. Override the sleep reason so powerd and others can
6115 // treat this as an emergency sleep.
0a7de745 6116 if (lowBatteryCondition) {
0a7de745 6117 sleepReason = kIOPMSleepReasonLowPower;
f427ee49
A
6118 } else if (thermalEmergencyState) {
6119 sleepReason = kIOPMSleepReasonThermalEmergency;
0a7de745
A
6120 }
6121
6122 // 1. Explicit capability change.
0a7de745 6123 if (changeFlags & kIOPMSynchronize) {
f427ee49 6124 if (newPowerState == ON_STATE) {
0a7de745
A
6125 if (changeFlags & kIOPMSyncNoChildNotify) {
6126 _systemTransitionType = kSystemTransitionNewCapClient;
6127 } else {
6128 _systemTransitionType = kSystemTransitionCapability;
6129 }
6130 }
6131 }
6132 // 2. Going to sleep (cancellation still possible).
f427ee49 6133 else if (newPowerState < currentPowerState) {
0a7de745
A
6134 _systemTransitionType = kSystemTransitionSleep;
6135 }
6136 // 3. Woke from (idle or demand) sleep.
6137 else if (!systemBooting &&
6138 (changeFlags & kIOPMSelfInitiated) &&
f427ee49 6139 (newPowerState > currentPowerState)) {
0a7de745 6140 _systemTransitionType = kSystemTransitionWake;
f427ee49 6141 _desiredCapability = kIOPMSystemCapabilityCPU | kIOPMSystemCapabilityNetwork;
0a7de745
A
6142
6143 // Early exit from dark wake to full (e.g. LID open)
6144 if (kFullWakeReasonNone != fullWakeReason) {
6145 _desiredCapability |= (
6146 kIOPMSystemCapabilityGraphics |
6147 kIOPMSystemCapabilityAudio);
f427ee49
A
6148
6149#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6150 if (fullWakeReason == kFullWakeReasonLocalUser) {
6151 darkWakeExit = true;
6152 darkWakeToSleepASAP = false;
6153 setProperty(kIOPMRootDomainWakeTypeKey, isRTCAlarmWake ?
6154 kIOPMRootDomainWakeTypeAlarm : kIOPMRootDomainWakeTypeUser);
6155 }
6156#endif
0a7de745 6157 }
39236c6e 6158#if HIBERNATION
0a7de745 6159 IOHibernateSetWakeCapabilities(_desiredCapability);
39236c6e 6160#endif
0a7de745
A
6161 }
6162
6163 // Update pending wake capability at the beginning of every
6164 // state transition (including synchronize). This will become
6165 // the current capability at the end of the transition.
6166
6167 if (kSystemTransitionSleep == _systemTransitionType) {
6168 _pendingCapability = 0;
6169 capabilityLoss = true;
6170 } else if (kSystemTransitionNewCapClient != _systemTransitionType) {
6171 _pendingCapability = _desiredCapability |
6172 kIOPMSystemCapabilityCPU |
6173 kIOPMSystemCapabilityNetwork;
6174
6175 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6176 _pendingCapability |= kIOPMSystemCapabilityAudio;
6177 }
6178
6179 if ((kSystemTransitionCapability == _systemTransitionType) &&
6180 (_pendingCapability == _currentCapability)) {
6181 // Cancel the PM state change.
6182 _systemTransitionType = kSystemTransitionNone;
6183 *inOutChangeFlags |= kIOPMNotDone;
6184 }
6185 if (__builtin_popcount(_pendingCapability) <
6186 __builtin_popcount(_currentCapability)) {
6187 capabilityLoss = true;
6188 }
6189 }
6190
6191 // 1. Capability change.
0a7de745
A
6192 if (kSystemTransitionCapability == _systemTransitionType) {
6193 // Dark to Full transition.
6194 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
6195 tracePoint( kIOPMTracePointDarkWakeExit );
6196
f427ee49
A
6197#if defined(XNU_TARGET_OS_OSX)
6198 // rdar://problem/65627936
6199 // When a dark->full wake promotion is scheduled before an ON->SLEEP
6200 // power state drop, invalidate any request to drop power state already
6201 // in the queue, including the override variant, unless full wake cannot
6202 // be sustained. Any power state drop queued after this SustainFullWake
6203 // request will not be affected.
6204 if (checkSystemCanSustainFullWake()) {
6205 changePowerStateWithOverrideTo(getRUN_STATE(), kCPSReasonSustainFullWake);
6206 }
6207#endif
6208
0a7de745
A
6209 willEnterFullWake();
6210 }
6211
6212 // Full to Dark transition.
6213 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
6214 // Clear previous stats
6215 IOLockLock(pmStatsLock);
6216 if (pmStatsAppResponses) {
0a7de745
A
6217 pmStatsAppResponses = OSArray::withCapacity(5);
6218 }
6219 IOLockUnlock(pmStatsLock);
6220
0a7de745
A
6221 tracePoint( kIOPMTracePointDarkWakeEntry );
6222 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
6223 _systemMessageClientMask = kSystemMessageClientPowerd |
6224 kSystemMessageClientLegacyApp;
6225
0a7de745
A
6226 // rdar://15971327
6227 // Prevent user active transitions before notifying clients
6228 // that system will sleep.
6229 preventTransitionToUserActive(true);
6230
6231 IOService::setAdvisoryTickleEnable( false );
6232
6233 // Publish the sleep reason for full to dark wake
6234 publishSleepReason = true;
6235 lastSleepReason = fullToDarkReason = sleepReason;
6236
6237 // Publish a UUID for the Sleep --> Wake cycle
6238 handlePublishSleepWakeUUID(true);
6239 if (sleepDelaysReport) {
6240 clock_get_uptime(&ts_sleepStart);
6241 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
6242 }
6243
f427ee49 6244 darkWakeExit = false;
0a7de745
A
6245 }
6246 }
6247 // 2. System sleep.
6248 else if (kSystemTransitionSleep == _systemTransitionType) {
6249 // Beginning of a system sleep transition.
6250 // Cancellation is still possible.
6251 tracePoint( kIOPMTracePointSleepStarted );
6252
6253 _systemMessageClientMask = kSystemMessageClientAll;
6254 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) {
6255 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
6256 }
6257 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) {
cb323159
A
6258 // Kernel priority clients are only notified on the initial
6259 // transition to full wake, so don't notify them unless system
6260 // has gained graphics capability since the last system wake.
0a7de745 6261 _systemMessageClientMask &= ~kSystemMessageClientKernel;
f427ee49
A
6262 } else {
6263 // System was in full wake, but the downwards power transition is driven
6264 // by a request that originates from IOServicePM, so it isn't tagged with
6265 // a valid system sleep reason.
6266 if (REQUEST_TAG_TO_REASON(requestTag) == kCPSReasonPMInternals) {
6267 // Publish the same reason for full to dark
6268 sleepReason = fullToDarkReason;
6269 }
0a7de745 6270 }
eee35659 6271#if HIBERNATION
0a7de745 6272 gIOHibernateState = 0;
eee35659 6273#endif
6d2010ae 6274
0a7de745
A
6275 // Record the reason for dark wake back to sleep
6276 // System may not have ever achieved full wake
6277
6278 publishSleepReason = true;
6279 lastSleepReason = sleepReason;
6280 if (sleepDelaysReport) {
6281 clock_get_uptime(&ts_sleepStart);
6282 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
6283 }
6284 }
6285 // 3. System wake.
6286 else if (kSystemTransitionWake == _systemTransitionType) {
6287 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
6288 // Clear stats about sleep
6289
f427ee49 6290 if (AOT_STATE == newPowerState) {
cb323159
A
6291 _pendingCapability = 0;
6292 }
6293
f427ee49
A
6294 if (AOT_STATE == currentPowerState) {
6295 // Wake events are no longer accepted after waking to AOT_STATE.
6296 // Re-enable wake event acceptance to append wake events claimed
6297 // during the AOT to ON_STATE transition.
6298 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Reenable);
6299 }
6300
0a7de745
A
6301 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6302 willEnterFullWake();
0a7de745
A
6303 }
6304 }
6305
6306 // The only location where the sleep reason is published. At this point
6307 // sleep can still be cancelled, but sleep reason should be published
6308 // early for logging purposes.
6309
6310 if (publishSleepReason) {
6311 static const char * IOPMSleepReasons[] =
6312 {
6313 kIOPMClamshellSleepKey,
6314 kIOPMPowerButtonSleepKey,
6315 kIOPMSoftwareSleepKey,
6316 kIOPMOSSwitchHibernationKey,
6317 kIOPMIdleSleepKey,
6318 kIOPMLowPowerSleepKey,
6319 kIOPMThermalEmergencySleepKey,
6320 kIOPMMaintenanceSleepKey,
6321 kIOPMSleepServiceExitKey,
f427ee49
A
6322 kIOPMDarkWakeThermalEmergencyKey,
6323 kIOPMNotificationWakeExitKey
0a7de745
A
6324 };
6325
6326 // Record sleep cause in IORegistry
6327 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
6328 if (reasonIndex < sizeof(IOPMSleepReasons) / sizeof(IOPMSleepReasons[0])) {
6329 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
6330 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
6331 }
6332 }
6333
6334 if ((kSystemTransitionNone != _systemTransitionType) &&
6335 (kSystemTransitionNewCapClient != _systemTransitionType)) {
6336 _systemStateGeneration++;
6337 systemDarkWake = false;
6338
f427ee49
A
6339 DLOG("=== START (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6340 getPowerStateString(currentPowerState),
6341 getPowerStateString((uint32_t) newPowerState),
6342 _currentCapability, _pendingCapability,
6343 *inOutChangeFlags, _systemStateGeneration, _systemMessageClientMask,
6344 requestTag);
0a7de745 6345 }
cb323159 6346
f427ee49 6347 if ((AOT_STATE == newPowerState) && (SLEEP_STATE != currentPowerState)) {
cb323159
A
6348 panic("illegal AOT entry from %s", getPowerStateString(currentPowerState));
6349 }
f427ee49
A
6350 if (_aotNow && (ON_STATE == newPowerState)) {
6351 WAKEEVENT_LOCK();
cb323159 6352 aotShouldExit(false, true);
f427ee49 6353 WAKEEVENT_UNLOCK();
cb323159
A
6354 aotExit(false);
6355 }
0a7de745
A
6356}
6357
6358void
6359IOPMrootDomain::handleOurPowerChangeDone(
6360 IOService * service,
6361 IOPMActions * actions,
f427ee49
A
6362 const IOPMRequest * request,
6363 IOPMPowerStateIndex oldPowerState,
6364 IOPMPowerChangeFlags changeFlags )
0a7de745
A
6365{
6366 if (kSystemTransitionNewCapClient == _systemTransitionType) {
6367 _systemTransitionType = kSystemTransitionNone;
6368 return;
6369 }
6370
6371 if (_systemTransitionType != kSystemTransitionNone) {
6372 uint32_t currentPowerState = (uint32_t) getPowerState();
6373
6374 if (changeFlags & kIOPMNotDone) {
6375 // Power down was cancelled or vetoed.
6376 _pendingCapability = _currentCapability;
6377 lastSleepReason = 0;
6378
f427ee49
A
6379 // When sleep is cancelled or reverted, don't report
6380 // the target (lower) power state as the previous state.
6381 oldPowerState = currentPowerState;
6382
0a7de745
A
6383 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
6384 CAP_CURRENT(kIOPMSystemCapabilityCPU)) {
f427ee49 6385#if defined(XNU_TARGET_OS_OSX)
0a7de745
A
6386 pmPowerStateQueue->submitPowerEvent(
6387 kPowerEventPolicyStimulus,
6388 (void *) kStimulusDarkWakeReentry,
6389 _systemStateGeneration );
f427ee49 6390#else /* !defined(XNU_TARGET_OS_OSX) */
0a7de745
A
6391 // On embedded, there are no factors that can prolong a
6392 // "darkWake" when a power down is vetoed. We need to
6393 // promote to "fullWake" at least once so that factors
6394 // that prevent idle sleep can assert themselves if required
6395 pmPowerStateQueue->submitPowerEvent(
6396 kPowerEventPolicyStimulus,
6397 (void *) kStimulusDarkWakeActivityTickle);
f427ee49 6398#endif /* !defined(XNU_TARGET_OS_OSX) */
0a7de745
A
6399 }
6400
6401 // Revert device desire to max.
f427ee49 6402 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerDownCancel);
0a7de745
A
6403 } else {
6404 // Send message on dark wake to full wake promotion.
6405 // tellChangeUp() handles the normal SLEEP->ON case.
6406
6407 if (kSystemTransitionCapability == _systemTransitionType) {
6408 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
6409 lastSleepReason = 0; // stop logging wrangler tickles
6410 tellClients(kIOMessageSystemHasPoweredOn);
6411 }
6412 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
6413 // Going dark, reset full wake state
6414 // userIsActive will be cleared by wrangler powering down
6415 fullWakeReason = kFullWakeReasonNone;
6416
6417 if (ts_sleepStart) {
6418 clock_get_uptime(&wake2DarkwakeDelay);
6419 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
6420 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
6421 ts_sleepStart = 0;
6422 }
6423 }
6424 }
6425
6426 // Reset state after exiting from dark wake.
6427
6428 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
6429 CAP_LOSS(kIOPMSystemCapabilityCPU)) {
6430 darkWakeMaintenance = false;
6431 darkWakeToSleepASAP = false;
6432 pciCantSleepValid = false;
6433 darkWakeSleepService = false;
6434
6435 if (CAP_LOSS(kIOPMSystemCapabilityCPU)) {
6436 // Remove the influence of display power assertion
6437 // before next system wake.
6438 if (wrangler) {
6439 wrangler->changePowerStateForRootDomain(
6440 kWranglerPowerStateMin );
6441 }
f427ee49 6442 removeProperty(gIOPMUserTriggeredFullWakeKey.get());
0a7de745
A
6443 }
6444 }
6445
6446 // Entered dark mode.
6447
6448 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6449 (_pendingCapability & kIOPMSystemCapabilityCPU)) {
6450 // Queue an evaluation of whether to remain in dark wake,
6451 // and for how long. This serves the purpose of draining
6452 // any assertions from the queue.
6453
6454 pmPowerStateQueue->submitPowerEvent(
6455 kPowerEventPolicyStimulus,
6456 (void *) kStimulusDarkWakeEntry,
6457 _systemStateGeneration );
6458 }
6459 }
6460
f427ee49
A
6461 DLOG("=== FINISH (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6462 getPowerStateString((uint32_t) oldPowerState), getPowerStateString(currentPowerState),
6463 _currentCapability, _pendingCapability,
6464 changeFlags, _systemStateGeneration, _systemMessageClientMask,
6465 request->getTag());
6466
6467 if ((currentPowerState == ON_STATE) && pmAssertions) {
6468 pmAssertions->reportCPUBitAccounting();
6469 }
0a7de745
A
6470
6471 if (_pendingCapability & kIOPMSystemCapabilityGraphics) {
6472 displayWakeCnt++;
f427ee49
A
6473#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
6474 if (clamshellExists && fullWakeThreadCall) {
0a7de745 6475 AbsoluteTime deadline;
f427ee49 6476 clock_interval_to_deadline(DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY, kSecondScale, &deadline);
0a7de745
A
6477 thread_call_enter_delayed(fullWakeThreadCall, deadline);
6478 }
39236c6e 6479#endif
0a7de745
A
6480 } else if (CAP_GAIN(kIOPMSystemCapabilityCPU)) {
6481 darkWakeCnt++;
6482 }
0c530ab8 6483
0a7de745
A
6484 // Update current system capability.
6485 if (_currentCapability != _pendingCapability) {
6486 _currentCapability = _pendingCapability;
6487 }
6d2010ae 6488
0a7de745 6489 // Update highest system capability.
6d2010ae 6490
0a7de745 6491 _highestCapability |= _currentCapability;
6d2010ae 6492
0a7de745
A
6493 if (darkWakePostTickle &&
6494 (kSystemTransitionWake == _systemTransitionType) &&
f427ee49
A
6495 (gDarkWakeFlags & kDarkWakeFlagPromotionMask) ==
6496 kDarkWakeFlagPromotionLate) {
0a7de745
A
6497 darkWakePostTickle = false;
6498 reportUserInput();
f427ee49 6499 } else if (darkWakeExit) {
0a7de745
A
6500 requestFullWake( kFullWakeReasonLocalUser );
6501 }
6d2010ae 6502
0a7de745
A
6503 // Reset tracepoint at completion of capability change,
6504 // completion of wake transition, and aborted sleep transition.
0c530ab8 6505
0a7de745
A
6506 if ((_systemTransitionType == kSystemTransitionCapability) ||
6507 (_systemTransitionType == kSystemTransitionWake) ||
6508 ((_systemTransitionType == kSystemTransitionSleep) &&
6509 (changeFlags & kIOPMNotDone))) {
6510 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
6511 tracePoint( kIOPMTracePointSystemUp );
6512 }
0c530ab8 6513
0a7de745
A
6514 _systemTransitionType = kSystemTransitionNone;
6515 _systemMessageClientMask = 0;
6516 toldPowerdCapWillChange = false;
39037602 6517
f427ee49 6518 darkWakeLogClamp = false;
743345f9 6519
0a7de745
A
6520 if (lowBatteryCondition) {
6521 privateSleepSystem(kIOPMSleepReasonLowPower);
f427ee49
A
6522 } else if (thermalEmergencyState) {
6523 privateSleepSystem(kIOPMSleepReasonThermalEmergency);
6524 } else if ((fullWakeReason == kFullWakeReasonDisplayOn) && !displayPowerOnRequested) {
0a7de745
A
6525 // Request for full wake is removed while system is waking up to full wake
6526 DLOG("DisplayOn fullwake request is removed\n");
f427ee49 6527 handleSetDisplayPowerOn(false);
0a7de745 6528 }
cb323159 6529
f427ee49 6530 if ((gClamshellFlags & kClamshell_WAR_47715679) && isRTCAlarmWake) {
cb323159
A
6531 pmPowerStateQueue->submitPowerEvent(
6532 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) kLocalEvalClamshellCommand );
6533 }
0a7de745 6534 }
6d2010ae 6535}
0c530ab8 6536
6d2010ae
A
6537//******************************************************************************
6538// PM actions for graphics and audio.
6539//******************************************************************************
6540
0a7de745 6541void
f427ee49 6542IOPMrootDomain::overridePowerChangeForService(
0a7de745
A
6543 IOService * service,
6544 IOPMActions * actions,
f427ee49 6545 const IOPMRequest * request,
0a7de745
A
6546 IOPMPowerStateIndex * inOutPowerState,
6547 IOPMPowerChangeFlags * inOutChangeFlags )
6548{
6549 uint32_t powerState = (uint32_t) *inOutPowerState;
6550 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
f427ee49 6551 const uint32_t actionFlags = actions->flags;
0a7de745
A
6552
6553 if (kSystemTransitionNone == _systemTransitionType) {
6554 // Not in midst of a system transition.
f427ee49
A
6555 // Do not set kPMActionsStatePowerClamped.
6556 } else if ((actions->state & kPMActionsStatePowerClamped) == 0) {
6557 bool enableClamp = false;
0a7de745 6558
f427ee49
A
6559 // For most drivers, enable the clamp during ON->Dark transition
6560 // which has the kIOPMSynchronize flag set in changeFlags.
6561 if ((actionFlags & kPMActionsFlagIsDisplayWrangler) &&
0a7de745
A
6562 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6563 (changeFlags & kIOPMSynchronize)) {
f427ee49
A
6564 enableClamp = true;
6565 } else if ((actionFlags & kPMActionsFlagIsAudioDriver) &&
0a7de745
A
6566 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
6567 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
6568 (changeFlags & kIOPMSynchronize)) {
f427ee49
A
6569 enableClamp = true;
6570 } else if ((actionFlags & kPMActionsFlagHasDarkWakePowerState) &&
6571 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
6572 (changeFlags & kIOPMSynchronize)) {
6573 enableClamp = true;
6574 } else if ((actionFlags & kPMActionsFlagIsGraphicsDriver) &&
0a7de745 6575 (_systemTransitionType == kSystemTransitionSleep)) {
f427ee49 6576 // For graphics drivers, clamp power when entering
0a7de745 6577 // system sleep. Not when dropping to dark wake.
f427ee49 6578 enableClamp = true;
0a7de745
A
6579 }
6580
f427ee49
A
6581 if (enableClamp) {
6582 actions->state |= kPMActionsStatePowerClamped;
6583 DLOG("power clamp enabled %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6584 service->getName(), service->getRegistryEntryID(),
6585 _pendingCapability, powerState, changeFlags);
0a7de745 6586 }
f427ee49
A
6587 } else if ((actions->state & kPMActionsStatePowerClamped) != 0) {
6588 bool disableClamp = false;
0a7de745 6589
f427ee49 6590 if ((actionFlags & (
0a7de745 6591 kPMActionsFlagIsDisplayWrangler |
f427ee49 6592 kPMActionsFlagIsGraphicsDriver)) &&
0a7de745 6593 (_pendingCapability & kIOPMSystemCapabilityGraphics)) {
f427ee49
A
6594 disableClamp = true;
6595 } else if ((actionFlags & kPMActionsFlagIsAudioDriver) &&
0a7de745 6596 (_pendingCapability & kIOPMSystemCapabilityAudio)) {
f427ee49
A
6597 disableClamp = true;
6598 } else if ((actionFlags & kPMActionsFlagHasDarkWakePowerState) &&
6599 (_pendingCapability & kIOPMSystemCapabilityGraphics)) {
6600 disableClamp = true;
0a7de745
A
6601 }
6602
f427ee49
A
6603 if (disableClamp) {
6604 actions->state &= ~kPMActionsStatePowerClamped;
6605 DLOG("power clamp removed %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6606 service->getName(), service->getRegistryEntryID(),
6607 _pendingCapability, powerState, changeFlags);
0a7de745
A
6608 }
6609 }
6610
f427ee49
A
6611 if (actions->state & kPMActionsStatePowerClamped) {
6612 uint32_t maxPowerState = 0;
0a7de745 6613
f427ee49 6614 // Determine the max power state allowed when clamp is enabled
0a7de745 6615 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange)) {
f427ee49 6616 // Parent intiated power state changes
0a7de745 6617 if ((service->getPowerState() > maxPowerState) &&
f427ee49 6618 (actionFlags & kPMActionsFlagIsDisplayWrangler)) {
0a7de745
A
6619 maxPowerState++;
6620
6621 // Remove lingering effects of any tickle before entering
6622 // dark wake. It will take a new tickle to return to full
6623 // wake, so the existing tickle state is useless.
6624
6625 if (changeFlags & kIOPMDomainDidChange) {
6626 *inOutChangeFlags |= kIOPMExpireIdleTimer;
6627 }
f427ee49 6628 } else if (actionFlags & kPMActionsFlagIsGraphicsDriver) {
0a7de745 6629 maxPowerState++;
f427ee49
A
6630 } else if (actionFlags & kPMActionsFlagHasDarkWakePowerState) {
6631 maxPowerState = actions->darkWakePowerState;
0a7de745
A
6632 }
6633 } else {
6634 // Deny all self-initiated changes when power is limited.
6635 // Wrangler tickle should never defeat the limiter.
0a7de745
A
6636 maxPowerState = service->getPowerState();
6637 }
6638
6639 if (powerState > maxPowerState) {
f427ee49
A
6640 DLOG("power clamped %s %qx, ps %u->%u, cflags 0x%x)\n",
6641 service->getName(), service->getRegistryEntryID(),
6642 powerState, maxPowerState, changeFlags);
0a7de745
A
6643 *inOutPowerState = maxPowerState;
6644
6645 if (darkWakePostTickle &&
f427ee49 6646 (actionFlags & kPMActionsFlagIsDisplayWrangler) &&
0a7de745 6647 (changeFlags & kIOPMDomainWillChange) &&
f427ee49
A
6648 ((gDarkWakeFlags & kDarkWakeFlagPromotionMask) ==
6649 kDarkWakeFlagPromotionEarly)) {
0a7de745
A
6650 darkWakePostTickle = false;
6651 reportUserInput();
6652 }
6653 }
6654
f427ee49
A
6655 if (!darkWakePowerClamped && (changeFlags & kIOPMDomainDidChange)) {
6656 if (darkWakeLogClamp) {
0a7de745
A
6657 AbsoluteTime now;
6658 uint64_t nsec;
6659
6660 clock_get_uptime(&now);
6661 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
6662 absolutetime_to_nanoseconds(now, &nsec);
f427ee49
A
6663 DLOG("dark wake power clamped after %u ms\n",
6664 ((int)((nsec) / NSEC_PER_MSEC)));
0a7de745 6665 }
f427ee49 6666 darkWakePowerClamped = true;
0a7de745
A
6667 }
6668 }
6669}
6670
6671void
6672IOPMrootDomain::handleActivityTickleForDisplayWrangler(
6673 IOService * service,
6674 IOPMActions * actions )
6d2010ae 6675{
f427ee49 6676#if DISPLAY_WRANGLER_PRESENT
0a7de745
A
6677 // Warning: Not running in PM work loop context - don't modify state !!!
6678 // Trap tickle directed to IODisplayWrangler while running with graphics
6679 // capability suppressed.
6680
6681 assert(service == wrangler);
6682
6683 clock_get_uptime(&userActivityTime);
6684 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
6685 || (lastSleepReason == kIOPMSleepReasonMaintenance)
6686 || (lastSleepReason == kIOPMSleepReasonSoftware));
6687 if (aborting) {
6688 userActivityCount++;
6689 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
6690 userActivityCount, lastSleepReason);
6691 }
6692
f427ee49 6693 if (!darkWakeExit && ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0)) {
0a7de745
A
6694 DLOG("display wrangler tickled\n");
6695 if (kIOLogPMRootDomain & gIOKitDebug) {
6696 OSReportWithBacktrace("Dark wake display tickle");
6697 }
6698 if (pmPowerStateQueue) {
6699 pmPowerStateQueue->submitPowerEvent(
6700 kPowerEventPolicyStimulus,
6701 (void *) kStimulusDarkWakeActivityTickle,
6702 true /* set wake type */ );
6703 }
6704 }
f427ee49 6705#endif /* DISPLAY_WRANGLER_PRESENT */
1c79356b
A
6706}
6707
0a7de745
A
6708void
6709IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
6710 IOService * service,
6711 IOPMActions * actions,
6712 const OSSymbol * powerClient,
6713 IOPMPowerStateIndex oldPowerState,
6714 IOPMPowerStateIndex newPowerState )
39236c6e 6715{
f427ee49 6716#if DISPLAY_WRANGLER_PRESENT
0a7de745
A
6717 assert(service == wrangler);
6718
6719 // This function implements half of the user active detection
6720 // by monitoring changes to the display wrangler's device desire.
6721 //
6722 // User becomes active when either:
6723 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
6724 // in max power state. This desire change in absence of a power state
6725 // change is detected within. This handles the case when user becomes
6726 // active while the display is already lit by setDisplayPowerOn().
6727 //
6728 // 2. Power state change to max, and DeviceDesire is also at max.
6729 // Handled by displayWranglerNotification().
6730 //
6731 // User becomes inactive when DeviceDesire drops to sleep state or below.
6732
6733 DLOG("wrangler %s (ps %u, %u->%u)\n",
6734 powerClient->getCStringNoCopy(),
6735 (uint32_t) service->getPowerState(),
6736 (uint32_t) oldPowerState, (uint32_t) newPowerState);
6737
6738 if (powerClient == gIOPMPowerClientDevice) {
6739 if ((newPowerState > oldPowerState) &&
6740 (newPowerState == kWranglerPowerStateMax) &&
6741 (service->getPowerState() == kWranglerPowerStateMax)) {
6742 evaluatePolicy( kStimulusEnterUserActiveState );
6743 } else if ((newPowerState < oldPowerState) &&
6744 (newPowerState <= kWranglerPowerStateSleep)) {
6745 evaluatePolicy( kStimulusLeaveUserActiveState );
6746 }
6747 }
6748
6749 if (newPowerState <= kWranglerPowerStateSleep) {
6750 evaluatePolicy( kStimulusDisplayWranglerSleep );
6751 } else if (newPowerState == kWranglerPowerStateMax) {
6752 evaluatePolicy( kStimulusDisplayWranglerWake );
6753 }
f427ee49 6754#endif /* DISPLAY_WRANGLER_PRESENT */
22ba694c
A
6755}
6756
6757//******************************************************************************
6758// User active state management
6759//******************************************************************************
6760
0a7de745
A
6761void
6762IOPMrootDomain::preventTransitionToUserActive( bool prevent )
22ba694c 6763{
f427ee49 6764#if DISPLAY_WRANGLER_PRESENT
0a7de745
A
6765 _preventUserActive = prevent;
6766 if (wrangler && !_preventUserActive) {
6767 // Allowing transition to user active, but the wrangler may have
6768 // already powered ON in case of sleep cancel/revert. Poll the
6769 // same conditions checked for in displayWranglerNotification()
6770 // to bring the user active state up to date.
6771
6772 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
6773 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
6774 kWranglerPowerStateMax)) {
6775 evaluatePolicy( kStimulusEnterUserActiveState );
6776 }
6777 }
f427ee49 6778#endif /* DISPLAY_WRANGLER_PRESENT */
39236c6e
A
6779}
6780
b0d623f7 6781//******************************************************************************
6d2010ae 6782// Approve usage of delayed child notification by PM.
b0d623f7 6783//******************************************************************************
1c79356b 6784
0a7de745
A
6785bool
6786IOPMrootDomain::shouldDelayChildNotification(
6787 IOService * service )
1c79356b 6788{
f427ee49 6789 if ((kFullWakeReasonNone == fullWakeReason) &&
0a7de745
A
6790 (kSystemTransitionWake == _systemTransitionType)) {
6791 DLOG("%s: delay child notify\n", service->getName());
6792 return true;
6793 }
6794 return false;
b0d623f7 6795}
0b4e3aa0 6796
b0d623f7 6797//******************************************************************************
6d2010ae 6798// PM actions for PCI device.
b0d623f7
A
6799//******************************************************************************
6800
0a7de745
A
6801void
6802IOPMrootDomain::handlePowerChangeStartForPCIDevice(
6803 IOService * service,
6804 IOPMActions * actions,
f427ee49 6805 const IOPMRequest * request,
0a7de745
A
6806 IOPMPowerStateIndex powerState,
6807 IOPMPowerChangeFlags * inOutChangeFlags )
b0d623f7 6808{
0a7de745
A
6809 pmTracer->tracePCIPowerChange(
6810 PMTraceWorker::kPowerChangeStart,
6811 service, *inOutChangeFlags,
f427ee49 6812 (actions->flags & kPMActionsPCIBitNumberMask));
0b4e3aa0
A
6813}
6814
0a7de745
A
6815void
6816IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
6817 IOService * service,
6818 IOPMActions * actions,
f427ee49 6819 const IOPMRequest * request,
0a7de745
A
6820 IOPMPowerStateIndex powerState,
6821 IOPMPowerChangeFlags changeFlags )
6822{
6823 pmTracer->tracePCIPowerChange(
6824 PMTraceWorker::kPowerChangeCompleted,
6825 service, changeFlags,
f427ee49 6826 (actions->flags & kPMActionsPCIBitNumberMask));
0a7de745
A
6827}
6828
6829//******************************************************************************
6830// registerInterest
6831//
f427ee49 6832// Override IOService::registerInterest() for root domain clients.
0a7de745
A
6833//******************************************************************************
6834
6835class IOPMServiceInterestNotifier : public _IOServiceInterestNotifier
6836{
6837 friend class IOPMrootDomain;
cb323159 6838 OSDeclareDefaultStructors(IOPMServiceInterestNotifier);
0a7de745
A
6839
6840protected:
f427ee49
A
6841 uint32_t ackTimeoutCnt;
6842 uint32_t msgType; // Message pending ack
6843 uint32_t msgIndex;
6844 uint32_t maxMsgDelayMS;
6845 uint32_t maxAckDelayMS;
6846 uint64_t msgAbsTime;
6847 uint64_t uuid0;
6848 uint64_t uuid1;
6849 OSSharedPtr<const OSSymbol> identifier;
6850 OSSharedPtr<const OSSymbol> clientName;
0a7de745
A
6851};
6852
6853OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
6854
f427ee49
A
6855OSSharedPtr<IONotifier>
6856IOPMrootDomain::registerInterest(
0a7de745
A
6857 const OSSymbol * typeOfInterest,
6858 IOServiceInterestHandler handler,
6859 void * target, void * ref )
6860{
f427ee49 6861 IOPMServiceInterestNotifier* notifier;
0a7de745
A
6862 bool isSystemCapabilityClient;
6863 bool isKernelCapabilityClient;
f427ee49 6864 IOReturn rc = kIOReturnError;
0a7de745 6865
f427ee49 6866 isSystemCapabilityClient = typeOfInterest &&
0a7de745
A
6867 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
6868
f427ee49 6869 isKernelCapabilityClient = typeOfInterest &&
0a7de745
A
6870 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
6871
6872 if (isSystemCapabilityClient) {
6873 typeOfInterest = gIOAppPowerStateInterest;
6874 }
6875
6876 notifier = new IOPMServiceInterestNotifier;
6877 if (!notifier) {
6878 return NULL;
6879 }
6880
6881 if (notifier->init()) {
6882 rc = super::registerInterestForNotifier(notifier, typeOfInterest, handler, target, ref);
6883 }
6884 if (rc != kIOReturnSuccess) {
0a7de745
A
6885 return NULL;
6886 }
f427ee49
A
6887
6888 notifier->ackTimeoutCnt = 0;
6889
0a7de745 6890 if (pmPowerStateQueue) {
0a7de745
A
6891 if (isSystemCapabilityClient) {
6892 notifier->retain();
6893 if (pmPowerStateQueue->submitPowerEvent(
6894 kPowerEventRegisterSystemCapabilityClient, notifier) == false) {
6895 notifier->release();
6896 }
6897 }
6898
6899 if (isKernelCapabilityClient) {
6900 notifier->retain();
6901 if (pmPowerStateQueue->submitPowerEvent(
6902 kPowerEventRegisterKernelCapabilityClient, notifier) == false) {
6903 notifier->release();
6904 }
6905 }
6906 }
6907
f427ee49 6908 OSSharedPtr<OSData> data;
0a7de745 6909 uint8_t *uuid = NULL;
f427ee49 6910 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithAddress((vm_address_t)handler);
0a7de745
A
6911 if (kext) {
6912 data = kext->copyUUID();
6913 }
6914 if (data && (data->getLength() == sizeof(uuid_t))) {
6915 uuid = (uint8_t *)(data->getBytesNoCopy());
6916
6917 notifier->uuid0 = ((uint64_t)(uuid[0]) << 56) | ((uint64_t)(uuid[1]) << 48) | ((uint64_t)(uuid[2]) << 40) |
6918 ((uint64_t)(uuid[3]) << 32) | ((uint64_t)(uuid[4]) << 24) | ((uint64_t)(uuid[5]) << 16) |
6919 ((uint64_t)(uuid[6]) << 8) | (uuid[7]);
6920 notifier->uuid1 = ((uint64_t)(uuid[8]) << 56) | ((uint64_t)(uuid[9]) << 48) | ((uint64_t)(uuid[10]) << 40) |
6921 ((uint64_t)(uuid[11]) << 32) | ((uint64_t)(uuid[12]) << 24) | ((uint64_t)(uuid[13]) << 16) |
6922 ((uint64_t)(uuid[14]) << 8) | (uuid[15]);
6923
f427ee49 6924 notifier->identifier = copyKextIdentifierWithAddress((vm_address_t) handler);
0a7de745 6925 }
f427ee49 6926 return OSSharedPtr<IOPMServiceInterestNotifier>(notifier, OSNoRetain);
6d2010ae 6927}
b0d623f7
A
6928
6929//******************************************************************************
0a7de745 6930// systemMessageFilter
0b4e3aa0 6931//
b0d623f7 6932//******************************************************************************
0b4e3aa0 6933
0a7de745
A
6934bool
6935IOPMrootDomain::systemMessageFilter(
6936 void * object, void * arg1, void * arg2, void * arg3 )
fe8ab488 6937{
0a7de745
A
6938 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
6939 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
6940 bool isCapClient = false;
6941 bool allow = false;
6942 IOPMServiceInterestNotifier *notifier;
fe8ab488 6943
0a7de745 6944 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
cb323159 6945
0a7de745
A
6946 do {
6947 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
6948 (!isCapMsg || !_joinedCapabilityClients ||
6949 !_joinedCapabilityClients->containsObject((OSObject *) object))) {
6950 break;
6951 }
fe8ab488 6952
0a7de745 6953 // Capability change message for app and kernel clients.
fe8ab488 6954
0a7de745 6955 if (isCapMsg) {
f427ee49 6956 // Kernel clients
0a7de745
A
6957 if ((context->notifyType == kNotifyPriority) ||
6958 (context->notifyType == kNotifyCapabilityChangePriority)) {
6959 isCapClient = true;
6960 }
fe8ab488 6961
f427ee49 6962 // powerd's systemCapabilityNotifier
0a7de745 6963 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
f427ee49 6964 (object == (void *) systemCapabilityNotifier.get())) {
0a7de745
A
6965 isCapClient = true;
6966 }
6967 }
fe8ab488 6968
0a7de745
A
6969 if (isCapClient) {
6970 IOPMSystemCapabilityChangeParameters * capArgs =
6971 (IOPMSystemCapabilityChangeParameters *) arg2;
6972
6973 if (kSystemTransitionNewCapClient == _systemTransitionType) {
6974 capArgs->fromCapabilities = 0;
6975 capArgs->toCapabilities = _currentCapability;
6976 capArgs->changeFlags = 0;
6977 } else {
6978 capArgs->fromCapabilities = _currentCapability;
6979 capArgs->toCapabilities = _pendingCapability;
6980
6981 if (context->isPreChange) {
6982 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
6983 } else {
6984 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
6985 }
6986
f427ee49 6987 if ((object == (void *) systemCapabilityNotifier.get()) &&
0a7de745
A
6988 context->isPreChange) {
6989 toldPowerdCapWillChange = true;
6990 }
6991 }
0b4e3aa0 6992
0a7de745
A
6993 // Capability change messages only go to the PM configd plugin.
6994 // Wait for response post-change if capabilitiy is increasing.
6995 // Wait for response pre-change if capability is decreasing.
6996
6997 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
6998 ((capabilityLoss && context->isPreChange) ||
6999 (!capabilityLoss && !context->isPreChange))) {
7000 // app has not replied yet, wait for it
7001 *((OSObject **) arg3) = kOSBooleanFalse;
7002 }
7003
7004 allow = true;
7005 break;
7006 }
7007
7008 // Capability client will always see kIOMessageCanSystemSleep,
7009 // even for demand sleep. It will also have a chance to veto
7010 // sleep one last time after all clients have responded to
7011 // kIOMessageSystemWillSleep
7012
7013 if ((kIOMessageCanSystemSleep == context->messageType) ||
7014 (kIOMessageSystemWillNotSleep == context->messageType)) {
f427ee49 7015 if (object == (OSObject *) systemCapabilityNotifier.get()) {
0a7de745
A
7016 allow = true;
7017 break;
7018 }
7019
7020 // Not idle sleep, don't ask apps.
7021 if (context->changeFlags & kIOPMSkipAskPowerDown) {
7022 break;
7023 }
7024 }
7025
7026 if (kIOPMMessageLastCallBeforeSleep == context->messageType) {
f427ee49 7027 if ((object == (OSObject *) systemCapabilityNotifier.get()) &&
0a7de745
A
7028 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
7029 (fullToDarkReason == kIOPMSleepReasonIdle)) {
7030 allow = true;
7031 }
7032 break;
7033 }
7034
7035 // Reject capability change messages for legacy clients.
7036 // Reject legacy system sleep messages for capability client.
7037
f427ee49 7038 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier.get())) {
0a7de745
A
7039 break;
7040 }
7041
7042 // Filter system sleep messages.
7043
7044 if ((context->notifyType == kNotifyApps) &&
7045 (_systemMessageClientMask & kSystemMessageClientLegacyApp)) {
7046 allow = true;
7047
7048 if (notifier) {
7049 if (arg3) {
7050 if (notifier->ackTimeoutCnt >= 3) {
7051 *((OSObject **) arg3) = kOSBooleanFalse;
7052 } else {
7053 *((OSObject **) arg3) = kOSBooleanTrue;
7054 }
7055 }
7056 }
7057 } else if ((context->notifyType == kNotifyPriority) &&
7058 (_systemMessageClientMask & kSystemMessageClientKernel)) {
7059 allow = true;
7060 }
7061 }while (false);
7062
7063 if (allow && isCapMsg && _joinedCapabilityClients) {
7064 _joinedCapabilityClients->removeObject((OSObject *) object);
7065 if (_joinedCapabilityClients->getCount() == 0) {
7066 DLOG("destroyed capability client set %p\n",
f427ee49
A
7067 OBFUSCATE(_joinedCapabilityClients.get()));
7068 _joinedCapabilityClients.reset();
0a7de745
A
7069 }
7070 }
7071 if (notifier) {
7072 notifier->msgType = context->messageType;
7073 }
0b4e3aa0 7074
0a7de745 7075 return allow;
1c79356b
A
7076}
7077
b0d623f7 7078//******************************************************************************
6d2010ae 7079// setMaintenanceWakeCalendar
2d21ac55 7080//
b0d623f7 7081//******************************************************************************
2d21ac55 7082
0a7de745
A
7083IOReturn
7084IOPMrootDomain::setMaintenanceWakeCalendar(
7085 const IOPMCalendarStruct * calendar )
2d21ac55 7086{
f427ee49 7087 OSSharedPtr<OSData> data;
0a7de745 7088 IOReturn ret = 0;
2d21ac55 7089
0a7de745
A
7090 if (!calendar) {
7091 return kIOReturnBadArgument;
7092 }
fe8ab488 7093
0a7de745
A
7094 data = OSData::withBytes((void *) calendar, sizeof(*calendar));
7095 if (!data) {
7096 return kIOReturnNoMemory;
7097 }
7ddcb079 7098
0a7de745 7099 if (kPMCalendarTypeMaintenance == calendar->selector) {
f427ee49 7100 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey.get(), data.get());
0a7de745 7101 } else if (kPMCalendarTypeSleepService == calendar->selector) {
f427ee49 7102 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey.get(), data.get());
0a7de745 7103 }
fe8ab488 7104
0a7de745 7105 return ret;
6d2010ae 7106}
2d21ac55 7107
6d2010ae
A
7108// MARK: -
7109// MARK: Display Wrangler
2d21ac55 7110
6d2010ae
A
7111//******************************************************************************
7112// displayWranglerNotification
7113//
7114// Handle the notification when the IODisplayWrangler changes power state.
7115//******************************************************************************
2d21ac55 7116
0a7de745
A
7117IOReturn
7118IOPMrootDomain::displayWranglerNotification(
7119 void * target, void * refCon,
7120 UInt32 messageType, IOService * service,
7121 void * messageArgument, vm_size_t argSize )
6d2010ae 7122{
f427ee49
A
7123#if DISPLAY_WRANGLER_PRESENT
7124 IOPMPowerStateIndex displayPowerState;
0a7de745
A
7125 IOPowerStateChangeNotification * params =
7126 (IOPowerStateChangeNotification *) messageArgument;
7127
7128 if ((messageType != kIOMessageDeviceWillPowerOff) &&
7129 (messageType != kIOMessageDeviceHasPoweredOn)) {
7130 return kIOReturnUnsupported;
7131 }
7132
7133 ASSERT_GATED();
7134 if (!gRootDomain) {
7135 return kIOReturnUnsupported;
7136 }
7137
7138 displayPowerState = params->stateNumber;
7139 DLOG("wrangler %s ps %d\n",
f427ee49 7140 getIOMessageString(messageType), (uint32_t) displayPowerState);
0a7de745
A
7141
7142 switch (messageType) {
7143 case kIOMessageDeviceWillPowerOff:
7144 // Display wrangler has dropped power due to display idle
7145 // or force system sleep.
7146 //
7147 // 4 Display ON kWranglerPowerStateMax
7148 // 3 Display Dim kWranglerPowerStateDim
7149 // 2 Display Sleep kWranglerPowerStateSleep
7150 // 1 Not visible to user
7151 // 0 Not visible to user kWranglerPowerStateMin
7152
7153 if (displayPowerState <= kWranglerPowerStateSleep) {
7154 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
7155 }
7156 break;
7157
7158 case kIOMessageDeviceHasPoweredOn:
7159 // Display wrangler has powered on due to user activity
7160 // or wake from sleep.
7161
7162 if (kWranglerPowerStateMax == displayPowerState) {
7163 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
7164
7165 // See comment in handleUpdatePowerClientForDisplayWrangler
7166 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
7167 kWranglerPowerStateMax) {
7168 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
7169 }
7170 }
7171 break;
7172 }
f427ee49 7173#endif /* DISPLAY_WRANGLER_PRESENT */
0a7de745 7174 return kIOReturnUnsupported;
b0d623f7
A
7175}
7176
13f56ec4 7177//******************************************************************************
f427ee49 7178// reportUserInput
b0d623f7
A
7179//
7180//******************************************************************************
7181
f427ee49
A
7182void
7183IOPMrootDomain::updateUserActivity( void )
7184{
7185#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7186 clock_get_uptime(&userActivityTime);
7187 bool aborting = ((lastSleepReason == kIOPMSleepReasonSoftware)
7188 || (lastSleepReason == kIOPMSleepReasonIdle)
7189 || (lastSleepReason == kIOPMSleepReasonMaintenance));
7190 if (aborting) {
7191 userActivityCount++;
7192 DLOG("user activity reported %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
0a7de745 7193 }
b0d623f7 7194#endif
b0d623f7 7195}
0a7de745
A
7196void
7197IOPMrootDomain::reportUserInput( void )
b0d623f7 7198{
f427ee49
A
7199 if (wrangler) {
7200 wrangler->activityTickle(0, 0);
7201 }
7202#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7203 // Update user activity
7204 updateUserActivity();
0a7de745 7205
f427ee49
A
7206 if (!darkWakeExit && ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0)) {
7207 // update user active abs time
7208 clock_get_uptime(&gUserActiveAbsTime);
7209 pmPowerStateQueue->submitPowerEvent(
7210 kPowerEventPolicyStimulus,
7211 (void *) kStimulusDarkWakeActivityTickle,
7212 true /* set wake type */ );
0a7de745 7213 }
f427ee49
A
7214#endif
7215}
0a7de745 7216
f427ee49
A
7217void
7218IOPMrootDomain::requestUserActive(IOService *device, const char *reason)
7219{
7220#if DISPLAY_WRANGLER_PRESENT
0a7de745
A
7221 if (wrangler) {
7222 wrangler->activityTickle(0, 0);
7223 }
f427ee49
A
7224#else
7225 if (!device) {
7226 DLOG("requestUserActive: device is null\n");
7227 return;
7228 }
7229 OSSharedPtr<const OSSymbol> deviceName = device->copyName();
7230 uint64_t registryID = device->getRegistryEntryID();
7231
7232 if (!deviceName || !registryID) {
7233 DLOG("requestUserActive: no device name or registry entry\n");
7234 return;
7235 }
7236 const char *name = deviceName->getCStringNoCopy();
7237 char payload[128];
7238 snprintf(payload, sizeof(payload), "%s:%s", name, reason);
7239 DLOG("requestUserActive from %s (0x%llx) for %s\n", name, registryID, reason);
7240 messageClient(kIOPMMessageRequestUserActive, systemCapabilityNotifier.get(), (void *)payload, sizeof(payload));
b0d623f7 7241#endif
2d21ac55
A
7242}
7243
13f56ec4 7244//******************************************************************************
39236c6e 7245// latchDisplayWranglerTickle
13f56ec4
A
7246//******************************************************************************
7247
0a7de745
A
7248bool
7249IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
13f56ec4 7250{
f427ee49 7251#if DISPLAY_WRANGLER_PRESENT
0a7de745
A
7252 if (latch) {
7253 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
7254 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7255 !checkSystemCanSustainFullWake()) {
7256 // Currently in dark wake, and not transitioning to full wake.
7257 // Full wake is unsustainable, so latch the tickle to prevent
7258 // the display from lighting up momentarily.
f427ee49 7259 wranglerTickled = true;
0a7de745 7260 } else {
f427ee49 7261 wranglerTickled = false;
0a7de745 7262 }
f427ee49
A
7263 } else if (wranglerTickled && checkSystemCanSustainFullWake()) {
7264 wranglerTickled = false;
0a7de745
A
7265
7266 pmPowerStateQueue->submitPowerEvent(
7267 kPowerEventPolicyStimulus,
7268 (void *) kStimulusDarkWakeActivityTickle );
7269 }
7270
f427ee49
A
7271 return wranglerTickled;
7272#else /* ! DISPLAY_WRANGLER_PRESENT */
0a7de745 7273 return false;
f427ee49 7274#endif /* ! DISPLAY_WRANGLER_PRESENT */
13f56ec4
A
7275}
7276
39236c6e
A
7277//******************************************************************************
7278// setDisplayPowerOn
7279//
7280// For root domain user client
7281//******************************************************************************
7282
0a7de745
A
7283void
7284IOPMrootDomain::setDisplayPowerOn( uint32_t options )
39236c6e 7285{
0a7de745 7286 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
cb323159 7287 (void *) NULL, options );
39236c6e
A
7288}
7289
6d2010ae
A
7290// MARK: -
7291// MARK: System PM Policy
0c530ab8 7292
6d2010ae 7293//******************************************************************************
39236c6e 7294// checkSystemSleepAllowed
6d2010ae
A
7295//
7296//******************************************************************************
0b4c1975 7297
0a7de745
A
7298bool
7299IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
7300 uint32_t sleepReason )
6d2010ae 7301{
cb323159 7302 uint32_t err = 0;
b0d623f7 7303
0a7de745 7304 // Conditions that prevent idle and demand system sleep.
b0d623f7 7305
0a7de745
A
7306 do {
7307 if (userDisabledAllSleep) {
cb323159 7308 err = kPMUserDisabledAllSleep; // 1. user-space sleep kill switch
0a7de745
A
7309 break;
7310 }
b0d623f7 7311
0a7de745 7312 if (systemBooting || systemShutdown || gWillShutdown) {
cb323159 7313 err = kPMSystemRestartBootingInProgress; // 2. restart or shutdown in progress
0a7de745
A
7314 break;
7315 }
b0d623f7 7316
0a7de745
A
7317 if (options == 0) {
7318 break;
7319 }
0b4c1975 7320
0a7de745
A
7321 // Conditions above pegs the system at full wake.
7322 // Conditions below prevent system sleep but does not prevent
7323 // dark wake, and must be called from gated context.
b0d623f7 7324
6d2010ae 7325#if !CONFIG_SLEEP
cb323159 7326 err = kPMConfigPreventSystemSleep; // 3. config does not support sleep
0a7de745 7327 break;
b0d623f7 7328#endif
b0d623f7 7329
f427ee49
A
7330 if (lowBatteryCondition || thermalWarningState || thermalEmergencyState) {
7331 break; // always sleep on low battery or when in thermal warning/emergency state
0a7de745
A
7332 }
7333
7334 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency) {
7335 break; // always sleep on dark wake thermal emergencies
7336 }
7337
7338 if (preventSystemSleepList->getCount() != 0) {
cb323159 7339 err = kPMChildPreventSystemSleep; // 4. child prevent system sleep clamp
0a7de745
A
7340 break;
7341 }
7342
7343 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
7344 kIOPMDriverAssertionLevelOn) {
cb323159 7345 err = kPMCPUAssertion; // 5. CPU assertion
0a7de745
A
7346 break;
7347 }
7348
7349 if (pciCantSleepValid) {
7350 if (pciCantSleepFlag) {
cb323159 7351 err = kPMPCIUnsupported; // 6. PCI card does not support PM (cached)
0a7de745
A
7352 }
7353 break;
7354 } else if (sleepSupportedPEFunction &&
7355 CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
7356 IOReturn ret;
7357 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
7358 ret = getPlatform()->callPlatformFunction(
f427ee49 7359 sleepSupportedPEFunction.get(), false,
0a7de745
A
7360 NULL, NULL, NULL, NULL);
7361 pciCantSleepValid = true;
7362 pciCantSleepFlag = false;
7363 if ((platformSleepSupport & kPCICantSleep) ||
7364 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported))) {
7365 err = 6; // 6. PCI card does not support PM
7366 pciCantSleepFlag = true;
7367 break;
7368 }
7369 }
7370 }while (false);
7371
7372 if (err) {
cb323159 7373 DLOG("System sleep prevented by %s\n", getSystemSleepPreventerString(err));
0a7de745
A
7374 return false;
7375 }
7376 return true;
7377}
7378
7379bool
7380IOPMrootDomain::checkSystemSleepEnabled( void )
7381{
7382 return checkSystemSleepAllowed(0, 0);
7383}
7384
7385bool
7386IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
7387{
7388 ASSERT_GATED();
7389 return checkSystemSleepAllowed(1, sleepReason);
39236c6e
A
7390}
7391
13f56ec4
A
7392//******************************************************************************
7393// checkSystemCanSustainFullWake
7394//******************************************************************************
7395
0a7de745
A
7396bool
7397IOPMrootDomain::checkSystemCanSustainFullWake( void )
13f56ec4 7398{
f427ee49 7399 if (lowBatteryCondition || thermalWarningState || thermalEmergencyState) {
0a7de745
A
7400 // Low battery wake, or received a low battery notification
7401 // while system is awake. This condition will persist until
7402 // the following wake.
7403 return false;
7404 }
7405
f427ee49 7406 if (clamshellExists && clamshellClosed && !clamshellSleepDisableMask) {
0a7de745
A
7407 // Graphics state is unknown and external display might not be probed.
7408 // Do not incorporate state that requires graphics to be in max power
7409 // such as desktopMode or clamshellDisabled.
7410
7411 if (!acAdaptorConnected) {
7412 DLOG("full wake check: no AC\n");
7413 return false;
7414 }
7415 }
0a7de745 7416 return true;
13f56ec4
A
7417}
7418
00867663
A
7419//******************************************************************************
7420// mustHibernate
7421//******************************************************************************
7422
0a7de745
A
7423#if HIBERNATION
7424
7425bool
7426IOPMrootDomain::mustHibernate( void )
7427{
7428 return lowBatteryCondition || thermalWarningState;
7429}
7430
7431#endif /* HIBERNATION */
7432
cb323159
A
7433//******************************************************************************
7434// AOT
7435//******************************************************************************
7436
7437// Tables for accumulated days in year by month, latter used for leap years
7438
f427ee49 7439static const unsigned int daysbymonth[] =
cb323159
A
7440{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
7441
f427ee49 7442static const unsigned int lydaysbymonth[] =
cb323159
A
7443{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
7444
7445static int __unused
f427ee49 7446IOPMConvertSecondsToCalendar(clock_sec_t secs, IOPMCalendarStruct * dt)
cb323159 7447{
f427ee49
A
7448 const unsigned int * dbm = daysbymonth;
7449 clock_sec_t n, x, y, z;
cb323159
A
7450
7451 // Calculate seconds, minutes and hours
7452
7453 n = secs % (24 * 3600);
7454 dt->second = n % 60;
7455 n /= 60;
7456 dt->minute = n % 60;
f427ee49 7457 dt->hour = (typeof(dt->hour))(n / 60);
cb323159
A
7458
7459 // Calculate day of week
7460
7461 n = secs / (24 * 3600);
7462// dt->dayWeek = (n + 4) % 7;
7463
7464 // Calculate year
7465 // Rebase from days since Unix epoch (1/1/1970) store in 'n',
7466 // to days since 1/1/1968 to start on 4 year cycle, beginning
7467 // on a leap year.
7468
7469 n += (366 + 365);
7470
7471 // Every 4 year cycle will be exactly (366 + 365 * 3) = 1461 days.
7472 // Valid before 2100, since 2100 is not a leap year.
7473
7474 x = n / 1461; // number of 4 year cycles
7475 y = n % 1461; // days into current 4 year cycle
7476 z = 1968 + (4 * x);
7477
7478 // Add in years in the current 4 year cycle
7479
7480 if (y >= 366) {
7481 y -= 366; // days after the leap year
7482 n = y % 365; // days into the current year
7483 z += (1 + y / 365); // years after the past 4-yr cycle
7484 } else {
7485 n = y;
7486 dbm = lydaysbymonth;
7487 }
7488 if (z > 2099) {
7489 return 0;
7490 }
7491
f427ee49 7492 dt->year = (typeof(dt->year))z;
cb323159
A
7493
7494 // Adjust remaining days value to start at 1
7495
7496 n += 1;
7497
7498 // Calculate month
7499
f427ee49 7500 for (x = 1; (n > dbm[x]) && (x < 12); x++) {
cb323159
A
7501 continue;
7502 }
f427ee49 7503 dt->month = (typeof(dt->month))x;
cb323159
A
7504
7505 // Calculate day of month
7506
f427ee49 7507 dt->day = (typeof(dt->day))(n - dbm[x - 1]);
cb323159
A
7508
7509 return 1;
7510}
7511
f427ee49 7512static clock_sec_t
cb323159
A
7513IOPMConvertCalendarToSeconds(const IOPMCalendarStruct * dt)
7514{
f427ee49 7515 const unsigned int * dbm = daysbymonth;
cb323159
A
7516 long y, secs, days;
7517
f427ee49 7518 if (dt->year < 1970 || dt->month > 12) {
cb323159
A
7519 return 0;
7520 }
7521
7522 // Seconds elapsed in the current day
7523
7524 secs = dt->second + 60 * dt->minute + 3600 * dt->hour;
7525
7526 // Number of days from 1/1/70 to beginning of current year
7527 // Account for extra day every 4 years starting at 1973
7528
7529 y = dt->year - 1970;
7530 days = (y * 365) + ((y + 1) / 4);
7531
7532 // Change table if current year is a leap year
7533
7534 if ((dt->year % 4) == 0) {
7535 dbm = lydaysbymonth;
7536 }
7537
7538 // Add in days elapsed in the current year
7539
7540 days += (dt->day - 1) + dbm[dt->month - 1];
7541
7542 // Add accumulated days to accumulated seconds
7543
7544 secs += 24 * 3600 * days;
7545
7546 return secs;
7547}
7548
cb323159
A
7549unsigned long
7550IOPMrootDomain::getRUN_STATE(void)
7551{
7552 return _aotNow ? AOT_STATE : ON_STATE;
7553}
7554
7555bool
7556IOPMrootDomain::isAOTMode()
7557{
7558 return _aotNow;
7559}
7560
7561IOReturn
7562IOPMrootDomain::setWakeTime(uint64_t wakeContinuousTime)
7563{
7564 clock_sec_t nowsecs, wakesecs;
7565 clock_usec_t nowmicrosecs, wakemicrosecs;
7566 uint64_t nowAbs, wakeAbs;
7567
7568 clock_gettimeofday_and_absolute_time(&nowsecs, &nowmicrosecs, &nowAbs);
7569 wakeAbs = continuoustime_to_absolutetime(wakeContinuousTime);
7570 if (wakeAbs < nowAbs) {
7571 printf(LOG_PREFIX "wakeAbs %qd < nowAbs %qd\n", wakeAbs, nowAbs);
7572 wakeAbs = nowAbs;
7573 }
7574 wakeAbs -= nowAbs;
7575 absolutetime_to_microtime(wakeAbs, &wakesecs, &wakemicrosecs);
7576
7577 wakesecs += nowsecs;
7578 wakemicrosecs += nowmicrosecs;
7579 if (wakemicrosecs >= USEC_PER_SEC) {
7580 wakesecs++;
7581 wakemicrosecs -= USEC_PER_SEC;
7582 }
7583 if (wakemicrosecs >= (USEC_PER_SEC / 10)) {
7584 wakesecs++;
7585 }
7586
7587 IOPMConvertSecondsToCalendar(wakesecs, &_aotWakeTimeCalendar);
7588
7589 if (_aotWakeTimeContinuous != wakeContinuousTime) {
7590 _aotWakeTimeContinuous = wakeContinuousTime;
7591 IOLog(LOG_PREFIX "setWakeTime: " YMDTF "\n", YMDT(&_aotWakeTimeCalendar));
7592 }
7593 _aotWakeTimeCalendar.selector = kPMCalendarTypeMaintenance;
7594 _aotWakeTimeUTC = wakesecs;
7595
7596 return kIOReturnSuccess;
7597}
7598
7599// assumes WAKEEVENT_LOCK
7600bool
7601IOPMrootDomain::aotShouldExit(bool checkTimeSet, bool software)
7602{
7603 bool exitNow;
7604 const char * reason = "";
7605
7606 if (software) {
7607 _aotExit = true;
7608 _aotMetrics->softwareRequestCount++;
7609 reason = "software request";
7610 } else if (kIOPMWakeEventAOTExitFlags & _aotPendingFlags) {
7611 _aotExit = true;
7612 reason = gWakeReasonString;
7613 } else if (checkTimeSet && (kPMCalendarTypeInvalid == _aotWakeTimeCalendar.selector)) {
7614 _aotExit = true;
7615 _aotMetrics->noTimeSetCount++;
7616 reason = "flipbook expired";
f427ee49 7617 } else if ((kIOPMAOTModeRespectTimers & _aotMode) && _calendarWakeAlarmUTC) {
cb323159
A
7618 clock_sec_t sec;
7619 clock_usec_t usec;
7620 clock_get_calendar_microtime(&sec, &usec);
f427ee49 7621 if (_calendarWakeAlarmUTC <= sec) {
cb323159
A
7622 _aotExit = true;
7623 _aotMetrics->rtcAlarmsCount++;
7624 reason = "user alarm";
7625 }
7626 }
7627 exitNow = (_aotNow && _aotExit);
7628 if (exitNow) {
7629 _aotNow = false;
7630 IOLog(LOG_PREFIX "AOT exit for %s, sc %d po %d, cp %d, rj %d, ex %d, nt %d, rt %d\n",
7631 reason,
7632 _aotMetrics->sleepCount,
7633 _aotMetrics->possibleCount,
7634 _aotMetrics->confirmedPossibleCount,
7635 _aotMetrics->rejectedPossibleCount,
7636 _aotMetrics->expiredPossibleCount,
7637 _aotMetrics->noTimeSetCount,
7638 _aotMetrics->rtcAlarmsCount);
7639 }
7640 return exitNow;
7641}
7642
7643void
7644IOPMrootDomain::aotExit(bool cps)
7645{
f427ee49
A
7646 uint32_t savedMessageMask;
7647
7648 ASSERT_GATED();
cb323159
A
7649 _aotTasksSuspended = false;
7650 _aotReadyToFullWake = false;
7651 if (_aotTimerScheduled) {
7652 _aotTimerES->cancelTimeout();
7653 _aotTimerScheduled = false;
7654 }
7655 updateTasksSuspend();
7656
7657 _aotMetrics->totalTime += mach_absolute_time() - _aotLastWakeTime;
7658 _aotLastWakeTime = 0;
7659 if (_aotMetrics->sleepCount && (_aotMetrics->sleepCount <= kIOPMAOTMetricsKernelWakeCountMax)) {
f427ee49 7660 WAKEEVENT_LOCK();
cb323159
A
7661 strlcpy(&_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount - 1][0],
7662 gWakeReasonString,
7663 sizeof(_aotMetrics->kernelWakeReason[_aotMetrics->sleepCount]));
f427ee49 7664 WAKEEVENT_UNLOCK();
cb323159
A
7665 }
7666
7667 _aotWakeTimeCalendar.selector = kPMCalendarTypeInvalid;
7668
f427ee49
A
7669 // Preserve the message mask since a system wake transition
7670 // may have already started and initialized the mask.
7671 savedMessageMask = _systemMessageClientMask;
cb323159
A
7672 _systemMessageClientMask = kSystemMessageClientLegacyApp;
7673 tellClients(kIOMessageSystemWillPowerOn);
f427ee49 7674 _systemMessageClientMask = savedMessageMask | kSystemMessageClientLegacyApp;
cb323159
A
7675
7676 if (cps) {
f427ee49 7677 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAOTExit);
cb323159
A
7678 }
7679}
7680
7681void
7682IOPMrootDomain::aotEvaluate(IOTimerEventSource * timer)
7683{
7684 bool exitNow;
7685
7686 IOLog("aotEvaluate(%d) 0x%x\n", (timer != NULL), _aotPendingFlags);
7687
7688 WAKEEVENT_LOCK();
7689 exitNow = aotShouldExit(false, false);
7690 if (timer != NULL) {
7691 _aotTimerScheduled = false;
7692 }
7693 WAKEEVENT_UNLOCK();
7694 if (exitNow) {
7695 aotExit(true);
7696 } else {
7697#if 0
7698 if (_aotLingerTime) {
7699 uint64_t deadline;
7700 IOLog("aot linger before sleep\n");
7701 clock_absolutetime_interval_to_deadline(_aotLingerTime, &deadline);
7702 clock_delay_until(deadline);
7703 }
7704#endif
7705 privateSleepSystem(kIOPMSleepReasonSoftware);
7706 }
7707}
7708
0a7de745
A
7709//******************************************************************************
7710// adjustPowerState
7711//
7712// Conditions that affect our wake/sleep decision has changed.
7713// If conditions dictate that the system must remain awake, clamp power
7714// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
7715// is TRUE, then remove the power clamp and allow the power state to drop
7716// to SLEEP_STATE.
7717//******************************************************************************
7718
7719void
7720IOPMrootDomain::adjustPowerState( bool sleepASAP )
7721{
f427ee49 7722 DEBUG_LOG("adjustPowerState %s, asap %d, idleSleepEnabled %d\n",
cb323159 7723 getPowerStateString((uint32_t) getPowerState()), sleepASAP, idleSleepEnabled);
0a7de745
A
7724
7725 ASSERT_GATED();
7726
cb323159
A
7727 if (_aotNow) {
7728 bool exitNow;
7729
7730 if (AOT_STATE != getPowerState()) {
7731 return;
7732 }
7733 WAKEEVENT_LOCK();
7734 exitNow = aotShouldExit(true, false);
7735 if (!exitNow
7736 && !_aotTimerScheduled
7737 && (kIOPMWakeEventAOTPossibleExit == (kIOPMWakeEventAOTPossibleFlags & _aotPendingFlags))) {
7738 _aotTimerScheduled = true;
7739 if (_aotLingerTime) {
7740 _aotTimerES->setTimeout(_aotLingerTime);
7741 } else {
7742 _aotTimerES->setTimeout(800, kMillisecondScale);
7743 }
7744 }
7745 WAKEEVENT_UNLOCK();
7746 if (exitNow) {
7747 aotExit(true);
7748 } else {
7749 _aotReadyToFullWake = true;
7750 if (!_aotTimerScheduled) {
7751 privateSleepSystem(kIOPMSleepReasonSoftware);
7752 }
7753 }
7754 return;
7755 }
cb323159 7756
0a7de745 7757 if ((!idleSleepEnabled) || !checkSystemSleepEnabled()) {
f427ee49 7758 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAdjustPowerState);
0a7de745 7759 } else if (sleepASAP) {
f427ee49 7760 changePowerStateWithTagToPriv(SLEEP_STATE, kCPSReasonAdjustPowerState);
0a7de745
A
7761 }
7762}
7763
7764void
f427ee49 7765IOPMrootDomain::handleSetDisplayPowerOn(bool powerOn)
0a7de745 7766{
f427ee49 7767 if (powerOn) {
0a7de745 7768 if (!checkSystemCanSustainFullWake()) {
f427ee49 7769 DLOG("System cannot sustain full wake\n");
0a7de745
A
7770 return;
7771 }
7772
7773 // Force wrangler to max power state. If system is in dark wake
7774 // this alone won't raise the wrangler's power state.
f427ee49
A
7775 if (wrangler) {
7776 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
7777 }
0a7de745
A
7778
7779 // System in dark wake, always requesting full wake should
7780 // not have any bad side-effects, even if the request fails.
7781
7782 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
7783 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
7784 requestFullWake( kFullWakeReasonDisplayOn );
7785 }
7786 } else {
7787 // Relenquish desire to power up display.
7788 // Must first transition to state 1 since wrangler doesn't
7789 // power off the displays at state 0. At state 0 the root
7790 // domain is removed from the wrangler's power client list.
f427ee49
A
7791 if (wrangler) {
7792 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
7793 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
7794 }
0a7de745
A
7795 }
7796}
7797
7798//******************************************************************************
7799// dispatchPowerEvent
7800//
7801// IOPMPowerStateQueue callback function. Running on PM work loop thread.
7802//******************************************************************************
7803
7804void
7805IOPMrootDomain::dispatchPowerEvent(
7806 uint32_t event, void * arg0, uint64_t arg1 )
7807{
7808 ASSERT_GATED();
7809
7810 switch (event) {
7811 case kPowerEventFeatureChanged:
7812 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7813 messageClients(kIOPMMessageFeatureChange, this);
7814 break;
7815
7816 case kPowerEventReceivedPowerNotification:
7817 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7818 handlePowerNotification((UInt32)(uintptr_t) arg0 );
7819 break;
7820
7821 case kPowerEventSystemBootCompleted:
7822 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7823 if (systemBooting) {
7824 systemBooting = false;
7825
7826 // read noidle setting from Device Tree
f427ee49 7827 OSSharedPtr<IORegistryEntry> defaults = IORegistryEntry::fromPath("IODeviceTree:/defaults");
0a7de745 7828 if (defaults != NULL) {
f427ee49
A
7829 OSSharedPtr<OSObject> noIdleProp = defaults->copyProperty("no-idle");
7830 OSData *data = OSDynamicCast(OSData, noIdleProp.get());
0a7de745
A
7831 if ((data != NULL) && (data->getLength() == 4)) {
7832 gNoIdleFlag = *(uint32_t*)data->getBytesNoCopy();
7833 DLOG("Setting gNoIdleFlag to %u from device tree\n", gNoIdleFlag);
7834 }
0a7de745 7835 }
f427ee49
A
7836 if (lowBatteryCondition || thermalEmergencyState) {
7837 if (lowBatteryCondition) {
7838 privateSleepSystem(kIOPMSleepReasonLowPower);
7839 } else {
7840 privateSleepSystem(kIOPMSleepReasonThermalEmergency);
7841 }
0a7de745
A
7842 // The rest is unnecessary since the system is expected
7843 // to sleep immediately. The following wake will update
7844 // everything.
7845 break;
7846 }
7847
7848 sleepWakeDebugMemAlloc();
7849 saveFailureData2File();
7850
7851 // If lid is closed, re-send lid closed notification
7852 // now that booting is complete.
7853 if (clamshellClosed) {
7854 handlePowerNotification(kLocalEvalClamshellCommand);
7855 }
7856 evaluatePolicy( kStimulusAllowSystemSleepChanged );
7857 }
7858 break;
7859
7860 case kPowerEventSystemShutdown:
7861 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7862 if (kOSBooleanTrue == (OSBoolean *) arg0) {
7863 /* We set systemShutdown = true during shutdown
7864 * to prevent sleep at unexpected times while loginwindow is trying
7865 * to shutdown apps and while the OS is trying to transition to
7866 * complete power of.
7867 *
7868 * Set to true during shutdown, as soon as loginwindow shows
7869 * the "shutdown countdown dialog", through individual app
7870 * termination, and through black screen kernel shutdown.
7871 */
7872 systemShutdown = true;
7873 } else {
7874 /*
7875 * A shutdown was initiated, but then the shutdown
7876 * was cancelled, clearing systemShutdown to false here.
7877 */
7878 systemShutdown = false;
7879 }
7880 break;
7881
7882 case kPowerEventUserDisabledSleep:
7883 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7884 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
7885 break;
7886
7887 case kPowerEventRegisterSystemCapabilityClient:
7888 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
f427ee49
A
7889
7890 // reset() handles the arg0 == nullptr case for us
7891 systemCapabilityNotifier.reset((IONotifier *) arg0, OSRetain);
0a7de745
A
7892 /* intentional fall-through */
7893 [[clang::fallthrough]];
7894
7895 case kPowerEventRegisterKernelCapabilityClient:
7896 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7897 if (!_joinedCapabilityClients) {
7898 _joinedCapabilityClients = OSSet::withCapacity(8);
7899 }
7900 if (arg0) {
f427ee49 7901 OSSharedPtr<IONotifier> notify((IONotifier *) arg0, OSNoRetain);
0a7de745 7902 if (_joinedCapabilityClients) {
f427ee49 7903 _joinedCapabilityClients->setObject(notify.get());
0a7de745
A
7904 synchronizePowerTree( kIOPMSyncNoChildNotify );
7905 }
0a7de745
A
7906 }
7907 break;
7908
7909 case kPowerEventPolicyStimulus:
7910 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7911 if (arg0) {
f427ee49
A
7912 int stimulus = (int)(uintptr_t) arg0;
7913 evaluatePolicy(stimulus, (uint32_t) arg1);
0a7de745
A
7914 }
7915 break;
7916
7917 case kPowerEventAssertionCreate:
7918 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7919 if (pmAssertions) {
7920 pmAssertions->handleCreateAssertion((OSData *)arg0);
7921 }
7922 break;
7923
7924
7925 case kPowerEventAssertionRelease:
7926 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7927 if (pmAssertions) {
7928 pmAssertions->handleReleaseAssertion(arg1);
7929 }
7930 break;
7931
7932 case kPowerEventAssertionSetLevel:
7933 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7934 if (pmAssertions) {
7935 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
7936 }
7937 break;
7938
7939 case kPowerEventQueueSleepWakeUUID:
7940 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7941 handleQueueSleepWakeUUID((OSObject *)arg0);
7942 break;
7943 case kPowerEventPublishSleepWakeUUID:
7944 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7945 handlePublishSleepWakeUUID((bool)arg0);
7946 break;
7947
7948 case kPowerEventSetDisplayPowerOn:
7949 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
0a7de745
A
7950 if (arg1 != 0) {
7951 displayPowerOnRequested = true;
7952 } else {
7953 displayPowerOnRequested = false;
7954 }
f427ee49
A
7955 handleSetDisplayPowerOn(displayPowerOnRequested);
7956 break;
7957
7958 case kPowerEventPublishWakeType:
7959 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7960
7961 // Don't replace wake type property if already set
7962 if ((arg0 == gIOPMWakeTypeUserKey) ||
7963 !propertyExists(kIOPMRootDomainWakeTypeKey)) {
7964 const char * wakeType = NULL;
7965
7966 if (arg0 == gIOPMWakeTypeUserKey) {
7967 requestUserActive(this, "WakeTypeUser");
7968 wakeType = kIOPMRootDomainWakeTypeUser;
7969 } else if (arg0 == gIOPMSettingDebugWakeRelativeKey) {
7970 requestUserActive(this, "WakeTypeAlarm");
7971 wakeType = kIOPMRootDomainWakeTypeAlarm;
7972 } else if (arg0 == gIOPMSettingSleepServiceWakeCalendarKey) {
7973 darkWakeSleepService = true;
7974 wakeType = kIOPMRootDomainWakeTypeSleepService;
7975 } else if (arg0 == gIOPMSettingMaintenanceWakeCalendarKey) {
7976 wakeType = kIOPMRootDomainWakeTypeMaintenance;
7977 }
7978
7979 if (wakeType) {
7980 setProperty(kIOPMRootDomainWakeTypeKey, wakeType);
7981 }
7982 }
7983 break;
7984
7985 case kPowerEventAOTEvaluate:
7986 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
7987 if (_aotReadyToFullWake) {
7988 aotEvaluate(NULL);
7989 }
0a7de745
A
7990 break;
7991 }
7992}
7993
7994//******************************************************************************
7995// systemPowerEventOccurred
7996//
7997// The power controller is notifying us of a hardware-related power management
7998// event that we must handle.
7999//
8000// systemPowerEventOccurred covers the same functionality that
8001// receivePowerNotification does; it simply provides a richer API for conveying
8002// more information.
8003//******************************************************************************
8004
8005IOReturn
8006IOPMrootDomain::systemPowerEventOccurred(
8007 const OSSymbol *event,
8008 uint32_t intValue)
8009{
8010 IOReturn attempt = kIOReturnSuccess;
f427ee49 8011 OSSharedPtr<OSNumber> newNumber;
0a7de745
A
8012
8013 if (!event) {
8014 return kIOReturnBadArgument;
8015 }
8016
8017 newNumber = OSNumber::withNumber(intValue, 8 * sizeof(intValue));
8018 if (!newNumber) {
8019 return kIOReturnInternalError;
8020 }
8021
f427ee49 8022 attempt = systemPowerEventOccurred(event, static_cast<OSObject *>(newNumber.get()));
0a7de745
A
8023
8024 return attempt;
8025}
8026
8027void
8028IOPMrootDomain::setThermalState(OSObject *value)
8029{
8030 OSNumber * num;
8031
8032 if (gIOPMWorkLoop->inGate() == false) {
8033 gIOPMWorkLoop->runAction(
8034 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
8035 (OSObject *)this,
8036 (void *)value);
8037
8038 return;
8039 }
8040 if (value && (num = OSDynamicCast(OSNumber, value))) {
8041 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
8042 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
8043 }
8044}
8045
8046IOReturn
8047IOPMrootDomain::systemPowerEventOccurred(
8048 const OSSymbol *event,
8049 OSObject *value)
8050{
f427ee49 8051 OSSharedPtr<OSDictionary> thermalsDict;
0a7de745
A
8052 bool shouldUpdate = true;
8053
8054 if (!event || !value) {
8055 return kIOReturnBadArgument;
8056 }
8057
8058 // LOCK
8059 // We reuse featuresDict Lock because it already exists and guards
8060 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
8061 // of stepping on that lock.
8062 if (featuresDictLock) {
8063 IOLockLock(featuresDictLock);
8064 }
8065
f427ee49
A
8066 OSSharedPtr<OSObject> origThermalsProp = copyProperty(kIOPMRootDomainPowerStatusKey);
8067 OSDictionary * origThermalsDict = OSDynamicCast(OSDictionary, origThermalsProp.get());
0a7de745 8068
f427ee49
A
8069 if (origThermalsDict) {
8070 thermalsDict = OSDictionary::withDictionary(origThermalsDict);
0a7de745
A
8071 } else {
8072 thermalsDict = OSDictionary::withCapacity(1);
8073 }
8074
8075 if (!thermalsDict) {
8076 shouldUpdate = false;
8077 goto exit;
8078 }
8079
8080 thermalsDict->setObject(event, value);
8081
f427ee49 8082 setProperty(kIOPMRootDomainPowerStatusKey, thermalsDict.get());
0a7de745
A
8083
8084exit:
8085 // UNLOCK
8086 if (featuresDictLock) {
8087 IOLockUnlock(featuresDictLock);
8088 }
8089
8090 if (shouldUpdate) {
8091 if (event &&
8092 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
8093 setThermalState(value);
8094 }
8095 messageClients(kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
8096 }
8097
8098 return kIOReturnSuccess;
8099}
8100
8101//******************************************************************************
8102// receivePowerNotification
8103//
8104// The power controller is notifying us of a hardware-related power management
8105// event that we must handle. This may be a result of an 'environment' interrupt
8106// from the power mgt micro.
8107//******************************************************************************
8108
8109IOReturn
8110IOPMrootDomain::receivePowerNotification( UInt32 msg )
8111{
cb323159
A
8112 if (msg & kIOPMPowerButton) {
8113 uint32_t currentPhase = pmTracer->getTracePhase();
8114 if (currentPhase != kIOPMTracePointSystemUp && currentPhase > kIOPMTracePointSystemSleep) {
8115 DEBUG_LOG("power button pressed during wake. phase = %u\n", currentPhase);
8116 swd_flags |= SWD_PWR_BTN_STACKSHOT;
8117 thread_call_enter(powerButtonDown);
8118 } else {
8119 DEBUG_LOG("power button pressed when system is up\n");
8120 }
8121 } else if (msg & kIOPMPowerButtonUp) {
8122 if (swd_flags & SWD_PWR_BTN_STACKSHOT) {
8123 swd_flags &= ~SWD_PWR_BTN_STACKSHOT;
8124 thread_call_enter(powerButtonUp);
8125 }
8126 } else {
8127 pmPowerStateQueue->submitPowerEvent(
8128 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
8129 }
0a7de745
A
8130 return kIOReturnSuccess;
8131}
8132
8133void
8134IOPMrootDomain::handlePowerNotification( UInt32 msg )
8135{
8136 bool eval_clamshell = false;
cb323159 8137 bool eval_clamshell_alarm = false;
0a7de745
A
8138
8139 ASSERT_GATED();
8140
8141 /*
8142 * Local (IOPMrootDomain only) eval clamshell command
8143 */
8144 if (msg & kLocalEvalClamshellCommand) {
f427ee49 8145 if ((gClamshellFlags & kClamshell_WAR_47715679) && isRTCAlarmWake) {
cb323159
A
8146 eval_clamshell_alarm = true;
8147
8148 // reset isRTCAlarmWake. This evaluation should happen only once
8149 // on RTC/Alarm wake. Any clamshell events after wake should follow
8150 // the regular evaluation
8151 isRTCAlarmWake = false;
8152 } else {
8153 eval_clamshell = true;
8154 }
0a7de745
A
8155 }
8156
8157 /*
8158 * Overtemp
8159 */
8160 if (msg & kIOPMOverTemp) {
f427ee49
A
8161 DLOG("Thermal overtemp message received!\n");
8162 thermalEmergencyState = true;
0a7de745
A
8163 privateSleepSystem(kIOPMSleepReasonThermalEmergency);
8164 }
8165
8166 /*
8167 * Forward DW thermal notification to client, if system is not going to sleep
8168 */
8169 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep)) {
8170 DLOG("DarkWake thermal limits message received!\n");
0a7de745
A
8171 messageClients(kIOPMMessageDarkWakeThermalEmergency);
8172 }
8173
8174 /*
8175 * Sleep Now!
8176 */
8177 if (msg & kIOPMSleepNow) {
8178 privateSleepSystem(kIOPMSleepReasonSoftware);
8179 }
8180
8181 /*
8182 * Power Emergency
8183 */
8184 if (msg & kIOPMPowerEmergency) {
c3c9b80d 8185 DLOG("Received kIOPMPowerEmergency");
0a7de745
A
8186 lowBatteryCondition = true;
8187 privateSleepSystem(kIOPMSleepReasonLowPower);
8188 }
8189
8190 /*
8191 * Clamshell OPEN
8192 */
8193 if (msg & kIOPMClamshellOpened) {
8194 DLOG("Clamshell opened\n");
8195 // Received clamshel open message from clamshell controlling driver
8196 // Update our internal state and tell general interest clients
8197 clamshellClosed = false;
8198 clamshellExists = true;
8199
8200 // Don't issue a hid tickle when lid is open and polled on wake
8201 if (msg & kIOPMSetValue) {
8202 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
8203 reportUserInput();
8204 }
8205
8206 // Tell PMCPU
8207 informCPUStateChange(kInformLid, 0);
8208
8209 // Tell general interest clients
8210 sendClientClamshellNotification();
8211
8212 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
8213 || (lastSleepReason == kIOPMSleepReasonIdle)
8214 || (lastSleepReason == kIOPMSleepReasonMaintenance));
8215 if (aborting) {
8216 userActivityCount++;
8217 }
8218 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
8219 }
8220
8221 /*
8222 * Clamshell CLOSED
8223 * Send the clamshell interest notification since the lid is closing.
8224 */
8225 if (msg & kIOPMClamshellClosed) {
f427ee49
A
8226 if ((clamshellIgnoreClose || (gClamshellFlags & kClamshell_WAR_38378787)) &&
8227 clamshellClosed && clamshellExists) {
0a7de745
A
8228 DLOG("Ignoring redundant Clamshell close event\n");
8229 } else {
8230 DLOG("Clamshell closed\n");
8231 // Received clamshel open message from clamshell controlling driver
8232 // Update our internal state and tell general interest clients
8233 clamshellClosed = true;
8234 clamshellExists = true;
8235
f427ee49
A
8236 // Ignore all following clamshell close events until the clamshell
8237 // is opened or the system sleeps. When a clamshell close triggers
8238 // a system wake, the lid driver may send us two clamshell close
8239 // events, one for the clamshell close event itself, and a second
8240 // close event when the driver polls the lid state on wake.
8241 clamshellIgnoreClose = true;
8242
0a7de745
A
8243 // Tell PMCPU
8244 informCPUStateChange(kInformLid, 1);
8245
8246 // Tell general interest clients
8247 sendClientClamshellNotification();
8248
8249 // And set eval_clamshell = so we can attempt
8250 eval_clamshell = true;
8251 }
8252 }
00867663 8253
0a7de745
A
8254 /*
8255 * Set Desktop mode (sent from graphics)
8256 *
8257 * -> reevaluate lid state
8258 */
8259 if (msg & kIOPMSetDesktopMode) {
0a7de745
A
8260 desktopMode = (0 != (msg & kIOPMSetValue));
8261 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
f427ee49 8262 DLOG("Desktop mode %d\n", desktopMode);
00867663 8263
0a7de745 8264 sendClientClamshellNotification();
00867663 8265
0a7de745
A
8266 // Re-evaluate the lid state
8267 eval_clamshell = true;
8268 }
1c79356b 8269
0a7de745
A
8270 /*
8271 * AC Adaptor connected
8272 *
8273 * -> reevaluate lid state
8274 */
8275 if (msg & kIOPMSetACAdaptorConnected) {
8276 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
8277 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
b0d623f7 8278
0a7de745
A
8279 // Tell CPU PM
8280 informCPUStateChange(kInformAC, !acAdaptorConnected);
b0d623f7 8281
0a7de745
A
8282 // Tell BSD if AC is connected
8283 // 0 == external power source; 1 == on battery
8284 post_sys_powersource(acAdaptorConnected ? 0:1);
1c79356b 8285
0a7de745
A
8286 sendClientClamshellNotification();
8287
8288 // Re-evaluate the lid state
8289 eval_clamshell = true;
3e170ce0 8290
0a7de745
A
8291 // Lack of AC may have latched a display wrangler tickle.
8292 // This mirrors the hardware's USB wake event latch, where a latched
8293 // USB wake event followed by an AC attach will trigger a full wake.
8294 latchDisplayWranglerTickle( false );
3e170ce0 8295
0a7de745
A
8296#if HIBERNATION
8297 // AC presence will reset the standy timer delay adjustment.
8298 _standbyTimerResetSeconds = 0;
8299#endif
8300 if (!userIsActive) {
8301 // Reset userActivityTime when power supply is changed(rdr 13789330)
8302 clock_get_uptime(&userActivityTime);
8303 }
8304 }
3e170ce0 8305
0a7de745
A
8306 /*
8307 * Enable Clamshell (external display disappear)
8308 *
8309 * -> reevaluate lid state
8310 */
8311 if (msg & kIOPMEnableClamshell) {
8312 DLOG("Clamshell enabled\n");
f427ee49 8313
0a7de745
A
8314 // Re-evaluate the lid state
8315 // System should sleep on external display disappearance
8316 // in lid closed operation.
8317 if (true == clamshellDisabled) {
8318 eval_clamshell = true;
f427ee49
A
8319
8320#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8321 // Also clear kClamshellSleepDisableInternal when graphics enables
8322 // the clamshell during a full wake. When graphics is behaving as
8323 // expected, this will allow clamshell close to be honored earlier
8324 // rather than waiting for the delayed evaluation.
8325 if ((clamshellSleepDisableMask & kClamshellSleepDisableInternal) &&
8326 (CAP_PENDING(kIOPMSystemCapabilityGraphics) ||
8327 CAP_CURRENT(kIOPMSystemCapabilityGraphics))) {
8328 setClamShellSleepDisable(false, kClamshellSleepDisableInternal);
8329
8330 // Cancel the TC to avoid an extra kLocalEvalClamshellCommand
8331 // when timer expires which is harmless but useless.
8332 thread_call_cancel(fullWakeThreadCall);
8333 }
8334#endif
0a7de745 8335 }
3e170ce0 8336
0a7de745
A
8337 clamshellDisabled = false;
8338 sendClientClamshellNotification();
8339 }
3e170ce0 8340
0a7de745
A
8341 /*
8342 * Disable Clamshell (external display appeared)
8343 * We don't bother re-evaluating clamshell state. If the system is awake,
8344 * the lid is probably open.
8345 */
8346 if (msg & kIOPMDisableClamshell) {
8347 DLOG("Clamshell disabled\n");
8348 clamshellDisabled = true;
8349 sendClientClamshellNotification();
8350 }
3e170ce0 8351
0a7de745 8352 /*
f427ee49 8353 * Evaluate clamshell and SLEEP if appropriate
0a7de745 8354 */
cb323159
A
8355 if (eval_clamshell_alarm && clamshellClosed) {
8356 if (shouldSleepOnRTCAlarmWake()) {
8357 privateSleepSystem(kIOPMSleepReasonClamshell);
8358 }
8359 } else if (eval_clamshell && clamshellClosed) {
0a7de745
A
8360 if (shouldSleepOnClamshellClosed()) {
8361 privateSleepSystem(kIOPMSleepReasonClamshell);
8362 } else {
8363 evaluatePolicy( kStimulusDarkWakeEvaluate );
8364 }
8365 }
94ff46dc
A
8366
8367 if (msg & kIOPMProModeEngaged) {
8368 int newState = 1;
8369 DLOG("ProModeEngaged\n");
f427ee49 8370 messageClient(kIOPMMessageProModeStateChange, systemCapabilityNotifier.get(), &newState, sizeof(newState));
94ff46dc
A
8371 }
8372
8373 if (msg & kIOPMProModeDisengaged) {
8374 int newState = 0;
8375 DLOG("ProModeDisengaged\n");
f427ee49 8376 messageClient(kIOPMMessageProModeStateChange, systemCapabilityNotifier.get(), &newState, sizeof(newState));
94ff46dc 8377 }
3e170ce0
A
8378}
8379
b0d623f7 8380//******************************************************************************
0a7de745 8381// evaluatePolicy
1c79356b 8382//
0a7de745 8383// Evaluate root-domain policy in response to external changes.
b0d623f7 8384//******************************************************************************
1c79356b 8385
0a7de745
A
8386void
8387IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
8388{
8389 union {
8390 struct {
8391 int idleSleepEnabled : 1;
8392 int idleSleepDisabled : 1;
8393 int displaySleep : 1;
8394 int sleepDelayChanged : 1;
8395 int evaluateDarkWake : 1;
8396 int adjustPowerState : 1;
8397 int userBecameInactive : 1;
f427ee49 8398 int displaySleepEntry : 1;
0a7de745
A
8399 } bit;
8400 uint32_t u32;
8401 } flags;
8402
8403
8404 ASSERT_GATED();
8405 flags.u32 = 0;
8406
8407 switch (stimulus) {
8408 case kStimulusDisplayWranglerSleep:
8409 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
f427ee49
A
8410 if (!wranglerPowerOff) {
8411 // wrangler is in sleep state or lower
0a7de745
A
8412 flags.bit.displaySleep = true;
8413 }
f427ee49
A
8414 if (!wranglerAsleep) {
8415 // transition from wrangler wake to wrangler sleep
8416 flags.bit.displaySleepEntry = true;
8417 wranglerAsleep = true;
8418 }
0a7de745
A
8419 break;
8420
8421 case kStimulusDisplayWranglerWake:
8422 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8423 displayIdleForDemandSleep = false;
f427ee49 8424 wranglerPowerOff = false;
0a7de745
A
8425 wranglerAsleep = false;
8426 break;
8427
8428 case kStimulusEnterUserActiveState:
8429 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8430 if (_preventUserActive) {
8431 DLOG("user active dropped\n");
8432 break;
8433 }
8434 if (!userIsActive) {
8435 userIsActive = true;
8436 userWasActive = true;
8437 clock_get_uptime(&gUserActiveAbsTime);
8438
8439 // Stay awake after dropping demand for display power on
8440 if (kFullWakeReasonDisplayOn == fullWakeReason) {
8441 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
8442 DLOG("User activity while in notification wake\n");
cb323159 8443 changePowerStateWithOverrideTo( getRUN_STATE(), 0);
0a7de745 8444 }
0b4e3aa0 8445
0a7de745 8446 kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
f427ee49 8447 setProperty(gIOPMUserIsActiveKey.get(), kOSBooleanTrue);
0a7de745
A
8448 messageClients(kIOPMMessageUserIsActiveChanged);
8449 }
8450 flags.bit.idleSleepDisabled = true;
8451 break;
8452
8453 case kStimulusLeaveUserActiveState:
8454 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8455 if (userIsActive) {
8456 clock_get_uptime(&gUserInactiveAbsTime);
8457 userIsActive = false;
8458 clock_get_uptime(&userBecameInactiveTime);
8459 flags.bit.userBecameInactive = true;
8460
8461 kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
f427ee49 8462 setProperty(gIOPMUserIsActiveKey.get(), kOSBooleanFalse);
0a7de745
A
8463 messageClients(kIOPMMessageUserIsActiveChanged);
8464 }
8465 break;
b0d623f7 8466
0a7de745
A
8467 case kStimulusAggressivenessChanged:
8468 {
8469 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
f427ee49
A
8470 unsigned long aggressiveValue;
8471 uint32_t minutesToIdleSleep = 0;
8472 uint32_t minutesToDisplayDim = 0;
8473 uint32_t minutesDelta = 0;
0a7de745
A
8474
8475 // Fetch latest display and system sleep slider values.
f427ee49
A
8476 aggressiveValue = 0;
8477 getAggressiveness(kPMMinutesToSleep, &aggressiveValue);
8478 minutesToIdleSleep = (uint32_t) aggressiveValue;
8479
8480 aggressiveValue = 0;
8481 getAggressiveness(kPMMinutesToDim, &aggressiveValue);
8482 minutesToDisplayDim = (uint32_t) aggressiveValue;
0a7de745 8483 DLOG("aggressiveness changed: system %u->%u, display %u\n",
f427ee49 8484 sleepSlider, minutesToIdleSleep, minutesToDisplayDim);
0a7de745 8485
f427ee49 8486 DLOG("idle time -> %d secs (ena %d)\n",
0a7de745
A
8487 idleSeconds, (minutesToIdleSleep != 0));
8488
0a7de745
A
8489 // How long to wait before sleeping the system once
8490 // the displays turns off is indicated by 'extraSleepDelay'.
8491
8492 if (minutesToIdleSleep > minutesToDisplayDim) {
8493 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
8494 } else if (minutesToIdleSleep == minutesToDisplayDim) {
8495 minutesDelta = 1;
8496 }
6d2010ae 8497
0a7de745
A
8498 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0)) {
8499 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
8500 }
fe8ab488 8501
0a7de745
A
8502 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
8503 flags.bit.idleSleepDisabled = true;
8504 idleSleepEnabled = false;
8505 }
f427ee49 8506#if !defined(XNU_TARGET_OS_OSX)
0a7de745
A
8507 if (0x7fffffff == minutesToIdleSleep) {
8508 minutesToIdleSleep = idleSeconds;
8509 }
f427ee49 8510#endif /* !defined(XNU_TARGET_OS_OSX) */
b0d623f7 8511
0a7de745
A
8512 if (((minutesDelta != extraSleepDelay) ||
8513 (userActivityTime != userActivityTime_prev)) &&
8514 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled) {
8515 flags.bit.sleepDelayChanged = true;
8516 }
b0d623f7 8517
0a7de745
A
8518 if (systemDarkWake && !darkWakeToSleepASAP &&
8519 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled)) {
8520 // Reconsider decision to remain in dark wake
8521 flags.bit.evaluateDarkWake = true;
8522 }
b0d623f7 8523
0a7de745
A
8524 sleepSlider = minutesToIdleSleep;
8525 extraSleepDelay = minutesDelta;
8526 userActivityTime_prev = userActivityTime;
8527 } break;
8528
8529 case kStimulusDemandSystemSleep:
8530 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8531 displayIdleForDemandSleep = true;
8532 if (wrangler && wranglerIdleSettings) {
8533 // Request wrangler idle only when demand sleep is triggered
8534 // from full wake.
8535 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
f427ee49 8536 wrangler->setProperties(wranglerIdleSettings.get());
0a7de745
A
8537 DLOG("Requested wrangler idle\n");
8538 }
8539 }
8540 // arg = sleepReason
8541 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
8542 break;
8543
8544 case kStimulusAllowSystemSleepChanged:
8545 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8546 flags.bit.adjustPowerState = true;
8547 break;
8548
8549 case kStimulusDarkWakeActivityTickle:
8550 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8551 // arg == true implies real and not self generated wrangler tickle.
8552 // Update wake type on PM work loop instead of the tickle thread to
8553 // eliminate the possibility of an early tickle clobbering the wake
8554 // type set by the platform driver.
8555 if (arg == true) {
8556 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
8557 }
b0d623f7 8558
f427ee49 8559 if (!darkWakeExit) {
0a7de745
A
8560 if (latchDisplayWranglerTickle(true)) {
8561 DLOG("latched tickle\n");
8562 break;
8563 }
a1c7dba1 8564
f427ee49
A
8565 darkWakeExit = true;
8566 DLOG("Requesting full wake due to dark wake activity tickle\n");
0a7de745
A
8567 requestFullWake( kFullWakeReasonLocalUser );
8568 }
8569 break;
a1c7dba1 8570
0a7de745
A
8571 case kStimulusDarkWakeEntry:
8572 case kStimulusDarkWakeReentry:
8573 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8574 // Any system transitions since the last dark wake transition
8575 // will invalid the stimulus.
a1c7dba1 8576
0a7de745
A
8577 if (arg == _systemStateGeneration) {
8578 DLOG("dark wake entry\n");
8579 systemDarkWake = true;
8580
f427ee49 8581 // Keep wranglerPowerOff an invariant when wrangler is absent
0a7de745 8582 if (wrangler) {
f427ee49 8583 wranglerPowerOff = true;
0a7de745 8584 }
fe8ab488 8585
0a7de745
A
8586 if (kStimulusDarkWakeEntry == stimulus) {
8587 clock_get_uptime(&userBecameInactiveTime);
8588 flags.bit.evaluateDarkWake = true;
8589 if (activitySinceSleep()) {
8590 DLOG("User activity recorded while going to darkwake\n");
8591 reportUserInput();
8592 }
8593 }
b0d623f7 8594
0a7de745
A
8595 // Always accelerate disk spindown while in dark wake,
8596 // even if system does not support/allow sleep.
b0d623f7 8597
0a7de745
A
8598 cancelIdleSleepTimer();
8599 setQuickSpinDownTimeout();
8600 }
8601 break;
fe8ab488 8602
0a7de745
A
8603 case kStimulusDarkWakeEvaluate:
8604 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8605 if (systemDarkWake) {
8606 flags.bit.evaluateDarkWake = true;
8607 }
8608 break;
8609
8610 case kStimulusNoIdleSleepPreventers:
8611 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
8612 flags.bit.adjustPowerState = true;
8613 break;
8614 } /* switch(stimulus) */
8615
8616 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason)) {
f427ee49
A
8617 DLOG("DarkWake: sleepASAP %d, clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
8618 darkWakeToSleepASAP, clamshellClosed, clamshellDisabled, clamshellSleepDisableMask, desktopMode, acAdaptorConnected);
0a7de745
A
8619 if (darkWakeToSleepASAP ||
8620 (clamshellClosed && !(desktopMode && acAdaptorConnected))) {
8621 uint32_t newSleepReason;
8622
8623 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
8624 // System was previously in full wake. Sleep reason from
8625 // full to dark already recorded in fullToDarkReason.
8626
8627 if (lowBatteryCondition) {
8628 newSleepReason = kIOPMSleepReasonLowPower;
f427ee49
A
8629 } else if (thermalEmergencyState) {
8630 newSleepReason = kIOPMSleepReasonThermalEmergency;
0a7de745
A
8631 } else {
8632 newSleepReason = fullToDarkReason;
8633 }
8634 } else {
8635 // In dark wake from system sleep.
8636
8637 if (darkWakeSleepService) {
8638 newSleepReason = kIOPMSleepReasonSleepServiceExit;
8639 } else {
8640 newSleepReason = kIOPMSleepReasonMaintenance;
8641 }
8642 }
b0d623f7 8643
0a7de745
A
8644 if (checkSystemCanSleep(newSleepReason)) {
8645 privateSleepSystem(newSleepReason);
8646 }
8647 } else { // non-maintenance (network) dark wake
8648 if (checkSystemCanSleep(kIOPMSleepReasonIdle)) {
8649 // Release power clamp, and wait for children idle.
8650 adjustPowerState(true);
8651 } else {
f427ee49 8652 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonDarkWakeCannotSleep);
0a7de745
A
8653 }
8654 }
8655 }
b0d623f7 8656
0a7de745
A
8657 if (systemDarkWake) {
8658 // The rest are irrelevant while system is in dark wake.
8659 flags.u32 = 0;
8660 }
b0d623f7 8661
f427ee49 8662 if ((flags.bit.displaySleepEntry) &&
0a7de745 8663 (kFullWakeReasonDisplayOn == fullWakeReason)) {
f427ee49 8664 // kIOPMSleepReasonNotificationWakeExit
0a7de745 8665 DLOG("Display sleep while in notification wake\n");
f427ee49 8666 changePowerStateWithOverrideTo(SLEEP_STATE, kIOPMSleepReasonNotificationWakeExit);
0a7de745 8667 }
0b4c1975 8668
0a7de745
A
8669 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged) {
8670 bool cancelQuickSpindown = false;
0b4c1975 8671
0a7de745
A
8672 if (flags.bit.sleepDelayChanged) {
8673 // Cancel existing idle sleep timer and quick disk spindown.
8674 // New settings will be applied by the idleSleepEnabled flag
8675 // handler below if idle sleep is enabled.
0b4c1975 8676
0a7de745
A
8677 DLOG("extra sleep timer changed\n");
8678 cancelIdleSleepTimer();
8679 cancelQuickSpindown = true;
8680 } else {
8681 DLOG("user inactive\n");
8682 }
0b4c1975 8683
0a7de745
A
8684 if (!userIsActive && idleSleepEnabled) {
8685 startIdleSleepTimer(getTimeToIdleSleep());
8686 }
b0d623f7 8687
0a7de745
A
8688 if (cancelQuickSpindown) {
8689 restoreUserSpinDownTimeout();
8690 }
8691 }
b0d623f7 8692
0a7de745
A
8693 if (flags.bit.idleSleepEnabled) {
8694 DLOG("idle sleep timer enabled\n");
8695 if (!wrangler) {
f427ee49
A
8696#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8697 startIdleSleepTimer(getTimeToIdleSleep());
8698#else
8699 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonIdleSleepEnabled);
0a7de745 8700 startIdleSleepTimer( idleSeconds );
f427ee49 8701#endif
0a7de745
A
8702 } else {
8703 // Start idle timer if prefs now allow system sleep
8704 // and user is already inactive. Disk spindown is
8705 // accelerated upon timer expiration.
316670eb 8706
0a7de745
A
8707 if (!userIsActive) {
8708 startIdleSleepTimer(getTimeToIdleSleep());
8709 }
8710 }
8711 }
0b4e3aa0 8712
0a7de745
A
8713 if (flags.bit.idleSleepDisabled) {
8714 DLOG("idle sleep timer disabled\n");
8715 cancelIdleSleepTimer();
8716 restoreUserSpinDownTimeout();
8717 adjustPowerState();
8718 }
8719
8720 if (flags.bit.adjustPowerState) {
8721 bool sleepASAP = false;
8722
cb323159 8723 if (!systemBooting && (0 == idleSleepPreventersCount())) {
0a7de745 8724 if (!wrangler) {
f427ee49 8725 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonEvaluatePolicy);
0a7de745 8726 if (idleSleepEnabled) {
f427ee49
A
8727#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8728 if (!extraSleepDelay && !idleSleepTimerPending) {
8729 sleepASAP = true;
8730 }
8731#else
0a7de745
A
8732 // stay awake for at least idleSeconds
8733 startIdleSleepTimer(idleSeconds);
f427ee49 8734#endif
0a7de745
A
8735 }
8736 } else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake) {
8737 sleepASAP = true;
8738 }
8739 }
0b4e3aa0 8740
0a7de745
A
8741 adjustPowerState(sleepASAP);
8742 }
0c530ab8
A
8743}
8744
cb323159
A
8745//******************************************************************************
8746
8747unsigned int
8748IOPMrootDomain::idleSleepPreventersCount()
8749{
cb323159
A
8750 if (_aotMode) {
8751 unsigned int count __block;
8752 count = 0;
8753 preventIdleSleepList->iterateObjects(^bool (OSObject * obj)
8754 {
8755 count += (NULL == obj->metaCast("AppleARMBacklight"));
8756 return false;
8757 });
8758 return count;
8759 }
cb323159
A
8760
8761 return preventIdleSleepList->getCount();
8762}
8763
8764
39236c6e
A
8765//******************************************************************************
8766// requestFullWake
8767//
8768// Request transition from dark wake to full wake
8769//******************************************************************************
8770
0a7de745
A
8771void
8772IOPMrootDomain::requestFullWake( FullWakeReason reason )
8773{
8774 uint32_t options = 0;
cb323159 8775 IOService * pciRoot = NULL;
0a7de745
A
8776 bool promotion = false;
8777
8778 // System must be in dark wake and a valid reason for entering full wake
8779 if ((kFullWakeReasonNone == reason) ||
8780 (kFullWakeReasonNone != fullWakeReason) ||
8781 (CAP_CURRENT(kIOPMSystemCapabilityGraphics))) {
8782 return;
8783 }
8784
8785 // Will clear reason upon exit from full wake
8786 fullWakeReason = reason;
8787
8788 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
8789 kIOPMSystemCapabilityAudio);
8790
8791 if ((kSystemTransitionWake == _systemTransitionType) &&
8792 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
f427ee49 8793 !darkWakePowerClamped) {
0a7de745
A
8794 // Promote to full wake while waking up to dark wake due to tickle.
8795 // PM will hold off notifying the graphics subsystem about system wake
8796 // as late as possible, so if a HID tickle does arrive, graphics can
f427ee49
A
8797 // power up from this same wake transition. Otherwise, the latency to
8798 // power up graphics on the following transition can be huge on certain
8799 // systems. However, once any power clamping has taken effect, it is
8800 // too late to promote the current dark wake transition to a full wake.
0a7de745
A
8801 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
8802 kIOPMSystemCapabilityAudio);
8803
f427ee49
A
8804 // Tell the PCI parent of audio and graphics drivers to stop
8805 // delaying the child notifications. Same for root domain.
8806 pciRoot = pciHostBridgeDriver.get();
0a7de745
A
8807 willEnterFullWake();
8808 promotion = true;
8809 }
8810
8811 // Unsafe to cancel once graphics was powered.
8812 // If system woke from dark wake, the return to sleep can
8813 // be cancelled. "awake -> dark -> sleep" transition
f427ee49 8814 // can be cancelled also, during the "dark -> sleep" phase
0a7de745
A
8815 // *prior* to driver power down.
8816 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
8817 _pendingCapability == 0) {
8818 options |= kIOPMSyncCancelPowerDown;
8819 }
8820
8821 synchronizePowerTree(options, pciRoot);
f427ee49 8822
0a7de745
A
8823 if (kFullWakeReasonLocalUser == fullWakeReason) {
8824 // IOGraphics doesn't light the display even though graphics is
8825 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
8826 // So, do an explicit activity tickle
8827 if (wrangler) {
8828 wrangler->activityTickle(0, 0);
8829 }
8830 }
8831
8832 // Log a timestamp for the initial full wake request.
8833 // System may not always honor this full wake request.
8834 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
8835 AbsoluteTime now;
8836 uint64_t nsec;
8837
8838 clock_get_uptime(&now);
8839 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
8840 absolutetime_to_nanoseconds(now, &nsec);
8841 MSG("full wake %s (reason %u) %u ms\n",
8842 promotion ? "promotion" : "request",
8843 fullWakeReason, ((int)((nsec) / NSEC_PER_MSEC)));
8844 }
39236c6e
A
8845}
8846
8847//******************************************************************************
8848// willEnterFullWake
8849//
8850// System will enter full wake from sleep, from dark wake, or from dark
8851// wake promotion. This function aggregate things that are in common to
8852// all three full wake transitions.
8853//
8854// Assumptions: fullWakeReason was updated
8855//******************************************************************************
8856
0a7de745
A
8857void
8858IOPMrootDomain::willEnterFullWake( void )
39236c6e 8859{
0a7de745
A
8860 hibernateRetry = false;
8861 sleepToStandby = false;
8862 standbyNixed = false;
8863 resetTimers = false;
8864 sleepTimerMaintenance = false;
39236c6e 8865
f427ee49
A
8866 assert(!CAP_CURRENT(kIOPMSystemCapabilityGraphics));
8867
0a7de745
A
8868 _systemMessageClientMask = kSystemMessageClientPowerd |
8869 kSystemMessageClientLegacyApp;
39236c6e 8870
0a7de745 8871 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) {
f427ee49 8872 // First time to attain full wake capability since the last wake
0a7de745 8873 _systemMessageClientMask |= kSystemMessageClientKernel;
39236c6e 8874
0a7de745 8875 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
f427ee49 8876 setProperty(gIOPMUserTriggeredFullWakeKey.get(),
0a7de745
A
8877 (kFullWakeReasonLocalUser == fullWakeReason) ?
8878 kOSBooleanTrue : kOSBooleanFalse);
8879 }
8a3053a0 8880#if HIBERNATION
0a7de745 8881 IOHibernateSetWakeCapabilities(_pendingCapability);
8a3053a0 8882#endif
39236c6e 8883
0a7de745
A
8884 IOService::setAdvisoryTickleEnable( true );
8885 tellClients(kIOMessageSystemWillPowerOn);
8886 preventTransitionToUserActive(false);
39236c6e
A
8887}
8888
8889//******************************************************************************
8890// fullWakeDelayedWork
8891//
8892// System has already entered full wake. Invoked by a delayed thread call.
8893//******************************************************************************
8894
0a7de745
A
8895void
8896IOPMrootDomain::fullWakeDelayedWork( void )
39236c6e 8897{
f427ee49
A
8898#if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8899 if (!gIOPMWorkLoop->inGate()) {
8900 gIOPMWorkLoop->runAction(
8901 OSMemberFunctionCast(IOWorkLoop::Action, this,
8902 &IOPMrootDomain::fullWakeDelayedWork), this);
8903 return;
8904 }
8905
8906 DLOG("fullWakeDelayedWork cap cur %x pend %x high %x, clamshell disable %x/%x\n",
8907 _currentCapability, _pendingCapability, _highestCapability,
8908 clamshellDisabled, clamshellSleepDisableMask);
8909
8910 if (clamshellExists &&
8911 CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
8912 !CAP_CHANGE(kIOPMSystemCapabilityGraphics)) {
8913 if (clamshellSleepDisableMask & kClamshellSleepDisableInternal) {
8914 setClamShellSleepDisable(false, kClamshellSleepDisableInternal);
8915 } else {
8916 // Not the initial full wake after waking from sleep.
8917 // Evaluate the clamshell for rdar://problem/9157444.
8918 receivePowerNotification(kLocalEvalClamshellCommand);
8919 }
0a7de745 8920 }
39236c6e
A
8921#endif
8922}
8923
7ddcb079
A
8924//******************************************************************************
8925// evaluateAssertions
8926//
8927//******************************************************************************
cb323159
A
8928
8929// Bitmask of all kernel assertions that prevent system idle sleep.
8930// kIOPMDriverAssertionReservedBit7 is reserved for IOMediaBSDClient.
8931#define NO_IDLE_SLEEP_ASSERTIONS_MASK \
8932 (kIOPMDriverAssertionReservedBit7 | \
8933 kIOPMDriverAssertionPreventSystemIdleSleepBit)
8934
0a7de745
A
8935void
8936IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
8937{
8938 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
8939
8940 messageClients(kIOPMMessageDriverAssertionsChanged);
8941
8942 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
8943 if (wrangler) {
8944 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
8945
8946 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
8947 wrangler->setIgnoreIdleTimer( value );
8948 }
8949 }
8950
8951 if (changedBits & kIOPMDriverAssertionCPUBit) {
cb323159
A
8952 if (_aotNow) {
8953 IOLog("CPU assertions %d\n", (0 != (kIOPMDriverAssertionCPUBit & newAssertions)));
8954 }
8955 evaluatePolicy(_aotNow ? kStimulusNoIdleSleepPreventers : kStimulusDarkWakeEvaluate);
0a7de745
A
8956 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
8957 AbsoluteTime now;
8958 clock_usec_t microsecs;
8959 clock_get_uptime(&now);
8960 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
8961 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
8962 if (assertOnWakeReport) {
8963 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
8964 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
8965 }
8966 }
8967 }
8968
cb323159
A
8969 if (changedBits & NO_IDLE_SLEEP_ASSERTIONS_MASK) {
8970 if ((newAssertions & NO_IDLE_SLEEP_ASSERTIONS_MASK) != 0) {
8971 if ((oldAssertions & NO_IDLE_SLEEP_ASSERTIONS_MASK) == 0) {
8972 DLOG("PreventIdleSleep driver assertion raised\n");
8973 bool ok = updatePreventIdleSleepList(this, true);
8974 if (ok && (changedBits & kIOPMDriverAssertionPreventSystemIdleSleepBit)) {
8975 // Cancel idle sleep if there is one in progress
8976 cancelIdlePowerDown(this);
8977 }
8978 }
0a7de745 8979 } else {
cb323159 8980 DLOG("PreventIdleSleep driver assertion dropped\n");
0a7de745
A
8981 updatePreventIdleSleepList(this, false);
8982 }
8983 }
7ddcb079
A
8984}
8985
6d2010ae
A
8986// MARK: -
8987// MARK: Statistics
8988
8989//******************************************************************************
8990// pmStats
8991//
8992//******************************************************************************
8993
0a7de745
A
8994void
8995IOPMrootDomain::pmStatsRecordEvent(
8996 int eventIndex,
8997 AbsoluteTime timestamp)
b0d623f7 8998{
0a7de745
A
8999 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
9000 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
9001 uint64_t delta;
9002 uint64_t nsec;
f427ee49 9003 OSSharedPtr<OSData> publishPMStats;
b0d623f7 9004
0a7de745 9005 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
b0d623f7 9006
0a7de745 9007 absolutetime_to_nanoseconds(timestamp, &nsec);
b0d623f7 9008
0a7de745
A
9009 switch (eventIndex) {
9010 case kIOPMStatsHibernateImageWrite:
9011 if (starting) {
9012 gPMStats.hibWrite.start = nsec;
9013 } else if (stopping) {
9014 gPMStats.hibWrite.stop = nsec;
9015 }
b0d623f7 9016
0a7de745
A
9017 if (stopping) {
9018 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
9019 IOLog("PMStats: Hibernate write took %qd ms\n", delta / NSEC_PER_MSEC);
9020 }
9021 break;
9022 case kIOPMStatsHibernateImageRead:
9023 if (starting) {
9024 gPMStats.hibRead.start = nsec;
9025 } else if (stopping) {
9026 gPMStats.hibRead.stop = nsec;
9027 }
b0d623f7 9028
0a7de745
A
9029 if (stopping) {
9030 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
9031 IOLog("PMStats: Hibernate read took %qd ms\n", delta / NSEC_PER_MSEC);
316670eb 9032
0a7de745 9033 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
f427ee49 9034 setProperty(kIOPMSleepStatisticsKey, publishPMStats.get());
0a7de745
A
9035 bzero(&gPMStats, sizeof(gPMStats));
9036 }
9037 break;
9038 }
b0d623f7
A
9039}
9040
9041/*
9042 * Appends a record of the application response to
9043 * IOPMrootDomain::pmStatsAppResponses
9044 */
0a7de745
A
9045void
9046IOPMrootDomain::pmStatsRecordApplicationResponse(
9047 const OSSymbol *response,
9048 const char *name,
9049 int messageType,
9050 uint32_t delay_ms,
9051 uint64_t id,
9052 OSObject *object,
f427ee49
A
9053 IOPMPowerStateIndex powerState,
9054 bool async)
9055{
9056 OSSharedPtr<OSDictionary> responseDescription;
9057 OSSharedPtr<OSNumber> delayNum;
9058 OSSharedPtr<OSNumber> powerCaps;
9059 OSSharedPtr<OSNumber> pidNum;
9060 OSSharedPtr<OSNumber> msgNum;
9061 OSSharedPtr<const OSSymbol> appname;
9062 OSSharedPtr<const OSSymbol> sleep;
9063 OSSharedPtr<const OSSymbol> wake;
cb323159 9064 IOPMServiceInterestNotifier *notify = NULL;
0a7de745
A
9065
9066 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object))) {
f427ee49 9067 if (response->isEqualTo(gIOPMStatsResponseTimedOut.get())) {
0a7de745
A
9068 notify->ackTimeoutCnt++;
9069 } else {
9070 notify->ackTimeoutCnt = 0;
9071 }
9072 }
9073
f427ee49 9074 if (response->isEqualTo(gIOPMStatsResponsePrompt.get()) ||
0a7de745
A
9075 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient)) {
9076 return;
9077 }
9078
9079
f427ee49 9080 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow.get())) {
0a7de745
A
9081 kdebugTrace(kPMLogDrvPSChangeDelay, id, messageType, delay_ms);
9082 } else if (notify) {
9083 // User space app or kernel capability client
9084 if (id) {
9085 kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
9086 } else {
9087 kdebugTrace(kPMLogDrvResponseDelay, notify->uuid0, messageType, delay_ms);
9088 }
9089 notify->msgType = 0;
9090 }
9091
9092 responseDescription = OSDictionary::withCapacity(5);
9093 if (responseDescription) {
9094 if (response) {
f427ee49 9095 responseDescription->setObject(_statsResponseTypeKey.get(), response);
0a7de745
A
9096 }
9097
9098 msgNum = OSNumber::withNumber(messageType, 32);
9099 if (msgNum) {
f427ee49 9100 responseDescription->setObject(_statsMessageTypeKey.get(), msgNum.get());
0a7de745
A
9101 }
9102
9103 if (!name && notify && notify->identifier) {
9104 name = notify->identifier->getCStringNoCopy();
9105 }
9106
9107 if (name && (strlen(name) > 0)) {
9108 appname = OSSymbol::withCString(name);
9109 if (appname) {
f427ee49 9110 responseDescription->setObject(_statsNameKey.get(), appname.get());
0a7de745
A
9111 }
9112 }
9113
9114 if (!id && notify) {
9115 id = notify->uuid0;
9116 }
9117 if (id != 0) {
9118 pidNum = OSNumber::withNumber(id, 64);
9119 if (pidNum) {
f427ee49 9120 responseDescription->setObject(_statsPIDKey.get(), pidNum.get());
0a7de745
A
9121 }
9122 }
9123
9124 delayNum = OSNumber::withNumber(delay_ms, 32);
9125 if (delayNum) {
f427ee49 9126 responseDescription->setObject(_statsTimeMSKey.get(), delayNum.get());
0a7de745
A
9127 }
9128
f427ee49 9129 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow.get())) {
0a7de745 9130 powerCaps = OSNumber::withNumber(powerState, 32);
fe8ab488 9131
3e170ce0 9132#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
f427ee49
A
9133 static const char * driverCallTypes[] = {
9134 [kDriverCallInformPreChange] = "powerStateWillChangeTo",
9135 [kDriverCallInformPostChange] = "powerStateDidChangeTo",
9136 [kDriverCallSetPowerState] = "setPowerState"
9137 };
9138
9139 if (messageType < (sizeof(driverCallTypes) / sizeof(driverCallTypes[0]))) {
9140 DLOG("%s[0x%qx]::%s(%u) %stook %d ms\n",
9141 name, id, driverCallTypes[messageType], (uint32_t) powerState,
9142 async ? "async " : "", delay_ms);
9143 }
fe8ab488 9144#endif
0a7de745
A
9145 } else {
9146 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
9147 }
9148 if (powerCaps) {
f427ee49 9149 responseDescription->setObject(_statsPowerCapsKey.get(), powerCaps.get());
0a7de745 9150 }
fe8ab488 9151
0a7de745
A
9152 sleep = OSSymbol::withCString("Sleep");
9153 wake = OSSymbol::withCString("Wake");
9154 if (_systemTransitionType == kSystemTransitionSleep) {
f427ee49 9155 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep.get());
0a7de745 9156 } else if (_systemTransitionType == kSystemTransitionWake) {
f427ee49 9157 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake.get());
0a7de745
A
9158 } else if (_systemTransitionType == kSystemTransitionCapability) {
9159 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) {
f427ee49 9160 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep.get());
0a7de745 9161 } else if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) {
f427ee49 9162 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake.get());
0a7de745
A
9163 }
9164 }
0a7de745
A
9165
9166 IOLockLock(pmStatsLock);
9167 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
f427ee49 9168 pmStatsAppResponses->setObject(responseDescription.get());
0a7de745
A
9169 }
9170 IOLockUnlock(pmStatsLock);
0a7de745
A
9171 }
9172
9173 return;
b0d623f7
A
9174}
9175
6d2010ae
A
9176// MARK: -
9177// MARK: PMTraceWorker
b0d623f7
A
9178
9179//******************************************************************************
9180// TracePoint support
9181//
9182//******************************************************************************
9183
0a7de745
A
9184#define kIOPMRegisterNVRAMTracePointHandlerKey \
9185 "IOPMRegisterNVRAMTracePointHandler"
9186
9187IOReturn
9188IOPMrootDomain::callPlatformFunction(
9189 const OSSymbol * functionName,
9190 bool waitForFunction,
9191 void * param1, void * param2,
9192 void * param3, void * param4 )
9193{
0a7de745
A
9194 if (pmTracer && functionName &&
9195 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
9196 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget) {
9197 uint32_t tracePointPhases, tracePointPCI;
9198 uint64_t statusCode;
9199
9200 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
9201 pmTracer->tracePointTarget = (void *) param2;
9202 tracePointPCI = (uint32_t)(uintptr_t) param3;
9203 tracePointPhases = (uint32_t)(uintptr_t) param4;
9204 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
f427ee49 9205 OSSharedPtr<IORegistryEntry> node = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
0a7de745 9206 if (node) {
f427ee49
A
9207 OSSharedPtr<OSObject> bootRomFailureProp;
9208 bootRomFailureProp = node->copyProperty(kIOEFIBootRomFailureKey);
9209 OSData *data = OSDynamicCast(OSData, bootRomFailureProp.get());
9210 uint32_t bootFailureCode;
0a7de745 9211 if (data && data->getLength() == sizeof(bootFailureCode)) {
f427ee49 9212 // Failure code from EFI/BootRom is a four byte structure
0a7de745 9213 memcpy(&bootFailureCode, data->getBytesNoCopy(), sizeof(bootFailureCode));
f427ee49 9214 tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
0a7de745 9215 }
0a7de745 9216 }
0a7de745
A
9217 }
9218 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
9219 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
9220 MSG("Sleep failure code 0x%08x 0x%08x\n",
9221 tracePointPCI, tracePointPhases);
9222 }
9223 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
9224 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
9225
9226 return kIOReturnSuccess;
9227 }
9228#if HIBERNATION
9229 else if (functionName &&
9230 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey)) {
9231 if (gSleepPolicyHandler) {
9232 return kIOReturnExclusiveAccess;
9233 }
9234 if (!param1) {
9235 return kIOReturnBadArgument;
9236 }
9237 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
9238 gSleepPolicyTarget = (void *) param2;
9239 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
9240 return kIOReturnSuccess;
9241 }
9242#endif
9243
9244 return super::callPlatformFunction(
9245 functionName, waitForFunction, param1, param2, param3, param4);
9246}
9247
9248void
9249IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
9250 uintptr_t param1, uintptr_t param2, uintptr_t param3)
9251{
9252 uint32_t code = IODBG_POWER(event);
9253 uint64_t regId = id;
9254 if (regId == 0) {
9255 regId = getRegistryEntryID();
9256 }
f427ee49 9257 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, code, (uintptr_t) regId, param1, param2, param3, 0);
0a7de745
A
9258}
9259
0a7de745
A
9260void
9261IOPMrootDomain::tracePoint( uint8_t point )
9262{
9263 if (systemBooting) {
9264 return;
9265 }
9266
9267 if (kIOPMTracePointWakeCapabilityClients == point) {
f427ee49 9268 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Disable);
0a7de745
A
9269 }
9270
9271 kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
9272 pmTracer->tracePoint(point);
9273}
9274
f427ee49
A
9275static void
9276kext_log_putc(char c)
9277{
9278 if (gKextNameEnd || gKextNamePos >= (sizeof(gKextNameBuf) - 1)) {
9279 return;
9280 }
9281 if (c == '(' || c == '[' || c == ' ') {
9282 c = 0;
9283 gKextNameEnd = true;
9284 }
9285
9286 gKextNameBuf[gKextNamePos++] = c;
9287}
9288
9289static int
9290kext_log(const char *fmt, ...)
9291{
9292 va_list listp;
9293
9294 va_start(listp, fmt);
9295 _doprnt(fmt, &listp, &kext_log_putc, 16);
9296 va_end(listp);
9297
9298 return 0;
9299}
9300
9301static OSPtr<const OSSymbol>
9302copyKextIdentifierWithAddress(vm_address_t address)
9303{
9304 OSSharedPtr<const OSSymbol> identifer;
9305
9306 IOLockLock(gHaltLogLock);
9307
9308 gKextNameEnd = false;
9309 gKextNamePos = 0;
9310 gKextNameBuf[0] = 0;
9311
9312 OSKext::printKextsInBacktrace(&address, 1, kext_log, OSKext::kPrintKextsLock | OSKext::kPrintKextsTerse);
9313 gKextNameBuf[sizeof(gKextNameBuf) - 1] = 0;
9314 identifer = OSSymbol::withCString((gKextNameBuf[0] != 0) ? gKextNameBuf : kOSKextKernelIdentifier);
9315
9316 IOLockUnlock(gHaltLogLock);
9317
9318 return identifer;
9319}
9320
9321// Caller serialized using PM workloop
9322const char *
9323IOPMrootDomain::getNotificationClientName(OSObject *object)
9324{
9325 IOPMServiceInterestNotifier *notifier = (typeof(notifier))object;
9326 const char *clientName = "UNKNOWN";
9327
9328 if (!notifier->clientName) {
9329 // Check for user client
9330 if (systemCapabilityNotifier && (((IOPMServiceInterestNotifier *) systemCapabilityNotifier.get())->handler == notifier->handler)) {
9331 OSNumber *clientID = NULL;
9332 messageClient(kIOMessageCopyClientID, object, &clientID);
9333 if (clientID) {
9334 OSSharedPtr<OSString> string(IOCopyLogNameForPID(clientID->unsigned32BitValue()), OSNoRetain);
9335 if (string) {
9336 notifier->clientName = OSSymbol::withString(string.get());
9337 }
9338 clientID->release();
9339 }
9340 } else if (notifier->identifier) {
9341 notifier->clientName.reset(notifier->identifier.get(), OSRetain);
9342 }
9343 }
9344
9345 if (notifier->clientName) {
9346 clientName = notifier->clientName->getCStringNoCopy();
9347 }
9348
9349 return clientName;
9350}
9351
0a7de745 9352void
f427ee49 9353IOPMrootDomain::traceNotification(OSObject *object, bool start, uint64_t timestamp, uint32_t msgIndex)
0a7de745
A
9354{
9355 IOPMServiceInterestNotifier *notifier;
9356
9357 if (systemBooting) {
9358 return;
9359 }
0a7de745
A
9360 notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9361 if (!notifier) {
9362 return;
9363 }
9364
9365 if (start) {
f427ee49
A
9366 pmTracer->traceDetail(notifier->uuid0 >> 32);
9367 kdebugTrace(kPMLogSleepWakeMessage, pmTracer->getTracePhase(),
9368 (uintptr_t) notifier->msgType, (uintptr_t) notifier->uuid0, (uintptr_t) notifier->uuid1);
9369
9370 // Update notifier state used for response/ack logging
9371 notifier->msgIndex = msgIndex;
9372 notifier->msgAbsTime = timestamp;
9373
9374 if (msgIndex != UINT_MAX) {
9375 DLOG("%s[%u] to %s\n", getIOMessageString(notifier->msgType), msgIndex, getNotificationClientName(notifier));
0a7de745 9376 } else {
f427ee49 9377 DLOG("%s to %s\n", getIOMessageString(notifier->msgType), getNotificationClientName(notifier));
0a7de745 9378 }
f427ee49
A
9379
9380 assert(notifierObject == NULL);
0a7de745 9381 notifierThread = current_thread();
f427ee49 9382 notifierObject.reset(notifier, OSRetain);
0a7de745 9383 } else {
f427ee49
A
9384 uint64_t nsec;
9385 uint32_t delayMS;
9386
9387 SUB_ABSOLUTETIME(&timestamp, &notifier->msgAbsTime);
9388 absolutetime_to_nanoseconds(timestamp, &nsec);
9389 delayMS = (uint32_t)(nsec / 1000000ULL);
9390 if (delayMS > notifier->maxMsgDelayMS) {
9391 notifier->maxMsgDelayMS = delayMS;
9392 }
9393
9394 assert(notifierObject == notifier);
9395 notifierObject.reset();
0a7de745 9396 notifierThread = NULL;
0a7de745
A
9397 }
9398}
9399
f427ee49
A
9400void
9401IOPMrootDomain::traceNotificationAck(OSObject *object, uint32_t delay_ms)
9402{
9403 if (systemBooting) {
9404 return;
9405 }
9406 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9407 if (!notifier) {
9408 return;
9409 }
9410
9411 kdebugTrace(kPMLogDrvResponseDelay, notifier->uuid0,
9412 (uintptr_t) notifier->uuid1, (uintptr_t) 0, (uintptr_t) delay_ms);
9413
9414 DLOG("%s[%u] ack from %s took %d ms\n",
9415 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms);
9416 if (delay_ms > notifier->maxAckDelayMS) {
9417 notifier->maxAckDelayMS = delay_ms;
9418 }
9419}
0a7de745
A
9420
9421void
f427ee49 9422IOPMrootDomain::traceNotificationResponse(OSObject *object, uint32_t delay_ms, uint32_t ack_time_us)
0a7de745 9423{
f427ee49
A
9424 if (systemBooting) {
9425 return;
9426 }
0a7de745
A
9427 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9428 if (!notifier) {
0a7de745
A
9429 return;
9430 }
9431
f427ee49
A
9432 kdebugTrace(kPMLogDrvResponseDelay, notifier->uuid0,
9433 (uintptr_t) notifier->uuid1, (uintptr_t)(ack_time_us / 1000), (uintptr_t) delay_ms);
9434
9435 if (ack_time_us == 0) {
9436 // Client work is done and ack will not be forthcoming
9437 DLOG("%s[%u] response from %s took %d ms\n",
9438 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms);
9439 } else {
9440 // Client needs more time and it must ack within ack_time_us
9441 DLOG("%s[%u] response from %s took %d ms (ack in %d us)\n",
9442 getIOMessageString(notifier->msgType), notifier->msgIndex, getNotificationClientName(notifier), delay_ms, ack_time_us);
0a7de745
A
9443 }
9444}
9445
f427ee49
A
9446void
9447IOPMrootDomain::traceFilteredNotification(OSObject *object)
9448{
9449 if ((kIOLogDebugPower & gIOKitDebug) == 0) {
9450 return;
9451 }
9452 if (systemBooting) {
9453 return;
9454 }
9455 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
9456 if (!notifier) {
9457 return;
9458 }
9459
9460 DLOG("%s to %s dropped\n", getIOMessageString(notifier->msgType), getNotificationClientName(notifier));
9461}
9462
0a7de745
A
9463void
9464IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uint32_t delay)
9465{
9466 if (!systemBooting) {
9467 uint32_t detail = ((msgType & 0xffff) << 16) | (delay & 0xffff);
9468 pmTracer->traceDetail( detail );
9469 kdebugTrace(kPMLogSleepWakeTracePoint, pmTracer->getTracePhase(), msgType, delay);
9470 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
9471 }
9472}
9473
0a7de745
A
9474void
9475IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
9476{
9477 size_t reportSize;
9478 void **report = NULL;
9479 uint32_t bktCnt;
9480 uint32_t bktSize;
9481 uint32_t *clientCnt;
9482
9483 ASSERT_GATED();
9484
9485 report = NULL;
9486 if (channel_id == kAssertDelayChID) {
9487 report = &assertOnWakeReport;
9488 bktCnt = kAssertDelayBcktCnt;
9489 bktSize = kAssertDelayBcktSize;
9490 clientCnt = &assertOnWakeClientCnt;
9491 } else if (channel_id == kSleepDelaysChID) {
9492 report = &sleepDelaysReport;
9493 bktCnt = kSleepDelaysBcktCnt;
9494 bktSize = kSleepDelaysBcktSize;
9495 clientCnt = &sleepDelaysClientCnt;
f427ee49
A
9496 } else {
9497 assert(false);
9498 return;
0a7de745
A
9499 }
9500
9501 switch (action) {
9502 case kIOReportEnable:
9503
9504 if (*report) {
9505 (*clientCnt)++;
9506 break;
9507 }
9508
9509 reportSize = HISTREPORT_BUFSIZE(bktCnt);
9510 *report = IOMalloc(reportSize);
9511 if (*report == NULL) {
9512 break;
9513 }
9514 bzero(*report, reportSize);
f427ee49 9515 HISTREPORT_INIT((uint16_t)bktCnt, bktSize, *report, reportSize,
0a7de745
A
9516 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
9517
9518 if (channel_id == kAssertDelayChID) {
9519 assertOnWakeSecs = 0;
9520 }
9521
9522 break;
9523
9524 case kIOReportDisable:
9525 if (*clientCnt == 0) {
9526 break;
9527 }
9528 if (*clientCnt == 1) {
9529 IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
9530 *report = NULL;
9531 }
9532 (*clientCnt)--;
9533
9534 if (channel_id == kAssertDelayChID) {
9535 assertOnWakeSecs = -1; // Invalid value to prevent updates
9536 }
9537 break;
9538
9539 case kIOReportGetDimensions:
9540 if (*report) {
9541 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
9542 }
9543 break;
9544 }
b0d623f7 9545
0a7de745 9546 return;
b0d623f7
A
9547}
9548
0a7de745
A
9549IOReturn
9550IOPMrootDomain::configureReport(IOReportChannelList *channelList,
9551 IOReportConfigureAction action,
9552 void *result,
9553 void *destination)
39037602 9554{
0a7de745
A
9555 unsigned cnt;
9556 uint64_t configAction = (uint64_t)action;
9557
9558 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9559 if ((channelList->channels[cnt].channel_id == kSleepCntChID) ||
9560 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
9561 (channelList->channels[cnt].channel_id == kUserWkCntChID)) {
9562 if (action != kIOReportGetDimensions) {
9563 continue;
9564 }
9565 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
9566 } else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
9567 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
9568 gIOPMWorkLoop->runAction(
9569 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
9570 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
9571 (void *)configAction, (void *)result);
9572 }
9573 }
39037602 9574
0a7de745
A
9575 return super::configureReport(channelList, action, result, destination);
9576}
39037602 9577
0a7de745
A
9578IOReturn
9579IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
b0d623f7 9580{
0a7de745
A
9581 uint32_t size2cpy;
9582 void *data2cpy;
9583 void **report;
9584
9585 ASSERT_GATED();
9586
9587 report = NULL;
9588 if (ch_id == kAssertDelayChID) {
9589 report = &assertOnWakeReport;
9590 } else if (ch_id == kSleepDelaysChID) {
9591 report = &sleepDelaysReport;
f427ee49
A
9592 } else {
9593 assert(false);
9594 return kIOReturnBadArgument;
0a7de745
A
9595 }
9596
9597 if (*report == NULL) {
9598 return kIOReturnNotOpen;
9599 }
316670eb 9600
0a7de745
A
9601 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
9602 if (size2cpy > (dest->getCapacity() - dest->getLength())) {
9603 return kIOReturnOverrun;
9604 }
9605
9606 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
9607 dest->appendBytes(data2cpy, size2cpy);
fe8ab488 9608
0a7de745 9609 return kIOReturnSuccess;
6d2010ae
A
9610}
9611
0a7de745
A
9612IOReturn
9613IOPMrootDomain::updateReport(IOReportChannelList *channelList,
9614 IOReportUpdateAction action,
9615 void *result,
9616 void *destination)
6d2010ae 9617{
0a7de745
A
9618 uint32_t size2cpy;
9619 void *data2cpy;
9620 uint8_t buf[SIMPLEREPORT_BUFSIZE];
9621 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
9622 unsigned cnt;
9623 uint64_t ch_id;
d9a64523 9624
0a7de745
A
9625 if (action != kIOReportCopyChannelData) {
9626 goto exit;
9627 }
5ba3f43e 9628
0a7de745
A
9629 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9630 ch_id = channelList->channels[cnt].channel_id;
9631
9632 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
9633 gIOPMWorkLoop->runAction(
9634 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
9635 (OSObject *)this, (void *)ch_id,
9636 (void *)result, (void *)dest);
9637 continue;
9638 } else if ((ch_id == kSleepCntChID) ||
9639 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
9640 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
9641 } else {
9642 continue;
9643 }
5ba3f43e 9644
0a7de745
A
9645 if (ch_id == kSleepCntChID) {
9646 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
9647 } else if (ch_id == kDarkWkCntChID) {
9648 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
9649 } else if (ch_id == kUserWkCntChID) {
9650 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
9651 }
39236c6e 9652
0a7de745
A
9653 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
9654 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
9655 dest->appendBytes(data2cpy, size2cpy);
9656 }
39236c6e
A
9657
9658exit:
0a7de745 9659 return super::updateReport(channelList, action, result, destination);
39236c6e
A
9660}
9661
9662
b0d623f7
A
9663//******************************************************************************
9664// PMTraceWorker Class
9665//
9666//******************************************************************************
9667
9668#undef super
9669#define super OSObject
9670OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
9671
9672#define kPMBestGuessPCIDevicesCount 25
9673#define kPMMaxRTCBitfieldSize 32
9674
f427ee49
A
9675OSPtr<PMTraceWorker>
9676PMTraceWorker::tracer(IOPMrootDomain * owner)
b0d623f7 9677{
f427ee49 9678 OSSharedPtr<PMTraceWorker> me = OSMakeShared<PMTraceWorker>();
0a7de745
A
9679 if (!me || !me->init()) {
9680 return NULL;
9681 }
b0d623f7 9682
f427ee49 9683 DLOG("PMTraceWorker %p\n", OBFUSCATE(me.get()));
b0d623f7 9684
0a7de745
A
9685 // Note that we cannot instantiate the PCI device -> bit mappings here, since
9686 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
9687 // this dictionary lazily.
9688 me->owner = owner;
9689 me->pciDeviceBitMappings = NULL;
9690 me->pmTraceWorkerLock = IOLockAlloc();
9691 me->tracePhase = kIOPMTracePointSystemUp;
9692 me->traceData32 = 0;
9693 me->loginWindowData = 0;
9694 me->coreDisplayData = 0;
9695 me->coreGraphicsData = 0;
9696 return me;
b0d623f7
A
9697}
9698
0a7de745
A
9699void
9700PMTraceWorker::RTC_TRACE(void)
b0d623f7 9701{
0a7de745
A
9702 if (tracePointHandler && tracePointTarget) {
9703 uint32_t wordA;
b0d623f7 9704
0a7de745
A
9705 IOLockLock(pmTraceWorkerLock);
9706 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
9707 (coreGraphicsData << 8) | tracePhase;
9708 IOLockUnlock(pmTraceWorkerLock);
b0d623f7 9709
0a7de745
A
9710 tracePointHandler( tracePointTarget, traceData32, wordA );
9711 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
9712 }
cb323159
A
9713#if DEVELOPMENT || DEBUG
9714 if ((swd_panic_phase != 0) && (swd_panic_phase == tracePhase)) {
9715 DEBUG_LOG("Causing sleep wake failure in phase 0x%08x\n", tracePhase);
9716 IOLock *l = IOLockAlloc();
9717 IOLockLock(l);
9718 IOLockLock(l);
9719 }
9720#endif
b0d623f7
A
9721}
9722
0a7de745
A
9723int
9724PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
b0d623f7 9725{
f427ee49 9726 OSSharedPtr<const OSSymbol> deviceName;
0a7de745 9727 int index = -1;
b0d623f7 9728
0a7de745 9729 IOLockLock(pmTraceWorkerLock);
b0d623f7 9730
0a7de745
A
9731 if (!pciDeviceBitMappings) {
9732 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
9733 if (!pciDeviceBitMappings) {
9734 goto exit;
9735 }
9736 }
b0d623f7 9737
0a7de745
A
9738 // Check for bitmask overflow.
9739 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize) {
9740 goto exit;
9741 }
b0d623f7 9742
0a7de745 9743 if ((deviceName = pciDevice->copyName()) &&
f427ee49
A
9744 (pciDeviceBitMappings->getNextIndexOfObject(deviceName.get(), 0) == (unsigned int)-1) &&
9745 pciDeviceBitMappings->setObject(deviceName.get())) {
0a7de745
A
9746 index = pciDeviceBitMappings->getCount() - 1;
9747 _LOG("PMTrace PCI array: set object %s => %d\n",
9748 deviceName->getCStringNoCopy(), index);
9749 }
f427ee49 9750
0a7de745
A
9751 if (!addedToRegistry && (index >= 0)) {
9752 addedToRegistry = owner->setProperty("PCITopLevel", this);
9753 }
b0d623f7
A
9754
9755exit:
0a7de745
A
9756 IOLockUnlock(pmTraceWorkerLock);
9757 return index;
b0d623f7 9758}
0a7de745
A
9759
9760bool
9761PMTraceWorker::serialize(OSSerialize *s) const
b0d623f7 9762{
0a7de745
A
9763 bool ok = false;
9764 if (pciDeviceBitMappings) {
9765 IOLockLock(pmTraceWorkerLock);
9766 ok = pciDeviceBitMappings->serialize(s);
9767 IOLockUnlock(pmTraceWorkerLock);
9768 }
9769 return ok;
b0d623f7
A
9770}
9771
0a7de745
A
9772void
9773PMTraceWorker::tracePoint(uint8_t phase)
b0d623f7 9774{
0a7de745
A
9775 // clear trace detail when phase begins
9776 if (tracePhase != phase) {
9777 traceData32 = 0;
9778 }
6d2010ae 9779
0a7de745 9780 tracePhase = phase;
6d2010ae 9781
0a7de745
A
9782 DLOG("trace point 0x%02x\n", tracePhase);
9783 RTC_TRACE();
6d2010ae
A
9784}
9785
0a7de745
A
9786void
9787PMTraceWorker::traceDetail(uint32_t detail)
6d2010ae 9788{
0a7de745
A
9789 if (detail == traceData32) {
9790 return;
9791 }
9792 traceData32 = detail;
9793 RTC_TRACE();
9794}
9795
9796void
9797PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
9798{
9799 switch (component) {
9800 case kIOPMLoginWindowProgress:
9801 loginWindowData = data & kIOPMLoginWindowProgressMask;
9802 break;
9803 case kIOPMCoreDisplayProgress:
9804 coreDisplayData = data & kIOPMCoreDisplayProgressMask;
9805 break;
9806 case kIOPMCoreGraphicsProgress:
9807 coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
9808 break;
9809 default:
9810 return;
9811 }
b0d623f7 9812
0a7de745
A
9813 DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
9814 RTC_TRACE();
b0d623f7
A
9815}
9816
0a7de745
A
9817void
9818PMTraceWorker::tracePCIPowerChange(
9819 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
b0d623f7 9820{
0a7de745
A
9821 uint32_t bitMask;
9822 uint32_t expectedFlag;
b0d623f7 9823
0a7de745
A
9824 // Ignore PCI changes outside of system sleep/wake.
9825 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
9826 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase)) {
9827 return;
9828 }
b0d623f7 9829
0a7de745
A
9830 // Only record the WillChange transition when going to sleep,
9831 // and the DidChange on the way up.
9832 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
9833 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
9834 kIOPMDomainWillChange : kIOPMDomainDidChange;
9835 if (changeFlags != expectedFlag) {
9836 return;
9837 }
b0d623f7 9838
0a7de745
A
9839 // Mark this device off in our bitfield
9840 if (bitNum < kPMMaxRTCBitfieldSize) {
9841 bitMask = (1 << bitNum);
b0d623f7 9842
0a7de745
A
9843 if (kPowerChangeStart == type) {
9844 traceData32 |= bitMask;
9845 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
9846 service->getName(), bitNum, bitMask, traceData32);
9847 owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
9848 } else {
9849 traceData32 &= ~bitMask;
9850 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
9851 service->getName(), bitNum, bitMask, traceData32);
9852 owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
9853 }
b0d623f7 9854
0a7de745
A
9855 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
9856 RTC_TRACE();
9857 }
b0d623f7
A
9858}
9859
0a7de745
A
9860uint64_t
9861PMTraceWorker::getPMStatusCode()
39236c6e 9862{
0a7de745 9863 return ((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase);
39236c6e
A
9864}
9865
0a7de745
A
9866uint8_t
9867PMTraceWorker::getTracePhase()
39037602 9868{
0a7de745 9869 return tracePhase;
39037602
A
9870}
9871
0a7de745
A
9872uint32_t
9873PMTraceWorker::getTraceData()
39037602 9874{
0a7de745 9875 return traceData32;
39037602
A
9876}
9877
6d2010ae
A
9878// MARK: -
9879// MARK: PMHaltWorker
b0d623f7
A
9880
9881//******************************************************************************
2d21ac55
A
9882// PMHaltWorker Class
9883//
b0d623f7 9884//******************************************************************************
2d21ac55 9885
0a7de745
A
9886PMHaltWorker *
9887PMHaltWorker::worker( void )
9888{
9889 PMHaltWorker * me;
9890 IOThread thread;
9891
9892 do {
9893 me = OSTypeAlloc( PMHaltWorker );
9894 if (!me || !me->init()) {
9895 break;
9896 }
9897
9898 me->lock = IOLockAlloc();
9899 if (!me->lock) {
9900 break;
9901 }
9902
9903 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
9904 me->retain(); // thread holds extra retain
9905 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread)) {
9906 me->release();
9907 break;
9908 }
9909 thread_deallocate(thread);
9910 return me;
9911 } while (false);
9912
9913 if (me) {
9914 me->release();
9915 }
cb323159 9916 return NULL;
0a7de745
A
9917}
9918
9919void
9920PMHaltWorker::free( void )
9921{
9922 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
9923 if (lock) {
9924 IOLockFree(lock);
cb323159 9925 lock = NULL;
0a7de745
A
9926 }
9927 return OSObject::free();
9928}
9929
9930void
9931PMHaltWorker::main( void * arg, wait_result_t waitResult )
9932{
9933 PMHaltWorker * me = (PMHaltWorker *) arg;
9934
9935 IOLockLock( gPMHaltLock );
9936 gPMHaltBusyCount++;
9937 me->depth = gPMHaltDepth;
9938 IOLockUnlock( gPMHaltLock );
9939
9940 while (me->depth >= 0) {
9941 PMHaltWorker::work( me );
9942
9943 IOLockLock( gPMHaltLock );
9944 if (++gPMHaltIdleCount >= gPMHaltBusyCount) {
9945 // This is the last thread to finish work on this level,
9946 // inform everyone to start working on next lower level.
9947 gPMHaltDepth--;
9948 me->depth = gPMHaltDepth;
9949 gPMHaltIdleCount = 0;
9950 thread_wakeup((event_t) &gPMHaltIdleCount);
9951 } else {
9952 // One or more threads are still working on this level,
9953 // this thread must wait.
9954 me->depth = gPMHaltDepth - 1;
9955 do {
9956 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
9957 } while (me->depth != gPMHaltDepth);
9958 }
9959 IOLockUnlock( gPMHaltLock );
9960 }
9961
9962 // No more work to do, terminate thread
9963 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
9964 thread_wakeup( &gPMHaltDepth );
9965 me->release();
9966}
9967
9968void
9969PMHaltWorker::work( PMHaltWorker * me )
9970{
f427ee49 9971 OSSharedPtr<IOService> service;
0a7de745
A
9972 OSSet * inner;
9973 AbsoluteTime startTime, elapsedTime;
9974 UInt32 deltaTime;
9975 bool timeout;
9976
9977 while (true) {
0a7de745
A
9978 timeout = false;
9979
9980 // Claim an unit of work from the shared pool
9981 IOLockLock( gPMHaltLock );
9982 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
9983 if (inner) {
f427ee49 9984 service.reset(OSDynamicCast(IOService, inner->getAnyObject()), OSRetain);
0a7de745 9985 if (service) {
f427ee49 9986 inner->removeObject(service.get());
0a7de745
A
9987 }
9988 }
9989 IOLockUnlock( gPMHaltLock );
9990 if (!service) {
9991 break; // no more work at this depth
9992 }
9993 clock_get_uptime(&startTime);
9994
9995 if (!service->isInactive() &&
f427ee49 9996 service->setProperty(gPMHaltClientAcknowledgeKey.get(), me)) {
0a7de745
A
9997 IOLockLock(me->lock);
9998 me->startTime = startTime;
f427ee49 9999 me->service = service.get();
0a7de745
A
10000 me->timeout = false;
10001 IOLockUnlock(me->lock);
10002
f427ee49 10003 service->systemWillShutdown( gPMHaltMessageType);
0a7de745
A
10004
10005 // Wait for driver acknowledgement
10006 IOLockLock(me->lock);
f427ee49 10007 while (service->propertyExists(gPMHaltClientAcknowledgeKey.get())) {
0a7de745
A
10008 IOLockSleep(me->lock, me, THREAD_UNINT);
10009 }
cb323159 10010 me->service = NULL;
0a7de745
A
10011 timeout = me->timeout;
10012 IOLockUnlock(me->lock);
10013 }
10014
10015 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
10016 if ((deltaTime > kPMHaltTimeoutMS) || timeout) {
10017 LOG("%s driver %s (0x%llx) took %u ms\n",
10018 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
10019 "PowerOff" : "Restart",
10020 service->getName(), service->getRegistryEntryID(),
10021 (uint32_t) deltaTime );
10022 halt_log_enter("PowerOff/Restart handler completed",
f427ee49 10023 OSMemberFunctionCast(const void *, service.get(), &IOService::systemWillShutdown),
0a7de745
A
10024 elapsedTime);
10025 }
10026
0a7de745
A
10027 me->visits++;
10028 }
10029}
10030
10031void
10032PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
10033{
10034 UInt64 nano;
10035 AbsoluteTime startTime;
10036 AbsoluteTime endTime;
10037
10038 endTime = *now;
10039
10040 IOLockLock(me->lock);
10041 if (me->service && !me->timeout) {
10042 startTime = me->startTime;
10043 nano = 0;
10044 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
10045 SUB_ABSOLUTETIME(&endTime, &startTime);
10046 absolutetime_to_nanoseconds(endTime, &nano);
10047 }
10048 if (nano > 3000000000ULL) {
10049 me->timeout = true;
10050
10051 halt_log_enter("PowerOff/Restart still waiting on handler",
10052 OSMemberFunctionCast(const void *, me->service, &IOService::systemWillShutdown),
10053 endTime);
10054 MSG("%s still waiting on %s\n",
10055 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
10056 me->service->getName());
10057 }
10058 }
10059 IOLockUnlock(me->lock);
2d21ac55
A
10060}
10061
b0d623f7 10062//******************************************************************************
2d21ac55
A
10063// acknowledgeSystemWillShutdown
10064//
10065// Acknowledgement from drivers that they have prepared for shutdown/restart.
b0d623f7 10066//******************************************************************************
2d21ac55 10067
0a7de745
A
10068void
10069IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
2d21ac55 10070{
f427ee49
A
10071 PMHaltWorker * worker;
10072 OSSharedPtr<OSObject> prop;
fe8ab488 10073
0a7de745
A
10074 if (!from) {
10075 return;
10076 }
fe8ab488 10077
0a7de745 10078 //DLOG("%s acknowledged\n", from->getName());
f427ee49 10079 prop = from->copyProperty( gPMHaltClientAcknowledgeKey.get());
0a7de745 10080 if (prop) {
f427ee49 10081 worker = (PMHaltWorker *) prop.get();
0a7de745 10082 IOLockLock(worker->lock);
f427ee49 10083 from->removeProperty( gPMHaltClientAcknowledgeKey.get());
0a7de745
A
10084 thread_wakeup((event_t) worker);
10085 IOLockUnlock(worker->lock);
0a7de745
A
10086 } else {
10087 DLOG("%s acknowledged without worker property\n",
10088 from->getName());
10089 }
2d21ac55
A
10090}
10091
b0d623f7
A
10092
10093//******************************************************************************
2d21ac55
A
10094// notifySystemShutdown
10095//
10096// Notify all objects in PM tree that system will shutdown or restart
b0d623f7 10097//******************************************************************************
2d21ac55
A
10098
10099static void
3e170ce0 10100notifySystemShutdown( IOService * root, uint32_t messageType )
2d21ac55 10101{
f427ee49
A
10102#define PLACEHOLDER ((OSSet *)gPMHaltArray.get())
10103 OSSharedPtr<IORegistryIterator> iter;
10104 IORegistryEntry * entry;
10105 IOService * node;
10106 OSSet * inner;
10107 OSSharedPtr<OSSet> newInner;
10108 PMHaltWorker * workers[kPMHaltMaxWorkers];
10109 AbsoluteTime deadline;
10110 unsigned int totalNodes = 0;
10111 unsigned int depth;
10112 unsigned int rootDepth;
10113 unsigned int numWorkers;
10114 unsigned int count;
10115 int waitResult;
10116 void * baseFunc;
10117 bool ok;
0a7de745
A
10118
10119 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
10120
10121 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
10122
10123 // Iterate the entire PM tree starting from root
10124
10125 rootDepth = root->getDepth( gIOPowerPlane );
10126 if (!rootDepth) {
10127 goto done;
10128 }
10129
10130 // debug - for repeated test runs
10131 while (PMHaltWorker::metaClass->getInstanceCount()) {
10132 IOSleep(1);
10133 }
10134
10135 if (!gPMHaltArray) {
10136 gPMHaltArray = OSArray::withCapacity(40);
10137 if (!gPMHaltArray) {
10138 goto done;
10139 }
10140 } else { // debug
10141 gPMHaltArray->flushCollection();
10142 }
10143
10144 if (!gPMHaltLock) {
10145 gPMHaltLock = IOLockAlloc();
10146 if (!gPMHaltLock) {
10147 goto done;
10148 }
10149 }
10150
10151 if (!gPMHaltClientAcknowledgeKey) {
10152 gPMHaltClientAcknowledgeKey =
10153 OSSymbol::withCStringNoCopy("PMShutdown");
10154 if (!gPMHaltClientAcknowledgeKey) {
10155 goto done;
10156 }
10157 }
10158
10159 gPMHaltMessageType = messageType;
10160
10161 // Depth-first walk of PM plane
10162
10163 iter = IORegistryIterator::iterateOver(
10164 root, gIOPowerPlane, kIORegistryIterateRecursively);
10165
10166 if (iter) {
10167 while ((entry = iter->getNextObject())) {
10168 node = OSDynamicCast(IOService, entry);
10169 if (!node) {
10170 continue;
10171 }
10172
10173 if (baseFunc ==
10174 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown)) {
10175 continue;
10176 }
10177
10178 depth = node->getDepth( gIOPowerPlane );
10179 if (depth <= rootDepth) {
10180 continue;
10181 }
10182
10183 ok = false;
10184
10185 // adjust to zero based depth
10186 depth -= (rootDepth + 1);
10187
10188 // gPMHaltArray is an array of containers, each container
10189 // refers to nodes with the same depth.
10190
10191 count = gPMHaltArray->getCount();
10192 while (depth >= count) {
10193 // expand array and insert placeholders
10194 gPMHaltArray->setObject(PLACEHOLDER);
10195 count++;
10196 }
10197 count = gPMHaltArray->getCount();
10198 if (depth < count) {
10199 inner = (OSSet *)gPMHaltArray->getObject(depth);
10200 if (inner == PLACEHOLDER) {
f427ee49
A
10201 newInner = OSSet::withCapacity(40);
10202 if (newInner) {
10203 gPMHaltArray->replaceObject(depth, newInner.get());
10204 inner = newInner.get();
0a7de745
A
10205 }
10206 }
10207
10208 // PM nodes that appear more than once in the tree will have
10209 // the same depth, OSSet will refuse to add the node twice.
10210 if (inner) {
10211 ok = inner->setObject(node);
10212 }
10213 }
10214 if (!ok) {
10215 DLOG("Skipped PM node %s\n", node->getName());
10216 }
10217 }
0a7de745
A
10218 }
10219
10220 // debug only
10221 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++) {
10222 count = 0;
10223 if (inner != PLACEHOLDER) {
10224 count = inner->getCount();
10225 }
10226 DLOG("Nodes at depth %u = %u\n", i, count);
10227 }
10228
10229 // strip placeholders (not all depths are populated)
10230 numWorkers = 0;
10231 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i));) {
10232 if (inner == PLACEHOLDER) {
10233 gPMHaltArray->removeObject(i);
10234 continue;
10235 }
10236 count = inner->getCount();
10237 if (count > numWorkers) {
10238 numWorkers = count;
10239 }
10240 totalNodes += count;
10241 i++;
10242 }
10243
10244 if (gPMHaltArray->getCount() == 0 || !numWorkers) {
10245 goto done;
10246 }
10247
10248 gPMHaltBusyCount = 0;
10249 gPMHaltIdleCount = 0;
10250 gPMHaltDepth = gPMHaltArray->getCount() - 1;
10251
10252 // Create multiple workers (and threads)
10253
10254 if (numWorkers > kPMHaltMaxWorkers) {
10255 numWorkers = kPMHaltMaxWorkers;
10256 }
10257
10258 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
10259 totalNodes, gPMHaltArray->getCount(), numWorkers);
10260
10261 for (unsigned int i = 0; i < numWorkers; i++) {
10262 workers[i] = PMHaltWorker::worker();
10263 }
10264
10265 // Wait for workers to exhaust all available work
10266
10267 IOLockLock(gPMHaltLock);
10268 while (gPMHaltDepth >= 0) {
10269 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
10270
10271 waitResult = IOLockSleepDeadline(
10272 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
10273 if (THREAD_TIMED_OUT == waitResult) {
10274 AbsoluteTime now;
10275 clock_get_uptime(&now);
10276
10277 IOLockUnlock(gPMHaltLock);
10278 for (unsigned int i = 0; i < numWorkers; i++) {
10279 if (workers[i]) {
10280 PMHaltWorker::checkTimeout(workers[i], &now);
10281 }
10282 }
10283 IOLockLock(gPMHaltLock);
10284 }
10285 }
10286 IOLockUnlock(gPMHaltLock);
10287
10288 // Release all workers
10289
10290 for (unsigned int i = 0; i < numWorkers; i++) {
10291 if (workers[i]) {
10292 workers[i]->release();
10293 }
10294 // worker also retained by it's own thread
10295 }
2d21ac55 10296
fe8ab488 10297done:
0a7de745
A
10298 DLOG("%s done\n", __FUNCTION__);
10299 return;
2d21ac55
A
10300}
10301
39236c6e
A
10302// MARK: -
10303// MARK: Kernel Assertion
10304
0b4c1975
A
10305/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10306
0a7de745
A
10307IOPMDriverAssertionID
10308IOPMrootDomain::createPMAssertion(
10309 IOPMDriverAssertionType whichAssertionBits,
10310 IOPMDriverAssertionLevel assertionLevel,
10311 IOService *ownerService,
10312 const char *ownerDescription)
0b4c1975 10313{
0a7de745
A
10314 IOReturn ret;
10315 IOPMDriverAssertionID newAssertion;
fe8ab488 10316
0a7de745
A
10317 if (!pmAssertions) {
10318 return 0;
10319 }
fe8ab488 10320
0a7de745 10321 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
0b4c1975 10322
0a7de745
A
10323 if (kIOReturnSuccess == ret) {
10324 return newAssertion;
10325 } else {
10326 return 0;
10327 }
0b4c1975
A
10328}
10329
0a7de745
A
10330IOReturn
10331IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
0b4c1975 10332{
0a7de745
A
10333 if (!pmAssertions) {
10334 return kIOReturnInternalError;
10335 }
fe8ab488 10336
0a7de745 10337 return pmAssertions->releaseAssertion(releaseAssertion);
0b4c1975
A
10338}
10339
fe8ab488 10340
0a7de745
A
10341IOReturn
10342IOPMrootDomain::setPMAssertionLevel(
10343 IOPMDriverAssertionID assertionID,
10344 IOPMDriverAssertionLevel assertionLevel)
0b4c1975 10345{
0a7de745 10346 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
0b4c1975
A
10347}
10348
0a7de745
A
10349IOPMDriverAssertionLevel
10350IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
0b4c1975 10351{
0a7de745 10352 IOPMDriverAssertionType sysLevels;
0b4c1975 10353
0a7de745
A
10354 if (!pmAssertions || whichAssertion == 0) {
10355 return kIOPMDriverAssertionLevelOff;
10356 }
0b4c1975 10357
0a7de745 10358 sysLevels = pmAssertions->getActivatedAssertions();
fe8ab488 10359
0a7de745
A
10360 // Check that every bit set in argument 'whichAssertion' is asserted
10361 // in the aggregate bits.
10362 if ((sysLevels & whichAssertion) == whichAssertion) {
10363 return kIOPMDriverAssertionLevelOn;
10364 } else {
10365 return kIOPMDriverAssertionLevelOff;
10366 }
0b4c1975
A
10367}
10368
0a7de745
A
10369IOReturn
10370IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
0b4c1975 10371{
0a7de745
A
10372 if (!pmAssertions) {
10373 return kIOReturnNotFound;
10374 }
0b4c1975 10375
0a7de745 10376 return pmAssertions->setUserAssertionLevels(inLevels);
0b4c1975
A
10377}
10378
0a7de745
A
10379bool
10380IOPMrootDomain::serializeProperties( OSSerialize * s ) const
0b4c1975 10381{
0a7de745
A
10382 if (pmAssertions) {
10383 pmAssertions->publishProperties();
10384 }
10385 return IOService::serializeProperties(s);
0b4c1975 10386}
2d21ac55 10387
f427ee49 10388OSSharedPtr<OSObject>
0a7de745 10389IOPMrootDomain::copyProperty( const char * aKey) const
39236c6e 10390{
f427ee49 10391 OSSharedPtr<OSObject> obj;
0a7de745 10392 obj = IOService::copyProperty(aKey);
39236c6e 10393
0a7de745
A
10394 if (obj) {
10395 return obj;
10396 }
10397
10398 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
10399 sizeof(kIOPMSleepWakeWdogRebootKey))) {
10400 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
f427ee49 10401 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
0a7de745 10402 } else {
f427ee49 10403 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
0a7de745
A
10404 }
10405 }
10406
10407 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
10408 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
10409 if (swd_flags & SWD_VALID_LOGS) {
f427ee49 10410 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
0a7de745 10411 } else {
f427ee49 10412 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
0a7de745
A
10413 }
10414 }
39236c6e 10415
0a7de745
A
10416 /*
10417 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
10418 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
10419 * issued by DisplayWrangler on darkwake.
10420 */
10421 if (!strcmp(aKey, "DesktopMode")) {
10422 if (desktopMode) {
f427ee49 10423 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
0a7de745 10424 } else {
f427ee49 10425 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
0a7de745
A
10426 }
10427 }
10428 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
10429 if (displayIdleForDemandSleep) {
f427ee49 10430 return OSSharedPtr<OSBoolean>(kOSBooleanTrue, OSNoRetain);
0a7de745 10431 } else {
f427ee49 10432 return OSSharedPtr<OSBoolean>(kOSBooleanFalse, OSNoRetain);
0a7de745
A
10433 }
10434 }
fe8ab488 10435
0a7de745 10436 if (!strcmp(aKey, kIOPMDriverWakeEventsKey)) {
f427ee49 10437 OSSharedPtr<OSArray> array;
0a7de745
A
10438 WAKEEVENT_LOCK();
10439 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
f427ee49
A
10440 OSSharedPtr<OSCollection> collection = _systemWakeEventsArray->copyCollection();
10441 if (collection) {
10442 array = OSDynamicPtrCast<OSArray>(collection);
0a7de745
A
10443 }
10444 }
10445 WAKEEVENT_UNLOCK();
f427ee49 10446 return os::move(array);
0a7de745 10447 }
39236c6e 10448
0a7de745 10449 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey)) {
f427ee49 10450 OSSharedPtr<OSArray> array;
0a7de745
A
10451 IOLockLock(pmStatsLock);
10452 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
f427ee49
A
10453 OSSharedPtr<OSCollection> collection = pmStatsAppResponses->copyCollection();
10454 if (collection) {
10455 array = OSDynamicPtrCast<OSArray>(collection);
0a7de745 10456 }
0a7de745
A
10457 }
10458 IOLockUnlock(pmStatsLock);
f427ee49 10459 return os::move(array);
0a7de745 10460 }
fe8ab488 10461
0a7de745
A
10462 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey)) {
10463 OSArray *idleSleepList = NULL;
10464 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
f427ee49 10465 return OSSharedPtr<OSArray>(idleSleepList, OSNoRetain);
0a7de745 10466 }
39236c6e 10467
0a7de745
A
10468 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey)) {
10469 OSArray *systemSleepList = NULL;
10470 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
f427ee49 10471 return OSSharedPtr<OSArray>(systemSleepList, OSNoRetain);
0a7de745 10472 }
fe8ab488 10473
cb323159
A
10474 if (!strcmp(aKey, kIOPMIdleSleepPreventersWithIDKey)) {
10475 OSArray *idleSleepList = NULL;
10476 gRootDomain->copySleepPreventersListWithID(&idleSleepList, NULL);
f427ee49 10477 return OSSharedPtr<OSArray>(idleSleepList, OSNoRetain);
cb323159
A
10478 }
10479
10480 if (!strcmp(aKey, kIOPMSystemSleepPreventersWithIDKey)) {
10481 OSArray *systemSleepList = NULL;
10482 gRootDomain->copySleepPreventersListWithID(NULL, &systemSleepList);
f427ee49 10483 return OSSharedPtr<OSArray>(systemSleepList, OSNoRetain);
cb323159 10484 }
0a7de745 10485 return NULL;
fe8ab488
A
10486}
10487
10488// MARK: -
10489// MARK: Wake Event Reporting
10490
0a7de745
A
10491void
10492IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
fe8ab488 10493{
0a7de745
A
10494 WAKEEVENT_LOCK();
10495 strlcpy(outBuf, gWakeReasonString, bufSize);
10496 WAKEEVENT_UNLOCK();
fe8ab488
A
10497}
10498
f427ee49
A
10499void
10500IOPMrootDomain::copyShutdownReasonString( char * outBuf, size_t bufSize )
10501{
10502 WAKEEVENT_LOCK();
10503 strlcpy(outBuf, gShutdownReasonString, bufSize);
10504 WAKEEVENT_UNLOCK();
10505}
10506
fe8ab488
A
10507//******************************************************************************
10508// acceptSystemWakeEvents
10509//
10510// Private control for the acceptance of driver wake event claims.
10511//******************************************************************************
10512
0a7de745 10513void
f427ee49 10514IOPMrootDomain::acceptSystemWakeEvents( uint32_t control )
fe8ab488 10515{
0a7de745 10516 bool logWakeReason = false;
fe8ab488 10517
0a7de745 10518 WAKEEVENT_LOCK();
f427ee49
A
10519 switch (control) {
10520 case kAcceptSystemWakeEvents_Enable:
10521 assert(_acceptSystemWakeEvents == false);
0a7de745
A
10522 if (!_systemWakeEventsArray) {
10523 _systemWakeEventsArray = OSArray::withCapacity(4);
10524 }
cb323159 10525 _acceptSystemWakeEvents = (_systemWakeEventsArray != NULL);
ea3f0419 10526 if (!(_aotNow && (kIOPMWakeEventAOTExitFlags & _aotPendingFlags))) {
cb323159
A
10527 gWakeReasonString[0] = '\0';
10528 if (_systemWakeEventsArray) {
10529 _systemWakeEventsArray->flushCollection();
10530 }
0a7de745 10531 }
f427ee49
A
10532
10533 // Remove stale WakeType property before system sleep
10534 removeProperty(kIOPMRootDomainWakeTypeKey);
10535 removeProperty(kIOPMRootDomainWakeReasonKey);
10536 break;
10537
10538 case kAcceptSystemWakeEvents_Disable:
0a7de745 10539 _acceptSystemWakeEvents = false;
f427ee49
A
10540#if defined(XNU_TARGET_OS_OSX)
10541 logWakeReason = (gWakeReasonString[0] != '\0');
10542#else /* !defined(XNU_TARGET_OS_OSX) */
0a7de745 10543 logWakeReason = gWakeReasonSysctlRegistered;
5ba3f43e 10544#if DEVELOPMENT
0a7de745
A
10545 static int panic_allowed = -1;
10546
10547 if ((panic_allowed == -1) &&
10548 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed, sizeof(panic_allowed)) == false)) {
cb323159 10549 panic_allowed = 0;
0a7de745
A
10550 }
10551
10552 if (panic_allowed) {
10553 size_t i = 0;
10554 // Panic if wake reason is null or empty
10555 for (i = 0; (i < strlen(gWakeReasonString)); i++) {
10556 if ((gWakeReasonString[i] != ' ') && (gWakeReasonString[i] != '\t')) {
10557 break;
10558 }
10559 }
10560 if (i >= strlen(gWakeReasonString)) {
10561 panic("Wake reason is empty\n");
10562 }
10563 }
f427ee49
A
10564#endif /* DEVELOPMENT */
10565#endif /* !defined(XNU_TARGET_OS_OSX) */
10566
10567 // publish kIOPMRootDomainWakeReasonKey if not already set
10568 if (!propertyExists(kIOPMRootDomainWakeReasonKey)) {
10569 setProperty(kIOPMRootDomainWakeReasonKey, gWakeReasonString);
10570 }
10571 break;
10572
10573 case kAcceptSystemWakeEvents_Reenable:
10574 assert(_acceptSystemWakeEvents == false);
10575 _acceptSystemWakeEvents = (_systemWakeEventsArray != NULL);
10576 removeProperty(kIOPMRootDomainWakeReasonKey);
10577 break;
0a7de745
A
10578 }
10579 WAKEEVENT_UNLOCK();
fe8ab488 10580
0a7de745 10581 if (logWakeReason) {
f427ee49 10582 MSG("system wake events: %s\n", gWakeReasonString);
0a7de745 10583 }
fe8ab488
A
10584}
10585
10586//******************************************************************************
10587// claimSystemWakeEvent
10588//
10589// For a driver to claim a device is the source/conduit of a system wake event.
10590//******************************************************************************
10591
0a7de745
A
10592void
10593IOPMrootDomain::claimSystemWakeEvent(
10594 IOService * device,
10595 IOOptionBits flags,
10596 const char * reason,
10597 OSObject * details )
10598{
f427ee49
A
10599 OSSharedPtr<const OSSymbol> deviceName;
10600 OSSharedPtr<OSNumber> deviceRegId;
10601 OSSharedPtr<OSNumber> claimTime;
10602 OSSharedPtr<OSData> flagsData;
10603 OSSharedPtr<OSString> reasonString;
10604 OSSharedPtr<OSDictionary> dict;
10605 uint64_t timestamp;
10606 bool addWakeReason;
0a7de745
A
10607
10608 if (!device || !reason) {
10609 return;
10610 }
10611
f427ee49
A
10612 pmEventTimeStamp(&timestamp);
10613
cb323159
A
10614 IOOptionBits aotFlags = 0;
10615 bool needAOTEvaluate = FALSE;
10616
10617 if (kIOPMAOTModeAddEventFlags & _aotMode) {
10618 if (!strcmp("hold", reason)
10619 || !strcmp("help", reason)
10620 || !strcmp("menu", reason)
10621 || !strcmp("stockholm", reason)
10622 || !strcmp("ringer", reason)
10623 || !strcmp("ringerab", reason)
10624 || !strcmp("smc0", reason)
10625 || !strcmp("AOP.RTPWakeupAP", reason)
10626 || !strcmp("BT.OutboxNotEmpty", reason)
10627 || !strcmp("WL.OutboxNotEmpty", reason)) {
10628 flags |= kIOPMWakeEventAOTExit;
10629 }
10630 }
10631
10632#if DEVELOPMENT || DEBUG
10633 if (_aotLingerTime && !strcmp("rtc", reason)) {
10634 flags |= kIOPMWakeEventAOTPossibleExit;
10635 }
10636#endif /* DEVELOPMENT || DEBUG */
cb323159 10637
f427ee49
A
10638#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
10639 // Publishing the WakeType is serialized by the PM work loop
10640 if (!strcmp("rtc", reason) && (_nextScheduledAlarmType != NULL)) {
10641 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishWakeType,
10642 (void *) _nextScheduledAlarmType.get());
10643 }
10644
10645 // Workaround for the missing wake HID event
10646 if (gDarkWakeFlags & kDarkWakeFlagUserWakeWorkaround) {
10647 if (!strcmp("trackpadkeyboard", reason)) {
10648 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishWakeType,
10649 (void *) gIOPMWakeTypeUserKey.get());
10650 }
10651 }
10652#endif
10653
0a7de745
A
10654 deviceName = device->copyName(gIOServicePlane);
10655 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
10656 claimTime = OSNumber::withNumber(timestamp, 64);
10657 flagsData = OSData::withBytes(&flags, sizeof(flags));
10658 reasonString = OSString::withCString(reason);
f427ee49
A
10659 dict = OSDictionary::withCapacity(5 + (details ? 1 : 0));
10660 if (!dict || !deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString) {
0a7de745
A
10661 goto done;
10662 }
10663
f427ee49
A
10664 dict->setObject(gIONameKey, deviceName.get());
10665 dict->setObject(gIORegistryEntryIDKey, deviceRegId.get());
10666 dict->setObject(kIOPMWakeEventTimeKey, claimTime.get());
10667 dict->setObject(kIOPMWakeEventFlagsKey, flagsData.get());
10668 dict->setObject(kIOPMWakeEventReasonKey, reasonString.get());
0a7de745 10669 if (details) {
f427ee49 10670 dict->setObject(kIOPMWakeEventDetailsKey, details);
0a7de745
A
10671 }
10672
10673 WAKEEVENT_LOCK();
cb323159 10674 addWakeReason = _acceptSystemWakeEvents;
cb323159
A
10675 if (_aotMode) {
10676 IOLog("claimSystemWakeEvent(%s, %s, 0x%x) 0x%x %d\n", reason, deviceName->getCStringNoCopy(), (int)flags, _aotPendingFlags, _aotReadyToFullWake);
10677 }
10678 aotFlags = (kIOPMWakeEventAOTFlags & flags);
10679 aotFlags = (aotFlags & ~_aotPendingFlags);
10680 needAOTEvaluate = false;
10681 if (_aotNow && aotFlags) {
10682 if (kIOPMWakeEventAOTPossibleExit & flags) {
10683 _aotMetrics->possibleCount++;
10684 }
10685 if (kIOPMWakeEventAOTConfirmedPossibleExit & flags) {
10686 _aotMetrics->confirmedPossibleCount++;
10687 }
10688 if (kIOPMWakeEventAOTRejectedPossibleExit & flags) {
10689 _aotMetrics->rejectedPossibleCount++;
10690 }
10691 if (kIOPMWakeEventAOTExpiredPossibleExit & flags) {
10692 _aotMetrics->expiredPossibleCount++;
10693 }
10694
10695 _aotPendingFlags |= aotFlags;
10696 addWakeReason = _aotNow && _systemWakeEventsArray && ((kIOPMWakeEventAOTExitFlags & aotFlags));
10697 needAOTEvaluate = _aotReadyToFullWake;
10698 }
f427ee49
A
10699 DMSG("claimSystemWakeEvent(%s, 0x%x, %s, 0x%llx) aot %d phase 0x%x add %d\n",
10700 reason, (int)flags, deviceName->getCStringNoCopy(), device->getRegistryEntryID(),
10701 _aotNow, pmTracer->getTracePhase(), addWakeReason);
cb323159 10702
0a7de745
A
10703 if (!gWakeReasonSysctlRegistered) {
10704 // Lazy registration until the platform driver stops registering
10705 // the same name.
10706 gWakeReasonSysctlRegistered = true;
0a7de745 10707 }
cb323159 10708 if (addWakeReason) {
f427ee49 10709 _systemWakeEventsArray->setObject(dict.get());
0a7de745
A
10710 if (gWakeReasonString[0] != '\0') {
10711 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
10712 }
10713 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
10714 }
cb323159 10715
0a7de745 10716 WAKEEVENT_UNLOCK();
cb323159 10717 if (needAOTEvaluate) {
f427ee49
A
10718 // Call aotEvaluate() on PM work loop since it may call
10719 // aotExit() which accesses PM state.
10720 pmPowerStateQueue->submitPowerEvent(kPowerEventAOTEvaluate);
cb323159 10721 }
39236c6e 10722
fe8ab488 10723done:
f427ee49
A
10724 return;
10725}
10726
10727//******************************************************************************
10728// claimSystemBootEvent
10729//
10730// For a driver to claim a device is the source/conduit of a system boot event.
10731//******************************************************************************
10732
10733void
10734IOPMrootDomain::claimSystemBootEvent(
10735 IOService * device,
10736 IOOptionBits flags,
10737 const char * reason,
10738 __unused OSObject * details )
10739{
10740 if (!device || !reason) {
10741 return;
0a7de745 10742 }
f427ee49
A
10743
10744 DEBUG_LOG("claimSystemBootEvent(%s, %s, 0x%x)\n", reason, device->getName(), (uint32_t) flags);
10745 WAKEEVENT_LOCK();
10746 if (!gBootReasonSysctlRegistered) {
10747 // Lazy sysctl registration after setting gBootReasonString
10748 strlcat(gBootReasonString, reason, sizeof(gBootReasonString));
c3c9b80d 10749 os_atomic_store(&gBootReasonSysctlRegistered, true, release);
0a7de745 10750 }
f427ee49
A
10751 WAKEEVENT_UNLOCK();
10752}
10753
10754//******************************************************************************
10755// claimSystemShutdownEvent
10756//
10757// For drivers to claim a system shutdown event on the ensuing boot.
10758//******************************************************************************
10759
10760void
10761IOPMrootDomain::claimSystemShutdownEvent(
10762 IOService * device,
10763 IOOptionBits flags,
10764 const char * reason,
10765 __unused OSObject * details )
10766{
10767 if (!device || !reason) {
10768 return;
0a7de745 10769 }
f427ee49
A
10770
10771 DEBUG_LOG("claimSystemShutdownEvent(%s, %s, 0x%x)\n", reason, device->getName(), (uint32_t) flags);
10772 WAKEEVENT_LOCK();
10773 if (gShutdownReasonString[0] != '\0') {
10774 strlcat(gShutdownReasonString, " ", sizeof(gShutdownReasonString));
0a7de745 10775 }
f427ee49
A
10776 strlcat(gShutdownReasonString, reason, sizeof(gShutdownReasonString));
10777
c3c9b80d 10778 gShutdownReasonSysctlRegistered = true;
f427ee49 10779 WAKEEVENT_UNLOCK();
39236c6e
A
10780}
10781
0c530ab8
A
10782/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10783
6d2010ae
A
10784// MARK: -
10785// MARK: PMSettingHandle
0c530ab8 10786
6d2010ae 10787OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
0c530ab8 10788
0a7de745
A
10789void
10790PMSettingHandle::free( void )
0c530ab8 10791{
0a7de745
A
10792 if (pmso) {
10793 pmso->clientHandleFreed();
10794 pmso->release();
cb323159 10795 pmso = NULL;
0a7de745 10796 }
6d2010ae 10797
0a7de745 10798 OSObject::free();
0c530ab8
A
10799}
10800
6d2010ae
A
10801// MARK: -
10802// MARK: PMSettingObject
10803
10804#undef super
10805#define super OSObject
10806OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
10807
fe8ab488 10808/*
0c530ab8
A
10809 * Static constructor/initializer for PMSettingObject
10810 */
10811PMSettingObject *PMSettingObject::pmSettingObject(
0a7de745
A
10812 IOPMrootDomain * parent_arg,
10813 IOPMSettingControllerCallback handler_arg,
10814 OSObject * target_arg,
10815 uintptr_t refcon_arg,
10816 uint32_t supportedPowerSources,
10817 const OSSymbol * settings[],
10818 OSObject * *handle_obj)
10819{
10820 uint32_t settingCount = 0;
cb323159
A
10821 PMSettingObject *pmso = NULL;
10822 PMSettingHandle *pmsh = NULL;
0a7de745
A
10823
10824 if (!parent_arg || !handler_arg || !settings || !handle_obj) {
10825 return NULL;
10826 }
10827
10828 // count OSSymbol entries in NULL terminated settings array
10829 while (settings[settingCount]) {
10830 settingCount++;
10831 }
10832 if (0 == settingCount) {
10833 return NULL;
10834 }
10835
10836 pmso = new PMSettingObject;
10837 if (!pmso || !pmso->init()) {
10838 goto fail;
10839 }
10840
10841 pmsh = new PMSettingHandle;
10842 if (!pmsh || !pmsh->init()) {
10843 goto fail;
10844 }
10845
10846 queue_init(&pmso->calloutQueue);
10847 pmso->parent = parent_arg;
10848 pmso->func = handler_arg;
10849 pmso->target = target_arg;
10850 pmso->refcon = refcon_arg;
10851 pmso->settingCount = settingCount;
10852
10853 pmso->retain(); // handle holds a retain on pmso
10854 pmsh->pmso = pmso;
10855 pmso->pmsh = pmsh;
10856
10857 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t) * settingCount);
10858 if (pmso->publishedFeatureID) {
10859 for (unsigned int i = 0; i < settingCount; i++) {
10860 // Since there is now at least one listener to this setting, publish
10861 // PM root domain support for it.
10862 parent_arg->publishPMSetting( settings[i],
10863 supportedPowerSources, &pmso->publishedFeatureID[i] );
10864 }
10865 }
10866
10867 *handle_obj = pmsh;
10868 return pmso;
6d2010ae
A
10869
10870fail:
0a7de745
A
10871 if (pmso) {
10872 pmso->release();
10873 }
10874 if (pmsh) {
10875 pmsh->release();
10876 }
10877 return NULL;
0c530ab8
A
10878}
10879
0a7de745
A
10880void
10881PMSettingObject::free( void )
0c530ab8 10882{
0a7de745
A
10883 if (publishedFeatureID) {
10884 for (uint32_t i = 0; i < settingCount; i++) {
10885 if (publishedFeatureID[i]) {
10886 parent->removePublishedFeature( publishedFeatureID[i] );
10887 }
10888 }
6d2010ae 10889
0a7de745
A
10890 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
10891 }
6d2010ae 10892
0a7de745 10893 super::free();
6d2010ae
A
10894}
10895
f427ee49 10896IOReturn
0a7de745 10897PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
6d2010ae 10898{
f427ee49 10899 return (*func)(target, type, object, refcon);
6d2010ae
A
10900}
10901
0a7de745
A
10902void
10903PMSettingObject::clientHandleFreed( void )
6d2010ae 10904{
0a7de745 10905 parent->deregisterPMSettingObject(this);
6d2010ae
A
10906}
10907
0b4c1975
A
10908// MARK: -
10909// MARK: PMAssertionsTracker
10910
10911//*********************************************************************************
10912//*********************************************************************************
10913//*********************************************************************************
10914// class PMAssertionsTracker Implementation
10915
10916#define kAssertUniqueIDStart 500
10917
0a7de745
A
10918PMAssertionsTracker *
10919PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
10920{
f427ee49 10921 PMAssertionsTracker *me;
0a7de745 10922
f427ee49
A
10923 me = new PMAssertionsTracker;
10924 if (!me || !me->init()) {
10925 if (me) {
10926 me->release();
0a7de745 10927 }
f427ee49 10928 return NULL;
0a7de745
A
10929 }
10930
f427ee49
A
10931 me->owner = rootDomain;
10932 me->issuingUniqueID = kAssertUniqueIDStart;
10933 me->assertionsArray = OSArray::withCapacity(5);
10934 me->assertionsKernel = 0;
10935 me->assertionsUser = 0;
10936 me->assertionsCombined = 0;
10937 me->assertionsArrayLock = IOLockAlloc();
10938 me->tabulateProducerCount = me->tabulateConsumerCount = 0;
10939
10940 assert(me->assertionsArray);
10941 assert(me->assertionsArrayLock);
10942
10943 return me;
0a7de745
A
10944}
10945
10946/* tabulate
10947 * - Update assertionsKernel to reflect the state of all
10948 * assertions in the kernel.
10949 * - Update assertionsCombined to reflect both kernel & user space.
10950 */
10951void
10952PMAssertionsTracker::tabulate(void)
10953{
10954 int i;
10955 int count;
10956 PMAssertStruct *_a = NULL;
10957 OSData *_d = NULL;
10958
10959 IOPMDriverAssertionType oldKernel = assertionsKernel;
10960 IOPMDriverAssertionType oldCombined = assertionsCombined;
10961
10962 ASSERT_GATED();
10963
10964 assertionsKernel = 0;
10965 assertionsCombined = 0;
10966
10967 if (!assertionsArray) {
10968 return;
10969 }
10970
10971 if ((count = assertionsArray->getCount())) {
10972 for (i = 0; i < count; i++) {
10973 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
10974 if (_d) {
10975 _a = (PMAssertStruct *)_d->getBytesNoCopy();
10976 if (_a && (kIOPMDriverAssertionLevelOn == _a->level)) {
10977 assertionsKernel |= _a->assertionBits;
10978 }
10979 }
10980 }
10981 }
10982
10983 tabulateProducerCount++;
10984 assertionsCombined = assertionsKernel | assertionsUser;
10985
10986 if ((assertionsKernel != oldKernel) ||
10987 (assertionsCombined != oldCombined)) {
10988 owner->evaluateAssertions(assertionsCombined, oldCombined);
10989 }
10990}
10991
f427ee49
A
10992void
10993PMAssertionsTracker::updateCPUBitAccounting( PMAssertStruct *assertStruct )
10994{
10995 AbsoluteTime now;
10996 uint64_t nsec;
10997
10998 if (((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) == 0) ||
10999 (assertStruct->assertCPUStartTime == 0)) {
11000 return;
11001 }
11002
11003 now = mach_absolute_time();
11004 SUB_ABSOLUTETIME(&now, &assertStruct->assertCPUStartTime);
11005 absolutetime_to_nanoseconds(now, &nsec);
11006 assertStruct->assertCPUDuration += nsec;
11007 assertStruct->assertCPUStartTime = 0;
11008
11009 if (assertStruct->assertCPUDuration > maxAssertCPUDuration) {
11010 maxAssertCPUDuration = assertStruct->assertCPUDuration;
11011 maxAssertCPUEntryId = assertStruct->registryEntryID;
11012 }
11013}
11014
11015void
11016PMAssertionsTracker::reportCPUBitAccounting( void )
11017{
11018 PMAssertStruct *_a;
11019 OSData *_d;
11020 int i, count;
11021 AbsoluteTime now;
11022 uint64_t nsec;
11023
11024 ASSERT_GATED();
11025
11026 // Account for drivers that are still holding the CPU assertion
11027 if (assertionsKernel & kIOPMDriverAssertionCPUBit) {
11028 now = mach_absolute_time();
11029 if ((count = assertionsArray->getCount())) {
11030 for (i = 0; i < count; i++) {
11031 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
11032 if (_d) {
11033 _a = (PMAssertStruct *)_d->getBytesNoCopy();
11034 if ((_a->assertionBits & kIOPMDriverAssertionCPUBit) &&
11035 (_a->level == kIOPMDriverAssertionLevelOn) &&
11036 (_a->assertCPUStartTime != 0)) {
11037 // Don't modify PMAssertStruct, leave that
11038 // for updateCPUBitAccounting()
11039 SUB_ABSOLUTETIME(&now, &_a->assertCPUStartTime);
11040 absolutetime_to_nanoseconds(now, &nsec);
11041 nsec += _a->assertCPUDuration;
11042 if (nsec > maxAssertCPUDuration) {
11043 maxAssertCPUDuration = nsec;
11044 maxAssertCPUEntryId = _a->registryEntryID;
11045 }
11046 }
11047 }
11048 }
11049 }
11050 }
11051
11052 if (maxAssertCPUDuration) {
11053 DLOG("cpu assertion held for %llu ms by 0x%llx\n",
11054 (maxAssertCPUDuration / NSEC_PER_MSEC), maxAssertCPUEntryId);
11055 }
11056
11057 maxAssertCPUDuration = 0;
11058 maxAssertCPUEntryId = 0;
11059}
11060
0a7de745
A
11061void
11062PMAssertionsTracker::publishProperties( void )
0b4c1975 11063{
f427ee49 11064 OSSharedPtr<OSArray> assertionsSummary;
fe8ab488 11065
0a7de745
A
11066 if (tabulateConsumerCount != tabulateProducerCount) {
11067 IOLockLock(assertionsArrayLock);
fe8ab488 11068
0a7de745
A
11069 tabulateConsumerCount = tabulateProducerCount;
11070
11071 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
11072 */
11073 assertionsSummary = copyAssertionsArray();
11074 if (assertionsSummary) {
f427ee49 11075 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary.get());
0a7de745
A
11076 } else {
11077 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
11078 }
fe8ab488 11079
0a7de745
A
11080 /* Publish the IOPMrootDomain property "DriverPMAssertions"
11081 */
11082 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
0b4c1975 11083
0a7de745
A
11084 IOLockUnlock(assertionsArrayLock);
11085 }
0b4c1975
A
11086}
11087
0a7de745
A
11088PMAssertionsTracker::PMAssertStruct *
11089PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
11090{
11091 PMAssertStruct *_a = NULL;
11092 OSData *_d = NULL;
11093 int found = -1;
11094 int count = 0;
11095 int i = 0;
11096
11097 if (assertionsArray
11098 && (count = assertionsArray->getCount())) {
11099 for (i = 0; i < count; i++) {
11100 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
11101 if (_d) {
11102 _a = (PMAssertStruct *)_d->getBytesNoCopy();
11103 if (_a && (_id == _a->id)) {
11104 found = i;
11105 break;
11106 }
11107 }
11108 }
11109 }
11110
11111 if (-1 == found) {
11112 return NULL;
11113 } else {
11114 if (index) {
11115 *index = found;
11116 }
11117 return _a;
11118 }
0b4c1975
A
11119}
11120
11121/* PMAssertionsTracker::handleCreateAssertion
11122 * Perform assertion work on the PM workloop. Do not call directly.
11123 */
0a7de745
A
11124IOReturn
11125PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
0b4c1975 11126{
f427ee49
A
11127 PMAssertStruct *assertStruct;
11128
0a7de745 11129 ASSERT_GATED();
0b4c1975 11130
0a7de745
A
11131 if (newAssertion) {
11132 IOLockLock(assertionsArrayLock);
f427ee49
A
11133 assertStruct = (PMAssertStruct *) newAssertion->getBytesNoCopy();
11134 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11135 (assertStruct->level == kIOPMDriverAssertionLevelOn)) {
11136 assertStruct->assertCPUStartTime = mach_absolute_time();
11137 }
0a7de745
A
11138 assertionsArray->setObject(newAssertion);
11139 IOLockUnlock(assertionsArrayLock);
11140 newAssertion->release();
0b4c1975 11141
0a7de745
A
11142 tabulate();
11143 }
11144 return kIOReturnSuccess;
0b4c1975
A
11145}
11146
11147/* PMAssertionsTracker::createAssertion
fe8ab488 11148 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
0b4c1975
A
11149 * appropiate.
11150 */
0a7de745
A
11151IOReturn
11152PMAssertionsTracker::createAssertion(
11153 IOPMDriverAssertionType which,
11154 IOPMDriverAssertionLevel level,
11155 IOService *serviceID,
11156 const char *whoItIs,
11157 IOPMDriverAssertionID *outID)
11158{
f427ee49 11159 OSSharedPtr<OSData> dataStore;
0a7de745
A
11160 PMAssertStruct track;
11161
11162 // Warning: trillions and trillions of created assertions may overflow the unique ID.
11163 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
11164 track.level = level;
11165 track.assertionBits = which;
f427ee49
A
11166
11167 // NB: ownerString is explicitly managed by PMAssertStruct
11168 // it will be released in `handleReleaseAssertion' below
11169 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs).detach():nullptr;
0a7de745
A
11170 track.ownerService = serviceID;
11171 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
11172 track.modifiedTime = 0;
11173 pmEventTimeStamp(&track.createdTime);
f427ee49
A
11174 track.assertCPUStartTime = 0;
11175 track.assertCPUDuration = 0;
0a7de745
A
11176
11177 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
11178 if (!dataStore) {
11179 if (track.ownerString) {
11180 track.ownerString->release();
f427ee49 11181 track.ownerString = NULL;
0a7de745
A
11182 }
11183 return kIOReturnNoMemory;
11184 }
11185
11186 *outID = track.id;
11187
11188 if (owner && owner->pmPowerStateQueue) {
f427ee49
A
11189 // queue action is responsible for releasing dataStore
11190 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore.detach());
0a7de745
A
11191 }
11192
11193 return kIOReturnSuccess;
0b4c1975 11194}
1c79356b 11195
0b4c1975
A
11196/* PMAssertionsTracker::handleReleaseAssertion
11197 * Runs in PM workloop. Do not call directly.
11198 */
0a7de745
A
11199IOReturn
11200PMAssertionsTracker::handleReleaseAssertion(
11201 IOPMDriverAssertionID _id)
0b4c1975 11202{
0a7de745 11203 ASSERT_GATED();
0b4c1975 11204
0a7de745
A
11205 int index;
11206 PMAssertStruct *assertStruct = detailsForID(_id, &index);
fe8ab488 11207
0a7de745
A
11208 if (!assertStruct) {
11209 return kIOReturnNotFound;
11210 }
0b4c1975 11211
0a7de745 11212 IOLockLock(assertionsArrayLock);
f427ee49
A
11213
11214 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11215 (assertStruct->level == kIOPMDriverAssertionLevelOn)) {
11216 updateCPUBitAccounting(assertStruct);
11217 }
11218
0a7de745
A
11219 if (assertStruct->ownerString) {
11220 assertStruct->ownerString->release();
f427ee49 11221 assertStruct->ownerString = NULL;
0a7de745 11222 }
0b4c1975 11223
0a7de745
A
11224 assertionsArray->removeObject(index);
11225 IOLockUnlock(assertionsArrayLock);
fe8ab488 11226
0a7de745
A
11227 tabulate();
11228 return kIOReturnSuccess;
0b4c1975
A
11229}
11230
11231/* PMAssertionsTracker::releaseAssertion
11232 * Releases an assertion and affects system behavior if appropiate.
11233 * Actual work happens on PM workloop.
11234 */
0a7de745
A
11235IOReturn
11236PMAssertionsTracker::releaseAssertion(
11237 IOPMDriverAssertionID _id)
0b4c1975 11238{
0a7de745 11239 if (owner && owner->pmPowerStateQueue) {
cb323159 11240 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, NULL, _id);
0a7de745
A
11241 }
11242 return kIOReturnSuccess;
0b4c1975
A
11243}
11244
11245/* PMAssertionsTracker::handleSetAssertionLevel
11246 * Runs in PM workloop. Do not call directly.
11247 */
0a7de745
A
11248IOReturn
11249PMAssertionsTracker::handleSetAssertionLevel(
11250 IOPMDriverAssertionID _id,
11251 IOPMDriverAssertionLevel _level)
0b4c1975 11252{
0a7de745 11253 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
0b4c1975 11254
0a7de745 11255 ASSERT_GATED();
0b4c1975 11256
0a7de745
A
11257 if (!assertStruct) {
11258 return kIOReturnNotFound;
11259 }
0b4c1975 11260
0a7de745
A
11261 IOLockLock(assertionsArrayLock);
11262 pmEventTimeStamp(&assertStruct->modifiedTime);
f427ee49
A
11263 if ((assertStruct->assertionBits & kIOPMDriverAssertionCPUBit) &&
11264 (assertStruct->level != _level)) {
11265 if (_level == kIOPMDriverAssertionLevelOn) {
11266 assertStruct->assertCPUStartTime = mach_absolute_time();
11267 } else {
11268 updateCPUBitAccounting(assertStruct);
11269 }
11270 }
0a7de745
A
11271 assertStruct->level = _level;
11272 IOLockUnlock(assertionsArrayLock);
0b4c1975 11273
0a7de745
A
11274 tabulate();
11275 return kIOReturnSuccess;
0b4c1975
A
11276}
11277
11278/* PMAssertionsTracker::setAssertionLevel
11279 */
0a7de745
A
11280IOReturn
11281PMAssertionsTracker::setAssertionLevel(
11282 IOPMDriverAssertionID _id,
11283 IOPMDriverAssertionLevel _level)
11284{
11285 if (owner && owner->pmPowerStateQueue) {
11286 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
11287 (void *)(uintptr_t)_level, _id);
11288 }
11289
11290 return kIOReturnSuccess;
11291}
11292
11293IOReturn
11294PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
11295{
11296 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
11297
11298 ASSERT_GATED();
11299
11300 if (new_user_levels != assertionsUser) {
f427ee49 11301 DLOG("assertionsUser 0x%llx->0x%llx\n", assertionsUser, new_user_levels);
0a7de745 11302 assertionsUser = new_user_levels;
0a7de745
A
11303 }
11304
11305 tabulate();
11306 return kIOReturnSuccess;
11307}
11308
11309IOReturn
11310PMAssertionsTracker::setUserAssertionLevels(
11311 IOPMDriverAssertionType new_user_levels)
11312{
11313 if (gIOPMWorkLoop) {
11314 gIOPMWorkLoop->runAction(
11315 OSMemberFunctionCast(
11316 IOWorkLoop::Action,
11317 this,
11318 &PMAssertionsTracker::handleSetUserAssertionLevels),
11319 this,
cb323159 11320 (void *) &new_user_levels, NULL, NULL, NULL);
0a7de745
A
11321 }
11322
11323 return kIOReturnSuccess;
11324}
11325
11326
f427ee49 11327OSSharedPtr<OSArray>
0a7de745
A
11328PMAssertionsTracker::copyAssertionsArray(void)
11329{
11330 int count;
11331 int i;
f427ee49 11332 OSSharedPtr<OSArray> outArray = NULL;
0a7de745 11333
f427ee49
A
11334 if (!assertionsArray || (0 == (count = assertionsArray->getCount()))) {
11335 goto exit;
11336 }
11337 outArray = OSArray::withCapacity(count);
11338 if (!outArray) {
0a7de745
A
11339 goto exit;
11340 }
11341
11342 for (i = 0; i < count; i++) {
11343 PMAssertStruct *_a = NULL;
11344 OSData *_d = NULL;
f427ee49 11345 OSSharedPtr<OSDictionary> details;
0a7de745
A
11346
11347 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
11348 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy())) {
f427ee49 11349 OSSharedPtr<OSNumber> _n;
0a7de745
A
11350
11351 details = OSDictionary::withCapacity(7);
11352 if (!details) {
11353 continue;
11354 }
11355
f427ee49 11356 outArray->setObject(details.get());
0a7de745
A
11357
11358 _n = OSNumber::withNumber(_a->id, 64);
11359 if (_n) {
f427ee49 11360 details->setObject(kIOPMDriverAssertionIDKey, _n.get());
0a7de745
A
11361 }
11362 _n = OSNumber::withNumber(_a->createdTime, 64);
11363 if (_n) {
f427ee49 11364 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n.get());
0a7de745
A
11365 }
11366 _n = OSNumber::withNumber(_a->modifiedTime, 64);
11367 if (_n) {
f427ee49 11368 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n.get());
0a7de745
A
11369 }
11370 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
11371 if (_n) {
f427ee49 11372 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n.get());
0a7de745
A
11373 }
11374 _n = OSNumber::withNumber(_a->level, 64);
11375 if (_n) {
f427ee49 11376 details->setObject(kIOPMDriverAssertionLevelKey, _n.get());
0a7de745
A
11377 }
11378 _n = OSNumber::withNumber(_a->assertionBits, 64);
11379 if (_n) {
f427ee49 11380 details->setObject(kIOPMDriverAssertionAssertedKey, _n.get());
0a7de745
A
11381 }
11382
11383 if (_a->ownerString) {
11384 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
11385 }
11386 }
11387 }
0b4c1975
A
11388
11389exit:
f427ee49 11390 return os::move(outArray);
0b4c1975
A
11391}
11392
0a7de745
A
11393IOPMDriverAssertionType
11394PMAssertionsTracker::getActivatedAssertions(void)
0b4c1975 11395{
0a7de745 11396 return assertionsCombined;
0b4c1975
A
11397}
11398
0a7de745
A
11399IOPMDriverAssertionLevel
11400PMAssertionsTracker::getAssertionLevel(
11401 IOPMDriverAssertionType type)
0b4c1975 11402{
f427ee49 11403 // FIXME: unused and also wrong
0a7de745
A
11404 if (type && ((type & assertionsKernel) == assertionsKernel)) {
11405 return kIOPMDriverAssertionLevelOn;
11406 } else {
11407 return kIOPMDriverAssertionLevelOff;
11408 }
0b4c1975
A
11409}
11410
11411//*********************************************************************************
11412//*********************************************************************************
11413//*********************************************************************************
11414
6d2010ae 11415
0a7de745
A
11416static void
11417pmEventTimeStamp(uint64_t *recordTS)
0b4c1975 11418{
0a7de745
A
11419 clock_sec_t tsec;
11420 clock_usec_t tusec;
0b4c1975 11421
0a7de745
A
11422 if (!recordTS) {
11423 return;
11424 }
fe8ab488 11425
0a7de745
A
11426 // We assume tsec fits into 32 bits; 32 bits holds enough
11427 // seconds for 136 years since the epoch in 1970.
11428 clock_get_calendar_microtime(&tsec, &tusec);
0b4c1975
A
11429
11430
0a7de745
A
11431 // Pack the sec & microsec calendar time into a uint64_t, for fun.
11432 *recordTS = 0;
11433 *recordTS |= (uint32_t)tusec;
11434 *recordTS |= ((uint64_t)tsec << 32);
0b4c1975 11435
0a7de745 11436 return;
0b4c1975 11437}
0c530ab8 11438
6d2010ae
A
11439// MARK: -
11440// MARK: IORootParent
1c79356b 11441
6d2010ae 11442/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b 11443
b0d623f7 11444OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
1c79356b 11445
6d2010ae
A
11446// The reason that root domain needs a root parent is to facilitate demand
11447// sleep, since a power change from the root parent cannot be vetoed.
11448//
11449// The above statement is no longer true since root domain now performs
11450// demand sleep using overrides. But root parent remains to avoid changing
11451// the power tree stacking. Root parent is parked at the max power state.
11452
1c79356b 11453
6d2010ae 11454static IOPMPowerState patriarchPowerStates[2] =
b0d623f7 11455{
0a7de745
A
11456 {1, 0, ON_POWER, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11457 {1, 0, ON_POWER, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1c79356b
A
11458};
11459
0a7de745
A
11460void
11461IORootParent::initialize( void )
6d2010ae 11462{
e8c3f781 11463
0a7de745
A
11464 gIOPMPSExternalConnectedKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey);
11465 gIOPMPSExternalChargeCapableKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey);
11466 gIOPMPSBatteryInstalledKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey);
11467 gIOPMPSIsChargingKey = OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey);
11468 gIOPMPSAtWarnLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey);
11469 gIOPMPSAtCriticalLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey);
11470 gIOPMPSCurrentCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey);
11471 gIOPMPSMaxCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey);
11472 gIOPMPSDesignCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey);
11473 gIOPMPSTimeRemainingKey = OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey);
11474 gIOPMPSAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey);
11475 gIOPMPSVoltageKey = OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey);
11476 gIOPMPSCycleCountKey = OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey);
11477 gIOPMPSMaxErrKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey);
11478 gIOPMPSAdapterInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey);
11479 gIOPMPSLocationKey = OSSymbol::withCStringNoCopy(kIOPMPSLocationKey);
11480 gIOPMPSErrorConditionKey = OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey);
11481 gIOPMPSManufacturerKey = OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey);
11482 gIOPMPSManufactureDateKey = OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey);
11483 gIOPMPSModelKey = OSSymbol::withCStringNoCopy(kIOPMPSModelKey);
11484 gIOPMPSSerialKey = OSSymbol::withCStringNoCopy(kIOPMPSSerialKey);
11485 gIOPMPSLegacyBatteryInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey);
11486 gIOPMPSBatteryHealthKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey);
11487 gIOPMPSHealthConfidenceKey = OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey);
11488 gIOPMPSCapacityEstimatedKey = OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey);
11489 gIOPMPSBatteryChargeStatusKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey);
11490 gIOPMPSBatteryTemperatureKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey);
11491 gIOPMPSAdapterDetailsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey);
11492 gIOPMPSChargerConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey);
11493 gIOPMPSAdapterDetailsIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey);
11494 gIOPMPSAdapterDetailsWattsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey);
11495 gIOPMPSAdapterDetailsRevisionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey);
11496 gIOPMPSAdapterDetailsSerialNumberKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey);
11497 gIOPMPSAdapterDetailsFamilyKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey);
11498 gIOPMPSAdapterDetailsAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey);
11499 gIOPMPSAdapterDetailsDescriptionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey);
11500 gIOPMPSAdapterDetailsPMUConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey);
11501 gIOPMPSAdapterDetailsSourceIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey);
11502 gIOPMPSAdapterDetailsErrorFlagsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey);
11503 gIOPMPSAdapterDetailsSharedSourceKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey);
11504 gIOPMPSAdapterDetailsCloakedKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey);
11505 gIOPMPSInvalidWakeSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey);
11506 gIOPMPSPostChargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey);
11507 gIOPMPSPostDishargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey);
6d2010ae
A
11508}
11509
0a7de745
A
11510bool
11511IORootParent::start( IOService * nub )
1c79356b 11512{
0a7de745
A
11513 IOService::start(nub);
11514 attachToParent( getRegistryRoot(), gIOPowerPlane );
11515 PMinit();
11516 registerPowerDriver(this, patriarchPowerStates, 2);
11517 makeUsable();
11518 return true;
1c79356b
A
11519}
11520
0a7de745
A
11521void
11522IORootParent::shutDownSystem( void )
1c79356b 11523{
0b4e3aa0
A
11524}
11525
0a7de745
A
11526void
11527IORootParent::restartSystem( void )
0b4e3aa0 11528{
1c79356b
A
11529}
11530
0a7de745
A
11531void
11532IORootParent::sleepSystem( void )
1c79356b 11533{
0b4e3aa0
A
11534}
11535
0a7de745
A
11536void
11537IORootParent::dozeSystem( void )
0b4e3aa0 11538{
0b4e3aa0
A
11539}
11540
0a7de745
A
11541void
11542IORootParent::sleepToDoze( void )
0b4e3aa0 11543{
1c79356b
A
11544}
11545
0a7de745
A
11546void
11547IORootParent::wakeSystem( void )
1c79356b 11548{
1c79356b 11549}
6d2010ae 11550
f427ee49 11551OSSharedPtr<OSObject>
0a7de745 11552IORootParent::copyProperty( const char * aKey) const
6d2010ae 11553{
0a7de745 11554 return IOService::copyProperty(aKey);
6d2010ae
A
11555}
11556
0a7de745
A
11557uint32_t
11558IOPMrootDomain::getWatchdogTimeout()
d9a64523 11559{
0a7de745
A
11560 if (gSwdSleepWakeTimeout) {
11561 gSwdSleepTimeout = gSwdWakeTimeout = gSwdSleepWakeTimeout;
11562 }
11563 if ((pmTracer->getTracePhase() < kIOPMTracePointSystemSleep) ||
11564 (pmTracer->getTracePhase() == kIOPMTracePointDarkWakeEntry)) {
11565 return gSwdSleepTimeout ? gSwdSleepTimeout : WATCHDOG_SLEEP_TIMEOUT;
11566 } else {
11567 return gSwdWakeTimeout ? gSwdWakeTimeout : WATCHDOG_WAKE_TIMEOUT;
11568 }
d9a64523
A
11569}
11570
39236c6e 11571
f427ee49 11572#if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
0a7de745
A
11573IOReturn
11574IOPMrootDomain::restartWithStackshot()
fe8ab488 11575{
cb323159 11576 takeStackshot(true);
0a7de745
A
11577
11578 return kIOReturnSuccess;
11579}
39236c6e 11580
0a7de745
A
11581void
11582IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
11583{
cb323159 11584 takeStackshot(wdogTrigger);
39236c6e
A
11585}
11586
0a7de745
A
11587void
11588IOPMrootDomain::tracePhase2String(uint32_t tracePhase, const char **phaseString, const char **description)
fe8ab488 11589{
0a7de745
A
11590 switch (tracePhase) {
11591 case kIOPMTracePointSleepStarted:
11592 *phaseString = "kIOPMTracePointSleepStarted";
11593 *description = "starting sleep";
11594 break;
11595
11596 case kIOPMTracePointSleepApplications:
11597 *phaseString = "kIOPMTracePointSleepApplications";
11598 *description = "notifying applications";
11599 break;
11600
11601 case kIOPMTracePointSleepPriorityClients:
11602 *phaseString = "kIOPMTracePointSleepPriorityClients";
11603 *description = "notifying clients about upcoming system capability changes";
11604 break;
11605
11606 case kIOPMTracePointSleepWillChangeInterests:
11607 *phaseString = "kIOPMTracePointSleepWillChangeInterests";
11608 *description = "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
11609 break;
11610
11611 case kIOPMTracePointSleepPowerPlaneDrivers:
11612 *phaseString = "kIOPMTracePointSleepPowerPlaneDrivers";
11613 *description = "calling power state change callbacks";
11614 break;
11615
11616 case kIOPMTracePointSleepDidChangeInterests:
11617 *phaseString = "kIOPMTracePointSleepDidChangeInterests";
11618 *description = "calling rootDomain's clients about rootDomain's state changes";
11619 break;
11620
11621 case kIOPMTracePointSleepCapabilityClients:
11622 *phaseString = "kIOPMTracePointSleepCapabilityClients";
11623 *description = "notifying clients about current system capabilities";
11624 break;
11625
11626 case kIOPMTracePointSleepPlatformActions:
11627 *phaseString = "kIOPMTracePointSleepPlatformActions";
11628 *description = "calling Quiesce/Sleep action callbacks";
11629 break;
11630
11631 case kIOPMTracePointSleepCPUs:
11632 {
11633 *phaseString = "kIOPMTracePointSleepCPUs";
11634#if defined(__i386__) || defined(__x86_64__)
11635 /*
11636 * We cannot use the getCPUNumber() method to get the cpu number, since
11637 * that cpu number is unrelated to the cpu number we need (we need the cpu
11638 * number as enumerated by the scheduler, NOT the CPU number enumerated
11639 * by ACPIPlatform as the CPUs are enumerated in MADT order).
11640 * Instead, pass the Mach processor pointer associated with the current
11641 * shutdown target so its associated cpu_id can be used in
11642 * processor_to_datastring.
11643 */
11644 if (currentShutdownTarget != NULL &&
11645 currentShutdownTarget->getMachProcessor() != NULL) {
11646 const char *sbuf = processor_to_datastring("halting all non-boot CPUs",
11647 currentShutdownTarget->getMachProcessor());
11648 *description = sbuf;
11649 } else {
11650 *description = "halting all non-boot CPUs";
11651 }
11652#else
11653 *description = "halting all non-boot CPUs";
11654#endif
11655 break;
11656 }
11657 case kIOPMTracePointSleepPlatformDriver:
11658 *phaseString = "kIOPMTracePointSleepPlatformDriver";
11659 *description = "executing platform specific code";
11660 break;
11661
11662 case kIOPMTracePointHibernate:
11663 *phaseString = "kIOPMTracePointHibernate";
11664 *description = "writing the hibernation image";
11665 break;
11666
11667 case kIOPMTracePointSystemSleep:
11668 *phaseString = "kIOPMTracePointSystemSleep";
11669 *description = "in EFI/Bootrom after last point of entry to sleep";
11670 break;
11671
11672 case kIOPMTracePointWakePlatformDriver:
11673 *phaseString = "kIOPMTracePointWakePlatformDriver";
11674 *description = "executing platform specific code";
11675 break;
11676
11677
11678 case kIOPMTracePointWakePlatformActions:
11679 *phaseString = "kIOPMTracePointWakePlatformActions";
11680 *description = "calling Wake action callbacks";
11681 break;
11682
11683 case kIOPMTracePointWakeCPUs:
11684 *phaseString = "kIOPMTracePointWakeCPUs";
11685 *description = "starting non-boot CPUs";
11686 break;
11687
11688 case kIOPMTracePointWakeWillPowerOnClients:
11689 *phaseString = "kIOPMTracePointWakeWillPowerOnClients";
11690 *description = "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
11691 break;
11692
11693 case kIOPMTracePointWakeWillChangeInterests:
11694 *phaseString = "kIOPMTracePointWakeWillChangeInterests";
11695 *description = "calling rootDomain's clients about upcoming rootDomain's state changes";
11696 break;
11697
11698 case kIOPMTracePointWakeDidChangeInterests:
11699 *phaseString = "kIOPMTracePointWakeDidChangeInterests";
11700 *description = "calling rootDomain's clients about completed rootDomain's state changes";
11701 break;
11702
11703 case kIOPMTracePointWakePowerPlaneDrivers:
11704 *phaseString = "kIOPMTracePointWakePowerPlaneDrivers";
11705 *description = "calling power state change callbacks";
11706 break;
11707
11708 case kIOPMTracePointWakeCapabilityClients:
11709 *phaseString = "kIOPMTracePointWakeCapabilityClients";
11710 *description = "informing clients about current system capabilities";
11711 break;
11712
11713 case kIOPMTracePointWakeApplications:
11714 *phaseString = "kIOPMTracePointWakeApplications";
11715 *description = "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
11716 break;
11717
11718 case kIOPMTracePointDarkWakeEntry:
11719 *phaseString = "kIOPMTracePointDarkWakeEntry";
11720 *description = "entering darkwake on way to sleep";
11721 break;
11722
11723 case kIOPMTracePointDarkWakeExit:
11724 *phaseString = "kIOPMTracePointDarkWakeExit";
11725 *description = "entering fullwake from darkwake";
11726 break;
11727
11728 default:
11729 *phaseString = NULL;
11730 *description = NULL;
11731 }
fe8ab488
A
11732}
11733
0a7de745
A
11734void
11735IOPMrootDomain::saveFailureData2File()
39236c6e 11736{
0a7de745
A
11737 unsigned int len = 0;
11738 char failureStr[512];
11739 errno_t error;
11740 char *outbuf;
cb323159
A
11741 OSNumber *statusCode;
11742 uint64_t pmStatusCode = 0;
11743 uint32_t phaseData = 0;
11744 uint32_t phaseDetail = 0;
11745 bool efiFailure = false;
11746
f427ee49
A
11747 OSSharedPtr<OSObject> statusCodeProp = copyProperty(kIOPMSleepWakeFailureCodeKey);
11748 statusCode = OSDynamicCast(OSNumber, statusCodeProp.get());
cb323159
A
11749 if (statusCode) {
11750 pmStatusCode = statusCode->unsigned64BitValue();
11751 phaseData = pmStatusCode & 0xFFFFFFFF;
11752 phaseDetail = (pmStatusCode >> 32) & 0xFFFFFFFF;
11753 if ((phaseData & 0xFF) == kIOPMTracePointSystemSleep) {
11754 LOG("Sleep Wake failure in EFI\n");
11755 efiFailure = true;
11756 failureStr[0] = 0;
11757 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);
f427ee49 11758 len = (typeof(len))strnlen(failureStr, sizeof(failureStr));
cb323159
A
11759 }
11760 }
11761
11762 if (!efiFailure) {
11763 if (PEReadNVRAMProperty(kIOSleepWakeFailurePanic, NULL, &len)) {
11764 swd_flags |= SWD_BOOT_BY_SW_WDOG;
11765 PERemoveNVRAMProperty(kIOSleepWakeFailurePanic);
11766 // dump panic will handle saving nvram data
11767 return;
11768 }
39236c6e 11769
cb323159
A
11770 /* Keeping this around for capturing data during power
11771 * button press */
0a7de745 11772
cb323159
A
11773 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString, NULL, &len)) {
11774 DLOG("No sleep wake failure string\n");
11775 return;
11776 }
11777 if (len == 0) {
11778 DLOG("Ignoring zero byte SleepWake failure string\n");
11779 goto exit;
11780 }
39236c6e 11781
cb323159
A
11782 // if PMStatus code is zero, delete stackshot and return
11783 if (statusCode) {
11784 if (((pmStatusCode & 0xFFFFFFFF) & 0xFF) == 0) {
11785 // there was no sleep wake failure
11786 // this can happen if delete stackshot was called
11787 // before take stackshot completed. Let us delete any
11788 // sleep wake failure data in nvram
11789 DLOG("Deleting stackshot on successful wake\n");
11790 deleteStackshot();
11791 return;
11792 }
11793 }
11794
11795 if (len > sizeof(failureStr)) {
11796 len = sizeof(failureStr);
0a7de745 11797 }
cb323159
A
11798 failureStr[0] = 0;
11799 PEReadNVRAMProperty(kIOSleepWakeFailureString, failureStr, &len);
0a7de745
A
11800 }
11801 if (failureStr[0] != 0) {
cb323159 11802 error = sleepWakeDebugSaveFile(kSleepWakeFailureStringFile, failureStr, len);
0a7de745
A
11803 if (error) {
11804 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error);
11805 } else {
11806 DLOG("Saved SleepWake failure string to file.\n");
11807 }
0a7de745 11808 }
3e170ce0 11809
0a7de745
A
11810 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
11811 goto exit;
11812 }
3e170ce0 11813
0a7de745
A
11814 if (swd_buffer) {
11815 unsigned int len = 0;
11816 errno_t error;
11817 char nvram_var_name_buffer[20];
11818 unsigned int concat_len = 0;
11819 swd_hdr *hdr = NULL;
39236c6e 11820
39236c6e 11821
0a7de745
A
11822 hdr = (swd_hdr *)swd_buffer;
11823 outbuf = (char *)hdr + hdr->spindump_offset;
f427ee49 11824 OSBoundedArrayRef<char> boundedOutBuf(outbuf, hdr->alloc_size - hdr->spindump_offset);
3e170ce0 11825
0a7de745 11826 for (int i = 0; i < 8; i++) {
f427ee49 11827 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i + 1);
0a7de745
A
11828 if (!PEReadNVRAMProperty(nvram_var_name_buffer, NULL, &len)) {
11829 LOG("No SleepWake blob to read beyond chunk %d\n", i);
11830 break;
11831 }
f427ee49 11832 if (PEReadNVRAMProperty(nvram_var_name_buffer, boundedOutBuf.slice(concat_len, len).data(), &len) == FALSE) {
0a7de745
A
11833 PERemoveNVRAMProperty(nvram_var_name_buffer);
11834 LOG("Could not read the property :-(\n");
11835 break;
11836 }
11837 PERemoveNVRAMProperty(nvram_var_name_buffer);
11838 concat_len += len;
11839 }
11840 LOG("Concatenated length for the SWD blob %d\n", concat_len);
11841
11842 if (concat_len) {
cb323159
A
11843 error = sleepWakeDebugSaveFile(kSleepWakeStacksFilename, outbuf, concat_len);
11844 if (error) {
11845 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
11846 } else {
11847 LOG("Saved SleepWake zipped data to file.\n");
11848 }
11849 } else {
11850 // There is a sleep wake failure string but no stackshot
11851 // Write a placeholder stacks file so that swd runs
11852 snprintf(outbuf, 20, "%s", "No stackshot data\n");
11853 error = sleepWakeDebugSaveFile(kSleepWakeStacksFilename, outbuf, 20);
0a7de745
A
11854 if (error) {
11855 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
11856 } else {
11857 LOG("Saved SleepWake zipped data to file.\n");
11858 }
11859 }
11860 } else {
11861 LOG("No buffer allocated to save failure stackshot\n");
11862 }
fe8ab488 11863
3e170ce0 11864
0a7de745 11865 gRootDomain->swd_lock = 0;
d9a64523 11866exit:
cb323159 11867 PERemoveNVRAMProperty(kIOSleepWakeFailureString);
0a7de745
A
11868 return;
11869}
11870
11871
11872void
11873IOPMrootDomain::getFailureData(thread_t *thread, char *failureStr, size_t strLen)
11874{
f427ee49
A
11875 OSSharedPtr<IORegistryIterator> iter;
11876 OSSharedPtr<const OSSymbol> kextName = NULL;
0a7de745
A
11877 IORegistryEntry * entry;
11878 IOService * node;
11879 bool nodeFound = false;
11880
11881 const void * callMethod = NULL;
11882 const char * objectName = NULL;
11883 uint32_t timeout = getWatchdogTimeout();
11884 const char * phaseString = NULL;
11885 const char * phaseDescription = NULL;
11886
f427ee49 11887 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, notifierObject.get());
0a7de745
A
11888 uint32_t tracePhase = pmTracer->getTracePhase();
11889
11890 *thread = NULL;
11891 if ((tracePhase < kIOPMTracePointSystemSleep) || (tracePhase == kIOPMTracePointDarkWakeEntry)) {
f427ee49 11892 snprintf(failureStr, strLen, "Sleep transition timed out after %d seconds", timeout);
0a7de745 11893 } else {
f427ee49 11894 snprintf(failureStr, strLen, "Wake transition timed out after %d seconds", timeout);
0a7de745
A
11895 }
11896 tracePhase2String(tracePhase, &phaseString, &phaseDescription);
11897
11898 if (notifierThread) {
11899 if (notifier && (notifier->identifier)) {
11900 objectName = notifier->identifier->getCStringNoCopy();
11901 }
11902 *thread = notifierThread;
11903 } else {
11904 iter = IORegistryIterator::iterateOver(
11905 getPMRootDomain(), gIOPowerPlane, kIORegistryIterateRecursively);
11906
11907 if (iter) {
11908 while ((entry = iter->getNextObject())) {
11909 node = OSDynamicCast(IOService, entry);
11910 if (!node) {
11911 continue;
11912 }
11913 if (OSDynamicCast(IOPowerConnection, node)) {
11914 continue;
11915 }
11916
11917 if (node->getBlockingDriverCall(thread, &callMethod)) {
11918 nodeFound = true;
11919 break;
11920 }
11921 }
0a7de745
A
11922 }
11923 if (nodeFound) {
f427ee49
A
11924 kextName = copyKextIdentifierWithAddress((vm_address_t) callMethod);
11925 if (kextName) {
11926 objectName = kextName->getCStringNoCopy();
0a7de745
A
11927 }
11928 }
11929 }
11930 if (phaseDescription) {
f427ee49
A
11931 strlcat(failureStr, " while ", strLen);
11932 strlcat(failureStr, phaseDescription, strLen);
11933 strlcat(failureStr, ".", strLen);
0a7de745
A
11934 }
11935 if (objectName) {
f427ee49
A
11936 strlcat(failureStr, " Suspected bundle: ", strLen);
11937 strlcat(failureStr, objectName, strLen);
11938 strlcat(failureStr, ".", strLen);
0a7de745
A
11939 }
11940 if (*thread) {
f427ee49
A
11941 char threadName[40];
11942 snprintf(threadName, sizeof(threadName), " Thread 0x%llx.", thread_tid(*thread));
11943 strlcat(failureStr, threadName, strLen);
0a7de745
A
11944 }
11945
11946 DLOG("%s\n", failureStr);
11947}
11948
11949struct swd_stackshot_compressed_data {
11950 z_output_func zoutput;
11951 size_t zipped;
11952 uint64_t totalbytes;
11953 uint64_t lastpercent;
11954 IOReturn error;
11955 unsigned outremain;
11956 unsigned outlen;
11957 unsigned writes;
11958 Bytef * outbuf;
d9a64523
A
11959};
11960struct swd_stackshot_compressed_data swd_zip_var = { };
11961
0a7de745
A
11962static void *
11963swd_zs_alloc(void *__unused ref, u_int items, u_int size)
d9a64523
A
11964{
11965 void *result;
11966 LOG("Alloc in zipping %d items of size %d\n", items, size);
11967
11968 result = (void *)(swd_zs_zmem + swd_zs_zoffset);
11969 swd_zs_zoffset += ~31L & (31 + (items * size)); // 32b align for vector crc
11970 LOG("Offset %zu\n", swd_zs_zoffset);
0a7de745 11971 return result;
d9a64523
A
11972}
11973
0a7de745
A
11974static int
11975swd_zinput(z_streamp strm, Bytef *buf, unsigned size)
d9a64523
A
11976{
11977 unsigned len;
11978
11979 len = strm->avail_in;
11980
0a7de745 11981 if (len > size) {
d9a64523 11982 len = size;
0a7de745
A
11983 }
11984 if (len == 0) {
d9a64523 11985 return 0;
0a7de745 11986 }
d9a64523 11987
0a7de745 11988 if (strm->next_in != (Bytef *) strm) {
d9a64523 11989 memcpy(buf, strm->next_in, len);
0a7de745 11990 } else {
d9a64523 11991 bzero(buf, len);
0a7de745 11992 }
d9a64523 11993
0a7de745 11994 strm->adler = z_crc32(strm->adler, buf, len);
d9a64523 11995
0a7de745
A
11996 strm->avail_in -= len;
11997 strm->next_in += len;
11998 strm->total_in += len;
d9a64523 11999
0a7de745 12000 return (int)len;
d9a64523
A
12001}
12002
0a7de745
A
12003static int
12004swd_zoutput(z_streamp strm, Bytef *buf, unsigned len)
d9a64523
A
12005{
12006 unsigned int i = 0;
12007 // if outlen > max size don't add to the buffer
f427ee49 12008 assert(buf != NULL);
d9a64523
A
12009 if (strm && buf) {
12010 if (swd_zip_var.outlen + len > SWD_COMPRESSED_BUFSIZE) {
12011 LOG("No space to GZIP... not writing to NVRAM\n");
0a7de745 12012 return len;
d9a64523
A
12013 }
12014 }
12015 for (i = 0; i < len; i++) {
0a7de745 12016 *(swd_zip_var.outbuf + swd_zip_var.outlen + i) = *(buf + i);
d9a64523
A
12017 }
12018 swd_zip_var.outlen += len;
0a7de745
A
12019 return len;
12020}
f427ee49 12021
0a7de745
A
12022static void
12023swd_zs_free(void * __unused ref, void * __unused ptr)
12024{
12025}
12026
12027static int
12028swd_compress(char *inPtr, char *outPtr, size_t numBytes)
12029{
12030 int wbits = 12;
12031 int memlevel = 3;
12032
f427ee49
A
12033 if (((unsigned int) numBytes) != numBytes) {
12034 return 0;
12035 }
12036
0a7de745
A
12037 if (!swd_zs.zalloc) {
12038 swd_zs.zalloc = swd_zs_alloc;
12039 swd_zs.zfree = swd_zs_free;
12040 if (deflateInit2(&swd_zs, Z_BEST_SPEED, Z_DEFLATED, wbits + 16, memlevel, Z_DEFAULT_STRATEGY)) {
12041 // allocation failed
12042 bzero(&swd_zs, sizeof(swd_zs));
12043 // swd_zs_zoffset = 0;
12044 } else {
12045 LOG("PMRD inited the zlib allocation routines\n");
12046 }
12047 }
12048
0a7de745
A
12049 swd_zip_var.zipped = 0;
12050 swd_zip_var.totalbytes = 0; // should this be the max that we have?
12051 swd_zip_var.lastpercent = 0;
12052 swd_zip_var.error = kIOReturnSuccess;
12053 swd_zip_var.outremain = 0;
12054 swd_zip_var.outlen = 0;
12055 swd_zip_var.writes = 0;
12056 swd_zip_var.outbuf = (Bytef *)outPtr;
12057
12058 swd_zip_var.totalbytes = numBytes;
12059
12060 swd_zs.avail_in = 0;
12061 swd_zs.next_in = NULL;
12062 swd_zs.avail_out = 0;
12063 swd_zs.next_out = NULL;
12064
12065 deflateResetWithIO(&swd_zs, swd_zinput, swd_zoutput);
12066
12067 z_stream *zs;
12068 int zr;
12069 zs = &swd_zs;
12070
0a7de745
A
12071 while (swd_zip_var.error >= 0) {
12072 if (!zs->avail_in) {
12073 zs->next_in = (unsigned char *)inPtr ? (Bytef *)inPtr : (Bytef *)zs; /* zero marker? */
f427ee49 12074 zs->avail_in = (unsigned int) numBytes;
0a7de745
A
12075 }
12076 if (!zs->avail_out) {
12077 zs->next_out = (Bytef *)zs;
12078 zs->avail_out = UINT32_MAX;
12079 }
12080 zr = deflate(zs, Z_NO_FLUSH);
12081 if (Z_STREAM_END == zr) {
12082 break;
12083 }
12084 if (zr != Z_OK) {
12085 LOG("ZERR %d\n", zr);
12086 swd_zip_var.error = zr;
12087 } else {
12088 if (zs->total_in == numBytes) {
12089 break;
12090 }
12091 }
12092 }
f427ee49 12093
0a7de745
A
12094 //now flush the stream
12095 while (swd_zip_var.error >= 0) {
12096 if (!zs->avail_out) {
12097 zs->next_out = (Bytef *)zs;
12098 zs->avail_out = UINT32_MAX;
12099 }
12100 zr = deflate(zs, Z_FINISH);
12101 if (Z_STREAM_END == zr) {
12102 break;
12103 }
12104 if (zr != Z_OK) {
12105 LOG("ZERR %d\n", zr);
12106 swd_zip_var.error = zr;
12107 } else {
12108 if (zs->total_in == numBytes) {
12109 LOG("Total output size %d\n", swd_zip_var.outlen);
12110 break;
12111 }
12112 }
12113 }
12114
12115 return swd_zip_var.outlen;
12116}
12117
12118void
cb323159 12119IOPMrootDomain::deleteStackshot()
0a7de745 12120{
cb323159
A
12121 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12122 // takeStackshot hasn't completed
12123 return;
12124 }
12125 LOG("Deleting any sleepwake failure data in nvram\n");
0a7de745 12126
cb323159
A
12127 PERemoveNVRAMProperty(kIOSleepWakeFailureString);
12128 char nvram_var_name_buf[20];
12129 for (int i = 0; i < 8; i++) {
f427ee49 12130 snprintf(nvram_var_name_buf, sizeof(nvram_var_name_buf), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i + 1);
cb323159
A
12131 if (PERemoveNVRAMProperty(nvram_var_name_buf) == false) {
12132 LOG("Removing %s returned false\n", nvram_var_name_buf);
12133 }
12134 }
12135 // force NVRAM sync
f427ee49 12136 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey)) == false) {
cb323159
A
12137 DLOG("Failed to force nvram sync\n");
12138 }
12139 gRootDomain->swd_lock = 0;
12140}
f427ee49 12141
cb323159
A
12142void
12143IOPMrootDomain::takeStackshot(bool wdogTrigger)
12144{
12145 swd_hdr * hdr = NULL;
12146 int cnt = 0;
12147 int max_cnt = 2;
12148 pid_t pid = 0;
12149 kern_return_t kr = KERN_SUCCESS;
f427ee49 12150 uint64_t flags;
0a7de745 12151
cb323159
A
12152 char * dstAddr;
12153 uint32_t size;
12154 uint32_t bytesRemaining;
12155 unsigned bytesWritten = 0;
0a7de745 12156
cb323159
A
12157 char failureStr[512];
12158 thread_t thread = NULL;
12159 const char * swfPanic = "swfPanic";
0a7de745 12160
f427ee49
A
12161 uint32_t bufSize;
12162 int success = 0;
0a7de745 12163
f427ee49
A
12164#if defined(__i386__) || defined(__x86_64__)
12165 const bool concise = false;
12166#else
12167 const bool concise = true;
12168#endif
0a7de745 12169
cb323159
A
12170 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12171 return;
12172 }
0a7de745
A
12173
12174 failureStr[0] = 0;
cb323159
A
12175 if ((kIOSleepWakeWdogOff & gIOKitDebug) || systemBooting || systemShutdown || gWillShutdown) {
12176 return;
12177 }
0a7de745 12178
cb323159
A
12179 if (wdogTrigger) {
12180 getFailureData(&thread, failureStr, sizeof(failureStr));
0a7de745 12181
f427ee49 12182 if (concise || (PEGetCoprocessorVersion() >= kCoprocessorVersion2)) {
cb323159 12183 goto skip_stackshot;
0a7de745 12184 }
cb323159
A
12185 } else {
12186 AbsoluteTime now;
12187 uint64_t nsec;
12188 clock_get_uptime(&now);
12189 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
12190 absolutetime_to_nanoseconds(now, &nsec);
f427ee49 12191 snprintf(failureStr, sizeof(failureStr), "Power button pressed during wake transition after %u ms.\n", ((int)((nsec) / NSEC_PER_MSEC)));
cb323159 12192 }
0a7de745 12193
cb323159
A
12194 if (swd_buffer == NULL) {
12195 sleepWakeDebugMemAlloc();
0a7de745 12196 if (swd_buffer == NULL) {
cb323159 12197 return;
0a7de745 12198 }
0a7de745 12199 }
cb323159 12200 hdr = (swd_hdr *)swd_buffer;
f427ee49 12201 bufSize = hdr->alloc_size;
0a7de745
A
12202
12203 dstAddr = (char*)hdr + hdr->spindump_offset;
0a7de745 12204 flags = STACKSHOT_KCDATA_FORMAT | STACKSHOT_NO_IO_STATS | STACKSHOT_SAVE_KEXT_LOADINFO | STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY | STACKSHOT_THREAD_WAITINFO;
cb323159
A
12205 /* If not wdogTrigger only take kernel tasks stackshot
12206 */
12207 if (wdogTrigger) {
12208 pid = -1;
12209 } else {
12210 pid = 0;
12211 }
12212
12213 /* Attempt to take stackshot with all ACTIVE_KERNEL_THREADS
12214 * If we run out of space, take stackshot with only kernel task
12215 */
12216 while (success == 0 && cnt < max_cnt) {
12217 bytesRemaining = bufSize - hdr->spindump_offset;
12218 cnt++;
12219 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
0a7de745 12220
cb323159 12221 size = bytesRemaining;
f427ee49
A
12222 kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, 0, &bytesWritten);
12223 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%llx bytesWritten: %d\n",
0a7de745
A
12224 kr, pid, size, flags, bytesWritten);
12225 if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
12226 if (pid == -1) {
cb323159
A
12227 pid = 0;
12228 } else {
12229 LOG("Insufficient buffer size for only kernel task\n");
12230 break;
0a7de745
A
12231 }
12232 }
cb323159
A
12233 if (kr == KERN_SUCCESS) {
12234 if (bytesWritten == 0) {
f427ee49 12235 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%llx\n", kr, size, flags);
cb323159
A
12236 continue;
12237 }
12238 bytesRemaining -= bytesWritten;
12239 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
0a7de745 12240
cb323159 12241 memset(hdr->reason, 0x20, sizeof(hdr->reason));
0a7de745 12242
cb323159
A
12243 // Compress stackshot and save to NVRAM
12244 {
12245 char *outbuf = (char *)swd_compressed_buffer;
12246 int outlen = 0;
12247 int num_chunks = 0;
12248 int max_chunks = 0;
12249 int leftover = 0;
12250 char nvram_var_name_buffer[20];
0a7de745 12251
cb323159 12252 outlen = swd_compress((char*)hdr + hdr->spindump_offset, outbuf, bytesWritten);
0a7de745 12253
cb323159
A
12254 if (outlen) {
12255 max_chunks = outlen / (2096 - 200);
12256 leftover = outlen % (2096 - 200);
0a7de745 12257
cb323159
A
12258 if (max_chunks < 8) {
12259 for (num_chunks = 0; num_chunks < max_chunks; num_chunks++) {
f427ee49 12260 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks + 1);
cb323159
A
12261 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer, (outbuf + (num_chunks * (2096 - 200))), (2096 - 200)) == FALSE) {
12262 LOG("Failed to update NVRAM %d\n", num_chunks);
12263 break;
12264 }
12265 }
12266 if (leftover) {
f427ee49 12267 snprintf(nvram_var_name_buffer, sizeof(nvram_var_name_buffer), "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks + 1);
cb323159
A
12268 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer, (outbuf + (num_chunks * (2096 - 200))), leftover) == FALSE) {
12269 LOG("Failed to update NVRAM with leftovers\n");
12270 }
12271 }
12272 success = 1;
12273 LOG("Successfully saved stackshot to NVRAM\n");
12274 } else {
12275 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen);
12276 if (pid == -1) {
12277 pid = 0;
12278 } else {
12279 LOG("Compressed failure stackshot of only kernel is too large size=%d bytes\n", outlen);
12280 break;
12281 }
0a7de745
A
12282 }
12283 }
0a7de745
A
12284 }
12285 }
12286 }
12287
12288 if (failureStr[0]) {
cb323159 12289 // append sleep-wake failure code
f427ee49
A
12290 char traceCode[80];
12291 snprintf(traceCode, sizeof(traceCode), "\nFailure code:: 0x%08x %08x\n",
12292 pmTracer->getTraceData(), pmTracer->getTracePhase());
12293 strlcat(failureStr, traceCode, sizeof(failureStr));
12294 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString, failureStr, (unsigned int) strnlen(failureStr, sizeof(failureStr))) == false) {
cb323159 12295 DLOG("Failed to write SleepWake failure string\n");
0a7de745
A
12296 }
12297 }
cb323159
A
12298
12299 // force NVRAM sync
f427ee49 12300 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey)) == false) {
cb323159
A
12301 DLOG("Failed to force nvram sync\n");
12302 }
39236c6e 12303
d9a64523 12304skip_stackshot:
0a7de745 12305 if (wdogTrigger) {
cb323159
A
12306 if (PEGetCoprocessorVersion() < kCoprocessorVersion2) {
12307 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
12308 // If current boot is due to this watch dog trigger restart in previous boot,
12309 // then don't trigger again until at least 1 successful sleep & wake.
12310 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
12311 LOG("Shutting down due to repeated Sleep/Wake failures\n");
12312 if (!tasksSuspended) {
12313 tasksSuspended = TRUE;
12314 updateTasksSuspend();
12315 }
12316 PEHaltRestart(kPEHaltCPU);
12317 return;
12318 }
0a7de745 12319 }
cb323159
A
12320 if (gSwdPanic == 0) {
12321 LOG("Calling panic prevented by swd_panic boot-args. Calling restart");
0a7de745
A
12322 if (!tasksSuspended) {
12323 tasksSuspended = TRUE;
cb323159 12324 updateTasksSuspend();
0a7de745 12325 }
cb323159 12326 PEHaltRestart(kPERestartCPU);
0a7de745
A
12327 }
12328 }
f427ee49 12329 if (!concise && (PEWriteNVRAMProperty(kIOSleepWakeFailurePanic, swfPanic, (unsigned int) strlen(swfPanic)) == false)) {
cb323159
A
12330 DLOG("Failed to write SleepWake failure panic key\n");
12331 }
f427ee49 12332#if defined(__x86_64__)
cb323159
A
12333 if (thread) {
12334 panic_with_thread_context(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, thread, "%s", failureStr);
f427ee49
A
12335 } else
12336#endif /* defined(__x86_64__) */
12337 {
cb323159 12338 panic_with_options(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, "%s", failureStr);
0a7de745 12339 }
0a7de745 12340 } else {
cb323159
A
12341 gRootDomain->swd_lock = 0;
12342 return;
0a7de745
A
12343 }
12344}
12345
12346void
12347IOPMrootDomain::sleepWakeDebugMemAlloc()
12348{
12349 vm_size_t size = SWD_STACKSHOT_SIZE + SWD_COMPRESSED_BUFSIZE + SWD_ZLIB_BUFSIZE;
12350
12351 swd_hdr *hdr = NULL;
12352 void *bufPtr = NULL;
12353
f427ee49 12354 OSSharedPtr<IOBufferMemoryDescriptor> memDesc;
0a7de745
A
12355
12356
12357 if (kIOSleepWakeWdogOff & gIOKitDebug) {
12358 return;
12359 }
12360
0a7de745
A
12361 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12362 return;
12363 }
12364
12365 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
12366 kernel_task, kIODirectionIn | kIOMemoryMapperNone,
12367 size);
12368 if (memDesc == NULL) {
12369 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
12370 goto exit;
12371 }
12372
12373 bufPtr = memDesc->getBytesNoCopy();
12374
12375 // Carve out memory for zlib routines
12376 swd_zs_zmem = (vm_offset_t)bufPtr;
12377 bufPtr = (char *)bufPtr + SWD_ZLIB_BUFSIZE;
12378
12379 // Carve out memory for compressed stackshots
12380 swd_compressed_buffer = bufPtr;
12381 bufPtr = (char *)bufPtr + SWD_COMPRESSED_BUFSIZE;
12382
12383 // Remaining is used for holding stackshot
12384 hdr = (swd_hdr *)bufPtr;
12385 memset(hdr, 0, sizeof(swd_hdr));
12386
12387 hdr->signature = SWD_HDR_SIGNATURE;
12388 hdr->alloc_size = SWD_STACKSHOT_SIZE;
12389
12390 hdr->spindump_offset = sizeof(swd_hdr);
12391 swd_buffer = (void *)hdr;
f427ee49 12392 swd_memDesc = os::move(memDesc);
0a7de745 12393 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
39236c6e
A
12394
12395exit:
0a7de745 12396 gRootDomain->swd_lock = 0;
39236c6e
A
12397}
12398
0a7de745
A
12399void
12400IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc()
3e170ce0 12401{
f427ee49 12402#if UNUSED
0a7de745 12403 vm_size_t size = SWD_SPINDUMP_SIZE;
3e170ce0 12404
0a7de745 12405 swd_hdr *hdr = NULL;
3e170ce0 12406
f427ee49 12407 OSSharedPtr<IOBufferMemoryDescriptor> memDesc;
3e170ce0 12408
0a7de745
A
12409 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) {
12410 return;
12411 }
3e170ce0 12412
0a7de745
A
12413 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
12414 kernel_task, kIODirectionIn | kIOMemoryMapperNone,
12415 SWD_SPINDUMP_SIZE);
3e170ce0 12416
0a7de745
A
12417 if (memDesc == NULL) {
12418 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
12419 goto exit;
12420 }
3e170ce0
A
12421
12422
0a7de745
A
12423 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
12424 memset(hdr, 0, sizeof(swd_hdr));
3e170ce0 12425
0a7de745
A
12426 hdr->signature = SWD_HDR_SIGNATURE;
12427 hdr->alloc_size = size;
3e170ce0 12428
0a7de745
A
12429 hdr->spindump_offset = sizeof(swd_hdr);
12430 swd_spindump_buffer = (void *)hdr;
f427ee49 12431 swd_spindump_memDesc = os::move(memDesc);
3e170ce0
A
12432
12433exit:
0a7de745 12434 gRootDomain->swd_lock = 0;
f427ee49 12435#endif /* UNUSED */
3e170ce0
A
12436}
12437
0a7de745
A
12438void
12439IOPMrootDomain::sleepWakeDebugEnableWdog()
39236c6e 12440{
39236c6e
A
12441}
12442
0a7de745
A
12443bool
12444IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
39236c6e 12445{
0a7de745 12446 return !systemBooting && !systemShutdown && !gWillShutdown;
3e170ce0
A
12447}
12448
0a7de745
A
12449void
12450IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
3e170ce0 12451{
0a7de745
A
12452 swd_hdr *hdr = NULL;
12453 errno_t error = EIO;
3e170ce0 12454
0a7de745
A
12455 if (swd_spindump_buffer && gSpinDumpBufferFull) {
12456 hdr = (swd_hdr *)swd_spindump_buffer;
3e170ce0 12457
0a7de745
A
12458 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
12459 (char*)hdr + hdr->spindump_offset, hdr->spindump_size);
3e170ce0 12460
0a7de745
A
12461 if (error) {
12462 return;
12463 }
3e170ce0 12464
0a7de745
A
12465 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
12466 (char*)hdr + offsetof(swd_hdr, UUID),
12467 sizeof(swd_hdr) - offsetof(swd_hdr, UUID));
3e170ce0 12468
0a7de745
A
12469 gSpinDumpBufferFull = false;
12470 }
39236c6e
A
12471}
12472
0a7de745
A
12473errno_t
12474IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
39236c6e 12475{
0a7de745
A
12476 struct vnode *vp = NULL;
12477 vfs_context_t ctx = vfs_context_create(vfs_context_current());
12478 kauth_cred_t cred = vfs_context_ucred(ctx);
12479 struct vnode_attr va;
12480 errno_t error = EIO;
39236c6e 12481
0a7de745
A
12482 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
12483 S_IRUSR | S_IRGRP | S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0) {
12484 LOG("Failed to open the file %s\n", name);
12485 swd_flags |= SWD_FILEOP_ERROR;
12486 goto exit;
12487 }
12488 VATTR_INIT(&va);
12489 VATTR_WANTED(&va, va_nlink);
12490 /* Don't dump to non-regular files or files with links. */
12491 if (vp->v_type != VREG ||
12492 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
12493 LOG("Bailing as this is not a regular file\n");
12494 swd_flags |= SWD_FILEOP_ERROR;
12495 goto exit;
12496 }
12497 VATTR_INIT(&va);
12498 VATTR_SET(&va, va_data_size, 0);
12499 vnode_setattr(vp, &va, ctx);
fe8ab488 12500
39236c6e 12501
0a7de745
A
12502 if (buf != NULL) {
12503 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
12504 UIO_SYSSPACE, IO_NODELOCKED | IO_UNIT, cred, (int *) NULL, vfs_context_proc(ctx));
12505 if (error != 0) {
12506 LOG("Failed to save sleep wake log. err 0x%x\n", error);
12507 swd_flags |= SWD_FILEOP_ERROR;
12508 } else {
12509 DLOG("Saved %d bytes to file %s\n", len, name);
12510 }
12511 }
39236c6e
A
12512
12513exit:
0a7de745
A
12514 if (vp) {
12515 vnode_close(vp, FWRITE, ctx);
12516 }
12517 if (ctx) {
12518 vfs_context_rele(ctx);
12519 }
fe8ab488 12520
0a7de745 12521 return error;
fe8ab488
A
12522}
12523
f427ee49 12524#else /* defined(__i386__) || defined(__x86_64__) */
39236c6e 12525
0a7de745
A
12526void
12527IOPMrootDomain::sleepWakeDebugTrig(bool restart)
39236c6e 12528{
0a7de745 12529 if (restart) {
cb323159 12530 if (gSwdPanic == 0) {
0a7de745
A
12531 return;
12532 }
12533 panic("Sleep/Wake hang detected");
12534 return;
12535 }
39236c6e
A
12536}
12537
0a7de745 12538void
cb323159 12539IOPMrootDomain::takeStackshot(bool restart)
39236c6e 12540{
fe8ab488 12541#pragma unused(restart)
39236c6e 12542}
f427ee49 12543
cb323159
A
12544void
12545IOPMrootDomain::deleteStackshot()
12546{
12547}
f427ee49 12548
0a7de745
A
12549void
12550IOPMrootDomain::sleepWakeDebugMemAlloc()
39236c6e
A
12551{
12552}
f427ee49 12553
0a7de745
A
12554void
12555IOPMrootDomain::saveFailureData2File()
39236c6e 12556{
39236c6e
A
12557}
12558
0a7de745
A
12559void
12560IOPMrootDomain::sleepWakeDebugEnableWdog()
39236c6e
A
12561{
12562}
12563
0a7de745
A
12564bool
12565IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
39236c6e 12566{
0a7de745 12567 return false;
39236c6e
A
12568}
12569
f427ee49
A
12570void
12571IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12572{
12573}
12574
0a7de745
A
12575errno_t
12576IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
39236c6e 12577{
0a7de745 12578 return 0;
39236c6e
A
12579}
12580
f427ee49 12581#endif /* defined(__i386__) || defined(__x86_64__) */
39236c6e 12582