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 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
717 (CAP_LOSS(kIOPMSystemCapabilityGraphics
))) {
718 IOHibernateSystemPostWakeTrim((void*)1, NULL
);
720 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
727 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
729 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
730 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
732 rootDomain
->swdDebugTeardown();
734 rootDomain
->allowPowerChange(notifyRef
);
736 DLOG("swdDebugTeardownCallout finish\n");
739 void IOPMrootDomain::swdDebugTeardown( )
743 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
744 if (swd_DebugImageSetup
== TRUE
) {
745 swd_DebugImageSetup
= FALSE
;
746 IOCloseDebugDataFile();
752 //******************************************************************************
755 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
757 IOService
* rootDomain
= (IOService
*) p0
;
758 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
759 uint32_t powerState
= rootDomain
->getPowerState();
761 DLOG("disk_sync_callout ps=%u\n", powerState
);
763 if (ON_STATE
== powerState
)
766 swdDebugSetupCallout(p0
, NULL
);
771 swdDebugTeardownCallout(p0
, NULL
);
772 IOHibernateSystemPostWake();
775 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
779 rootDomain
->allowPowerChange(notifyRef
);
780 DLOG("disk_sync_callout finish\n");
783 //******************************************************************************
784 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
786 AbsoluteTime endTime
;
789 clock_get_uptime(&endTime
);
790 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
792 SUB_ABSOLUTETIME(&endTime
, startTime
);
793 absolutetime_to_nanoseconds(endTime
, &nano
);
796 return (UInt32
)(nano
/ 1000000ULL);
799 //******************************************************************************
802 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
804 struct timeval
*swt
= (struct timeval
*)arg1
;
805 struct proc
*p
= req
->p
;
808 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
809 } else if(proc_is64bit(p
)) {
810 struct user64_timeval t
;
811 t
.tv_sec
= swt
->tv_sec
;
812 t
.tv_usec
= swt
->tv_usec
;
813 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
815 struct user32_timeval t
;
816 t
.tv_sec
= swt
->tv_sec
;
817 t
.tv_usec
= swt
->tv_usec
;
818 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
822 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
823 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
824 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
826 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
827 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
828 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
830 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
831 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
835 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
837 int new_value
, changed
;
838 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
840 if (!gWillShutdown
&& (new_value
== 1)) {
841 IOPMRootDomainWillShutdown();
848 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
849 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
850 0, 0, sysctl_willshutdown
, "I", "");
852 extern struct sysctl_oid sysctl__kern_iokittest
;
856 sysctl_progressmeterenable
857 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
860 int new_value
, changed
;
862 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
864 if (changed
) vc_enable_progressmeter(new_value
);
871 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
874 int new_value
, changed
;
876 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
878 if (changed
) vc_set_progressmeter(new_value
);
883 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
884 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
885 0, 0, sysctl_progressmeterenable
, "I", "");
887 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
888 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
889 0, 0, sysctl_progressmeter
, "I", "");
895 sysctl_consoleoptions
896 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
901 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
903 if (changed
) vc_user_options
.options
= new_value
;
908 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
909 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
910 0, 0, sysctl_consoleoptions
, "I", "");
914 sysctl_progressoptions SYSCTL_HANDLER_ARGS
916 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
919 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
920 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
921 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
925 sysctl_wakereason SYSCTL_HANDLER_ARGS
927 char wr
[ sizeof(gWakeReasonString
) ];
931 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
933 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
936 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
937 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
938 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
941 sysctl_targettype SYSCTL_HANDLER_ARGS
949 root
= IOService::getServiceRoot();
950 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
952 if ((data
= OSDynamicCast(OSData
, obj
)))
954 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
958 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
961 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
962 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
963 NULL
, 0, sysctl_targettype
, "A", "targettype");
965 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
966 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
968 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
969 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
970 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
971 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
972 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
973 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
974 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
975 static const OSSymbol
* gIOPMUserIsActiveKey
;
977 //******************************************************************************
980 //******************************************************************************
982 #define kRootDomainSettingsCount 17
984 bool IOPMrootDomain::start( IOService
* nub
)
986 OSIterator
*psIterator
;
987 OSDictionary
*tmpDict
;
988 IORootParent
* patriarch
;
989 #if defined(__i386__) || defined(__x86_64__)
990 IONotifier
* notifier
;
996 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
997 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
998 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
999 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1000 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1001 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1002 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1003 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1005 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1006 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1007 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1008 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1009 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1011 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1012 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1014 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1016 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1017 gIOPMSettingAutoWakeSecondsKey
,
1018 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1019 gIOPMSettingAutoWakeCalendarKey
,
1020 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1021 gIOPMSettingDebugWakeRelativeKey
,
1022 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1023 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1024 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1025 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1026 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1027 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1028 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1029 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1030 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1031 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1032 gIOPMSettingSilentRunningKey
1035 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1036 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1038 queue_init(&aggressivesQueue
);
1039 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1040 aggressivesData
= OSData::withCapacity(
1041 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1043 featuresDictLock
= IOLockAlloc();
1044 settingsCtrlLock
= IOLockAlloc();
1045 wakeEventLock
= IOLockAlloc();
1046 setPMRootDomain(this);
1048 extraSleepTimer
= thread_call_allocate(
1049 idleSleepTimerExpired
,
1050 (thread_call_param_t
) this);
1052 diskSyncCalloutEntry
= thread_call_allocate(
1054 (thread_call_param_t
) this);
1055 swdDebugSetupEntry
= thread_call_allocate(
1056 &swdDebugSetupCallout
,
1057 (thread_call_param_t
) this);
1058 swdDebugTearDownEntry
= thread_call_allocate(
1059 &swdDebugTeardownCallout
,
1060 (thread_call_param_t
) this);
1061 updateConsoleUsersEntry
= thread_call_allocate(
1062 &updateConsoleUsersCallout
,
1063 (thread_call_param_t
) this);
1065 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1066 fullWakeThreadCall
= thread_call_allocate(
1067 OSMemberFunctionCast(thread_call_func_t
, this,
1068 &IOPMrootDomain::fullWakeDelayedWork
),
1069 (thread_call_param_t
) this);
1072 setProperty(kIOSleepSupportedKey
, true);
1074 bzero(&gPMStats
, sizeof(gPMStats
));
1076 pmTracer
= PMTraceWorker::tracer(this);
1078 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1080 userDisabledAllSleep
= false;
1081 systemBooting
= true;
1082 idleSleepEnabled
= false;
1084 idleSleepTimerPending
= false;
1086 clamshellClosed
= false;
1087 clamshellExists
= false;
1088 clamshellDisabled
= true;
1089 acAdaptorConnected
= true;
1090 clamshellSleepDisabled
= false;
1091 gWakeReasonString
[0] = '\0';
1093 // Initialize to user active.
1094 // Will never transition to user inactive w/o wrangler.
1095 fullWakeReason
= kFullWakeReasonLocalUser
;
1096 userIsActive
= userWasActive
= true;
1097 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1099 // Set the default system capabilities at boot.
1100 _currentCapability
= kIOPMSystemCapabilityCPU
|
1101 kIOPMSystemCapabilityGraphics
|
1102 kIOPMSystemCapabilityAudio
|
1103 kIOPMSystemCapabilityNetwork
;
1105 _pendingCapability
= _currentCapability
;
1106 _desiredCapability
= _currentCapability
;
1107 _highestCapability
= _currentCapability
;
1108 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1110 queuedSleepWakeUUIDString
= NULL
;
1111 initializeBootSessionUUID();
1112 pmStatsAppResponses
= OSArray::withCapacity(5);
1113 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1114 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1115 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1116 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1117 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1118 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1119 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1121 pmStatsLock
= IOLockAlloc();
1122 idxPMCPUClamshell
= kCPUUnknownIndex
;
1123 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1125 tmpDict
= OSDictionary::withCapacity(1);
1126 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1129 settingsCallbacks
= OSDictionary::withCapacity(1);
1131 // Create a list of the valid PM settings that we'll relay to
1132 // interested clients in setProperties() => setPMSetting()
1133 allowedPMSettings
= OSArray::withObjects(
1134 (const OSObject
**)settingsArr
,
1135 kRootDomainSettingsCount
,
1138 // List of PM settings that should not automatically publish itself
1139 // as a feature when registered by a listener.
1140 noPublishPMSettings
= OSArray::withObjects(
1141 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1143 fPMSettingsDict
= OSDictionary::withCapacity(5);
1144 preventIdleSleepList
= OSSet::withCapacity(8);
1145 preventSystemSleepList
= OSSet::withCapacity(2);
1147 PMinit(); // creates gIOPMWorkLoop
1148 gIOPMWorkLoop
= getIOPMWorkloop();
1150 // Create IOPMPowerStateQueue used to queue external power
1151 // events, and to handle those events on the PM work loop.
1152 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1153 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1154 &IOPMrootDomain::dispatchPowerEvent
));
1155 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1157 // create our power parent
1158 patriarch
= new IORootParent
;
1160 patriarch
->attach(this);
1161 patriarch
->start(this);
1162 patriarch
->addPowerChild(this);
1164 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1165 changePowerStateToPriv(ON_STATE
);
1167 // install power change handler
1168 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1171 // Register for a notification when IODisplayWrangler is published
1172 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1174 _displayWranglerNotifier
= addMatchingNotification(
1175 gIOPublishNotification
, tmpDict
,
1176 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1182 #if defined(__i386__) || defined(__x86_64__)
1184 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1186 notifier
= addMatchingNotification(
1187 gIOFirstPublishNotification
, tmpDict
,
1188 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1193 wranglerIdleSettings
= NULL
;
1194 OSNumber
* wranglerIdlePeriod
= NULL
;
1195 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1196 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1198 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1199 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1200 wranglerIdlePeriod
);
1202 if(wranglerIdlePeriod
)
1203 wranglerIdlePeriod
->release();
1206 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1207 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1208 ucClassName
->release();
1210 // IOBacklightDisplay can take a long time to load at boot, or it may
1211 // not load at all if you're booting with clamshell closed. We publish
1212 // 'DisplayDims' here redundantly to get it published early and at all.
1213 OSDictionary
* matching
;
1214 matching
= serviceMatching("IOPMPowerSource");
1215 psIterator
= getMatchingServices( matching
);
1216 if (matching
) matching
->release();
1217 if( psIterator
&& psIterator
->getNextObject() )
1219 // There's at least one battery on the system, so we publish
1220 // 'DisplayDims' support for the LCD.
1221 publishFeature("DisplayDims");
1224 psIterator
->release();
1227 sysctl_register_oid(&sysctl__kern_sleeptime
);
1228 sysctl_register_oid(&sysctl__kern_waketime
);
1229 sysctl_register_oid(&sysctl__kern_willshutdown
);
1230 sysctl_register_oid(&sysctl__kern_iokittest
);
1231 sysctl_register_oid(&sysctl__hw_targettype
);
1233 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1234 sysctl_register_oid(&sysctl__kern_progressmeter
);
1235 sysctl_register_oid(&sysctl__kern_wakereason
);
1236 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1237 sysctl_register_oid(&sysctl__kern_progressoptions
);
1240 IOHibernateSystemInit(this);
1243 registerService(); // let clients find us
1248 //******************************************************************************
1251 // Receive a setProperty call
1252 // The "System Boot" property means the system is completely booted.
1253 //******************************************************************************
1255 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1257 IOReturn return_value
= kIOReturnSuccess
;
1258 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1261 const OSSymbol
*key
;
1263 OSCollectionIterator
* iter
= 0;
1265 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1266 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1267 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1268 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1269 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1270 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1271 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1272 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1273 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1274 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1275 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1277 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1278 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1279 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1280 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1281 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1282 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1287 return_value
= kIOReturnBadArgument
;
1291 iter
= OSCollectionIterator::withCollection(dict
);
1294 return_value
= kIOReturnNoMemory
;
1298 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1299 (obj
= dict
->getObject(key
)))
1301 if (key
->isEqualTo(publish_simulated_battery_string
))
1303 if (OSDynamicCast(OSBoolean
, obj
))
1304 publishResource(key
, kOSBooleanTrue
);
1306 else if (key
->isEqualTo(idle_seconds_string
))
1308 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1310 setProperty(key
, n
);
1311 idleSeconds
= n
->unsigned32BitValue();
1314 else if (key
->isEqualTo(boot_complete_string
))
1316 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1318 else if (key
->isEqualTo(sys_shutdown_string
))
1320 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1321 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1323 else if (key
->isEqualTo(battery_warning_disabled_string
))
1325 setProperty(key
, obj
);
1328 else if (key
->isEqualTo(hibernatemode_string
) ||
1329 key
->isEqualTo(hibernatefilemin_string
) ||
1330 key
->isEqualTo(hibernatefilemax_string
) ||
1331 key
->isEqualTo(hibernatefreeratio_string
) ||
1332 key
->isEqualTo(hibernatefreetime_string
))
1334 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1335 setProperty(key
, n
);
1337 else if (key
->isEqualTo(hibernatefile_string
))
1339 OSString
* str
= OSDynamicCast(OSString
, obj
);
1340 if (str
) setProperty(key
, str
);
1343 else if (key
->isEqualTo(sleepdisabled_string
))
1345 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1347 setProperty(key
, b
);
1348 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1351 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1354 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1356 else if (key
->isEqualTo(loginwindow_progress_string
))
1358 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1359 uint32_t data
= n
->unsigned32BitValue();
1360 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1361 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1364 else if (key
->isEqualTo(coredisplay_progress_string
))
1366 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1367 uint32_t data
= n
->unsigned32BitValue();
1368 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1369 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1372 else if (key
->isEqualTo(coregraphics_progress_string
))
1374 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1375 uint32_t data
= n
->unsigned32BitValue();
1376 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1377 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1380 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1381 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1382 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1383 key
->isEqualTo(stall_halt_string
))
1385 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1386 setProperty(key
, b
);
1388 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1389 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1390 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1392 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1393 setProperty(key
, n
);
1395 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1397 if (kOSBooleanTrue
== obj
)
1398 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1400 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1401 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1404 // Relay our allowed PM settings onto our registered PM clients
1405 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1407 return_value
= setPMSetting(key
, obj
);
1408 if (kIOReturnSuccess
!= return_value
)
1411 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1413 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1414 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1416 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1420 _debugWakeSeconds
= 0;
1421 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1423 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1425 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1428 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1429 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1431 const IOPMCalendarStruct
* cs
=
1432 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1435 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1437 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1438 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1444 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1449 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1450 if(boot_complete_string
) boot_complete_string
->release();
1451 if(sys_shutdown_string
) sys_shutdown_string
->release();
1452 if(stall_halt_string
) stall_halt_string
->release();
1453 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1454 if(idle_seconds_string
) idle_seconds_string
->release();
1455 if(sleepdisabled_string
) sleepdisabled_string
->release();
1456 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1457 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1458 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1459 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1461 if(hibernatemode_string
) hibernatemode_string
->release();
1462 if(hibernatefile_string
) hibernatefile_string
->release();
1463 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1464 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1466 if (iter
) iter
->release();
1467 return return_value
;
1471 // MARK: Aggressiveness
1473 //******************************************************************************
1474 // setAggressiveness
1476 // Override IOService::setAggressiveness()
1477 //******************************************************************************
1479 IOReturn
IOPMrootDomain::setAggressiveness(
1481 unsigned long value
)
1483 return setAggressiveness( type
, value
, 0 );
1487 * Private setAggressiveness() with an internal options argument.
1489 IOReturn
IOPMrootDomain::setAggressiveness(
1491 unsigned long value
,
1492 IOOptionBits options
)
1494 AggressivesRequest
* entry
;
1495 AggressivesRequest
* request
;
1498 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1499 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1501 request
= IONew(AggressivesRequest
, 1);
1503 return kIOReturnNoMemory
;
1505 memset(request
, 0, sizeof(*request
));
1506 request
->options
= options
;
1507 request
->dataType
= kAggressivesRequestTypeRecord
;
1508 request
->data
.record
.type
= (uint32_t) type
;
1509 request
->data
.record
.value
= (uint32_t) value
;
1513 // Update disk quick spindown flag used by getAggressiveness().
1514 // Never merge requests with quick spindown flags set.
1516 if (options
& kAggressivesOptionQuickSpindownEnable
)
1517 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1518 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1519 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1522 // Coalesce requests with identical aggressives types.
1523 // Deal with callers that calls us too "aggressively".
1525 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1527 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1528 (entry
->data
.record
.type
== type
) &&
1529 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1531 entry
->data
.record
.value
= value
;
1540 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1543 AGGRESSIVES_UNLOCK();
1546 IODelete(request
, AggressivesRequest
, 1);
1548 if (options
& kAggressivesOptionSynchronous
)
1549 handleAggressivesRequests(); // not truly synchronous
1551 thread_call_enter(aggressivesThreadCall
);
1553 return kIOReturnSuccess
;
1556 //******************************************************************************
1557 // getAggressiveness
1559 // Override IOService::setAggressiveness()
1560 // Fetch the aggressiveness factor with the given type.
1561 //******************************************************************************
1563 IOReturn
IOPMrootDomain::getAggressiveness (
1565 unsigned long * outLevel
)
1571 return kIOReturnBadArgument
;
1575 // Disk quick spindown in effect, report value = 1
1577 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1578 (type
== kPMMinutesToSpinDown
))
1580 value
= kAggressivesMinValue
;
1584 // Consult the pending request queue.
1588 AggressivesRequest
* entry
;
1590 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1592 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1593 (entry
->data
.record
.type
== type
) &&
1594 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1596 value
= entry
->data
.record
.value
;
1603 // Consult the backend records.
1605 if (!source
&& aggressivesData
)
1607 AggressivesRecord
* record
;
1610 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1611 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1613 for (i
= 0; i
< count
; i
++, record
++)
1615 if (record
->type
== type
)
1617 value
= record
->value
;
1624 AGGRESSIVES_UNLOCK();
1628 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1629 source
, (uint32_t) type
, value
);
1630 *outLevel
= (unsigned long) value
;
1631 return kIOReturnSuccess
;
1635 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1636 *outLevel
= 0; // default return = 0, driver may not check for error
1637 return kIOReturnInvalid
;
1641 //******************************************************************************
1642 // joinAggressiveness
1644 // Request from IOService to join future aggressiveness broadcasts.
1645 //******************************************************************************
1647 IOReturn
IOPMrootDomain::joinAggressiveness(
1648 IOService
* service
)
1650 AggressivesRequest
* request
;
1652 if (!service
|| (service
== this))
1653 return kIOReturnBadArgument
;
1655 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1657 request
= IONew(AggressivesRequest
, 1);
1659 return kIOReturnNoMemory
;
1661 service
->retain(); // released by synchronizeAggressives()
1663 memset(request
, 0, sizeof(*request
));
1664 request
->dataType
= kAggressivesRequestTypeService
;
1665 request
->data
.service
= service
;
1668 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1669 AGGRESSIVES_UNLOCK();
1671 thread_call_enter(aggressivesThreadCall
);
1673 return kIOReturnSuccess
;
1676 //******************************************************************************
1677 // handleAggressivesRequests
1679 // Backend thread processes all incoming aggressiveness requests in the queue.
1680 //******************************************************************************
1683 handleAggressivesFunction(
1684 thread_call_param_t param1
,
1685 thread_call_param_t param2
)
1689 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1693 void IOPMrootDomain::handleAggressivesRequests( void )
1695 AggressivesRecord
* start
;
1696 AggressivesRecord
* record
;
1697 AggressivesRequest
* request
;
1698 queue_head_t joinedQueue
;
1702 bool pingSelf
= false;
1706 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1707 queue_empty(&aggressivesQueue
))
1710 gAggressivesState
|= kAggressivesStateBusy
;
1711 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1712 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1717 queue_init(&joinedQueue
);
1721 // Remove request from the incoming queue in FIFO order.
1722 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1723 switch (request
->dataType
)
1725 case kAggressivesRequestTypeRecord
:
1726 // Update existing record if found.
1728 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1730 if (record
->type
== request
->data
.record
.type
)
1734 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1736 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1739 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1740 kAggressivesRecordFlagModified
);
1741 DLOG("disk spindown accelerated, was %u min\n",
1745 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1747 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1750 record
->flags
|= kAggressivesRecordFlagModified
;
1751 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1752 DLOG("disk spindown restored to %u min\n",
1756 else if (record
->value
!= request
->data
.record
.value
)
1758 record
->value
= request
->data
.record
.value
;
1759 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1762 record
->flags
|= kAggressivesRecordFlagModified
;
1769 // No matching record, append a new record.
1771 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1773 AggressivesRecord newRecord
;
1775 newRecord
.flags
= kAggressivesRecordFlagModified
;
1776 newRecord
.type
= request
->data
.record
.type
;
1777 newRecord
.value
= request
->data
.record
.value
;
1778 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1780 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1781 DLOG("disk spindown accelerated\n");
1784 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1786 // OSData may have switched to another (larger) buffer.
1787 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1788 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1792 // Finished processing the request, release it.
1793 IODelete(request
, AggressivesRequest
, 1);
1796 case kAggressivesRequestTypeService
:
1797 // synchronizeAggressives() will free request.
1798 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1802 panic("bad aggressives request type %x\n", request
->dataType
);
1805 } while (!queue_empty(&aggressivesQueue
));
1807 // Release the lock to perform work, with busy flag set.
1808 if (!queue_empty(&joinedQueue
) || broadcast
)
1810 AGGRESSIVES_UNLOCK();
1811 if (!queue_empty(&joinedQueue
))
1812 synchronizeAggressives(&joinedQueue
, start
, count
);
1814 broadcastAggressives(start
, count
);
1818 // Remove the modified flag from all records.
1819 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1821 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1822 ((record
->type
== kPMMinutesToDim
) ||
1823 (record
->type
== kPMMinutesToSleep
)))
1826 record
->flags
&= ~kAggressivesRecordFlagModified
;
1829 // Check the incoming queue again since new entries may have been
1830 // added while lock was released above.
1832 } while (!queue_empty(&aggressivesQueue
));
1834 gAggressivesState
&= ~kAggressivesStateBusy
;
1837 AGGRESSIVES_UNLOCK();
1839 // Root domain is interested in system and display sleep slider changes.
1840 // Submit a power event to handle those changes on the PM work loop.
1842 if (pingSelf
&& pmPowerStateQueue
) {
1843 pmPowerStateQueue
->submitPowerEvent(
1844 kPowerEventPolicyStimulus
,
1845 (void *) kStimulusAggressivenessChanged
);
1849 //******************************************************************************
1850 // synchronizeAggressives
1852 // Push all known aggressiveness records to one or more IOService.
1853 //******************************************************************************
1855 void IOPMrootDomain::synchronizeAggressives(
1856 queue_head_t
* joinedQueue
,
1857 const AggressivesRecord
* array
,
1860 IOService
* service
;
1861 AggressivesRequest
* request
;
1862 const AggressivesRecord
* record
;
1863 IOPMDriverCallEntry callEntry
;
1867 while (!queue_empty(joinedQueue
))
1869 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1870 if (request
->dataType
== kAggressivesRequestTypeService
)
1871 service
= request
->data
.service
;
1875 IODelete(request
, AggressivesRequest
, 1);
1880 if (service
->assertPMDriverCall(&callEntry
))
1882 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1884 value
= record
->value
;
1885 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1886 value
= kAggressivesMinValue
;
1888 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1889 record
->type
, value
, service
->getName());
1890 service
->setAggressiveness(record
->type
, value
);
1892 service
->deassertPMDriverCall(&callEntry
);
1894 service
->release(); // retained by joinAggressiveness()
1899 //******************************************************************************
1900 // broadcastAggressives
1902 // Traverse PM tree and call setAggressiveness() for records that have changed.
1903 //******************************************************************************
1905 void IOPMrootDomain::broadcastAggressives(
1906 const AggressivesRecord
* array
,
1909 IORegistryIterator
* iter
;
1910 IORegistryEntry
* entry
;
1911 IOPowerConnection
* connect
;
1912 IOService
* service
;
1913 const AggressivesRecord
* record
;
1914 IOPMDriverCallEntry callEntry
;
1918 iter
= IORegistryIterator::iterateOver(
1919 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1925 while ((entry
= iter
->getNextObject()))
1927 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1928 if (!connect
|| !connect
->getReadyFlag())
1931 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
1933 if (service
->assertPMDriverCall(&callEntry
))
1935 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1937 if (record
->flags
& kAggressivesRecordFlagModified
)
1939 value
= record
->value
;
1940 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1941 value
= kAggressivesMinValue
;
1942 _LOG("broadcastAggressives %x = %u to %s\n",
1943 record
->type
, value
, service
->getName());
1944 service
->setAggressiveness(record
->type
, value
);
1947 service
->deassertPMDriverCall(&callEntry
);
1953 while (!entry
&& !iter
->isValid());
1959 // MARK: System Sleep
1961 //******************************************************************************
1962 // startIdleSleepTimer
1964 //******************************************************************************
1966 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1968 AbsoluteTime deadline
;
1972 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
1977 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1978 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1979 idleSleepTimerPending
= true;
1983 thread_call_enter(extraSleepTimer
);
1985 DLOG("idle timer set for %u seconds\n", inSeconds
);
1988 //******************************************************************************
1989 // cancelIdleSleepTimer
1991 //******************************************************************************
1993 void IOPMrootDomain::cancelIdleSleepTimer( void )
1996 if (idleSleepTimerPending
)
1998 DLOG("idle timer cancelled\n");
1999 thread_call_cancel(extraSleepTimer
);
2000 idleSleepTimerPending
= false;
2002 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2004 clock_usec_t microsecs
;
2005 clock_get_uptime(&now
);
2006 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2007 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2008 if (assertOnWakeReport
) {
2009 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2010 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2016 //******************************************************************************
2017 // idleSleepTimerExpired
2019 //******************************************************************************
2021 static void idleSleepTimerExpired(
2022 thread_call_param_t us
, thread_call_param_t
)
2024 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2027 //******************************************************************************
2028 // handleSleepTimerExpiration
2030 // The time between the sleep idle timeout and the next longest one has elapsed.
2031 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2032 //******************************************************************************
2034 void IOPMrootDomain::handleSleepTimerExpiration( void )
2036 if (!gIOPMWorkLoop
->inGate())
2038 gIOPMWorkLoop
->runAction(
2039 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2040 &IOPMrootDomain::handleSleepTimerExpiration
),
2047 DLOG("sleep timer expired\n");
2050 idleSleepTimerPending
= false;
2052 clock_get_uptime(&time
);
2053 setQuickSpinDownTimeout();
2054 adjustPowerState(true);
2057 //******************************************************************************
2058 // getTimeToIdleSleep
2060 // Returns number of seconds left before going into idle sleep.
2061 // Caller has to make sure that idle sleep is allowed at the time of calling
2063 //******************************************************************************
2065 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2068 AbsoluteTime now
, lastActivityTime
;
2070 uint32_t minutesSinceUserInactive
= 0;
2071 uint32_t sleepDelay
= 0;
2073 if (!idleSleepEnabled
)
2076 if (userActivityTime
)
2077 lastActivityTime
= userActivityTime
;
2079 lastActivityTime
= userBecameInactiveTime
;
2081 clock_get_uptime(&now
);
2082 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2084 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2085 absolutetime_to_nanoseconds(now
, &nanos
);
2086 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2088 if (minutesSinceUserInactive
>= sleepSlider
)
2091 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2095 sleepDelay
= sleepSlider
;
2098 DLOG("user inactive %u min, time to idle sleep %u min\n",
2099 minutesSinceUserInactive
, sleepDelay
);
2101 return (sleepDelay
* 60);
2104 //******************************************************************************
2105 // setQuickSpinDownTimeout
2107 //******************************************************************************
2109 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2113 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2116 //******************************************************************************
2117 // restoreUserSpinDownTimeout
2119 //******************************************************************************
2121 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2125 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2128 //******************************************************************************
2131 //******************************************************************************
2134 IOReturn
IOPMrootDomain::sleepSystem( void )
2136 return sleepSystemOptions(NULL
);
2140 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2142 OSObject
*obj
= NULL
;
2143 OSString
*reason
= NULL
;
2144 /* sleepSystem is a public function, and may be called by any kernel driver.
2145 * And that's bad - drivers should sleep the system by calling
2146 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2148 * Note that user space app calls to IOPMSleepSystem() will also travel
2149 * this code path and thus be correctly identified as software sleeps.
2152 if (options
&& options
->getObject("OSSwitch"))
2154 // Log specific sleep cause for OS Switch hibernation
2155 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2158 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2160 reason
= OSDynamicCast(OSString
, obj
);
2161 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2162 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2165 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2169 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2171 /* Called from both gated and non-gated context */
2173 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2175 return kIOReturnNotPermitted
;
2178 pmPowerStateQueue
->submitPowerEvent(
2179 kPowerEventPolicyStimulus
,
2180 (void *) kStimulusDemandSystemSleep
,
2183 return kIOReturnSuccess
;
2186 //******************************************************************************
2189 // This overrides powerChangeDone in IOService.
2190 //******************************************************************************
2192 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2196 DLOG("PowerChangeDone: %u->%u\n",
2197 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2199 switch ( getPowerState() )
2202 if (previousPowerState
!= ON_STATE
)
2205 acceptSystemWakeEvents(true);
2207 // re-enable this timer for next sleep
2208 cancelIdleSleepTimer();
2211 clock_usec_t microsecs
;
2212 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2214 gIOLastSleepTime
.tv_sec
= secs
;
2215 gIOLastSleepTime
.tv_usec
= microsecs
;
2216 gIOLastWakeTime
.tv_sec
= 0;
2217 gIOLastWakeTime
.tv_usec
= 0;
2218 gIOLastSleepAbsTime
= now
;
2220 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2221 clock_usec_t microsecs
;
2222 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2223 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2225 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2226 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2227 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2228 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2229 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2231 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2232 wake2DarkwakeDelay
= 0;
2235 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2237 IOHibernateSystemHasSlept();
2239 evaluateSystemSleepPolicyFinal();
2241 LOG("System Sleep\n");
2243 if (thermalWarningState
) {
2244 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2246 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2250 assertOnWakeSecs
= 0;
2251 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2252 lowBatteryCondition
= false;
2254 getPlatform()->sleepKernel();
2256 // The CPU(s) are off at this point,
2257 // Code will resume execution here upon wake.
2259 clock_get_uptime(&gIOLastWakeAbsTime
);
2260 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2261 _highestCapability
= 0;
2263 ((IOService
*)this)->start_watchdog_timer(); //14456299
2265 IOHibernateSystemWake();
2268 // sleep transition complete
2269 gSleepOrShutdownPending
= 0;
2271 // trip the reset of the calendar clock
2273 clock_sec_t wakeSecs
;
2274 clock_usec_t wakeMicrosecs
;
2276 clock_initialize_calendar();
2278 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2279 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2280 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2284 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2287 lastSleepReason
= 0;
2289 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2290 _debugWakeSeconds
= 0;
2291 _scheduledAlarms
= 0;
2293 #if defined(__i386__) || defined(__x86_64__)
2294 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2295 wranglerTickled
= false;
2296 graphicsSuppressed
= false;
2297 darkWakePostTickle
= false;
2298 darkWakeHibernateError
= false;
2299 darkWakeToSleepASAP
= true;
2300 logGraphicsClamp
= true;
2301 sleepTimerMaintenance
= false;
2302 sleepToStandby
= false;
2303 wranglerTickleLatched
= false;
2304 userWasActive
= false;
2305 fullWakeReason
= kFullWakeReasonNone
;
2307 OSString
* wakeType
= OSDynamicCast(
2308 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2309 OSString
* wakeReason
= OSDynamicCast(
2310 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2312 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2313 gWakeReasonString
[0] == '\0')
2315 // Until the platform driver can claim its wake reasons
2316 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2317 sizeof(gWakeReasonString
));
2320 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2322 lowBatteryCondition
= true;
2323 darkWakeMaintenance
= true;
2325 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2328 OSNumber
* hibOptions
= OSDynamicCast(
2329 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2330 if (hibernateAborted
|| ((hibOptions
&&
2331 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2333 // Hibernate aborted, or EFI brought up graphics
2334 wranglerTickled
= true;
2335 DLOG("hibernation aborted %d, options 0x%x\n",
2337 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2342 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2343 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2345 // User wake or RTC alarm
2346 wranglerTickled
= true;
2350 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2352 // SMC standby timer trumps SleepX
2353 darkWakeMaintenance
= true;
2354 sleepTimerMaintenance
= true;
2357 if ((_lastDebugWakeSeconds
!= 0) &&
2358 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2360 // SleepX before maintenance
2361 wranglerTickled
= true;
2365 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2367 darkWakeMaintenance
= true;
2371 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2373 darkWakeMaintenance
= true;
2374 darkWakeSleepService
= true;
2376 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2377 sleepToStandby
= true;
2383 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2385 darkWakeMaintenance
= true;
2386 darkWakeHibernateError
= true;
2390 // Unidentified wake source, resume to full wake if debug
2391 // alarm is pending.
2393 if (_lastDebugWakeSeconds
&&
2394 (!wakeReason
|| wakeReason
->isEqualTo("")))
2395 wranglerTickled
= true;
2401 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2403 darkWakeMaintenance
= true;
2404 sleepTimerMaintenance
= true;
2406 else if (hibernateAborted
|| !wakeType
||
2407 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2408 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2410 // Post a HID tickle immediately - except for RTC maintenance wake.
2411 wranglerTickled
= true;
2415 darkWakeMaintenance
= true;
2419 if (wranglerTickled
)
2421 darkWakeToSleepASAP
= false;
2422 fullWakeReason
= kFullWakeReasonLocalUser
;
2425 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2427 handleDisplayPowerOn();
2429 else if (!darkWakeMaintenance
)
2431 // Early/late tickle for non-maintenance wake.
2432 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2433 kDarkWakeFlagHIDTickleEarly
) ||
2434 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2435 kDarkWakeFlagHIDTickleLate
))
2437 darkWakePostTickle
= true;
2440 #else /* !__i386__ && !__x86_64__ */
2441 kdebugTrace(kPMLogSystemWake
, 0, ml_get_wake_timebase() >> 32, ml_get_wake_timebase());
2442 // stay awake for at least 30 seconds
2443 wranglerTickled
= true;
2444 fullWakeReason
= kFullWakeReasonLocalUser
;
2445 startIdleSleepTimer(30);
2449 thread_call_enter(updateConsoleUsersEntry
);
2451 changePowerStateToPriv(ON_STATE
);
2453 #if !__i386__ && !__x86_64__
2455 if (previousPowerState
!= ON_STATE
)
2457 DLOG("Force re-evaluating aggressiveness\n");
2458 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2459 pmPowerStateQueue
->submitPowerEvent(
2460 kPowerEventPolicyStimulus
,
2461 (void *) kStimulusNoIdleSleepPreventers
);
2471 //******************************************************************************
2472 // requestPowerDomainState
2474 // Extend implementation in IOService. Running on PM work loop thread.
2475 //******************************************************************************
2477 IOReturn
IOPMrootDomain::requestPowerDomainState (
2478 IOPMPowerFlags childDesire
,
2479 IOPowerConnection
* childConnection
,
2480 unsigned long specification
)
2482 // Idle and system sleep prevention flags affects driver desire.
2483 // Children desire are irrelevant so they are cleared.
2485 return super::requestPowerDomainState(0, childConnection
, specification
);
2489 //******************************************************************************
2490 // updatePreventIdleSleepList
2492 // Called by IOService on PM work loop.
2493 // Returns true if PM policy recognized the driver's desire to prevent idle
2494 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2495 //******************************************************************************
2497 bool IOPMrootDomain::updatePreventIdleSleepList(
2498 IOService
* service
, bool addNotRemove
)
2500 unsigned int oldCount
, newCount
;
2504 #if defined(__i386__) || defined(__x86_64__)
2505 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2506 // idle sleep, except in the case of legacy disk I/O
2507 if ((service
!= wrangler
) && (service
!= this))
2513 oldCount
= preventIdleSleepList
->getCount();
2516 preventIdleSleepList
->setObject(service
);
2517 DLOG("prevent idle sleep list: %s+ (%u)\n",
2518 service
->getName(), preventIdleSleepList
->getCount());
2520 else if (preventIdleSleepList
->member(service
))
2522 preventIdleSleepList
->removeObject(service
);
2523 DLOG("prevent idle sleep list: %s- (%u)\n",
2524 service
->getName(), preventIdleSleepList
->getCount());
2526 newCount
= preventIdleSleepList
->getCount();
2528 if ((oldCount
== 0) && (newCount
!= 0))
2530 // Driver added to empty prevent list.
2531 // Update the driver desire to prevent idle sleep.
2532 // Driver desire does not prevent demand sleep.
2534 changePowerStateTo(ON_STATE
);
2536 else if ((oldCount
!= 0) && (newCount
== 0))
2538 // Last driver removed from prevent list.
2539 // Drop the driver clamp to allow idle sleep.
2541 changePowerStateTo(SLEEP_STATE
);
2542 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2544 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2545 &newCount
, sizeof(newCount
));
2547 #if defined(__i386__) || defined(__x86_64__)
2548 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2550 return false; // do not idle-cancel
2554 MSG("prevent idle sleep list: %s%c (%u)\n",
2556 (addNotRemove
) ? '+' : '-', newCount
);
2560 //******************************************************************************
2561 // preventSystemSleepListUpdate
2563 // Called by IOService on PM work loop.
2564 //******************************************************************************
2566 void IOPMrootDomain::updatePreventSystemSleepList(
2567 IOService
* service
, bool addNotRemove
)
2569 unsigned int oldCount
, newCount
;
2572 if (this == service
)
2575 oldCount
= preventSystemSleepList
->getCount();
2578 preventSystemSleepList
->setObject(service
);
2579 DLOG("prevent system sleep list: %s+ (%u)\n",
2580 service
->getName(), preventSystemSleepList
->getCount());
2581 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2583 clock_usec_t microsecs
;
2584 clock_get_uptime(&now
);
2585 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2586 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2587 if (assertOnWakeReport
) {
2588 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2589 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2593 else if (preventSystemSleepList
->member(service
))
2595 preventSystemSleepList
->removeObject(service
);
2596 DLOG("prevent system sleep list: %s- (%u)\n",
2597 service
->getName(), preventSystemSleepList
->getCount());
2599 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2601 // Lost all system sleep preventers.
2602 // Send stimulus if system sleep was blocked, and is in dark wake.
2603 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2606 newCount
= preventSystemSleepList
->getCount();
2607 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2608 &newCount
, sizeof(newCount
));
2611 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2614 OSCollectionIterator
*iterator
= NULL
;
2615 OSObject
*object
= NULL
;
2616 OSArray
*array
= NULL
;
2618 if (!gIOPMWorkLoop
->inGate())
2620 gIOPMWorkLoop
->runAction(
2621 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2622 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2623 this, (void *)idleSleepList
, (void *)systemSleepList
);
2627 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2629 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2630 array
= OSArray::withCapacity(5);
2632 while ((object
= iterator
->getNextObject()))
2634 IOService
*service
= OSDynamicCast(IOService
, object
);
2637 array
->setObject(OSSymbol::withCString(service
->getName()));
2641 iterator
->release();
2642 *idleSleepList
= array
;
2645 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2647 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2648 array
= OSArray::withCapacity(5);
2650 while ((object
= iterator
->getNextObject()))
2652 IOService
*service
= OSDynamicCast(IOService
, object
);
2655 array
->setObject(OSSymbol::withCString(service
->getName()));
2659 iterator
->release();
2660 *systemSleepList
= array
;
2664 //******************************************************************************
2667 // Override the superclass implementation to send a different message type.
2668 //******************************************************************************
2670 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2672 DLOG("tellChangeDown %u->%u\n",
2673 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2675 if (SLEEP_STATE
== stateNum
)
2677 // Legacy apps were already told in the full->dark transition
2678 if (!ignoreTellChangeDown
)
2679 tracePoint( kIOPMTracePointSleepApplications
);
2681 tracePoint( kIOPMTracePointSleepPriorityClients
);
2684 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2686 userActivityAtSleep
= userActivityCount
;
2687 hibernateAborted
= false;
2688 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2690 // Direct callout into OSKext so it can disable kext unloads
2691 // during sleep/wake to prevent deadlocks.
2692 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2694 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2696 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2697 // But tellClientsWithResponse() must be called for both.
2698 ignoreTellChangeDown
= true;
2701 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2704 //******************************************************************************
2707 // Override the superclass implementation to send a different message type.
2708 // This must be idle sleep since we don't ask during any other power change.
2709 //******************************************************************************
2711 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2713 DLOG("askChangeDown %u->%u\n",
2714 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2716 // Don't log for dark wake entry
2717 if (kSystemTransitionSleep
== _systemTransitionType
)
2718 tracePoint( kIOPMTracePointSleepApplications
);
2720 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2723 //******************************************************************************
2724 // askChangeDownDone
2726 // An opportunity for root domain to cancel the power transition,
2727 // possibily due to an assertion created by powerd in response to
2728 // kIOMessageCanSystemSleep.
2731 // full -> dark wake transition
2732 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2733 // 2. askChangeDownDone()
2734 // dark -> sleep transition
2735 // 1. Notify powerd with kIOMessageCanSystemSleep
2736 // 2. askChangeDownDone()
2739 // full -> dark wake transition
2740 // 1. Notify powerd with kIOMessageCanSystemSleep
2741 // 2. askChangeDownDone()
2742 // dark -> sleep transition
2743 // 1. Notify powerd with kIOMessageCanSystemSleep
2744 // 2. askChangeDownDone()
2745 //******************************************************************************
2747 void IOPMrootDomain::askChangeDownDone(
2748 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2750 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2751 *inOutChangeFlags
, *cancel
,
2752 _systemTransitionType
,
2753 _currentCapability
, _pendingCapability
);
2755 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2757 // Dark->Sleep transition.
2758 // Check if there are any deny sleep assertions.
2759 // lastSleepReason already set by handleOurPowerChangeStart()
2761 if (!checkSystemCanSleep(lastSleepReason
))
2763 // Cancel dark wake to sleep transition.
2764 // Must re-scan assertions upon entering dark wake.
2767 DLOG("cancel dark->sleep\n");
2772 //******************************************************************************
2773 // systemDidNotSleep
2775 // Work common to both canceled or aborted sleep.
2776 //******************************************************************************
2778 void IOPMrootDomain::systemDidNotSleep( void )
2780 // reset console lock state
2781 thread_call_enter(updateConsoleUsersEntry
);
2785 if (idleSleepEnabled
)
2787 // stay awake for at least idleSeconds
2788 startIdleSleepTimer(idleSeconds
);
2793 if (idleSleepEnabled
&& !userIsActive
)
2795 // Manually start the idle sleep timer besides waiting for
2796 // the user to become inactive.
2797 startIdleSleepTimer( kIdleSleepRetryInterval
);
2801 preventTransitionToUserActive(false);
2802 IOService::setAdvisoryTickleEnable( true );
2804 // After idle revert and cancel, send a did-change message to powerd
2805 // to balance the previous will-change message. Kernel clients do not
2806 // need this since sleep cannot be canceled once they are notified.
2808 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2809 (_pendingCapability
!= _currentCapability
) &&
2810 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2812 // Differs from a real capability gain change where notifyRef != 0,
2813 // but it is zero here since no response is expected.
2815 IOPMSystemCapabilityChangeParameters params
;
2817 bzero(¶ms
, sizeof(params
));
2818 params
.fromCapabilities
= _pendingCapability
;
2819 params
.toCapabilities
= _currentCapability
;
2820 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2822 DLOG("MESG cap %x->%x did change\n",
2823 params
.fromCapabilities
, params
.toCapabilities
);
2824 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2825 ¶ms
, sizeof(params
));
2829 //******************************************************************************
2832 // Notify registered applications and kernel clients that we are not dropping
2835 // We override the superclass implementation so we can send a different message
2836 // type to the client or application being notified.
2838 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2839 //******************************************************************************
2841 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2843 DLOG("tellNoChangeDown %u->%u\n",
2844 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2846 // Sleep canceled, clear the sleep trace point.
2847 tracePoint(kIOPMTracePointSystemUp
);
2849 systemDidNotSleep();
2850 return tellClients( kIOMessageSystemWillNotSleep
);
2853 //******************************************************************************
2856 // Notify registered applications and kernel clients that we are raising power.
2858 // We override the superclass implementation so we can send a different message
2859 // type to the client or application being notified.
2860 //******************************************************************************
2862 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2864 DLOG("tellChangeUp %u->%u\n",
2865 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2867 ignoreTellChangeDown
= false;
2869 if ( stateNum
== ON_STATE
)
2871 // Direct callout into OSKext so it can disable kext unloads
2872 // during sleep/wake to prevent deadlocks.
2873 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2875 // Notify platform that sleep was cancelled or resumed.
2876 getPlatform()->callPlatformFunction(
2877 sleepMessagePEFunction
, false,
2878 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2881 if (getPowerState() == ON_STATE
)
2883 // this is a quick wake from aborted sleep
2884 systemDidNotSleep();
2885 tellClients( kIOMessageSystemWillPowerOn
);
2888 tracePoint( kIOPMTracePointWakeApplications
);
2889 tellClients( kIOMessageSystemHasPoweredOn
);
2893 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2894 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2895 ((params)->fromCapabilities & (flag)) && \
2896 (((params)->toCapabilities & (flag)) == 0))
2898 #define CAP_DID_CHANGE_TO_ON(params, flag) \
2899 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2900 ((params)->toCapabilities & (flag)) && \
2901 (((params)->fromCapabilities & (flag)) == 0))
2903 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
2904 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2905 ((params)->fromCapabilities & (flag)) && \
2906 (((params)->toCapabilities & (flag)) == 0))
2908 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
2909 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2910 ((params)->toCapabilities & (flag)) && \
2911 (((params)->fromCapabilities & (flag)) == 0))
2913 //******************************************************************************
2914 // sysPowerDownHandler
2916 // Perform a vfs sync before system sleep.
2917 //******************************************************************************
2919 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2920 void * target
, void * refCon
,
2921 UInt32 messageType
, IOService
* service
,
2922 void * messageArgs
, vm_size_t argSize
)
2926 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2929 return kIOReturnUnsupported
;
2931 if (messageType
== kIOMessageSystemWillSleep
)
2934 IOPowerStateChangeNotification
*notify
=
2935 (IOPowerStateChangeNotification
*)messageArgs
;
2937 notify
->returnValue
= 30 * 1000 * 1000;
2939 gRootDomain
->swdDebugSetupEntry
,
2940 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2943 else if (messageType
== kIOMessageSystemCapabilityChange
)
2945 IOPMSystemCapabilityChangeParameters
* params
=
2946 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2948 // Interested applications have been notified of an impending power
2949 // change and have acked (when applicable).
2950 // This is our chance to save whatever state we can before powering
2952 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2955 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2956 params
->fromCapabilities
, params
->toCapabilities
,
2957 params
->changeFlags
);
2959 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
2961 // We will ack within 20 seconds
2962 params
->maxWaitForReply
= 20 * 1000 * 1000;
2964 // Remove EFI/BootRom's previous wake's failure data
2965 PERemoveNVRAMProperty(kIOEFIBootRomFailureKey
);
2968 gRootDomain
->evaluateSystemSleepPolicyEarly();
2970 // add in time we could spend freeing pages
2971 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2973 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2975 DLOG("sysPowerDownHandler max wait %d s\n",
2976 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2979 // Notify platform that sleep has begun, after the early
2980 // sleep policy evaluation.
2981 getPlatform()->callPlatformFunction(
2982 sleepMessagePEFunction
, false,
2983 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2986 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2988 // Purposely delay the ack and hope that shutdown occurs quickly.
2989 // Another option is not to schedule the thread and wait for
2991 AbsoluteTime deadline
;
2992 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2993 thread_call_enter1_delayed(
2994 gRootDomain
->diskSyncCalloutEntry
,
2995 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3000 gRootDomain
->diskSyncCalloutEntry
,
3001 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3004 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3006 // We will ack within 110 seconds
3007 params
->maxWaitForReply
= 110 * 1000 * 1000;
3010 gRootDomain
->diskSyncCalloutEntry
,
3011 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3013 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3014 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3016 // WillChange for Full wake -> Darkwake
3017 params
->maxWaitForReply
= 30 * 1000 * 1000;
3019 gRootDomain
->swdDebugSetupEntry
,
3020 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3022 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3023 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3025 // DidChange for Full wake -> Darkwake
3026 params
->maxWaitForReply
= 30 * 1000 * 1000;
3028 gRootDomain
->swdDebugTearDownEntry
,
3029 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3033 ret
= kIOReturnSuccess
;
3039 //******************************************************************************
3040 // handleQueueSleepWakeUUID
3042 // Called from IOPMrootDomain when we're initiating a sleep,
3043 // or indirectly from PM configd when PM decides to clear the UUID.
3044 // PM clears the UUID several minutes after successful wake from sleep,
3045 // so that we might associate App spindumps with the immediately previous
3048 // @param obj has a retain on it. We're responsible for releasing that retain.
3049 //******************************************************************************
3051 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3053 OSString
*str
= NULL
;
3055 if (kOSBooleanFalse
== obj
)
3057 handlePublishSleepWakeUUID(NULL
);
3059 else if ((str
= OSDynamicCast(OSString
, obj
)))
3061 // This branch caches the UUID for an upcoming sleep/wake
3062 if (queuedSleepWakeUUIDString
) {
3063 queuedSleepWakeUUIDString
->release();
3064 queuedSleepWakeUUIDString
= NULL
;
3066 queuedSleepWakeUUIDString
= str
;
3067 queuedSleepWakeUUIDString
->retain();
3069 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3078 //******************************************************************************
3079 // handlePublishSleepWakeUUID
3081 // Called from IOPMrootDomain when we're initiating a sleep,
3082 // or indirectly from PM configd when PM decides to clear the UUID.
3083 // PM clears the UUID several minutes after successful wake from sleep,
3084 // so that we might associate App spindumps with the immediately previous
3086 //******************************************************************************
3088 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3093 * Clear the current UUID
3095 if (gSleepWakeUUIDIsSet
)
3097 DLOG("SleepWake UUID cleared\n");
3099 gSleepWakeUUIDIsSet
= false;
3101 removeProperty(kIOPMSleepWakeUUIDKey
);
3102 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3106 * Optionally, publish a new UUID
3108 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3110 OSString
*publishThisUUID
= NULL
;
3112 publishThisUUID
= queuedSleepWakeUUIDString
;
3113 publishThisUUID
->retain();
3115 if (publishThisUUID
)
3117 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3118 publishThisUUID
->release();
3121 gSleepWakeUUIDIsSet
= true;
3122 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3124 queuedSleepWakeUUIDString
->release();
3125 queuedSleepWakeUUIDString
= NULL
;
3129 //******************************************************************************
3130 // initializeBootSessionUUID
3132 // Initialize the boot session uuid at boot up and sets it into registry.
3133 //******************************************************************************
3135 void IOPMrootDomain::initializeBootSessionUUID(void)
3138 uuid_string_t new_uuid_string
;
3140 uuid_generate(new_uuid
);
3141 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3142 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3144 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3147 //******************************************************************************
3148 // changePowerStateTo & changePowerStateToPriv
3150 // Override of these methods for logging purposes.
3151 //******************************************************************************
3153 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3155 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3157 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3158 return kIOReturnUnsupported
;
3160 return super::changePowerStateTo(ordinal
);
3163 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3165 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3167 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3168 return kIOReturnUnsupported
;
3170 return super::changePowerStateToPriv(ordinal
);
3173 //******************************************************************************
3176 //******************************************************************************
3178 bool IOPMrootDomain::activitySinceSleep(void)
3180 return (userActivityCount
!= userActivityAtSleep
);
3183 bool IOPMrootDomain::abortHibernation(void)
3185 bool ret
= activitySinceSleep();
3187 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3189 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3190 hibernateAborted
= true;
3196 hibernate_should_abort(void)
3199 return (gRootDomain
->abortHibernation());
3204 //******************************************************************************
3205 // willNotifyPowerChildren
3207 // Called after all interested drivers have all acknowledged the power change,
3208 // but before any power children is informed. Dispatched though a thread call,
3209 // so it is safe to perform work that might block on a sleeping disk. PM state
3210 // machine (not thread) will block w/o timeout until this function returns.
3211 //******************************************************************************
3213 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3218 if (SLEEP_STATE
== newPowerState
)
3220 if (!tasksSuspended
)
3222 AbsoluteTime deadline
;
3223 tasksSuspended
= TRUE
;
3224 tasks_system_suspend(tasksSuspended
);
3226 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3227 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3231 IOHibernateSystemSleep();
3232 IOHibernateIOKitSleep();
3234 if (gRootDomain
->activitySinceSleep()) {
3235 dict
= OSDictionary::withCapacity(1);
3236 secs
= OSNumber::withNumber(1, 32);
3239 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3240 gRootDomain
->setProperties(dict
);
3241 MSG("Reverting sleep with relative wake\n");
3243 if (dict
) dict
->release();
3244 if (secs
) secs
->release();
3250 //******************************************************************************
3251 // sleepOnClamshellClosed
3253 // contains the logic to determine if the system should sleep when the clamshell
3255 //******************************************************************************
3257 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3259 if (!clamshellExists
)
3262 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3263 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3265 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3268 void IOPMrootDomain::sendClientClamshellNotification( void )
3270 /* Only broadcast clamshell alert if clamshell exists. */
3271 if (!clamshellExists
)
3274 setProperty(kAppleClamshellStateKey
,
3275 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3277 setProperty(kAppleClamshellCausesSleepKey
,
3278 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3280 /* Argument to message is a bitfiel of
3281 * ( kClamshellStateBit | kClamshellSleepBit )
3283 messageClients(kIOPMMessageClamshellStateChange
,
3284 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3285 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3288 //******************************************************************************
3289 // getSleepSupported
3292 //******************************************************************************
3294 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3296 return( platformSleepSupport
);
3299 //******************************************************************************
3300 // setSleepSupported
3303 //******************************************************************************
3305 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3307 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3308 OSBitOrAtomic(flags
, &platformSleepSupport
);
3311 //******************************************************************************
3312 // setDisableClamShellSleep
3314 //******************************************************************************
3316 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3318 if (gIOPMWorkLoop
->inGate() == false) {
3320 gIOPMWorkLoop
->runAction(
3321 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3328 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3329 if ( clamshellSleepDisabled
!= val
)
3331 clamshellSleepDisabled
= val
;
3332 // If clamshellSleepDisabled is reset to 0, reevaluate if
3333 // system need to go to sleep due to clamshell state
3334 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3335 handlePowerNotification(kLocalEvalClamshellCommand
);
3340 //******************************************************************************
3344 //******************************************************************************
3346 void IOPMrootDomain::wakeFromDoze( void )
3348 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3354 //******************************************************************************
3357 // Adds a new feature to the supported features dictionary
3358 //******************************************************************************
3360 void IOPMrootDomain::publishFeature( const char * feature
)
3362 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3365 //******************************************************************************
3366 // publishFeature (with supported power source specified)
3368 // Adds a new feature to the supported features dictionary
3369 //******************************************************************************
3371 void IOPMrootDomain::publishFeature(
3372 const char *feature
,
3373 uint32_t supportedWhere
,
3374 uint32_t *uniqueFeatureID
)
3376 static uint16_t next_feature_id
= 500;
3378 OSNumber
*new_feature_data
= NULL
;
3379 OSNumber
*existing_feature
= NULL
;
3380 OSArray
*existing_feature_arr
= NULL
;
3381 OSObject
*osObj
= NULL
;
3382 uint32_t feature_value
= 0;
3384 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3386 if(!supportedWhere
) {
3387 // Feature isn't supported anywhere!
3391 if(next_feature_id
> 5000) {
3392 // Far, far too many features!
3396 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3398 OSDictionary
*features
=
3399 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3401 // Create new features dict if necessary
3402 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3403 features
= OSDictionary::withDictionary(features
);
3405 features
= OSDictionary::withCapacity(1);
3408 // Create OSNumber to track new feature
3410 next_feature_id
+= 1;
3411 if( uniqueFeatureID
) {
3412 // We don't really mind if the calling kext didn't give us a place
3413 // to stash their unique id. Many kexts don't plan to unload, and thus
3414 // have no need to remove themselves later.
3415 *uniqueFeatureID
= next_feature_id
;
3418 feature_value
= (uint32_t)next_feature_id
;
3419 feature_value
<<= 16;
3420 feature_value
+= supportedWhere
;
3422 new_feature_data
= OSNumber::withNumber(
3423 (unsigned long long)feature_value
, 32);
3425 // Does features object already exist?
3426 if( (osObj
= features
->getObject(feature
)) )
3428 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3430 // We need to create an OSArray to hold the now 2 elements.
3431 existing_feature_arr
= OSArray::withObjects(
3432 (const OSObject
**)&existing_feature
, 1, 2);
3433 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3435 // Add object to existing array
3436 existing_feature_arr
= OSArray::withArray(
3437 existing_feature_arr
,
3438 existing_feature_arr
->getCount() + 1);
3441 if (existing_feature_arr
)
3443 existing_feature_arr
->setObject(new_feature_data
);
3444 features
->setObject(feature
, existing_feature_arr
);
3445 existing_feature_arr
->release();
3446 existing_feature_arr
= 0;
3449 // The easy case: no previously existing features listed. We simply
3450 // set the OSNumber at key 'feature' and we're on our way.
3451 features
->setObject(feature
, new_feature_data
);
3454 new_feature_data
->release();
3456 setProperty(kRootDomainSupportedFeatures
, features
);
3458 features
->release();
3460 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3462 // Notify EnergySaver and all those in user space so they might
3463 // re-populate their feature specific UI
3464 if(pmPowerStateQueue
) {
3465 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3469 //******************************************************************************
3470 // removePublishedFeature
3472 // Removes previously published feature
3473 //******************************************************************************
3475 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3477 IOReturn ret
= kIOReturnError
;
3478 uint32_t feature_value
= 0;
3479 uint16_t feature_id
= 0;
3480 bool madeAChange
= false;
3482 OSSymbol
*dictKey
= NULL
;
3483 OSCollectionIterator
*dictIterator
= NULL
;
3484 OSArray
*arrayMember
= NULL
;
3485 OSNumber
*numberMember
= NULL
;
3486 OSObject
*osObj
= NULL
;
3487 OSNumber
*osNum
= NULL
;
3488 OSArray
*arrayMemberCopy
;
3490 if (kBadPMFeatureID
== removeFeatureID
)
3491 return kIOReturnNotFound
;
3493 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3495 OSDictionary
*features
=
3496 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3498 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3500 // Any modifications to the dictionary are made to the copy to prevent
3501 // races & crashes with userland clients. Dictionary updated
3502 // automically later.
3503 features
= OSDictionary::withDictionary(features
);
3506 ret
= kIOReturnNotFound
;
3510 // We iterate 'features' dictionary looking for an entry tagged
3511 // with 'removeFeatureID'. If found, we remove it from our tracking
3512 // structures and notify the OS via a general interest message.
3514 dictIterator
= OSCollectionIterator::withCollection(features
);
3519 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3521 osObj
= features
->getObject(dictKey
);
3523 // Each Feature is either tracked by an OSNumber
3524 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3526 feature_value
= numberMember
->unsigned32BitValue();
3527 feature_id
= (uint16_t)(feature_value
>> 16);
3529 if( feature_id
== (uint16_t)removeFeatureID
)
3532 features
->removeObject(dictKey
);
3537 // Or tracked by an OSArray of OSNumbers
3538 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3540 unsigned int arrayCount
= arrayMember
->getCount();
3542 for(unsigned int i
=0; i
<arrayCount
; i
++)
3544 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3549 feature_value
= osNum
->unsigned32BitValue();
3550 feature_id
= (uint16_t)(feature_value
>> 16);
3552 if( feature_id
== (uint16_t)removeFeatureID
)
3555 if( 1 == arrayCount
) {
3556 // If the array only contains one element, remove
3558 features
->removeObject(dictKey
);
3560 // Otherwise remove the element from a copy of the array.
3561 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3562 if (arrayMemberCopy
)
3564 arrayMemberCopy
->removeObject(i
);
3565 features
->setObject(dictKey
, arrayMemberCopy
);
3566 arrayMemberCopy
->release();
3577 dictIterator
->release();
3581 ret
= kIOReturnSuccess
;
3583 setProperty(kRootDomainSupportedFeatures
, features
);
3585 // Notify EnergySaver and all those in user space so they might
3586 // re-populate their feature specific UI
3587 if(pmPowerStateQueue
) {
3588 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3591 ret
= kIOReturnNotFound
;
3595 if(features
) features
->release();
3596 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3600 //******************************************************************************
3601 // publishPMSetting (private)
3603 // Should only be called by PMSettingObject to publish a PM Setting as a
3604 // supported feature.
3605 //******************************************************************************
3607 void IOPMrootDomain::publishPMSetting(
3608 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3610 if (noPublishPMSettings
&&
3611 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3613 // Setting found in noPublishPMSettings array
3614 *featureID
= kBadPMFeatureID
;
3619 feature
->getCStringNoCopy(), where
, featureID
);
3622 //******************************************************************************
3623 // setPMSetting (private)
3625 // Internal helper to relay PM settings changes from user space to individual
3626 // drivers. Should be called only by IOPMrootDomain::setProperties.
3627 //******************************************************************************
3629 IOReturn
IOPMrootDomain::setPMSetting(
3630 const OSSymbol
*type
,
3633 PMSettingCallEntry
*entries
= 0;
3634 OSArray
*chosen
= 0;
3635 const OSArray
*array
;
3636 PMSettingObject
*pmso
;
3637 thread_t thisThread
;
3638 int i
, j
, count
, capacity
;
3641 return kIOReturnBadArgument
;
3645 // Update settings dict so changes are visible from copyPMSetting().
3646 fPMSettingsDict
->setObject(type
, object
);
3648 // Prep all PMSetting objects with the given 'type' for callout.
3649 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3650 if (!array
|| ((capacity
= array
->getCount()) == 0))
3653 // Array to retain PMSetting objects targeted for callout.
3654 chosen
= OSArray::withCapacity(capacity
);
3656 goto unlock_exit
; // error
3658 entries
= IONew(PMSettingCallEntry
, capacity
);
3660 goto unlock_exit
; // error
3661 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3663 thisThread
= current_thread();
3665 for (i
= 0, j
= 0; i
<capacity
; i
++)
3667 pmso
= (PMSettingObject
*) array
->getObject(i
);
3670 entries
[j
].thread
= thisThread
;
3671 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3672 chosen
->setObject(pmso
);
3681 // Call each pmso in the chosen array.
3682 for (i
=0; i
<count
; i
++)
3684 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3685 pmso
->dispatchPMSetting(type
, object
);
3689 for (i
=0; i
<count
; i
++)
3691 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3692 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3693 if (pmso
->waitThread
)
3695 PMSETTING_WAKEUP(pmso
);
3701 if (chosen
) chosen
->release();
3702 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3704 return kIOReturnSuccess
;
3707 //******************************************************************************
3708 // copyPMSetting (public)
3710 // Allows kexts to safely read setting values, without being subscribed to
3712 //******************************************************************************
3714 OSObject
* IOPMrootDomain::copyPMSetting(
3715 OSSymbol
*whichSetting
)
3717 OSObject
*obj
= NULL
;
3719 if(!whichSetting
) return NULL
;
3722 obj
= fPMSettingsDict
->getObject(whichSetting
);
3731 //******************************************************************************
3732 // registerPMSettingController (public)
3734 // direct wrapper to registerPMSettingController with uint32_t power source arg
3735 //******************************************************************************
3737 IOReturn
IOPMrootDomain::registerPMSettingController(
3738 const OSSymbol
* settings
[],
3739 IOPMSettingControllerCallback func
,
3744 return registerPMSettingController(
3746 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3747 func
, target
, refcon
, handle
);
3750 //******************************************************************************
3751 // registerPMSettingController (public)
3753 // Kexts may register for notifications when a particular setting is changed.
3754 // A list of settings is available in IOPM.h.
3756 // * settings - An OSArray containing OSSymbols. Caller should populate this
3757 // array with a list of settings caller wants notifications from.
3758 // * func - A C function callback of the type IOPMSettingControllerCallback
3759 // * target - caller may provide an OSObject *, which PM will pass as an
3760 // target to calls to "func"
3761 // * refcon - caller may provide an void *, which PM will pass as an
3762 // argument to calls to "func"
3763 // * handle - This is a return argument. We will populate this pointer upon
3764 // call success. Hold onto this and pass this argument to
3765 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3767 // kIOReturnSuccess on success
3768 //******************************************************************************
3770 IOReturn
IOPMrootDomain::registerPMSettingController(
3771 const OSSymbol
* settings
[],
3772 uint32_t supportedPowerSources
,
3773 IOPMSettingControllerCallback func
,
3778 PMSettingObject
*pmso
= NULL
;
3779 OSObject
*pmsh
= NULL
;
3780 OSArray
*list
= NULL
;
3783 if (NULL
== settings
||
3787 return kIOReturnBadArgument
;
3790 pmso
= PMSettingObject::pmSettingObject(
3791 (IOPMrootDomain
*) this, func
, target
,
3792 refcon
, supportedPowerSources
, settings
, &pmsh
);
3796 return kIOReturnInternalError
;
3800 for (i
=0; settings
[i
]; i
++)
3802 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3804 // New array of callbacks for this setting
3805 list
= OSArray::withCapacity(1);
3806 settingsCallbacks
->setObject(settings
[i
], list
);
3810 // Add caller to the callback list
3811 list
->setObject(pmso
);
3815 // Return handle to the caller, the setting object is private.
3818 return kIOReturnSuccess
;
3821 //******************************************************************************
3822 // deregisterPMSettingObject (private)
3824 // Only called from PMSettingObject.
3825 //******************************************************************************
3827 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3829 thread_t thisThread
= current_thread();
3830 PMSettingCallEntry
*callEntry
;
3831 OSCollectionIterator
*iter
;
3839 pmso
->disabled
= true;
3841 // Wait for all callout threads to finish.
3844 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3846 if (callEntry
->thread
!= thisThread
)
3854 assert(0 == pmso
->waitThread
);
3855 pmso
->waitThread
= thisThread
;
3856 PMSETTING_WAIT(pmso
);
3857 pmso
->waitThread
= 0;
3861 // Search each PM settings array in the kernel.
3862 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3865 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3867 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3868 index
= array
->getNextIndexOfObject(pmso
, 0);
3870 array
->removeObject(index
);
3881 //******************************************************************************
3882 // informCPUStateChange
3884 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3885 // running on battery, with the lid closed, etc.
3887 // informCPUStateChange is a no-op on non x86 systems
3888 // only x86 has explicit support in the IntelCPUPowerManagement kext
3889 //******************************************************************************
3891 void IOPMrootDomain::informCPUStateChange(
3895 #if defined(__i386__) || defined(__x86_64__)
3897 pmioctlVariableInfo_t varInfoStruct
;
3899 const char *varNameStr
= NULL
;
3900 int32_t *varIndex
= NULL
;
3902 if (kInformAC
== type
) {
3903 varNameStr
= kIOPMRootDomainBatPowerCString
;
3904 varIndex
= &idxPMCPULimitedPower
;
3905 } else if (kInformLid
== type
) {
3906 varNameStr
= kIOPMRootDomainLidCloseCString
;
3907 varIndex
= &idxPMCPUClamshell
;
3912 // Set the new value!
3913 // pmCPUControl will assign us a new ID if one doesn't exist yet
3914 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3915 varInfoStruct
.varID
= *varIndex
;
3916 varInfoStruct
.varType
= vBool
;
3917 varInfoStruct
.varInitValue
= value
;
3918 varInfoStruct
.varCurValue
= value
;
3919 strlcpy( (char *)varInfoStruct
.varName
,
3920 (const char *)varNameStr
,
3921 sizeof(varInfoStruct
.varName
));
3924 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3926 // pmCPU only assigns numerical id's when a new varName is specified
3928 && (*varIndex
== kCPUUnknownIndex
))
3930 // pmCPUControl has assigned us a new variable ID.
3931 // Let's re-read the structure we just SET to learn that ID.
3932 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3936 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3937 *varIndex
= varInfoStruct
.varID
;
3943 #endif /* __i386__ || __x86_64__ */
3947 // MARK: Deep Sleep Policy
3951 //******************************************************************************
3952 // evaluateSystemSleepPolicy
3953 //******************************************************************************
3955 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3959 kIOPMSleepFlagHibernate
= 0x00000001,
3960 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3963 struct IOPMSystemSleepPolicyEntry
3965 uint32_t factorMask
;
3966 uint32_t factorBits
;
3967 uint32_t sleepFlags
;
3968 uint32_t wakeEvents
;
3969 } __attribute__((packed
));
3971 struct IOPMSystemSleepPolicyTable
3975 uint16_t entryCount
;
3976 IOPMSystemSleepPolicyEntry entries
[];
3977 } __attribute__((packed
));
3980 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3981 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3985 getSleepTypeAttributes( uint32_t sleepType
)
3987 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3992 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3993 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3994 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3995 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3999 if (sleepType
>= kIOPMSleepTypeLast
)
4002 return sleepTypeAttributes
[sleepType
];
4005 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4006 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4008 const IOPMSystemSleepPolicyTable
* pt
;
4009 OSObject
* prop
= 0;
4010 OSData
* policyData
;
4011 uint64_t currentFactors
= 0;
4012 uint32_t standbyDelay
= 0;
4013 uint32_t powerOffDelay
= 0;
4014 uint32_t powerOffTimer
= 0;
4016 bool standbyEnabled
;
4017 bool powerOffEnabled
;
4020 // Get platform's sleep policy table
4021 if (!gSleepPolicyHandler
)
4023 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4024 if (!prop
) goto done
;
4027 // Fetch additional settings
4028 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4029 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4030 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4031 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4032 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4033 powerOffTimer
= powerOffDelay
;
4035 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4036 sleepPhase
, standbyEnabled
, standbyDelay
,
4037 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4039 // pmset level overrides
4040 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4042 if (!gSleepPolicyHandler
)
4044 standbyEnabled
= false;
4045 powerOffEnabled
= false;
4048 else if (!(*hibMode
& kIOHibernateModeSleep
))
4050 // Force hibernate (i.e. mode 25)
4051 // If standby is enabled, force standy.
4052 // If poweroff is enabled, force poweroff.
4054 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4055 else if (powerOffEnabled
)
4056 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4058 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4061 // Current factors based on environment and assertions
4062 if (sleepTimerMaintenance
)
4063 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4064 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4065 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4066 if (!clamshellClosed
)
4067 currentFactors
|= kIOPMSleepFactorLidOpen
;
4068 if (acAdaptorConnected
)
4069 currentFactors
|= kIOPMSleepFactorACPower
;
4070 if (lowBatteryCondition
)
4071 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4073 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4074 if (standbyNixed
|| !standbyEnabled
)
4075 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4078 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4079 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4081 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4082 kIOPMDriverAssertionLevelOff
)
4083 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4084 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4085 kIOPMDriverAssertionLevelOff
)
4086 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4087 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4088 kIOPMDriverAssertionLevelOff
)
4089 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4090 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4091 kIOPMDriverAssertionLevelOff
)
4092 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4093 if (_scheduledAlarms
!= 0)
4094 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4095 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4096 kIOPMDriverAssertionLevelOff
)
4097 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4098 #define TCPKEEPALIVE 1
4100 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4101 kIOPMDriverAssertionLevelOff
)
4102 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4104 if (!powerOffEnabled
)
4105 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4107 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4109 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4110 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4111 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4112 if (thermalWarningState
)
4113 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4115 DLOG("sleep factors 0x%llx\n", currentFactors
);
4117 if (gSleepPolicyHandler
)
4119 uint32_t savedHibernateMode
;
4122 if (!gSleepPolicyVars
)
4124 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4125 if (!gSleepPolicyVars
)
4127 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4129 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4130 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4131 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4132 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4133 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4134 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4135 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4136 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4137 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4138 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4139 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4141 if (kIOPMSleepPhase0
== sleepPhase
)
4143 // preserve hibernateMode
4144 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4145 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4147 else if (kIOPMSleepPhase1
== sleepPhase
)
4149 // use original hibernateMode for phase2
4150 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4153 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4155 if (kIOPMSleepPhase0
== sleepPhase
)
4157 // restore hibernateMode
4158 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4161 if ((result
!= kIOReturnSuccess
) ||
4162 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4163 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4164 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4166 MSG("sleep policy handler error\n");
4170 if ((getSleepTypeAttributes(params
->sleepType
) &
4171 kIOPMSleepAttributeHibernateSetup
) &&
4172 ((*hibMode
& kIOHibernateModeOn
) == 0))
4174 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4177 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4178 params
->version
, params
->sleepType
, params
->sleepFlags
,
4179 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4184 // Policy table is meaningless without standby enabled
4185 if (!standbyEnabled
)
4188 // Validate the sleep policy table
4189 policyData
= OSDynamicCast(OSData
, prop
);
4190 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4193 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4194 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4195 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4198 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4199 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4202 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4204 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4205 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4207 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4208 entry
->factorMask
, entry
->factorBits
,
4209 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4213 DLOG("^ found match\n");
4216 params
->version
= kIOPMSystemSleepParametersVersion
;
4217 params
->reserved1
= 1;
4218 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4219 params
->sleepType
= kIOPMSleepTypeStandby
;
4221 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4223 params
->ecWakeEvents
= entry
->wakeEvents
;
4224 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4226 if (kIOPMSleepPhase2
== sleepPhase
)
4228 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4230 if (!_standbyTimerResetSeconds
||
4231 (now_secs
<= _standbyTimerResetSeconds
))
4233 // Reset standby timer adjustment
4234 _standbyTimerResetSeconds
= now_secs
;
4235 DLOG("standby delay %u, reset %u\n",
4236 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4238 else if (standbyDelay
)
4240 // Shorten the standby delay timer
4241 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4242 if (standbyDelay
> elapsed
)
4243 standbyDelay
-= elapsed
;
4245 standbyDelay
= 1; // must be > 0
4247 DLOG("standby delay %u, elapsed %u\n",
4248 standbyDelay
, (uint32_t) elapsed
);
4251 params
->ecWakeTimer
= standbyDelay
;
4253 else if (kIOPMSleepPhase2
== sleepPhase
)
4255 // A sleep that does not enable the sleep timer will reset
4256 // the standby delay adjustment.
4257 _standbyTimerResetSeconds
= 0;
4269 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4271 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4273 // Evaluate early (priority interest phase), before drivers sleep.
4275 DLOG("%s\n", __FUNCTION__
);
4276 removeProperty(kIOPMSystemSleepParametersKey
);
4278 // Full wake resets the standby timer delay adjustment
4279 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4280 _standbyTimerResetSeconds
= 0;
4282 hibernateDisabled
= false;
4284 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4286 // Save for late evaluation if sleep is aborted
4287 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4289 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4292 if (!hibernateRetry
&&
4293 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4294 kIOPMSleepAttributeHibernateSetup
) == 0))
4296 // skip hibernate setup
4297 hibernateDisabled
= true;
4301 // Publish IOPMSystemSleepType
4302 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4303 if (sleepType
== kIOPMSleepTypeInvalid
)
4306 sleepType
= kIOPMSleepTypeNormalSleep
;
4307 if (hibernateMode
& kIOHibernateModeOn
)
4308 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4309 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4311 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4312 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4314 // report the lowest possible sleep state
4315 sleepType
= kIOPMSleepTypePowerOff
;
4318 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4321 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4323 IOPMSystemSleepParameters params
;
4324 OSData
* paramsData
;
4326 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4328 DLOG("%s\n", __FUNCTION__
);
4330 bzero(¶ms
, sizeof(params
));
4332 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4334 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4335 && gIOHibernateStandbyDisabled
4336 && (!(kIOPMSleepFactorStandbyForced
& gSleepPolicyVars
->sleepFactors
)))
4338 standbyNixed
= true;
4342 || ((hibernateDisabled
|| hibernateAborted
) &&
4343 (getSleepTypeAttributes(params
.sleepType
) &
4344 kIOPMSleepAttributeHibernateSetup
)))
4346 // Final evaluation picked a state requiring hibernation,
4347 // but hibernate isn't going to proceed. Arm a short sleep using
4348 // the early non-hibernate sleep parameters.
4349 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4350 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4351 params
.ecWakeTimer
= 1;
4358 // Set hibernateRetry flag to force hibernate setup on the
4360 hibernateRetry
= true;
4362 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4363 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4367 hibernateRetry
= false;
4370 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4372 resetTimers
= false;
4375 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4378 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4379 paramsData
->release();
4382 if (getSleepTypeAttributes(params
.sleepType
) &
4383 kIOPMSleepAttributeHibernateSleep
)
4385 // Disable sleep to force hibernation
4386 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4391 bool IOPMrootDomain::getHibernateSettings(
4392 uint32_t * hibernateModePtr
,
4393 uint32_t * hibernateFreeRatio
,
4394 uint32_t * hibernateFreeTime
)
4396 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4397 // has updated the hibernateDisabled flag.
4399 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4400 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4401 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4402 if (hibernateDisabled
)
4403 *hibernateModePtr
= 0;
4404 else if (gSleepPolicyHandler
)
4405 *hibernateModePtr
= hibernateMode
;
4406 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4410 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4412 OSObject
* optionsProp
;
4413 OSDictionary
* optionsDict
;
4418 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4419 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4423 obj
= optionsDict
->getObject(key
);
4424 if (obj
) obj
->retain();
4428 obj
= copyProperty(key
);
4432 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4434 *option
= num
->unsigned32BitValue();
4437 else if (OSDynamicCast(OSBoolean
, obj
))
4439 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4447 optionsProp
->release();
4451 #endif /* HIBERNATION */
4453 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4456 IOPMSystemSleepParameters params
;
4457 uint32_t hibMode
= 0;
4460 if (gIOPMWorkLoop
->inGate() == false)
4462 IOReturn ret
= gIOPMWorkLoop
->runAction(
4463 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4464 &IOPMrootDomain::getSystemSleepType
),
4466 (void *) sleepType
);
4470 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4471 bzero(¶ms
, sizeof(params
));
4473 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4476 *sleepType
= params
.sleepType
;
4477 return kIOReturnSuccess
;
4481 return kIOReturnUnsupported
;
4485 // MARK: Shutdown and Restart
4487 //******************************************************************************
4488 // handlePlatformHaltRestart
4490 //******************************************************************************
4492 struct HaltRestartApplierContext
{
4493 IOPMrootDomain
* RootDomain
;
4494 unsigned long PowerState
;
4495 IOPMPowerFlags PowerFlags
;
4498 const char * LogString
;
4502 platformHaltRestartApplier( OSObject
* object
, void * context
)
4504 IOPowerStateChangeNotification notify
;
4505 HaltRestartApplierContext
* ctx
;
4506 AbsoluteTime startTime
;
4509 ctx
= (HaltRestartApplierContext
*) context
;
4511 memset(¬ify
, 0, sizeof(notify
));
4512 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4513 notify
.returnValue
= 0;
4514 notify
.stateNumber
= ctx
->PowerState
;
4515 notify
.stateFlags
= ctx
->PowerFlags
;
4517 clock_get_uptime(&startTime
);
4518 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4519 deltaTime
= computeDeltaTimeMS(&startTime
);
4521 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4522 (gIOKitDebug
& kIOLogPMRootDomain
))
4524 _IOServiceInterestNotifier
* notifier
;
4525 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4527 // IOService children of IOPMrootDomain are not instrumented.
4528 // Only IORootParent currently falls under that group.
4532 LOG("%s handler %p took %u ms\n",
4533 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4540 static void quiescePowerTreeCallback( void * target
, void * param
)
4542 IOLockLock(gPMHaltLock
);
4544 thread_wakeup(param
);
4545 IOLockUnlock(gPMHaltLock
);
4548 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4550 HaltRestartApplierContext ctx
;
4551 AbsoluteTime startTime
;
4554 memset(&ctx
, 0, sizeof(ctx
));
4555 ctx
.RootDomain
= this;
4557 clock_get_uptime(&startTime
);
4561 case kPEUPSDelayHaltCPU
:
4562 ctx
.PowerState
= OFF_STATE
;
4563 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4564 ctx
.LogString
= "PowerOff";
4568 ctx
.PowerState
= RESTART_STATE
;
4569 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4570 ctx
.LogString
= "Restart";
4574 ctx
.PowerState
= ON_STATE
;
4575 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4576 ctx
.LogString
= "PagingOff";
4577 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4579 IOHibernateSystemRestart();
4587 // Notify legacy clients
4588 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4590 // For normal shutdown, turn off File Server Mode.
4591 if (kPEHaltCPU
== pe_type
)
4593 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4594 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4597 setPMSetting(setting
, num
);
4603 if (kPEPagingOff
!= pe_type
)
4605 // Notify in power tree order
4606 notifySystemShutdown(this, ctx
.MessageType
);
4609 IOCPURunPlatformHaltRestartActions(pe_type
);
4611 // Wait for PM to quiesce
4612 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4614 AbsoluteTime quiesceTime
= mach_absolute_time();
4616 IOLockLock(gPMHaltLock
);
4617 gPMQuiesced
= false;
4618 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4621 while (!gPMQuiesced
)
4623 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4626 IOLockUnlock(gPMHaltLock
);
4628 deltaTime
= computeDeltaTimeMS(&quiesceTime
);
4629 DLOG("PM quiesce took %u ms\n", deltaTime
);
4632 deltaTime
= computeDeltaTimeMS(&startTime
);
4633 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4636 //******************************************************************************
4639 //******************************************************************************
4641 IOReturn
IOPMrootDomain::shutdownSystem( void )
4643 return kIOReturnUnsupported
;
4646 //******************************************************************************
4649 //******************************************************************************
4651 IOReturn
IOPMrootDomain::restartSystem( void )
4653 return kIOReturnUnsupported
;
4657 // MARK: System Capability
4659 //******************************************************************************
4660 // tagPowerPlaneService
4662 // Running on PM work loop thread.
4663 //******************************************************************************
4665 void IOPMrootDomain::tagPowerPlaneService(
4666 IOService
* service
,
4667 IOPMActions
* actions
)
4670 bool isDisplayWrangler
;
4672 memset(actions
, 0, sizeof(*actions
));
4673 actions
->target
= this;
4675 if (service
== this)
4677 actions
->actionPowerChangeStart
=
4678 OSMemberFunctionCast(
4679 IOPMActionPowerChangeStart
, this,
4680 &IOPMrootDomain::handleOurPowerChangeStart
);
4682 actions
->actionPowerChangeDone
=
4683 OSMemberFunctionCast(
4684 IOPMActionPowerChangeDone
, this,
4685 &IOPMrootDomain::handleOurPowerChangeDone
);
4687 actions
->actionPowerChangeOverride
=
4688 OSMemberFunctionCast(
4689 IOPMActionPowerChangeOverride
, this,
4690 &IOPMrootDomain::overrideOurPowerChange
);
4695 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4696 if (isDisplayWrangler
)
4701 isDisplayWrangler
= false;
4704 #if defined(__i386__) || defined(__x86_64__)
4705 if (isDisplayWrangler
)
4706 flags
|= kPMActionsFlagIsDisplayWrangler
;
4707 if (service
->getProperty("IOPMStrictTreeOrder"))
4708 flags
|= kPMActionsFlagIsGraphicsDevice
;
4709 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4710 flags
|= kPMActionsFlagIsAudioDevice
;
4713 // Find the power connection object that is a child of the PCI host
4714 // bridge, and has a graphics/audio device attached below. Mark the
4715 // power branch for delayed child notifications.
4719 IORegistryEntry
* child
= service
;
4720 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4722 while (child
!= this)
4724 if ((parent
== pciHostBridgeDriver
) ||
4727 if (OSDynamicCast(IOPowerConnection
, child
))
4729 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4730 conn
->delayChildNotification
= true;
4735 parent
= child
->getParentEntry(gIOPowerPlane
);
4741 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4742 actions
->parameter
|= flags
;
4743 actions
->actionPowerChangeOverride
=
4744 OSMemberFunctionCast(
4745 IOPMActionPowerChangeOverride
, this,
4746 &IOPMrootDomain::overridePowerChangeForUIService
);
4748 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4750 actions
->actionActivityTickle
=
4751 OSMemberFunctionCast(
4752 IOPMActionActivityTickle
, this,
4753 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4755 actions
->actionUpdatePowerClient
=
4756 OSMemberFunctionCast(
4757 IOPMActionUpdatePowerClient
, this,
4758 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4763 // Locate the first PCI host bridge for PMTrace.
4764 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4766 IOService
* provider
= service
->getProvider();
4767 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4768 provider
->inPlane(gIODTPlane
))
4770 pciHostBridgeDevice
= provider
;
4771 pciHostBridgeDriver
= service
;
4772 DLOG("PMTrace found PCI host bridge %s->%s\n",
4773 provider
->getName(), service
->getName());
4777 // Tag top-level PCI devices. The order of PMinit() call does not
4778 // change across boots and is used as the PCI bit number.
4779 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4781 // Would prefer to check built-in property, but tagPowerPlaneService()
4782 // is called before pciDevice->registerService().
4783 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4784 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4786 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4789 // Save the assigned bit for fast lookup.
4790 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4792 actions
->actionPowerChangeStart
=
4793 OSMemberFunctionCast(
4794 IOPMActionPowerChangeStart
, this,
4795 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4797 actions
->actionPowerChangeDone
=
4798 OSMemberFunctionCast(
4799 IOPMActionPowerChangeDone
, this,
4800 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4806 //******************************************************************************
4807 // PM actions for root domain
4808 //******************************************************************************
4810 void IOPMrootDomain::overrideOurPowerChange(
4811 IOService
* service
,
4812 IOPMActions
* actions
,
4813 IOPMPowerStateIndex
* inOutPowerState
,
4814 IOPMPowerChangeFlags
* inOutChangeFlags
,
4815 IOPMRequestTag requestTag
)
4817 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4818 uint32_t changeFlags
= *inOutChangeFlags
;
4819 uint32_t currentPowerState
= (uint32_t) getPowerState();
4821 if (changeFlags
& kIOPMParentInitiated
)
4823 // Root parent is permanently pegged at max power,
4824 // a parent initiated power change is unexpected.
4825 *inOutChangeFlags
|= kIOPMNotDone
;
4829 if (powerState
< currentPowerState
)
4831 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4833 // Root domain is dropping power state ON->SLEEP.
4834 // If system is in full wake, first enter dark wake by
4835 // converting the power drop to a capability change.
4836 // Once in dark wake, transition to sleep state ASAP.
4838 darkWakeToSleepASAP
= true;
4840 // Drop graphics and audio capability
4841 _desiredCapability
&= ~(
4842 kIOPMSystemCapabilityGraphics
|
4843 kIOPMSystemCapabilityAudio
);
4845 // Convert to capability change (ON->ON)
4846 *inOutPowerState
= ON_STATE
;
4847 *inOutChangeFlags
|= kIOPMSynchronize
;
4849 // Revert device desire from SLEEP to ON
4850 changePowerStateToPriv(ON_STATE
);
4854 // System is in dark wake, ok to drop power state.
4855 // Broadcast root powering down to entire tree.
4856 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4859 else if (powerState
> currentPowerState
)
4861 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4863 // Broadcast power up when waking from sleep, but not for the
4864 // initial power change at boot by checking for cpu capability.
4865 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4870 void IOPMrootDomain::handleOurPowerChangeStart(
4871 IOService
* service
,
4872 IOPMActions
* actions
,
4873 IOPMPowerStateIndex powerState
,
4874 IOPMPowerChangeFlags
* inOutChangeFlags
,
4875 IOPMRequestTag requestTag
)
4877 uint32_t changeFlags
= *inOutChangeFlags
;
4878 uint32_t currentPowerState
= (uint32_t) getPowerState();
4879 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4880 bool publishSleepReason
= false;
4882 _systemTransitionType
= kSystemTransitionNone
;
4883 _systemMessageClientMask
= 0;
4884 capabilityLoss
= false;
4885 toldPowerdCapWillChange
= false;
4887 if (lowBatteryCondition
)
4889 // Low battery notification may arrive after the initial sleep request
4890 // has been queued. Override the sleep reason so powerd and others can
4891 // treat this as an emergency sleep.
4892 sleepReason
= kIOPMSleepReasonLowPower
;
4895 // 1. Explicit capability change.
4897 if (changeFlags
& kIOPMSynchronize
)
4899 if (powerState
== ON_STATE
)
4901 if (changeFlags
& kIOPMSyncNoChildNotify
)
4902 _systemTransitionType
= kSystemTransitionNewCapClient
;
4904 _systemTransitionType
= kSystemTransitionCapability
;
4908 // 2. Going to sleep (cancellation still possible).
4910 else if (powerState
< currentPowerState
)
4911 _systemTransitionType
= kSystemTransitionSleep
;
4913 // 3. Woke from (idle or demand) sleep.
4915 else if (!systemBooting
&&
4916 (changeFlags
& kIOPMSelfInitiated
) &&
4917 (powerState
> currentPowerState
))
4919 _systemTransitionType
= kSystemTransitionWake
;
4920 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4921 kIOPMSystemCapabilityNetwork
;
4923 // Early exit from dark wake to full (e.g. LID open)
4924 if (kFullWakeReasonNone
!= fullWakeReason
)
4926 _desiredCapability
|= (
4927 kIOPMSystemCapabilityGraphics
|
4928 kIOPMSystemCapabilityAudio
);
4931 IOHibernateSetWakeCapabilities(_desiredCapability
);
4935 // Update pending wake capability at the beginning of every
4936 // state transition (including synchronize). This will become
4937 // the current capability at the end of the transition.
4939 if (kSystemTransitionSleep
== _systemTransitionType
)
4941 _pendingCapability
= 0;
4942 capabilityLoss
= true;
4945 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4947 _pendingCapability
= _desiredCapability
|
4948 kIOPMSystemCapabilityCPU
|
4949 kIOPMSystemCapabilityNetwork
;
4951 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4952 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4954 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4955 (_pendingCapability
== _currentCapability
))
4957 // Cancel the PM state change.
4958 _systemTransitionType
= kSystemTransitionNone
;
4959 *inOutChangeFlags
|= kIOPMNotDone
;
4961 if (__builtin_popcount(_pendingCapability
) <
4962 __builtin_popcount(_currentCapability
))
4963 capabilityLoss
= true;
4966 // 1. Capability change.
4968 if (kSystemTransitionCapability
== _systemTransitionType
)
4970 // Dark to Full transition.
4971 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4973 tracePoint( kIOPMTracePointDarkWakeExit
);
4975 willEnterFullWake();
4978 // Full to Dark transition.
4979 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4981 // Clear previous stats
4982 IOLockLock(pmStatsLock
);
4983 if (pmStatsAppResponses
)
4985 pmStatsAppResponses
->release();
4986 pmStatsAppResponses
= OSArray::withCapacity(5);
4988 IOLockUnlock(pmStatsLock
);
4991 tracePoint( kIOPMTracePointDarkWakeEntry
);
4992 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4993 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4994 kSystemMessageClientLegacyApp
;
4998 // Prevent user active transitions before notifying clients
4999 // that system will sleep.
5000 preventTransitionToUserActive(true);
5002 IOService::setAdvisoryTickleEnable( false );
5004 // Publish the sleep reason for full to dark wake
5005 publishSleepReason
= true;
5006 lastSleepReason
= fullToDarkReason
= sleepReason
;
5008 // Publish a UUID for the Sleep --> Wake cycle
5009 handlePublishSleepWakeUUID(true);
5010 if (sleepDelaysReport
) {
5011 clock_get_uptime(&ts_sleepStart
);
5012 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5015 wranglerTickled
= false;
5021 else if (kSystemTransitionSleep
== _systemTransitionType
)
5023 // Beginning of a system sleep transition.
5024 // Cancellation is still possible.
5025 tracePoint( kIOPMTracePointSleepStarted
);
5027 _systemMessageClientMask
= kSystemMessageClientAll
;
5028 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5029 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5030 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5031 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5033 gIOHibernateState
= 0;
5036 // Record the reason for dark wake back to sleep
5037 // System may not have ever achieved full wake
5039 publishSleepReason
= true;
5040 lastSleepReason
= sleepReason
;
5041 if (sleepDelaysReport
) {
5042 clock_get_uptime(&ts_sleepStart
);
5043 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5049 else if (kSystemTransitionWake
== _systemTransitionType
)
5051 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5052 // Clear stats about sleep
5054 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5056 willEnterFullWake();
5060 // Message powerd only
5061 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5062 tellClients(kIOMessageSystemWillPowerOn
);
5066 // The only location where the sleep reason is published. At this point
5067 // sleep can still be cancelled, but sleep reason should be published
5068 // early for logging purposes.
5070 if (publishSleepReason
)
5072 static const char * IOPMSleepReasons
[] =
5074 kIOPMClamshellSleepKey
,
5075 kIOPMPowerButtonSleepKey
,
5076 kIOPMSoftwareSleepKey
,
5077 kIOPMOSSwitchHibernationKey
,
5079 kIOPMLowPowerSleepKey
,
5080 kIOPMThermalEmergencySleepKey
,
5081 kIOPMMaintenanceSleepKey
,
5082 kIOPMSleepServiceExitKey
,
5083 kIOPMDarkWakeThermalEmergencyKey
5086 // Record sleep cause in IORegistry
5087 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5088 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5089 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5090 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5094 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5095 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5097 _systemStateGeneration
++;
5098 systemDarkWake
= false;
5100 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5102 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5103 _systemTransitionType
, _systemStateGeneration
,
5104 _systemMessageClientMask
,
5105 _desiredCapability
, _currentCapability
, _pendingCapability
);
5109 void IOPMrootDomain::handleOurPowerChangeDone(
5110 IOService
* service
,
5111 IOPMActions
* actions
,
5112 IOPMPowerStateIndex powerState
,
5113 IOPMPowerChangeFlags changeFlags
,
5114 IOPMRequestTag requestTag __unused
)
5116 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5118 _systemTransitionType
= kSystemTransitionNone
;
5122 if (_systemTransitionType
!= kSystemTransitionNone
)
5124 uint32_t currentPowerState
= (uint32_t) getPowerState();
5126 if (changeFlags
& kIOPMNotDone
)
5128 // Power down was cancelled or vetoed.
5129 _pendingCapability
= _currentCapability
;
5130 lastSleepReason
= 0;
5132 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5133 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5135 pmPowerStateQueue
->submitPowerEvent(
5136 kPowerEventPolicyStimulus
,
5137 (void *) kStimulusDarkWakeReentry
,
5138 _systemStateGeneration
);
5141 // Revert device desire to max.
5142 changePowerStateToPriv(ON_STATE
);
5146 // Send message on dark wake to full wake promotion.
5147 // tellChangeUp() handles the normal SLEEP->ON case.
5149 if (kSystemTransitionCapability
== _systemTransitionType
)
5151 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5153 lastSleepReason
= 0; // stop logging wrangler tickles
5154 tellClients(kIOMessageSystemHasPoweredOn
);
5156 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5158 // Going dark, reset full wake state
5159 // userIsActive will be cleared by wrangler powering down
5160 fullWakeReason
= kFullWakeReasonNone
;
5162 if (ts_sleepStart
) {
5163 clock_get_uptime(&wake2DarkwakeDelay
);
5164 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5165 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5171 // Reset state after exiting from dark wake.
5173 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5174 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5176 darkWakeMaintenance
= false;
5177 darkWakeToSleepASAP
= false;
5178 pciCantSleepValid
= false;
5179 darkWakeSleepService
= false;
5181 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5183 // Remove the influence of display power assertion
5184 // before next system wake.
5185 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5186 kWranglerPowerStateMin
);
5187 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5191 // Entered dark mode.
5193 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5194 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5196 // Queue an evaluation of whether to remain in dark wake,
5197 // and for how long. This serves the purpose of draining
5198 // any assertions from the queue.
5200 pmPowerStateQueue
->submitPowerEvent(
5201 kPowerEventPolicyStimulus
,
5202 (void *) kStimulusDarkWakeEntry
,
5203 _systemStateGeneration
);
5207 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5208 "dcp %x:%x:%x, dbgtimer %u\n",
5209 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5210 _systemTransitionType
, _systemStateGeneration
,
5211 _systemMessageClientMask
,
5212 _desiredCapability
, _currentCapability
, _pendingCapability
,
5213 _lastDebugWakeSeconds
);
5215 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5218 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5219 if (clamshellExists
&& fullWakeThreadCall
&&
5220 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5222 // Not the initial graphics full power, graphics won't
5223 // send a power notification to trigger a lid state
5226 AbsoluteTime deadline
;
5227 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5228 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5232 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5235 // Update current system capability.
5236 if (_currentCapability
!= _pendingCapability
)
5237 _currentCapability
= _pendingCapability
;
5239 // Update highest system capability.
5241 _highestCapability
|= _currentCapability
;
5243 if (darkWakePostTickle
&&
5244 (kSystemTransitionWake
== _systemTransitionType
) &&
5245 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5246 kDarkWakeFlagHIDTickleLate
)
5248 darkWakePostTickle
= false;
5251 else if (wranglerTickled
) {
5252 requestFullWake( kFullWakeReasonLocalUser
);
5255 // Reset tracepoint at completion of capability change,
5256 // completion of wake transition, and aborted sleep transition.
5258 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5259 (_systemTransitionType
== kSystemTransitionWake
) ||
5260 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5261 (changeFlags
& kIOPMNotDone
)))
5263 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5264 tracePoint( kIOPMTracePointSystemUp
);
5267 _systemTransitionType
= kSystemTransitionNone
;
5268 _systemMessageClientMask
= 0;
5269 toldPowerdCapWillChange
= false;
5271 logGraphicsClamp
= false;
5273 if (lowBatteryCondition
) {
5274 privateSleepSystem (kIOPMSleepReasonLowPower
);
5276 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5277 // Request for full wake is removed while system is waking up to full wake
5278 DLOG("DisplayOn fullwake request is removed\n");
5279 handleDisplayPowerOn();
5285 //******************************************************************************
5286 // PM actions for graphics and audio.
5287 //******************************************************************************
5289 void IOPMrootDomain::overridePowerChangeForUIService(
5290 IOService
* service
,
5291 IOPMActions
* actions
,
5292 IOPMPowerStateIndex
* inOutPowerState
,
5293 IOPMPowerChangeFlags
* inOutChangeFlags
)
5295 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5296 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5298 if (kSystemTransitionNone
== _systemTransitionType
)
5300 // Not in midst of a system transition.
5301 // Do not modify power limit enable state.
5303 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5305 // Activate power limiter.
5307 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5308 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5309 (changeFlags
& kIOPMSynchronize
))
5311 actions
->parameter
|= kPMActionsFlagLimitPower
;
5313 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5314 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5315 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5316 (changeFlags
& kIOPMSynchronize
))
5318 actions
->parameter
|= kPMActionsFlagLimitPower
;
5320 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5321 (_systemTransitionType
== kSystemTransitionSleep
))
5323 // For graphics devices, arm the limiter when entering
5324 // system sleep. Not when dropping to dark wake.
5325 actions
->parameter
|= kPMActionsFlagLimitPower
;
5328 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5330 DLOG("+ plimit %s %p\n",
5331 service
->getName(), OBFUSCATE(service
));
5336 // Remove power limit.
5338 if ((actions
->parameter
& (
5339 kPMActionsFlagIsDisplayWrangler
|
5340 kPMActionsFlagIsGraphicsDevice
)) &&
5341 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5343 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5345 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5346 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5348 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5351 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5353 DLOG("- plimit %s %p\n",
5354 service
->getName(), OBFUSCATE(service
));
5358 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5360 uint32_t maxPowerState
= (uint32_t)(-1);
5362 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5364 // Enforce limit for system power/cap transitions.
5367 if ((service
->getPowerState() > maxPowerState
) &&
5368 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5372 // Remove lingering effects of any tickle before entering
5373 // dark wake. It will take a new tickle to return to full
5374 // wake, so the existing tickle state is useless.
5376 if (changeFlags
& kIOPMDomainDidChange
)
5377 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5379 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5386 // Deny all self-initiated changes when power is limited.
5387 // Wrangler tickle should never defeat the limiter.
5389 maxPowerState
= service
->getPowerState();
5392 if (powerState
> maxPowerState
)
5394 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5395 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5397 *inOutPowerState
= maxPowerState
;
5399 if (darkWakePostTickle
&&
5400 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5401 (changeFlags
& kIOPMDomainWillChange
) &&
5402 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5403 kDarkWakeFlagHIDTickleEarly
))
5405 darkWakePostTickle
= false;
5410 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5412 if (logGraphicsClamp
)
5417 clock_get_uptime(&now
);
5418 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5419 absolutetime_to_nanoseconds(now
, &nsec
);
5420 if (kIOLogPMRootDomain
& gIOKitDebug
)
5421 MSG("Graphics suppressed %u ms\n",
5422 ((int)((nsec
) / 1000000ULL)));
5424 graphicsSuppressed
= true;
5429 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5430 IOService
* service
,
5431 IOPMActions
* actions
)
5434 // Warning: Not running in PM work loop context - don't modify state !!!
5435 // Trap tickle directed to IODisplayWrangler while running with graphics
5436 // capability suppressed.
5438 assert(service
== wrangler
);
5440 clock_get_uptime(&userActivityTime
);
5441 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5442 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5443 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5445 userActivityCount
++;
5446 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5447 userActivityCount
, lastSleepReason
);
5450 if (!wranglerTickled
&&
5451 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5453 DLOG("display wrangler tickled\n");
5454 if (kIOLogPMRootDomain
& gIOKitDebug
)
5455 OSReportWithBacktrace("Dark wake display tickle");
5456 if (pmPowerStateQueue
)
5458 pmPowerStateQueue
->submitPowerEvent(
5459 kPowerEventPolicyStimulus
,
5460 (void *) kStimulusDarkWakeActivityTickle
,
5461 true /* set wake type */ );
5467 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5468 IOService
* service
,
5469 IOPMActions
* actions
,
5470 const OSSymbol
* powerClient
,
5471 IOPMPowerStateIndex oldPowerState
,
5472 IOPMPowerStateIndex newPowerState
)
5475 assert(service
== wrangler
);
5477 // This function implements half of the user active detection
5478 // by monitoring changes to the display wrangler's device desire.
5480 // User becomes active when either:
5481 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5482 // in max power state. This desire change in absence of a power state
5483 // change is detected within. This handles the case when user becomes
5484 // active while the display is already lit by setDisplayPowerOn().
5486 // 2. Power state change to max, and DeviceDesire is also at max.
5487 // Handled by displayWranglerNotification().
5489 // User becomes inactive when DeviceDesire drops to sleep state or below.
5491 DLOG("wrangler %s (ps %u, %u->%u)\n",
5492 powerClient
->getCStringNoCopy(),
5493 (uint32_t) service
->getPowerState(),
5494 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5496 if (powerClient
== gIOPMPowerClientDevice
)
5498 if ((newPowerState
> oldPowerState
) &&
5499 (newPowerState
== kWranglerPowerStateMax
) &&
5500 (service
->getPowerState() == kWranglerPowerStateMax
))
5502 evaluatePolicy( kStimulusEnterUserActiveState
);
5505 if ((newPowerState
< oldPowerState
) &&
5506 (newPowerState
<= kWranglerPowerStateSleep
))
5508 evaluatePolicy( kStimulusLeaveUserActiveState
);
5512 if (newPowerState
<= kWranglerPowerStateSleep
) {
5513 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5515 else if (newPowerState
== kWranglerPowerStateMax
) {
5516 evaluatePolicy( kStimulusDisplayWranglerWake
);
5521 //******************************************************************************
5522 // User active state management
5523 //******************************************************************************
5525 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5528 _preventUserActive
= prevent
;
5529 if (wrangler
&& !_preventUserActive
)
5531 // Allowing transition to user active, but the wrangler may have
5532 // already powered ON in case of sleep cancel/revert. Poll the
5533 // same conditions checked for in displayWranglerNotification()
5534 // to bring the user active state up to date.
5536 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5537 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5538 kWranglerPowerStateMax
))
5540 evaluatePolicy( kStimulusEnterUserActiveState
);
5546 //******************************************************************************
5547 // Approve usage of delayed child notification by PM.
5548 //******************************************************************************
5550 bool IOPMrootDomain::shouldDelayChildNotification(
5551 IOService
* service
)
5553 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5554 (kFullWakeReasonNone
== fullWakeReason
) &&
5555 (kSystemTransitionWake
== _systemTransitionType
))
5557 DLOG("%s: delay child notify\n", service
->getName());
5563 //******************************************************************************
5564 // PM actions for PCI device.
5565 //******************************************************************************
5567 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5568 IOService
* service
,
5569 IOPMActions
* actions
,
5570 IOPMPowerStateIndex powerState
,
5571 IOPMPowerChangeFlags
* inOutChangeFlags
)
5573 pmTracer
->tracePCIPowerChange(
5574 PMTraceWorker::kPowerChangeStart
,
5575 service
, *inOutChangeFlags
,
5576 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5579 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5580 IOService
* service
,
5581 IOPMActions
* actions
,
5582 IOPMPowerStateIndex powerState
,
5583 IOPMPowerChangeFlags changeFlags
)
5585 pmTracer
->tracePCIPowerChange(
5586 PMTraceWorker::kPowerChangeCompleted
,
5587 service
, changeFlags
,
5588 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5591 //******************************************************************************
5594 // Override IOService::registerInterest() to intercept special clients.
5595 //******************************************************************************
5597 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5600 friend class IOPMrootDomain
;
5601 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5604 uint32_t ackTimeoutCnt
;
5605 uint32_t msgType
; // Message pending ack
5609 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5611 IONotifier
* IOPMrootDomain::registerInterest(
5612 const OSSymbol
* typeOfInterest
,
5613 IOServiceInterestHandler handler
,
5614 void * target
, void * ref
)
5616 IOPMServiceInterestNotifier
*notifier
= 0;
5617 bool isSystemCapabilityClient
;
5618 bool isKernelCapabilityClient
;
5619 IOReturn rc
= kIOReturnError
;;
5621 isSystemCapabilityClient
=
5623 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5625 isKernelCapabilityClient
=
5627 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5629 if (isSystemCapabilityClient
)
5630 typeOfInterest
= gIOAppPowerStateInterest
;
5632 notifier
= new IOPMServiceInterestNotifier
;
5633 if (!notifier
) return NULL
;
5635 if (notifier
->init()) {
5636 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5638 if (rc
!= kIOReturnSuccess
) {
5639 notifier
->release();
5644 if (pmPowerStateQueue
)
5646 notifier
->ackTimeoutCnt
= 0;
5647 if (isSystemCapabilityClient
)
5650 if (pmPowerStateQueue
->submitPowerEvent(
5651 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5652 notifier
->release();
5655 if (isKernelCapabilityClient
)
5658 if (pmPowerStateQueue
->submitPowerEvent(
5659 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5660 notifier
->release();
5667 //******************************************************************************
5668 // systemMessageFilter
5670 //******************************************************************************
5672 bool IOPMrootDomain::systemMessageFilter(
5673 void * object
, void * arg1
, void * arg2
, void * arg3
)
5675 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5676 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5677 bool isCapClient
= false;
5679 IOPMServiceInterestNotifier
*notifier
;
5681 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5683 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5684 (!isCapMsg
|| !_joinedCapabilityClients
||
5685 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5688 // Capability change message for app and kernel clients.
5692 if ((context
->notifyType
== kNotifyPriority
) ||
5693 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5696 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5697 (object
== (void *) systemCapabilityNotifier
))
5703 IOPMSystemCapabilityChangeParameters
* capArgs
=
5704 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5706 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5708 capArgs
->fromCapabilities
= 0;
5709 capArgs
->toCapabilities
= _currentCapability
;
5710 capArgs
->changeFlags
= 0;
5714 capArgs
->fromCapabilities
= _currentCapability
;
5715 capArgs
->toCapabilities
= _pendingCapability
;
5717 if (context
->isPreChange
)
5718 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5720 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5722 if ((object
== (void *) systemCapabilityNotifier
) &&
5723 context
->isPreChange
)
5725 toldPowerdCapWillChange
= true;
5729 // Capability change messages only go to the PM configd plugin.
5730 // Wait for response post-change if capabilitiy is increasing.
5731 // Wait for response pre-change if capability is decreasing.
5733 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5734 ( (capabilityLoss
&& context
->isPreChange
) ||
5735 (!capabilityLoss
&& !context
->isPreChange
) ) )
5737 // app has not replied yet, wait for it
5738 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5741 notifier
->msgType
= context
->messageType
;
5749 // Capability client will always see kIOMessageCanSystemSleep,
5750 // even for demand sleep. It will also have a chance to veto
5751 // sleep one last time after all clients have responded to
5752 // kIOMessageSystemWillSleep
5754 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5755 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5757 if (object
== (OSObject
*) systemCapabilityNotifier
)
5761 notifier
->msgType
= context
->messageType
;
5766 // Not idle sleep, don't ask apps.
5767 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5773 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5775 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5776 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5777 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5779 notifier
->msgType
= context
->messageType
;
5786 // Reject capability change messages for legacy clients.
5787 // Reject legacy system sleep messages for capability client.
5789 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5794 // Filter system sleep messages.
5796 if ((context
->notifyType
== kNotifyApps
) &&
5797 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5803 if (notifier
->ackTimeoutCnt
>= 3)
5804 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5806 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5809 notifier
->msgType
= context
->messageType
;
5812 else if ((context
->notifyType
== kNotifyPriority
) &&
5813 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5820 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5822 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5823 if (_joinedCapabilityClients
->getCount() == 0)
5825 DLOG("destroyed capability client set %p\n",
5826 OBFUSCATE(_joinedCapabilityClients
));
5827 _joinedCapabilityClients
->release();
5828 _joinedCapabilityClients
= 0;
5835 //******************************************************************************
5836 // setMaintenanceWakeCalendar
5838 //******************************************************************************
5840 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5841 const IOPMCalendarStruct
* calendar
)
5847 return kIOReturnBadArgument
;
5849 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5851 return kIOReturnNoMemory
;
5853 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5854 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5855 if (kIOReturnSuccess
== ret
)
5856 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5858 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5860 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5861 if (kIOReturnSuccess
== ret
)
5862 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5864 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5871 // MARK: Display Wrangler
5873 //******************************************************************************
5874 // displayWranglerNotification
5876 // Handle the notification when the IODisplayWrangler changes power state.
5877 //******************************************************************************
5879 IOReturn
IOPMrootDomain::displayWranglerNotification(
5880 void * target
, void * refCon
,
5881 UInt32 messageType
, IOService
* service
,
5882 void * messageArgument
, vm_size_t argSize
)
5885 int displayPowerState
;
5886 IOPowerStateChangeNotification
* params
=
5887 (IOPowerStateChangeNotification
*) messageArgument
;
5889 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5890 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5891 return kIOReturnUnsupported
;
5895 return kIOReturnUnsupported
;
5897 displayPowerState
= params
->stateNumber
;
5898 DLOG("wrangler %s ps %d\n",
5899 getIOMessageString(messageType
), displayPowerState
);
5901 switch (messageType
) {
5902 case kIOMessageDeviceWillPowerOff
:
5903 // Display wrangler has dropped power due to display idle
5904 // or force system sleep.
5906 // 4 Display ON kWranglerPowerStateMax
5907 // 3 Display Dim kWranglerPowerStateDim
5908 // 2 Display Sleep kWranglerPowerStateSleep
5909 // 1 Not visible to user
5910 // 0 Not visible to user kWranglerPowerStateMin
5912 if (displayPowerState
<= kWranglerPowerStateSleep
)
5913 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5916 case kIOMessageDeviceHasPoweredOn
:
5917 // Display wrangler has powered on due to user activity
5918 // or wake from sleep.
5920 if (kWranglerPowerStateMax
== displayPowerState
)
5922 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5924 // See comment in handleUpdatePowerClientForDisplayWrangler
5925 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5926 kWranglerPowerStateMax
)
5928 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5934 return kIOReturnUnsupported
;
5937 //******************************************************************************
5938 // displayWranglerMatchPublished
5940 // Receives a notification when the IODisplayWrangler is published.
5941 // When it's published we install a power state change handler.
5942 //******************************************************************************
5944 bool IOPMrootDomain::displayWranglerMatchPublished(
5947 IOService
* newService
,
5948 IONotifier
* notifier __unused
)
5951 // found the display wrangler, now install a handler
5952 if( !newService
->registerInterest( gIOGeneralInterest
,
5953 &displayWranglerNotification
, target
, 0) )
5961 #if defined(__i386__) || defined(__x86_64__)
5963 bool IOPMrootDomain::IONVRAMMatchPublished(
5966 IOService
* newService
,
5967 IONotifier
* notifier
)
5969 unsigned int len
= 0;
5970 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5971 OSNumber
*statusCode
= NULL
;
5973 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5975 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5976 if (statusCode
!= NULL
) {
5977 if (statusCode
->unsigned64BitValue() != 0) {
5978 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5979 MSG("System was rebooted due to Sleep/Wake failure\n");
5982 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5983 MSG("System was non-responsive and was rebooted by watchdog\n");
5987 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5989 if (notifier
) notifier
->remove();
5994 bool IOPMrootDomain::IONVRAMMatchPublished(
5997 IOService
* newService
,
5998 IONotifier
* notifier __unused
)
6005 //******************************************************************************
6008 //******************************************************************************
6010 void IOPMrootDomain::reportUserInput( void )
6014 OSDictionary
* matching
;
6018 matching
= serviceMatching("IODisplayWrangler");
6019 iter
= getMatchingServices(matching
);
6020 if (matching
) matching
->release();
6023 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6029 wrangler
->activityTickle(0,0);
6033 //******************************************************************************
6034 // latchDisplayWranglerTickle
6035 //******************************************************************************
6037 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6042 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6043 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6044 !checkSystemCanSustainFullWake())
6046 // Currently in dark wake, and not transitioning to full wake.
6047 // Full wake is unsustainable, so latch the tickle to prevent
6048 // the display from lighting up momentarily.
6049 wranglerTickleLatched
= true;
6053 wranglerTickleLatched
= false;
6056 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6058 wranglerTickleLatched
= false;
6060 pmPowerStateQueue
->submitPowerEvent(
6061 kPowerEventPolicyStimulus
,
6062 (void *) kStimulusDarkWakeActivityTickle
);
6065 return wranglerTickleLatched
;
6071 //******************************************************************************
6072 // setDisplayPowerOn
6074 // For root domain user client
6075 //******************************************************************************
6077 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6079 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6080 (void *) 0, options
);
6086 //******************************************************************************
6089 // Notification on battery class IOPowerSource appearance
6090 //******************************************************************************
6092 bool IOPMrootDomain::batteryPublished(
6095 IOService
* resourceService
,
6096 IONotifier
* notifier __unused
)
6098 // rdar://2936060&4435589
6099 // All laptops have dimmable LCD displays
6100 // All laptops have batteries
6101 // So if this machine has a battery, publish the fact that the backlight
6102 // supports dimming.
6103 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6109 // MARK: System PM Policy
6111 //******************************************************************************
6112 // checkSystemSleepAllowed
6114 //******************************************************************************
6116 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6117 uint32_t sleepReason
)
6121 // Conditions that prevent idle and demand system sleep.
6124 if (userDisabledAllSleep
)
6126 err
= 1; // 1. user-space sleep kill switch
6130 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6132 err
= 2; // 2. restart or shutdown in progress
6139 // Conditions above pegs the system at full wake.
6140 // Conditions below prevent system sleep but does not prevent
6141 // dark wake, and must be called from gated context.
6144 err
= 3; // 3. config does not support sleep
6148 if (lowBatteryCondition
|| thermalWarningState
)
6150 break; // always sleep on low battery or when in thermal warning state
6153 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6155 break; // always sleep on dark wake thermal emergencies
6158 if (preventSystemSleepList
->getCount() != 0)
6160 err
= 4; // 4. child prevent system sleep clamp
6164 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6165 kIOPMDriverAssertionLevelOn
)
6167 err
= 5; // 5. CPU assertion
6171 if (pciCantSleepValid
)
6173 if (pciCantSleepFlag
)
6174 err
= 6; // 6. PCI card does not support PM (cached)
6177 else if (sleepSupportedPEFunction
&&
6178 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6181 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6182 ret
= getPlatform()->callPlatformFunction(
6183 sleepSupportedPEFunction
, false,
6184 NULL
, NULL
, NULL
, NULL
);
6185 pciCantSleepValid
= true;
6186 pciCantSleepFlag
= false;
6187 if ((platformSleepSupport
& kPCICantSleep
) ||
6188 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6190 err
= 6; // 6. PCI card does not support PM
6191 pciCantSleepFlag
= true;
6200 DLOG("System sleep prevented by %d\n", err
);
6206 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6208 return checkSystemSleepAllowed(0, 0);
6211 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6214 return checkSystemSleepAllowed(1, sleepReason
);
6217 //******************************************************************************
6218 // checkSystemCanSustainFullWake
6219 //******************************************************************************
6221 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6224 if (lowBatteryCondition
|| thermalWarningState
)
6226 // Low battery wake, or received a low battery notification
6227 // while system is awake. This condition will persist until
6228 // the following wake.
6232 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6234 // Graphics state is unknown and external display might not be probed.
6235 // Do not incorporate state that requires graphics to be in max power
6236 // such as desktopMode or clamshellDisabled.
6238 if (!acAdaptorConnected
)
6240 DLOG("full wake check: no AC\n");
6248 //******************************************************************************
6251 // Conditions that affect our wake/sleep decision has changed.
6252 // If conditions dictate that the system must remain awake, clamp power
6253 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6254 // is TRUE, then remove the power clamp and allow the power state to drop
6256 //******************************************************************************
6258 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6260 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6261 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6265 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6267 changePowerStateToPriv(ON_STATE
);
6269 else if ( sleepASAP
)
6271 changePowerStateToPriv(SLEEP_STATE
);
6275 void IOPMrootDomain::handleDisplayPowerOn( )
6277 if (!wrangler
) return;
6278 if (displayPowerOnRequested
)
6280 if (!checkSystemCanSustainFullWake()) return;
6282 // Force wrangler to max power state. If system is in dark wake
6283 // this alone won't raise the wrangler's power state.
6285 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6287 // System in dark wake, always requesting full wake should
6288 // not have any bad side-effects, even if the request fails.
6290 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6292 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6293 requestFullWake( kFullWakeReasonDisplayOn
);
6298 // Relenquish desire to power up display.
6299 // Must first transition to state 1 since wrangler doesn't
6300 // power off the displays at state 0. At state 0 the root
6301 // domain is removed from the wrangler's power client list.
6303 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6304 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6310 //******************************************************************************
6311 // dispatchPowerEvent
6313 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6314 //******************************************************************************
6316 void IOPMrootDomain::dispatchPowerEvent(
6317 uint32_t event
, void * arg0
, uint64_t arg1
)
6319 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6324 case kPowerEventFeatureChanged
:
6325 messageClients(kIOPMMessageFeatureChange
, this);
6328 case kPowerEventReceivedPowerNotification
:
6329 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6332 case kPowerEventSystemBootCompleted
:
6335 systemBooting
= false;
6337 if (lowBatteryCondition
)
6339 privateSleepSystem (kIOPMSleepReasonLowPower
);
6341 // The rest is unnecessary since the system is expected
6342 // to sleep immediately. The following wake will update
6347 if (swd_flags
& SWD_VALID_LOGS
) {
6348 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6349 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6350 swd_logBufMap
->release();
6353 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6354 sleepWakeDebugDumpFromFile();
6356 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6357 // If logs are invalid, write the failure code
6358 sleepWakeDebugDumpFromMem(NULL
);
6360 // If lid is closed, re-send lid closed notification
6361 // now that booting is complete.
6362 if ( clamshellClosed
)
6364 handlePowerNotification(kLocalEvalClamshellCommand
);
6366 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6371 case kPowerEventSystemShutdown
:
6372 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6374 /* We set systemShutdown = true during shutdown
6375 to prevent sleep at unexpected times while loginwindow is trying
6376 to shutdown apps and while the OS is trying to transition to
6379 Set to true during shutdown, as soon as loginwindow shows
6380 the "shutdown countdown dialog", through individual app
6381 termination, and through black screen kernel shutdown.
6383 systemShutdown
= true;
6386 A shutdown was initiated, but then the shutdown
6387 was cancelled, clearing systemShutdown to false here.
6389 systemShutdown
= false;
6393 case kPowerEventUserDisabledSleep
:
6394 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6397 case kPowerEventRegisterSystemCapabilityClient
:
6398 if (systemCapabilityNotifier
)
6400 systemCapabilityNotifier
->release();
6401 systemCapabilityNotifier
= 0;
6405 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6406 systemCapabilityNotifier
->retain();
6408 /* intentional fall-through */
6409 [[clang::fallthrough]];
6411 case kPowerEventRegisterKernelCapabilityClient
:
6412 if (!_joinedCapabilityClients
)
6413 _joinedCapabilityClients
= OSSet::withCapacity(8);
6416 IONotifier
* notify
= (IONotifier
*) arg0
;
6417 if (_joinedCapabilityClients
)
6419 _joinedCapabilityClients
->setObject(notify
);
6420 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6426 case kPowerEventPolicyStimulus
:
6429 int stimulus
= (uintptr_t) arg0
;
6430 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6434 case kPowerEventAssertionCreate
:
6436 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6441 case kPowerEventAssertionRelease
:
6443 pmAssertions
->handleReleaseAssertion(arg1
);
6447 case kPowerEventAssertionSetLevel
:
6449 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6453 case kPowerEventQueueSleepWakeUUID
:
6454 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6456 case kPowerEventPublishSleepWakeUUID
:
6457 handlePublishSleepWakeUUID((bool)arg0
);
6460 case kPowerEventSetDisplayPowerOn
:
6461 if (!wrangler
) break;
6464 displayPowerOnRequested
= true;
6468 displayPowerOnRequested
= false;
6470 handleDisplayPowerOn();
6475 //******************************************************************************
6476 // systemPowerEventOccurred
6478 // The power controller is notifying us of a hardware-related power management
6479 // event that we must handle.
6481 // systemPowerEventOccurred covers the same functionality that
6482 // receivePowerNotification does; it simply provides a richer API for conveying
6483 // more information.
6484 //******************************************************************************
6486 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6487 const OSSymbol
*event
,
6490 IOReturn attempt
= kIOReturnSuccess
;
6491 OSNumber
*newNumber
= NULL
;
6494 return kIOReturnBadArgument
;
6496 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6498 return kIOReturnInternalError
;
6500 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6502 newNumber
->release();
6507 void IOPMrootDomain::setThermalState(OSObject
*value
)
6511 if (gIOPMWorkLoop
->inGate() == false) {
6512 gIOPMWorkLoop
->runAction(
6513 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6519 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6520 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6521 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6525 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6526 const OSSymbol
*event
,
6529 OSDictionary
*thermalsDict
= NULL
;
6530 bool shouldUpdate
= true;
6532 if (!event
|| !value
)
6533 return kIOReturnBadArgument
;
6536 // We reuse featuresDict Lock because it already exists and guards
6537 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6538 // of stepping on that lock.
6539 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6541 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6543 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6544 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6546 thermalsDict
= OSDictionary::withCapacity(1);
6549 if (!thermalsDict
) {
6550 shouldUpdate
= false;
6554 thermalsDict
->setObject (event
, value
);
6556 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6558 thermalsDict
->release();
6562 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6566 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6567 setThermalState(value
);
6569 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6572 return kIOReturnSuccess
;
6575 //******************************************************************************
6576 // receivePowerNotification
6578 // The power controller is notifying us of a hardware-related power management
6579 // event that we must handle. This may be a result of an 'environment' interrupt
6580 // from the power mgt micro.
6581 //******************************************************************************
6583 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6585 pmPowerStateQueue
->submitPowerEvent(
6586 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6587 return kIOReturnSuccess
;
6590 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6592 bool eval_clamshell
= false;
6597 * Local (IOPMrootDomain only) eval clamshell command
6599 if (msg
& kLocalEvalClamshellCommand
)
6601 eval_clamshell
= true;
6607 if (msg
& kIOPMOverTemp
)
6609 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6610 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6614 * Forward DW thermal notification to client, if system is not going to sleep
6616 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6618 DLOG("DarkWake thermal limits message received!\n");
6620 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6626 if (msg
& kIOPMSleepNow
)
6628 privateSleepSystem (kIOPMSleepReasonSoftware
);
6634 if (msg
& kIOPMPowerEmergency
)
6636 lowBatteryCondition
= true;
6637 privateSleepSystem (kIOPMSleepReasonLowPower
);
6643 if (msg
& kIOPMClamshellOpened
)
6645 // Received clamshel open message from clamshell controlling driver
6646 // Update our internal state and tell general interest clients
6647 clamshellClosed
= false;
6648 clamshellExists
= true;
6650 // Don't issue a hid tickle when lid is open and polled on wake
6651 if (msg
& kIOPMSetValue
)
6653 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6658 informCPUStateChange(kInformLid
, 0);
6660 // Tell general interest clients
6661 sendClientClamshellNotification();
6663 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6664 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6665 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6666 if (aborting
) userActivityCount
++;
6667 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6672 * Send the clamshell interest notification since the lid is closing.
6674 if (msg
& kIOPMClamshellClosed
)
6676 // Received clamshel open message from clamshell controlling driver
6677 // Update our internal state and tell general interest clients
6678 clamshellClosed
= true;
6679 clamshellExists
= true;
6682 informCPUStateChange(kInformLid
, 1);
6684 // Tell general interest clients
6685 sendClientClamshellNotification();
6687 // And set eval_clamshell = so we can attempt
6688 eval_clamshell
= true;
6692 * Set Desktop mode (sent from graphics)
6694 * -> reevaluate lid state
6696 if (msg
& kIOPMSetDesktopMode
)
6698 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6699 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6701 sendClientClamshellNotification();
6703 // Re-evaluate the lid state
6704 eval_clamshell
= true;
6708 * AC Adaptor connected
6710 * -> reevaluate lid state
6712 if (msg
& kIOPMSetACAdaptorConnected
)
6714 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6715 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6718 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6720 // Tell BSD if AC is connected
6721 // 0 == external power source; 1 == on battery
6722 post_sys_powersource(acAdaptorConnected
? 0:1);
6724 sendClientClamshellNotification();
6726 // Re-evaluate the lid state
6727 eval_clamshell
= true;
6729 // Lack of AC may have latched a display wrangler tickle.
6730 // This mirrors the hardware's USB wake event latch, where a latched
6731 // USB wake event followed by an AC attach will trigger a full wake.
6732 latchDisplayWranglerTickle( false );
6735 // AC presence will reset the standy timer delay adjustment.
6736 _standbyTimerResetSeconds
= 0;
6738 if (!userIsActive
) {
6739 // Reset userActivityTime when power supply is changed(rdr 13789330)
6740 clock_get_uptime(&userActivityTime
);
6745 * Enable Clamshell (external display disappear)
6747 * -> reevaluate lid state
6749 if (msg
& kIOPMEnableClamshell
)
6751 // Re-evaluate the lid state
6752 // System should sleep on external display disappearance
6753 // in lid closed operation.
6754 if (true == clamshellDisabled
)
6756 eval_clamshell
= true;
6759 clamshellDisabled
= false;
6760 sendClientClamshellNotification();
6764 * Disable Clamshell (external display appeared)
6765 * We don't bother re-evaluating clamshell state. If the system is awake,
6766 * the lid is probably open.
6768 if (msg
& kIOPMDisableClamshell
)
6770 clamshellDisabled
= true;
6771 sendClientClamshellNotification();
6775 * Evaluate clamshell and SLEEP if appropiate
6777 if (eval_clamshell
&& clamshellClosed
)
6779 if (shouldSleepOnClamshellClosed())
6780 privateSleepSystem (kIOPMSleepReasonClamshell
);
6782 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6788 if (msg
& kIOPMPowerButton
)
6790 if (!wranglerAsleep
)
6792 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6793 // Check that power button sleep is enabled
6795 if( kOSBooleanTrue
!= getProperty(pbs
))
6796 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6804 //******************************************************************************
6807 // Evaluate root-domain policy in response to external changes.
6808 //******************************************************************************
6810 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6814 int idleSleepEnabled
: 1;
6815 int idleSleepDisabled
: 1;
6816 int displaySleep
: 1;
6817 int sleepDelayChanged
: 1;
6818 int evaluateDarkWake
: 1;
6819 int adjustPowerState
: 1;
6820 int userBecameInactive
: 1;
6825 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6832 case kStimulusDisplayWranglerSleep
:
6833 if (!wranglerAsleep
)
6835 // first transition to wrangler sleep or lower
6836 flags
.bit
.displaySleep
= true;
6840 case kStimulusDisplayWranglerWake
:
6841 displayIdleForDemandSleep
= false;
6842 wranglerAsleep
= false;
6845 case kStimulusEnterUserActiveState
:
6846 if (_preventUserActive
)
6848 DLOG("user active dropped\n");
6853 userIsActive
= true;
6854 userWasActive
= true;
6856 // Stay awake after dropping demand for display power on
6857 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
6858 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6859 DLOG("User activity while in notification wake\n");
6860 changePowerStateWithOverrideTo( ON_STATE
, 0);
6863 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
6864 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6865 messageClients(kIOPMMessageUserIsActiveChanged
);
6867 flags
.bit
.idleSleepDisabled
= true;
6870 case kStimulusLeaveUserActiveState
:
6873 userIsActive
= false;
6874 clock_get_uptime(&userBecameInactiveTime
);
6875 flags
.bit
.userBecameInactive
= true;
6877 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
6878 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6879 messageClients(kIOPMMessageUserIsActiveChanged
);
6883 case kStimulusAggressivenessChanged
:
6885 unsigned long minutesToIdleSleep
= 0;
6886 unsigned long minutesToDisplayDim
= 0;
6887 unsigned long minutesDelta
= 0;
6889 // Fetch latest display and system sleep slider values.
6890 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6891 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6892 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6893 (uint32_t) sleepSlider
,
6894 (uint32_t) minutesToIdleSleep
,
6895 (uint32_t) minutesToDisplayDim
);
6897 DLOG("idle time -> %ld secs (ena %d)\n",
6898 idleSeconds
, (minutesToIdleSleep
!= 0));
6901 // How long to wait before sleeping the system once
6902 // the displays turns off is indicated by 'extraSleepDelay'.
6904 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6905 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6906 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6909 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
6910 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
6912 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
6913 flags
.bit
.idleSleepDisabled
= true;
6914 idleSleepEnabled
= false;
6916 if (0x7fffffff == minutesToIdleSleep
)
6917 minutesToIdleSleep
= idleSeconds
;
6919 if (((minutesDelta
!= extraSleepDelay
) ||
6920 (userActivityTime
!= userActivityTime_prev
)) &&
6921 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6922 flags
.bit
.sleepDelayChanged
= true;
6924 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6925 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6927 // Reconsider decision to remain in dark wake
6928 flags
.bit
.evaluateDarkWake
= true;
6931 sleepSlider
= minutesToIdleSleep
;
6932 extraSleepDelay
= minutesDelta
;
6933 userActivityTime_prev
= userActivityTime
;
6936 case kStimulusDemandSystemSleep
:
6937 displayIdleForDemandSleep
= true;
6938 if (wrangler
&& wranglerIdleSettings
)
6940 // Request wrangler idle only when demand sleep is triggered
6942 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6944 wrangler
->setProperties(wranglerIdleSettings
);
6945 DLOG("Requested wrangler idle\n");
6948 // arg = sleepReason
6949 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6952 case kStimulusAllowSystemSleepChanged
:
6953 flags
.bit
.adjustPowerState
= true;
6956 case kStimulusDarkWakeActivityTickle
:
6957 // arg == true implies real and not self generated wrangler tickle.
6958 // Update wake type on PM work loop instead of the tickle thread to
6959 // eliminate the possibility of an early tickle clobbering the wake
6960 // type set by the platform driver.
6962 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6964 if (false == wranglerTickled
)
6966 if (latchDisplayWranglerTickle(true))
6968 DLOG("latched tickle\n");
6972 wranglerTickled
= true;
6973 DLOG("Requesting full wake after dark wake activity tickle\n");
6974 requestFullWake( kFullWakeReasonLocalUser
);
6978 case kStimulusDarkWakeEntry
:
6979 case kStimulusDarkWakeReentry
:
6980 // Any system transitions since the last dark wake transition
6981 // will invalid the stimulus.
6983 if (arg
== _systemStateGeneration
)
6985 DLOG("dark wake entry\n");
6986 systemDarkWake
= true;
6988 // Keep wranglerAsleep an invariant when wrangler is absent
6990 wranglerAsleep
= true;
6992 if (kStimulusDarkWakeEntry
== stimulus
)
6994 clock_get_uptime(&userBecameInactiveTime
);
6995 flags
.bit
.evaluateDarkWake
= true;
6998 // Always accelerate disk spindown while in dark wake,
6999 // even if system does not support/allow sleep.
7001 cancelIdleSleepTimer();
7002 setQuickSpinDownTimeout();
7006 case kStimulusDarkWakeEvaluate
:
7009 flags
.bit
.evaluateDarkWake
= true;
7013 case kStimulusNoIdleSleepPreventers
:
7014 flags
.bit
.adjustPowerState
= true;
7017 } /* switch(stimulus) */
7019 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7021 if (darkWakeToSleepASAP
||
7022 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7024 uint32_t newSleepReason
;
7026 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7028 // System was previously in full wake. Sleep reason from
7029 // full to dark already recorded in fullToDarkReason.
7031 if (lowBatteryCondition
)
7032 newSleepReason
= kIOPMSleepReasonLowPower
;
7034 newSleepReason
= fullToDarkReason
;
7038 // In dark wake from system sleep.
7040 if (darkWakeSleepService
)
7041 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7043 newSleepReason
= kIOPMSleepReasonMaintenance
;
7046 if (checkSystemCanSleep(newSleepReason
))
7048 privateSleepSystem(newSleepReason
);
7051 else // non-maintenance (network) dark wake
7053 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7055 // Release power clamp, and wait for children idle.
7056 adjustPowerState(true);
7060 changePowerStateToPriv(ON_STATE
);
7067 // The rest are irrelevant while system is in dark wake.
7071 if ((flags
.bit
.displaySleep
) &&
7072 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7074 // kIOPMSleepReasonMaintenance?
7075 DLOG("Display sleep while in notification wake\n");
7076 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7079 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7081 bool cancelQuickSpindown
= false;
7083 if (flags
.bit
.sleepDelayChanged
)
7085 // Cancel existing idle sleep timer and quick disk spindown.
7086 // New settings will be applied by the idleSleepEnabled flag
7087 // handler below if idle sleep is enabled.
7089 DLOG("extra sleep timer changed\n");
7090 cancelIdleSleepTimer();
7091 cancelQuickSpindown
= true;
7095 DLOG("user inactive\n");
7098 if (!userIsActive
&& idleSleepEnabled
)
7100 startIdleSleepTimer(getTimeToIdleSleep());
7103 if (cancelQuickSpindown
)
7104 restoreUserSpinDownTimeout();
7107 if (flags
.bit
.idleSleepEnabled
)
7109 DLOG("idle sleep timer enabled\n");
7112 changePowerStateToPriv(ON_STATE
);
7113 startIdleSleepTimer( idleSeconds
);
7117 // Start idle timer if prefs now allow system sleep
7118 // and user is already inactive. Disk spindown is
7119 // accelerated upon timer expiration.
7123 startIdleSleepTimer(getTimeToIdleSleep());
7128 if (flags
.bit
.idleSleepDisabled
)
7130 DLOG("idle sleep timer disabled\n");
7131 cancelIdleSleepTimer();
7132 restoreUserSpinDownTimeout();
7136 if (flags
.bit
.adjustPowerState
)
7138 bool sleepASAP
= false;
7140 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7144 changePowerStateToPriv(ON_STATE
);
7145 if (idleSleepEnabled
)
7147 // stay awake for at least idleSeconds
7148 startIdleSleepTimer(idleSeconds
);
7151 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7157 adjustPowerState(sleepASAP
);
7161 //******************************************************************************
7164 // Request transition from dark wake to full wake
7165 //******************************************************************************
7167 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7169 uint32_t options
= 0;
7170 IOService
* pciRoot
= 0;
7171 bool promotion
= false;
7173 // System must be in dark wake and a valid reason for entering full wake
7174 if ((kFullWakeReasonNone
== reason
) ||
7175 (kFullWakeReasonNone
!= fullWakeReason
) ||
7176 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7181 // Will clear reason upon exit from full wake
7182 fullWakeReason
= reason
;
7184 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7185 kIOPMSystemCapabilityAudio
);
7187 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7188 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7189 !graphicsSuppressed
)
7191 // Promote to full wake while waking up to dark wake due to tickle.
7192 // PM will hold off notifying the graphics subsystem about system wake
7193 // as late as possible, so if a HID tickle does arrive, graphics can
7194 // power up on this same wake cycle. The latency to power up graphics
7195 // on the next cycle can be huge on some systems. However, once any
7196 // graphics suppression has taken effect, it is too late. All other
7197 // graphics devices must be similarly suppressed. But the delay till
7198 // the following cycle should be short.
7200 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7201 kIOPMSystemCapabilityAudio
);
7203 // Immediately bring up audio and graphics
7204 pciRoot
= pciHostBridgeDriver
;
7205 willEnterFullWake();
7209 // Unsafe to cancel once graphics was powered.
7210 // If system woke from dark wake, the return to sleep can
7211 // be cancelled. "awake -> dark -> sleep" transition
7212 // can be canceled also, during the "dark --> sleep" phase
7213 // *prior* to driver power down.
7214 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7215 _pendingCapability
== 0) {
7216 options
|= kIOPMSyncCancelPowerDown
;
7219 synchronizePowerTree(options
, pciRoot
);
7220 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7222 // IOGraphics doesn't light the display even though graphics is
7223 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7224 // So, do an explicit activity tickle
7226 wrangler
->activityTickle(0,0);
7229 // Log a timestamp for the initial full wake request.
7230 // System may not always honor this full wake request.
7231 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7236 clock_get_uptime(&now
);
7237 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7238 absolutetime_to_nanoseconds(now
, &nsec
);
7239 MSG("full wake %s (reason %u) %u ms\n",
7240 promotion
? "promotion" : "request",
7241 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7245 //******************************************************************************
7246 // willEnterFullWake
7248 // System will enter full wake from sleep, from dark wake, or from dark
7249 // wake promotion. This function aggregate things that are in common to
7250 // all three full wake transitions.
7252 // Assumptions: fullWakeReason was updated
7253 //******************************************************************************
7255 void IOPMrootDomain::willEnterFullWake( void )
7257 hibernateRetry
= false;
7258 sleepToStandby
= false;
7259 standbyNixed
= false;
7260 resetTimers
= false;
7261 sleepTimerMaintenance
= false;
7263 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7264 kSystemMessageClientLegacyApp
;
7266 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7268 // Initial graphics full power
7269 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7271 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7272 setProperty(gIOPMUserTriggeredFullWakeKey
,
7273 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7274 kOSBooleanTrue
: kOSBooleanFalse
);
7277 IOHibernateSetWakeCapabilities(_pendingCapability
);
7280 IOService::setAdvisoryTickleEnable( true );
7281 tellClients(kIOMessageSystemWillPowerOn
);
7282 preventTransitionToUserActive(false);
7285 //******************************************************************************
7286 // fullWakeDelayedWork
7288 // System has already entered full wake. Invoked by a delayed thread call.
7289 //******************************************************************************
7291 void IOPMrootDomain::fullWakeDelayedWork( void )
7293 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7294 // Not gated, don't modify state
7295 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7296 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7298 receivePowerNotification( kLocalEvalClamshellCommand
);
7303 //******************************************************************************
7304 // evaluateAssertions
7306 //******************************************************************************
7307 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7309 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7311 messageClients(kIOPMMessageDriverAssertionsChanged
);
7313 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7316 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7318 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7319 wrangler
->setIgnoreIdleTimer( value
);
7323 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7324 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7325 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7327 clock_usec_t microsecs
;
7328 clock_get_uptime(&now
);
7329 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7330 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7331 if (assertOnWakeReport
) {
7332 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7333 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7338 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7339 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7341 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7342 updatePreventIdleSleepList(this, true);
7345 DLOG("Driver assertion ReservedBit7 dropped\n");
7346 updatePreventIdleSleepList(this, false);
7354 //******************************************************************************
7357 //******************************************************************************
7359 void IOPMrootDomain::pmStatsRecordEvent(
7361 AbsoluteTime timestamp
)
7363 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7364 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7367 OSData
*publishPMStats
= NULL
;
7369 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7371 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7373 switch (eventIndex
) {
7374 case kIOPMStatsHibernateImageWrite
:
7376 gPMStats
.hibWrite
.start
= nsec
;
7378 gPMStats
.hibWrite
.stop
= nsec
;
7381 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7382 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7385 case kIOPMStatsHibernateImageRead
:
7387 gPMStats
.hibRead
.start
= nsec
;
7389 gPMStats
.hibRead
.stop
= nsec
;
7392 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7393 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7395 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7396 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7397 publishPMStats
->release();
7398 bzero(&gPMStats
, sizeof(gPMStats
));
7405 * Appends a record of the application response to
7406 * IOPMrootDomain::pmStatsAppResponses
7408 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7409 const OSSymbol
*response
,
7415 IOPMPowerStateIndex powerState
)
7417 OSDictionary
*responseDescription
= NULL
;
7418 OSNumber
*delayNum
= NULL
;
7419 OSNumber
*powerCaps
= NULL
;
7420 OSNumber
*pidNum
= NULL
;
7421 OSNumber
*msgNum
= NULL
;
7422 const OSSymbol
*appname
;
7423 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7424 IOPMServiceInterestNotifier
*notify
= 0;
7426 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7428 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7429 notify
->ackTimeoutCnt
++;
7431 notify
->ackTimeoutCnt
= 0;
7435 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7436 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7440 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7441 kdebugTrace(kPMLogDrvResponseDelay
, id
, messageType
, delay_ms
);
7444 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7445 notify
->msgType
= 0;
7448 responseDescription
= OSDictionary::withCapacity(5);
7449 if (responseDescription
)
7452 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7455 msgNum
= OSNumber::withNumber(messageType
, 32);
7457 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7461 if (name
&& (strlen(name
) > 0))
7463 appname
= OSSymbol::withCString(name
);
7465 responseDescription
->setObject(_statsNameKey
, appname
);
7471 pidNum
= OSNumber::withNumber(id
, 32);
7473 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7478 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7480 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7481 delayNum
->release();
7484 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7485 powerCaps
= OSNumber::withNumber(powerState
, 32);
7487 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7488 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7490 powerState
, delay_ms
);
7495 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7498 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7499 powerCaps
->release();
7502 sleep
= OSSymbol::withCString("Sleep");
7503 wake
= OSSymbol::withCString("Wake");
7504 if (_systemTransitionType
== kSystemTransitionSleep
) {
7505 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7507 else if (_systemTransitionType
== kSystemTransitionWake
) {
7508 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7510 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7511 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7512 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7513 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7514 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7516 if (sleep
) sleep
->release();
7517 if (wake
) wake
->release();
7521 IOLockLock(pmStatsLock
);
7522 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7523 pmStatsAppResponses
->setObject(responseDescription
);
7525 IOLockUnlock(pmStatsLock
);
7527 responseDescription
->release();
7534 // MARK: PMTraceWorker
7536 //******************************************************************************
7537 // TracePoint support
7539 //******************************************************************************
7541 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7542 "IOPMRegisterNVRAMTracePointHandler"
7544 IOReturn
IOPMrootDomain::callPlatformFunction(
7545 const OSSymbol
* functionName
,
7546 bool waitForFunction
,
7547 void * param1
, void * param2
,
7548 void * param3
, void * param4
)
7550 uint32_t bootFailureCode
= 0xffffffff;
7551 unsigned int len
= sizeof(bootFailureCode
);
7552 if (pmTracer
&& functionName
&&
7553 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7554 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7556 uint32_t tracePointPhases
, tracePointPCI
;
7557 uint64_t statusCode
;
7559 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7560 pmTracer
->tracePointTarget
= (void *) param2
;
7561 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7562 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7563 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7564 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey
, &bootFailureCode
, &len
)) {
7565 MSG("Failed to read failure code from NVRam\n");
7567 // Failure code from EFI/BootRom is a four byte structure
7568 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7570 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7571 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7572 MSG("Sleep failure code 0x%08x 0x%08x\n",
7573 tracePointPCI
, tracePointPhases
);
7575 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7576 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7578 return kIOReturnSuccess
;
7581 else if (functionName
&&
7582 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7584 if (gSleepPolicyHandler
)
7585 return kIOReturnExclusiveAccess
;
7587 return kIOReturnBadArgument
;
7588 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7589 gSleepPolicyTarget
= (void *) param2
;
7590 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7591 return kIOReturnSuccess
;
7595 return super::callPlatformFunction(
7596 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7599 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7600 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7602 uint32_t code
= IODBG_POWER(event
);
7603 uint64_t regId
= id
;
7605 regId
= getRegistryEntryID();
7607 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7611 void IOPMrootDomain::tracePoint( uint8_t point
)
7613 if (systemBooting
) return;
7615 if (kIOPMTracePointWakeCapabilityClients
== point
)
7616 acceptSystemWakeEvents(false);
7618 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7619 pmTracer
->tracePoint(point
);
7622 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uintptr_t handler
)
7624 if (!systemBooting
) {
7625 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
7626 ((msgType
& 0xfff) << 12) |
7628 pmTracer
->traceDetail( detail
);
7629 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, pmTracer
->getTracePhase(), msgType
, handler
& 0xfff);
7634 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7637 void **report
= NULL
;
7640 uint32_t *clientCnt
;
7645 if (channel_id
== kAssertDelayChID
) {
7646 report
= &assertOnWakeReport
;
7647 bktCnt
= kAssertDelayBcktCnt
;
7648 bktSize
= kAssertDelayBcktSize
;
7649 clientCnt
= &assertOnWakeClientCnt
;
7651 else if (channel_id
== kSleepDelaysChID
) {
7652 report
= &sleepDelaysReport
;
7653 bktCnt
= kSleepDelaysBcktCnt
;
7654 bktSize
= kSleepDelaysBcktSize
;
7655 clientCnt
= &sleepDelaysClientCnt
;
7660 case kIOReportEnable
:
7667 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7668 *report
= IOMalloc(reportSize
);
7669 if (*report
== NULL
) {
7672 bzero(*report
, reportSize
);
7673 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7674 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7676 if (channel_id
== kAssertDelayChID
)
7677 assertOnWakeSecs
= 0;
7681 case kIOReportDisable
:
7682 if (*clientCnt
== 0) {
7685 if (*clientCnt
== 1)
7687 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7692 if (channel_id
== kAssertDelayChID
)
7693 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7697 case kIOReportGetDimensions
:
7699 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7707 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7708 IOReportConfigureAction action
,
7713 uint64_t configAction
= (uint64_t)action
;
7715 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7716 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7717 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7718 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7719 if (action
!= kIOReportGetDimensions
) continue;
7720 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7722 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7723 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7724 gIOPMWorkLoop
->runAction(
7725 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7726 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7727 (void *)configAction
, (void *)result
);
7731 return super::configureReport(channelList
, action
, result
, destination
);
7734 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7744 if (ch_id
== kAssertDelayChID
) {
7745 report
= &assertOnWakeReport
;
7747 else if (ch_id
== kSleepDelaysChID
) {
7748 report
= &sleepDelaysReport
;
7751 if (*report
== NULL
) {
7752 return kIOReturnNotOpen
;
7755 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7756 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7757 return kIOReturnOverrun
;
7760 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7761 dest
->appendBytes(data2cpy
, size2cpy
);
7763 return kIOReturnSuccess
;
7766 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7767 IOReportUpdateAction action
,
7773 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7774 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7778 if (action
!= kIOReportCopyChannelData
) goto exit
;
7780 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7781 ch_id
= channelList
->channels
[cnt
].channel_id
;
7783 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7784 gIOPMWorkLoop
->runAction(
7785 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7786 (OSObject
*)this, (void *)ch_id
,
7787 (void *)result
, (void *)dest
);
7791 else if ((ch_id
== kSleepCntChID
) ||
7792 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7793 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7797 if (ch_id
== kSleepCntChID
)
7798 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7799 else if (ch_id
== kDarkWkCntChID
)
7800 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7801 else if (ch_id
== kUserWkCntChID
)
7802 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7804 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7805 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7806 dest
->appendBytes(data2cpy
, size2cpy
);
7810 return super::updateReport(channelList
, action
, result
, destination
);
7814 //******************************************************************************
7815 // PMTraceWorker Class
7817 //******************************************************************************
7820 #define super OSObject
7821 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7823 #define kPMBestGuessPCIDevicesCount 25
7824 #define kPMMaxRTCBitfieldSize 32
7826 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7830 me
= OSTypeAlloc( PMTraceWorker
);
7831 if (!me
|| !me
->init())
7836 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7838 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7839 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7840 // this dictionary lazily.
7842 me
->pciDeviceBitMappings
= NULL
;
7843 me
->pmTraceWorkerLock
= IOLockAlloc();
7844 me
->tracePhase
= kIOPMTracePointSystemUp
;
7845 me
->traceData32
= 0;
7846 me
->loginWindowData
= 0;
7847 me
->coreDisplayData
= 0;
7848 me
->coreGraphicsData
= 0;
7852 void PMTraceWorker::RTC_TRACE(void)
7854 if (tracePointHandler
&& tracePointTarget
)
7858 IOLockLock(pmTraceWorkerLock
);
7859 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
7860 (coreGraphicsData
<< 8) | tracePhase
;
7861 IOLockUnlock(pmTraceWorkerLock
);
7863 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7864 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7868 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7870 const OSSymbol
* deviceName
;
7873 IOLockLock(pmTraceWorkerLock
);
7875 if (!pciDeviceBitMappings
)
7877 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7878 if (!pciDeviceBitMappings
)
7882 // Check for bitmask overflow.
7883 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7886 if ((deviceName
= pciDevice
->copyName()) &&
7887 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7888 pciDeviceBitMappings
->setObject(deviceName
))
7890 index
= pciDeviceBitMappings
->getCount() - 1;
7891 _LOG("PMTrace PCI array: set object %s => %d\n",
7892 deviceName
->getCStringNoCopy(), index
);
7895 deviceName
->release();
7896 if (!addedToRegistry
&& (index
>= 0))
7897 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7900 IOLockUnlock(pmTraceWorkerLock
);
7904 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7907 if (pciDeviceBitMappings
)
7909 IOLockLock(pmTraceWorkerLock
);
7910 ok
= pciDeviceBitMappings
->serialize(s
);
7911 IOLockUnlock(pmTraceWorkerLock
);
7916 void PMTraceWorker::tracePoint(uint8_t phase
)
7918 // clear trace detail when phase begins
7919 if (tracePhase
!= phase
)
7924 DLOG("trace point 0x%02x\n", tracePhase
);
7928 void PMTraceWorker::traceDetail(uint32_t detail
)
7931 traceData32
= detail
;
7932 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7937 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
7939 switch (component
) {
7940 case kIOPMLoginWindowProgress
:
7941 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
7943 case kIOPMCoreDisplayProgress
:
7944 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
7946 case kIOPMCoreGraphicsProgress
:
7947 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
7953 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
7957 void PMTraceWorker::tracePCIPowerChange(
7958 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7961 uint32_t expectedFlag
;
7963 // Ignore PCI changes outside of system sleep/wake.
7964 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7965 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7968 // Only record the WillChange transition when going to sleep,
7969 // and the DidChange on the way up.
7970 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7971 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7972 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7973 if (changeFlags
!= expectedFlag
)
7976 // Mark this device off in our bitfield
7977 if (bitNum
< kPMMaxRTCBitfieldSize
)
7979 bitMask
= (1 << bitNum
);
7981 if (kPowerChangeStart
== type
)
7983 traceData32
|= bitMask
;
7984 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7985 service
->getName(), bitNum
, bitMask
, traceData32
);
7986 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
7990 traceData32
&= ~bitMask
;
7991 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7992 service
->getName(), bitNum
, bitMask
, traceData32
);
7993 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
7996 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8001 uint64_t PMTraceWorker::getPMStatusCode( )
8003 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8007 uint8_t PMTraceWorker::getTracePhase()
8012 uint32_t PMTraceWorker::getTraceData()
8018 // MARK: PMHaltWorker
8020 //******************************************************************************
8021 // PMHaltWorker Class
8023 //******************************************************************************
8025 PMHaltWorker
* PMHaltWorker::worker( void )
8031 me
= OSTypeAlloc( PMHaltWorker
);
8032 if (!me
|| !me
->init())
8035 me
->lock
= IOLockAlloc();
8039 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8040 me
->retain(); // thread holds extra retain
8041 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8046 thread_deallocate(thread
);
8051 if (me
) me
->release();
8055 void PMHaltWorker::free( void )
8057 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8063 return OSObject::free();
8066 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8068 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8070 IOLockLock( gPMHaltLock
);
8072 me
->depth
= gPMHaltDepth
;
8073 IOLockUnlock( gPMHaltLock
);
8075 while (me
->depth
>= 0)
8077 PMHaltWorker::work( me
);
8079 IOLockLock( gPMHaltLock
);
8080 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8082 // This is the last thread to finish work on this level,
8083 // inform everyone to start working on next lower level.
8085 me
->depth
= gPMHaltDepth
;
8086 gPMHaltIdleCount
= 0;
8087 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8091 // One or more threads are still working on this level,
8092 // this thread must wait.
8093 me
->depth
= gPMHaltDepth
- 1;
8095 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8096 } while (me
->depth
!= gPMHaltDepth
);
8098 IOLockUnlock( gPMHaltLock
);
8101 // No more work to do, terminate thread
8102 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8103 thread_wakeup( &gPMHaltDepth
);
8107 void PMHaltWorker::work( PMHaltWorker
* me
)
8109 IOService
* service
;
8111 AbsoluteTime startTime
;
8120 // Claim an unit of work from the shared pool
8121 IOLockLock( gPMHaltLock
);
8122 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8125 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8129 inner
->removeObject(service
);
8132 IOLockUnlock( gPMHaltLock
);
8134 break; // no more work at this depth
8136 clock_get_uptime(&startTime
);
8138 if (!service
->isInactive() &&
8139 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8141 IOLockLock(me
->lock
);
8142 me
->startTime
= startTime
;
8143 me
->service
= service
;
8144 me
->timeout
= false;
8145 IOLockUnlock(me
->lock
);
8147 service
->systemWillShutdown( gPMHaltMessageType
);
8149 // Wait for driver acknowledgement
8150 IOLockLock(me
->lock
);
8151 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8153 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8156 timeout
= me
->timeout
;
8157 IOLockUnlock(me
->lock
);
8160 deltaTime
= computeDeltaTimeMS(&startTime
);
8161 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
8162 (gIOKitDebug
& kIOLogPMRootDomain
))
8164 LOG("%s driver %s (0x%llx) took %u ms\n",
8165 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8166 "PowerOff" : "Restart",
8167 service
->getName(), service
->getRegistryEntryID(),
8168 (uint32_t) deltaTime
);
8176 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8179 AbsoluteTime startTime
;
8180 AbsoluteTime endTime
;
8184 IOLockLock(me
->lock
);
8185 if (me
->service
&& !me
->timeout
)
8187 startTime
= me
->startTime
;
8189 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8191 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8192 absolutetime_to_nanoseconds(endTime
, &nano
);
8194 if (nano
> 3000000000ULL)
8197 MSG("%s still waiting on %s\n",
8198 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8199 "PowerOff" : "Restart",
8200 me
->service
->getName());
8203 IOLockUnlock(me
->lock
);
8206 //******************************************************************************
8207 // acknowledgeSystemWillShutdown
8209 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8210 //******************************************************************************
8212 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8214 PMHaltWorker
* worker
;
8220 //DLOG("%s acknowledged\n", from->getName());
8221 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8224 worker
= (PMHaltWorker
*) prop
;
8225 IOLockLock(worker
->lock
);
8226 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8227 thread_wakeup((event_t
) worker
);
8228 IOLockUnlock(worker
->lock
);
8233 DLOG("%s acknowledged without worker property\n",
8239 //******************************************************************************
8240 // notifySystemShutdown
8242 // Notify all objects in PM tree that system will shutdown or restart
8243 //******************************************************************************
8246 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8248 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8249 IORegistryIterator
* iter
;
8250 IORegistryEntry
* entry
;
8253 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8254 AbsoluteTime deadline
;
8255 unsigned int totalNodes
= 0;
8257 unsigned int rootDepth
;
8258 unsigned int numWorkers
;
8264 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8266 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8268 // Iterate the entire PM tree starting from root
8270 rootDepth
= root
->getDepth( gIOPowerPlane
);
8271 if (!rootDepth
) goto done
;
8273 // debug - for repeated test runs
8274 while (PMHaltWorker::metaClass
->getInstanceCount())
8279 gPMHaltArray
= OSArray::withCapacity(40);
8280 if (!gPMHaltArray
) goto done
;
8283 gPMHaltArray
->flushCollection();
8287 gPMHaltLock
= IOLockAlloc();
8288 if (!gPMHaltLock
) goto done
;
8291 if (!gPMHaltClientAcknowledgeKey
)
8293 gPMHaltClientAcknowledgeKey
=
8294 OSSymbol::withCStringNoCopy("PMShutdown");
8295 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8298 gPMHaltMessageType
= messageType
;
8300 // Depth-first walk of PM plane
8302 iter
= IORegistryIterator::iterateOver(
8303 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8307 while ((entry
= iter
->getNextObject()))
8309 node
= OSDynamicCast(IOService
, entry
);
8314 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8317 depth
= node
->getDepth( gIOPowerPlane
);
8318 if (depth
<= rootDepth
)
8323 // adjust to zero based depth
8324 depth
-= (rootDepth
+ 1);
8326 // gPMHaltArray is an array of containers, each container
8327 // refers to nodes with the same depth.
8329 count
= gPMHaltArray
->getCount();
8330 while (depth
>= count
)
8332 // expand array and insert placeholders
8333 gPMHaltArray
->setObject(PLACEHOLDER
);
8336 count
= gPMHaltArray
->getCount();
8339 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8340 if (inner
== PLACEHOLDER
)
8342 inner
= OSSet::withCapacity(40);
8345 gPMHaltArray
->replaceObject(depth
, inner
);
8350 // PM nodes that appear more than once in the tree will have
8351 // the same depth, OSSet will refuse to add the node twice.
8353 ok
= inner
->setObject(node
);
8356 DLOG("Skipped PM node %s\n", node
->getName());
8362 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8365 if (inner
!= PLACEHOLDER
)
8366 count
= inner
->getCount();
8367 DLOG("Nodes at depth %u = %u\n", i
, count
);
8370 // strip placeholders (not all depths are populated)
8372 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8374 if (inner
== PLACEHOLDER
)
8376 gPMHaltArray
->removeObject(i
);
8379 count
= inner
->getCount();
8380 if (count
> numWorkers
)
8382 totalNodes
+= count
;
8386 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8389 gPMHaltBusyCount
= 0;
8390 gPMHaltIdleCount
= 0;
8391 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8393 // Create multiple workers (and threads)
8395 if (numWorkers
> kPMHaltMaxWorkers
)
8396 numWorkers
= kPMHaltMaxWorkers
;
8398 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8399 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8401 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8402 workers
[i
] = PMHaltWorker::worker();
8404 // Wait for workers to exhaust all available work
8406 IOLockLock(gPMHaltLock
);
8407 while (gPMHaltDepth
>= 0)
8409 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8411 waitResult
= IOLockSleepDeadline(
8412 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8413 if (THREAD_TIMED_OUT
== waitResult
)
8416 clock_get_uptime(&now
);
8418 IOLockUnlock(gPMHaltLock
);
8419 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8422 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8424 IOLockLock(gPMHaltLock
);
8427 IOLockUnlock(gPMHaltLock
);
8429 // Release all workers
8431 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8434 workers
[i
]->release();
8435 // worker also retained by it's own thread
8439 DLOG("%s done\n", __FUNCTION__
);
8444 // MARK: Kernel Assertion
8446 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8448 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8449 IOPMDriverAssertionType whichAssertionBits
,
8450 IOPMDriverAssertionLevel assertionLevel
,
8451 IOService
*ownerService
,
8452 const char *ownerDescription
)
8455 IOPMDriverAssertionID newAssertion
;
8460 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8462 if (kIOReturnSuccess
== ret
)
8463 return newAssertion
;
8468 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8471 return kIOReturnInternalError
;
8473 return pmAssertions
->releaseAssertion(releaseAssertion
);
8477 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8478 IOPMDriverAssertionID assertionID
,
8479 IOPMDriverAssertionLevel assertionLevel
)
8481 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8484 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8486 IOPMDriverAssertionType sysLevels
;
8488 if (!pmAssertions
|| whichAssertion
== 0)
8489 return kIOPMDriverAssertionLevelOff
;
8491 sysLevels
= pmAssertions
->getActivatedAssertions();
8493 // Check that every bit set in argument 'whichAssertion' is asserted
8494 // in the aggregate bits.
8495 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8496 return kIOPMDriverAssertionLevelOn
;
8498 return kIOPMDriverAssertionLevelOff
;
8501 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8504 return kIOReturnNotFound
;
8506 return pmAssertions
->setUserAssertionLevels(inLevels
);
8509 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8513 pmAssertions
->publishProperties();
8515 return( IOService::serializeProperties(s
) );
8518 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8520 OSObject
*obj
= NULL
;
8521 obj
= IOService::copyProperty(aKey
);
8523 if (obj
) return obj
;
8525 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8526 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8527 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8528 return kOSBooleanTrue
;
8530 return kOSBooleanFalse
;
8534 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8535 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8536 if (swd_flags
& SWD_VALID_LOGS
)
8537 return kOSBooleanTrue
;
8539 return kOSBooleanFalse
;
8544 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8545 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8546 * issued by DisplayWrangler on darkwake.
8548 if (!strcmp(aKey
, "DesktopMode")) {
8550 return kOSBooleanTrue
;
8552 return kOSBooleanFalse
;
8554 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8555 if (displayIdleForDemandSleep
) {
8556 return kOSBooleanTrue
;
8559 return kOSBooleanFalse
;
8563 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8565 OSArray
* array
= 0;
8567 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8568 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8569 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8570 collection
->release();
8577 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8579 OSArray
* array
= 0;
8580 IOLockLock(pmStatsLock
);
8581 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8582 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8583 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8584 collection
->release();
8586 pmStatsAppResponses
->flushCollection();
8588 IOLockUnlock(pmStatsLock
);
8592 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8594 OSArray
*idleSleepList
= NULL
;
8595 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8596 return idleSleepList
;
8599 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8601 OSArray
*systemSleepList
= NULL
;
8602 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8603 return systemSleepList
;
8610 // MARK: Wake Event Reporting
8612 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8615 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8619 //******************************************************************************
8620 // acceptSystemWakeEvents
8622 // Private control for the acceptance of driver wake event claims.
8623 //******************************************************************************
8625 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8627 bool logWakeReason
= false;
8632 gWakeReasonString
[0] = '\0';
8633 if (!_systemWakeEventsArray
)
8634 _systemWakeEventsArray
= OSArray::withCapacity(4);
8635 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8636 _systemWakeEventsArray
->flushCollection();
8640 _acceptSystemWakeEvents
= false;
8645 MSG("system wake events:%s\n", gWakeReasonString
);
8648 //******************************************************************************
8649 // claimSystemWakeEvent
8651 // For a driver to claim a device is the source/conduit of a system wake event.
8652 //******************************************************************************
8654 void IOPMrootDomain::claimSystemWakeEvent(
8657 const char * reason
,
8658 OSObject
* details
)
8660 const OSSymbol
* deviceName
= 0;
8661 OSNumber
* deviceRegId
= 0;
8662 OSNumber
* claimTime
= 0;
8663 OSData
* flagsData
= 0;
8664 OSString
* reasonString
= 0;
8665 OSDictionary
* d
= 0;
8669 pmEventTimeStamp(×tamp
);
8671 if (!device
|| !reason
) return;
8673 deviceName
= device
->copyName(gIOServicePlane
);
8674 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8675 claimTime
= OSNumber::withNumber(timestamp
, 64);
8676 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8677 reasonString
= OSString::withCString(reason
);
8678 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8679 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8682 d
->setObject(gIONameKey
, deviceName
);
8683 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8684 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8685 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8686 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8688 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8691 if (!gWakeReasonSysctlRegistered
)
8693 // Lazy registration until the platform driver stops registering
8695 gWakeReasonSysctlRegistered
= true;
8697 if (_acceptSystemWakeEvents
)
8699 ok
= _systemWakeEventsArray
->setObject(d
);
8700 if (gWakeReasonString
[0] != '\0')
8701 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8702 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8707 if (deviceName
) deviceName
->release();
8708 if (deviceRegId
) deviceRegId
->release();
8709 if (claimTime
) claimTime
->release();
8710 if (flagsData
) flagsData
->release();
8711 if (reasonString
) reasonString
->release();
8712 if (d
) d
->release();
8715 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8718 // MARK: PMSettingHandle
8720 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8722 void PMSettingHandle::free( void )
8726 pmso
->clientHandleFreed();
8735 // MARK: PMSettingObject
8738 #define super OSObject
8739 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8742 * Static constructor/initializer for PMSettingObject
8744 PMSettingObject
*PMSettingObject::pmSettingObject(
8745 IOPMrootDomain
*parent_arg
,
8746 IOPMSettingControllerCallback handler_arg
,
8747 OSObject
*target_arg
,
8748 uintptr_t refcon_arg
,
8749 uint32_t supportedPowerSources
,
8750 const OSSymbol
* settings
[],
8751 OSObject
**handle_obj
)
8753 uint32_t settingCount
= 0;
8754 PMSettingObject
*pmso
= 0;
8755 PMSettingHandle
*pmsh
= 0;
8757 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8760 // count OSSymbol entries in NULL terminated settings array
8761 while (settings
[settingCount
]) {
8764 if (0 == settingCount
)
8767 pmso
= new PMSettingObject
;
8768 if (!pmso
|| !pmso
->init())
8771 pmsh
= new PMSettingHandle
;
8772 if (!pmsh
|| !pmsh
->init())
8775 queue_init(&pmso
->calloutQueue
);
8776 pmso
->parent
= parent_arg
;
8777 pmso
->func
= handler_arg
;
8778 pmso
->target
= target_arg
;
8779 pmso
->refcon
= refcon_arg
;
8780 pmso
->settingCount
= settingCount
;
8782 pmso
->retain(); // handle holds a retain on pmso
8786 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8787 if (pmso
->publishedFeatureID
) {
8788 for (unsigned int i
=0; i
<settingCount
; i
++) {
8789 // Since there is now at least one listener to this setting, publish
8790 // PM root domain support for it.
8791 parent_arg
->publishPMSetting( settings
[i
],
8792 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8800 if (pmso
) pmso
->release();
8801 if (pmsh
) pmsh
->release();
8805 void PMSettingObject::free( void )
8807 if (publishedFeatureID
) {
8808 for (uint32_t i
=0; i
<settingCount
; i
++) {
8809 if (publishedFeatureID
[i
]) {
8810 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8814 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8820 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8822 (*func
)(target
, type
, object
, refcon
);
8825 void PMSettingObject::clientHandleFreed( void )
8827 parent
->deregisterPMSettingObject(this);
8831 // MARK: PMAssertionsTracker
8833 //*********************************************************************************
8834 //*********************************************************************************
8835 //*********************************************************************************
8836 // class PMAssertionsTracker Implementation
8838 #define kAssertUniqueIDStart 500
8840 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8842 PMAssertionsTracker
*myself
;
8844 myself
= new PMAssertionsTracker
;
8848 myself
->owner
= rootDomain
;
8849 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8850 myself
->assertionsArray
= OSArray::withCapacity(5);
8851 myself
->assertionsKernel
= 0;
8852 myself
->assertionsUser
= 0;
8853 myself
->assertionsCombined
= 0;
8854 myself
->assertionsArrayLock
= IOLockAlloc();
8855 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8857 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8865 * - Update assertionsKernel to reflect the state of all
8866 * assertions in the kernel.
8867 * - Update assertionsCombined to reflect both kernel & user space.
8869 void PMAssertionsTracker::tabulate(void)
8873 PMAssertStruct
*_a
= NULL
;
8876 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8877 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8881 assertionsKernel
= 0;
8882 assertionsCombined
= 0;
8884 if (!assertionsArray
)
8887 if ((count
= assertionsArray
->getCount()))
8889 for (i
=0; i
<count
; i
++)
8891 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8894 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8895 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8896 assertionsKernel
|= _a
->assertionBits
;
8901 tabulateProducerCount
++;
8902 assertionsCombined
= assertionsKernel
| assertionsUser
;
8904 if ((assertionsKernel
!= oldKernel
) ||
8905 (assertionsCombined
!= oldCombined
))
8907 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8911 void PMAssertionsTracker::publishProperties( void )
8913 OSArray
*assertionsSummary
= NULL
;
8915 if (tabulateConsumerCount
!= tabulateProducerCount
)
8917 IOLockLock(assertionsArrayLock
);
8919 tabulateConsumerCount
= tabulateProducerCount
;
8921 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8923 assertionsSummary
= copyAssertionsArray();
8924 if (assertionsSummary
)
8926 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8927 assertionsSummary
->release();
8931 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8934 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8936 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8938 IOLockUnlock(assertionsArrayLock
);
8942 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8944 PMAssertStruct
*_a
= NULL
;
8951 && (count
= assertionsArray
->getCount()))
8953 for (i
=0; i
<count
; i
++)
8955 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8958 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8959 if (_a
&& (_id
== _a
->id
)) {
8976 /* PMAssertionsTracker::handleCreateAssertion
8977 * Perform assertion work on the PM workloop. Do not call directly.
8979 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8985 IOLockLock(assertionsArrayLock
);
8986 assertionsArray
->setObject(newAssertion
);
8987 IOLockUnlock(assertionsArrayLock
);
8988 newAssertion
->release();
8992 return kIOReturnSuccess
;
8995 /* PMAssertionsTracker::createAssertion
8996 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8999 IOReturn
PMAssertionsTracker::createAssertion(
9000 IOPMDriverAssertionType which
,
9001 IOPMDriverAssertionLevel level
,
9002 IOService
*serviceID
,
9003 const char *whoItIs
,
9004 IOPMDriverAssertionID
*outID
)
9006 OSData
*dataStore
= NULL
;
9007 PMAssertStruct track
;
9009 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9010 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9011 track
.level
= level
;
9012 track
.assertionBits
= which
;
9013 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9014 track
.ownerService
= serviceID
;
9015 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9016 track
.modifiedTime
= 0;
9017 pmEventTimeStamp(&track
.createdTime
);
9019 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9022 if (track
.ownerString
)
9023 track
.ownerString
->release();
9024 return kIOReturnNoMemory
;
9029 if (owner
&& owner
->pmPowerStateQueue
) {
9030 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9033 return kIOReturnSuccess
;
9036 /* PMAssertionsTracker::handleReleaseAssertion
9037 * Runs in PM workloop. Do not call directly.
9039 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9040 IOPMDriverAssertionID _id
)
9045 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9048 return kIOReturnNotFound
;
9050 IOLockLock(assertionsArrayLock
);
9051 if (assertStruct
->ownerString
)
9052 assertStruct
->ownerString
->release();
9054 assertionsArray
->removeObject(index
);
9055 IOLockUnlock(assertionsArrayLock
);
9058 return kIOReturnSuccess
;
9061 /* PMAssertionsTracker::releaseAssertion
9062 * Releases an assertion and affects system behavior if appropiate.
9063 * Actual work happens on PM workloop.
9065 IOReturn
PMAssertionsTracker::releaseAssertion(
9066 IOPMDriverAssertionID _id
)
9068 if (owner
&& owner
->pmPowerStateQueue
) {
9069 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9071 return kIOReturnSuccess
;
9074 /* PMAssertionsTracker::handleSetAssertionLevel
9075 * Runs in PM workloop. Do not call directly.
9077 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9078 IOPMDriverAssertionID _id
,
9079 IOPMDriverAssertionLevel _level
)
9081 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9085 if (!assertStruct
) {
9086 return kIOReturnNotFound
;
9089 IOLockLock(assertionsArrayLock
);
9090 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9091 assertStruct
->level
= _level
;
9092 IOLockUnlock(assertionsArrayLock
);
9095 return kIOReturnSuccess
;
9098 /* PMAssertionsTracker::setAssertionLevel
9100 IOReturn
PMAssertionsTracker::setAssertionLevel(
9101 IOPMDriverAssertionID _id
,
9102 IOPMDriverAssertionLevel _level
)
9104 if (owner
&& owner
->pmPowerStateQueue
) {
9105 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9106 (void *)(uintptr_t)_level
, _id
);
9109 return kIOReturnSuccess
;
9112 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9114 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9118 if (new_user_levels
!= assertionsUser
)
9120 assertionsUser
= new_user_levels
;
9121 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9125 return kIOReturnSuccess
;
9128 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9129 IOPMDriverAssertionType new_user_levels
)
9131 if (gIOPMWorkLoop
) {
9132 gIOPMWorkLoop
->runAction(
9133 OSMemberFunctionCast(
9136 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9138 (void *) &new_user_levels
, 0, 0, 0);
9141 return kIOReturnSuccess
;
9145 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9149 OSArray
*outArray
= NULL
;
9151 if (!assertionsArray
||
9152 (0 == (count
= assertionsArray
->getCount())) ||
9153 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9158 for (i
=0; i
<count
; i
++)
9160 PMAssertStruct
*_a
= NULL
;
9162 OSDictionary
*details
= NULL
;
9164 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9165 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9167 OSNumber
*_n
= NULL
;
9169 details
= OSDictionary::withCapacity(7);
9173 outArray
->setObject(details
);
9176 _n
= OSNumber::withNumber(_a
->id
, 64);
9178 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9181 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9183 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9186 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9188 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9191 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9193 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9196 _n
= OSNumber::withNumber(_a
->level
, 64);
9198 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9201 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9203 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9207 if (_a
->ownerString
) {
9208 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9217 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9219 return assertionsCombined
;
9222 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9223 IOPMDriverAssertionType type
)
9225 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9227 return kIOPMDriverAssertionLevelOn
;
9229 return kIOPMDriverAssertionLevelOff
;
9233 //*********************************************************************************
9234 //*********************************************************************************
9235 //*********************************************************************************
9238 static void pmEventTimeStamp(uint64_t *recordTS
)
9246 // We assume tsec fits into 32 bits; 32 bits holds enough
9247 // seconds for 136 years since the epoch in 1970.
9248 clock_get_calendar_microtime(&tsec
, &tusec
);
9251 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9253 *recordTS
|= (uint32_t)tusec
;
9254 *recordTS
|= ((uint64_t)tsec
<< 32);
9260 // MARK: IORootParent
9262 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9264 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9266 // The reason that root domain needs a root parent is to facilitate demand
9267 // sleep, since a power change from the root parent cannot be vetoed.
9269 // The above statement is no longer true since root domain now performs
9270 // demand sleep using overrides. But root parent remains to avoid changing
9271 // the power tree stacking. Root parent is parked at the max power state.
9274 static IOPMPowerState patriarchPowerStates
[2] =
9276 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9277 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9280 void IORootParent::initialize( void )
9284 bool IORootParent::start( IOService
* nub
)
9286 IOService::start(nub
);
9287 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9289 registerPowerDriver(this, patriarchPowerStates
, 2);
9294 void IORootParent::shutDownSystem( void )
9298 void IORootParent::restartSystem( void )
9302 void IORootParent::sleepSystem( void )
9306 void IORootParent::dozeSystem( void )
9310 void IORootParent::sleepToDoze( void )
9314 void IORootParent::wakeSystem( void )
9318 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9320 return (IOService::copyProperty(aKey
));
9324 #if defined(__i386__) || defined(__x86_64__)
9325 IOReturn
IOPMrootDomain::restartWithStackshot()
9327 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9328 return kIOReturnError
;
9330 takeStackshot(true, true, false);
9332 return kIOReturnSuccess
;
9335 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9337 takeStackshot(wdogTrigger
, false, false);
9340 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9342 swd_hdr
* hdr
= NULL
;
9344 int wdog_panic
= -1;
9347 kern_return_t kr
= KERN_SUCCESS
;
9352 uint32_t bytesRemaining
;
9353 unsigned bytesWritten
= 0;
9354 unsigned totalBytes
= 0;
9356 OSString
* UUIDstring
= NULL
;
9358 IOMemoryMap
* logBufMap
= NULL
;
9362 uint32_t initialStackSize
;
9365 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9366 _systemTransitionType
!= kSystemTransitionWake
)
9369 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9374 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9375 if (wdog_panic
== 1) {
9376 // If boot-arg specifies to panic then panic.
9377 panic("Sleep/Wake hang detected\n");
9380 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9381 // If current boot is due to this watch dog trigger restart in previous boot,
9382 // then don't trigger again until at least 1 successful sleep & wake.
9383 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9384 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9385 PEHaltRestart(kPEHaltCPU
);
9393 if (gSpinDumpBufferFull
)
9395 if (swd_spindump_buffer
== NULL
) {
9396 sleepWakeDebugSpinDumpMemAlloc();
9397 if (swd_spindump_buffer
== NULL
) return;
9400 bufSize
= SWD_SPINDUMP_SIZE
;
9401 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9403 if (sleepWakeDebugIsWdogEnabled() == false)
9406 if (swd_buffer
== NULL
) {
9407 sleepWakeDebugMemAlloc();
9408 if (swd_buffer
== NULL
) return;
9411 bufSize
= SWD_BUF_SIZE
;
9412 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9415 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9419 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9422 hdr
= (swd_hdr
*)swd_buffer
;
9425 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9426 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9428 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9429 const char *str
= UUIDstring
->getCStringNoCopy();
9430 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9433 DLOG("Data for current UUID already exists\n");
9438 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9439 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9441 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9442 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9444 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9446 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9447 while (kr
== KERN_SUCCESS
) {
9451 * Take stackshot of all process on first sample. Size is restricted
9452 * to SWD_INITIAL_STACK_SIZE
9455 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9456 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9459 /* Take sample of kernel threads only */
9461 size
= bytesRemaining
;
9464 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9465 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9466 kr
, pid
, size
, flags
, bytesWritten
);
9467 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9469 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9470 // Continue to take stackshot of just kernel threads
9475 else if (totalBytes
== 0) {
9476 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9480 dstAddr
+= bytesWritten
;
9481 totalBytes
+= bytesWritten
;
9482 bytesRemaining
-= bytesWritten
;
9487 IOSleep(10); // 10 ms
9490 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9493 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9494 code
= pmTracer
->getPMStatusCode();
9495 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9496 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9497 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9498 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9500 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9501 gRootDomain
->swd_lock
= 0;
9502 gSpinDumpBufferFull
= true;
9505 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9508 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9509 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9510 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9511 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9512 len
= sizeof(addr64_t
)*3;
9513 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9514 data
[0], data
[1], data
[2]);
9516 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9518 DLOG("Failed to update nvram boot-args\n");
9524 gRootDomain
->swd_lock
= 0;
9527 IOLog("Restarting to collect Sleep wake debug logs\n");
9528 PEHaltRestart(kPERestartCPU
);
9531 logBufMap
= sleepWakeDebugRetrieve();
9533 sleepWakeDebugDumpFromMem(logBufMap
);
9534 logBufMap
->release();
9540 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9542 vm_size_t size
= SWD_BUF_SIZE
;
9544 swd_hdr
*hdr
= NULL
;
9546 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9549 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9552 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9555 // Try allocating above 4GB. If that fails, try at 2GB
9556 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9557 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9558 size
, 0xFFFFFFFF00000000ULL
);
9560 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9561 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9562 size
, 0xFFFFFFFF10000000ULL
);
9565 if (memDesc
== NULL
)
9567 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9572 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9573 memset(hdr
, 0, sizeof(swd_hdr
));
9575 hdr
->signature
= SWD_HDR_SIGNATURE
;
9576 hdr
->alloc_size
= size
;
9578 hdr
->spindump_offset
= sizeof(swd_hdr
);
9579 swd_buffer
= (void *)hdr
;
9580 swd_memDesc
= memDesc
;
9581 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9584 gRootDomain
->swd_lock
= 0;
9587 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9589 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9591 swd_hdr
*hdr
= NULL
;
9593 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9595 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9598 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9599 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9602 if (memDesc
== NULL
)
9604 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9609 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9610 memset(hdr
, 0, sizeof(swd_hdr
));
9612 hdr
->signature
= SWD_HDR_SIGNATURE
;
9613 hdr
->alloc_size
= size
;
9615 hdr
->spindump_offset
= sizeof(swd_hdr
);
9616 swd_spindump_buffer
= (void *)hdr
;
9619 gRootDomain
->swd_lock
= 0;
9622 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9624 swd_flags
|= SWD_WDOG_ENABLED
;
9626 sleepWakeDebugMemAlloc();
9629 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9631 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9632 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9635 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9637 swd_hdr
*hdr
= NULL
;
9638 errno_t error
= EIO
;
9640 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9641 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9643 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9644 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9648 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9649 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9650 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9652 gSpinDumpBufferFull
= false;
9656 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9658 struct vnode
*vp
= NULL
;
9659 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9660 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9661 struct vnode_attr va
;
9662 errno_t error
= EIO
;
9664 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9665 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9667 IOLog("Failed to open the file %s\n", name
);
9668 swd_flags
|= SWD_FILEOP_ERROR
;
9672 VATTR_WANTED(&va
, va_nlink
);
9673 /* Don't dump to non-regular files or files with links. */
9674 if (vp
->v_type
!= VREG
||
9675 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9676 IOLog("Bailing as this is not a regular file\n");
9677 swd_flags
|= SWD_FILEOP_ERROR
;
9681 VATTR_SET(&va
, va_data_size
, 0);
9682 vnode_setattr(vp
, &va
, ctx
);
9686 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9687 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9689 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9690 swd_flags
|= SWD_FILEOP_ERROR
;
9693 DLOG("Saved %d bytes to file %s\n",len
, name
);
9698 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9699 if (ctx
) vfs_context_rele(ctx
);
9705 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9706 struct vnode
*srcVp
,
9707 vfs_context_t srcCtx
,
9708 char *tmpBuf
, uint64_t tmpBufSize
,
9710 const char *dstFname
,
9714 struct vnode
*vp
= NULL
;
9715 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9716 struct vnode_attr va
;
9717 errno_t error
= EIO
;
9718 uint64_t bytesToRead
, bytesToWrite
;
9719 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9720 uint32_t newcrc
= 0;
9722 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9723 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9725 IOLog("Failed to open the file %s\n", dstFname
);
9726 swd_flags
|= SWD_FILEOP_ERROR
;
9730 VATTR_WANTED(&va
, va_nlink
);
9731 /* Don't dump to non-regular files or files with links. */
9732 if (vp
->v_type
!= VREG
||
9733 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9734 IOLog("Bailing as this is not a regular file\n");
9735 swd_flags
|= SWD_FILEOP_ERROR
;
9739 VATTR_SET(&va
, va_data_size
, 0);
9740 vnode_setattr(vp
, &va
, ctx
);
9742 writeFileOffset
= 0;
9744 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9745 readFileOffset
= trunc_page(srcOffset
);
9747 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9748 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9749 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9750 vfs_context_ucred(srcCtx
), (int *) 0,
9751 vfs_context_proc(srcCtx
));
9753 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9754 swd_flags
|= SWD_FILEOP_ERROR
;
9758 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9759 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9760 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9763 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9765 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9766 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9767 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9768 vfs_context_ucred(ctx
), (int *) 0,
9769 vfs_context_proc(ctx
));
9771 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9772 swd_flags
|= SWD_FILEOP_ERROR
;
9776 writeFileOffset
+= bytesToWrite
;
9777 numBytes
-= bytesToWrite
;
9778 srcOffset
+= bytesToWrite
;
9781 if (crc
!= newcrc
) {
9782 /* Set stackshot size to 0 if crc doesn't match */
9784 VATTR_SET(&va
, va_data_size
, 0);
9785 vnode_setattr(vp
, &va
, ctx
);
9787 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9788 swd_flags
|= SWD_DATA_CRC_ERROR
;
9793 error
= vnode_close(vp
, FWRITE
, ctx
);
9794 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
9796 if (ctx
) vfs_context_rele(ctx
);
9803 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9804 void *tmpBuf
, struct vnode
**vp
)
9810 struct vnode_attr va
;
9811 IOHibernateImageHeader
*imageHdr
;
9814 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9815 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9817 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9821 VATTR_WANTED(&va
, va_nlink
);
9822 VATTR_WANTED(&va
, va_data_alloc
);
9823 if ((*vp
)->v_type
!= VREG
||
9824 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9825 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9826 error
= SWD_FILEOP_ERROR
;
9830 /* Read the sleepimage file header */
9831 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9832 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9833 vfs_context_ucred(*ctx
), (int *) 0,
9834 vfs_context_proc(*ctx
));
9836 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9837 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9838 error
= SWD_FILEOP_ERROR
;
9842 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9843 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9844 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9845 fname
, imageHdr
->signature
);
9846 error
= SWD_HDR_SIGNATURE_ERROR
;
9850 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9851 hdrOffset
= imageHdr
->deviceBlockSize
;
9852 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9853 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9854 va
.va_data_alloc
, fname
);
9855 error
= SWD_HDR_SIZE_ERROR
;
9862 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9868 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9872 char hibernateFilename
[MAXPATHLEN
+1];
9874 swd_hdr
*hdr
= NULL
;
9875 uint32_t stacksSize
, logSize
;
9876 uint64_t tmpBufSize
;
9877 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9878 errno_t error
= EIO
;
9879 OSObject
*obj
= NULL
;
9880 OSString
*str
= NULL
;
9881 OSNumber
*failStat
= NULL
;
9882 struct vnode
*vp
= NULL
;
9883 vfs_context_t ctx
= NULL
;
9884 const char *stacksFname
, *logFname
;
9886 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9888 DLOG("sleepWakeDebugDumpFromFile\n");
9889 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9892 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9896 /* Allocate a temp buffer to copy data between files */
9897 tmpBufSize
= 2*4096;
9898 tmpBufDesc
= IOBufferMemoryDescriptor::
9899 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9900 tmpBufSize
, PAGE_SIZE
);
9903 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9907 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9909 ctx
= vfs_context_create(vfs_context_current());
9911 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9912 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9914 /* Check if the debug data is saved to hibernation file */
9915 hibernateFilename
[0] = 0;
9916 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9918 if ((str
= OSDynamicCast(OSString
, obj
)))
9919 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9920 sizeof(hibernateFilename
));
9923 if (!hibernateFilename
[0]) {
9924 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9928 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9930 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9933 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9936 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9939 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9941 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9942 /* Read the sleep/wake debug header(swd_hdr) */
9943 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9944 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9945 vfs_context_ucred(ctx
), (int *) 0,
9946 vfs_context_proc(ctx
));
9948 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9949 round_page(sizeof(swd_hdr
)), rc
);
9950 swd_flags
|= SWD_FILEOP_ERROR
;
9954 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9955 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9956 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9957 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9958 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9959 swd_flags
|= SWD_BUF_SIZE_ERROR
;
9962 stacksSize
= hdr
->spindump_size
;
9964 /* Get stacks & log offsets in the image file */
9965 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9966 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9967 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9968 stacksFname
= getDumpStackFilename(hdr
);
9969 logFname
= getDumpLogFilename(hdr
);
9971 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9972 stacksFname
, stacksSize
, hdr
->crc
);
9973 if (error
== EFAULT
) {
9974 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9977 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9978 logFname
, logSize
, 0);
9980 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9985 // Write just the SleepWakeLog.dump with failure code
9989 char *offset
= NULL
;
9993 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9994 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9995 fcode
= failStat
->unsigned64BitValue();
9996 fname
= kSleepWakeLogFilename
;
9999 fname
= kAppleOSXWatchdogLogFilename
;
10002 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10003 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10004 memset(offset
, 0x20, size
); // Fill with spaces
10007 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10008 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10009 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10010 sleepWakeDebugSaveFile(fname
, offset
, size
);
10013 gRootDomain
->swd_lock
= 0;
10015 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10016 if (ctx
) vfs_context_rele(ctx
);
10017 if (tmpBufDesc
) tmpBufDesc
->release();
10018 #endif /* HIBERNATION */
10021 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10023 IOVirtualAddress srcBuf
= NULL
;
10024 char *stackBuf
= NULL
, *logOffset
= NULL
;
10027 errno_t error
= EIO
;
10028 uint64_t bufSize
= 0;
10029 swd_hdr
*hdr
= NULL
;
10030 OSNumber
*failStat
= NULL
;
10032 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10035 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10037 DLOG("Nothing saved to dump to file\n");
10041 hdr
= (swd_hdr
*)srcBuf
;
10042 bufSize
= logBufMap
->getLength();
10043 if (bufSize
<= sizeof(swd_hdr
))
10045 IOLog("SleepWake log buffer size is invalid\n");
10046 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10050 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10052 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10053 if (error
) goto exit
;
10055 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10056 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10058 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10059 if (error
) goto exit
;
10061 hdr
->spindump_size
= 0;
10066 // Write just the SleepWakeLog.dump with failure code
10067 uint64_t fcode
= 0;
10068 const char *sname
, *lname
;
10071 /* Try writing an empty stacks file */
10073 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10074 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10075 fcode
= failStat
->unsigned64BitValue();
10076 lname
= kSleepWakeLogFilename
;
10077 sname
= kSleepWakeStackFilename
;
10080 lname
= kAppleOSXWatchdogLogFilename
;
10081 sname
= kAppleOSXWatchdogStackFilename
;
10084 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10086 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10087 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10088 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10091 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10092 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10093 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10094 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10097 gRootDomain
->swd_lock
= 0;
10100 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10102 IOVirtualAddress vaddr
= NULL
;
10103 IOMemoryDescriptor
* desc
= NULL
;
10104 IOMemoryMap
* logBufMap
= NULL
;
10106 uint32_t len
= INT_MAX
;
10108 uint64_t bufSize
= 0;
10110 uint64_t newcrc
= 0;
10111 uint64_t paddr
= 0;
10112 swd_hdr
*hdr
= NULL
;
10117 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10120 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10121 DLOG("No sleepWakeDebug note to read\n");
10125 if (len
== strlen("sleepimage")) {
10127 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10129 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10130 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10131 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10135 else if (len
== sizeof(addr64_t
)*3) {
10136 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10139 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10145 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10146 data
[0], data
[1], data
[2]);
10147 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10151 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10153 IOLog("SleepWake log buffer size is invalid\n");
10154 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10158 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10159 bufSize
, crc
, paddr
);
10162 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10163 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10166 IOLog("Fail to map SleepWake log buffer\n");
10167 swd_flags
|= SWD_INTERNAL_FAILURE
;
10171 logBufMap
= desc
->map();
10173 vaddr
= logBufMap
->getVirtualAddress();
10176 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10177 IOLog("Fail to map SleepWake log buffer\n");
10178 swd_flags
|= SWD_INTERNAL_FAILURE
;
10182 hdr
= (swd_hdr
*)vaddr
;
10183 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10185 IOLog("SleepWake log header size is invalid\n");
10186 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10191 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10192 hdr
->spindump_size
);
10193 if (newcrc
!= crc
) {
10194 IOLog("SleepWake log buffer contents are invalid\n");
10195 swd_flags
|= SWD_DATA_CRC_ERROR
;
10200 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10204 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10206 if (logBufMap
) logBufMap
->release();
10209 if (desc
) desc
->release();
10210 gRootDomain
->swd_lock
= 0;
10217 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10219 uint32_t wdog_panic
= 1;
10222 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10223 (wdog_panic
== 0)) {
10226 panic("Sleep/Wake hang detected\n");
10231 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10233 #pragma unused(restart)
10234 #pragma unused(isOSXWatchdog)
10237 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10240 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10243 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10244 struct vnode
*srcVp
,
10245 vfs_context_t srcCtx
,
10246 char *tmpBuf
, uint64_t tmpBufSize
,
10247 uint64_t srcOffset
,
10248 const char *dstFname
,
10255 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10259 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10264 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10268 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10273 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)