2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOCPU.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOTimeStamp.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/pwr_mgt/IOPMPrivate.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOReturn.h>
44 #include <IOKit/IONVRAM.h>
45 #include "RootDomainUserClient.h"
46 #include "IOKit/pwr_mgt/IOPowerConnection.h"
47 #include "IOPMPowerStateQueue.h"
48 #include <IOKit/IOCatalogue.h>
49 #include <IOKit/IOReportMacros.h>
50 #include "IOKitKernelInternal.h"
52 #include <IOKit/IOHibernatePrivate.h>
54 #include <console/video_console.h>
55 #include <sys/syslog.h>
56 #include <sys/sysctl.h>
57 #include <sys/vnode.h>
58 #include <sys/vnode_internal.h>
59 #include <sys/fcntl.h>
62 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
63 #include "IOServicePMPrivate.h"
66 #include <mach/shared_region.h>
67 #include <kern/clock.h>
70 #if defined(__i386__) || defined(__x86_64__)
72 #include "IOPMrootDomainInternal.h"
76 #define kIOPMrootDomainClass "IOPMrootDomain"
77 #define LOG_PREFIX "PMRD: "
81 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
84 do { kprintf(LOG_PREFIX x); } while (false)
86 #define DLOG(x...) do { \
87 if (kIOLogPMRootDomain & gIOKitDebug) \
88 kprintf(LOG_PREFIX x); \
91 #define DMSG(x...) do { \
92 if (kIOLogPMRootDomain & gIOKitDebug) { \
93 kprintf(LOG_PREFIX x); IOLog(x); \
100 #define CHECK_THREAD_CONTEXT
101 #ifdef CHECK_THREAD_CONTEXT
102 static IOWorkLoop
* gIOPMWorkLoop
= 0;
103 #define ASSERT_GATED() \
105 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
106 panic("RootDomain: not inside PM gate"); \
110 #define ASSERT_GATED()
111 #endif /* CHECK_THREAD_CONTEXT */
113 #define CAP_LOSS(c) \
114 (((_pendingCapability & (c)) == 0) && \
115 ((_currentCapability & (c)) != 0))
117 #define CAP_GAIN(c) \
118 (((_currentCapability & (c)) == 0) && \
119 ((_pendingCapability & (c)) != 0))
121 #define CAP_CHANGE(c) \
122 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
124 #define CAP_CURRENT(c) \
125 ((_currentCapability & (c)) != 0)
127 #define CAP_HIGHEST(c) \
128 ((_highestCapability & (c)) != 0)
130 #if defined(__i386__) || defined(__x86_64__)
131 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
134 // Event types for IOPMPowerStateQueue::submitPowerEvent()
136 kPowerEventFeatureChanged
= 1, // 1
137 kPowerEventReceivedPowerNotification
, // 2
138 kPowerEventSystemBootCompleted
, // 3
139 kPowerEventSystemShutdown
, // 4
140 kPowerEventUserDisabledSleep
, // 5
141 kPowerEventRegisterSystemCapabilityClient
, // 6
142 kPowerEventRegisterKernelCapabilityClient
, // 7
143 kPowerEventPolicyStimulus
, // 8
144 kPowerEventAssertionCreate
, // 9
145 kPowerEventAssertionRelease
, // 10
146 kPowerEventAssertionSetLevel
, // 11
147 kPowerEventQueueSleepWakeUUID
, // 12
148 kPowerEventPublishSleepWakeUUID
, // 13
149 kPowerEventSetDisplayPowerOn
// 14
152 // For evaluatePolicy()
153 // List of stimuli that affects the root domain policy.
155 kStimulusDisplayWranglerSleep
, // 0
156 kStimulusDisplayWranglerWake
, // 1
157 kStimulusAggressivenessChanged
, // 2
158 kStimulusDemandSystemSleep
, // 3
159 kStimulusAllowSystemSleepChanged
, // 4
160 kStimulusDarkWakeActivityTickle
, // 5
161 kStimulusDarkWakeEntry
, // 6
162 kStimulusDarkWakeReentry
, // 7
163 kStimulusDarkWakeEvaluate
, // 8
164 kStimulusNoIdleSleepPreventers
, // 9
165 kStimulusEnterUserActiveState
, // 10
166 kStimulusLeaveUserActiveState
// 11
170 IOReturn
OSKextSystemSleepOrWake( UInt32
);
172 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
173 extern "C" addr64_t
kvtophys(vm_offset_t va
);
175 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
176 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
177 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
178 static void pmEventTimeStamp(uint64_t *recordTS
);
180 // "IOPMSetSleepSupported" callPlatformFunction name
181 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
182 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
184 #define kIOSleepSupportedKey "IOSleepSupported"
185 #define kIOPMSystemCapabilitiesKey "System Capabilities"
187 #define kIORequestWranglerIdleKey "IORequestIdle"
188 #define kDefaultWranglerIdlePeriod 25 // in milliseconds
190 #define kIOSleepWakeDebugKey "Persistent-memory-note"
191 #define kIOEFIBootRomFailureKey "wake-failure"
193 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
194 | kIOPMSupportedOnBatt \
195 | kIOPMSupportedOnUPS)
197 #define kLocalEvalClamshellCommand (1 << 15)
198 #define kIdleSleepRetryInterval (3 * 60)
201 kWranglerPowerStateMin
= 0,
202 kWranglerPowerStateSleep
= 2,
203 kWranglerPowerStateDim
= 3,
204 kWranglerPowerStateMax
= 4
215 #define ON_POWER kIOPMPowerOn
216 #define RESTART_POWER kIOPMRestart
217 #define SLEEP_POWER kIOPMAuxPowerOn
219 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
221 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
222 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
223 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
224 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
227 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
228 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
229 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
230 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
231 #define kIOPMRootDomainWakeTypeUser "User"
232 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
233 #define kIOPMRootDomainWakeTypeNetwork "Network"
234 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
235 #define kIOPMRootDomainWakeTypeNotification "Notification"
236 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
238 // Special interest that entitles the interested client from receiving
239 // all system messages. Only used by powerd.
241 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
243 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
244 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
249 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
250 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
252 #define kAggressivesMinValue 1
255 kAggressivesStateBusy
= 0x01,
256 kAggressivesStateQuickSpindown
= 0x02
259 struct AggressivesRecord
{
265 struct AggressivesRequest
{
271 AggressivesRecord record
;
276 kAggressivesRequestTypeService
= 1,
277 kAggressivesRequestTypeRecord
281 kAggressivesOptionSynchronous
= 0x00000001,
282 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
283 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
284 kAggressivesOptionQuickSpindownMask
= 0x00000300
288 kAggressivesRecordFlagModified
= 0x00000001,
289 kAggressivesRecordFlagMinValue
= 0x00000002
294 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
295 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
296 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
297 kDarkWakeFlagHIDTickleMask
= 0x03,
298 kDarkWakeFlagAlarmIsDark
= 0x0100,
299 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
300 kDarkWakeFlagAudioNotSuppressed
= 0x0400
303 static IOPMrootDomain
* gRootDomain
;
304 static IONotifier
* gSysPowerDownNotifier
= 0;
305 static UInt32 gSleepOrShutdownPending
= 0;
306 static UInt32 gWillShutdown
= 0;
307 static UInt32 gPagingOff
= 0;
308 static UInt32 gSleepWakeUUIDIsSet
= false;
309 static uint32_t gAggressivesState
= 0;
311 uuid_string_t bootsessionuuid_string
;
313 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
314 static uint32_t gNoIdleFlag
= 0;
315 static PMStatsStruct gPMStats
;
318 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
319 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
320 static void * gSleepPolicyTarget
;
323 struct timeval gIOLastSleepTime
;
324 struct timeval gIOLastWakeTime
;
326 static char gWakeReasonString
[128];
327 static bool gWakeReasonSysctlRegistered
= false;
328 static AbsoluteTime gIOLastWakeAbsTime
;
329 static AbsoluteTime gIOLastSleepAbsTime
;
331 #if defined(__i386__) || defined(__x86_64__)
332 static bool gSpinDumpBufferFull
= false;
335 static unsigned int gPMHaltBusyCount
;
336 static unsigned int gPMHaltIdleCount
;
337 static int gPMHaltDepth
;
338 static uint32_t gPMHaltMessageType
;
339 static IOLock
* gPMHaltLock
= 0;
340 static OSArray
* gPMHaltArray
= 0;
341 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
342 static bool gPMQuiesced
;
344 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
345 #define kCPUUnknownIndex 9999999
352 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
353 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
354 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
355 const OSSymbol
*gIOPMStatsApplicationResponsePrompt
;
356 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
358 #define kBadPMFeatureID 0
362 * Opaque handle passed to clients of registerPMSettingController()
364 class PMSettingHandle
: public OSObject
366 OSDeclareFinalStructors( PMSettingHandle
)
367 friend class PMSettingObject
;
370 PMSettingObject
*pmso
;
371 void free(void) APPLE_KEXT_OVERRIDE
;
376 * Internal object to track each PM setting controller
378 class PMSettingObject
: public OSObject
380 OSDeclareFinalStructors( PMSettingObject
)
381 friend class IOPMrootDomain
;
384 queue_head_t calloutQueue
;
386 IOPMrootDomain
*parent
;
387 PMSettingHandle
*pmsh
;
388 IOPMSettingControllerCallback func
;
391 uint32_t *publishedFeatureID
;
392 uint32_t settingCount
;
395 void free(void) APPLE_KEXT_OVERRIDE
;
398 static PMSettingObject
*pmSettingObject(
399 IOPMrootDomain
*parent_arg
,
400 IOPMSettingControllerCallback handler_arg
,
401 OSObject
*target_arg
,
402 uintptr_t refcon_arg
,
403 uint32_t supportedPowerSources
,
404 const OSSymbol
*settings
[],
405 OSObject
**handle_obj
);
407 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
408 void clientHandleFreed(void);
411 struct PMSettingCallEntry
{
416 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
417 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
418 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
419 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
423 * Internal helper object for logging trace points to RTC
424 * IOPMrootDomain and only IOPMrootDomain should instantiate
425 * exactly one of these.
428 typedef void (*IOPMTracePointHandler
)(
429 void * target
, uint32_t code
, uint32_t data
);
431 class PMTraceWorker
: public OSObject
433 OSDeclareDefaultStructors(PMTraceWorker
)
435 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
437 static PMTraceWorker
*tracer( IOPMrootDomain
* );
438 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
439 void tracePoint(uint8_t phase
);
440 void traceDetail(uint32_t detail
);
441 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
442 int recordTopLevelPCIDevice(IOService
*);
443 void RTC_TRACE(void);
444 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
446 IOPMTracePointHandler tracePointHandler
;
447 void * tracePointTarget
;
448 uint64_t getPMStatusCode();
449 uint8_t getTracePhase();
450 uint32_t getTraceData();
452 IOPMrootDomain
*owner
;
453 IOLock
*pmTraceWorkerLock
;
454 OSArray
*pciDeviceBitMappings
;
456 uint8_t addedToRegistry
;
458 uint32_t traceData32
;
459 uint8_t loginWindowData
;
460 uint8_t coreDisplayData
;
461 uint8_t coreGraphicsData
;
465 * PMAssertionsTracker
466 * Tracks kernel and user space PM assertions
468 class PMAssertionsTracker
: public OSObject
470 OSDeclareFinalStructors(PMAssertionsTracker
)
472 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
474 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
475 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
476 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
477 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
479 OSArray
*copyAssertionsArray(void);
480 IOPMDriverAssertionType
getActivatedAssertions(void);
481 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
483 IOReturn
handleCreateAssertion(OSData
*);
484 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
485 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
486 IOReturn
handleSetUserAssertionLevels(void * arg0
);
487 void publishProperties(void);
491 IOPMDriverAssertionID id
;
492 IOPMDriverAssertionType assertionBits
;
493 uint64_t createdTime
;
494 uint64_t modifiedTime
;
495 const OSSymbol
*ownerString
;
496 IOService
*ownerService
;
497 uint64_t registryEntryID
;
498 IOPMDriverAssertionLevel level
;
501 uint32_t tabulateProducerCount
;
502 uint32_t tabulateConsumerCount
;
504 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
507 IOPMrootDomain
*owner
;
508 OSArray
*assertionsArray
;
509 IOLock
*assertionsArrayLock
;
510 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
511 IOPMDriverAssertionType assertionsKernel
;
512 IOPMDriverAssertionType assertionsUser
;
513 IOPMDriverAssertionType assertionsCombined
;
516 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
520 * Internal helper object for Shutdown/Restart notifications.
522 #define kPMHaltMaxWorkers 8
523 #define kPMHaltTimeoutMS 100
525 class PMHaltWorker
: public OSObject
527 OSDeclareFinalStructors( PMHaltWorker
)
530 IOService
* service
; // service being worked on
531 AbsoluteTime startTime
; // time when work started
532 int depth
; // work on nubs at this PM-tree depth
533 int visits
; // number of nodes visited (debug)
535 bool timeout
; // service took too long
537 static PMHaltWorker
* worker( void );
538 static void main( void * arg
, wait_result_t waitResult
);
539 static void work( PMHaltWorker
* me
);
540 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
541 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
544 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
547 #define super IOService
548 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
550 static void IOPMRootDomainWillShutdown(void)
552 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
554 OSKext::willShutdown();
555 for (int i
= 0; i
< 100; i
++)
557 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
565 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
567 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
570 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
572 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
575 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
577 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
580 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
582 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
585 IOReturn
rootDomainRestart ( void )
587 return gRootDomain
->restartSystem();
590 IOReturn
rootDomainShutdown ( void )
592 return gRootDomain
->shutdownSystem();
595 void IOSystemShutdownNotification(void)
597 IOPMRootDomainWillShutdown();
599 IOHibernateSystemPostWake();
601 if (OSCompareAndSwap(0, 1, &gPagingOff
))
603 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
607 int sync_internal(void);
611 A device is always in the highest power state which satisfies its driver,
612 its policy-maker, and any power children it has, but within the constraint
613 of the power state provided by its parent. The driver expresses its desire by
614 calling changePowerStateTo(), the policy-maker expresses its desire by calling
615 changePowerStateToPriv(), and the children express their desires by calling
616 requestPowerDomainState().
618 The Root Power Domain owns the policy for idle and demand sleep for the system.
619 It is a power-managed IOService just like the others in the system.
620 It implements several power states which map to what we see as Sleep and On.
622 The sleep policy is as follows:
623 1. Sleep is prevented if the case is open so that nobody will think the machine
624 is off and plug/unplug cards.
625 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
626 3. System cannot Sleep if some object in the tree is in a power state marked
627 kIOPMPreventSystemSleep.
629 These three conditions are enforced using the "driver clamp" by calling
630 changePowerStateTo(). For example, if the case is opened,
631 changePowerStateTo(ON_STATE) is called to hold the system on regardless
632 of the desires of the children of the root or the state of the other clamp.
634 Demand Sleep is initiated by pressing the front panel power button, closing
635 the clamshell, or selecting the menu item. In this case the root's parent
636 actually initiates the power state change so that the root domain has no
637 choice and does not give applications the opportunity to veto the change.
639 Idle Sleep occurs if no objects in the tree are in a state marked
640 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
641 the root on, so it sets the "policy-maker clamp" by calling
642 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
643 This timer is set for the difference between the sleep timeout slider and the
644 display dim timeout slider. When the timer expires, it releases its clamp and
645 now nothing is holding it awake, so it falls asleep.
647 Demand sleep is prevented when the system is booting. When preferences are
648 transmitted by the loginwindow at the end of boot, a flag is cleared,
649 and this allows subsequent Demand Sleep.
652 //******************************************************************************
654 IOPMrootDomain
* IOPMrootDomain::construct( void )
656 IOPMrootDomain
*root
;
658 root
= new IOPMrootDomain
;
665 //******************************************************************************
666 // updateConsoleUsersCallout
668 //******************************************************************************
670 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
672 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
673 rootDomain
->updateConsoleUsers();
676 void IOPMrootDomain::updateConsoleUsers(void)
678 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
681 tasksSuspended
= FALSE
;
682 tasks_system_suspend(tasksSuspended
);
686 //******************************************************************************
688 static void swdDebugSetupCallout( thread_call_param_t p0
, thread_call_param_t p1
)
690 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
691 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
693 rootDomain
->swdDebugSetup();
696 rootDomain
->allowPowerChange(notifyRef
);
698 DLOG("swdDebugSetupCallout finish\n");
701 void IOPMrootDomain::swdDebugSetup( )
704 static int32_t mem_only
= -1;
705 if ((mem_only
== -1) &&
706 (PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
)) == false)) {
710 if ((mem_only
== 1) || (gRootDomain
->sleepWakeDebugIsWdogEnabled() == false)) {
713 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup
);
714 if (swd_DebugImageSetup
== FALSE
) {
715 swd_DebugImageSetup
= TRUE
;
716 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
723 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
725 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
726 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
728 rootDomain
->swdDebugTeardown();
730 rootDomain
->allowPowerChange(notifyRef
);
732 DLOG("swdDebugTeardownCallout finish\n");
735 void IOPMrootDomain::swdDebugTeardown( )
739 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
740 if (swd_DebugImageSetup
== TRUE
) {
741 swd_DebugImageSetup
= FALSE
;
742 IOCloseDebugDataFile();
748 //******************************************************************************
751 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
753 IOService
* rootDomain
= (IOService
*) p0
;
754 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
755 uint32_t powerState
= rootDomain
->getPowerState();
757 DLOG("disk_sync_callout ps=%u\n", powerState
);
759 if (ON_STATE
== powerState
)
762 swdDebugSetupCallout(p0
, NULL
);
767 swdDebugTeardownCallout(p0
, NULL
);
768 IOHibernateSystemPostWake();
771 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
775 rootDomain
->allowPowerChange(notifyRef
);
776 DLOG("disk_sync_callout finish\n");
779 //******************************************************************************
780 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
782 AbsoluteTime endTime
;
785 clock_get_uptime(&endTime
);
786 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
788 SUB_ABSOLUTETIME(&endTime
, startTime
);
789 absolutetime_to_nanoseconds(endTime
, &nano
);
792 return (UInt32
)(nano
/ 1000000ULL);
795 //******************************************************************************
798 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
800 struct timeval
*swt
= (struct timeval
*)arg1
;
801 struct proc
*p
= req
->p
;
804 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
805 } else if(proc_is64bit(p
)) {
806 struct user64_timeval t
;
807 t
.tv_sec
= swt
->tv_sec
;
808 t
.tv_usec
= swt
->tv_usec
;
809 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
811 struct user32_timeval t
;
812 t
.tv_sec
= swt
->tv_sec
;
813 t
.tv_usec
= swt
->tv_usec
;
814 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
818 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
819 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
820 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
822 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
823 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
824 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
826 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
827 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
831 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
833 int new_value
, changed
;
834 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
836 if (!gWillShutdown
&& (new_value
== 1)) {
837 IOPMRootDomainWillShutdown();
844 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
845 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
846 0, 0, sysctl_willshutdown
, "I", "");
848 extern struct sysctl_oid sysctl__kern_iokittest
;
852 sysctl_progressmeterenable
853 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
856 int new_value
, changed
;
858 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
860 if (changed
) vc_enable_progressmeter(new_value
);
867 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
870 int new_value
, changed
;
872 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
874 if (changed
) vc_set_progressmeter(new_value
);
879 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
880 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
881 0, 0, sysctl_progressmeterenable
, "I", "");
883 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
884 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
885 0, 0, sysctl_progressmeter
, "I", "");
891 sysctl_consoleoptions
892 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
897 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
899 if (changed
) vc_user_options
.options
= new_value
;
904 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
905 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
906 0, 0, sysctl_consoleoptions
, "I", "");
910 sysctl_progressoptions SYSCTL_HANDLER_ARGS
912 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
915 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
916 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
917 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
921 sysctl_wakereason SYSCTL_HANDLER_ARGS
923 char wr
[ sizeof(gWakeReasonString
) ];
927 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
929 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
932 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
933 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
934 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
937 sysctl_targettype SYSCTL_HANDLER_ARGS
945 root
= IOService::getServiceRoot();
946 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
948 if ((data
= OSDynamicCast(OSData
, obj
)))
950 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
954 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
957 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
958 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
959 NULL
, 0, sysctl_targettype
, "A", "targettype");
961 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
962 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
964 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
965 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
966 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
967 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
968 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
969 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
970 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
971 static const OSSymbol
* gIOPMUserIsActiveKey
;
973 //******************************************************************************
976 //******************************************************************************
978 #define kRootDomainSettingsCount 17
980 bool IOPMrootDomain::start( IOService
* nub
)
982 OSIterator
*psIterator
;
983 OSDictionary
*tmpDict
;
984 IORootParent
* patriarch
;
985 #if defined(__i386__) || defined(__x86_64__)
986 IONotifier
* notifier
;
992 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
993 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
994 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
995 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
996 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
997 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
998 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
999 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1001 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1002 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1003 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1004 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1005 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1007 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1008 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1010 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1012 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1013 gIOPMSettingAutoWakeSecondsKey
,
1014 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1015 gIOPMSettingAutoWakeCalendarKey
,
1016 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1017 gIOPMSettingDebugWakeRelativeKey
,
1018 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1019 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1020 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1021 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1022 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1023 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1024 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1025 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1026 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1027 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1028 gIOPMSettingSilentRunningKey
1031 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1032 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1034 queue_init(&aggressivesQueue
);
1035 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1036 aggressivesData
= OSData::withCapacity(
1037 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1039 featuresDictLock
= IOLockAlloc();
1040 settingsCtrlLock
= IOLockAlloc();
1041 wakeEventLock
= IOLockAlloc();
1042 setPMRootDomain(this);
1044 extraSleepTimer
= thread_call_allocate(
1045 idleSleepTimerExpired
,
1046 (thread_call_param_t
) this);
1048 diskSyncCalloutEntry
= thread_call_allocate(
1050 (thread_call_param_t
) this);
1051 swdDebugSetupEntry
= thread_call_allocate(
1052 &swdDebugSetupCallout
,
1053 (thread_call_param_t
) this);
1054 swdDebugTearDownEntry
= thread_call_allocate(
1055 &swdDebugTeardownCallout
,
1056 (thread_call_param_t
) this);
1057 updateConsoleUsersEntry
= thread_call_allocate(
1058 &updateConsoleUsersCallout
,
1059 (thread_call_param_t
) this);
1061 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1062 fullWakeThreadCall
= thread_call_allocate(
1063 OSMemberFunctionCast(thread_call_func_t
, this,
1064 &IOPMrootDomain::fullWakeDelayedWork
),
1065 (thread_call_param_t
) this);
1068 setProperty(kIOSleepSupportedKey
, true);
1070 bzero(&gPMStats
, sizeof(gPMStats
));
1072 pmTracer
= PMTraceWorker::tracer(this);
1074 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1076 userDisabledAllSleep
= false;
1077 systemBooting
= true;
1079 idleSleepTimerPending
= false;
1081 clamshellClosed
= false;
1082 clamshellExists
= false;
1083 clamshellDisabled
= true;
1084 acAdaptorConnected
= true;
1085 clamshellSleepDisabled
= false;
1086 gWakeReasonString
[0] = '\0';
1088 // Initialize to user active.
1089 // Will never transition to user inactive w/o wrangler.
1090 fullWakeReason
= kFullWakeReasonLocalUser
;
1091 userIsActive
= userWasActive
= true;
1092 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1094 // Set the default system capabilities at boot.
1095 _currentCapability
= kIOPMSystemCapabilityCPU
|
1096 kIOPMSystemCapabilityGraphics
|
1097 kIOPMSystemCapabilityAudio
|
1098 kIOPMSystemCapabilityNetwork
;
1100 _pendingCapability
= _currentCapability
;
1101 _desiredCapability
= _currentCapability
;
1102 _highestCapability
= _currentCapability
;
1103 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1105 queuedSleepWakeUUIDString
= NULL
;
1106 initializeBootSessionUUID();
1107 pmStatsAppResponses
= OSArray::withCapacity(5);
1108 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1109 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1110 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1111 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1112 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1113 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1114 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1116 pmStatsLock
= IOLockAlloc();
1117 idxPMCPUClamshell
= kCPUUnknownIndex
;
1118 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1120 tmpDict
= OSDictionary::withCapacity(1);
1121 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1124 settingsCallbacks
= OSDictionary::withCapacity(1);
1126 // Create a list of the valid PM settings that we'll relay to
1127 // interested clients in setProperties() => setPMSetting()
1128 allowedPMSettings
= OSArray::withObjects(
1129 (const OSObject
**)settingsArr
,
1130 kRootDomainSettingsCount
,
1133 // List of PM settings that should not automatically publish itself
1134 // as a feature when registered by a listener.
1135 noPublishPMSettings
= OSArray::withObjects(
1136 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1138 fPMSettingsDict
= OSDictionary::withCapacity(5);
1139 preventIdleSleepList
= OSSet::withCapacity(8);
1140 preventSystemSleepList
= OSSet::withCapacity(2);
1142 PMinit(); // creates gIOPMWorkLoop
1143 gIOPMWorkLoop
= getIOPMWorkloop();
1145 // Create IOPMPowerStateQueue used to queue external power
1146 // events, and to handle those events on the PM work loop.
1147 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1148 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1149 &IOPMrootDomain::dispatchPowerEvent
));
1150 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1152 // create our power parent
1153 patriarch
= new IORootParent
;
1155 patriarch
->attach(this);
1156 patriarch
->start(this);
1157 patriarch
->addPowerChild(this);
1159 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1160 changePowerStateToPriv(ON_STATE
);
1162 // install power change handler
1163 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1166 // Register for a notification when IODisplayWrangler is published
1167 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1169 _displayWranglerNotifier
= addMatchingNotification(
1170 gIOPublishNotification
, tmpDict
,
1171 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1177 #if defined(__i386__) || defined(__x86_64__)
1179 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1181 notifier
= addMatchingNotification(
1182 gIOFirstPublishNotification
, tmpDict
,
1183 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1188 wranglerIdleSettings
= NULL
;
1189 OSNumber
* wranglerIdlePeriod
= NULL
;
1190 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1191 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1193 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1194 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1195 wranglerIdlePeriod
);
1197 if(wranglerIdlePeriod
)
1198 wranglerIdlePeriod
->release();
1201 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1202 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1203 ucClassName
->release();
1205 // IOBacklightDisplay can take a long time to load at boot, or it may
1206 // not load at all if you're booting with clamshell closed. We publish
1207 // 'DisplayDims' here redundantly to get it published early and at all.
1208 OSDictionary
* matching
;
1209 matching
= serviceMatching("IOPMPowerSource");
1210 psIterator
= getMatchingServices( matching
);
1211 if (matching
) matching
->release();
1212 if( psIterator
&& psIterator
->getNextObject() )
1214 // There's at least one battery on the system, so we publish
1215 // 'DisplayDims' support for the LCD.
1216 publishFeature("DisplayDims");
1219 psIterator
->release();
1222 sysctl_register_oid(&sysctl__kern_sleeptime
);
1223 sysctl_register_oid(&sysctl__kern_waketime
);
1224 sysctl_register_oid(&sysctl__kern_willshutdown
);
1225 sysctl_register_oid(&sysctl__kern_iokittest
);
1226 sysctl_register_oid(&sysctl__hw_targettype
);
1228 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1229 sysctl_register_oid(&sysctl__kern_progressmeter
);
1230 sysctl_register_oid(&sysctl__kern_wakereason
);
1231 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1232 sysctl_register_oid(&sysctl__kern_progressoptions
);
1235 IOHibernateSystemInit(this);
1238 registerService(); // let clients find us
1243 //******************************************************************************
1246 // Receive a setProperty call
1247 // The "System Boot" property means the system is completely booted.
1248 //******************************************************************************
1250 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1252 IOReturn return_value
= kIOReturnSuccess
;
1253 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1256 const OSSymbol
*key
;
1258 OSCollectionIterator
* iter
= 0;
1260 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1261 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1262 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1263 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1264 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1265 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1266 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1267 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1268 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1269 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1270 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1272 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1273 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1274 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1275 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1276 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1277 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1282 return_value
= kIOReturnBadArgument
;
1286 iter
= OSCollectionIterator::withCollection(dict
);
1289 return_value
= kIOReturnNoMemory
;
1293 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1294 (obj
= dict
->getObject(key
)))
1296 if (key
->isEqualTo(publish_simulated_battery_string
))
1298 if (OSDynamicCast(OSBoolean
, obj
))
1299 publishResource(key
, kOSBooleanTrue
);
1301 else if (key
->isEqualTo(idle_seconds_string
))
1303 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1305 setProperty(key
, n
);
1306 idleSeconds
= n
->unsigned32BitValue();
1309 else if (key
->isEqualTo(boot_complete_string
))
1311 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1313 else if (key
->isEqualTo(sys_shutdown_string
))
1315 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1316 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1318 else if (key
->isEqualTo(battery_warning_disabled_string
))
1320 setProperty(key
, obj
);
1323 else if (key
->isEqualTo(hibernatemode_string
) ||
1324 key
->isEqualTo(hibernatefilemin_string
) ||
1325 key
->isEqualTo(hibernatefilemax_string
) ||
1326 key
->isEqualTo(hibernatefreeratio_string
) ||
1327 key
->isEqualTo(hibernatefreetime_string
))
1329 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1330 setProperty(key
, n
);
1332 else if (key
->isEqualTo(hibernatefile_string
))
1334 OSString
* str
= OSDynamicCast(OSString
, obj
);
1335 if (str
) setProperty(key
, str
);
1338 else if (key
->isEqualTo(sleepdisabled_string
))
1340 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1342 setProperty(key
, b
);
1343 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1346 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1349 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1351 else if (key
->isEqualTo(loginwindow_progress_string
))
1353 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1354 uint32_t data
= n
->unsigned32BitValue();
1355 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1356 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1359 else if (key
->isEqualTo(coredisplay_progress_string
))
1361 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1362 uint32_t data
= n
->unsigned32BitValue();
1363 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1364 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1367 else if (key
->isEqualTo(coregraphics_progress_string
))
1369 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1370 uint32_t data
= n
->unsigned32BitValue();
1371 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1372 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1375 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1376 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1377 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1378 key
->isEqualTo(stall_halt_string
))
1380 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1381 setProperty(key
, b
);
1383 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1384 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1385 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1387 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1388 setProperty(key
, n
);
1390 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1392 if (kOSBooleanTrue
== obj
)
1393 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1395 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1396 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1399 // Relay our allowed PM settings onto our registered PM clients
1400 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1402 return_value
= setPMSetting(key
, obj
);
1403 if (kIOReturnSuccess
!= return_value
)
1406 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1408 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1409 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1411 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1415 _debugWakeSeconds
= 0;
1416 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1418 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1420 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1423 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1424 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1426 const IOPMCalendarStruct
* cs
=
1427 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1430 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1432 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1433 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1439 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1444 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1445 if(boot_complete_string
) boot_complete_string
->release();
1446 if(sys_shutdown_string
) sys_shutdown_string
->release();
1447 if(stall_halt_string
) stall_halt_string
->release();
1448 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1449 if(idle_seconds_string
) idle_seconds_string
->release();
1450 if(sleepdisabled_string
) sleepdisabled_string
->release();
1451 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1452 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1453 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1454 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1456 if(hibernatemode_string
) hibernatemode_string
->release();
1457 if(hibernatefile_string
) hibernatefile_string
->release();
1458 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1459 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1461 if (iter
) iter
->release();
1462 return return_value
;
1466 // MARK: Aggressiveness
1468 //******************************************************************************
1469 // setAggressiveness
1471 // Override IOService::setAggressiveness()
1472 //******************************************************************************
1474 IOReturn
IOPMrootDomain::setAggressiveness(
1476 unsigned long value
)
1478 return setAggressiveness( type
, value
, 0 );
1482 * Private setAggressiveness() with an internal options argument.
1484 IOReturn
IOPMrootDomain::setAggressiveness(
1486 unsigned long value
,
1487 IOOptionBits options
)
1489 AggressivesRequest
* entry
;
1490 AggressivesRequest
* request
;
1493 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1494 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1496 request
= IONew(AggressivesRequest
, 1);
1498 return kIOReturnNoMemory
;
1500 memset(request
, 0, sizeof(*request
));
1501 request
->options
= options
;
1502 request
->dataType
= kAggressivesRequestTypeRecord
;
1503 request
->data
.record
.type
= (uint32_t) type
;
1504 request
->data
.record
.value
= (uint32_t) value
;
1508 // Update disk quick spindown flag used by getAggressiveness().
1509 // Never merge requests with quick spindown flags set.
1511 if (options
& kAggressivesOptionQuickSpindownEnable
)
1512 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1513 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1514 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1517 // Coalesce requests with identical aggressives types.
1518 // Deal with callers that calls us too "aggressively".
1520 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1522 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1523 (entry
->data
.record
.type
== type
) &&
1524 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1526 entry
->data
.record
.value
= value
;
1535 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1538 AGGRESSIVES_UNLOCK();
1541 IODelete(request
, AggressivesRequest
, 1);
1543 if (options
& kAggressivesOptionSynchronous
)
1544 handleAggressivesRequests(); // not truly synchronous
1546 thread_call_enter(aggressivesThreadCall
);
1548 return kIOReturnSuccess
;
1551 //******************************************************************************
1552 // getAggressiveness
1554 // Override IOService::setAggressiveness()
1555 // Fetch the aggressiveness factor with the given type.
1556 //******************************************************************************
1558 IOReturn
IOPMrootDomain::getAggressiveness (
1560 unsigned long * outLevel
)
1566 return kIOReturnBadArgument
;
1570 // Disk quick spindown in effect, report value = 1
1572 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1573 (type
== kPMMinutesToSpinDown
))
1575 value
= kAggressivesMinValue
;
1579 // Consult the pending request queue.
1583 AggressivesRequest
* entry
;
1585 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1587 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1588 (entry
->data
.record
.type
== type
) &&
1589 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1591 value
= entry
->data
.record
.value
;
1598 // Consult the backend records.
1600 if (!source
&& aggressivesData
)
1602 AggressivesRecord
* record
;
1605 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1606 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1608 for (i
= 0; i
< count
; i
++, record
++)
1610 if (record
->type
== type
)
1612 value
= record
->value
;
1619 AGGRESSIVES_UNLOCK();
1623 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1624 source
, (uint32_t) type
, value
);
1625 *outLevel
= (unsigned long) value
;
1626 return kIOReturnSuccess
;
1630 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1631 *outLevel
= 0; // default return = 0, driver may not check for error
1632 return kIOReturnInvalid
;
1636 //******************************************************************************
1637 // joinAggressiveness
1639 // Request from IOService to join future aggressiveness broadcasts.
1640 //******************************************************************************
1642 IOReturn
IOPMrootDomain::joinAggressiveness(
1643 IOService
* service
)
1645 AggressivesRequest
* request
;
1647 if (!service
|| (service
== this))
1648 return kIOReturnBadArgument
;
1650 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1652 request
= IONew(AggressivesRequest
, 1);
1654 return kIOReturnNoMemory
;
1656 service
->retain(); // released by synchronizeAggressives()
1658 memset(request
, 0, sizeof(*request
));
1659 request
->dataType
= kAggressivesRequestTypeService
;
1660 request
->data
.service
= service
;
1663 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1664 AGGRESSIVES_UNLOCK();
1666 thread_call_enter(aggressivesThreadCall
);
1668 return kIOReturnSuccess
;
1671 //******************************************************************************
1672 // handleAggressivesRequests
1674 // Backend thread processes all incoming aggressiveness requests in the queue.
1675 //******************************************************************************
1678 handleAggressivesFunction(
1679 thread_call_param_t param1
,
1680 thread_call_param_t param2
)
1684 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1688 void IOPMrootDomain::handleAggressivesRequests( void )
1690 AggressivesRecord
* start
;
1691 AggressivesRecord
* record
;
1692 AggressivesRequest
* request
;
1693 queue_head_t joinedQueue
;
1697 bool pingSelf
= false;
1701 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1702 queue_empty(&aggressivesQueue
))
1705 gAggressivesState
|= kAggressivesStateBusy
;
1706 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1707 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1712 queue_init(&joinedQueue
);
1716 // Remove request from the incoming queue in FIFO order.
1717 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1718 switch (request
->dataType
)
1720 case kAggressivesRequestTypeRecord
:
1721 // Update existing record if found.
1723 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1725 if (record
->type
== request
->data
.record
.type
)
1729 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1731 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1734 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1735 kAggressivesRecordFlagModified
);
1736 DLOG("disk spindown accelerated, was %u min\n",
1740 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1742 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1745 record
->flags
|= kAggressivesRecordFlagModified
;
1746 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1747 DLOG("disk spindown restored to %u min\n",
1751 else if (record
->value
!= request
->data
.record
.value
)
1753 record
->value
= request
->data
.record
.value
;
1754 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1757 record
->flags
|= kAggressivesRecordFlagModified
;
1764 // No matching record, append a new record.
1766 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1768 AggressivesRecord newRecord
;
1770 newRecord
.flags
= kAggressivesRecordFlagModified
;
1771 newRecord
.type
= request
->data
.record
.type
;
1772 newRecord
.value
= request
->data
.record
.value
;
1773 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1775 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1776 DLOG("disk spindown accelerated\n");
1779 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1781 // OSData may have switched to another (larger) buffer.
1782 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1783 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1787 // Finished processing the request, release it.
1788 IODelete(request
, AggressivesRequest
, 1);
1791 case kAggressivesRequestTypeService
:
1792 // synchronizeAggressives() will free request.
1793 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1797 panic("bad aggressives request type %x\n", request
->dataType
);
1800 } while (!queue_empty(&aggressivesQueue
));
1802 // Release the lock to perform work, with busy flag set.
1803 if (!queue_empty(&joinedQueue
) || broadcast
)
1805 AGGRESSIVES_UNLOCK();
1806 if (!queue_empty(&joinedQueue
))
1807 synchronizeAggressives(&joinedQueue
, start
, count
);
1809 broadcastAggressives(start
, count
);
1813 // Remove the modified flag from all records.
1814 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1816 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1817 ((record
->type
== kPMMinutesToDim
) ||
1818 (record
->type
== kPMMinutesToSleep
)))
1821 record
->flags
&= ~kAggressivesRecordFlagModified
;
1824 // Check the incoming queue again since new entries may have been
1825 // added while lock was released above.
1827 } while (!queue_empty(&aggressivesQueue
));
1829 gAggressivesState
&= ~kAggressivesStateBusy
;
1832 AGGRESSIVES_UNLOCK();
1834 // Root domain is interested in system and display sleep slider changes.
1835 // Submit a power event to handle those changes on the PM work loop.
1837 if (pingSelf
&& pmPowerStateQueue
) {
1838 pmPowerStateQueue
->submitPowerEvent(
1839 kPowerEventPolicyStimulus
,
1840 (void *) kStimulusAggressivenessChanged
);
1844 //******************************************************************************
1845 // synchronizeAggressives
1847 // Push all known aggressiveness records to one or more IOService.
1848 //******************************************************************************
1850 void IOPMrootDomain::synchronizeAggressives(
1851 queue_head_t
* joinedQueue
,
1852 const AggressivesRecord
* array
,
1855 IOService
* service
;
1856 AggressivesRequest
* request
;
1857 const AggressivesRecord
* record
;
1858 IOPMDriverCallEntry callEntry
;
1862 while (!queue_empty(joinedQueue
))
1864 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1865 if (request
->dataType
== kAggressivesRequestTypeService
)
1866 service
= request
->data
.service
;
1870 IODelete(request
, AggressivesRequest
, 1);
1875 if (service
->assertPMDriverCall(&callEntry
))
1877 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1879 value
= record
->value
;
1880 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1881 value
= kAggressivesMinValue
;
1883 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1884 record
->type
, value
, service
->getName());
1885 service
->setAggressiveness(record
->type
, value
);
1887 service
->deassertPMDriverCall(&callEntry
);
1889 service
->release(); // retained by joinAggressiveness()
1894 //******************************************************************************
1895 // broadcastAggressives
1897 // Traverse PM tree and call setAggressiveness() for records that have changed.
1898 //******************************************************************************
1900 void IOPMrootDomain::broadcastAggressives(
1901 const AggressivesRecord
* array
,
1904 IORegistryIterator
* iter
;
1905 IORegistryEntry
* entry
;
1906 IOPowerConnection
* connect
;
1907 IOService
* service
;
1908 const AggressivesRecord
* record
;
1909 IOPMDriverCallEntry callEntry
;
1913 iter
= IORegistryIterator::iterateOver(
1914 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1920 while ((entry
= iter
->getNextObject()))
1922 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1923 if (!connect
|| !connect
->getReadyFlag())
1926 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
1928 if (service
->assertPMDriverCall(&callEntry
))
1930 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1932 if (record
->flags
& kAggressivesRecordFlagModified
)
1934 value
= record
->value
;
1935 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1936 value
= kAggressivesMinValue
;
1937 _LOG("broadcastAggressives %x = %u to %s\n",
1938 record
->type
, value
, service
->getName());
1939 service
->setAggressiveness(record
->type
, value
);
1942 service
->deassertPMDriverCall(&callEntry
);
1948 while (!entry
&& !iter
->isValid());
1954 // MARK: System Sleep
1956 //******************************************************************************
1957 // startIdleSleepTimer
1959 //******************************************************************************
1961 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1963 AbsoluteTime deadline
;
1967 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
1972 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1973 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1974 idleSleepTimerPending
= true;
1978 thread_call_enter(extraSleepTimer
);
1980 DLOG("idle timer set for %u seconds\n", inSeconds
);
1983 //******************************************************************************
1984 // cancelIdleSleepTimer
1986 //******************************************************************************
1988 void IOPMrootDomain::cancelIdleSleepTimer( void )
1991 if (idleSleepTimerPending
)
1993 DLOG("idle timer cancelled\n");
1994 thread_call_cancel(extraSleepTimer
);
1995 idleSleepTimerPending
= false;
1997 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
1999 clock_usec_t microsecs
;
2000 clock_get_uptime(&now
);
2001 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2002 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2003 if (assertOnWakeReport
) {
2004 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2005 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2011 //******************************************************************************
2012 // idleSleepTimerExpired
2014 //******************************************************************************
2016 static void idleSleepTimerExpired(
2017 thread_call_param_t us
, thread_call_param_t
)
2019 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2022 //******************************************************************************
2023 // handleSleepTimerExpiration
2025 // The time between the sleep idle timeout and the next longest one has elapsed.
2026 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2027 //******************************************************************************
2029 void IOPMrootDomain::handleSleepTimerExpiration( void )
2031 if (!gIOPMWorkLoop
->inGate())
2033 gIOPMWorkLoop
->runAction(
2034 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2035 &IOPMrootDomain::handleSleepTimerExpiration
),
2042 DLOG("sleep timer expired\n");
2045 idleSleepTimerPending
= false;
2047 clock_get_uptime(&time
);
2048 setQuickSpinDownTimeout();
2049 adjustPowerState(true);
2052 //******************************************************************************
2053 // getTimeToIdleSleep
2055 // Returns number of seconds left before going into idle sleep.
2056 // Caller has to make sure that idle sleep is allowed at the time of calling
2058 //******************************************************************************
2060 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2063 AbsoluteTime now
, lastActivityTime
;
2065 uint32_t minutesSinceUserInactive
= 0;
2066 uint32_t sleepDelay
= 0;
2068 if (sleepSlider
== 0)
2071 if (userActivityTime
)
2072 lastActivityTime
= userActivityTime
;
2074 lastActivityTime
= userBecameInactiveTime
;
2076 clock_get_uptime(&now
);
2077 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2079 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2080 absolutetime_to_nanoseconds(now
, &nanos
);
2081 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2083 if (minutesSinceUserInactive
>= sleepSlider
)
2086 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2090 sleepDelay
= sleepSlider
;
2093 DLOG("user inactive %u min, time to idle sleep %u min\n",
2094 minutesSinceUserInactive
, sleepDelay
);
2096 return (sleepDelay
* 60);
2099 //******************************************************************************
2100 // setQuickSpinDownTimeout
2102 //******************************************************************************
2104 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2108 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2111 //******************************************************************************
2112 // restoreUserSpinDownTimeout
2114 //******************************************************************************
2116 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2120 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2123 //******************************************************************************
2126 //******************************************************************************
2129 IOReturn
IOPMrootDomain::sleepSystem( void )
2131 return sleepSystemOptions(NULL
);
2135 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2137 OSObject
*obj
= NULL
;
2138 OSString
*reason
= NULL
;
2139 /* sleepSystem is a public function, and may be called by any kernel driver.
2140 * And that's bad - drivers should sleep the system by calling
2141 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2143 * Note that user space app calls to IOPMSleepSystem() will also travel
2144 * this code path and thus be correctly identified as software sleeps.
2147 if (options
&& options
->getObject("OSSwitch"))
2149 // Log specific sleep cause for OS Switch hibernation
2150 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2153 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2155 reason
= OSDynamicCast(OSString
, obj
);
2156 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2157 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2160 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2164 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2166 /* Called from both gated and non-gated context */
2168 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2170 return kIOReturnNotPermitted
;
2173 pmPowerStateQueue
->submitPowerEvent(
2174 kPowerEventPolicyStimulus
,
2175 (void *) kStimulusDemandSystemSleep
,
2178 return kIOReturnSuccess
;
2181 //******************************************************************************
2184 // This overrides powerChangeDone in IOService.
2185 //******************************************************************************
2187 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2191 DLOG("PowerChangeDone: %u->%u\n",
2192 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2194 switch ( getPowerState() )
2197 if (previousPowerState
!= ON_STATE
)
2200 acceptSystemWakeEvents(true);
2202 // re-enable this timer for next sleep
2203 cancelIdleSleepTimer();
2206 clock_usec_t microsecs
;
2207 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2209 gIOLastSleepTime
.tv_sec
= secs
;
2210 gIOLastSleepTime
.tv_usec
= microsecs
;
2211 gIOLastWakeTime
.tv_sec
= 0;
2212 gIOLastWakeTime
.tv_usec
= 0;
2213 gIOLastSleepAbsTime
= now
;
2215 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2216 clock_usec_t microsecs
;
2217 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2218 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2220 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2221 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2222 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2223 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2224 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2226 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2227 wake2DarkwakeDelay
= 0;
2230 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2232 IOHibernateSystemHasSlept();
2234 evaluateSystemSleepPolicyFinal();
2236 LOG("System Sleep\n");
2238 if (thermalWarningState
) {
2239 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2241 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2245 assertOnWakeSecs
= 0;
2246 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2247 lowBatteryCondition
= false;
2249 getPlatform()->sleepKernel();
2251 // The CPU(s) are off at this point,
2252 // Code will resume execution here upon wake.
2254 clock_get_uptime(&gIOLastWakeAbsTime
);
2255 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2256 _highestCapability
= 0;
2258 ((IOService
*)this)->start_watchdog_timer(); //14456299
2260 IOHibernateSystemWake();
2263 // sleep transition complete
2264 gSleepOrShutdownPending
= 0;
2266 // trip the reset of the calendar clock
2268 clock_sec_t wakeSecs
;
2269 clock_usec_t wakeMicrosecs
;
2271 clock_initialize_calendar();
2273 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2274 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2275 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2279 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2282 lastSleepReason
= 0;
2284 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2285 _debugWakeSeconds
= 0;
2286 _scheduledAlarms
= 0;
2288 #if defined(__i386__) || defined(__x86_64__)
2289 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2290 wranglerTickled
= false;
2291 graphicsSuppressed
= false;
2292 darkWakePostTickle
= false;
2293 darkWakeHibernateError
= false;
2294 darkWakeToSleepASAP
= true;
2295 logGraphicsClamp
= true;
2296 sleepTimerMaintenance
= false;
2297 sleepToStandby
= false;
2298 wranglerTickleLatched
= false;
2299 userWasActive
= false;
2300 fullWakeReason
= kFullWakeReasonNone
;
2302 OSString
* wakeType
= OSDynamicCast(
2303 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2304 OSString
* wakeReason
= OSDynamicCast(
2305 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2307 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2308 gWakeReasonString
[0] == '\0')
2310 // Until the platform driver can claim its wake reasons
2311 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2312 sizeof(gWakeReasonString
));
2315 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2317 lowBatteryCondition
= true;
2318 darkWakeMaintenance
= true;
2320 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2323 OSNumber
* hibOptions
= OSDynamicCast(
2324 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2325 if (hibernateAborted
|| ((hibOptions
&&
2326 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2328 // Hibernate aborted, or EFI brought up graphics
2329 wranglerTickled
= true;
2330 DLOG("hibernation aborted %d, options 0x%x\n",
2332 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2337 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2338 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2340 // User wake or RTC alarm
2341 wranglerTickled
= true;
2345 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2347 // SMC standby timer trumps SleepX
2348 darkWakeMaintenance
= true;
2349 sleepTimerMaintenance
= true;
2352 if ((_lastDebugWakeSeconds
!= 0) &&
2353 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2355 // SleepX before maintenance
2356 wranglerTickled
= true;
2360 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2362 darkWakeMaintenance
= true;
2366 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2368 darkWakeMaintenance
= true;
2369 darkWakeSleepService
= true;
2371 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2372 sleepToStandby
= true;
2378 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2380 darkWakeMaintenance
= true;
2381 darkWakeHibernateError
= true;
2385 // Unidentified wake source, resume to full wake if debug
2386 // alarm is pending.
2388 if (_lastDebugWakeSeconds
&&
2389 (!wakeReason
|| wakeReason
->isEqualTo("")))
2390 wranglerTickled
= true;
2396 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2398 darkWakeMaintenance
= true;
2399 sleepTimerMaintenance
= true;
2401 else if (hibernateAborted
|| !wakeType
||
2402 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2403 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2405 // Post a HID tickle immediately - except for RTC maintenance wake.
2406 wranglerTickled
= true;
2410 darkWakeMaintenance
= true;
2414 if (wranglerTickled
)
2416 darkWakeToSleepASAP
= false;
2417 fullWakeReason
= kFullWakeReasonLocalUser
;
2420 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2422 handleDisplayPowerOn();
2424 else if (!darkWakeMaintenance
)
2426 // Early/late tickle for non-maintenance wake.
2427 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2428 kDarkWakeFlagHIDTickleEarly
) ||
2429 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2430 kDarkWakeFlagHIDTickleLate
))
2432 darkWakePostTickle
= true;
2435 #else /* !__i386__ && !__x86_64__ */
2436 kdebugTrace(kPMLogSystemWake
, 0, ml_get_wake_timebase() >> 32, ml_get_wake_timebase());
2437 // stay awake for at least 30 seconds
2438 wranglerTickled
= true;
2439 fullWakeReason
= kFullWakeReasonLocalUser
;
2440 startIdleSleepTimer(30);
2444 thread_call_enter(updateConsoleUsersEntry
);
2446 changePowerStateToPriv(ON_STATE
);
2448 #if !__i386__ && !__x86_64__
2450 if (previousPowerState
!= ON_STATE
)
2452 DLOG("Force re-evaluating aggressiveness\n");
2453 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2454 pmPowerStateQueue
->submitPowerEvent(
2455 kPowerEventPolicyStimulus
,
2456 (void *) kStimulusNoIdleSleepPreventers
);
2466 //******************************************************************************
2467 // requestPowerDomainState
2469 // Extend implementation in IOService. Running on PM work loop thread.
2470 //******************************************************************************
2472 IOReturn
IOPMrootDomain::requestPowerDomainState (
2473 IOPMPowerFlags childDesire
,
2474 IOPowerConnection
* childConnection
,
2475 unsigned long specification
)
2477 // Idle and system sleep prevention flags affects driver desire.
2478 // Children desire are irrelevant so they are cleared.
2480 return super::requestPowerDomainState(0, childConnection
, specification
);
2484 //******************************************************************************
2485 // updatePreventIdleSleepList
2487 // Called by IOService on PM work loop.
2488 // Returns true if PM policy recognized the driver's desire to prevent idle
2489 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2490 //******************************************************************************
2492 bool IOPMrootDomain::updatePreventIdleSleepList(
2493 IOService
* service
, bool addNotRemove
)
2495 unsigned int oldCount
, newCount
;
2499 #if defined(__i386__) || defined(__x86_64__)
2500 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2501 // idle sleep, except in the case of legacy disk I/O
2502 if ((service
!= wrangler
) && (service
!= this))
2508 oldCount
= preventIdleSleepList
->getCount();
2511 preventIdleSleepList
->setObject(service
);
2512 DLOG("prevent idle sleep list: %s+ (%u)\n",
2513 service
->getName(), preventIdleSleepList
->getCount());
2515 else if (preventIdleSleepList
->member(service
))
2517 preventIdleSleepList
->removeObject(service
);
2518 DLOG("prevent idle sleep list: %s- (%u)\n",
2519 service
->getName(), preventIdleSleepList
->getCount());
2521 newCount
= preventIdleSleepList
->getCount();
2523 if ((oldCount
== 0) && (newCount
!= 0))
2525 // Driver added to empty prevent list.
2526 // Update the driver desire to prevent idle sleep.
2527 // Driver desire does not prevent demand sleep.
2529 changePowerStateTo(ON_STATE
);
2531 else if ((oldCount
!= 0) && (newCount
== 0))
2533 // Last driver removed from prevent list.
2534 // Drop the driver clamp to allow idle sleep.
2536 changePowerStateTo(SLEEP_STATE
);
2537 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2539 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2540 &newCount
, sizeof(newCount
));
2542 #if defined(__i386__) || defined(__x86_64__)
2543 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2545 return false; // do not idle-cancel
2549 MSG("prevent idle sleep list: %s%c (%u)\n",
2551 (addNotRemove
) ? '+' : '-', newCount
);
2555 //******************************************************************************
2556 // preventSystemSleepListUpdate
2558 // Called by IOService on PM work loop.
2559 //******************************************************************************
2561 void IOPMrootDomain::updatePreventSystemSleepList(
2562 IOService
* service
, bool addNotRemove
)
2564 unsigned int oldCount
, newCount
;
2567 if (this == service
)
2570 oldCount
= preventSystemSleepList
->getCount();
2573 preventSystemSleepList
->setObject(service
);
2574 DLOG("prevent system sleep list: %s+ (%u)\n",
2575 service
->getName(), preventSystemSleepList
->getCount());
2576 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2578 clock_usec_t microsecs
;
2579 clock_get_uptime(&now
);
2580 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2581 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2582 if (assertOnWakeReport
) {
2583 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2584 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2588 else if (preventSystemSleepList
->member(service
))
2590 preventSystemSleepList
->removeObject(service
);
2591 DLOG("prevent system sleep list: %s- (%u)\n",
2592 service
->getName(), preventSystemSleepList
->getCount());
2594 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2596 // Lost all system sleep preventers.
2597 // Send stimulus if system sleep was blocked, and is in dark wake.
2598 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2601 newCount
= preventSystemSleepList
->getCount();
2602 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2603 &newCount
, sizeof(newCount
));
2606 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2609 OSCollectionIterator
*iterator
= NULL
;
2610 OSObject
*object
= NULL
;
2611 OSArray
*array
= NULL
;
2613 if (!gIOPMWorkLoop
->inGate())
2615 gIOPMWorkLoop
->runAction(
2616 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2617 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2618 this, (void *)idleSleepList
, (void *)systemSleepList
);
2622 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2624 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2625 array
= OSArray::withCapacity(5);
2627 while ((object
= iterator
->getNextObject()))
2629 IOService
*service
= OSDynamicCast(IOService
, object
);
2632 array
->setObject(OSSymbol::withCString(service
->getName()));
2636 iterator
->release();
2637 *idleSleepList
= array
;
2640 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2642 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2643 array
= OSArray::withCapacity(5);
2645 while ((object
= iterator
->getNextObject()))
2647 IOService
*service
= OSDynamicCast(IOService
, object
);
2650 array
->setObject(OSSymbol::withCString(service
->getName()));
2654 iterator
->release();
2655 *systemSleepList
= array
;
2659 //******************************************************************************
2662 // Override the superclass implementation to send a different message type.
2663 //******************************************************************************
2665 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2667 DLOG("tellChangeDown %u->%u\n",
2668 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2670 if (SLEEP_STATE
== stateNum
)
2672 // Legacy apps were already told in the full->dark transition
2673 if (!ignoreTellChangeDown
)
2674 tracePoint( kIOPMTracePointSleepApplications
);
2676 tracePoint( kIOPMTracePointSleepPriorityClients
);
2679 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2681 userActivityAtSleep
= userActivityCount
;
2682 hibernateAborted
= false;
2683 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2685 // Direct callout into OSKext so it can disable kext unloads
2686 // during sleep/wake to prevent deadlocks.
2687 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2689 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2691 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2692 // But tellClientsWithResponse() must be called for both.
2693 ignoreTellChangeDown
= true;
2696 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2699 //******************************************************************************
2702 // Override the superclass implementation to send a different message type.
2703 // This must be idle sleep since we don't ask during any other power change.
2704 //******************************************************************************
2706 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2708 DLOG("askChangeDown %u->%u\n",
2709 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2711 // Don't log for dark wake entry
2712 if (kSystemTransitionSleep
== _systemTransitionType
)
2713 tracePoint( kIOPMTracePointSleepApplications
);
2715 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2718 //******************************************************************************
2719 // askChangeDownDone
2721 // An opportunity for root domain to cancel the power transition,
2722 // possibily due to an assertion created by powerd in response to
2723 // kIOMessageCanSystemSleep.
2726 // full -> dark wake transition
2727 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2728 // 2. askChangeDownDone()
2729 // dark -> sleep transition
2730 // 1. Notify powerd with kIOMessageCanSystemSleep
2731 // 2. askChangeDownDone()
2734 // full -> dark wake transition
2735 // 1. Notify powerd with kIOMessageCanSystemSleep
2736 // 2. askChangeDownDone()
2737 // dark -> sleep transition
2738 // 1. Notify powerd with kIOMessageCanSystemSleep
2739 // 2. askChangeDownDone()
2740 //******************************************************************************
2742 void IOPMrootDomain::askChangeDownDone(
2743 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2745 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2746 *inOutChangeFlags
, *cancel
,
2747 _systemTransitionType
,
2748 _currentCapability
, _pendingCapability
);
2750 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2752 // Dark->Sleep transition.
2753 // Check if there are any deny sleep assertions.
2754 // lastSleepReason already set by handleOurPowerChangeStart()
2756 if (!checkSystemCanSleep(lastSleepReason
))
2758 // Cancel dark wake to sleep transition.
2759 // Must re-scan assertions upon entering dark wake.
2762 DLOG("cancel dark->sleep\n");
2767 //******************************************************************************
2768 // systemDidNotSleep
2770 // Work common to both canceled or aborted sleep.
2771 //******************************************************************************
2773 void IOPMrootDomain::systemDidNotSleep( void )
2775 // reset console lock state
2776 thread_call_enter(updateConsoleUsersEntry
);
2782 // stay awake for at least idleSeconds
2783 startIdleSleepTimer(idleSeconds
);
2788 if (sleepSlider
&& !userIsActive
)
2790 // Manually start the idle sleep timer besides waiting for
2791 // the user to become inactive.
2792 startIdleSleepTimer( kIdleSleepRetryInterval
);
2796 preventTransitionToUserActive(false);
2797 IOService::setAdvisoryTickleEnable( true );
2799 // After idle revert and cancel, send a did-change message to powerd
2800 // to balance the previous will-change message. Kernel clients do not
2801 // need this since sleep cannot be canceled once they are notified.
2803 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2804 (_pendingCapability
!= _currentCapability
) &&
2805 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2807 // Differs from a real capability gain change where notifyRef != 0,
2808 // but it is zero here since no response is expected.
2810 IOPMSystemCapabilityChangeParameters params
;
2812 bzero(¶ms
, sizeof(params
));
2813 params
.fromCapabilities
= _pendingCapability
;
2814 params
.toCapabilities
= _currentCapability
;
2815 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2817 DLOG("MESG cap %x->%x did change\n",
2818 params
.fromCapabilities
, params
.toCapabilities
);
2819 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2820 ¶ms
, sizeof(params
));
2824 //******************************************************************************
2827 // Notify registered applications and kernel clients that we are not dropping
2830 // We override the superclass implementation so we can send a different message
2831 // type to the client or application being notified.
2833 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2834 //******************************************************************************
2836 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2838 DLOG("tellNoChangeDown %u->%u\n",
2839 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2841 // Sleep canceled, clear the sleep trace point.
2842 tracePoint(kIOPMTracePointSystemUp
);
2844 systemDidNotSleep();
2845 return tellClients( kIOMessageSystemWillNotSleep
);
2848 //******************************************************************************
2851 // Notify registered applications and kernel clients that we are raising power.
2853 // We override the superclass implementation so we can send a different message
2854 // type to the client or application being notified.
2855 //******************************************************************************
2857 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2859 DLOG("tellChangeUp %u->%u\n",
2860 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2862 ignoreTellChangeDown
= false;
2864 if ( stateNum
== ON_STATE
)
2866 // Direct callout into OSKext so it can disable kext unloads
2867 // during sleep/wake to prevent deadlocks.
2868 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2870 // Notify platform that sleep was cancelled or resumed.
2871 getPlatform()->callPlatformFunction(
2872 sleepMessagePEFunction
, false,
2873 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2876 if (getPowerState() == ON_STATE
)
2878 // this is a quick wake from aborted sleep
2879 systemDidNotSleep();
2880 tellClients( kIOMessageSystemWillPowerOn
);
2883 tracePoint( kIOPMTracePointWakeApplications
);
2884 tellClients( kIOMessageSystemHasPoweredOn
);
2888 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2889 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2890 ((params)->fromCapabilities & (flag)) && \
2891 (((params)->toCapabilities & (flag)) == 0))
2893 #define CAP_DID_CHANGE_TO_ON(params, flag) \
2894 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2895 ((params)->toCapabilities & (flag)) && \
2896 (((params)->fromCapabilities & (flag)) == 0))
2898 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
2899 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2900 ((params)->fromCapabilities & (flag)) && \
2901 (((params)->toCapabilities & (flag)) == 0))
2903 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
2904 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2905 ((params)->toCapabilities & (flag)) && \
2906 (((params)->fromCapabilities & (flag)) == 0))
2908 //******************************************************************************
2909 // sysPowerDownHandler
2911 // Perform a vfs sync before system sleep.
2912 //******************************************************************************
2914 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2915 void * target
, void * refCon
,
2916 UInt32 messageType
, IOService
* service
,
2917 void * messageArgs
, vm_size_t argSize
)
2921 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2924 return kIOReturnUnsupported
;
2926 if (messageType
== kIOMessageSystemWillSleep
)
2929 IOPowerStateChangeNotification
*notify
=
2930 (IOPowerStateChangeNotification
*)messageArgs
;
2932 notify
->returnValue
= 30 * 1000 * 1000;
2934 gRootDomain
->swdDebugSetupEntry
,
2935 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2938 else if (messageType
== kIOMessageSystemCapabilityChange
)
2940 IOPMSystemCapabilityChangeParameters
* params
=
2941 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2943 // Interested applications have been notified of an impending power
2944 // change and have acked (when applicable).
2945 // This is our chance to save whatever state we can before powering
2947 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2950 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2951 params
->fromCapabilities
, params
->toCapabilities
,
2952 params
->changeFlags
);
2954 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
2956 // We will ack within 20 seconds
2957 params
->maxWaitForReply
= 20 * 1000 * 1000;
2959 // Remove EFI/BootRom's previous wake's failure data
2960 PERemoveNVRAMProperty(kIOEFIBootRomFailureKey
);
2963 gRootDomain
->evaluateSystemSleepPolicyEarly();
2965 // add in time we could spend freeing pages
2966 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2968 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2970 DLOG("sysPowerDownHandler max wait %d s\n",
2971 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2974 // Notify platform that sleep has begun, after the early
2975 // sleep policy evaluation.
2976 getPlatform()->callPlatformFunction(
2977 sleepMessagePEFunction
, false,
2978 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2981 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2983 // Purposely delay the ack and hope that shutdown occurs quickly.
2984 // Another option is not to schedule the thread and wait for
2986 AbsoluteTime deadline
;
2987 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2988 thread_call_enter1_delayed(
2989 gRootDomain
->diskSyncCalloutEntry
,
2990 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2995 gRootDomain
->diskSyncCalloutEntry
,
2996 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2999 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3001 // We will ack within 110 seconds
3002 params
->maxWaitForReply
= 110 * 1000 * 1000;
3005 gRootDomain
->diskSyncCalloutEntry
,
3006 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3008 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3009 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3011 // WillChange for Full wake -> Darkwake
3012 params
->maxWaitForReply
= 30 * 1000 * 1000;
3014 gRootDomain
->swdDebugSetupEntry
,
3015 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3017 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3018 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3020 // DidChange for Full wake -> Darkwake
3021 params
->maxWaitForReply
= 30 * 1000 * 1000;
3023 gRootDomain
->swdDebugTearDownEntry
,
3024 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3028 ret
= kIOReturnSuccess
;
3034 //******************************************************************************
3035 // handleQueueSleepWakeUUID
3037 // Called from IOPMrootDomain when we're initiating a sleep,
3038 // or indirectly from PM configd when PM decides to clear the UUID.
3039 // PM clears the UUID several minutes after successful wake from sleep,
3040 // so that we might associate App spindumps with the immediately previous
3043 // @param obj has a retain on it. We're responsible for releasing that retain.
3044 //******************************************************************************
3046 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3048 OSString
*str
= NULL
;
3050 if (kOSBooleanFalse
== obj
)
3052 handlePublishSleepWakeUUID(NULL
);
3054 else if ((str
= OSDynamicCast(OSString
, obj
)))
3056 // This branch caches the UUID for an upcoming sleep/wake
3057 if (queuedSleepWakeUUIDString
) {
3058 queuedSleepWakeUUIDString
->release();
3059 queuedSleepWakeUUIDString
= NULL
;
3061 queuedSleepWakeUUIDString
= str
;
3062 queuedSleepWakeUUIDString
->retain();
3064 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3073 //******************************************************************************
3074 // handlePublishSleepWakeUUID
3076 // Called from IOPMrootDomain when we're initiating a sleep,
3077 // or indirectly from PM configd when PM decides to clear the UUID.
3078 // PM clears the UUID several minutes after successful wake from sleep,
3079 // so that we might associate App spindumps with the immediately previous
3081 //******************************************************************************
3083 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3088 * Clear the current UUID
3090 if (gSleepWakeUUIDIsSet
)
3092 DLOG("SleepWake UUID cleared\n");
3094 gSleepWakeUUIDIsSet
= false;
3096 removeProperty(kIOPMSleepWakeUUIDKey
);
3097 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3101 * Optionally, publish a new UUID
3103 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3105 OSString
*publishThisUUID
= NULL
;
3107 publishThisUUID
= queuedSleepWakeUUIDString
;
3108 publishThisUUID
->retain();
3110 if (publishThisUUID
)
3112 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3113 publishThisUUID
->release();
3116 gSleepWakeUUIDIsSet
= true;
3117 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3119 queuedSleepWakeUUIDString
->release();
3120 queuedSleepWakeUUIDString
= NULL
;
3124 //******************************************************************************
3125 // initializeBootSessionUUID
3127 // Initialize the boot session uuid at boot up and sets it into registry.
3128 //******************************************************************************
3130 void IOPMrootDomain::initializeBootSessionUUID(void)
3133 uuid_string_t new_uuid_string
;
3135 uuid_generate(new_uuid
);
3136 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3137 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3139 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3142 //******************************************************************************
3143 // changePowerStateTo & changePowerStateToPriv
3145 // Override of these methods for logging purposes.
3146 //******************************************************************************
3148 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3150 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3152 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3153 return kIOReturnUnsupported
;
3155 return super::changePowerStateTo(ordinal
);
3158 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3160 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3162 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3163 return kIOReturnUnsupported
;
3165 return super::changePowerStateToPriv(ordinal
);
3168 //******************************************************************************
3171 //******************************************************************************
3173 bool IOPMrootDomain::activitySinceSleep(void)
3175 return (userActivityCount
!= userActivityAtSleep
);
3178 bool IOPMrootDomain::abortHibernation(void)
3180 bool ret
= activitySinceSleep();
3182 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3184 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3185 hibernateAborted
= true;
3191 hibernate_should_abort(void)
3194 return (gRootDomain
->abortHibernation());
3199 //******************************************************************************
3200 // willNotifyPowerChildren
3202 // Called after all interested drivers have all acknowledged the power change,
3203 // but before any power children is informed. Dispatched though a thread call,
3204 // so it is safe to perform work that might block on a sleeping disk. PM state
3205 // machine (not thread) will block w/o timeout until this function returns.
3206 //******************************************************************************
3208 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3213 if (SLEEP_STATE
== newPowerState
)
3215 if (!tasksSuspended
)
3217 AbsoluteTime deadline
;
3218 tasksSuspended
= TRUE
;
3219 tasks_system_suspend(tasksSuspended
);
3221 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3222 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3226 IOHibernateSystemSleep();
3227 IOHibernateIOKitSleep();
3229 if (gRootDomain
->activitySinceSleep()) {
3230 dict
= OSDictionary::withCapacity(1);
3231 secs
= OSNumber::withNumber(1, 32);
3234 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3235 gRootDomain
->setProperties(dict
);
3236 MSG("Reverting sleep with relative wake\n");
3238 if (dict
) dict
->release();
3239 if (secs
) secs
->release();
3245 //******************************************************************************
3246 // sleepOnClamshellClosed
3248 // contains the logic to determine if the system should sleep when the clamshell
3250 //******************************************************************************
3252 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3254 if (!clamshellExists
)
3257 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3258 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3260 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3263 void IOPMrootDomain::sendClientClamshellNotification( void )
3265 /* Only broadcast clamshell alert if clamshell exists. */
3266 if (!clamshellExists
)
3269 setProperty(kAppleClamshellStateKey
,
3270 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3272 setProperty(kAppleClamshellCausesSleepKey
,
3273 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3275 /* Argument to message is a bitfiel of
3276 * ( kClamshellStateBit | kClamshellSleepBit )
3278 messageClients(kIOPMMessageClamshellStateChange
,
3279 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3280 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3283 //******************************************************************************
3284 // getSleepSupported
3287 //******************************************************************************
3289 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3291 return( platformSleepSupport
);
3294 //******************************************************************************
3295 // setSleepSupported
3298 //******************************************************************************
3300 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3302 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3303 OSBitOrAtomic(flags
, &platformSleepSupport
);
3306 //******************************************************************************
3307 // setDisableClamShellSleep
3309 //******************************************************************************
3311 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3313 if (gIOPMWorkLoop
->inGate() == false) {
3315 gIOPMWorkLoop
->runAction(
3316 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3323 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3324 if ( clamshellSleepDisabled
!= val
)
3326 clamshellSleepDisabled
= val
;
3327 // If clamshellSleepDisabled is reset to 0, reevaluate if
3328 // system need to go to sleep due to clamshell state
3329 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3330 handlePowerNotification(kLocalEvalClamshellCommand
);
3335 //******************************************************************************
3339 //******************************************************************************
3341 void IOPMrootDomain::wakeFromDoze( void )
3343 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3349 //******************************************************************************
3352 // Adds a new feature to the supported features dictionary
3353 //******************************************************************************
3355 void IOPMrootDomain::publishFeature( const char * feature
)
3357 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3360 //******************************************************************************
3361 // publishFeature (with supported power source specified)
3363 // Adds a new feature to the supported features dictionary
3364 //******************************************************************************
3366 void IOPMrootDomain::publishFeature(
3367 const char *feature
,
3368 uint32_t supportedWhere
,
3369 uint32_t *uniqueFeatureID
)
3371 static uint16_t next_feature_id
= 500;
3373 OSNumber
*new_feature_data
= NULL
;
3374 OSNumber
*existing_feature
= NULL
;
3375 OSArray
*existing_feature_arr
= NULL
;
3376 OSObject
*osObj
= NULL
;
3377 uint32_t feature_value
= 0;
3379 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3381 if(!supportedWhere
) {
3382 // Feature isn't supported anywhere!
3386 if(next_feature_id
> 5000) {
3387 // Far, far too many features!
3391 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3393 OSDictionary
*features
=
3394 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3396 // Create new features dict if necessary
3397 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3398 features
= OSDictionary::withDictionary(features
);
3400 features
= OSDictionary::withCapacity(1);
3403 // Create OSNumber to track new feature
3405 next_feature_id
+= 1;
3406 if( uniqueFeatureID
) {
3407 // We don't really mind if the calling kext didn't give us a place
3408 // to stash their unique id. Many kexts don't plan to unload, and thus
3409 // have no need to remove themselves later.
3410 *uniqueFeatureID
= next_feature_id
;
3413 feature_value
= (uint32_t)next_feature_id
;
3414 feature_value
<<= 16;
3415 feature_value
+= supportedWhere
;
3417 new_feature_data
= OSNumber::withNumber(
3418 (unsigned long long)feature_value
, 32);
3420 // Does features object already exist?
3421 if( (osObj
= features
->getObject(feature
)) )
3423 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3425 // We need to create an OSArray to hold the now 2 elements.
3426 existing_feature_arr
= OSArray::withObjects(
3427 (const OSObject
**)&existing_feature
, 1, 2);
3428 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3430 // Add object to existing array
3431 existing_feature_arr
= OSArray::withArray(
3432 existing_feature_arr
,
3433 existing_feature_arr
->getCount() + 1);
3436 if (existing_feature_arr
)
3438 existing_feature_arr
->setObject(new_feature_data
);
3439 features
->setObject(feature
, existing_feature_arr
);
3440 existing_feature_arr
->release();
3441 existing_feature_arr
= 0;
3444 // The easy case: no previously existing features listed. We simply
3445 // set the OSNumber at key 'feature' and we're on our way.
3446 features
->setObject(feature
, new_feature_data
);
3449 new_feature_data
->release();
3451 setProperty(kRootDomainSupportedFeatures
, features
);
3453 features
->release();
3455 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3457 // Notify EnergySaver and all those in user space so they might
3458 // re-populate their feature specific UI
3459 if(pmPowerStateQueue
) {
3460 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3464 //******************************************************************************
3465 // removePublishedFeature
3467 // Removes previously published feature
3468 //******************************************************************************
3470 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3472 IOReturn ret
= kIOReturnError
;
3473 uint32_t feature_value
= 0;
3474 uint16_t feature_id
= 0;
3475 bool madeAChange
= false;
3477 OSSymbol
*dictKey
= NULL
;
3478 OSCollectionIterator
*dictIterator
= NULL
;
3479 OSArray
*arrayMember
= NULL
;
3480 OSNumber
*numberMember
= NULL
;
3481 OSObject
*osObj
= NULL
;
3482 OSNumber
*osNum
= NULL
;
3483 OSArray
*arrayMemberCopy
;
3485 if (kBadPMFeatureID
== removeFeatureID
)
3486 return kIOReturnNotFound
;
3488 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3490 OSDictionary
*features
=
3491 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3493 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3495 // Any modifications to the dictionary are made to the copy to prevent
3496 // races & crashes with userland clients. Dictionary updated
3497 // automically later.
3498 features
= OSDictionary::withDictionary(features
);
3501 ret
= kIOReturnNotFound
;
3505 // We iterate 'features' dictionary looking for an entry tagged
3506 // with 'removeFeatureID'. If found, we remove it from our tracking
3507 // structures and notify the OS via a general interest message.
3509 dictIterator
= OSCollectionIterator::withCollection(features
);
3514 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3516 osObj
= features
->getObject(dictKey
);
3518 // Each Feature is either tracked by an OSNumber
3519 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3521 feature_value
= numberMember
->unsigned32BitValue();
3522 feature_id
= (uint16_t)(feature_value
>> 16);
3524 if( feature_id
== (uint16_t)removeFeatureID
)
3527 features
->removeObject(dictKey
);
3532 // Or tracked by an OSArray of OSNumbers
3533 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3535 unsigned int arrayCount
= arrayMember
->getCount();
3537 for(unsigned int i
=0; i
<arrayCount
; i
++)
3539 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3544 feature_value
= osNum
->unsigned32BitValue();
3545 feature_id
= (uint16_t)(feature_value
>> 16);
3547 if( feature_id
== (uint16_t)removeFeatureID
)
3550 if( 1 == arrayCount
) {
3551 // If the array only contains one element, remove
3553 features
->removeObject(dictKey
);
3555 // Otherwise remove the element from a copy of the array.
3556 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3557 if (arrayMemberCopy
)
3559 arrayMemberCopy
->removeObject(i
);
3560 features
->setObject(dictKey
, arrayMemberCopy
);
3561 arrayMemberCopy
->release();
3572 dictIterator
->release();
3576 ret
= kIOReturnSuccess
;
3578 setProperty(kRootDomainSupportedFeatures
, features
);
3580 // Notify EnergySaver and all those in user space so they might
3581 // re-populate their feature specific UI
3582 if(pmPowerStateQueue
) {
3583 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3586 ret
= kIOReturnNotFound
;
3590 if(features
) features
->release();
3591 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3595 //******************************************************************************
3596 // publishPMSetting (private)
3598 // Should only be called by PMSettingObject to publish a PM Setting as a
3599 // supported feature.
3600 //******************************************************************************
3602 void IOPMrootDomain::publishPMSetting(
3603 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3605 if (noPublishPMSettings
&&
3606 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3608 // Setting found in noPublishPMSettings array
3609 *featureID
= kBadPMFeatureID
;
3614 feature
->getCStringNoCopy(), where
, featureID
);
3617 //******************************************************************************
3618 // setPMSetting (private)
3620 // Internal helper to relay PM settings changes from user space to individual
3621 // drivers. Should be called only by IOPMrootDomain::setProperties.
3622 //******************************************************************************
3624 IOReturn
IOPMrootDomain::setPMSetting(
3625 const OSSymbol
*type
,
3628 PMSettingCallEntry
*entries
= 0;
3629 OSArray
*chosen
= 0;
3630 const OSArray
*array
;
3631 PMSettingObject
*pmso
;
3632 thread_t thisThread
;
3633 int i
, j
, count
, capacity
;
3636 return kIOReturnBadArgument
;
3640 // Update settings dict so changes are visible from copyPMSetting().
3641 fPMSettingsDict
->setObject(type
, object
);
3643 // Prep all PMSetting objects with the given 'type' for callout.
3644 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3645 if (!array
|| ((capacity
= array
->getCount()) == 0))
3648 // Array to retain PMSetting objects targeted for callout.
3649 chosen
= OSArray::withCapacity(capacity
);
3651 goto unlock_exit
; // error
3653 entries
= IONew(PMSettingCallEntry
, capacity
);
3655 goto unlock_exit
; // error
3656 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3658 thisThread
= current_thread();
3660 for (i
= 0, j
= 0; i
<capacity
; i
++)
3662 pmso
= (PMSettingObject
*) array
->getObject(i
);
3665 entries
[j
].thread
= thisThread
;
3666 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3667 chosen
->setObject(pmso
);
3676 // Call each pmso in the chosen array.
3677 for (i
=0; i
<count
; i
++)
3679 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3680 pmso
->dispatchPMSetting(type
, object
);
3684 for (i
=0; i
<count
; i
++)
3686 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3687 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3688 if (pmso
->waitThread
)
3690 PMSETTING_WAKEUP(pmso
);
3696 if (chosen
) chosen
->release();
3697 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3699 return kIOReturnSuccess
;
3702 //******************************************************************************
3703 // copyPMSetting (public)
3705 // Allows kexts to safely read setting values, without being subscribed to
3707 //******************************************************************************
3709 OSObject
* IOPMrootDomain::copyPMSetting(
3710 OSSymbol
*whichSetting
)
3712 OSObject
*obj
= NULL
;
3714 if(!whichSetting
) return NULL
;
3717 obj
= fPMSettingsDict
->getObject(whichSetting
);
3726 //******************************************************************************
3727 // registerPMSettingController (public)
3729 // direct wrapper to registerPMSettingController with uint32_t power source arg
3730 //******************************************************************************
3732 IOReturn
IOPMrootDomain::registerPMSettingController(
3733 const OSSymbol
* settings
[],
3734 IOPMSettingControllerCallback func
,
3739 return registerPMSettingController(
3741 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3742 func
, target
, refcon
, handle
);
3745 //******************************************************************************
3746 // registerPMSettingController (public)
3748 // Kexts may register for notifications when a particular setting is changed.
3749 // A list of settings is available in IOPM.h.
3751 // * settings - An OSArray containing OSSymbols. Caller should populate this
3752 // array with a list of settings caller wants notifications from.
3753 // * func - A C function callback of the type IOPMSettingControllerCallback
3754 // * target - caller may provide an OSObject *, which PM will pass as an
3755 // target to calls to "func"
3756 // * refcon - caller may provide an void *, which PM will pass as an
3757 // argument to calls to "func"
3758 // * handle - This is a return argument. We will populate this pointer upon
3759 // call success. Hold onto this and pass this argument to
3760 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3762 // kIOReturnSuccess on success
3763 //******************************************************************************
3765 IOReturn
IOPMrootDomain::registerPMSettingController(
3766 const OSSymbol
* settings
[],
3767 uint32_t supportedPowerSources
,
3768 IOPMSettingControllerCallback func
,
3773 PMSettingObject
*pmso
= NULL
;
3774 OSObject
*pmsh
= NULL
;
3775 OSArray
*list
= NULL
;
3778 if (NULL
== settings
||
3782 return kIOReturnBadArgument
;
3785 pmso
= PMSettingObject::pmSettingObject(
3786 (IOPMrootDomain
*) this, func
, target
,
3787 refcon
, supportedPowerSources
, settings
, &pmsh
);
3791 return kIOReturnInternalError
;
3795 for (i
=0; settings
[i
]; i
++)
3797 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3799 // New array of callbacks for this setting
3800 list
= OSArray::withCapacity(1);
3801 settingsCallbacks
->setObject(settings
[i
], list
);
3805 // Add caller to the callback list
3806 list
->setObject(pmso
);
3810 // Return handle to the caller, the setting object is private.
3813 return kIOReturnSuccess
;
3816 //******************************************************************************
3817 // deregisterPMSettingObject (private)
3819 // Only called from PMSettingObject.
3820 //******************************************************************************
3822 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3824 thread_t thisThread
= current_thread();
3825 PMSettingCallEntry
*callEntry
;
3826 OSCollectionIterator
*iter
;
3834 pmso
->disabled
= true;
3836 // Wait for all callout threads to finish.
3839 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3841 if (callEntry
->thread
!= thisThread
)
3849 assert(0 == pmso
->waitThread
);
3850 pmso
->waitThread
= thisThread
;
3851 PMSETTING_WAIT(pmso
);
3852 pmso
->waitThread
= 0;
3856 // Search each PM settings array in the kernel.
3857 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3860 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3862 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3863 index
= array
->getNextIndexOfObject(pmso
, 0);
3865 array
->removeObject(index
);
3876 //******************************************************************************
3877 // informCPUStateChange
3879 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3880 // running on battery, with the lid closed, etc.
3882 // informCPUStateChange is a no-op on non x86 systems
3883 // only x86 has explicit support in the IntelCPUPowerManagement kext
3884 //******************************************************************************
3886 void IOPMrootDomain::informCPUStateChange(
3890 #if defined(__i386__) || defined(__x86_64__)
3892 pmioctlVariableInfo_t varInfoStruct
;
3894 const char *varNameStr
= NULL
;
3895 int32_t *varIndex
= NULL
;
3897 if (kInformAC
== type
) {
3898 varNameStr
= kIOPMRootDomainBatPowerCString
;
3899 varIndex
= &idxPMCPULimitedPower
;
3900 } else if (kInformLid
== type
) {
3901 varNameStr
= kIOPMRootDomainLidCloseCString
;
3902 varIndex
= &idxPMCPUClamshell
;
3907 // Set the new value!
3908 // pmCPUControl will assign us a new ID if one doesn't exist yet
3909 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3910 varInfoStruct
.varID
= *varIndex
;
3911 varInfoStruct
.varType
= vBool
;
3912 varInfoStruct
.varInitValue
= value
;
3913 varInfoStruct
.varCurValue
= value
;
3914 strlcpy( (char *)varInfoStruct
.varName
,
3915 (const char *)varNameStr
,
3916 sizeof(varInfoStruct
.varName
));
3919 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3921 // pmCPU only assigns numerical id's when a new varName is specified
3923 && (*varIndex
== kCPUUnknownIndex
))
3925 // pmCPUControl has assigned us a new variable ID.
3926 // Let's re-read the structure we just SET to learn that ID.
3927 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3931 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3932 *varIndex
= varInfoStruct
.varID
;
3938 #endif /* __i386__ || __x86_64__ */
3942 // MARK: Deep Sleep Policy
3946 //******************************************************************************
3947 // evaluateSystemSleepPolicy
3948 //******************************************************************************
3950 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3954 kIOPMSleepFlagHibernate
= 0x00000001,
3955 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3958 struct IOPMSystemSleepPolicyEntry
3960 uint32_t factorMask
;
3961 uint32_t factorBits
;
3962 uint32_t sleepFlags
;
3963 uint32_t wakeEvents
;
3964 } __attribute__((packed
));
3966 struct IOPMSystemSleepPolicyTable
3970 uint16_t entryCount
;
3971 IOPMSystemSleepPolicyEntry entries
[];
3972 } __attribute__((packed
));
3975 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3976 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3980 getSleepTypeAttributes( uint32_t sleepType
)
3982 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3987 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3988 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3989 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3990 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3994 if (sleepType
>= kIOPMSleepTypeLast
)
3997 return sleepTypeAttributes
[sleepType
];
4000 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4001 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4003 const IOPMSystemSleepPolicyTable
* pt
;
4004 OSObject
* prop
= 0;
4005 OSData
* policyData
;
4006 uint64_t currentFactors
= 0;
4007 uint32_t standbyDelay
= 0;
4008 uint32_t powerOffDelay
= 0;
4009 uint32_t powerOffTimer
= 0;
4011 bool standbyEnabled
;
4012 bool powerOffEnabled
;
4015 // Get platform's sleep policy table
4016 if (!gSleepPolicyHandler
)
4018 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4019 if (!prop
) goto done
;
4022 // Fetch additional settings
4023 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4024 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4025 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4026 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4027 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4028 powerOffTimer
= powerOffDelay
;
4030 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4031 sleepPhase
, standbyEnabled
, standbyDelay
,
4032 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4034 // pmset level overrides
4035 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4037 if (!gSleepPolicyHandler
)
4039 standbyEnabled
= false;
4040 powerOffEnabled
= false;
4043 else if (!(*hibMode
& kIOHibernateModeSleep
))
4045 // Force hibernate (i.e. mode 25)
4046 // If standby is enabled, force standy.
4047 // If poweroff is enabled, force poweroff.
4049 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4050 else if (powerOffEnabled
)
4051 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4053 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4056 // Current factors based on environment and assertions
4057 if (sleepTimerMaintenance
)
4058 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4059 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4060 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4061 if (!clamshellClosed
)
4062 currentFactors
|= kIOPMSleepFactorLidOpen
;
4063 if (acAdaptorConnected
)
4064 currentFactors
|= kIOPMSleepFactorACPower
;
4065 if (lowBatteryCondition
)
4066 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4068 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4069 if (standbyNixed
|| !standbyEnabled
)
4070 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4073 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4074 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4076 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4077 kIOPMDriverAssertionLevelOff
)
4078 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4079 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4080 kIOPMDriverAssertionLevelOff
)
4081 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4082 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4083 kIOPMDriverAssertionLevelOff
)
4084 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4085 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4086 kIOPMDriverAssertionLevelOff
)
4087 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4088 if (_scheduledAlarms
!= 0)
4089 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4090 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4091 kIOPMDriverAssertionLevelOff
)
4092 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4093 #define TCPKEEPALIVE 1
4095 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4096 kIOPMDriverAssertionLevelOff
)
4097 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4099 if (!powerOffEnabled
)
4100 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4102 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4104 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4105 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4106 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4107 if (thermalWarningState
)
4108 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4110 DLOG("sleep factors 0x%llx\n", currentFactors
);
4112 if (gSleepPolicyHandler
)
4114 uint32_t savedHibernateMode
;
4117 if (!gSleepPolicyVars
)
4119 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4120 if (!gSleepPolicyVars
)
4122 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4124 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4125 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4126 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4127 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4128 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4129 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4130 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4131 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4132 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4133 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4134 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4136 if (kIOPMSleepPhase0
== sleepPhase
)
4138 // preserve hibernateMode
4139 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4140 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4142 else if (kIOPMSleepPhase1
== sleepPhase
)
4144 // use original hibernateMode for phase2
4145 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4148 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4150 if (kIOPMSleepPhase0
== sleepPhase
)
4152 // restore hibernateMode
4153 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4156 if ((result
!= kIOReturnSuccess
) ||
4157 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4158 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4159 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4161 MSG("sleep policy handler error\n");
4165 if ((getSleepTypeAttributes(params
->sleepType
) &
4166 kIOPMSleepAttributeHibernateSetup
) &&
4167 ((*hibMode
& kIOHibernateModeOn
) == 0))
4169 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4172 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4173 params
->version
, params
->sleepType
, params
->sleepFlags
,
4174 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4179 // Policy table is meaningless without standby enabled
4180 if (!standbyEnabled
)
4183 // Validate the sleep policy table
4184 policyData
= OSDynamicCast(OSData
, prop
);
4185 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4188 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4189 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4190 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4193 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4194 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4197 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4199 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4200 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4202 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4203 entry
->factorMask
, entry
->factorBits
,
4204 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4208 DLOG("^ found match\n");
4211 params
->version
= kIOPMSystemSleepParametersVersion
;
4212 params
->reserved1
= 1;
4213 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4214 params
->sleepType
= kIOPMSleepTypeStandby
;
4216 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4218 params
->ecWakeEvents
= entry
->wakeEvents
;
4219 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4221 if (kIOPMSleepPhase2
== sleepPhase
)
4223 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4225 if (!_standbyTimerResetSeconds
||
4226 (now_secs
<= _standbyTimerResetSeconds
))
4228 // Reset standby timer adjustment
4229 _standbyTimerResetSeconds
= now_secs
;
4230 DLOG("standby delay %u, reset %u\n",
4231 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4233 else if (standbyDelay
)
4235 // Shorten the standby delay timer
4236 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4237 if (standbyDelay
> elapsed
)
4238 standbyDelay
-= elapsed
;
4240 standbyDelay
= 1; // must be > 0
4242 DLOG("standby delay %u, elapsed %u\n",
4243 standbyDelay
, (uint32_t) elapsed
);
4246 params
->ecWakeTimer
= standbyDelay
;
4248 else if (kIOPMSleepPhase2
== sleepPhase
)
4250 // A sleep that does not enable the sleep timer will reset
4251 // the standby delay adjustment.
4252 _standbyTimerResetSeconds
= 0;
4264 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4266 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4268 // Evaluate early (priority interest phase), before drivers sleep.
4270 DLOG("%s\n", __FUNCTION__
);
4271 removeProperty(kIOPMSystemSleepParametersKey
);
4273 // Full wake resets the standby timer delay adjustment
4274 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4275 _standbyTimerResetSeconds
= 0;
4277 hibernateDisabled
= false;
4279 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4281 // Save for late evaluation if sleep is aborted
4282 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4284 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4287 if (!hibernateRetry
&&
4288 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4289 kIOPMSleepAttributeHibernateSetup
) == 0))
4291 // skip hibernate setup
4292 hibernateDisabled
= true;
4296 // Publish IOPMSystemSleepType
4297 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4298 if (sleepType
== kIOPMSleepTypeInvalid
)
4301 sleepType
= kIOPMSleepTypeNormalSleep
;
4302 if (hibernateMode
& kIOHibernateModeOn
)
4303 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4304 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4306 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4307 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4309 // report the lowest possible sleep state
4310 sleepType
= kIOPMSleepTypePowerOff
;
4313 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4316 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4318 IOPMSystemSleepParameters params
;
4319 OSData
* paramsData
;
4321 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4323 DLOG("%s\n", __FUNCTION__
);
4325 bzero(¶ms
, sizeof(params
));
4327 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4329 if ((kIOPMSleepTypeStandby
== params
.sleepType
) && gIOHibernateStandbyDisabled
)
4331 standbyNixed
= true;
4335 || ((hibernateDisabled
|| hibernateAborted
) &&
4336 (getSleepTypeAttributes(params
.sleepType
) &
4337 kIOPMSleepAttributeHibernateSetup
)))
4339 // Final evaluation picked a state requiring hibernation,
4340 // but hibernate isn't going to proceed. Arm a short sleep using
4341 // the early non-hibernate sleep parameters.
4342 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4343 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4344 params
.ecWakeTimer
= 1;
4345 gIOHibernateMode
= 0;
4352 // Set hibernateRetry flag to force hibernate setup on the
4354 hibernateRetry
= true;
4356 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4357 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4361 hibernateRetry
= false;
4364 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4366 resetTimers
= false;
4369 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4372 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4373 paramsData
->release();
4376 if (getSleepTypeAttributes(params
.sleepType
) &
4377 kIOPMSleepAttributeHibernateSleep
)
4379 // Disable sleep to force hibernation
4380 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4385 bool IOPMrootDomain::getHibernateSettings(
4386 uint32_t * hibernateModePtr
,
4387 uint32_t * hibernateFreeRatio
,
4388 uint32_t * hibernateFreeTime
)
4390 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4391 // has updated the hibernateDisabled flag.
4393 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4394 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4395 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4396 if (hibernateDisabled
)
4397 *hibernateModePtr
= 0;
4398 else if (gSleepPolicyHandler
)
4399 *hibernateModePtr
= hibernateMode
;
4400 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4404 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4406 OSObject
* optionsProp
;
4407 OSDictionary
* optionsDict
;
4412 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4413 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4417 obj
= optionsDict
->getObject(key
);
4418 if (obj
) obj
->retain();
4422 obj
= copyProperty(key
);
4426 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4428 *option
= num
->unsigned32BitValue();
4431 else if (OSDynamicCast(OSBoolean
, obj
))
4433 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4441 optionsProp
->release();
4445 #endif /* HIBERNATION */
4447 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4450 IOPMSystemSleepParameters params
;
4451 uint32_t hibMode
= 0;
4454 if (gIOPMWorkLoop
->inGate() == false)
4456 IOReturn ret
= gIOPMWorkLoop
->runAction(
4457 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4458 &IOPMrootDomain::getSystemSleepType
),
4460 (void *) sleepType
);
4464 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4465 bzero(¶ms
, sizeof(params
));
4467 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4470 *sleepType
= params
.sleepType
;
4471 return kIOReturnSuccess
;
4475 return kIOReturnUnsupported
;
4479 // MARK: Shutdown and Restart
4481 //******************************************************************************
4482 // handlePlatformHaltRestart
4484 //******************************************************************************
4486 struct HaltRestartApplierContext
{
4487 IOPMrootDomain
* RootDomain
;
4488 unsigned long PowerState
;
4489 IOPMPowerFlags PowerFlags
;
4492 const char * LogString
;
4496 platformHaltRestartApplier( OSObject
* object
, void * context
)
4498 IOPowerStateChangeNotification notify
;
4499 HaltRestartApplierContext
* ctx
;
4500 AbsoluteTime startTime
;
4503 ctx
= (HaltRestartApplierContext
*) context
;
4505 memset(¬ify
, 0, sizeof(notify
));
4506 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4507 notify
.returnValue
= 0;
4508 notify
.stateNumber
= ctx
->PowerState
;
4509 notify
.stateFlags
= ctx
->PowerFlags
;
4511 clock_get_uptime(&startTime
);
4512 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4513 deltaTime
= computeDeltaTimeMS(&startTime
);
4515 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4516 (gIOKitDebug
& kIOLogPMRootDomain
))
4518 _IOServiceInterestNotifier
* notifier
;
4519 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4521 // IOService children of IOPMrootDomain are not instrumented.
4522 // Only IORootParent currently falls under that group.
4526 LOG("%s handler %p took %u ms\n",
4527 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4534 static void quiescePowerTreeCallback( void * target
, void * param
)
4536 IOLockLock(gPMHaltLock
);
4538 thread_wakeup(param
);
4539 IOLockUnlock(gPMHaltLock
);
4542 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4544 HaltRestartApplierContext ctx
;
4545 AbsoluteTime startTime
;
4548 memset(&ctx
, 0, sizeof(ctx
));
4549 ctx
.RootDomain
= this;
4551 clock_get_uptime(&startTime
);
4555 case kPEUPSDelayHaltCPU
:
4556 ctx
.PowerState
= OFF_STATE
;
4557 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4558 ctx
.LogString
= "PowerOff";
4562 ctx
.PowerState
= RESTART_STATE
;
4563 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4564 ctx
.LogString
= "Restart";
4568 ctx
.PowerState
= ON_STATE
;
4569 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4570 ctx
.LogString
= "PagingOff";
4571 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4573 IOHibernateSystemRestart();
4581 // Notify legacy clients
4582 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4584 // For normal shutdown, turn off File Server Mode.
4585 if (kPEHaltCPU
== pe_type
)
4587 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4588 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4591 setPMSetting(setting
, num
);
4597 if (kPEPagingOff
!= pe_type
)
4599 // Notify in power tree order
4600 notifySystemShutdown(this, ctx
.MessageType
);
4603 IOCPURunPlatformHaltRestartActions(pe_type
);
4605 // Wait for PM to quiesce
4606 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4608 AbsoluteTime quiesceTime
= mach_absolute_time();
4610 IOLockLock(gPMHaltLock
);
4611 gPMQuiesced
= false;
4612 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4615 while (!gPMQuiesced
)
4617 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4620 IOLockUnlock(gPMHaltLock
);
4622 deltaTime
= computeDeltaTimeMS(&quiesceTime
);
4623 DLOG("PM quiesce took %u ms\n", deltaTime
);
4626 deltaTime
= computeDeltaTimeMS(&startTime
);
4627 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4630 //******************************************************************************
4633 //******************************************************************************
4635 IOReturn
IOPMrootDomain::shutdownSystem( void )
4637 return kIOReturnUnsupported
;
4640 //******************************************************************************
4643 //******************************************************************************
4645 IOReturn
IOPMrootDomain::restartSystem( void )
4647 return kIOReturnUnsupported
;
4651 // MARK: System Capability
4653 //******************************************************************************
4654 // tagPowerPlaneService
4656 // Running on PM work loop thread.
4657 //******************************************************************************
4659 void IOPMrootDomain::tagPowerPlaneService(
4660 IOService
* service
,
4661 IOPMActions
* actions
)
4664 bool isDisplayWrangler
;
4666 memset(actions
, 0, sizeof(*actions
));
4667 actions
->target
= this;
4669 if (service
== this)
4671 actions
->actionPowerChangeStart
=
4672 OSMemberFunctionCast(
4673 IOPMActionPowerChangeStart
, this,
4674 &IOPMrootDomain::handleOurPowerChangeStart
);
4676 actions
->actionPowerChangeDone
=
4677 OSMemberFunctionCast(
4678 IOPMActionPowerChangeDone
, this,
4679 &IOPMrootDomain::handleOurPowerChangeDone
);
4681 actions
->actionPowerChangeOverride
=
4682 OSMemberFunctionCast(
4683 IOPMActionPowerChangeOverride
, this,
4684 &IOPMrootDomain::overrideOurPowerChange
);
4689 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4690 if (isDisplayWrangler
)
4695 isDisplayWrangler
= false;
4698 #if defined(__i386__) || defined(__x86_64__)
4699 if (isDisplayWrangler
)
4700 flags
|= kPMActionsFlagIsDisplayWrangler
;
4701 if (service
->getProperty("IOPMStrictTreeOrder"))
4702 flags
|= kPMActionsFlagIsGraphicsDevice
;
4703 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4704 flags
|= kPMActionsFlagIsAudioDevice
;
4707 // Find the power connection object that is a child of the PCI host
4708 // bridge, and has a graphics/audio device attached below. Mark the
4709 // power branch for delayed child notifications.
4713 IORegistryEntry
* child
= service
;
4714 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4716 while (child
!= this)
4718 if ((parent
== pciHostBridgeDriver
) ||
4721 if (OSDynamicCast(IOPowerConnection
, child
))
4723 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4724 conn
->delayChildNotification
= true;
4729 parent
= child
->getParentEntry(gIOPowerPlane
);
4735 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4736 actions
->parameter
|= flags
;
4737 actions
->actionPowerChangeOverride
=
4738 OSMemberFunctionCast(
4739 IOPMActionPowerChangeOverride
, this,
4740 &IOPMrootDomain::overridePowerChangeForUIService
);
4742 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4744 actions
->actionActivityTickle
=
4745 OSMemberFunctionCast(
4746 IOPMActionActivityTickle
, this,
4747 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4749 actions
->actionUpdatePowerClient
=
4750 OSMemberFunctionCast(
4751 IOPMActionUpdatePowerClient
, this,
4752 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4757 // Locate the first PCI host bridge for PMTrace.
4758 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4760 IOService
* provider
= service
->getProvider();
4761 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4762 provider
->inPlane(gIODTPlane
))
4764 pciHostBridgeDevice
= provider
;
4765 pciHostBridgeDriver
= service
;
4766 DLOG("PMTrace found PCI host bridge %s->%s\n",
4767 provider
->getName(), service
->getName());
4771 // Tag top-level PCI devices. The order of PMinit() call does not
4772 // change across boots and is used as the PCI bit number.
4773 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4775 // Would prefer to check built-in property, but tagPowerPlaneService()
4776 // is called before pciDevice->registerService().
4777 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4778 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4780 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4783 // Save the assigned bit for fast lookup.
4784 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4786 actions
->actionPowerChangeStart
=
4787 OSMemberFunctionCast(
4788 IOPMActionPowerChangeStart
, this,
4789 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4791 actions
->actionPowerChangeDone
=
4792 OSMemberFunctionCast(
4793 IOPMActionPowerChangeDone
, this,
4794 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4800 //******************************************************************************
4801 // PM actions for root domain
4802 //******************************************************************************
4804 void IOPMrootDomain::overrideOurPowerChange(
4805 IOService
* service
,
4806 IOPMActions
* actions
,
4807 IOPMPowerStateIndex
* inOutPowerState
,
4808 IOPMPowerChangeFlags
* inOutChangeFlags
,
4809 IOPMRequestTag requestTag
)
4811 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4812 uint32_t changeFlags
= *inOutChangeFlags
;
4813 uint32_t currentPowerState
= (uint32_t) getPowerState();
4815 if (changeFlags
& kIOPMParentInitiated
)
4817 // Root parent is permanently pegged at max power,
4818 // a parent initiated power change is unexpected.
4819 *inOutChangeFlags
|= kIOPMNotDone
;
4823 if (powerState
< currentPowerState
)
4825 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4827 // Root domain is dropping power state ON->SLEEP.
4828 // If system is in full wake, first enter dark wake by
4829 // converting the power drop to a capability change.
4830 // Once in dark wake, transition to sleep state ASAP.
4832 darkWakeToSleepASAP
= true;
4834 // Drop graphics and audio capability
4835 _desiredCapability
&= ~(
4836 kIOPMSystemCapabilityGraphics
|
4837 kIOPMSystemCapabilityAudio
);
4839 // Convert to capability change (ON->ON)
4840 *inOutPowerState
= ON_STATE
;
4841 *inOutChangeFlags
|= kIOPMSynchronize
;
4843 // Revert device desire from SLEEP to ON
4844 changePowerStateToPriv(ON_STATE
);
4848 // System is in dark wake, ok to drop power state.
4849 // Broadcast root powering down to entire tree.
4850 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4853 else if (powerState
> currentPowerState
)
4855 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4857 // Broadcast power up when waking from sleep, but not for the
4858 // initial power change at boot by checking for cpu capability.
4859 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4864 void IOPMrootDomain::handleOurPowerChangeStart(
4865 IOService
* service
,
4866 IOPMActions
* actions
,
4867 IOPMPowerStateIndex powerState
,
4868 IOPMPowerChangeFlags
* inOutChangeFlags
,
4869 IOPMRequestTag requestTag
)
4871 uint32_t changeFlags
= *inOutChangeFlags
;
4872 uint32_t currentPowerState
= (uint32_t) getPowerState();
4873 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4874 bool publishSleepReason
= false;
4876 _systemTransitionType
= kSystemTransitionNone
;
4877 _systemMessageClientMask
= 0;
4878 capabilityLoss
= false;
4879 toldPowerdCapWillChange
= false;
4881 if (lowBatteryCondition
)
4883 // Low battery notification may arrive after the initial sleep request
4884 // has been queued. Override the sleep reason so powerd and others can
4885 // treat this as an emergency sleep.
4886 sleepReason
= kIOPMSleepReasonLowPower
;
4889 // 1. Explicit capability change.
4891 if (changeFlags
& kIOPMSynchronize
)
4893 if (powerState
== ON_STATE
)
4895 if (changeFlags
& kIOPMSyncNoChildNotify
)
4896 _systemTransitionType
= kSystemTransitionNewCapClient
;
4898 _systemTransitionType
= kSystemTransitionCapability
;
4902 // 2. Going to sleep (cancellation still possible).
4904 else if (powerState
< currentPowerState
)
4905 _systemTransitionType
= kSystemTransitionSleep
;
4907 // 3. Woke from (idle or demand) sleep.
4909 else if (!systemBooting
&&
4910 (changeFlags
& kIOPMSelfInitiated
) &&
4911 (powerState
> currentPowerState
))
4913 _systemTransitionType
= kSystemTransitionWake
;
4914 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4915 kIOPMSystemCapabilityNetwork
;
4917 // Early exit from dark wake to full (e.g. LID open)
4918 if (kFullWakeReasonNone
!= fullWakeReason
)
4920 _desiredCapability
|= (
4921 kIOPMSystemCapabilityGraphics
|
4922 kIOPMSystemCapabilityAudio
);
4925 IOHibernateSetWakeCapabilities(_desiredCapability
);
4929 // Update pending wake capability at the beginning of every
4930 // state transition (including synchronize). This will become
4931 // the current capability at the end of the transition.
4933 if (kSystemTransitionSleep
== _systemTransitionType
)
4935 _pendingCapability
= 0;
4936 capabilityLoss
= true;
4939 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4941 _pendingCapability
= _desiredCapability
|
4942 kIOPMSystemCapabilityCPU
|
4943 kIOPMSystemCapabilityNetwork
;
4945 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4946 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4948 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4949 (_pendingCapability
== _currentCapability
))
4951 // Cancel the PM state change.
4952 _systemTransitionType
= kSystemTransitionNone
;
4953 *inOutChangeFlags
|= kIOPMNotDone
;
4955 if (__builtin_popcount(_pendingCapability
) <
4956 __builtin_popcount(_currentCapability
))
4957 capabilityLoss
= true;
4960 // 1. Capability change.
4962 if (kSystemTransitionCapability
== _systemTransitionType
)
4964 // Dark to Full transition.
4965 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4967 tracePoint( kIOPMTracePointDarkWakeExit
);
4969 willEnterFullWake();
4972 // Full to Dark transition.
4973 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4975 // Clear previous stats
4976 IOLockLock(pmStatsLock
);
4977 if (pmStatsAppResponses
)
4979 pmStatsAppResponses
->release();
4980 pmStatsAppResponses
= OSArray::withCapacity(5);
4982 IOLockUnlock(pmStatsLock
);
4985 tracePoint( kIOPMTracePointDarkWakeEntry
);
4986 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4987 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4988 kSystemMessageClientLegacyApp
;
4992 // Prevent user active transitions before notifying clients
4993 // that system will sleep.
4994 preventTransitionToUserActive(true);
4996 IOService::setAdvisoryTickleEnable( false );
4998 // Publish the sleep reason for full to dark wake
4999 publishSleepReason
= true;
5000 lastSleepReason
= fullToDarkReason
= sleepReason
;
5002 // Publish a UUID for the Sleep --> Wake cycle
5003 handlePublishSleepWakeUUID(true);
5004 if (sleepDelaysReport
) {
5005 clock_get_uptime(&ts_sleepStart
);
5006 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5013 else if (kSystemTransitionSleep
== _systemTransitionType
)
5015 // Beginning of a system sleep transition.
5016 // Cancellation is still possible.
5017 tracePoint( kIOPMTracePointSleepStarted
);
5019 _systemMessageClientMask
= kSystemMessageClientAll
;
5020 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5021 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5022 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5023 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5025 // Record the reason for dark wake back to sleep
5026 // System may not have ever achieved full wake
5028 publishSleepReason
= true;
5029 lastSleepReason
= sleepReason
;
5030 if (sleepDelaysReport
) {
5031 clock_get_uptime(&ts_sleepStart
);
5032 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5038 else if (kSystemTransitionWake
== _systemTransitionType
)
5040 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5041 // Clear stats about sleep
5043 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5045 willEnterFullWake();
5049 // Message powerd only
5050 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5051 tellClients(kIOMessageSystemWillPowerOn
);
5055 // The only location where the sleep reason is published. At this point
5056 // sleep can still be cancelled, but sleep reason should be published
5057 // early for logging purposes.
5059 if (publishSleepReason
)
5061 static const char * IOPMSleepReasons
[] =
5063 kIOPMClamshellSleepKey
,
5064 kIOPMPowerButtonSleepKey
,
5065 kIOPMSoftwareSleepKey
,
5066 kIOPMOSSwitchHibernationKey
,
5068 kIOPMLowPowerSleepKey
,
5069 kIOPMThermalEmergencySleepKey
,
5070 kIOPMMaintenanceSleepKey
,
5071 kIOPMSleepServiceExitKey
,
5072 kIOPMDarkWakeThermalEmergencyKey
5075 // Record sleep cause in IORegistry
5076 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5077 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5078 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5079 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5083 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5084 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5086 _systemStateGeneration
++;
5087 systemDarkWake
= false;
5089 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5091 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5092 _systemTransitionType
, _systemStateGeneration
,
5093 _systemMessageClientMask
,
5094 _desiredCapability
, _currentCapability
, _pendingCapability
);
5098 void IOPMrootDomain::handleOurPowerChangeDone(
5099 IOService
* service
,
5100 IOPMActions
* actions
,
5101 IOPMPowerStateIndex powerState
,
5102 IOPMPowerChangeFlags changeFlags
,
5103 IOPMRequestTag requestTag __unused
)
5105 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5107 _systemTransitionType
= kSystemTransitionNone
;
5111 if (_systemTransitionType
!= kSystemTransitionNone
)
5113 uint32_t currentPowerState
= (uint32_t) getPowerState();
5115 if (changeFlags
& kIOPMNotDone
)
5117 // Power down was cancelled or vetoed.
5118 _pendingCapability
= _currentCapability
;
5119 lastSleepReason
= 0;
5121 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5122 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5124 pmPowerStateQueue
->submitPowerEvent(
5125 kPowerEventPolicyStimulus
,
5126 (void *) kStimulusDarkWakeReentry
,
5127 _systemStateGeneration
);
5130 // Revert device desire to max.
5131 changePowerStateToPriv(ON_STATE
);
5135 // Send message on dark wake to full wake promotion.
5136 // tellChangeUp() handles the normal SLEEP->ON case.
5138 if (kSystemTransitionCapability
== _systemTransitionType
)
5140 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5142 lastSleepReason
= 0; // stop logging wrangler tickles
5143 tellClients(kIOMessageSystemHasPoweredOn
);
5145 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5147 // Going dark, reset full wake state
5148 // userIsActive will be cleared by wrangler powering down
5149 wranglerTickled
= false;
5150 fullWakeReason
= kFullWakeReasonNone
;
5152 if (ts_sleepStart
) {
5153 clock_get_uptime(&wake2DarkwakeDelay
);
5154 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5155 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5161 // Reset state after exiting from dark wake.
5163 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5164 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5166 darkWakeMaintenance
= false;
5167 darkWakeToSleepASAP
= false;
5168 pciCantSleepValid
= false;
5169 darkWakeSleepService
= false;
5171 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5173 // Remove the influence of display power assertion
5174 // before next system wake.
5175 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5176 kWranglerPowerStateMin
);
5177 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5181 // Entered dark mode.
5183 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5184 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5186 // Queue an evaluation of whether to remain in dark wake,
5187 // and for how long. This serves the purpose of draining
5188 // any assertions from the queue.
5190 pmPowerStateQueue
->submitPowerEvent(
5191 kPowerEventPolicyStimulus
,
5192 (void *) kStimulusDarkWakeEntry
,
5193 _systemStateGeneration
);
5197 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5198 "dcp %x:%x:%x, dbgtimer %u\n",
5199 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5200 _systemTransitionType
, _systemStateGeneration
,
5201 _systemMessageClientMask
,
5202 _desiredCapability
, _currentCapability
, _pendingCapability
,
5203 _lastDebugWakeSeconds
);
5205 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5208 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5209 if (clamshellExists
&& fullWakeThreadCall
&&
5210 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5212 // Not the initial graphics full power, graphics won't
5213 // send a power notification to trigger a lid state
5216 AbsoluteTime deadline
;
5217 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5218 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5222 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5225 // Update current system capability.
5226 if (_currentCapability
!= _pendingCapability
)
5227 _currentCapability
= _pendingCapability
;
5229 // Update highest system capability.
5231 _highestCapability
|= _currentCapability
;
5233 if (darkWakePostTickle
&&
5234 (kSystemTransitionWake
== _systemTransitionType
) &&
5235 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5236 kDarkWakeFlagHIDTickleLate
)
5238 darkWakePostTickle
= false;
5242 // Reset tracepoint at completion of capability change,
5243 // completion of wake transition, and aborted sleep transition.
5245 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5246 (_systemTransitionType
== kSystemTransitionWake
) ||
5247 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5248 (changeFlags
& kIOPMNotDone
)))
5250 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5251 tracePoint( kIOPMTracePointSystemUp
);
5254 _systemTransitionType
= kSystemTransitionNone
;
5255 _systemMessageClientMask
= 0;
5256 toldPowerdCapWillChange
= false;
5258 logGraphicsClamp
= false;
5260 if (lowBatteryCondition
) {
5261 privateSleepSystem (kIOPMSleepReasonLowPower
);
5266 //******************************************************************************
5267 // PM actions for graphics and audio.
5268 //******************************************************************************
5270 void IOPMrootDomain::overridePowerChangeForUIService(
5271 IOService
* service
,
5272 IOPMActions
* actions
,
5273 IOPMPowerStateIndex
* inOutPowerState
,
5274 IOPMPowerChangeFlags
* inOutChangeFlags
)
5276 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5277 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5279 if (kSystemTransitionNone
== _systemTransitionType
)
5281 // Not in midst of a system transition.
5282 // Do not modify power limit enable state.
5284 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5286 // Activate power limiter.
5288 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5289 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5290 (changeFlags
& kIOPMSynchronize
))
5292 actions
->parameter
|= kPMActionsFlagLimitPower
;
5294 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5295 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5296 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5297 (changeFlags
& kIOPMSynchronize
))
5299 actions
->parameter
|= kPMActionsFlagLimitPower
;
5301 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5302 (_systemTransitionType
== kSystemTransitionSleep
))
5304 // For graphics devices, arm the limiter when entering
5305 // system sleep. Not when dropping to dark wake.
5306 actions
->parameter
|= kPMActionsFlagLimitPower
;
5309 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5311 DLOG("+ plimit %s %p\n",
5312 service
->getName(), OBFUSCATE(service
));
5317 // Remove power limit.
5319 if ((actions
->parameter
& (
5320 kPMActionsFlagIsDisplayWrangler
|
5321 kPMActionsFlagIsGraphicsDevice
)) &&
5322 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5324 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5326 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5327 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5329 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5332 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5334 DLOG("- plimit %s %p\n",
5335 service
->getName(), OBFUSCATE(service
));
5339 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5341 uint32_t maxPowerState
= (uint32_t)(-1);
5343 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5345 // Enforce limit for system power/cap transitions.
5348 if ((service
->getPowerState() > maxPowerState
) &&
5349 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5353 // Remove lingering effects of any tickle before entering
5354 // dark wake. It will take a new tickle to return to full
5355 // wake, so the existing tickle state is useless.
5357 if (changeFlags
& kIOPMDomainDidChange
)
5358 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5360 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5367 // Deny all self-initiated changes when power is limited.
5368 // Wrangler tickle should never defeat the limiter.
5370 maxPowerState
= service
->getPowerState();
5373 if (powerState
> maxPowerState
)
5375 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5376 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5378 *inOutPowerState
= maxPowerState
;
5380 if (darkWakePostTickle
&&
5381 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5382 (changeFlags
& kIOPMDomainWillChange
) &&
5383 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5384 kDarkWakeFlagHIDTickleEarly
))
5386 darkWakePostTickle
= false;
5391 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5393 if (logGraphicsClamp
)
5398 clock_get_uptime(&now
);
5399 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5400 absolutetime_to_nanoseconds(now
, &nsec
);
5401 if (kIOLogPMRootDomain
& gIOKitDebug
)
5402 MSG("Graphics suppressed %u ms\n",
5403 ((int)((nsec
) / 1000000ULL)));
5405 graphicsSuppressed
= true;
5410 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5411 IOService
* service
,
5412 IOPMActions
* actions
)
5415 // Warning: Not running in PM work loop context - don't modify state !!!
5416 // Trap tickle directed to IODisplayWrangler while running with graphics
5417 // capability suppressed.
5419 assert(service
== wrangler
);
5421 clock_get_uptime(&userActivityTime
);
5422 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5423 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5424 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5426 userActivityCount
++;
5427 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5428 userActivityCount
, lastSleepReason
);
5431 if (!wranglerTickled
&&
5432 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5434 DLOG("display wrangler tickled\n");
5435 if (kIOLogPMRootDomain
& gIOKitDebug
)
5436 OSReportWithBacktrace("Dark wake display tickle");
5437 if (pmPowerStateQueue
)
5439 pmPowerStateQueue
->submitPowerEvent(
5440 kPowerEventPolicyStimulus
,
5441 (void *) kStimulusDarkWakeActivityTickle
,
5442 true /* set wake type */ );
5448 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5449 IOService
* service
,
5450 IOPMActions
* actions
,
5451 const OSSymbol
* powerClient
,
5452 IOPMPowerStateIndex oldPowerState
,
5453 IOPMPowerStateIndex newPowerState
)
5456 assert(service
== wrangler
);
5458 // This function implements half of the user active detection
5459 // by monitoring changes to the display wrangler's device desire.
5461 // User becomes active when either:
5462 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5463 // in max power state. This desire change in absence of a power state
5464 // change is detected within. This handles the case when user becomes
5465 // active while the display is already lit by setDisplayPowerOn().
5467 // 2. Power state change to max, and DeviceDesire is also at max.
5468 // Handled by displayWranglerNotification().
5470 // User becomes inactive when DeviceDesire drops to sleep state or below.
5472 DLOG("wrangler %s (ps %u, %u->%u)\n",
5473 powerClient
->getCStringNoCopy(),
5474 (uint32_t) service
->getPowerState(),
5475 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5477 if (powerClient
== gIOPMPowerClientDevice
)
5479 if ((newPowerState
> oldPowerState
) &&
5480 (newPowerState
== kWranglerPowerStateMax
) &&
5481 (service
->getPowerState() == kWranglerPowerStateMax
))
5483 evaluatePolicy( kStimulusEnterUserActiveState
);
5486 if ((newPowerState
< oldPowerState
) &&
5487 (newPowerState
<= kWranglerPowerStateSleep
))
5489 evaluatePolicy( kStimulusLeaveUserActiveState
);
5495 //******************************************************************************
5496 // User active state management
5497 //******************************************************************************
5499 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5502 _preventUserActive
= prevent
;
5503 if (wrangler
&& !_preventUserActive
)
5505 // Allowing transition to user active, but the wrangler may have
5506 // already powered ON in case of sleep cancel/revert. Poll the
5507 // same conditions checked for in displayWranglerNotification()
5508 // to bring the user active state up to date.
5510 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5511 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5512 kWranglerPowerStateMax
))
5514 evaluatePolicy( kStimulusEnterUserActiveState
);
5520 //******************************************************************************
5521 // Approve usage of delayed child notification by PM.
5522 //******************************************************************************
5524 bool IOPMrootDomain::shouldDelayChildNotification(
5525 IOService
* service
)
5527 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5528 (kFullWakeReasonNone
== fullWakeReason
) &&
5529 (kSystemTransitionWake
== _systemTransitionType
))
5531 DLOG("%s: delay child notify\n", service
->getName());
5537 //******************************************************************************
5538 // PM actions for PCI device.
5539 //******************************************************************************
5541 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5542 IOService
* service
,
5543 IOPMActions
* actions
,
5544 IOPMPowerStateIndex powerState
,
5545 IOPMPowerChangeFlags
* inOutChangeFlags
)
5547 pmTracer
->tracePCIPowerChange(
5548 PMTraceWorker::kPowerChangeStart
,
5549 service
, *inOutChangeFlags
,
5550 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5553 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5554 IOService
* service
,
5555 IOPMActions
* actions
,
5556 IOPMPowerStateIndex powerState
,
5557 IOPMPowerChangeFlags changeFlags
)
5559 pmTracer
->tracePCIPowerChange(
5560 PMTraceWorker::kPowerChangeCompleted
,
5561 service
, changeFlags
,
5562 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5565 //******************************************************************************
5568 // Override IOService::registerInterest() to intercept special clients.
5569 //******************************************************************************
5571 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5574 friend class IOPMrootDomain
;
5575 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5578 uint32_t ackTimeoutCnt
;
5579 uint32_t msgType
; // Message pending ack
5583 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5585 IONotifier
* IOPMrootDomain::registerInterest(
5586 const OSSymbol
* typeOfInterest
,
5587 IOServiceInterestHandler handler
,
5588 void * target
, void * ref
)
5590 IOPMServiceInterestNotifier
*notifier
= 0;
5591 bool isSystemCapabilityClient
;
5592 bool isKernelCapabilityClient
;
5593 IOReturn rc
= kIOReturnError
;;
5595 isSystemCapabilityClient
=
5597 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5599 isKernelCapabilityClient
=
5601 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5603 if (isSystemCapabilityClient
)
5604 typeOfInterest
= gIOAppPowerStateInterest
;
5606 notifier
= new IOPMServiceInterestNotifier
;
5607 if (!notifier
) return NULL
;
5609 if (notifier
->init()) {
5610 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5612 if (rc
!= kIOReturnSuccess
) {
5613 notifier
->release();
5618 if (pmPowerStateQueue
)
5620 notifier
->ackTimeoutCnt
= 0;
5621 if (isSystemCapabilityClient
)
5624 if (pmPowerStateQueue
->submitPowerEvent(
5625 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5626 notifier
->release();
5629 if (isKernelCapabilityClient
)
5632 if (pmPowerStateQueue
->submitPowerEvent(
5633 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5634 notifier
->release();
5641 //******************************************************************************
5642 // systemMessageFilter
5644 //******************************************************************************
5646 bool IOPMrootDomain::systemMessageFilter(
5647 void * object
, void * arg1
, void * arg2
, void * arg3
)
5649 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5650 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5651 bool isCapClient
= false;
5653 IOPMServiceInterestNotifier
*notifier
;
5655 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5657 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5658 (!isCapMsg
|| !_joinedCapabilityClients
||
5659 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5662 // Capability change message for app and kernel clients.
5666 if ((context
->notifyType
== kNotifyPriority
) ||
5667 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5670 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5671 (object
== (void *) systemCapabilityNotifier
))
5677 IOPMSystemCapabilityChangeParameters
* capArgs
=
5678 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5680 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5682 capArgs
->fromCapabilities
= 0;
5683 capArgs
->toCapabilities
= _currentCapability
;
5684 capArgs
->changeFlags
= 0;
5688 capArgs
->fromCapabilities
= _currentCapability
;
5689 capArgs
->toCapabilities
= _pendingCapability
;
5691 if (context
->isPreChange
)
5692 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5694 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5696 if ((object
== (void *) systemCapabilityNotifier
) &&
5697 context
->isPreChange
)
5699 toldPowerdCapWillChange
= true;
5703 // Capability change messages only go to the PM configd plugin.
5704 // Wait for response post-change if capabilitiy is increasing.
5705 // Wait for response pre-change if capability is decreasing.
5707 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5708 ( (capabilityLoss
&& context
->isPreChange
) ||
5709 (!capabilityLoss
&& !context
->isPreChange
) ) )
5711 // app has not replied yet, wait for it
5712 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5715 notifier
->msgType
= context
->messageType
;
5723 // Capability client will always see kIOMessageCanSystemSleep,
5724 // even for demand sleep. It will also have a chance to veto
5725 // sleep one last time after all clients have responded to
5726 // kIOMessageSystemWillSleep
5728 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5729 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5731 if (object
== (OSObject
*) systemCapabilityNotifier
)
5735 notifier
->msgType
= context
->messageType
;
5740 // Not idle sleep, don't ask apps.
5741 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5747 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5749 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5750 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5751 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5753 notifier
->msgType
= context
->messageType
;
5760 // Reject capability change messages for legacy clients.
5761 // Reject legacy system sleep messages for capability client.
5763 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5768 // Filter system sleep messages.
5770 if ((context
->notifyType
== kNotifyApps
) &&
5771 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5777 if (notifier
->ackTimeoutCnt
>= 3)
5778 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5780 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5783 notifier
->msgType
= context
->messageType
;
5786 else if ((context
->notifyType
== kNotifyPriority
) &&
5787 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5794 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5796 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5797 if (_joinedCapabilityClients
->getCount() == 0)
5799 DLOG("destroyed capability client set %p\n",
5800 OBFUSCATE(_joinedCapabilityClients
));
5801 _joinedCapabilityClients
->release();
5802 _joinedCapabilityClients
= 0;
5809 //******************************************************************************
5810 // setMaintenanceWakeCalendar
5812 //******************************************************************************
5814 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5815 const IOPMCalendarStruct
* calendar
)
5821 return kIOReturnBadArgument
;
5823 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5825 return kIOReturnNoMemory
;
5827 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5828 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5829 if (kIOReturnSuccess
== ret
)
5830 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5832 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5834 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5835 if (kIOReturnSuccess
== ret
)
5836 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5838 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5845 // MARK: Display Wrangler
5847 //******************************************************************************
5848 // displayWranglerNotification
5850 // Handle the notification when the IODisplayWrangler changes power state.
5851 //******************************************************************************
5853 IOReturn
IOPMrootDomain::displayWranglerNotification(
5854 void * target
, void * refCon
,
5855 UInt32 messageType
, IOService
* service
,
5856 void * messageArgument
, vm_size_t argSize
)
5859 int displayPowerState
;
5860 IOPowerStateChangeNotification
* params
=
5861 (IOPowerStateChangeNotification
*) messageArgument
;
5863 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5864 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5865 return kIOReturnUnsupported
;
5869 return kIOReturnUnsupported
;
5871 displayPowerState
= params
->stateNumber
;
5872 DLOG("wrangler %s ps %d\n",
5873 getIOMessageString(messageType
), displayPowerState
);
5875 switch (messageType
) {
5876 case kIOMessageDeviceWillPowerOff
:
5877 // Display wrangler has dropped power due to display idle
5878 // or force system sleep.
5880 // 4 Display ON kWranglerPowerStateMax
5881 // 3 Display Dim kWranglerPowerStateDim
5882 // 2 Display Sleep kWranglerPowerStateSleep
5883 // 1 Not visible to user
5884 // 0 Not visible to user kWranglerPowerStateMin
5886 if (displayPowerState
<= kWranglerPowerStateSleep
)
5887 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5890 case kIOMessageDeviceHasPoweredOn
:
5891 // Display wrangler has powered on due to user activity
5892 // or wake from sleep.
5894 if (kWranglerPowerStateMax
== displayPowerState
)
5896 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5898 // See comment in handleUpdatePowerClientForDisplayWrangler
5899 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5900 kWranglerPowerStateMax
)
5902 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5908 return kIOReturnUnsupported
;
5911 //******************************************************************************
5912 // displayWranglerMatchPublished
5914 // Receives a notification when the IODisplayWrangler is published.
5915 // When it's published we install a power state change handler.
5916 //******************************************************************************
5918 bool IOPMrootDomain::displayWranglerMatchPublished(
5921 IOService
* newService
,
5922 IONotifier
* notifier __unused
)
5925 // found the display wrangler, now install a handler
5926 if( !newService
->registerInterest( gIOGeneralInterest
,
5927 &displayWranglerNotification
, target
, 0) )
5935 #if defined(__i386__) || defined(__x86_64__)
5937 bool IOPMrootDomain::IONVRAMMatchPublished(
5940 IOService
* newService
,
5941 IONotifier
* notifier
)
5943 unsigned int len
= 0;
5944 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5945 OSNumber
*statusCode
= NULL
;
5947 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5949 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5950 if (statusCode
!= NULL
) {
5951 if (statusCode
->unsigned64BitValue() != 0) {
5952 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5953 MSG("System was rebooted due to Sleep/Wake failure\n");
5956 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5957 MSG("System was non-responsive and was rebooted by watchdog\n");
5961 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5963 if (notifier
) notifier
->remove();
5968 bool IOPMrootDomain::IONVRAMMatchPublished(
5971 IOService
* newService
,
5972 IONotifier
* notifier __unused
)
5979 //******************************************************************************
5982 //******************************************************************************
5984 void IOPMrootDomain::reportUserInput( void )
5988 OSDictionary
* matching
;
5992 matching
= serviceMatching("IODisplayWrangler");
5993 iter
= getMatchingServices(matching
);
5994 if (matching
) matching
->release();
5997 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6003 wrangler
->activityTickle(0,0);
6007 //******************************************************************************
6008 // latchDisplayWranglerTickle
6009 //******************************************************************************
6011 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6016 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6017 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6018 !checkSystemCanSustainFullWake())
6020 // Currently in dark wake, and not transitioning to full wake.
6021 // Full wake is unsustainable, so latch the tickle to prevent
6022 // the display from lighting up momentarily.
6023 wranglerTickleLatched
= true;
6027 wranglerTickleLatched
= false;
6030 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6032 wranglerTickleLatched
= false;
6034 pmPowerStateQueue
->submitPowerEvent(
6035 kPowerEventPolicyStimulus
,
6036 (void *) kStimulusDarkWakeActivityTickle
);
6039 return wranglerTickleLatched
;
6045 //******************************************************************************
6046 // setDisplayPowerOn
6048 // For root domain user client
6049 //******************************************************************************
6051 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6053 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6054 (void *) 0, options
);
6060 //******************************************************************************
6063 // Notification on battery class IOPowerSource appearance
6064 //******************************************************************************
6066 bool IOPMrootDomain::batteryPublished(
6069 IOService
* resourceService
,
6070 IONotifier
* notifier __unused
)
6072 // rdar://2936060&4435589
6073 // All laptops have dimmable LCD displays
6074 // All laptops have batteries
6075 // So if this machine has a battery, publish the fact that the backlight
6076 // supports dimming.
6077 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6083 // MARK: System PM Policy
6085 //******************************************************************************
6086 // checkSystemSleepAllowed
6088 //******************************************************************************
6090 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6091 uint32_t sleepReason
)
6095 // Conditions that prevent idle and demand system sleep.
6098 if (userDisabledAllSleep
)
6100 err
= 1; // 1. user-space sleep kill switch
6104 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6106 err
= 2; // 2. restart or shutdown in progress
6113 // Conditions above pegs the system at full wake.
6114 // Conditions below prevent system sleep but does not prevent
6115 // dark wake, and must be called from gated context.
6118 err
= 3; // 3. config does not support sleep
6122 if (lowBatteryCondition
|| thermalWarningState
)
6124 break; // always sleep on low battery or when in thermal warning state
6127 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6129 break; // always sleep on dark wake thermal emergencies
6132 if (preventSystemSleepList
->getCount() != 0)
6134 err
= 4; // 4. child prevent system sleep clamp
6138 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6139 kIOPMDriverAssertionLevelOn
)
6141 err
= 5; // 5. CPU assertion
6145 if (pciCantSleepValid
)
6147 if (pciCantSleepFlag
)
6148 err
= 6; // 6. PCI card does not support PM (cached)
6151 else if (sleepSupportedPEFunction
&&
6152 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6155 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6156 ret
= getPlatform()->callPlatformFunction(
6157 sleepSupportedPEFunction
, false,
6158 NULL
, NULL
, NULL
, NULL
);
6159 pciCantSleepValid
= true;
6160 pciCantSleepFlag
= false;
6161 if ((platformSleepSupport
& kPCICantSleep
) ||
6162 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6164 err
= 6; // 6. PCI card does not support PM
6165 pciCantSleepFlag
= true;
6174 DLOG("System sleep prevented by %d\n", err
);
6180 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6182 return checkSystemSleepAllowed(0, 0);
6185 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6188 return checkSystemSleepAllowed(1, sleepReason
);
6191 //******************************************************************************
6192 // checkSystemCanSustainFullWake
6193 //******************************************************************************
6195 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6198 if (lowBatteryCondition
|| thermalWarningState
)
6200 // Low battery wake, or received a low battery notification
6201 // while system is awake. This condition will persist until
6202 // the following wake.
6206 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6208 // Graphics state is unknown and external display might not be probed.
6209 // Do not incorporate state that requires graphics to be in max power
6210 // such as desktopMode or clamshellDisabled.
6212 if (!acAdaptorConnected
)
6214 DLOG("full wake check: no AC\n");
6222 //******************************************************************************
6225 // Conditions that affect our wake/sleep decision has changed.
6226 // If conditions dictate that the system must remain awake, clamp power
6227 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6228 // is TRUE, then remove the power clamp and allow the power state to drop
6230 //******************************************************************************
6232 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6234 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
6235 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
6239 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
6241 changePowerStateToPriv(ON_STATE
);
6243 else if ( sleepASAP
)
6245 changePowerStateToPriv(SLEEP_STATE
);
6249 void IOPMrootDomain::handleDisplayPowerOn( )
6251 if (!wrangler
) return;
6252 if (displayPowerOnRequested
)
6254 if (!checkSystemCanSustainFullWake()) return;
6256 // Force wrangler to max power state. If system is in dark wake
6257 // this alone won't raise the wrangler's power state.
6259 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6261 // System in dark wake, always requesting full wake should
6262 // not have any bad side-effects, even if the request fails.
6264 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6266 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6267 requestFullWake( kFullWakeReasonDisplayOn
);
6272 // Relenquish desire to power up display.
6273 // Must first transition to state 1 since wrangler doesn't
6274 // power off the displays at state 0. At state 0 the root
6275 // domain is removed from the wrangler's power client list.
6277 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6278 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6284 //******************************************************************************
6285 // dispatchPowerEvent
6287 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6288 //******************************************************************************
6290 void IOPMrootDomain::dispatchPowerEvent(
6291 uint32_t event
, void * arg0
, uint64_t arg1
)
6293 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6298 case kPowerEventFeatureChanged
:
6299 messageClients(kIOPMMessageFeatureChange
, this);
6302 case kPowerEventReceivedPowerNotification
:
6303 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6306 case kPowerEventSystemBootCompleted
:
6309 systemBooting
= false;
6311 if (lowBatteryCondition
)
6313 privateSleepSystem (kIOPMSleepReasonLowPower
);
6315 // The rest is unnecessary since the system is expected
6316 // to sleep immediately. The following wake will update
6321 if (swd_flags
& SWD_VALID_LOGS
) {
6322 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6323 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6324 swd_logBufMap
->release();
6327 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6328 sleepWakeDebugDumpFromFile();
6330 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6331 // If logs are invalid, write the failure code
6332 sleepWakeDebugDumpFromMem(NULL
);
6334 // If lid is closed, re-send lid closed notification
6335 // now that booting is complete.
6336 if ( clamshellClosed
)
6338 handlePowerNotification(kLocalEvalClamshellCommand
);
6340 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6345 case kPowerEventSystemShutdown
:
6346 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6348 /* We set systemShutdown = true during shutdown
6349 to prevent sleep at unexpected times while loginwindow is trying
6350 to shutdown apps and while the OS is trying to transition to
6353 Set to true during shutdown, as soon as loginwindow shows
6354 the "shutdown countdown dialog", through individual app
6355 termination, and through black screen kernel shutdown.
6357 systemShutdown
= true;
6360 A shutdown was initiated, but then the shutdown
6361 was cancelled, clearing systemShutdown to false here.
6363 systemShutdown
= false;
6367 case kPowerEventUserDisabledSleep
:
6368 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6371 case kPowerEventRegisterSystemCapabilityClient
:
6372 if (systemCapabilityNotifier
)
6374 systemCapabilityNotifier
->release();
6375 systemCapabilityNotifier
= 0;
6379 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6380 systemCapabilityNotifier
->retain();
6382 /* intentional fall-through */
6383 [[clang::fallthrough]];
6385 case kPowerEventRegisterKernelCapabilityClient
:
6386 if (!_joinedCapabilityClients
)
6387 _joinedCapabilityClients
= OSSet::withCapacity(8);
6390 IONotifier
* notify
= (IONotifier
*) arg0
;
6391 if (_joinedCapabilityClients
)
6393 _joinedCapabilityClients
->setObject(notify
);
6394 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6400 case kPowerEventPolicyStimulus
:
6403 int stimulus
= (uintptr_t) arg0
;
6404 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6408 case kPowerEventAssertionCreate
:
6410 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6415 case kPowerEventAssertionRelease
:
6417 pmAssertions
->handleReleaseAssertion(arg1
);
6421 case kPowerEventAssertionSetLevel
:
6423 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6427 case kPowerEventQueueSleepWakeUUID
:
6428 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6430 case kPowerEventPublishSleepWakeUUID
:
6431 handlePublishSleepWakeUUID((bool)arg0
);
6434 case kPowerEventSetDisplayPowerOn
:
6435 if (!wrangler
) break;
6438 displayPowerOnRequested
= true;
6442 displayPowerOnRequested
= false;
6444 handleDisplayPowerOn();
6449 //******************************************************************************
6450 // systemPowerEventOccurred
6452 // The power controller is notifying us of a hardware-related power management
6453 // event that we must handle.
6455 // systemPowerEventOccurred covers the same functionality that
6456 // receivePowerNotification does; it simply provides a richer API for conveying
6457 // more information.
6458 //******************************************************************************
6460 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6461 const OSSymbol
*event
,
6464 IOReturn attempt
= kIOReturnSuccess
;
6465 OSNumber
*newNumber
= NULL
;
6468 return kIOReturnBadArgument
;
6470 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6472 return kIOReturnInternalError
;
6474 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6476 newNumber
->release();
6481 void IOPMrootDomain::setThermalState(OSObject
*value
)
6485 if (gIOPMWorkLoop
->inGate() == false) {
6486 gIOPMWorkLoop
->runAction(
6487 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6493 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6494 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6495 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6499 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6500 const OSSymbol
*event
,
6503 OSDictionary
*thermalsDict
= NULL
;
6504 bool shouldUpdate
= true;
6506 if (!event
|| !value
)
6507 return kIOReturnBadArgument
;
6510 // We reuse featuresDict Lock because it already exists and guards
6511 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6512 // of stepping on that lock.
6513 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6515 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6517 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6518 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6520 thermalsDict
= OSDictionary::withCapacity(1);
6523 if (!thermalsDict
) {
6524 shouldUpdate
= false;
6528 thermalsDict
->setObject (event
, value
);
6530 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6532 thermalsDict
->release();
6536 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6540 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6541 setThermalState(value
);
6543 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6546 return kIOReturnSuccess
;
6549 //******************************************************************************
6550 // receivePowerNotification
6552 // The power controller is notifying us of a hardware-related power management
6553 // event that we must handle. This may be a result of an 'environment' interrupt
6554 // from the power mgt micro.
6555 //******************************************************************************
6557 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6559 pmPowerStateQueue
->submitPowerEvent(
6560 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6561 return kIOReturnSuccess
;
6564 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6566 bool eval_clamshell
= false;
6571 * Local (IOPMrootDomain only) eval clamshell command
6573 if (msg
& kLocalEvalClamshellCommand
)
6575 eval_clamshell
= true;
6581 if (msg
& kIOPMOverTemp
)
6583 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6584 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6588 * Forward DW thermal notification to client, if system is not going to sleep
6590 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6592 DLOG("DarkWake thermal limits message received!\n");
6594 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6600 if (msg
& kIOPMSleepNow
)
6602 privateSleepSystem (kIOPMSleepReasonSoftware
);
6608 if (msg
& kIOPMPowerEmergency
)
6610 lowBatteryCondition
= true;
6611 privateSleepSystem (kIOPMSleepReasonLowPower
);
6617 if (msg
& kIOPMClamshellOpened
)
6619 // Received clamshel open message from clamshell controlling driver
6620 // Update our internal state and tell general interest clients
6621 clamshellClosed
= false;
6622 clamshellExists
= true;
6624 // Don't issue a hid tickle when lid is open and polled on wake
6625 if (msg
& kIOPMSetValue
)
6627 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6632 informCPUStateChange(kInformLid
, 0);
6634 // Tell general interest clients
6635 sendClientClamshellNotification();
6637 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6638 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6639 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6640 if (aborting
) userActivityCount
++;
6641 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6646 * Send the clamshell interest notification since the lid is closing.
6648 if (msg
& kIOPMClamshellClosed
)
6650 // Received clamshel open message from clamshell controlling driver
6651 // Update our internal state and tell general interest clients
6652 clamshellClosed
= true;
6653 clamshellExists
= true;
6656 informCPUStateChange(kInformLid
, 1);
6658 // Tell general interest clients
6659 sendClientClamshellNotification();
6661 // And set eval_clamshell = so we can attempt
6662 eval_clamshell
= true;
6666 * Set Desktop mode (sent from graphics)
6668 * -> reevaluate lid state
6670 if (msg
& kIOPMSetDesktopMode
)
6672 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6673 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6675 sendClientClamshellNotification();
6677 // Re-evaluate the lid state
6678 eval_clamshell
= true;
6682 * AC Adaptor connected
6684 * -> reevaluate lid state
6686 if (msg
& kIOPMSetACAdaptorConnected
)
6688 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6689 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6692 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6694 // Tell BSD if AC is connected
6695 // 0 == external power source; 1 == on battery
6696 post_sys_powersource(acAdaptorConnected
? 0:1);
6698 sendClientClamshellNotification();
6700 // Re-evaluate the lid state
6701 eval_clamshell
= true;
6703 // Lack of AC may have latched a display wrangler tickle.
6704 // This mirrors the hardware's USB wake event latch, where a latched
6705 // USB wake event followed by an AC attach will trigger a full wake.
6706 latchDisplayWranglerTickle( false );
6709 // AC presence will reset the standy timer delay adjustment.
6710 _standbyTimerResetSeconds
= 0;
6712 if (!userIsActive
) {
6713 // Reset userActivityTime when power supply is changed(rdr 13789330)
6714 clock_get_uptime(&userActivityTime
);
6719 * Enable Clamshell (external display disappear)
6721 * -> reevaluate lid state
6723 if (msg
& kIOPMEnableClamshell
)
6725 // Re-evaluate the lid state
6726 // System should sleep on external display disappearance
6727 // in lid closed operation.
6728 if (true == clamshellDisabled
)
6730 eval_clamshell
= true;
6733 clamshellDisabled
= false;
6734 sendClientClamshellNotification();
6738 * Disable Clamshell (external display appeared)
6739 * We don't bother re-evaluating clamshell state. If the system is awake,
6740 * the lid is probably open.
6742 if (msg
& kIOPMDisableClamshell
)
6744 clamshellDisabled
= true;
6745 sendClientClamshellNotification();
6749 * Evaluate clamshell and SLEEP if appropiate
6751 if (eval_clamshell
&& clamshellClosed
)
6753 if (shouldSleepOnClamshellClosed())
6754 privateSleepSystem (kIOPMSleepReasonClamshell
);
6756 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6762 if (msg
& kIOPMPowerButton
)
6764 if (!wranglerAsleep
)
6766 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6767 // Check that power button sleep is enabled
6769 if( kOSBooleanTrue
!= getProperty(pbs
))
6770 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6778 //******************************************************************************
6781 // Evaluate root-domain policy in response to external changes.
6782 //******************************************************************************
6784 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6788 int idleSleepEnabled
: 1;
6789 int idleSleepDisabled
: 1;
6790 int displaySleep
: 1;
6791 int sleepDelayChanged
: 1;
6792 int evaluateDarkWake
: 1;
6793 int adjustPowerState
: 1;
6794 int userBecameInactive
: 1;
6799 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6806 case kStimulusDisplayWranglerSleep
:
6807 if (!wranglerAsleep
)
6809 // first transition to wrangler sleep or lower
6810 wranglerAsleep
= true;
6811 flags
.bit
.displaySleep
= true;
6815 case kStimulusDisplayWranglerWake
:
6816 displayIdleForDemandSleep
= false;
6817 wranglerAsleep
= false;
6820 case kStimulusEnterUserActiveState
:
6821 if (_preventUserActive
)
6823 DLOG("user active dropped\n");
6828 userIsActive
= true;
6829 userWasActive
= true;
6831 // Stay awake after dropping demand for display power on
6832 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6833 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6835 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
6836 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6837 messageClients(kIOPMMessageUserIsActiveChanged
);
6839 flags
.bit
.idleSleepDisabled
= true;
6842 case kStimulusLeaveUserActiveState
:
6845 userIsActive
= false;
6846 clock_get_uptime(&userBecameInactiveTime
);
6847 flags
.bit
.userBecameInactive
= true;
6849 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
6850 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6851 messageClients(kIOPMMessageUserIsActiveChanged
);
6855 case kStimulusAggressivenessChanged
:
6857 unsigned long minutesToIdleSleep
= 0;
6858 unsigned long minutesToDisplayDim
= 0;
6859 unsigned long minutesDelta
= 0;
6861 // Fetch latest display and system sleep slider values.
6862 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6863 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6864 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6865 (uint32_t) sleepSlider
,
6866 (uint32_t) minutesToIdleSleep
,
6867 (uint32_t) minutesToDisplayDim
);
6869 DLOG("idle time -> %ld secs (ena %d)\n",
6870 idleSeconds
, (minutesToIdleSleep
!= 0));
6872 if (0x7fffffff == minutesToIdleSleep
)
6873 minutesToIdleSleep
= idleSeconds
;
6875 // How long to wait before sleeping the system once
6876 // the displays turns off is indicated by 'extraSleepDelay'.
6878 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6879 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6880 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6883 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6884 flags
.bit
.idleSleepEnabled
= true;
6886 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6887 flags
.bit
.idleSleepDisabled
= true;
6889 if (((minutesDelta
!= extraSleepDelay
) ||
6890 (userActivityTime
!= userActivityTime_prev
)) &&
6891 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6892 flags
.bit
.sleepDelayChanged
= true;
6894 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6895 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6897 // Reconsider decision to remain in dark wake
6898 flags
.bit
.evaluateDarkWake
= true;
6901 sleepSlider
= minutesToIdleSleep
;
6902 extraSleepDelay
= minutesDelta
;
6903 userActivityTime_prev
= userActivityTime
;
6906 case kStimulusDemandSystemSleep
:
6907 displayIdleForDemandSleep
= true;
6908 if (wrangler
&& wranglerIdleSettings
)
6910 // Request wrangler idle only when demand sleep is triggered
6912 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6914 wrangler
->setProperties(wranglerIdleSettings
);
6915 DLOG("Requested wrangler idle\n");
6918 // arg = sleepReason
6919 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6922 case kStimulusAllowSystemSleepChanged
:
6923 flags
.bit
.adjustPowerState
= true;
6926 case kStimulusDarkWakeActivityTickle
:
6927 // arg == true implies real and not self generated wrangler tickle.
6928 // Update wake type on PM work loop instead of the tickle thread to
6929 // eliminate the possibility of an early tickle clobbering the wake
6930 // type set by the platform driver.
6932 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6934 if (false == wranglerTickled
)
6936 if (latchDisplayWranglerTickle(true))
6938 DLOG("latched tickle\n");
6942 wranglerTickled
= true;
6943 DLOG("Requesting full wake after dark wake activity tickle\n");
6944 requestFullWake( kFullWakeReasonLocalUser
);
6948 case kStimulusDarkWakeEntry
:
6949 case kStimulusDarkWakeReentry
:
6950 // Any system transitions since the last dark wake transition
6951 // will invalid the stimulus.
6953 if (arg
== _systemStateGeneration
)
6955 DLOG("dark wake entry\n");
6956 systemDarkWake
= true;
6958 // Keep wranglerAsleep an invariant when wrangler is absent
6960 wranglerAsleep
= true;
6962 if (kStimulusDarkWakeEntry
== stimulus
)
6964 clock_get_uptime(&userBecameInactiveTime
);
6965 flags
.bit
.evaluateDarkWake
= true;
6968 // Always accelerate disk spindown while in dark wake,
6969 // even if system does not support/allow sleep.
6971 cancelIdleSleepTimer();
6972 setQuickSpinDownTimeout();
6976 case kStimulusDarkWakeEvaluate
:
6979 flags
.bit
.evaluateDarkWake
= true;
6983 case kStimulusNoIdleSleepPreventers
:
6984 flags
.bit
.adjustPowerState
= true;
6987 } /* switch(stimulus) */
6989 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6991 if (darkWakeToSleepASAP
||
6992 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6994 uint32_t newSleepReason
;
6996 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6998 // System was previously in full wake. Sleep reason from
6999 // full to dark already recorded in fullToDarkReason.
7001 if (lowBatteryCondition
)
7002 newSleepReason
= kIOPMSleepReasonLowPower
;
7004 newSleepReason
= fullToDarkReason
;
7008 // In dark wake from system sleep.
7010 if (darkWakeSleepService
)
7011 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7013 newSleepReason
= kIOPMSleepReasonMaintenance
;
7016 if (checkSystemCanSleep(newSleepReason
))
7018 privateSleepSystem(newSleepReason
);
7021 else // non-maintenance (network) dark wake
7023 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7025 // Release power clamp, and wait for children idle.
7026 adjustPowerState(true);
7030 changePowerStateToPriv(ON_STATE
);
7037 // The rest are irrelevant while system is in dark wake.
7041 if ((flags
.bit
.displaySleep
) &&
7042 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7044 // kIOPMSleepReasonMaintenance?
7045 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7048 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7050 bool cancelQuickSpindown
= false;
7052 if (flags
.bit
.sleepDelayChanged
)
7054 // Cancel existing idle sleep timer and quick disk spindown.
7055 // New settings will be applied by the idleSleepEnabled flag
7056 // handler below if idle sleep is enabled.
7058 DLOG("extra sleep timer changed\n");
7059 cancelIdleSleepTimer();
7060 cancelQuickSpindown
= true;
7064 DLOG("user inactive\n");
7067 if (!userIsActive
&& sleepSlider
)
7069 startIdleSleepTimer(getTimeToIdleSleep());
7072 if (cancelQuickSpindown
)
7073 restoreUserSpinDownTimeout();
7076 if (flags
.bit
.idleSleepEnabled
)
7078 DLOG("idle sleep timer enabled\n");
7081 changePowerStateToPriv(ON_STATE
);
7084 startIdleSleepTimer( idleSeconds
);
7089 // Start idle timer if prefs now allow system sleep
7090 // and user is already inactive. Disk spindown is
7091 // accelerated upon timer expiration.
7095 startIdleSleepTimer(getTimeToIdleSleep());
7100 if (flags
.bit
.idleSleepDisabled
)
7102 DLOG("idle sleep timer disabled\n");
7103 cancelIdleSleepTimer();
7104 restoreUserSpinDownTimeout();
7108 if (flags
.bit
.adjustPowerState
)
7110 bool sleepASAP
= false;
7112 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7116 changePowerStateToPriv(ON_STATE
);
7119 // stay awake for at least idleSeconds
7120 startIdleSleepTimer(idleSeconds
);
7123 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7129 adjustPowerState(sleepASAP
);
7133 //******************************************************************************
7136 // Request transition from dark wake to full wake
7137 //******************************************************************************
7139 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7141 uint32_t options
= 0;
7142 IOService
* pciRoot
= 0;
7143 bool promotion
= false;
7145 // System must be in dark wake and a valid reason for entering full wake
7146 if ((kFullWakeReasonNone
== reason
) ||
7147 (kFullWakeReasonNone
!= fullWakeReason
) ||
7148 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7153 // Will clear reason upon exit from full wake
7154 fullWakeReason
= reason
;
7156 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7157 kIOPMSystemCapabilityAudio
);
7159 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7160 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7161 !graphicsSuppressed
)
7163 // Promote to full wake while waking up to dark wake due to tickle.
7164 // PM will hold off notifying the graphics subsystem about system wake
7165 // as late as possible, so if a HID tickle does arrive, graphics can
7166 // power up on this same wake cycle. The latency to power up graphics
7167 // on the next cycle can be huge on some systems. However, once any
7168 // graphics suppression has taken effect, it is too late. All other
7169 // graphics devices must be similarly suppressed. But the delay till
7170 // the following cycle should be short.
7172 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7173 kIOPMSystemCapabilityAudio
);
7175 // Immediately bring up audio and graphics
7176 pciRoot
= pciHostBridgeDriver
;
7177 willEnterFullWake();
7181 // Unsafe to cancel once graphics was powered.
7182 // If system woke from dark wake, the return to sleep can
7183 // be cancelled. "awake -> dark -> sleep" transition
7184 // can be canceled also, during the "dark --> sleep" phase
7185 // *prior* to driver power down.
7186 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7187 _pendingCapability
== 0) {
7188 options
|= kIOPMSyncCancelPowerDown
;
7191 synchronizePowerTree(options
, pciRoot
);
7192 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7194 // IOGraphics doesn't light the display even though graphics is
7195 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7196 // So, do an explicit activity tickle
7198 wrangler
->activityTickle(0,0);
7201 // Log a timestamp for the initial full wake request.
7202 // System may not always honor this full wake request.
7203 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7208 clock_get_uptime(&now
);
7209 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7210 absolutetime_to_nanoseconds(now
, &nsec
);
7211 MSG("full wake %s (reason %u) %u ms\n",
7212 promotion
? "promotion" : "request",
7213 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7217 //******************************************************************************
7218 // willEnterFullWake
7220 // System will enter full wake from sleep, from dark wake, or from dark
7221 // wake promotion. This function aggregate things that are in common to
7222 // all three full wake transitions.
7224 // Assumptions: fullWakeReason was updated
7225 //******************************************************************************
7227 void IOPMrootDomain::willEnterFullWake( void )
7229 hibernateRetry
= false;
7230 sleepToStandby
= false;
7231 standbyNixed
= false;
7232 resetTimers
= false;
7233 sleepTimerMaintenance
= false;
7235 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7236 kSystemMessageClientLegacyApp
;
7238 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7240 // Initial graphics full power
7241 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7243 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7244 setProperty(gIOPMUserTriggeredFullWakeKey
,
7245 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7246 kOSBooleanTrue
: kOSBooleanFalse
);
7249 IOHibernateSetWakeCapabilities(_pendingCapability
);
7252 IOService::setAdvisoryTickleEnable( true );
7253 tellClients(kIOMessageSystemWillPowerOn
);
7254 preventTransitionToUserActive(false);
7257 //******************************************************************************
7258 // fullWakeDelayedWork
7260 // System has already entered full wake. Invoked by a delayed thread call.
7261 //******************************************************************************
7263 void IOPMrootDomain::fullWakeDelayedWork( void )
7265 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7266 // Not gated, don't modify state
7267 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7268 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7270 receivePowerNotification( kLocalEvalClamshellCommand
);
7275 //******************************************************************************
7276 // evaluateAssertions
7278 //******************************************************************************
7279 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7281 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7283 messageClients(kIOPMMessageDriverAssertionsChanged
);
7285 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7288 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7290 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7291 wrangler
->setIgnoreIdleTimer( value
);
7295 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7296 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7297 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7299 clock_usec_t microsecs
;
7300 clock_get_uptime(&now
);
7301 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7302 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7303 if (assertOnWakeReport
) {
7304 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7305 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7310 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7311 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7313 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7314 updatePreventIdleSleepList(this, true);
7317 DLOG("Driver assertion ReservedBit7 dropped\n");
7318 updatePreventIdleSleepList(this, false);
7326 //******************************************************************************
7329 //******************************************************************************
7331 void IOPMrootDomain::pmStatsRecordEvent(
7333 AbsoluteTime timestamp
)
7335 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7336 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7339 OSData
*publishPMStats
= NULL
;
7341 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7343 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7345 switch (eventIndex
) {
7346 case kIOPMStatsHibernateImageWrite
:
7348 gPMStats
.hibWrite
.start
= nsec
;
7350 gPMStats
.hibWrite
.stop
= nsec
;
7353 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7354 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7357 case kIOPMStatsHibernateImageRead
:
7359 gPMStats
.hibRead
.start
= nsec
;
7361 gPMStats
.hibRead
.stop
= nsec
;
7364 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7365 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7367 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7368 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7369 publishPMStats
->release();
7370 bzero(&gPMStats
, sizeof(gPMStats
));
7377 * Appends a record of the application response to
7378 * IOPMrootDomain::pmStatsAppResponses
7380 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7381 const OSSymbol
*response
,
7387 IOPMPowerStateIndex powerState
)
7389 OSDictionary
*responseDescription
= NULL
;
7390 OSNumber
*delayNum
= NULL
;
7391 OSNumber
*powerCaps
= NULL
;
7392 OSNumber
*pidNum
= NULL
;
7393 OSNumber
*msgNum
= NULL
;
7394 const OSSymbol
*appname
;
7395 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7396 IOPMServiceInterestNotifier
*notify
= 0;
7398 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7400 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7401 notify
->ackTimeoutCnt
++;
7403 notify
->ackTimeoutCnt
= 0;
7407 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7408 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7412 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7413 kdebugTrace(kPMLogDrvResponseDelay
, id
, messageType
, delay_ms
);
7416 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7417 notify
->msgType
= 0;
7420 responseDescription
= OSDictionary::withCapacity(5);
7421 if (responseDescription
)
7424 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7427 msgNum
= OSNumber::withNumber(messageType
, 32);
7429 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7433 if (name
&& (strlen(name
) > 0))
7435 appname
= OSSymbol::withCString(name
);
7437 responseDescription
->setObject(_statsNameKey
, appname
);
7443 pidNum
= OSNumber::withNumber(id
, 32);
7445 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7450 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7452 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7453 delayNum
->release();
7456 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7457 powerCaps
= OSNumber::withNumber(powerState
, 32);
7459 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7460 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7462 powerState
, delay_ms
);
7467 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7470 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7471 powerCaps
->release();
7474 sleep
= OSSymbol::withCString("Sleep");
7475 wake
= OSSymbol::withCString("Wake");
7476 if (_systemTransitionType
== kSystemTransitionSleep
) {
7477 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7479 else if (_systemTransitionType
== kSystemTransitionWake
) {
7480 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7482 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7483 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7484 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7485 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7486 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7488 if (sleep
) sleep
->release();
7489 if (wake
) wake
->release();
7493 IOLockLock(pmStatsLock
);
7494 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7495 pmStatsAppResponses
->setObject(responseDescription
);
7497 IOLockUnlock(pmStatsLock
);
7499 responseDescription
->release();
7506 // MARK: PMTraceWorker
7508 //******************************************************************************
7509 // TracePoint support
7511 //******************************************************************************
7513 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7514 "IOPMRegisterNVRAMTracePointHandler"
7516 IOReturn
IOPMrootDomain::callPlatformFunction(
7517 const OSSymbol
* functionName
,
7518 bool waitForFunction
,
7519 void * param1
, void * param2
,
7520 void * param3
, void * param4
)
7522 uint32_t bootFailureCode
= 0xffffffff;
7523 unsigned int len
= sizeof(bootFailureCode
);
7524 if (pmTracer
&& functionName
&&
7525 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7526 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7528 uint32_t tracePointPhases
, tracePointPCI
;
7529 uint64_t statusCode
;
7531 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7532 pmTracer
->tracePointTarget
= (void *) param2
;
7533 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7534 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7535 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7536 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey
, &bootFailureCode
, &len
)) {
7537 MSG("Failed to read failure code from NVRam\n");
7539 // Failure code from EFI/BootRom is a four byte structure
7540 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7542 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7543 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7544 MSG("Sleep failure code 0x%08x 0x%08x\n",
7545 tracePointPCI
, tracePointPhases
);
7547 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7548 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7550 return kIOReturnSuccess
;
7553 else if (functionName
&&
7554 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7556 if (gSleepPolicyHandler
)
7557 return kIOReturnExclusiveAccess
;
7559 return kIOReturnBadArgument
;
7560 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7561 gSleepPolicyTarget
= (void *) param2
;
7562 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7563 return kIOReturnSuccess
;
7567 return super::callPlatformFunction(
7568 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7571 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7572 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7574 uint32_t code
= IODBG_POWER(event
);
7575 uint64_t regId
= id
;
7577 regId
= getRegistryEntryID();
7579 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7583 void IOPMrootDomain::tracePoint( uint8_t point
)
7585 if (systemBooting
) return;
7587 if (kIOPMTracePointWakeCapabilityClients
== point
)
7588 acceptSystemWakeEvents(false);
7590 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7591 pmTracer
->tracePoint(point
);
7594 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uintptr_t handler
)
7596 if (!systemBooting
) {
7597 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
7598 ((msgType
& 0xfff) << 12) |
7600 pmTracer
->traceDetail( detail
);
7601 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, pmTracer
->getTracePhase(), msgType
, handler
& 0xfff);
7606 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7609 void **report
= NULL
;
7612 uint32_t *clientCnt
;
7617 if (channel_id
== kAssertDelayChID
) {
7618 report
= &assertOnWakeReport
;
7619 bktCnt
= kAssertDelayBcktCnt
;
7620 bktSize
= kAssertDelayBcktSize
;
7621 clientCnt
= &assertOnWakeClientCnt
;
7623 else if (channel_id
== kSleepDelaysChID
) {
7624 report
= &sleepDelaysReport
;
7625 bktCnt
= kSleepDelaysBcktCnt
;
7626 bktSize
= kSleepDelaysBcktSize
;
7627 clientCnt
= &sleepDelaysClientCnt
;
7632 case kIOReportEnable
:
7639 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7640 *report
= IOMalloc(reportSize
);
7641 if (*report
== NULL
) {
7644 bzero(*report
, reportSize
);
7645 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7646 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7648 if (channel_id
== kAssertDelayChID
)
7649 assertOnWakeSecs
= 0;
7653 case kIOReportDisable
:
7654 if (*clientCnt
== 0) {
7657 if (*clientCnt
== 1)
7659 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7664 if (channel_id
== kAssertDelayChID
)
7665 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7669 case kIOReportGetDimensions
:
7671 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7679 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7680 IOReportConfigureAction action
,
7685 uint64_t configAction
= (uint64_t)action
;
7687 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7688 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7689 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7690 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7691 if (action
!= kIOReportGetDimensions
) continue;
7692 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7694 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7695 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7696 gIOPMWorkLoop
->runAction(
7697 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7698 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7699 (void *)configAction
, (void *)result
);
7703 return super::configureReport(channelList
, action
, result
, destination
);
7706 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7716 if (ch_id
== kAssertDelayChID
) {
7717 report
= &assertOnWakeReport
;
7719 else if (ch_id
== kSleepDelaysChID
) {
7720 report
= &sleepDelaysReport
;
7723 if (*report
== NULL
) {
7724 return kIOReturnNotOpen
;
7727 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7728 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7729 return kIOReturnOverrun
;
7732 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7733 dest
->appendBytes(data2cpy
, size2cpy
);
7735 return kIOReturnSuccess
;
7738 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7739 IOReportUpdateAction action
,
7745 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7746 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7750 if (action
!= kIOReportCopyChannelData
) goto exit
;
7752 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7753 ch_id
= channelList
->channels
[cnt
].channel_id
;
7755 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7756 gIOPMWorkLoop
->runAction(
7757 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7758 (OSObject
*)this, (void *)ch_id
,
7759 (void *)result
, (void *)dest
);
7763 else if ((ch_id
== kSleepCntChID
) ||
7764 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7765 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7769 if (ch_id
== kSleepCntChID
)
7770 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7771 else if (ch_id
== kDarkWkCntChID
)
7772 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7773 else if (ch_id
== kUserWkCntChID
)
7774 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7776 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7777 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7778 dest
->appendBytes(data2cpy
, size2cpy
);
7782 return super::updateReport(channelList
, action
, result
, destination
);
7786 //******************************************************************************
7787 // PMTraceWorker Class
7789 //******************************************************************************
7792 #define super OSObject
7793 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7795 #define kPMBestGuessPCIDevicesCount 25
7796 #define kPMMaxRTCBitfieldSize 32
7798 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7802 me
= OSTypeAlloc( PMTraceWorker
);
7803 if (!me
|| !me
->init())
7808 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7810 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7811 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7812 // this dictionary lazily.
7814 me
->pciDeviceBitMappings
= NULL
;
7815 me
->pmTraceWorkerLock
= IOLockAlloc();
7816 me
->tracePhase
= kIOPMTracePointSystemUp
;
7817 me
->traceData32
= 0;
7818 me
->loginWindowData
= 0;
7819 me
->coreDisplayData
= 0;
7820 me
->coreGraphicsData
= 0;
7824 void PMTraceWorker::RTC_TRACE(void)
7826 if (tracePointHandler
&& tracePointTarget
)
7830 IOLockLock(pmTraceWorkerLock
);
7831 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
7832 (coreGraphicsData
<< 8) | tracePhase
;
7833 IOLockUnlock(pmTraceWorkerLock
);
7835 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7836 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7840 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7842 const OSSymbol
* deviceName
;
7845 IOLockLock(pmTraceWorkerLock
);
7847 if (!pciDeviceBitMappings
)
7849 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7850 if (!pciDeviceBitMappings
)
7854 // Check for bitmask overflow.
7855 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7858 if ((deviceName
= pciDevice
->copyName()) &&
7859 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7860 pciDeviceBitMappings
->setObject(deviceName
))
7862 index
= pciDeviceBitMappings
->getCount() - 1;
7863 _LOG("PMTrace PCI array: set object %s => %d\n",
7864 deviceName
->getCStringNoCopy(), index
);
7867 deviceName
->release();
7868 if (!addedToRegistry
&& (index
>= 0))
7869 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7872 IOLockUnlock(pmTraceWorkerLock
);
7876 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7879 if (pciDeviceBitMappings
)
7881 IOLockLock(pmTraceWorkerLock
);
7882 ok
= pciDeviceBitMappings
->serialize(s
);
7883 IOLockUnlock(pmTraceWorkerLock
);
7888 void PMTraceWorker::tracePoint(uint8_t phase
)
7890 // clear trace detail when phase begins
7891 if (tracePhase
!= phase
)
7896 DLOG("trace point 0x%02x\n", tracePhase
);
7900 void PMTraceWorker::traceDetail(uint32_t detail
)
7903 traceData32
= detail
;
7904 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7909 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
7911 switch (component
) {
7912 case kIOPMLoginWindowProgress
:
7913 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
7915 case kIOPMCoreDisplayProgress
:
7916 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
7918 case kIOPMCoreGraphicsProgress
:
7919 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
7925 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
7929 void PMTraceWorker::tracePCIPowerChange(
7930 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7933 uint32_t expectedFlag
;
7935 // Ignore PCI changes outside of system sleep/wake.
7936 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7937 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7940 // Only record the WillChange transition when going to sleep,
7941 // and the DidChange on the way up.
7942 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7943 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7944 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7945 if (changeFlags
!= expectedFlag
)
7948 // Mark this device off in our bitfield
7949 if (bitNum
< kPMMaxRTCBitfieldSize
)
7951 bitMask
= (1 << bitNum
);
7953 if (kPowerChangeStart
== type
)
7955 traceData32
|= bitMask
;
7956 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7957 service
->getName(), bitNum
, bitMask
, traceData32
);
7958 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
7962 traceData32
&= ~bitMask
;
7963 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7964 service
->getName(), bitNum
, bitMask
, traceData32
);
7965 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
7968 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7973 uint64_t PMTraceWorker::getPMStatusCode( )
7975 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
7979 uint8_t PMTraceWorker::getTracePhase()
7984 uint32_t PMTraceWorker::getTraceData()
7990 // MARK: PMHaltWorker
7992 //******************************************************************************
7993 // PMHaltWorker Class
7995 //******************************************************************************
7997 PMHaltWorker
* PMHaltWorker::worker( void )
8003 me
= OSTypeAlloc( PMHaltWorker
);
8004 if (!me
|| !me
->init())
8007 me
->lock
= IOLockAlloc();
8011 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8012 me
->retain(); // thread holds extra retain
8013 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8018 thread_deallocate(thread
);
8023 if (me
) me
->release();
8027 void PMHaltWorker::free( void )
8029 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8035 return OSObject::free();
8038 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8040 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8042 IOLockLock( gPMHaltLock
);
8044 me
->depth
= gPMHaltDepth
;
8045 IOLockUnlock( gPMHaltLock
);
8047 while (me
->depth
>= 0)
8049 PMHaltWorker::work( me
);
8051 IOLockLock( gPMHaltLock
);
8052 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8054 // This is the last thread to finish work on this level,
8055 // inform everyone to start working on next lower level.
8057 me
->depth
= gPMHaltDepth
;
8058 gPMHaltIdleCount
= 0;
8059 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8063 // One or more threads are still working on this level,
8064 // this thread must wait.
8065 me
->depth
= gPMHaltDepth
- 1;
8067 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8068 } while (me
->depth
!= gPMHaltDepth
);
8070 IOLockUnlock( gPMHaltLock
);
8073 // No more work to do, terminate thread
8074 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8075 thread_wakeup( &gPMHaltDepth
);
8079 void PMHaltWorker::work( PMHaltWorker
* me
)
8081 IOService
* service
;
8083 AbsoluteTime startTime
;
8092 // Claim an unit of work from the shared pool
8093 IOLockLock( gPMHaltLock
);
8094 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8097 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8101 inner
->removeObject(service
);
8104 IOLockUnlock( gPMHaltLock
);
8106 break; // no more work at this depth
8108 clock_get_uptime(&startTime
);
8110 if (!service
->isInactive() &&
8111 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8113 IOLockLock(me
->lock
);
8114 me
->startTime
= startTime
;
8115 me
->service
= service
;
8116 me
->timeout
= false;
8117 IOLockUnlock(me
->lock
);
8119 service
->systemWillShutdown( gPMHaltMessageType
);
8121 // Wait for driver acknowledgement
8122 IOLockLock(me
->lock
);
8123 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8125 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8128 timeout
= me
->timeout
;
8129 IOLockUnlock(me
->lock
);
8132 deltaTime
= computeDeltaTimeMS(&startTime
);
8133 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
8134 (gIOKitDebug
& kIOLogPMRootDomain
))
8136 LOG("%s driver %s (0x%llx) took %u ms\n",
8137 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8138 "PowerOff" : "Restart",
8139 service
->getName(), service
->getRegistryEntryID(),
8140 (uint32_t) deltaTime
);
8148 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8151 AbsoluteTime startTime
;
8152 AbsoluteTime endTime
;
8156 IOLockLock(me
->lock
);
8157 if (me
->service
&& !me
->timeout
)
8159 startTime
= me
->startTime
;
8161 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8163 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8164 absolutetime_to_nanoseconds(endTime
, &nano
);
8166 if (nano
> 3000000000ULL)
8169 MSG("%s still waiting on %s\n",
8170 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8171 "PowerOff" : "Restart",
8172 me
->service
->getName());
8175 IOLockUnlock(me
->lock
);
8178 //******************************************************************************
8179 // acknowledgeSystemWillShutdown
8181 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8182 //******************************************************************************
8184 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8186 PMHaltWorker
* worker
;
8192 //DLOG("%s acknowledged\n", from->getName());
8193 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8196 worker
= (PMHaltWorker
*) prop
;
8197 IOLockLock(worker
->lock
);
8198 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8199 thread_wakeup((event_t
) worker
);
8200 IOLockUnlock(worker
->lock
);
8205 DLOG("%s acknowledged without worker property\n",
8211 //******************************************************************************
8212 // notifySystemShutdown
8214 // Notify all objects in PM tree that system will shutdown or restart
8215 //******************************************************************************
8218 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8220 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8221 IORegistryIterator
* iter
;
8222 IORegistryEntry
* entry
;
8225 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8226 AbsoluteTime deadline
;
8227 unsigned int totalNodes
= 0;
8229 unsigned int rootDepth
;
8230 unsigned int numWorkers
;
8236 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8238 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8240 // Iterate the entire PM tree starting from root
8242 rootDepth
= root
->getDepth( gIOPowerPlane
);
8243 if (!rootDepth
) goto done
;
8245 // debug - for repeated test runs
8246 while (PMHaltWorker::metaClass
->getInstanceCount())
8251 gPMHaltArray
= OSArray::withCapacity(40);
8252 if (!gPMHaltArray
) goto done
;
8255 gPMHaltArray
->flushCollection();
8259 gPMHaltLock
= IOLockAlloc();
8260 if (!gPMHaltLock
) goto done
;
8263 if (!gPMHaltClientAcknowledgeKey
)
8265 gPMHaltClientAcknowledgeKey
=
8266 OSSymbol::withCStringNoCopy("PMShutdown");
8267 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8270 gPMHaltMessageType
= messageType
;
8272 // Depth-first walk of PM plane
8274 iter
= IORegistryIterator::iterateOver(
8275 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8279 while ((entry
= iter
->getNextObject()))
8281 node
= OSDynamicCast(IOService
, entry
);
8286 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8289 depth
= node
->getDepth( gIOPowerPlane
);
8290 if (depth
<= rootDepth
)
8295 // adjust to zero based depth
8296 depth
-= (rootDepth
+ 1);
8298 // gPMHaltArray is an array of containers, each container
8299 // refers to nodes with the same depth.
8301 count
= gPMHaltArray
->getCount();
8302 while (depth
>= count
)
8304 // expand array and insert placeholders
8305 gPMHaltArray
->setObject(PLACEHOLDER
);
8308 count
= gPMHaltArray
->getCount();
8311 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8312 if (inner
== PLACEHOLDER
)
8314 inner
= OSSet::withCapacity(40);
8317 gPMHaltArray
->replaceObject(depth
, inner
);
8322 // PM nodes that appear more than once in the tree will have
8323 // the same depth, OSSet will refuse to add the node twice.
8325 ok
= inner
->setObject(node
);
8328 DLOG("Skipped PM node %s\n", node
->getName());
8334 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8337 if (inner
!= PLACEHOLDER
)
8338 count
= inner
->getCount();
8339 DLOG("Nodes at depth %u = %u\n", i
, count
);
8342 // strip placeholders (not all depths are populated)
8344 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8346 if (inner
== PLACEHOLDER
)
8348 gPMHaltArray
->removeObject(i
);
8351 count
= inner
->getCount();
8352 if (count
> numWorkers
)
8354 totalNodes
+= count
;
8358 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8361 gPMHaltBusyCount
= 0;
8362 gPMHaltIdleCount
= 0;
8363 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8365 // Create multiple workers (and threads)
8367 if (numWorkers
> kPMHaltMaxWorkers
)
8368 numWorkers
= kPMHaltMaxWorkers
;
8370 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8371 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8373 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8374 workers
[i
] = PMHaltWorker::worker();
8376 // Wait for workers to exhaust all available work
8378 IOLockLock(gPMHaltLock
);
8379 while (gPMHaltDepth
>= 0)
8381 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8383 waitResult
= IOLockSleepDeadline(
8384 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8385 if (THREAD_TIMED_OUT
== waitResult
)
8388 clock_get_uptime(&now
);
8390 IOLockUnlock(gPMHaltLock
);
8391 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8394 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8396 IOLockLock(gPMHaltLock
);
8399 IOLockUnlock(gPMHaltLock
);
8401 // Release all workers
8403 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8406 workers
[i
]->release();
8407 // worker also retained by it's own thread
8411 DLOG("%s done\n", __FUNCTION__
);
8416 // MARK: Kernel Assertion
8418 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8420 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8421 IOPMDriverAssertionType whichAssertionBits
,
8422 IOPMDriverAssertionLevel assertionLevel
,
8423 IOService
*ownerService
,
8424 const char *ownerDescription
)
8427 IOPMDriverAssertionID newAssertion
;
8432 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8434 if (kIOReturnSuccess
== ret
)
8435 return newAssertion
;
8440 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8443 return kIOReturnInternalError
;
8445 return pmAssertions
->releaseAssertion(releaseAssertion
);
8449 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8450 IOPMDriverAssertionID assertionID
,
8451 IOPMDriverAssertionLevel assertionLevel
)
8453 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8456 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8458 IOPMDriverAssertionType sysLevels
;
8460 if (!pmAssertions
|| whichAssertion
== 0)
8461 return kIOPMDriverAssertionLevelOff
;
8463 sysLevels
= pmAssertions
->getActivatedAssertions();
8465 // Check that every bit set in argument 'whichAssertion' is asserted
8466 // in the aggregate bits.
8467 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8468 return kIOPMDriverAssertionLevelOn
;
8470 return kIOPMDriverAssertionLevelOff
;
8473 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8476 return kIOReturnNotFound
;
8478 return pmAssertions
->setUserAssertionLevels(inLevels
);
8481 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8485 pmAssertions
->publishProperties();
8487 return( IOService::serializeProperties(s
) );
8490 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8492 OSObject
*obj
= NULL
;
8493 obj
= IOService::copyProperty(aKey
);
8495 if (obj
) return obj
;
8497 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8498 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8499 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8500 return kOSBooleanTrue
;
8502 return kOSBooleanFalse
;
8506 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8507 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8508 if (swd_flags
& SWD_VALID_LOGS
)
8509 return kOSBooleanTrue
;
8511 return kOSBooleanFalse
;
8516 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8517 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8518 * issued by DisplayWrangler on darkwake.
8520 if (!strcmp(aKey
, "DesktopMode")) {
8522 return kOSBooleanTrue
;
8524 return kOSBooleanFalse
;
8526 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8527 if (displayIdleForDemandSleep
) {
8528 return kOSBooleanTrue
;
8531 return kOSBooleanFalse
;
8535 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8537 OSArray
* array
= 0;
8539 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8540 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8541 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8542 collection
->release();
8549 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8551 OSArray
* array
= 0;
8552 IOLockLock(pmStatsLock
);
8553 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8554 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8555 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8556 collection
->release();
8558 pmStatsAppResponses
->flushCollection();
8560 IOLockUnlock(pmStatsLock
);
8564 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8566 OSArray
*idleSleepList
= NULL
;
8567 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8568 return idleSleepList
;
8571 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8573 OSArray
*systemSleepList
= NULL
;
8574 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8575 return systemSleepList
;
8582 // MARK: Wake Event Reporting
8584 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8587 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8591 //******************************************************************************
8592 // acceptSystemWakeEvents
8594 // Private control for the acceptance of driver wake event claims.
8595 //******************************************************************************
8597 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8599 bool logWakeReason
= false;
8604 gWakeReasonString
[0] = '\0';
8605 if (!_systemWakeEventsArray
)
8606 _systemWakeEventsArray
= OSArray::withCapacity(4);
8607 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8608 _systemWakeEventsArray
->flushCollection();
8612 _acceptSystemWakeEvents
= false;
8617 MSG("system wake events:%s\n", gWakeReasonString
);
8620 //******************************************************************************
8621 // claimSystemWakeEvent
8623 // For a driver to claim a device is the source/conduit of a system wake event.
8624 //******************************************************************************
8626 void IOPMrootDomain::claimSystemWakeEvent(
8629 const char * reason
,
8630 OSObject
* details
)
8632 const OSSymbol
* deviceName
= 0;
8633 OSNumber
* deviceRegId
= 0;
8634 OSNumber
* claimTime
= 0;
8635 OSData
* flagsData
= 0;
8636 OSString
* reasonString
= 0;
8637 OSDictionary
* d
= 0;
8641 pmEventTimeStamp(×tamp
);
8643 if (!device
|| !reason
) return;
8645 deviceName
= device
->copyName(gIOServicePlane
);
8646 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8647 claimTime
= OSNumber::withNumber(timestamp
, 64);
8648 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8649 reasonString
= OSString::withCString(reason
);
8650 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8651 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8654 d
->setObject(gIONameKey
, deviceName
);
8655 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8656 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8657 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8658 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8660 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8663 if (!gWakeReasonSysctlRegistered
)
8665 // Lazy registration until the platform driver stops registering
8667 gWakeReasonSysctlRegistered
= true;
8669 if (_acceptSystemWakeEvents
)
8671 ok
= _systemWakeEventsArray
->setObject(d
);
8672 if (gWakeReasonString
[0] != '\0')
8673 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8674 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8679 if (deviceName
) deviceName
->release();
8680 if (deviceRegId
) deviceRegId
->release();
8681 if (claimTime
) claimTime
->release();
8682 if (flagsData
) flagsData
->release();
8683 if (reasonString
) reasonString
->release();
8684 if (d
) d
->release();
8687 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8690 // MARK: PMSettingHandle
8692 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8694 void PMSettingHandle::free( void )
8698 pmso
->clientHandleFreed();
8707 // MARK: PMSettingObject
8710 #define super OSObject
8711 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8714 * Static constructor/initializer for PMSettingObject
8716 PMSettingObject
*PMSettingObject::pmSettingObject(
8717 IOPMrootDomain
*parent_arg
,
8718 IOPMSettingControllerCallback handler_arg
,
8719 OSObject
*target_arg
,
8720 uintptr_t refcon_arg
,
8721 uint32_t supportedPowerSources
,
8722 const OSSymbol
* settings
[],
8723 OSObject
**handle_obj
)
8725 uint32_t settingCount
= 0;
8726 PMSettingObject
*pmso
= 0;
8727 PMSettingHandle
*pmsh
= 0;
8729 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8732 // count OSSymbol entries in NULL terminated settings array
8733 while (settings
[settingCount
]) {
8736 if (0 == settingCount
)
8739 pmso
= new PMSettingObject
;
8740 if (!pmso
|| !pmso
->init())
8743 pmsh
= new PMSettingHandle
;
8744 if (!pmsh
|| !pmsh
->init())
8747 queue_init(&pmso
->calloutQueue
);
8748 pmso
->parent
= parent_arg
;
8749 pmso
->func
= handler_arg
;
8750 pmso
->target
= target_arg
;
8751 pmso
->refcon
= refcon_arg
;
8752 pmso
->settingCount
= settingCount
;
8754 pmso
->retain(); // handle holds a retain on pmso
8758 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8759 if (pmso
->publishedFeatureID
) {
8760 for (unsigned int i
=0; i
<settingCount
; i
++) {
8761 // Since there is now at least one listener to this setting, publish
8762 // PM root domain support for it.
8763 parent_arg
->publishPMSetting( settings
[i
],
8764 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8772 if (pmso
) pmso
->release();
8773 if (pmsh
) pmsh
->release();
8777 void PMSettingObject::free( void )
8779 if (publishedFeatureID
) {
8780 for (uint32_t i
=0; i
<settingCount
; i
++) {
8781 if (publishedFeatureID
[i
]) {
8782 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8786 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8792 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8794 (*func
)(target
, type
, object
, refcon
);
8797 void PMSettingObject::clientHandleFreed( void )
8799 parent
->deregisterPMSettingObject(this);
8803 // MARK: PMAssertionsTracker
8805 //*********************************************************************************
8806 //*********************************************************************************
8807 //*********************************************************************************
8808 // class PMAssertionsTracker Implementation
8810 #define kAssertUniqueIDStart 500
8812 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8814 PMAssertionsTracker
*myself
;
8816 myself
= new PMAssertionsTracker
;
8820 myself
->owner
= rootDomain
;
8821 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8822 myself
->assertionsArray
= OSArray::withCapacity(5);
8823 myself
->assertionsKernel
= 0;
8824 myself
->assertionsUser
= 0;
8825 myself
->assertionsCombined
= 0;
8826 myself
->assertionsArrayLock
= IOLockAlloc();
8827 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8829 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8837 * - Update assertionsKernel to reflect the state of all
8838 * assertions in the kernel.
8839 * - Update assertionsCombined to reflect both kernel & user space.
8841 void PMAssertionsTracker::tabulate(void)
8845 PMAssertStruct
*_a
= NULL
;
8848 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8849 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8853 assertionsKernel
= 0;
8854 assertionsCombined
= 0;
8856 if (!assertionsArray
)
8859 if ((count
= assertionsArray
->getCount()))
8861 for (i
=0; i
<count
; i
++)
8863 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8866 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8867 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8868 assertionsKernel
|= _a
->assertionBits
;
8873 tabulateProducerCount
++;
8874 assertionsCombined
= assertionsKernel
| assertionsUser
;
8876 if ((assertionsKernel
!= oldKernel
) ||
8877 (assertionsCombined
!= oldCombined
))
8879 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8883 void PMAssertionsTracker::publishProperties( void )
8885 OSArray
*assertionsSummary
= NULL
;
8887 if (tabulateConsumerCount
!= tabulateProducerCount
)
8889 IOLockLock(assertionsArrayLock
);
8891 tabulateConsumerCount
= tabulateProducerCount
;
8893 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8895 assertionsSummary
= copyAssertionsArray();
8896 if (assertionsSummary
)
8898 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8899 assertionsSummary
->release();
8903 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8906 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8908 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8910 IOLockUnlock(assertionsArrayLock
);
8914 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8916 PMAssertStruct
*_a
= NULL
;
8923 && (count
= assertionsArray
->getCount()))
8925 for (i
=0; i
<count
; i
++)
8927 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8930 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8931 if (_a
&& (_id
== _a
->id
)) {
8948 /* PMAssertionsTracker::handleCreateAssertion
8949 * Perform assertion work on the PM workloop. Do not call directly.
8951 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8957 IOLockLock(assertionsArrayLock
);
8958 assertionsArray
->setObject(newAssertion
);
8959 IOLockUnlock(assertionsArrayLock
);
8960 newAssertion
->release();
8964 return kIOReturnSuccess
;
8967 /* PMAssertionsTracker::createAssertion
8968 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8971 IOReturn
PMAssertionsTracker::createAssertion(
8972 IOPMDriverAssertionType which
,
8973 IOPMDriverAssertionLevel level
,
8974 IOService
*serviceID
,
8975 const char *whoItIs
,
8976 IOPMDriverAssertionID
*outID
)
8978 OSData
*dataStore
= NULL
;
8979 PMAssertStruct track
;
8981 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8982 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8983 track
.level
= level
;
8984 track
.assertionBits
= which
;
8985 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8986 track
.ownerService
= serviceID
;
8987 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8988 track
.modifiedTime
= 0;
8989 pmEventTimeStamp(&track
.createdTime
);
8991 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8994 if (track
.ownerString
)
8995 track
.ownerString
->release();
8996 return kIOReturnNoMemory
;
9001 if (owner
&& owner
->pmPowerStateQueue
) {
9002 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9005 return kIOReturnSuccess
;
9008 /* PMAssertionsTracker::handleReleaseAssertion
9009 * Runs in PM workloop. Do not call directly.
9011 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9012 IOPMDriverAssertionID _id
)
9017 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9020 return kIOReturnNotFound
;
9022 IOLockLock(assertionsArrayLock
);
9023 if (assertStruct
->ownerString
)
9024 assertStruct
->ownerString
->release();
9026 assertionsArray
->removeObject(index
);
9027 IOLockUnlock(assertionsArrayLock
);
9030 return kIOReturnSuccess
;
9033 /* PMAssertionsTracker::releaseAssertion
9034 * Releases an assertion and affects system behavior if appropiate.
9035 * Actual work happens on PM workloop.
9037 IOReturn
PMAssertionsTracker::releaseAssertion(
9038 IOPMDriverAssertionID _id
)
9040 if (owner
&& owner
->pmPowerStateQueue
) {
9041 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9043 return kIOReturnSuccess
;
9046 /* PMAssertionsTracker::handleSetAssertionLevel
9047 * Runs in PM workloop. Do not call directly.
9049 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9050 IOPMDriverAssertionID _id
,
9051 IOPMDriverAssertionLevel _level
)
9053 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9057 if (!assertStruct
) {
9058 return kIOReturnNotFound
;
9061 IOLockLock(assertionsArrayLock
);
9062 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9063 assertStruct
->level
= _level
;
9064 IOLockUnlock(assertionsArrayLock
);
9067 return kIOReturnSuccess
;
9070 /* PMAssertionsTracker::setAssertionLevel
9072 IOReturn
PMAssertionsTracker::setAssertionLevel(
9073 IOPMDriverAssertionID _id
,
9074 IOPMDriverAssertionLevel _level
)
9076 if (owner
&& owner
->pmPowerStateQueue
) {
9077 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9078 (void *)(uintptr_t)_level
, _id
);
9081 return kIOReturnSuccess
;
9084 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9086 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9090 if (new_user_levels
!= assertionsUser
)
9092 assertionsUser
= new_user_levels
;
9093 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9097 return kIOReturnSuccess
;
9100 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9101 IOPMDriverAssertionType new_user_levels
)
9103 if (gIOPMWorkLoop
) {
9104 gIOPMWorkLoop
->runAction(
9105 OSMemberFunctionCast(
9108 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9110 (void *) &new_user_levels
, 0, 0, 0);
9113 return kIOReturnSuccess
;
9117 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9121 OSArray
*outArray
= NULL
;
9123 if (!assertionsArray
||
9124 (0 == (count
= assertionsArray
->getCount())) ||
9125 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9130 for (i
=0; i
<count
; i
++)
9132 PMAssertStruct
*_a
= NULL
;
9134 OSDictionary
*details
= NULL
;
9136 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9137 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9139 OSNumber
*_n
= NULL
;
9141 details
= OSDictionary::withCapacity(7);
9145 outArray
->setObject(details
);
9148 _n
= OSNumber::withNumber(_a
->id
, 64);
9150 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9153 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9155 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9158 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9160 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9163 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9165 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9168 _n
= OSNumber::withNumber(_a
->level
, 64);
9170 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9173 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9175 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9179 if (_a
->ownerString
) {
9180 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9189 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9191 return assertionsCombined
;
9194 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9195 IOPMDriverAssertionType type
)
9197 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9199 return kIOPMDriverAssertionLevelOn
;
9201 return kIOPMDriverAssertionLevelOff
;
9205 //*********************************************************************************
9206 //*********************************************************************************
9207 //*********************************************************************************
9210 static void pmEventTimeStamp(uint64_t *recordTS
)
9218 // We assume tsec fits into 32 bits; 32 bits holds enough
9219 // seconds for 136 years since the epoch in 1970.
9220 clock_get_calendar_microtime(&tsec
, &tusec
);
9223 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9225 *recordTS
|= (uint32_t)tusec
;
9226 *recordTS
|= ((uint64_t)tsec
<< 32);
9232 // MARK: IORootParent
9234 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9236 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9238 // The reason that root domain needs a root parent is to facilitate demand
9239 // sleep, since a power change from the root parent cannot be vetoed.
9241 // The above statement is no longer true since root domain now performs
9242 // demand sleep using overrides. But root parent remains to avoid changing
9243 // the power tree stacking. Root parent is parked at the max power state.
9246 static IOPMPowerState patriarchPowerStates
[2] =
9248 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9249 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9252 void IORootParent::initialize( void )
9256 bool IORootParent::start( IOService
* nub
)
9258 IOService::start(nub
);
9259 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9261 registerPowerDriver(this, patriarchPowerStates
, 2);
9266 void IORootParent::shutDownSystem( void )
9270 void IORootParent::restartSystem( void )
9274 void IORootParent::sleepSystem( void )
9278 void IORootParent::dozeSystem( void )
9282 void IORootParent::sleepToDoze( void )
9286 void IORootParent::wakeSystem( void )
9290 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9292 return (IOService::copyProperty(aKey
));
9296 #if defined(__i386__) || defined(__x86_64__)
9297 IOReturn
IOPMrootDomain::restartWithStackshot()
9299 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9300 return kIOReturnError
;
9302 takeStackshot(true, true, false);
9304 return kIOReturnSuccess
;
9307 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9309 takeStackshot(wdogTrigger
, false, false);
9312 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9314 swd_hdr
* hdr
= NULL
;
9316 int wdog_panic
= -1;
9319 kern_return_t kr
= KERN_SUCCESS
;
9324 uint32_t bytesRemaining
;
9325 unsigned bytesWritten
= 0;
9326 unsigned totalBytes
= 0;
9328 OSString
* UUIDstring
= NULL
;
9330 IOMemoryMap
* logBufMap
= NULL
;
9334 uint32_t initialStackSize
;
9337 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9338 _systemTransitionType
!= kSystemTransitionWake
)
9341 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9346 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9347 if (wdog_panic
== 1) {
9348 // If boot-arg specifies to panic then panic.
9349 panic("Sleep/Wake hang detected\n");
9352 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9353 // If current boot is due to this watch dog trigger restart in previous boot,
9354 // then don't trigger again until at least 1 successful sleep & wake.
9355 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9356 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9357 PEHaltRestart(kPEHaltCPU
);
9365 if (gSpinDumpBufferFull
)
9367 if (swd_spindump_buffer
== NULL
) {
9368 sleepWakeDebugSpinDumpMemAlloc();
9369 if (swd_spindump_buffer
== NULL
) return;
9372 bufSize
= SWD_SPINDUMP_SIZE
;
9373 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9375 if (sleepWakeDebugIsWdogEnabled() == false)
9378 if (swd_buffer
== NULL
) {
9379 sleepWakeDebugMemAlloc();
9380 if (swd_buffer
== NULL
) return;
9383 bufSize
= SWD_BUF_SIZE
;
9384 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9387 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9391 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9394 hdr
= (swd_hdr
*)swd_buffer
;
9397 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9398 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9400 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9401 const char *str
= UUIDstring
->getCStringNoCopy();
9402 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9405 DLOG("Data for current UUID already exists\n");
9410 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9411 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9413 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9414 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9416 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9418 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9419 while (kr
== KERN_SUCCESS
) {
9423 * Take stackshot of all process on first sample. Size is restricted
9424 * to SWD_INITIAL_STACK_SIZE
9427 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9428 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9431 /* Take sample of kernel threads only */
9433 size
= bytesRemaining
;
9436 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9437 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9438 kr
, pid
, size
, flags
, bytesWritten
);
9439 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9441 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9442 // Continue to take stackshot of just kernel threads
9447 else if (totalBytes
== 0) {
9448 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9452 dstAddr
+= bytesWritten
;
9453 totalBytes
+= bytesWritten
;
9454 bytesRemaining
-= bytesWritten
;
9459 IOSleep(10); // 10 ms
9462 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9465 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9466 code
= pmTracer
->getPMStatusCode();
9467 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9468 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9469 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9470 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9472 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9473 gRootDomain
->swd_lock
= 0;
9474 gSpinDumpBufferFull
= true;
9477 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9480 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9481 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9482 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9483 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9484 len
= sizeof(addr64_t
)*3;
9485 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9486 data
[0], data
[1], data
[2]);
9488 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9490 DLOG("Failed to update nvram boot-args\n");
9496 gRootDomain
->swd_lock
= 0;
9499 IOLog("Restarting to collect Sleep wake debug logs\n");
9500 PEHaltRestart(kPERestartCPU
);
9503 logBufMap
= sleepWakeDebugRetrieve();
9505 sleepWakeDebugDumpFromMem(logBufMap
);
9506 logBufMap
->release();
9512 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9514 vm_size_t size
= SWD_BUF_SIZE
;
9516 swd_hdr
*hdr
= NULL
;
9518 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9521 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9524 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9527 // Try allocating above 4GB. If that fails, try at 2GB
9528 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9529 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9530 size
, 0xFFFFFFFF00000000ULL
);
9532 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9533 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9534 size
, 0xFFFFFFFF10000000ULL
);
9537 if (memDesc
== NULL
)
9539 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9544 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9545 memset(hdr
, 0, sizeof(swd_hdr
));
9547 hdr
->signature
= SWD_HDR_SIGNATURE
;
9548 hdr
->alloc_size
= size
;
9550 hdr
->spindump_offset
= sizeof(swd_hdr
);
9551 swd_buffer
= (void *)hdr
;
9552 swd_memDesc
= memDesc
;
9553 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9556 gRootDomain
->swd_lock
= 0;
9559 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9561 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9563 swd_hdr
*hdr
= NULL
;
9565 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9567 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9570 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9571 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9574 if (memDesc
== NULL
)
9576 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9581 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9582 memset(hdr
, 0, sizeof(swd_hdr
));
9584 hdr
->signature
= SWD_HDR_SIGNATURE
;
9585 hdr
->alloc_size
= size
;
9587 hdr
->spindump_offset
= sizeof(swd_hdr
);
9588 swd_spindump_buffer
= (void *)hdr
;
9591 gRootDomain
->swd_lock
= 0;
9594 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9596 swd_flags
|= SWD_WDOG_ENABLED
;
9598 sleepWakeDebugMemAlloc();
9601 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9603 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9604 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9607 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9609 swd_hdr
*hdr
= NULL
;
9610 errno_t error
= EIO
;
9612 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9613 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9615 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9616 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9620 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9621 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9622 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9624 gSpinDumpBufferFull
= false;
9628 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9630 struct vnode
*vp
= NULL
;
9631 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9632 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9633 struct vnode_attr va
;
9634 errno_t error
= EIO
;
9636 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9637 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9639 IOLog("Failed to open the file %s\n", name
);
9640 swd_flags
|= SWD_FILEOP_ERROR
;
9644 VATTR_WANTED(&va
, va_nlink
);
9645 /* Don't dump to non-regular files or files with links. */
9646 if (vp
->v_type
!= VREG
||
9647 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9648 IOLog("Bailing as this is not a regular file\n");
9649 swd_flags
|= SWD_FILEOP_ERROR
;
9653 VATTR_SET(&va
, va_data_size
, 0);
9654 vnode_setattr(vp
, &va
, ctx
);
9658 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9659 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9661 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9662 swd_flags
|= SWD_FILEOP_ERROR
;
9665 DLOG("Saved %d bytes to file %s\n",len
, name
);
9670 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9671 if (ctx
) vfs_context_rele(ctx
);
9677 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9678 struct vnode
*srcVp
,
9679 vfs_context_t srcCtx
,
9680 char *tmpBuf
, uint64_t tmpBufSize
,
9682 const char *dstFname
,
9686 struct vnode
*vp
= NULL
;
9687 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9688 struct vnode_attr va
;
9689 errno_t error
= EIO
;
9690 uint64_t bytesToRead
, bytesToWrite
;
9691 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9692 uint32_t newcrc
= 0;
9694 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9695 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9697 IOLog("Failed to open the file %s\n", dstFname
);
9698 swd_flags
|= SWD_FILEOP_ERROR
;
9702 VATTR_WANTED(&va
, va_nlink
);
9703 /* Don't dump to non-regular files or files with links. */
9704 if (vp
->v_type
!= VREG
||
9705 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9706 IOLog("Bailing as this is not a regular file\n");
9707 swd_flags
|= SWD_FILEOP_ERROR
;
9711 VATTR_SET(&va
, va_data_size
, 0);
9712 vnode_setattr(vp
, &va
, ctx
);
9714 writeFileOffset
= 0;
9716 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9717 readFileOffset
= trunc_page(srcOffset
);
9719 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9720 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9721 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9722 vfs_context_ucred(srcCtx
), (int *) 0,
9723 vfs_context_proc(srcCtx
));
9725 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9726 swd_flags
|= SWD_FILEOP_ERROR
;
9730 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9731 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9732 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9735 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9737 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9738 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9739 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9740 vfs_context_ucred(ctx
), (int *) 0,
9741 vfs_context_proc(ctx
));
9743 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9744 swd_flags
|= SWD_FILEOP_ERROR
;
9748 writeFileOffset
+= bytesToWrite
;
9749 numBytes
-= bytesToWrite
;
9750 srcOffset
+= bytesToWrite
;
9753 if (crc
!= newcrc
) {
9754 /* Set stackshot size to 0 if crc doesn't match */
9756 VATTR_SET(&va
, va_data_size
, 0);
9757 vnode_setattr(vp
, &va
, ctx
);
9759 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9760 swd_flags
|= SWD_DATA_CRC_ERROR
;
9765 error
= vnode_close(vp
, FWRITE
, ctx
);
9766 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
9768 if (ctx
) vfs_context_rele(ctx
);
9775 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9776 void *tmpBuf
, struct vnode
**vp
)
9782 struct vnode_attr va
;
9783 IOHibernateImageHeader
*imageHdr
;
9786 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9787 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9789 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9793 VATTR_WANTED(&va
, va_nlink
);
9794 VATTR_WANTED(&va
, va_data_alloc
);
9795 if ((*vp
)->v_type
!= VREG
||
9796 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9797 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9798 error
= SWD_FILEOP_ERROR
;
9802 /* Read the sleepimage file header */
9803 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9804 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9805 vfs_context_ucred(*ctx
), (int *) 0,
9806 vfs_context_proc(*ctx
));
9808 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9809 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9810 error
= SWD_FILEOP_ERROR
;
9814 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9815 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9816 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9817 fname
, imageHdr
->signature
);
9818 error
= SWD_HDR_SIGNATURE_ERROR
;
9822 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9823 hdrOffset
= imageHdr
->deviceBlockSize
;
9824 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9825 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9826 va
.va_data_alloc
, fname
);
9827 error
= SWD_HDR_SIZE_ERROR
;
9834 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9840 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9844 char hibernateFilename
[MAXPATHLEN
+1];
9846 swd_hdr
*hdr
= NULL
;
9847 uint32_t stacksSize
, logSize
;
9848 uint64_t tmpBufSize
;
9849 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9850 errno_t error
= EIO
;
9851 OSObject
*obj
= NULL
;
9852 OSString
*str
= NULL
;
9853 OSNumber
*failStat
= NULL
;
9854 struct vnode
*vp
= NULL
;
9855 vfs_context_t ctx
= NULL
;
9856 const char *stacksFname
, *logFname
;
9858 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9860 DLOG("sleepWakeDebugDumpFromFile\n");
9861 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9864 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9868 /* Allocate a temp buffer to copy data between files */
9869 tmpBufSize
= 2*4096;
9870 tmpBufDesc
= IOBufferMemoryDescriptor::
9871 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9872 tmpBufSize
, PAGE_SIZE
);
9875 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9879 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9881 ctx
= vfs_context_create(vfs_context_current());
9883 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9884 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9886 /* Check if the debug data is saved to hibernation file */
9887 hibernateFilename
[0] = 0;
9888 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9890 if ((str
= OSDynamicCast(OSString
, obj
)))
9891 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9892 sizeof(hibernateFilename
));
9895 if (!hibernateFilename
[0]) {
9896 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9900 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9902 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9905 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9908 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9911 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9913 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9914 /* Read the sleep/wake debug header(swd_hdr) */
9915 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9916 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9917 vfs_context_ucred(ctx
), (int *) 0,
9918 vfs_context_proc(ctx
));
9920 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9921 round_page(sizeof(swd_hdr
)), rc
);
9922 swd_flags
|= SWD_FILEOP_ERROR
;
9926 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9927 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9928 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9929 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9930 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9931 swd_flags
|= SWD_BUF_SIZE_ERROR
;
9934 stacksSize
= hdr
->spindump_size
;
9936 /* Get stacks & log offsets in the image file */
9937 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9938 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9939 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9940 stacksFname
= getDumpStackFilename(hdr
);
9941 logFname
= getDumpLogFilename(hdr
);
9943 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9944 stacksFname
, stacksSize
, hdr
->crc
);
9945 if (error
== EFAULT
) {
9946 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9949 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9950 logFname
, logSize
, 0);
9952 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9957 // Write just the SleepWakeLog.dump with failure code
9961 char *offset
= NULL
;
9965 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9966 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9967 fcode
= failStat
->unsigned64BitValue();
9968 fname
= kSleepWakeLogFilename
;
9971 fname
= kAppleOSXWatchdogLogFilename
;
9974 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9975 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9976 memset(offset
, 0x20, size
); // Fill with spaces
9979 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
9980 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
9981 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9982 sleepWakeDebugSaveFile(fname
, offset
, size
);
9985 gRootDomain
->swd_lock
= 0;
9987 if (vp
) vnode_close(vp
, FREAD
, ctx
);
9988 if (ctx
) vfs_context_rele(ctx
);
9989 if (tmpBufDesc
) tmpBufDesc
->release();
9990 #endif /* HIBERNATION */
9993 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
9995 IOVirtualAddress srcBuf
= NULL
;
9996 char *stackBuf
= NULL
, *logOffset
= NULL
;
9999 errno_t error
= EIO
;
10000 uint64_t bufSize
= 0;
10001 swd_hdr
*hdr
= NULL
;
10002 OSNumber
*failStat
= NULL
;
10004 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10007 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10009 DLOG("Nothing saved to dump to file\n");
10013 hdr
= (swd_hdr
*)srcBuf
;
10014 bufSize
= logBufMap
->getLength();
10015 if (bufSize
<= sizeof(swd_hdr
))
10017 IOLog("SleepWake log buffer size is invalid\n");
10018 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10022 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10024 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10025 if (error
) goto exit
;
10027 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10028 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10030 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10031 if (error
) goto exit
;
10033 hdr
->spindump_size
= 0;
10038 // Write just the SleepWakeLog.dump with failure code
10039 uint64_t fcode
= 0;
10040 const char *sname
, *lname
;
10043 /* Try writing an empty stacks file */
10045 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10046 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10047 fcode
= failStat
->unsigned64BitValue();
10048 lname
= kSleepWakeLogFilename
;
10049 sname
= kSleepWakeStackFilename
;
10052 lname
= kAppleOSXWatchdogLogFilename
;
10053 sname
= kAppleOSXWatchdogStackFilename
;
10056 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10058 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10059 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10060 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10063 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10064 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10065 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10066 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10069 gRootDomain
->swd_lock
= 0;
10072 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10074 IOVirtualAddress vaddr
= NULL
;
10075 IOMemoryDescriptor
* desc
= NULL
;
10076 IOMemoryMap
* logBufMap
= NULL
;
10080 uint64_t bufSize
= 0;
10082 uint64_t newcrc
= 0;
10083 uint64_t paddr
= 0;
10084 swd_hdr
*hdr
= NULL
;
10089 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10092 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10093 DLOG("No sleepWakeDebug note to read\n");
10097 if (len
== strlen("sleepimage")) {
10099 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10101 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10102 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10103 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10107 else if (len
== sizeof(addr64_t
)*3) {
10108 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10111 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10117 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10118 data
[0], data
[1], data
[2]);
10119 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10123 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10125 IOLog("SleepWake log buffer size is invalid\n");
10126 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10130 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10131 bufSize
, crc
, paddr
);
10134 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10135 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10138 IOLog("Fail to map SleepWake log buffer\n");
10139 swd_flags
|= SWD_INTERNAL_FAILURE
;
10143 logBufMap
= desc
->map();
10145 vaddr
= logBufMap
->getVirtualAddress();
10148 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10149 IOLog("Fail to map SleepWake log buffer\n");
10150 swd_flags
|= SWD_INTERNAL_FAILURE
;
10154 hdr
= (swd_hdr
*)vaddr
;
10155 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10157 IOLog("SleepWake log header size is invalid\n");
10158 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10163 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10164 hdr
->spindump_size
);
10165 if (newcrc
!= crc
) {
10166 IOLog("SleepWake log buffer contents are invalid\n");
10167 swd_flags
|= SWD_DATA_CRC_ERROR
;
10172 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10176 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10178 if (logBufMap
) logBufMap
->release();
10181 if (desc
) desc
->release();
10182 gRootDomain
->swd_lock
= 0;
10189 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10191 uint32_t wdog_panic
= 1;
10194 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10195 (wdog_panic
== 0)) {
10198 panic("Sleep/Wake hang detected\n");
10203 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10205 #pragma unused(restart)
10206 #pragma unused(isOSXWatchdog)
10209 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10212 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10215 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10216 struct vnode
*srcVp
,
10217 vfs_context_t srcCtx
,
10218 char *tmpBuf
, uint64_t tmpBufSize
,
10219 uint64_t srcOffset
,
10220 const char *dstFname
,
10227 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10231 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10236 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10240 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10245 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)