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>
51 #include <IOKit/IOHibernatePrivate.h>
53 #include <console/video_console.h>
54 #include <sys/syslog.h>
55 #include <sys/sysctl.h>
56 #include <sys/vnode.h>
57 #include <sys/vnode_internal.h>
58 #include <sys/fcntl.h>
61 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
62 #include "IOServicePMPrivate.h"
65 #include <mach/shared_region.h>
68 #if defined(__i386__) || defined(__x86_64__)
70 #include "IOPMrootDomainInternal.h"
74 #define kIOPMrootDomainClass "IOPMrootDomain"
75 #define LOG_PREFIX "PMRD: "
79 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
82 do { kprintf(LOG_PREFIX x); } while (false)
84 #define DLOG(x...) do { \
85 if (kIOLogPMRootDomain & gIOKitDebug) \
86 kprintf(LOG_PREFIX x); \
89 #define DMSG(x...) do { \
90 if (kIOLogPMRootDomain & gIOKitDebug) { \
91 kprintf(LOG_PREFIX x); IOLog(x); \
98 #define CHECK_THREAD_CONTEXT
99 #ifdef CHECK_THREAD_CONTEXT
100 static IOWorkLoop
* gIOPMWorkLoop
= 0;
101 #define ASSERT_GATED() \
103 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
104 panic("RootDomain: not inside PM gate"); \
108 #define ASSERT_GATED()
109 #endif /* CHECK_THREAD_CONTEXT */
111 #define CAP_LOSS(c) \
112 (((_pendingCapability & (c)) == 0) && \
113 ((_currentCapability & (c)) != 0))
115 #define CAP_GAIN(c) \
116 (((_currentCapability & (c)) == 0) && \
117 ((_pendingCapability & (c)) != 0))
119 #define CAP_CHANGE(c) \
120 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
122 #define CAP_CURRENT(c) \
123 ((_currentCapability & (c)) != 0)
125 #define CAP_HIGHEST(c) \
126 ((_highestCapability & (c)) != 0)
128 #if defined(__i386__) || defined(__x86_64__)
129 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
132 // Event types for IOPMPowerStateQueue::submitPowerEvent()
134 kPowerEventFeatureChanged
= 1, // 1
135 kPowerEventReceivedPowerNotification
, // 2
136 kPowerEventSystemBootCompleted
, // 3
137 kPowerEventSystemShutdown
, // 4
138 kPowerEventUserDisabledSleep
, // 5
139 kPowerEventRegisterSystemCapabilityClient
, // 6
140 kPowerEventRegisterKernelCapabilityClient
, // 7
141 kPowerEventPolicyStimulus
, // 8
142 kPowerEventAssertionCreate
, // 9
143 kPowerEventAssertionRelease
, // 10
144 kPowerEventAssertionSetLevel
, // 11
145 kPowerEventQueueSleepWakeUUID
, // 12
146 kPowerEventPublishSleepWakeUUID
, // 13
147 kPowerEventSetDisplayPowerOn
// 14
150 // For evaluatePolicy()
151 // List of stimuli that affects the root domain policy.
153 kStimulusDisplayWranglerSleep
, // 0
154 kStimulusDisplayWranglerWake
, // 1
155 kStimulusAggressivenessChanged
, // 2
156 kStimulusDemandSystemSleep
, // 3
157 kStimulusAllowSystemSleepChanged
, // 4
158 kStimulusDarkWakeActivityTickle
, // 5
159 kStimulusDarkWakeEntry
, // 6
160 kStimulusDarkWakeReentry
, // 7
161 kStimulusDarkWakeEvaluate
, // 8
162 kStimulusNoIdleSleepPreventers
, // 9
163 kStimulusEnterUserActiveState
, // 10
164 kStimulusLeaveUserActiveState
// 11
168 IOReturn
OSKextSystemSleepOrWake( UInt32
);
170 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
171 extern "C" addr64_t
kvtophys(vm_offset_t va
);
172 extern "C" int stack_snapshot_from_kernel(pid_t pid
, void *buf
, uint32_t size
, uint32_t flags
, unsigned *bytesTraced
);
174 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
175 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
176 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
177 static void pmEventTimeStamp(uint64_t *recordTS
);
179 // "IOPMSetSleepSupported" callPlatformFunction name
180 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
181 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
183 #define kIOSleepSupportedKey "IOSleepSupported"
184 #define kIOPMSystemCapabilitiesKey "System Capabilities"
186 #define kIORequestWranglerIdleKey "IORequestIdle"
187 #define kDefaultWranglerIdlePeriod 25 // in milliseconds
189 #define kIOSleepWakeDebugKey "Persistent-memory-note"
191 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
192 | kIOPMSupportedOnBatt \
193 | kIOPMSupportedOnUPS)
197 // not idle around autowake time, secs
198 kAutoWakePreWindow
= 45,
199 kAutoWakePostWindow
= 15
202 #define kLocalEvalClamshellCommand (1 << 15)
203 #define kIdleSleepRetryInterval (3 * 60)
206 kWranglerPowerStateMin
= 0,
207 kWranglerPowerStateSleep
= 2,
208 kWranglerPowerStateDim
= 3,
209 kWranglerPowerStateMax
= 4
220 #define ON_POWER kIOPMPowerOn
221 #define RESTART_POWER kIOPMRestart
222 #define SLEEP_POWER kIOPMAuxPowerOn
224 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
226 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
227 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
228 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
229 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
232 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
233 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
234 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
235 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
236 #define kIOPMRootDomainWakeTypeUser "User"
237 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
238 #define kIOPMRootDomainWakeTypeNetwork "Network"
239 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
240 #define kIOPMRootDomainWakeTypeNotification "Notification"
241 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
243 // Special interest that entitles the interested client from receiving
244 // all system messages. Only used by powerd.
246 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
248 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
249 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
254 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
255 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
257 #define kAggressivesMinValue 1
260 kAggressivesStateBusy
= 0x01,
261 kAggressivesStateQuickSpindown
= 0x02
264 struct AggressivesRecord
{
270 struct AggressivesRequest
{
276 AggressivesRecord record
;
281 kAggressivesRequestTypeService
= 1,
282 kAggressivesRequestTypeRecord
286 kAggressivesOptionSynchronous
= 0x00000001,
287 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
288 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
289 kAggressivesOptionQuickSpindownMask
= 0x00000300
293 kAggressivesRecordFlagModified
= 0x00000001,
294 kAggressivesRecordFlagMinValue
= 0x00000002
299 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
300 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
301 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
302 kDarkWakeFlagHIDTickleMask
= 0x03,
303 kDarkWakeFlagAlarmIsDark
= 0x0100,
304 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
305 kDarkWakeFlagAudioNotSuppressed
= 0x0400
308 static IOPMrootDomain
* gRootDomain
;
309 static IONotifier
* gSysPowerDownNotifier
= 0;
310 static UInt32 gSleepOrShutdownPending
= 0;
311 static UInt32 gWillShutdown
= 0;
312 static UInt32 gPagingOff
= 0;
313 static UInt32 gSleepWakeUUIDIsSet
= false;
314 static uint32_t gAggressivesState
= 0;
316 uuid_string_t bootsessionuuid_string
;
318 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
319 static PMStatsStruct gPMStats
;
322 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
323 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
324 static void * gSleepPolicyTarget
;
327 struct timeval gIOLastSleepTime
;
328 struct timeval gIOLastWakeTime
;
330 static char gWakeReasonString
[128];
331 static bool gWakeReasonSysctlRegistered
= false;
333 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
334 #define kCPUUnknownIndex 9999999
341 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
342 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
343 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
344 const OSSymbol
*gIOPMStatsApplicationResponsePrompt
;
345 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
347 #define kBadPMFeatureID 0
351 * Opaque handle passed to clients of registerPMSettingController()
353 class PMSettingHandle
: public OSObject
355 OSDeclareFinalStructors( PMSettingHandle
)
356 friend class PMSettingObject
;
359 PMSettingObject
*pmso
;
365 * Internal object to track each PM setting controller
367 class PMSettingObject
: public OSObject
369 OSDeclareFinalStructors( PMSettingObject
)
370 friend class IOPMrootDomain
;
373 queue_head_t calloutQueue
;
375 IOPMrootDomain
*parent
;
376 PMSettingHandle
*pmsh
;
377 IOPMSettingControllerCallback func
;
380 uint32_t *publishedFeatureID
;
381 uint32_t settingCount
;
387 static PMSettingObject
*pmSettingObject(
388 IOPMrootDomain
*parent_arg
,
389 IOPMSettingControllerCallback handler_arg
,
390 OSObject
*target_arg
,
391 uintptr_t refcon_arg
,
392 uint32_t supportedPowerSources
,
393 const OSSymbol
*settings
[],
394 OSObject
**handle_obj
);
396 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
397 void clientHandleFreed(void);
400 struct PMSettingCallEntry
{
405 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
406 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
407 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
408 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
412 * Internal helper object for logging trace points to RTC
413 * IOPMrootDomain and only IOPMrootDomain should instantiate
414 * exactly one of these.
417 typedef void (*IOPMTracePointHandler
)(
418 void * target
, uint32_t code
, uint32_t data
);
420 class PMTraceWorker
: public OSObject
422 OSDeclareDefaultStructors(PMTraceWorker
)
424 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
426 static PMTraceWorker
*tracer( IOPMrootDomain
* );
427 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
428 void tracePoint(uint8_t phase
);
429 void tracePoint(uint8_t phase
, uint8_t data8
);
430 void traceDetail(uint32_t detail
);
431 void traceLoginWindowPhase(uint8_t phase
);
432 int recordTopLevelPCIDevice(IOService
*);
433 void RTC_TRACE(void);
434 virtual bool serialize(OSSerialize
*s
) const;
436 IOPMTracePointHandler tracePointHandler
;
437 void * tracePointTarget
;
438 uint64_t getPMStatusCode();
440 IOPMrootDomain
*owner
;
441 IOLock
*pciMappingLock
;
442 OSArray
*pciDeviceBitMappings
;
444 uint8_t addedToRegistry
;
446 uint8_t loginWindowPhase
;
448 uint32_t traceData32
;
452 * PMAssertionsTracker
453 * Tracks kernel and user space PM assertions
455 class PMAssertionsTracker
: public OSObject
457 OSDeclareFinalStructors(PMAssertionsTracker
)
459 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
461 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
462 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
463 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
464 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
466 OSArray
*copyAssertionsArray(void);
467 IOPMDriverAssertionType
getActivatedAssertions(void);
468 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
470 IOReturn
handleCreateAssertion(OSData
*);
471 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
472 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
473 IOReturn
handleSetUserAssertionLevels(void * arg0
);
474 void publishProperties(void);
478 IOPMDriverAssertionID id
;
479 IOPMDriverAssertionType assertionBits
;
480 uint64_t createdTime
;
481 uint64_t modifiedTime
;
482 const OSSymbol
*ownerString
;
483 IOService
*ownerService
;
484 uint64_t registryEntryID
;
485 IOPMDriverAssertionLevel level
;
488 uint32_t tabulateProducerCount
;
489 uint32_t tabulateConsumerCount
;
491 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
494 IOPMrootDomain
*owner
;
495 OSArray
*assertionsArray
;
496 IOLock
*assertionsArrayLock
;
497 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
498 IOPMDriverAssertionType assertionsKernel
;
499 IOPMDriverAssertionType assertionsUser
;
500 IOPMDriverAssertionType assertionsCombined
;
503 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
507 * Internal helper object for Shutdown/Restart notifications.
509 #define kPMHaltMaxWorkers 8
510 #define kPMHaltTimeoutMS 100
512 class PMHaltWorker
: public OSObject
514 OSDeclareFinalStructors( PMHaltWorker
)
517 IOService
* service
; // service being worked on
518 AbsoluteTime startTime
; // time when work started
519 int depth
; // work on nubs at this PM-tree depth
520 int visits
; // number of nodes visited (debug)
522 bool timeout
; // service took too long
524 static PMHaltWorker
* worker( void );
525 static void main( void * arg
, wait_result_t waitResult
);
526 static void work( PMHaltWorker
* me
);
527 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
528 virtual void free( void );
531 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
534 #define super IOService
535 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
537 static void IOPMRootDomainWillShutdown(void)
539 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
541 OSKext::willShutdown();
542 for (int i
= 0; i
< 100; i
++)
544 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
552 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
554 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
557 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
559 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
562 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
564 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
567 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
569 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
572 IOReturn
rootDomainRestart ( void )
574 return gRootDomain
->restartSystem();
577 IOReturn
rootDomainShutdown ( void )
579 return gRootDomain
->shutdownSystem();
582 void IOSystemShutdownNotification(void)
584 IOPMRootDomainWillShutdown();
585 if (OSCompareAndSwap(0, 1, &gPagingOff
))
587 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
591 int sync_internal(void);
595 A device is always in the highest power state which satisfies its driver,
596 its policy-maker, and any power children it has, but within the constraint
597 of the power state provided by its parent. The driver expresses its desire by
598 calling changePowerStateTo(), the policy-maker expresses its desire by calling
599 changePowerStateToPriv(), and the children express their desires by calling
600 requestPowerDomainState().
602 The Root Power Domain owns the policy for idle and demand sleep for the system.
603 It is a power-managed IOService just like the others in the system.
604 It implements several power states which map to what we see as Sleep and On.
606 The sleep policy is as follows:
607 1. Sleep is prevented if the case is open so that nobody will think the machine
608 is off and plug/unplug cards.
609 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
610 3. System cannot Sleep if some object in the tree is in a power state marked
611 kIOPMPreventSystemSleep.
613 These three conditions are enforced using the "driver clamp" by calling
614 changePowerStateTo(). For example, if the case is opened,
615 changePowerStateTo(ON_STATE) is called to hold the system on regardless
616 of the desires of the children of the root or the state of the other clamp.
618 Demand Sleep is initiated by pressing the front panel power button, closing
619 the clamshell, or selecting the menu item. In this case the root's parent
620 actually initiates the power state change so that the root domain has no
621 choice and does not give applications the opportunity to veto the change.
623 Idle Sleep occurs if no objects in the tree are in a state marked
624 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
625 the root on, so it sets the "policy-maker clamp" by calling
626 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
627 This timer is set for the difference between the sleep timeout slider and the
628 display dim timeout slider. When the timer expires, it releases its clamp and
629 now nothing is holding it awake, so it falls asleep.
631 Demand sleep is prevented when the system is booting. When preferences are
632 transmitted by the loginwindow at the end of boot, a flag is cleared,
633 and this allows subsequent Demand Sleep.
636 //******************************************************************************
638 IOPMrootDomain
* IOPMrootDomain::construct( void )
640 IOPMrootDomain
*root
;
642 root
= new IOPMrootDomain
;
649 //******************************************************************************
651 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
653 IOService
* rootDomain
= (IOService
*) p0
;
654 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
655 uint32_t powerState
= rootDomain
->getPowerState();
657 DLOG("disk_sync_callout ps=%u\n", powerState
);
659 if (ON_STATE
== powerState
)
666 IOHibernateSystemPostWake();
670 rootDomain
->allowPowerChange(notifyRef
);
671 DLOG("disk_sync_callout finish\n");
674 //******************************************************************************
676 static void hib_debugSetup_callout( thread_call_param_t p0
, thread_call_param_t p1
)
678 IOService
* rootDomain
= (IOService
*) p0
;
679 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
682 IOHibernateOpenForDebugData();
685 rootDomain
->allowPowerChange(notifyRef
);
686 DLOG("hib_debugSetup_callout finish\n");
688 //******************************************************************************
690 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
692 AbsoluteTime endTime
;
695 clock_get_uptime(&endTime
);
696 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
698 SUB_ABSOLUTETIME(&endTime
, startTime
);
699 absolutetime_to_nanoseconds(endTime
, &nano
);
702 return (UInt32
)(nano
/ 1000000ULL);
705 //******************************************************************************
708 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
710 struct timeval
*swt
= (struct timeval
*)arg1
;
711 struct proc
*p
= req
->p
;
714 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
715 } else if(proc_is64bit(p
)) {
716 struct user64_timeval t
;
717 t
.tv_sec
= swt
->tv_sec
;
718 t
.tv_usec
= swt
->tv_usec
;
719 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
721 struct user32_timeval t
;
722 t
.tv_sec
= swt
->tv_sec
;
723 t
.tv_usec
= swt
->tv_usec
;
724 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
728 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
729 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
730 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
732 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
733 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
734 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
739 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
741 int new_value
, changed
;
742 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
744 if (!gWillShutdown
&& (new_value
== 1)) {
745 IOPMRootDomainWillShutdown();
752 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
753 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
754 0, 0, sysctl_willshutdown
, "I", "");
758 sysctl_progressmeterenable
759 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
762 int new_value
, changed
;
764 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
766 if (changed
) vc_enable_progressmeter(new_value
);
773 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
776 int new_value
, changed
;
778 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
780 if (changed
) vc_set_progressmeter(new_value
);
785 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
786 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
787 0, 0, sysctl_progressmeterenable
, "I", "");
789 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
790 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
791 0, 0, sysctl_progressmeter
, "I", "");
795 sysctl_wakereason SYSCTL_HANDLER_ARGS
797 char wr
[ sizeof(gWakeReasonString
) ];
801 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
803 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
806 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
807 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
808 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
810 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
812 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
813 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
814 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
815 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
816 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
817 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
818 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
819 static const OSSymbol
* gIOPMUserIsActiveKey
;
821 //******************************************************************************
824 //******************************************************************************
826 #define kRootDomainSettingsCount 17
828 bool IOPMrootDomain::start( IOService
* nub
)
830 OSIterator
*psIterator
;
831 OSDictionary
*tmpDict
;
832 IORootParent
* patriarch
;
833 #if defined(__i386__) || defined(__x86_64__)
834 IONotifier
* notifier
;
840 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
841 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
842 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
843 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
844 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
845 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
846 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
847 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
849 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
850 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
851 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
852 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
853 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
855 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
856 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
858 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
860 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
861 gIOPMSettingAutoWakeSecondsKey
,
862 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
863 gIOPMSettingAutoWakeCalendarKey
,
864 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
865 gIOPMSettingDebugWakeRelativeKey
,
866 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
867 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
868 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
869 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
870 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
871 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
872 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
873 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
874 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
875 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
876 gIOPMSettingSilentRunningKey
879 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
881 queue_init(&aggressivesQueue
);
882 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
883 aggressivesData
= OSData::withCapacity(
884 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
886 featuresDictLock
= IOLockAlloc();
887 settingsCtrlLock
= IOLockAlloc();
888 wakeEventLock
= IOLockAlloc();
889 setPMRootDomain(this);
891 extraSleepTimer
= thread_call_allocate(
892 idleSleepTimerExpired
,
893 (thread_call_param_t
) this);
895 diskSyncCalloutEntry
= thread_call_allocate(
897 (thread_call_param_t
) this);
898 hibDebugSetupEntry
= thread_call_allocate(
899 &hib_debugSetup_callout
,
900 (thread_call_param_t
) this);
902 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
903 fullWakeThreadCall
= thread_call_allocate(
904 OSMemberFunctionCast(thread_call_func_t
, this,
905 &IOPMrootDomain::fullWakeDelayedWork
),
906 (thread_call_param_t
) this);
909 setProperty(kIOSleepSupportedKey
, true);
911 bzero(&gPMStats
, sizeof(gPMStats
));
913 pmTracer
= PMTraceWorker::tracer(this);
915 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
917 userDisabledAllSleep
= false;
918 systemBooting
= true;
920 idleSleepTimerPending
= false;
922 clamshellClosed
= false;
923 clamshellExists
= false;
924 clamshellDisabled
= true;
925 acAdaptorConnected
= true;
926 clamshellSleepDisabled
= false;
927 gWakeReasonString
[0] = '\0';
929 // Initialize to user active.
930 // Will never transition to user inactive w/o wrangler.
931 fullWakeReason
= kFullWakeReasonLocalUser
;
932 userIsActive
= userWasActive
= true;
933 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
935 // Set the default system capabilities at boot.
936 _currentCapability
= kIOPMSystemCapabilityCPU
|
937 kIOPMSystemCapabilityGraphics
|
938 kIOPMSystemCapabilityAudio
|
939 kIOPMSystemCapabilityNetwork
;
941 _pendingCapability
= _currentCapability
;
942 _desiredCapability
= _currentCapability
;
943 _highestCapability
= _currentCapability
;
944 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
946 queuedSleepWakeUUIDString
= NULL
;
947 initializeBootSessionUUID();
948 pmStatsAppResponses
= OSArray::withCapacity(5);
949 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
950 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
951 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
952 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
953 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
954 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
956 pmStatsLock
= IOLockAlloc();
957 idxPMCPUClamshell
= kCPUUnknownIndex
;
958 idxPMCPULimitedPower
= kCPUUnknownIndex
;
960 tmpDict
= OSDictionary::withCapacity(1);
961 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
964 settingsCallbacks
= OSDictionary::withCapacity(1);
966 // Create a list of the valid PM settings that we'll relay to
967 // interested clients in setProperties() => setPMSetting()
968 allowedPMSettings
= OSArray::withObjects(
969 (const OSObject
**)settingsArr
,
970 kRootDomainSettingsCount
,
973 // List of PM settings that should not automatically publish itself
974 // as a feature when registered by a listener.
975 noPublishPMSettings
= OSArray::withObjects(
976 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
978 fPMSettingsDict
= OSDictionary::withCapacity(5);
979 preventIdleSleepList
= OSSet::withCapacity(8);
980 preventSystemSleepList
= OSSet::withCapacity(2);
982 PMinit(); // creates gIOPMWorkLoop
984 // Create IOPMPowerStateQueue used to queue external power
985 // events, and to handle those events on the PM work loop.
986 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
987 this, OSMemberFunctionCast(IOEventSource::Action
, this,
988 &IOPMrootDomain::dispatchPowerEvent
));
989 getPMworkloop()->addEventSource(pmPowerStateQueue
);
990 #ifdef CHECK_THREAD_CONTEXT
991 gIOPMWorkLoop
= getPMworkloop();
994 // create our power parent
995 patriarch
= new IORootParent
;
997 patriarch
->attach(this);
998 patriarch
->start(this);
999 patriarch
->addPowerChild(this);
1001 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1002 changePowerStateToPriv(ON_STATE
);
1004 // install power change handler
1005 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1008 // Register for a notification when IODisplayWrangler is published
1009 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1011 _displayWranglerNotifier
= addMatchingNotification(
1012 gIOPublishNotification
, tmpDict
,
1013 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1019 #if defined(__i386__) || defined(__x86_64__)
1021 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1023 notifier
= addMatchingNotification(
1024 gIOFirstPublishNotification
, tmpDict
,
1025 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1030 wranglerIdleSettings
= NULL
;
1031 OSNumber
* wranglerIdlePeriod
= NULL
;
1032 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1033 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1035 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1036 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1037 wranglerIdlePeriod
);
1039 if(wranglerIdlePeriod
)
1040 wranglerIdlePeriod
->release();
1043 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1044 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1045 ucClassName
->release();
1047 // IOBacklightDisplay can take a long time to load at boot, or it may
1048 // not load at all if you're booting with clamshell closed. We publish
1049 // 'DisplayDims' here redundantly to get it published early and at all.
1050 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1051 if( psIterator
&& psIterator
->getNextObject() )
1053 // There's at least one battery on the system, so we publish
1054 // 'DisplayDims' support for the LCD.
1055 publishFeature("DisplayDims");
1058 psIterator
->release();
1061 sysctl_register_oid(&sysctl__kern_sleeptime
);
1062 sysctl_register_oid(&sysctl__kern_waketime
);
1063 sysctl_register_oid(&sysctl__kern_willshutdown
);
1064 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1065 sysctl_register_oid(&sysctl__kern_progressmeter
);
1066 sysctl_register_oid(&sysctl__kern_wakereason
);
1069 IOHibernateSystemInit(this);
1072 registerService(); // let clients find us
1077 //******************************************************************************
1080 // Receive a setProperty call
1081 // The "System Boot" property means the system is completely booted.
1082 //******************************************************************************
1084 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1086 IOReturn return_value
= kIOReturnSuccess
;
1087 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1090 const OSSymbol
*key
;
1092 OSCollectionIterator
* iter
= 0;
1094 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1095 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1096 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1097 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1098 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1099 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1100 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1101 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1102 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1104 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1105 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1106 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1107 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1108 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1109 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1114 return_value
= kIOReturnBadArgument
;
1118 iter
= OSCollectionIterator::withCollection(dict
);
1121 return_value
= kIOReturnNoMemory
;
1125 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1126 (obj
= dict
->getObject(key
)))
1128 if (key
->isEqualTo(publish_simulated_battery_string
))
1130 if (OSDynamicCast(OSBoolean
, obj
))
1131 publishResource(key
, kOSBooleanTrue
);
1133 else if (key
->isEqualTo(idle_seconds_string
))
1135 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1137 setProperty(key
, n
);
1138 idleSeconds
= n
->unsigned32BitValue();
1141 else if (key
->isEqualTo(boot_complete_string
))
1143 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1145 else if (key
->isEqualTo(sys_shutdown_string
))
1147 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1148 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1150 else if (key
->isEqualTo(battery_warning_disabled_string
))
1152 setProperty(key
, obj
);
1155 else if (key
->isEqualTo(hibernatemode_string
) ||
1156 key
->isEqualTo(hibernatefilemin_string
) ||
1157 key
->isEqualTo(hibernatefilemax_string
) ||
1158 key
->isEqualTo(hibernatefreeratio_string
) ||
1159 key
->isEqualTo(hibernatefreetime_string
))
1161 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1162 setProperty(key
, n
);
1164 else if (key
->isEqualTo(hibernatefile_string
))
1166 OSString
* str
= OSDynamicCast(OSString
, obj
);
1167 if (str
) setProperty(key
, str
);
1170 else if (key
->isEqualTo(sleepdisabled_string
))
1172 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1174 setProperty(key
, b
);
1175 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1178 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1181 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1183 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1185 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1186 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1188 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1189 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1190 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1191 key
->isEqualTo(stall_halt_string
))
1193 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1194 setProperty(key
, b
);
1196 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1197 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1198 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1200 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1201 setProperty(key
, n
);
1203 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1205 if (kOSBooleanTrue
== obj
)
1206 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1208 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1209 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1212 // Relay our allowed PM settings onto our registered PM clients
1213 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1215 if ((gIOPMSettingAutoWakeSecondsKey
== key
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1217 UInt32 rsecs
= n
->unsigned32BitValue();
1219 autoWakeStart
= autoWakeEnd
= 0;
1222 AbsoluteTime deadline
;
1223 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1224 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1225 if (rsecs
> kAutoWakePreWindow
)
1226 rsecs
-= kAutoWakePreWindow
;
1229 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1230 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1234 return_value
= setPMSetting(key
, obj
);
1235 if (kIOReturnSuccess
!= return_value
)
1238 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1240 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1241 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1243 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1247 _debugWakeSeconds
= 0;
1248 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1250 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1252 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1255 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1256 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1258 const IOPMCalendarStruct
* cs
=
1259 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1262 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1264 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1265 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1271 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1276 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1277 if(boot_complete_string
) boot_complete_string
->release();
1278 if(sys_shutdown_string
) sys_shutdown_string
->release();
1279 if(stall_halt_string
) stall_halt_string
->release();
1280 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1281 if(idle_seconds_string
) idle_seconds_string
->release();
1282 if(sleepdisabled_string
) sleepdisabled_string
->release();
1283 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1284 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1286 if(hibernatemode_string
) hibernatemode_string
->release();
1287 if(hibernatefile_string
) hibernatefile_string
->release();
1288 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1289 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1291 if (iter
) iter
->release();
1292 return return_value
;
1296 // MARK: Aggressiveness
1298 //******************************************************************************
1299 // setAggressiveness
1301 // Override IOService::setAggressiveness()
1302 //******************************************************************************
1304 IOReturn
IOPMrootDomain::setAggressiveness(
1306 unsigned long value
)
1308 return setAggressiveness( type
, value
, 0 );
1312 * Private setAggressiveness() with an internal options argument.
1314 IOReturn
IOPMrootDomain::setAggressiveness(
1316 unsigned long value
,
1317 IOOptionBits options
)
1319 AggressivesRequest
* entry
;
1320 AggressivesRequest
* request
;
1323 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1324 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1326 request
= IONew(AggressivesRequest
, 1);
1328 return kIOReturnNoMemory
;
1330 memset(request
, 0, sizeof(*request
));
1331 request
->options
= options
;
1332 request
->dataType
= kAggressivesRequestTypeRecord
;
1333 request
->data
.record
.type
= (uint32_t) type
;
1334 request
->data
.record
.value
= (uint32_t) value
;
1338 // Update disk quick spindown flag used by getAggressiveness().
1339 // Never merge requests with quick spindown flags set.
1341 if (options
& kAggressivesOptionQuickSpindownEnable
)
1342 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1343 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1344 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1347 // Coalesce requests with identical aggressives types.
1348 // Deal with callers that calls us too "aggressively".
1350 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1352 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1353 (entry
->data
.record
.type
== type
) &&
1354 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1356 entry
->data
.record
.value
= value
;
1365 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1368 AGGRESSIVES_UNLOCK();
1371 IODelete(request
, AggressivesRequest
, 1);
1373 if (options
& kAggressivesOptionSynchronous
)
1374 handleAggressivesRequests(); // not truly synchronous
1376 thread_call_enter(aggressivesThreadCall
);
1378 return kIOReturnSuccess
;
1381 //******************************************************************************
1382 // getAggressiveness
1384 // Override IOService::setAggressiveness()
1385 // Fetch the aggressiveness factor with the given type.
1386 //******************************************************************************
1388 IOReturn
IOPMrootDomain::getAggressiveness (
1390 unsigned long * outLevel
)
1396 return kIOReturnBadArgument
;
1400 // Disk quick spindown in effect, report value = 1
1402 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1403 (type
== kPMMinutesToSpinDown
))
1405 value
= kAggressivesMinValue
;
1409 // Consult the pending request queue.
1413 AggressivesRequest
* entry
;
1415 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1417 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1418 (entry
->data
.record
.type
== type
) &&
1419 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1421 value
= entry
->data
.record
.value
;
1428 // Consult the backend records.
1430 if (!source
&& aggressivesData
)
1432 AggressivesRecord
* record
;
1435 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1436 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1438 for (i
= 0; i
< count
; i
++, record
++)
1440 if (record
->type
== type
)
1442 value
= record
->value
;
1449 AGGRESSIVES_UNLOCK();
1453 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1454 source
, (uint32_t) type
, value
);
1455 *outLevel
= (unsigned long) value
;
1456 return kIOReturnSuccess
;
1460 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1461 *outLevel
= 0; // default return = 0, driver may not check for error
1462 return kIOReturnInvalid
;
1466 //******************************************************************************
1467 // joinAggressiveness
1469 // Request from IOService to join future aggressiveness broadcasts.
1470 //******************************************************************************
1472 IOReturn
IOPMrootDomain::joinAggressiveness(
1473 IOService
* service
)
1475 AggressivesRequest
* request
;
1477 if (!service
|| (service
== this))
1478 return kIOReturnBadArgument
;
1480 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1482 request
= IONew(AggressivesRequest
, 1);
1484 return kIOReturnNoMemory
;
1486 service
->retain(); // released by synchronizeAggressives()
1488 memset(request
, 0, sizeof(*request
));
1489 request
->dataType
= kAggressivesRequestTypeService
;
1490 request
->data
.service
= service
;
1493 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1494 AGGRESSIVES_UNLOCK();
1496 thread_call_enter(aggressivesThreadCall
);
1498 return kIOReturnSuccess
;
1501 //******************************************************************************
1502 // handleAggressivesRequests
1504 // Backend thread processes all incoming aggressiveness requests in the queue.
1505 //******************************************************************************
1508 handleAggressivesFunction(
1509 thread_call_param_t param1
,
1510 thread_call_param_t param2
)
1514 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1518 void IOPMrootDomain::handleAggressivesRequests( void )
1520 AggressivesRecord
* start
;
1521 AggressivesRecord
* record
;
1522 AggressivesRequest
* request
;
1523 queue_head_t joinedQueue
;
1527 bool pingSelf
= false;
1531 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1532 queue_empty(&aggressivesQueue
))
1535 gAggressivesState
|= kAggressivesStateBusy
;
1536 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1537 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1542 queue_init(&joinedQueue
);
1546 // Remove request from the incoming queue in FIFO order.
1547 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1548 switch (request
->dataType
)
1550 case kAggressivesRequestTypeRecord
:
1551 // Update existing record if found.
1553 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1555 if (record
->type
== request
->data
.record
.type
)
1559 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1561 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1564 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1565 kAggressivesRecordFlagModified
);
1566 DLOG("disk spindown accelerated, was %u min\n",
1570 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1572 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1575 record
->flags
|= kAggressivesRecordFlagModified
;
1576 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1577 DLOG("disk spindown restored to %u min\n",
1581 else if (record
->value
!= request
->data
.record
.value
)
1583 record
->value
= request
->data
.record
.value
;
1584 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1587 record
->flags
|= kAggressivesRecordFlagModified
;
1594 // No matching record, append a new record.
1596 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1598 AggressivesRecord newRecord
;
1600 newRecord
.flags
= kAggressivesRecordFlagModified
;
1601 newRecord
.type
= request
->data
.record
.type
;
1602 newRecord
.value
= request
->data
.record
.value
;
1603 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1605 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1606 DLOG("disk spindown accelerated\n");
1609 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1611 // OSData may have switched to another (larger) buffer.
1612 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1613 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1617 // Finished processing the request, release it.
1618 IODelete(request
, AggressivesRequest
, 1);
1621 case kAggressivesRequestTypeService
:
1622 // synchronizeAggressives() will free request.
1623 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1627 panic("bad aggressives request type %x\n", request
->dataType
);
1630 } while (!queue_empty(&aggressivesQueue
));
1632 // Release the lock to perform work, with busy flag set.
1633 if (!queue_empty(&joinedQueue
) || broadcast
)
1635 AGGRESSIVES_UNLOCK();
1636 if (!queue_empty(&joinedQueue
))
1637 synchronizeAggressives(&joinedQueue
, start
, count
);
1639 broadcastAggressives(start
, count
);
1643 // Remove the modified flag from all records.
1644 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1646 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1647 ((record
->type
== kPMMinutesToDim
) ||
1648 (record
->type
== kPMMinutesToSleep
)))
1651 record
->flags
&= ~kAggressivesRecordFlagModified
;
1654 // Check the incoming queue again since new entries may have been
1655 // added while lock was released above.
1657 } while (!queue_empty(&aggressivesQueue
));
1659 gAggressivesState
&= ~kAggressivesStateBusy
;
1662 AGGRESSIVES_UNLOCK();
1664 // Root domain is interested in system and display sleep slider changes.
1665 // Submit a power event to handle those changes on the PM work loop.
1667 if (pingSelf
&& pmPowerStateQueue
) {
1668 pmPowerStateQueue
->submitPowerEvent(
1669 kPowerEventPolicyStimulus
,
1670 (void *) kStimulusAggressivenessChanged
);
1674 //******************************************************************************
1675 // synchronizeAggressives
1677 // Push all known aggressiveness records to one or more IOService.
1678 //******************************************************************************
1680 void IOPMrootDomain::synchronizeAggressives(
1681 queue_head_t
* joinedQueue
,
1682 const AggressivesRecord
* array
,
1685 IOService
* service
;
1686 AggressivesRequest
* request
;
1687 const AggressivesRecord
* record
;
1688 IOPMDriverCallEntry callEntry
;
1692 while (!queue_empty(joinedQueue
))
1694 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1695 if (request
->dataType
== kAggressivesRequestTypeService
)
1696 service
= request
->data
.service
;
1700 IODelete(request
, AggressivesRequest
, 1);
1705 if (service
->assertPMDriverCall(&callEntry
))
1707 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1709 value
= record
->value
;
1710 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1711 value
= kAggressivesMinValue
;
1713 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1714 record
->type
, value
, service
->getName());
1715 service
->setAggressiveness(record
->type
, value
);
1717 service
->deassertPMDriverCall(&callEntry
);
1719 service
->release(); // retained by joinAggressiveness()
1724 //******************************************************************************
1725 // broadcastAggressives
1727 // Traverse PM tree and call setAggressiveness() for records that have changed.
1728 //******************************************************************************
1730 void IOPMrootDomain::broadcastAggressives(
1731 const AggressivesRecord
* array
,
1734 IORegistryIterator
* iter
;
1735 IORegistryEntry
* entry
;
1736 IOPowerConnection
* connect
;
1737 IOService
* service
;
1738 const AggressivesRecord
* record
;
1739 IOPMDriverCallEntry callEntry
;
1743 iter
= IORegistryIterator::iterateOver(
1744 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1750 while ((entry
= iter
->getNextObject()))
1752 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1753 if (!connect
|| !connect
->getReadyFlag())
1756 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1758 if (service
->assertPMDriverCall(&callEntry
))
1760 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1762 if (record
->flags
& kAggressivesRecordFlagModified
)
1764 value
= record
->value
;
1765 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1766 value
= kAggressivesMinValue
;
1767 _LOG("broadcastAggressives %x = %u to %s\n",
1768 record
->type
, value
, service
->getName());
1769 service
->setAggressiveness(record
->type
, value
);
1772 service
->deassertPMDriverCall(&callEntry
);
1778 while (!entry
&& !iter
->isValid());
1784 // MARK: System Sleep
1786 //******************************************************************************
1787 // startIdleSleepTimer
1789 //******************************************************************************
1791 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1793 AbsoluteTime deadline
;
1798 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1799 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1800 idleSleepTimerPending
= true;
1804 thread_call_enter(extraSleepTimer
);
1806 DLOG("idle timer set for %u seconds\n", inSeconds
);
1809 //******************************************************************************
1810 // cancelIdleSleepTimer
1812 //******************************************************************************
1814 void IOPMrootDomain::cancelIdleSleepTimer( void )
1817 if (idleSleepTimerPending
)
1819 DLOG("idle timer cancelled\n");
1820 thread_call_cancel(extraSleepTimer
);
1821 idleSleepTimerPending
= false;
1825 //******************************************************************************
1826 // idleSleepTimerExpired
1828 //******************************************************************************
1830 static void idleSleepTimerExpired(
1831 thread_call_param_t us
, thread_call_param_t
)
1833 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1836 //******************************************************************************
1837 // handleSleepTimerExpiration
1839 // The time between the sleep idle timeout and the next longest one has elapsed.
1840 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1841 //******************************************************************************
1843 void IOPMrootDomain::handleSleepTimerExpiration( void )
1845 if (!getPMworkloop()->inGate())
1847 getPMworkloop()->runAction(
1848 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1849 &IOPMrootDomain::handleSleepTimerExpiration
),
1856 DLOG("sleep timer expired\n");
1859 idleSleepTimerPending
= false;
1861 clock_get_uptime(&time
);
1862 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1863 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1865 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1869 setQuickSpinDownTimeout();
1870 adjustPowerState(true);
1873 //******************************************************************************
1874 // getTimeToIdleSleep
1876 // Returns number of seconds left before going into idle sleep.
1877 // Caller has to make sure that idle sleep is allowed at the time of calling
1879 //******************************************************************************
1881 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
1884 AbsoluteTime now
, lastActivityTime
;
1886 uint32_t minutesSinceUserInactive
= 0;
1887 uint32_t sleepDelay
= 0;
1889 if (sleepSlider
== 0)
1892 if (userActivityTime
)
1893 lastActivityTime
= userActivityTime
;
1895 lastActivityTime
= userBecameInactiveTime
;
1897 clock_get_uptime(&now
);
1898 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
1900 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
1901 absolutetime_to_nanoseconds(now
, &nanos
);
1902 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
1904 if (minutesSinceUserInactive
>= sleepSlider
)
1907 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
1911 sleepDelay
= sleepSlider
;
1914 DLOG("user inactive %u min, time to idle sleep %u min\n",
1915 minutesSinceUserInactive
, sleepDelay
);
1917 return (sleepDelay
* 60);
1920 //******************************************************************************
1921 // setQuickSpinDownTimeout
1923 //******************************************************************************
1925 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1929 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1932 //******************************************************************************
1933 // restoreUserSpinDownTimeout
1935 //******************************************************************************
1937 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1941 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
1944 //******************************************************************************
1947 //******************************************************************************
1950 IOReturn
IOPMrootDomain::sleepSystem( void )
1952 return sleepSystemOptions(NULL
);
1956 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1958 OSObject
*obj
= NULL
;
1959 OSString
*reason
= NULL
;
1960 /* sleepSystem is a public function, and may be called by any kernel driver.
1961 * And that's bad - drivers should sleep the system by calling
1962 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1964 * Note that user space app calls to IOPMSleepSystem() will also travel
1965 * this code path and thus be correctly identified as software sleeps.
1968 if (options
&& options
->getObject("OSSwitch"))
1970 // Log specific sleep cause for OS Switch hibernation
1971 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
1974 if (options
&& (obj
= options
->getObject("Sleep Reason")))
1976 reason
= OSDynamicCast(OSString
, obj
);
1977 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
1978 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
1981 return privateSleepSystem( kIOPMSleepReasonSoftware
);
1985 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
1987 /* Called from both gated and non-gated context */
1989 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
1991 return kIOReturnNotPermitted
;
1994 pmPowerStateQueue
->submitPowerEvent(
1995 kPowerEventPolicyStimulus
,
1996 (void *) kStimulusDemandSystemSleep
,
1999 return kIOReturnSuccess
;
2002 //******************************************************************************
2005 // This overrides powerChangeDone in IOService.
2006 //******************************************************************************
2008 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2011 DLOG("PowerChangeDone: %u->%u\n",
2012 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2014 switch ( getPowerState() )
2017 if (previousPowerState
!= ON_STATE
)
2020 acceptSystemWakeEvents(true);
2022 // re-enable this timer for next sleep
2023 cancelIdleSleepTimer();
2026 clock_usec_t microsecs
;
2027 clock_get_calendar_microtime(&secs
, µsecs
);
2029 gIOLastSleepTime
.tv_sec
= secs
;
2030 gIOLastSleepTime
.tv_usec
= microsecs
;
2031 gIOLastWakeTime
.tv_sec
= 0;
2032 gIOLastWakeTime
.tv_usec
= 0;
2035 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2037 IOHibernateSystemHasSlept();
2039 evaluateSystemSleepPolicyFinal();
2041 LOG("System Sleep\n");
2043 if (thermalWarningState
) {
2044 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2046 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2050 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2051 getPlatform()->sleepKernel();
2053 // The CPU(s) are off at this point,
2054 // Code will resume execution here upon wake.
2056 clock_get_uptime(&systemWakeTime
);
2057 _highestCapability
= 0;
2059 ((IOService
*)this)->start_watchdog_timer(); //14456299
2061 IOHibernateSystemWake();
2064 // sleep transition complete
2065 gSleepOrShutdownPending
= 0;
2067 // trip the reset of the calendar clock
2068 clock_wakeup_calendar();
2071 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2075 PMDebug(kPMLogSystemWake
, 0, 0);
2076 lowBatteryCondition
= false;
2077 lastSleepReason
= 0;
2079 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2080 _debugWakeSeconds
= 0;
2081 _scheduledAlarms
= 0;
2087 #if defined(__i386__) || defined(__x86_64__)
2088 wranglerTickled
= false;
2089 graphicsSuppressed
= false;
2090 darkWakePostTickle
= false;
2091 darkWakeHibernateError
= false;
2092 darkWakeToSleepASAP
= true;
2093 logGraphicsClamp
= true;
2094 sleepTimerMaintenance
= false;
2095 sleepToStandby
= false;
2096 wranglerTickleLatched
= false;
2097 userWasActive
= false;
2098 fullWakeReason
= kFullWakeReasonNone
;
2101 OSString
* wakeType
= OSDynamicCast(
2102 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2103 OSString
* wakeReason
= OSDynamicCast(
2104 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2106 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2107 gWakeReasonString
[0] == '\0')
2109 // Until the platform driver can claim its wake reasons
2110 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2111 sizeof(gWakeReasonString
));
2114 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2116 lowBatteryCondition
= true;
2117 darkWakeMaintenance
= true;
2119 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2121 OSNumber
* hibOptions
= OSDynamicCast(
2122 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2124 if (hibernateAborted
|| ((hibOptions
&&
2125 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2127 // Hibernate aborted, or EFI brought up graphics
2128 wranglerTickled
= true;
2129 DLOG("hibernation aborted %d, options 0x%x\n",
2131 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2135 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2136 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2138 // User wake or RTC alarm
2139 wranglerTickled
= true;
2143 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2145 // SMC standby timer trumps SleepX
2146 darkWakeMaintenance
= true;
2147 sleepTimerMaintenance
= true;
2150 if ((_lastDebugWakeSeconds
!= 0) &&
2151 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2153 // SleepX before maintenance
2154 wranglerTickled
= true;
2158 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2160 darkWakeMaintenance
= true;
2164 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2166 darkWakeMaintenance
= true;
2167 darkWakeSleepService
= true;
2168 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2169 sleepToStandby
= true;
2174 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2176 darkWakeMaintenance
= true;
2177 darkWakeHibernateError
= true;
2181 // Unidentified wake source, resume to full wake if debug
2182 // alarm is pending.
2184 if (_lastDebugWakeSeconds
&&
2185 (!wakeReason
|| wakeReason
->isEqualTo("")))
2186 wranglerTickled
= true;
2192 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2194 darkWakeMaintenance
= true;
2195 sleepTimerMaintenance
= true;
2197 else if (hibernateAborted
|| !wakeType
||
2198 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2199 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2201 // Post a HID tickle immediately - except for RTC maintenance wake.
2202 wranglerTickled
= true;
2206 darkWakeMaintenance
= true;
2210 if (wranglerTickled
)
2212 darkWakeToSleepASAP
= false;
2213 fullWakeReason
= kFullWakeReasonLocalUser
;
2216 else if (!darkWakeMaintenance
)
2218 // Early/late tickle for non-maintenance wake.
2219 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2220 kDarkWakeFlagHIDTickleEarly
) ||
2221 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2222 kDarkWakeFlagHIDTickleLate
))
2224 darkWakePostTickle
= true;
2227 #else /* !__i386__ && !__x86_64__ */
2228 // stay awake for at least 30 seconds
2229 wranglerTickled
= true;
2230 fullWakeReason
= kFullWakeReasonLocalUser
;
2231 startIdleSleepTimer(30);
2235 changePowerStateToPriv(ON_STATE
);
2241 //******************************************************************************
2242 // requestPowerDomainState
2244 // Extend implementation in IOService. Running on PM work loop thread.
2245 //******************************************************************************
2247 IOReturn
IOPMrootDomain::requestPowerDomainState (
2248 IOPMPowerFlags childDesire
,
2249 IOPowerConnection
* childConnection
,
2250 unsigned long specification
)
2252 // Idle and system sleep prevention flags affects driver desire.
2253 // Children desire are irrelevant so they are cleared.
2255 return super::requestPowerDomainState(0, childConnection
, specification
);
2258 //******************************************************************************
2259 // updatePreventIdleSleepList
2261 // Called by IOService on PM work loop.
2262 // Returns true if PM policy recognized the driver's desire to prevent idle
2263 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2264 //******************************************************************************
2266 bool IOPMrootDomain::updatePreventIdleSleepList(
2267 IOService
* service
, bool addNotRemove
)
2269 unsigned int oldCount
, newCount
;
2273 #if defined(__i386__) || defined(__x86_64__)
2274 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2275 // idle sleep, except in the case of legacy disk I/O
2276 if ((service
!= wrangler
) && (service
!= this))
2282 oldCount
= preventIdleSleepList
->getCount();
2285 preventIdleSleepList
->setObject(service
);
2286 DLOG("prevent idle sleep list: %s+ (%u)\n",
2287 service
->getName(), preventIdleSleepList
->getCount());
2289 else if (preventIdleSleepList
->member(service
))
2291 preventIdleSleepList
->removeObject(service
);
2292 DLOG("prevent idle sleep list: %s- (%u)\n",
2293 service
->getName(), preventIdleSleepList
->getCount());
2295 newCount
= preventIdleSleepList
->getCount();
2297 if ((oldCount
== 0) && (newCount
!= 0))
2299 // Driver added to empty prevent list.
2300 // Update the driver desire to prevent idle sleep.
2301 // Driver desire does not prevent demand sleep.
2303 changePowerStateTo(ON_STATE
);
2305 else if ((oldCount
!= 0) && (newCount
== 0))
2307 // Last driver removed from prevent list.
2308 // Drop the driver clamp to allow idle sleep.
2310 changePowerStateTo(SLEEP_STATE
);
2311 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2314 #if defined(__i386__) || defined(__x86_64__)
2315 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2317 return false; // do not idle-cancel
2324 //******************************************************************************
2325 // preventSystemSleepListUpdate
2327 // Called by IOService on PM work loop.
2328 //******************************************************************************
2330 void IOPMrootDomain::updatePreventSystemSleepList(
2331 IOService
* service
, bool addNotRemove
)
2333 unsigned int oldCount
;
2336 if (this == service
)
2339 oldCount
= preventSystemSleepList
->getCount();
2342 preventSystemSleepList
->setObject(service
);
2343 DLOG("prevent system sleep list: %s+ (%u)\n",
2344 service
->getName(), preventSystemSleepList
->getCount());
2346 else if (preventSystemSleepList
->member(service
))
2348 preventSystemSleepList
->removeObject(service
);
2349 DLOG("prevent system sleep list: %s- (%u)\n",
2350 service
->getName(), preventSystemSleepList
->getCount());
2352 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2354 // Lost all system sleep preventers.
2355 // Send stimulus if system sleep was blocked, and is in dark wake.
2356 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2361 //******************************************************************************
2364 // Override the superclass implementation to send a different message type.
2365 //******************************************************************************
2367 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2369 DLOG("tellChangeDown %u->%u\n",
2370 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2372 if (SLEEP_STATE
== stateNum
)
2374 // Legacy apps were already told in the full->dark transition
2375 if (!ignoreTellChangeDown
)
2376 tracePoint( kIOPMTracePointSleepApplications
);
2378 tracePoint( kIOPMTracePointSleepPriorityClients
);
2381 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2383 userActivityAtSleep
= userActivityCount
;
2384 hibernateAborted
= false;
2385 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2387 // Direct callout into OSKext so it can disable kext unloads
2388 // during sleep/wake to prevent deadlocks.
2389 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2391 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2393 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2394 // But tellClientsWithResponse() must be called for both.
2395 ignoreTellChangeDown
= true;
2398 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2401 //******************************************************************************
2404 // Override the superclass implementation to send a different message type.
2405 // This must be idle sleep since we don't ask during any other power change.
2406 //******************************************************************************
2408 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2410 DLOG("askChangeDown %u->%u\n",
2411 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2413 // Don't log for dark wake entry
2414 if (kSystemTransitionSleep
== _systemTransitionType
)
2415 tracePoint( kIOPMTracePointSleepApplications
);
2417 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2420 //******************************************************************************
2421 // askChangeDownDone
2423 // An opportunity for root domain to cancel the power transition,
2424 // possibily due to an assertion created by powerd in response to
2425 // kIOMessageCanSystemSleep.
2428 // full -> dark wake transition
2429 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2430 // 2. askChangeDownDone()
2431 // dark -> sleep transition
2432 // 1. Notify powerd with kIOMessageCanSystemSleep
2433 // 2. askChangeDownDone()
2436 // full -> dark wake transition
2437 // 1. Notify powerd with kIOMessageCanSystemSleep
2438 // 2. askChangeDownDone()
2439 // dark -> sleep transition
2440 // 1. Notify powerd with kIOMessageCanSystemSleep
2441 // 2. askChangeDownDone()
2442 //******************************************************************************
2444 void IOPMrootDomain::askChangeDownDone(
2445 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2447 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2448 *inOutChangeFlags
, *cancel
,
2449 _systemTransitionType
,
2450 _currentCapability
, _pendingCapability
);
2452 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2454 // Dark->Sleep transition.
2455 // Check if there are any deny sleep assertions.
2456 // lastSleepReason already set by handleOurPowerChangeStart()
2458 if (!checkSystemCanSleep(lastSleepReason
))
2460 // Cancel dark wake to sleep transition.
2461 // Must re-scan assertions upon entering dark wake.
2464 DLOG("cancel dark->sleep\n");
2469 //******************************************************************************
2470 // systemDidNotSleep
2472 // Work common to both canceled or aborted sleep.
2473 //******************************************************************************
2475 void IOPMrootDomain::systemDidNotSleep( void )
2481 // stay awake for at least idleSeconds
2482 startIdleSleepTimer(idleSeconds
);
2487 if (sleepSlider
&& !userIsActive
)
2489 // Manually start the idle sleep timer besides waiting for
2490 // the user to become inactive.
2491 startIdleSleepTimer( kIdleSleepRetryInterval
);
2495 preventTransitionToUserActive(false);
2496 IOService::setAdvisoryTickleEnable( true );
2499 //******************************************************************************
2502 // Notify registered applications and kernel clients that we are not dropping
2505 // We override the superclass implementation so we can send a different message
2506 // type to the client or application being notified.
2508 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2509 //******************************************************************************
2511 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2513 DLOG("tellNoChangeDown %u->%u\n",
2514 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2516 // Sleep canceled, clear the sleep trace point.
2517 tracePoint(kIOPMTracePointSystemUp
);
2519 systemDidNotSleep();
2520 return tellClients( kIOMessageSystemWillNotSleep
);
2523 //******************************************************************************
2526 // Notify registered applications and kernel clients that we are raising power.
2528 // We override the superclass implementation so we can send a different message
2529 // type to the client or application being notified.
2530 //******************************************************************************
2532 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2535 DLOG("tellChangeUp %u->%u\n",
2536 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2538 ignoreTellChangeDown
= false;
2540 if ( stateNum
== ON_STATE
)
2542 // Direct callout into OSKext so it can disable kext unloads
2543 // during sleep/wake to prevent deadlocks.
2544 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2546 // Notify platform that sleep was cancelled or resumed.
2547 getPlatform()->callPlatformFunction(
2548 sleepMessagePEFunction
, false,
2549 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2552 if (getPowerState() == ON_STATE
)
2554 // this is a quick wake from aborted sleep
2555 systemDidNotSleep();
2556 tellClients( kIOMessageSystemWillPowerOn
);
2560 tracePoint( kIOPMTracePointWakeApplications
);
2561 tellClients( kIOMessageSystemHasPoweredOn
);
2565 //******************************************************************************
2566 // sysPowerDownHandler
2568 // Perform a vfs sync before system sleep.
2569 //******************************************************************************
2571 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2572 void * target
, void * refCon
,
2573 UInt32 messageType
, IOService
* service
,
2574 void * messageArgs
, vm_size_t argSize
)
2578 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2581 return kIOReturnUnsupported
;
2583 if (messageType
== kIOMessageSystemWillSleep
)
2586 uint32_t mem_only
= 0;
2587 IOPowerStateChangeNotification
*notify
=
2588 (IOPowerStateChangeNotification
*)messageArgs
;
2590 PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
));
2591 if ((mem_only
!= 1) && (gRootDomain
->sleepWakeDebugIsWdogEnabled()))
2593 notify
->returnValue
= 30 * 1000 * 1000;
2595 gRootDomain
->hibDebugSetupEntry
,
2596 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2600 else if (messageType
== kIOMessageSystemCapabilityChange
)
2602 IOPMSystemCapabilityChangeParameters
* params
=
2603 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2605 // Interested applications have been notified of an impending power
2606 // change and have acked (when applicable).
2607 // This is our chance to save whatever state we can before powering
2609 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2612 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2613 params
->fromCapabilities
, params
->toCapabilities
,
2614 params
->changeFlags
);
2616 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2617 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2618 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2620 // We will ack within 20 seconds
2621 params
->maxWaitForReply
= 20 * 1000 * 1000;
2623 gRootDomain
->evaluateSystemSleepPolicyEarly();
2625 // add in time we could spend freeing pages
2626 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2628 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2630 DLOG("sysPowerDownHandler max wait %d s\n",
2631 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2634 // Notify platform that sleep has begun, after the early
2635 // sleep policy evaluation.
2636 getPlatform()->callPlatformFunction(
2637 sleepMessagePEFunction
, false,
2638 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2641 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2643 // Purposely delay the ack and hope that shutdown occurs quickly.
2644 // Another option is not to schedule the thread and wait for
2646 AbsoluteTime deadline
;
2647 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2648 thread_call_enter1_delayed(
2649 gRootDomain
->diskSyncCalloutEntry
,
2650 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2655 gRootDomain
->diskSyncCalloutEntry
,
2656 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2659 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2660 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2661 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2664 // We will ack within 110 seconds
2665 params
->maxWaitForReply
= 110 * 1000 * 1000;
2668 gRootDomain
->diskSyncCalloutEntry
,
2669 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2672 ret
= kIOReturnSuccess
;
2678 //******************************************************************************
2679 // handleQueueSleepWakeUUID
2681 // Called from IOPMrootDomain when we're initiating a sleep,
2682 // or indirectly from PM configd when PM decides to clear the UUID.
2683 // PM clears the UUID several minutes after successful wake from sleep,
2684 // so that we might associate App spindumps with the immediately previous
2687 // @param obj has a retain on it. We're responsible for releasing that retain.
2688 //******************************************************************************
2690 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2692 OSString
*str
= NULL
;
2694 if (kOSBooleanFalse
== obj
)
2696 handlePublishSleepWakeUUID(NULL
);
2698 else if ((str
= OSDynamicCast(OSString
, obj
)))
2700 // This branch caches the UUID for an upcoming sleep/wake
2701 if (queuedSleepWakeUUIDString
) {
2702 queuedSleepWakeUUIDString
->release();
2703 queuedSleepWakeUUIDString
= NULL
;
2705 queuedSleepWakeUUIDString
= str
;
2706 queuedSleepWakeUUIDString
->retain();
2708 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2717 //******************************************************************************
2718 // handlePublishSleepWakeUUID
2720 // Called from IOPMrootDomain when we're initiating a sleep,
2721 // or indirectly from PM configd when PM decides to clear the UUID.
2722 // PM clears the UUID several minutes after successful wake from sleep,
2723 // so that we might associate App spindumps with the immediately previous
2725 //******************************************************************************
2727 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2732 * Clear the current UUID
2734 if (gSleepWakeUUIDIsSet
)
2736 DLOG("SleepWake UUID cleared\n");
2738 gSleepWakeUUIDIsSet
= false;
2740 removeProperty(kIOPMSleepWakeUUIDKey
);
2741 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2745 * Optionally, publish a new UUID
2747 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2749 OSString
*publishThisUUID
= NULL
;
2751 publishThisUUID
= queuedSleepWakeUUIDString
;
2752 publishThisUUID
->retain();
2754 if (publishThisUUID
)
2756 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2757 publishThisUUID
->release();
2760 gSleepWakeUUIDIsSet
= true;
2761 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2763 queuedSleepWakeUUIDString
->release();
2764 queuedSleepWakeUUIDString
= NULL
;
2768 //******************************************************************************
2769 // initializeBootSessionUUID
2771 // Initialize the boot session uuid at boot up and sets it into registry.
2772 //******************************************************************************
2774 void IOPMrootDomain::initializeBootSessionUUID(void)
2777 uuid_string_t new_uuid_string
;
2779 uuid_generate(new_uuid
);
2780 uuid_unparse_upper(new_uuid
, new_uuid_string
);
2781 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
2783 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
2786 //******************************************************************************
2787 // changePowerStateTo & changePowerStateToPriv
2789 // Override of these methods for logging purposes.
2790 //******************************************************************************
2792 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2794 DLOG("changePowerStateTo(%lu)\n", ordinal
);
2796 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2797 return kIOReturnUnsupported
;
2799 return super::changePowerStateTo(ordinal
);
2802 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2804 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2806 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2807 return kIOReturnUnsupported
;
2809 return super::changePowerStateToPriv(ordinal
);
2812 //******************************************************************************
2815 //******************************************************************************
2817 bool IOPMrootDomain::activitySinceSleep(void)
2819 return (userActivityCount
!= userActivityAtSleep
);
2822 bool IOPMrootDomain::abortHibernation(void)
2824 bool ret
= activitySinceSleep();
2826 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
2828 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2829 hibernateAborted
= true;
2835 hibernate_should_abort(void)
2838 return (gRootDomain
->abortHibernation());
2843 //******************************************************************************
2844 // willNotifyPowerChildren
2846 // Called after all interested drivers have all acknowledged the power change,
2847 // but before any power children is informed. Dispatched though a thread call,
2848 // so it is safe to perform work that might block on a sleeping disk. PM state
2849 // machine (not thread) will block w/o timeout until this function returns.
2850 //******************************************************************************
2852 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
2855 if (SLEEP_STATE
== newPowerState
)
2857 IOHibernateSystemSleep();
2858 IOHibernateIOKitSleep();
2863 //******************************************************************************
2864 // sleepOnClamshellClosed
2866 // contains the logic to determine if the system should sleep when the clamshell
2868 //******************************************************************************
2870 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2872 if (!clamshellExists
)
2875 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
2876 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
2878 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
2881 void IOPMrootDomain::sendClientClamshellNotification( void )
2883 /* Only broadcast clamshell alert if clamshell exists. */
2884 if (!clamshellExists
)
2887 setProperty(kAppleClamshellStateKey
,
2888 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2890 setProperty(kAppleClamshellCausesSleepKey
,
2891 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2893 /* Argument to message is a bitfiel of
2894 * ( kClamshellStateBit | kClamshellSleepBit )
2896 messageClients(kIOPMMessageClamshellStateChange
,
2897 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
2898 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2901 //******************************************************************************
2902 // getSleepSupported
2905 //******************************************************************************
2907 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2909 return( platformSleepSupport
);
2912 //******************************************************************************
2913 // setSleepSupported
2916 //******************************************************************************
2918 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2920 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2921 OSBitOrAtomic(flags
, &platformSleepSupport
);
2924 //******************************************************************************
2925 // setDisableClamShellSleep
2927 //******************************************************************************
2929 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
2931 if (gIOPMWorkLoop
->inGate() == false) {
2933 gIOPMWorkLoop
->runAction(
2934 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
2941 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
2942 if ( clamshellSleepDisabled
!= val
)
2944 clamshellSleepDisabled
= val
;
2945 // If clamshellSleepDisabled is reset to 0, reevaluate if
2946 // system need to go to sleep due to clamshell state
2947 if ( !clamshellSleepDisabled
&& clamshellClosed
)
2948 handlePowerNotification(kLocalEvalClamshellCommand
);
2953 //******************************************************************************
2957 //******************************************************************************
2959 void IOPMrootDomain::wakeFromDoze( void )
2961 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2967 //******************************************************************************
2970 // Adds a new feature to the supported features dictionary
2971 //******************************************************************************
2973 void IOPMrootDomain::publishFeature( const char * feature
)
2975 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2978 //******************************************************************************
2979 // publishFeature (with supported power source specified)
2981 // Adds a new feature to the supported features dictionary
2982 //******************************************************************************
2984 void IOPMrootDomain::publishFeature(
2985 const char *feature
,
2986 uint32_t supportedWhere
,
2987 uint32_t *uniqueFeatureID
)
2989 static uint16_t next_feature_id
= 500;
2991 OSNumber
*new_feature_data
= NULL
;
2992 OSNumber
*existing_feature
= NULL
;
2993 OSArray
*existing_feature_arr
= NULL
;
2994 OSObject
*osObj
= NULL
;
2995 uint32_t feature_value
= 0;
2997 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2999 if(!supportedWhere
) {
3000 // Feature isn't supported anywhere!
3004 if(next_feature_id
> 5000) {
3005 // Far, far too many features!
3009 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3011 OSDictionary
*features
=
3012 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3014 // Create new features dict if necessary
3015 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3016 features
= OSDictionary::withDictionary(features
);
3018 features
= OSDictionary::withCapacity(1);
3021 // Create OSNumber to track new feature
3023 next_feature_id
+= 1;
3024 if( uniqueFeatureID
) {
3025 // We don't really mind if the calling kext didn't give us a place
3026 // to stash their unique id. Many kexts don't plan to unload, and thus
3027 // have no need to remove themselves later.
3028 *uniqueFeatureID
= next_feature_id
;
3031 feature_value
= (uint32_t)next_feature_id
;
3032 feature_value
<<= 16;
3033 feature_value
+= supportedWhere
;
3035 new_feature_data
= OSNumber::withNumber(
3036 (unsigned long long)feature_value
, 32);
3038 // Does features object already exist?
3039 if( (osObj
= features
->getObject(feature
)) )
3041 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3043 // We need to create an OSArray to hold the now 2 elements.
3044 existing_feature_arr
= OSArray::withObjects(
3045 (const OSObject
**)&existing_feature
, 1, 2);
3046 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3048 // Add object to existing array
3049 existing_feature_arr
= OSArray::withArray(
3050 existing_feature_arr
,
3051 existing_feature_arr
->getCount() + 1);
3054 if (existing_feature_arr
)
3056 existing_feature_arr
->setObject(new_feature_data
);
3057 features
->setObject(feature
, existing_feature_arr
);
3058 existing_feature_arr
->release();
3059 existing_feature_arr
= 0;
3062 // The easy case: no previously existing features listed. We simply
3063 // set the OSNumber at key 'feature' and we're on our way.
3064 features
->setObject(feature
, new_feature_data
);
3067 new_feature_data
->release();
3069 setProperty(kRootDomainSupportedFeatures
, features
);
3071 features
->release();
3073 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3075 // Notify EnergySaver and all those in user space so they might
3076 // re-populate their feature specific UI
3077 if(pmPowerStateQueue
) {
3078 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3082 //******************************************************************************
3083 // removePublishedFeature
3085 // Removes previously published feature
3086 //******************************************************************************
3088 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3090 IOReturn ret
= kIOReturnError
;
3091 uint32_t feature_value
= 0;
3092 uint16_t feature_id
= 0;
3093 bool madeAChange
= false;
3095 OSSymbol
*dictKey
= NULL
;
3096 OSCollectionIterator
*dictIterator
= NULL
;
3097 OSArray
*arrayMember
= NULL
;
3098 OSNumber
*numberMember
= NULL
;
3099 OSObject
*osObj
= NULL
;
3100 OSNumber
*osNum
= NULL
;
3101 OSArray
*arrayMemberCopy
;
3103 if (kBadPMFeatureID
== removeFeatureID
)
3104 return kIOReturnNotFound
;
3106 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3108 OSDictionary
*features
=
3109 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3111 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3113 // Any modifications to the dictionary are made to the copy to prevent
3114 // races & crashes with userland clients. Dictionary updated
3115 // automically later.
3116 features
= OSDictionary::withDictionary(features
);
3119 ret
= kIOReturnNotFound
;
3123 // We iterate 'features' dictionary looking for an entry tagged
3124 // with 'removeFeatureID'. If found, we remove it from our tracking
3125 // structures and notify the OS via a general interest message.
3127 dictIterator
= OSCollectionIterator::withCollection(features
);
3132 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3134 osObj
= features
->getObject(dictKey
);
3136 // Each Feature is either tracked by an OSNumber
3137 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3139 feature_value
= numberMember
->unsigned32BitValue();
3140 feature_id
= (uint16_t)(feature_value
>> 16);
3142 if( feature_id
== (uint16_t)removeFeatureID
)
3145 features
->removeObject(dictKey
);
3150 // Or tracked by an OSArray of OSNumbers
3151 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3153 unsigned int arrayCount
= arrayMember
->getCount();
3155 for(unsigned int i
=0; i
<arrayCount
; i
++)
3157 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3162 feature_value
= osNum
->unsigned32BitValue();
3163 feature_id
= (uint16_t)(feature_value
>> 16);
3165 if( feature_id
== (uint16_t)removeFeatureID
)
3168 if( 1 == arrayCount
) {
3169 // If the array only contains one element, remove
3171 features
->removeObject(dictKey
);
3173 // Otherwise remove the element from a copy of the array.
3174 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3175 if (arrayMemberCopy
)
3177 arrayMemberCopy
->removeObject(i
);
3178 features
->setObject(dictKey
, arrayMemberCopy
);
3179 arrayMemberCopy
->release();
3190 dictIterator
->release();
3194 ret
= kIOReturnSuccess
;
3196 setProperty(kRootDomainSupportedFeatures
, features
);
3198 // Notify EnergySaver and all those in user space so they might
3199 // re-populate their feature specific UI
3200 if(pmPowerStateQueue
) {
3201 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3204 ret
= kIOReturnNotFound
;
3208 if(features
) features
->release();
3209 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3213 //******************************************************************************
3214 // publishPMSetting (private)
3216 // Should only be called by PMSettingObject to publish a PM Setting as a
3217 // supported feature.
3218 //******************************************************************************
3220 void IOPMrootDomain::publishPMSetting(
3221 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3223 if (noPublishPMSettings
&&
3224 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3226 // Setting found in noPublishPMSettings array
3227 *featureID
= kBadPMFeatureID
;
3232 feature
->getCStringNoCopy(), where
, featureID
);
3235 //******************************************************************************
3236 // setPMSetting (private)
3238 // Internal helper to relay PM settings changes from user space to individual
3239 // drivers. Should be called only by IOPMrootDomain::setProperties.
3240 //******************************************************************************
3242 IOReturn
IOPMrootDomain::setPMSetting(
3243 const OSSymbol
*type
,
3246 PMSettingCallEntry
*entries
= 0;
3247 OSArray
*chosen
= 0;
3248 const OSArray
*array
;
3249 PMSettingObject
*pmso
;
3250 thread_t thisThread
;
3251 int i
, j
, count
, capacity
;
3254 return kIOReturnBadArgument
;
3258 // Update settings dict so changes are visible from copyPMSetting().
3259 fPMSettingsDict
->setObject(type
, object
);
3261 // Prep all PMSetting objects with the given 'type' for callout.
3262 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3263 if (!array
|| ((capacity
= array
->getCount()) == 0))
3266 // Array to retain PMSetting objects targeted for callout.
3267 chosen
= OSArray::withCapacity(capacity
);
3269 goto unlock_exit
; // error
3271 entries
= IONew(PMSettingCallEntry
, capacity
);
3273 goto unlock_exit
; // error
3274 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3276 thisThread
= current_thread();
3278 for (i
= 0, j
= 0; i
<capacity
; i
++)
3280 pmso
= (PMSettingObject
*) array
->getObject(i
);
3283 entries
[j
].thread
= thisThread
;
3284 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3285 chosen
->setObject(pmso
);
3294 // Call each pmso in the chosen array.
3295 for (i
=0; i
<count
; i
++)
3297 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3298 pmso
->dispatchPMSetting(type
, object
);
3302 for (i
=0; i
<count
; i
++)
3304 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3305 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3306 if (pmso
->waitThread
)
3308 PMSETTING_WAKEUP(pmso
);
3314 if (chosen
) chosen
->release();
3315 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3317 return kIOReturnSuccess
;
3320 //******************************************************************************
3321 // copyPMSetting (public)
3323 // Allows kexts to safely read setting values, without being subscribed to
3325 //******************************************************************************
3327 OSObject
* IOPMrootDomain::copyPMSetting(
3328 OSSymbol
*whichSetting
)
3330 OSObject
*obj
= NULL
;
3332 if(!whichSetting
) return NULL
;
3335 obj
= fPMSettingsDict
->getObject(whichSetting
);
3344 //******************************************************************************
3345 // registerPMSettingController (public)
3347 // direct wrapper to registerPMSettingController with uint32_t power source arg
3348 //******************************************************************************
3350 IOReturn
IOPMrootDomain::registerPMSettingController(
3351 const OSSymbol
* settings
[],
3352 IOPMSettingControllerCallback func
,
3357 return registerPMSettingController(
3359 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3360 func
, target
, refcon
, handle
);
3363 //******************************************************************************
3364 // registerPMSettingController (public)
3366 // Kexts may register for notifications when a particular setting is changed.
3367 // A list of settings is available in IOPM.h.
3369 // * settings - An OSArray containing OSSymbols. Caller should populate this
3370 // array with a list of settings caller wants notifications from.
3371 // * func - A C function callback of the type IOPMSettingControllerCallback
3372 // * target - caller may provide an OSObject *, which PM will pass as an
3373 // target to calls to "func"
3374 // * refcon - caller may provide an void *, which PM will pass as an
3375 // argument to calls to "func"
3376 // * handle - This is a return argument. We will populate this pointer upon
3377 // call success. Hold onto this and pass this argument to
3378 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3380 // kIOReturnSuccess on success
3381 //******************************************************************************
3383 IOReturn
IOPMrootDomain::registerPMSettingController(
3384 const OSSymbol
* settings
[],
3385 uint32_t supportedPowerSources
,
3386 IOPMSettingControllerCallback func
,
3391 PMSettingObject
*pmso
= NULL
;
3392 OSObject
*pmsh
= NULL
;
3393 OSArray
*list
= NULL
;
3396 if (NULL
== settings
||
3400 return kIOReturnBadArgument
;
3403 pmso
= PMSettingObject::pmSettingObject(
3404 (IOPMrootDomain
*) this, func
, target
,
3405 refcon
, supportedPowerSources
, settings
, &pmsh
);
3409 return kIOReturnInternalError
;
3413 for (i
=0; settings
[i
]; i
++)
3415 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3417 // New array of callbacks for this setting
3418 list
= OSArray::withCapacity(1);
3419 settingsCallbacks
->setObject(settings
[i
], list
);
3423 // Add caller to the callback list
3424 list
->setObject(pmso
);
3428 // Return handle to the caller, the setting object is private.
3431 return kIOReturnSuccess
;
3434 //******************************************************************************
3435 // deregisterPMSettingObject (private)
3437 // Only called from PMSettingObject.
3438 //******************************************************************************
3440 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3442 thread_t thisThread
= current_thread();
3443 PMSettingCallEntry
*callEntry
;
3444 OSCollectionIterator
*iter
;
3452 pmso
->disabled
= true;
3454 // Wait for all callout threads to finish.
3457 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3459 if (callEntry
->thread
!= thisThread
)
3467 assert(0 == pmso
->waitThread
);
3468 pmso
->waitThread
= thisThread
;
3469 PMSETTING_WAIT(pmso
);
3470 pmso
->waitThread
= 0;
3474 // Search each PM settings array in the kernel.
3475 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3478 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3480 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3481 index
= array
->getNextIndexOfObject(pmso
, 0);
3483 array
->removeObject(index
);
3494 //******************************************************************************
3495 // informCPUStateChange
3497 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3498 // running on battery, with the lid closed, etc.
3500 // informCPUStateChange is a no-op on non x86 systems
3501 // only x86 has explicit support in the IntelCPUPowerManagement kext
3502 //******************************************************************************
3504 void IOPMrootDomain::informCPUStateChange(
3508 #if defined(__i386__) || defined(__x86_64__)
3510 pmioctlVariableInfo_t varInfoStruct
;
3512 const char *varNameStr
= NULL
;
3513 int32_t *varIndex
= NULL
;
3515 if (kInformAC
== type
) {
3516 varNameStr
= kIOPMRootDomainBatPowerCString
;
3517 varIndex
= &idxPMCPULimitedPower
;
3518 } else if (kInformLid
== type
) {
3519 varNameStr
= kIOPMRootDomainLidCloseCString
;
3520 varIndex
= &idxPMCPUClamshell
;
3525 // Set the new value!
3526 // pmCPUControl will assign us a new ID if one doesn't exist yet
3527 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3528 varInfoStruct
.varID
= *varIndex
;
3529 varInfoStruct
.varType
= vBool
;
3530 varInfoStruct
.varInitValue
= value
;
3531 varInfoStruct
.varCurValue
= value
;
3532 strncpy( (char *)varInfoStruct
.varName
,
3533 (const char *)varNameStr
,
3534 strlen(varNameStr
) + 1 );
3537 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3539 // pmCPU only assigns numerical id's when a new varName is specified
3541 && (*varIndex
== kCPUUnknownIndex
))
3543 // pmCPUControl has assigned us a new variable ID.
3544 // Let's re-read the structure we just SET to learn that ID.
3545 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3549 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3550 *varIndex
= varInfoStruct
.varID
;
3556 #endif /* __i386__ || __x86_64__ */
3560 // MARK: Deep Sleep Policy
3564 //******************************************************************************
3565 // evaluateSystemSleepPolicy
3566 //******************************************************************************
3568 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3572 kIOPMSleepFlagHibernate
= 0x00000001,
3573 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3576 struct IOPMSystemSleepPolicyEntry
3578 uint32_t factorMask
;
3579 uint32_t factorBits
;
3580 uint32_t sleepFlags
;
3581 uint32_t wakeEvents
;
3582 } __attribute__((packed
));
3584 struct IOPMSystemSleepPolicyTable
3588 uint16_t entryCount
;
3589 IOPMSystemSleepPolicyEntry entries
[];
3590 } __attribute__((packed
));
3593 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3594 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3598 getSleepTypeAttributes( uint32_t sleepType
)
3600 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3605 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3606 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3607 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3608 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3612 if (sleepType
>= kIOPMSleepTypeLast
)
3615 return sleepTypeAttributes
[sleepType
];
3618 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3619 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3621 const IOPMSystemSleepPolicyTable
* pt
;
3622 OSObject
* prop
= 0;
3623 OSData
* policyData
;
3624 uint64_t currentFactors
= 0;
3625 uint32_t standbyDelay
= 0;
3626 uint32_t powerOffDelay
= 0;
3627 uint32_t powerOffTimer
= 0;
3629 bool standbyEnabled
;
3630 bool powerOffEnabled
;
3633 // Get platform's sleep policy table
3634 if (!gSleepPolicyHandler
)
3636 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3637 if (!prop
) goto done
;
3640 // Fetch additional settings
3641 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3642 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3643 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3644 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3645 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3646 powerOffTimer
= powerOffDelay
;
3648 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3649 sleepPhase
, standbyEnabled
, standbyDelay
,
3650 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3652 // pmset level overrides
3653 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3655 if (!gSleepPolicyHandler
)
3657 standbyEnabled
= false;
3658 powerOffEnabled
= false;
3661 else if (!(*hibMode
& kIOHibernateModeSleep
))
3663 // Force hibernate (i.e. mode 25)
3664 // If standby is enabled, force standy.
3665 // If poweroff is enabled, force poweroff.
3667 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3668 else if (powerOffEnabled
)
3669 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3671 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3674 // Current factors based on environment and assertions
3675 if (sleepTimerMaintenance
)
3676 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3677 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
3678 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3679 if (!clamshellClosed
)
3680 currentFactors
|= kIOPMSleepFactorLidOpen
;
3681 if (acAdaptorConnected
)
3682 currentFactors
|= kIOPMSleepFactorACPower
;
3683 if (lowBatteryCondition
)
3684 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3686 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3687 if (!standbyEnabled
)
3688 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3689 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3690 kIOPMDriverAssertionLevelOff
)
3691 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3692 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3693 kIOPMDriverAssertionLevelOff
)
3694 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3695 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3696 kIOPMDriverAssertionLevelOff
)
3697 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3698 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3699 kIOPMDriverAssertionLevelOff
)
3700 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3701 if (_scheduledAlarms
!= 0)
3702 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3703 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3704 kIOPMDriverAssertionLevelOff
)
3705 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3706 #define TCPKEEPALIVE 1
3708 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
3709 kIOPMDriverAssertionLevelOff
)
3710 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
3712 if (!powerOffEnabled
)
3713 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3715 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3717 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
3718 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
3719 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
3720 if (thermalWarningState
)
3721 currentFactors
|= kIOPMSleepFactorThermalWarning
;
3723 DLOG("sleep factors 0x%llx\n", currentFactors
);
3725 if (gSleepPolicyHandler
)
3727 uint32_t savedHibernateMode
;
3730 if (!gSleepPolicyVars
)
3732 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3733 if (!gSleepPolicyVars
)
3735 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3737 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3738 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3739 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3740 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3741 gSleepPolicyVars
->sleepFactors
= currentFactors
;
3742 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
3743 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
3744 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
3745 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3746 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
3747 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
3749 if (kIOPMSleepPhase0
== sleepPhase
)
3751 // preserve hibernateMode
3752 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
3753 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3755 else if (kIOPMSleepPhase1
== sleepPhase
)
3757 // use original hibernateMode for phase2
3758 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3761 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
3763 if (kIOPMSleepPhase0
== sleepPhase
)
3765 // restore hibernateMode
3766 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
3769 if ((result
!= kIOReturnSuccess
) ||
3770 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3771 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3772 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3774 MSG("sleep policy handler error\n");
3778 if ((getSleepTypeAttributes(params
->sleepType
) &
3779 kIOPMSleepAttributeHibernateSetup
) &&
3780 ((*hibMode
& kIOHibernateModeOn
) == 0))
3782 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
3785 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3786 params
->version
, params
->sleepType
, params
->sleepFlags
,
3787 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3792 // Policy table is meaningless without standby enabled
3793 if (!standbyEnabled
)
3796 // Validate the sleep policy table
3797 policyData
= OSDynamicCast(OSData
, prop
);
3798 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3801 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3802 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3803 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3806 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3807 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
3810 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3812 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
3813 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
3815 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3816 entry
->factorMask
, entry
->factorBits
,
3817 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
3821 DLOG("^ found match\n");
3824 params
->version
= kIOPMSystemSleepParametersVersion
;
3825 params
->reserved1
= 1;
3826 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
3827 params
->sleepType
= kIOPMSleepTypeStandby
;
3829 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
3831 params
->ecWakeEvents
= entry
->wakeEvents
;
3832 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3834 if (kIOPMSleepPhase2
== sleepPhase
)
3836 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
3838 if (!_standbyTimerResetSeconds
||
3839 (now_secs
<= _standbyTimerResetSeconds
))
3841 // Reset standby timer adjustment
3842 _standbyTimerResetSeconds
= now_secs
;
3843 DLOG("standby delay %u, reset %u\n",
3844 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
3846 else if (standbyDelay
)
3848 // Shorten the standby delay timer
3849 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
3850 if (standbyDelay
> elapsed
)
3851 standbyDelay
-= elapsed
;
3853 standbyDelay
= 1; // must be > 0
3855 DLOG("standby delay %u, elapsed %u\n",
3856 standbyDelay
, (uint32_t) elapsed
);
3859 params
->ecWakeTimer
= standbyDelay
;
3861 else if (kIOPMSleepPhase2
== sleepPhase
)
3863 // A sleep that does not enable the sleep timer will reset
3864 // the standby delay adjustment.
3865 _standbyTimerResetSeconds
= 0;
3877 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
3879 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3881 // Evaluate early (priority interest phase), before drivers sleep.
3883 DLOG("%s\n", __FUNCTION__
);
3884 removeProperty(kIOPMSystemSleepParametersKey
);
3886 // Full wake resets the standby timer delay adjustment
3887 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
3888 _standbyTimerResetSeconds
= 0;
3890 hibernateDisabled
= false;
3892 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3894 // Save for late evaluation if sleep is aborted
3895 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
3897 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
3900 if (!hibernateRetry
&&
3901 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
3902 kIOPMSleepAttributeHibernateSetup
) == 0))
3904 // skip hibernate setup
3905 hibernateDisabled
= true;
3909 // Publish IOPMSystemSleepType
3910 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
3911 if (sleepType
== kIOPMSleepTypeInvalid
)
3914 sleepType
= kIOPMSleepTypeNormalSleep
;
3915 if (hibernateMode
& kIOHibernateModeOn
)
3916 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
3917 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
3919 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
3920 (gEarlySystemSleepParams
.ecPoweroffTimer
))
3922 // report the lowest possible sleep state
3923 sleepType
= kIOPMSleepTypePowerOff
;
3926 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
3929 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3931 IOPMSystemSleepParameters params
;
3932 OSData
* paramsData
;
3934 // Evaluate sleep policy after sleeping drivers but before platform sleep.
3936 DLOG("%s\n", __FUNCTION__
);
3938 bzero(¶ms
, sizeof(params
));
3939 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
3941 if ((hibernateDisabled
|| hibernateAborted
) &&
3942 (getSleepTypeAttributes(params
.sleepType
) &
3943 kIOPMSleepAttributeHibernateSetup
))
3945 // Final evaluation picked a state requiring hibernation,
3946 // but hibernate setup was skipped. Arm a short sleep using
3947 // the early non-hibernate sleep parameters.
3948 // Set hibernateRetry flag to force hibernate setup on the
3951 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
3952 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
3953 params
.ecWakeTimer
= 1;
3954 hibernateRetry
= true;
3955 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3956 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
3960 hibernateRetry
= false;
3963 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3966 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3967 paramsData
->release();
3970 if (getSleepTypeAttributes(params
.sleepType
) &
3971 kIOPMSleepAttributeHibernateSleep
)
3973 // Disable sleep to force hibernation
3974 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3979 bool IOPMrootDomain::getHibernateSettings(
3980 uint32_t * hibernateModePtr
,
3981 uint32_t * hibernateFreeRatio
,
3982 uint32_t * hibernateFreeTime
)
3984 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
3985 // has updated the hibernateDisabled flag.
3987 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
3988 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3989 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3990 if (hibernateDisabled
)
3991 *hibernateModePtr
= 0;
3992 else if (gSleepPolicyHandler
)
3993 *hibernateModePtr
= hibernateMode
;
3994 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
3998 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4000 OSObject
* optionsProp
;
4001 OSDictionary
* optionsDict
;
4006 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4007 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4011 obj
= optionsDict
->getObject(key
);
4012 if (obj
) obj
->retain();
4016 obj
= copyProperty(key
);
4020 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4022 *option
= num
->unsigned32BitValue();
4025 else if (OSDynamicCast(OSBoolean
, obj
))
4027 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4035 optionsProp
->release();
4039 #endif /* HIBERNATION */
4041 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4044 IOPMSystemSleepParameters params
;
4045 uint32_t hibMode
= 0;
4048 if (gIOPMWorkLoop
->inGate() == false)
4050 IOReturn ret
= gIOPMWorkLoop
->runAction(
4051 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4052 &IOPMrootDomain::getSystemSleepType
),
4054 (void *) sleepType
);
4058 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4059 bzero(¶ms
, sizeof(params
));
4061 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4064 *sleepType
= params
.sleepType
;
4065 return kIOReturnSuccess
;
4069 return kIOReturnUnsupported
;
4073 // MARK: Shutdown and Restart
4075 //******************************************************************************
4076 // handlePlatformHaltRestart
4078 //******************************************************************************
4080 struct HaltRestartApplierContext
{
4081 IOPMrootDomain
* RootDomain
;
4082 unsigned long PowerState
;
4083 IOPMPowerFlags PowerFlags
;
4089 platformHaltRestartApplier( OSObject
* object
, void * context
)
4091 IOPowerStateChangeNotification notify
;
4092 HaltRestartApplierContext
* ctx
;
4093 AbsoluteTime startTime
;
4096 ctx
= (HaltRestartApplierContext
*) context
;
4098 memset(¬ify
, 0, sizeof(notify
));
4099 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4100 notify
.returnValue
= 0;
4101 notify
.stateNumber
= ctx
->PowerState
;
4102 notify
.stateFlags
= ctx
->PowerFlags
;
4104 clock_get_uptime(&startTime
);
4105 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4106 deltaTime
= computeDeltaTimeMS(&startTime
);
4108 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4109 (gIOKitDebug
& kIOLogPMRootDomain
))
4111 _IOServiceInterestNotifier
* notifier
;
4112 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4114 // IOService children of IOPMrootDomain are not instrumented.
4115 // Only IORootParent currently falls under that group.
4119 LOG("%s handler %p took %u ms\n",
4120 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4121 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4122 OBFUSCATE(notifier
->handler
), (uint32_t) deltaTime
);
4129 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4131 HaltRestartApplierContext ctx
;
4132 AbsoluteTime startTime
;
4135 memset(&ctx
, 0, sizeof(ctx
));
4136 ctx
.RootDomain
= this;
4138 clock_get_uptime(&startTime
);
4142 case kPEUPSDelayHaltCPU
:
4143 ctx
.PowerState
= OFF_STATE
;
4144 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4148 ctx
.PowerState
= RESTART_STATE
;
4149 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4153 ctx
.PowerState
= ON_STATE
;
4154 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4155 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4157 IOHibernateSystemRestart();
4165 // Notify legacy clients
4166 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4168 // For normal shutdown, turn off File Server Mode.
4169 if (kPEHaltCPU
== pe_type
)
4171 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4172 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4175 setPMSetting(setting
, num
);
4181 if (kPEPagingOff
!= pe_type
)
4183 // Notify in power tree order
4184 notifySystemShutdown(this, ctx
.MessageType
);
4187 IOCPURunPlatformHaltRestartActions(pe_type
);
4189 deltaTime
= computeDeltaTimeMS(&startTime
);
4190 LOG("%s all drivers took %u ms\n",
4191 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4192 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4193 (uint32_t) deltaTime
);
4196 //******************************************************************************
4199 //******************************************************************************
4201 IOReturn
IOPMrootDomain::shutdownSystem( void )
4203 return kIOReturnUnsupported
;
4206 //******************************************************************************
4209 //******************************************************************************
4211 IOReturn
IOPMrootDomain::restartSystem( void )
4213 return kIOReturnUnsupported
;
4217 // MARK: System Capability
4219 //******************************************************************************
4220 // tagPowerPlaneService
4222 // Running on PM work loop thread.
4223 //******************************************************************************
4225 void IOPMrootDomain::tagPowerPlaneService(
4226 IOService
* service
,
4227 IOPMActions
* actions
)
4230 bool isDisplayWrangler
;
4232 memset(actions
, 0, sizeof(*actions
));
4233 actions
->target
= this;
4235 if (service
== this)
4237 actions
->actionPowerChangeStart
=
4238 OSMemberFunctionCast(
4239 IOPMActionPowerChangeStart
, this,
4240 &IOPMrootDomain::handleOurPowerChangeStart
);
4242 actions
->actionPowerChangeDone
=
4243 OSMemberFunctionCast(
4244 IOPMActionPowerChangeDone
, this,
4245 &IOPMrootDomain::handleOurPowerChangeDone
);
4247 actions
->actionPowerChangeOverride
=
4248 OSMemberFunctionCast(
4249 IOPMActionPowerChangeOverride
, this,
4250 &IOPMrootDomain::overrideOurPowerChange
);
4255 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4256 if (isDisplayWrangler
)
4261 isDisplayWrangler
= false;
4264 #if defined(__i386__) || defined(__x86_64__)
4265 if (isDisplayWrangler
)
4266 flags
|= kPMActionsFlagIsDisplayWrangler
;
4267 if (service
->getProperty("IOPMStrictTreeOrder"))
4268 flags
|= kPMActionsFlagIsGraphicsDevice
;
4269 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4270 flags
|= kPMActionsFlagIsAudioDevice
;
4273 // Find the power connection object that is a child of the PCI host
4274 // bridge, and has a graphics/audio device attached below. Mark the
4275 // power branch for delayed child notifications.
4279 IORegistryEntry
* child
= service
;
4280 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4282 while (child
!= this)
4284 if ((parent
== pciHostBridgeDriver
) ||
4287 if (OSDynamicCast(IOPowerConnection
, child
))
4289 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4290 conn
->delayChildNotification
= true;
4295 parent
= child
->getParentEntry(gIOPowerPlane
);
4301 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4302 actions
->parameter
|= flags
;
4303 actions
->actionPowerChangeOverride
=
4304 OSMemberFunctionCast(
4305 IOPMActionPowerChangeOverride
, this,
4306 &IOPMrootDomain::overridePowerChangeForUIService
);
4308 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4310 actions
->actionActivityTickle
=
4311 OSMemberFunctionCast(
4312 IOPMActionActivityTickle
, this,
4313 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4315 actions
->actionUpdatePowerClient
=
4316 OSMemberFunctionCast(
4317 IOPMActionUpdatePowerClient
, this,
4318 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4323 // Locate the first PCI host bridge for PMTrace.
4324 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4326 IOService
* provider
= service
->getProvider();
4327 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4328 provider
->inPlane(gIODTPlane
))
4330 pciHostBridgeDevice
= provider
;
4331 pciHostBridgeDriver
= service
;
4332 DLOG("PMTrace found PCI host bridge %s->%s\n",
4333 provider
->getName(), service
->getName());
4337 // Tag top-level PCI devices. The order of PMinit() call does not
4338 // change across boots and is used as the PCI bit number.
4339 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4341 // Would prefer to check built-in property, but tagPowerPlaneService()
4342 // is called before pciDevice->registerService().
4343 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4344 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4346 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4349 // Save the assigned bit for fast lookup.
4350 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4352 actions
->actionPowerChangeStart
=
4353 OSMemberFunctionCast(
4354 IOPMActionPowerChangeStart
, this,
4355 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4357 actions
->actionPowerChangeDone
=
4358 OSMemberFunctionCast(
4359 IOPMActionPowerChangeDone
, this,
4360 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4366 //******************************************************************************
4367 // PM actions for root domain
4368 //******************************************************************************
4370 void IOPMrootDomain::overrideOurPowerChange(
4371 IOService
* service
,
4372 IOPMActions
* actions
,
4373 IOPMPowerStateIndex
* inOutPowerState
,
4374 IOPMPowerChangeFlags
* inOutChangeFlags
,
4375 IOPMRequestTag requestTag
)
4377 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4378 uint32_t changeFlags
= *inOutChangeFlags
;
4379 uint32_t currentPowerState
= (uint32_t) getPowerState();
4381 if (changeFlags
& kIOPMParentInitiated
)
4383 // Root parent is permanently pegged at max power,
4384 // a parent initiated power change is unexpected.
4385 *inOutChangeFlags
|= kIOPMNotDone
;
4389 if (powerState
< currentPowerState
)
4391 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4393 // Root domain is dropping power state ON->SLEEP.
4394 // If system is in full wake, first enter dark wake by
4395 // converting the power drop to a capability change.
4396 // Once in dark wake, transition to sleep state ASAP.
4398 darkWakeToSleepASAP
= true;
4400 // Drop graphics and audio capability
4401 _desiredCapability
&= ~(
4402 kIOPMSystemCapabilityGraphics
|
4403 kIOPMSystemCapabilityAudio
);
4405 // Convert to capability change (ON->ON)
4406 *inOutPowerState
= ON_STATE
;
4407 *inOutChangeFlags
|= kIOPMSynchronize
;
4409 // Revert device desire from SLEEP to ON
4410 changePowerStateToPriv(ON_STATE
);
4414 // System is in dark wake, ok to drop power state.
4415 // Broadcast root powering down to entire tree.
4416 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4419 else if (powerState
> currentPowerState
)
4421 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4423 // Broadcast power up when waking from sleep, but not for the
4424 // initial power change at boot by checking for cpu capability.
4425 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4430 void IOPMrootDomain::handleOurPowerChangeStart(
4431 IOService
* service
,
4432 IOPMActions
* actions
,
4433 IOPMPowerStateIndex powerState
,
4434 IOPMPowerChangeFlags
* inOutChangeFlags
,
4435 IOPMRequestTag requestTag
)
4437 uint32_t changeFlags
= *inOutChangeFlags
;
4438 uint32_t currentPowerState
= (uint32_t) getPowerState();
4439 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4440 bool publishSleepReason
= false;
4442 _systemTransitionType
= kSystemTransitionNone
;
4443 _systemMessageClientMask
= 0;
4444 capabilityLoss
= false;
4446 if (lowBatteryCondition
)
4448 // Low battery notification may arrive after the initial sleep request
4449 // has been queued. Override the sleep reason so powerd and others can
4450 // treat this as an emergency sleep.
4451 sleepReason
= kIOPMSleepReasonLowPower
;
4454 // 1. Explicit capability change.
4456 if (changeFlags
& kIOPMSynchronize
)
4458 if (powerState
== ON_STATE
)
4460 if (changeFlags
& kIOPMSyncNoChildNotify
)
4461 _systemTransitionType
= kSystemTransitionNewCapClient
;
4463 _systemTransitionType
= kSystemTransitionCapability
;
4467 // 2. Going to sleep (cancellation still possible).
4469 else if (powerState
< currentPowerState
)
4470 _systemTransitionType
= kSystemTransitionSleep
;
4472 // 3. Woke from (idle or demand) sleep.
4474 else if (!systemBooting
&&
4475 (changeFlags
& kIOPMSelfInitiated
) &&
4476 (powerState
> currentPowerState
))
4478 _systemTransitionType
= kSystemTransitionWake
;
4479 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4480 kIOPMSystemCapabilityNetwork
;
4482 // Early exit from dark wake to full (e.g. LID open)
4483 if (kFullWakeReasonNone
!= fullWakeReason
)
4485 _desiredCapability
|= (
4486 kIOPMSystemCapabilityGraphics
|
4487 kIOPMSystemCapabilityAudio
);
4490 IOHibernateSetWakeCapabilities(_desiredCapability
);
4494 // Update pending wake capability at the beginning of every
4495 // state transition (including synchronize). This will become
4496 // the current capability at the end of the transition.
4498 if (kSystemTransitionSleep
== _systemTransitionType
)
4500 _pendingCapability
= 0;
4501 capabilityLoss
= true;
4503 // Clear previous stats
4504 IOLockLock(pmStatsLock
);
4505 if (pmStatsAppResponses
)
4507 pmStatsAppResponses
->release();
4508 pmStatsAppResponses
= OSArray::withCapacity(5);
4510 IOLockUnlock(pmStatsLock
);
4513 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4515 _pendingCapability
= _desiredCapability
|
4516 kIOPMSystemCapabilityCPU
|
4517 kIOPMSystemCapabilityNetwork
;
4519 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4520 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4522 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4523 (_pendingCapability
== _currentCapability
))
4525 // Cancel the PM state change.
4526 _systemTransitionType
= kSystemTransitionNone
;
4527 *inOutChangeFlags
|= kIOPMNotDone
;
4529 if (__builtin_popcount(_pendingCapability
) <
4530 __builtin_popcount(_currentCapability
))
4531 capabilityLoss
= true;
4534 // 1. Capability change.
4536 if (kSystemTransitionCapability
== _systemTransitionType
)
4538 // Dark to Full transition.
4539 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4541 tracePoint( kIOPMTracePointDarkWakeExit
);
4543 willEnterFullWake();
4546 // Full to Dark transition.
4547 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4549 tracePoint( kIOPMTracePointDarkWakeEntry
);
4550 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4551 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4552 kSystemMessageClientLegacyApp
;
4556 // Prevent user active transitions before notifying clients
4557 // that system will sleep.
4558 preventTransitionToUserActive(true);
4560 IOService::setAdvisoryTickleEnable( false );
4562 // Publish the sleep reason for full to dark wake
4563 publishSleepReason
= true;
4564 lastSleepReason
= fullToDarkReason
= sleepReason
;
4566 // Publish a UUID for the Sleep --> Wake cycle
4567 handlePublishSleepWakeUUID(true);
4573 else if (kSystemTransitionSleep
== _systemTransitionType
)
4575 // Beginning of a system sleep transition.
4576 // Cancellation is still possible.
4577 tracePoint( kIOPMTracePointSleepStarted
, sleepReason
);
4579 _systemMessageClientMask
= kSystemMessageClientAll
;
4580 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4581 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
4582 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4583 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4585 // Record the reason for dark wake back to sleep
4586 // System may not have ever achieved full wake
4588 publishSleepReason
= true;
4589 lastSleepReason
= sleepReason
;
4594 else if (kSystemTransitionWake
== _systemTransitionType
)
4596 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4597 // Clear stats about sleep
4599 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4601 willEnterFullWake();
4605 // Message powerd only
4606 _systemMessageClientMask
= kSystemMessageClientPowerd
;
4607 tellClients(kIOMessageSystemWillPowerOn
);
4611 // The only location where the sleep reason is published. At this point
4612 // sleep can still be cancelled, but sleep reason should be published
4613 // early for logging purposes.
4615 if (publishSleepReason
)
4617 static const char * IOPMSleepReasons
[] =
4619 kIOPMClamshellSleepKey
,
4620 kIOPMPowerButtonSleepKey
,
4621 kIOPMSoftwareSleepKey
,
4622 kIOPMOSSwitchHibernationKey
,
4624 kIOPMLowPowerSleepKey
,
4625 kIOPMThermalEmergencySleepKey
,
4626 kIOPMMaintenanceSleepKey
,
4627 kIOPMSleepServiceExitKey
,
4628 kIOPMDarkWakeThermalEmergencyKey
4631 // Record sleep cause in IORegistry
4632 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
4633 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
4634 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
4635 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
4639 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4640 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4642 _systemStateGeneration
++;
4643 systemDarkWake
= false;
4645 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4647 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
4648 _systemTransitionType
, _systemStateGeneration
,
4649 _systemMessageClientMask
,
4650 _desiredCapability
, _currentCapability
, _pendingCapability
);
4654 void IOPMrootDomain::handleOurPowerChangeDone(
4655 IOService
* service
,
4656 IOPMActions
* actions
,
4657 IOPMPowerStateIndex powerState
,
4658 IOPMPowerChangeFlags changeFlags
,
4659 IOPMRequestTag requestTag __unused
)
4661 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4663 _systemTransitionType
= kSystemTransitionNone
;
4667 if (_systemTransitionType
!= kSystemTransitionNone
)
4669 uint32_t currentPowerState
= (uint32_t) getPowerState();
4671 if (changeFlags
& kIOPMNotDone
)
4673 // Power down was cancelled or vetoed.
4674 _pendingCapability
= _currentCapability
;
4675 lastSleepReason
= 0;
4677 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
4678 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4680 pmPowerStateQueue
->submitPowerEvent(
4681 kPowerEventPolicyStimulus
,
4682 (void *) kStimulusDarkWakeReentry
,
4683 _systemStateGeneration
);
4686 // Revert device desire to max.
4687 changePowerStateToPriv(ON_STATE
);
4691 // Send message on dark wake to full wake promotion.
4692 // tellChangeUp() handles the normal SLEEP->ON case.
4694 if (kSystemTransitionCapability
== _systemTransitionType
)
4696 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4698 lastSleepReason
= 0; // stop logging wrangler tickles
4699 tellClients(kIOMessageSystemHasPoweredOn
);
4701 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4703 // Going dark, reset full wake state
4704 // userIsActive will be cleared by wrangler powering down
4705 wranglerTickled
= false;
4706 fullWakeReason
= kFullWakeReasonNone
;
4710 // Reset state after exiting from dark wake.
4712 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4713 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4715 darkWakeMaintenance
= false;
4716 darkWakeToSleepASAP
= false;
4717 pciCantSleepValid
= false;
4718 darkWakeSleepService
= false;
4720 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
4722 // Remove the influence of display power assertion
4723 // before next system wake.
4724 if (wrangler
) wrangler
->changePowerStateForRootDomain(
4725 kWranglerPowerStateMin
);
4726 removeProperty(gIOPMUserTriggeredFullWakeKey
);
4730 // Entered dark mode.
4732 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4733 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4735 // Queue an evaluation of whether to remain in dark wake,
4736 // and for how long. This serves the purpose of draining
4737 // any assertions from the queue.
4739 pmPowerStateQueue
->submitPowerEvent(
4740 kPowerEventPolicyStimulus
,
4741 (void *) kStimulusDarkWakeEntry
,
4742 _systemStateGeneration
);
4746 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4747 "dcp %x:%x:%x, dbgtimer %u\n",
4748 currentPowerState
, (uint32_t) powerState
, changeFlags
,
4749 _systemTransitionType
, _systemStateGeneration
,
4750 _systemMessageClientMask
,
4751 _desiredCapability
, _currentCapability
, _pendingCapability
,
4752 _lastDebugWakeSeconds
);
4754 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4757 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4758 if (clamshellExists
&& fullWakeThreadCall
&&
4759 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4761 // Not the initial graphics full power, graphics won't
4762 // send a power notification to trigger a lid state
4765 AbsoluteTime deadline
;
4766 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
4767 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
4771 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
4774 // Update current system capability.
4775 if (_currentCapability
!= _pendingCapability
)
4776 _currentCapability
= _pendingCapability
;
4778 // Update highest system capability.
4780 _highestCapability
|= _currentCapability
;
4782 if (darkWakePostTickle
&&
4783 (kSystemTransitionWake
== _systemTransitionType
) &&
4784 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4785 kDarkWakeFlagHIDTickleLate
)
4787 darkWakePostTickle
= false;
4791 // Reset tracepoint at completion of capability change,
4792 // completion of wake transition, and aborted sleep transition.
4794 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4795 (_systemTransitionType
== kSystemTransitionWake
) ||
4796 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4797 (changeFlags
& kIOPMNotDone
)))
4799 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4800 tracePoint( kIOPMTracePointSystemUp
, 0 );
4803 _systemTransitionType
= kSystemTransitionNone
;
4804 _systemMessageClientMask
= 0;
4806 logGraphicsClamp
= false;
4810 //******************************************************************************
4811 // PM actions for graphics and audio.
4812 //******************************************************************************
4814 void IOPMrootDomain::overridePowerChangeForUIService(
4815 IOService
* service
,
4816 IOPMActions
* actions
,
4817 IOPMPowerStateIndex
* inOutPowerState
,
4818 IOPMPowerChangeFlags
* inOutChangeFlags
)
4820 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4821 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4823 if (kSystemTransitionNone
== _systemTransitionType
)
4825 // Not in midst of a system transition.
4826 // Do not modify power limit enable state.
4828 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4830 // Activate power limiter.
4832 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4833 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4834 (changeFlags
& kIOPMSynchronize
))
4836 actions
->parameter
|= kPMActionsFlagLimitPower
;
4838 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4839 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
4840 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
4841 (changeFlags
& kIOPMSynchronize
))
4843 actions
->parameter
|= kPMActionsFlagLimitPower
;
4845 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4846 (_systemTransitionType
== kSystemTransitionSleep
))
4848 // For graphics devices, arm the limiter when entering
4849 // system sleep. Not when dropping to dark wake.
4850 actions
->parameter
|= kPMActionsFlagLimitPower
;
4853 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4855 DLOG("+ plimit %s %p\n",
4856 service
->getName(), OBFUSCATE(service
));
4861 // Remove power limit.
4863 if ((actions
->parameter
& (
4864 kPMActionsFlagIsDisplayWrangler
|
4865 kPMActionsFlagIsGraphicsDevice
)) &&
4866 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4868 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4870 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4871 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4873 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4876 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4878 DLOG("- plimit %s %p\n",
4879 service
->getName(), OBFUSCATE(service
));
4883 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4885 uint32_t maxPowerState
= (uint32_t)(-1);
4887 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4889 // Enforce limit for system power/cap transitions.
4892 if ((service
->getPowerState() > maxPowerState
) &&
4893 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
4897 // Remove lingering effects of any tickle before entering
4898 // dark wake. It will take a new tickle to return to full
4899 // wake, so the existing tickle state is useless.
4901 if (changeFlags
& kIOPMDomainDidChange
)
4902 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
4904 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
4911 // Deny all self-initiated changes when power is limited.
4912 // Wrangler tickle should never defeat the limiter.
4914 maxPowerState
= service
->getPowerState();
4917 if (powerState
> maxPowerState
)
4919 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4920 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
4922 *inOutPowerState
= maxPowerState
;
4924 if (darkWakePostTickle
&&
4925 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4926 (changeFlags
& kIOPMDomainWillChange
) &&
4927 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4928 kDarkWakeFlagHIDTickleEarly
))
4930 darkWakePostTickle
= false;
4935 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4937 if (logGraphicsClamp
)
4942 clock_get_uptime(&now
);
4943 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4944 absolutetime_to_nanoseconds(now
, &nsec
);
4945 if (kIOLogPMRootDomain
& gIOKitDebug
)
4946 MSG("Graphics suppressed %u ms\n",
4947 ((int)((nsec
) / 1000000ULL)));
4949 graphicsSuppressed
= true;
4954 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4955 IOService
* service
,
4956 IOPMActions
* actions
)
4959 // Warning: Not running in PM work loop context - don't modify state !!!
4960 // Trap tickle directed to IODisplayWrangler while running with graphics
4961 // capability suppressed.
4963 assert(service
== wrangler
);
4965 clock_get_uptime(&userActivityTime
);
4966 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4967 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4969 userActivityCount
++;
4970 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
4971 userActivityCount
, lastSleepReason
);
4974 if (!wranglerTickled
&&
4975 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4977 DLOG("display wrangler tickled\n");
4978 if (kIOLogPMRootDomain
& gIOKitDebug
)
4979 OSReportWithBacktrace("Dark wake display tickle");
4980 if (pmPowerStateQueue
)
4982 pmPowerStateQueue
->submitPowerEvent(
4983 kPowerEventPolicyStimulus
,
4984 (void *) kStimulusDarkWakeActivityTickle
,
4985 true /* set wake type */ );
4991 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
4992 IOService
* service
,
4993 IOPMActions
* actions
,
4994 const OSSymbol
* powerClient
,
4995 IOPMPowerStateIndex oldPowerState
,
4996 IOPMPowerStateIndex newPowerState
)
4999 assert(service
== wrangler
);
5001 // This function implements half of the user active detection
5002 // by monitoring changes to the display wrangler's device desire.
5004 // User becomes active when either:
5005 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5006 // in max power state. This desire change in absence of a power state
5007 // change is detected within. This handles the case when user becomes
5008 // active while the display is already lit by setDisplayPowerOn().
5010 // 2. Power state change to max, and DeviceDesire is also at max.
5011 // Handled by displayWranglerNotification().
5013 // User becomes inactive when DeviceDesire drops to sleep state or below.
5015 DLOG("wrangler %s (ps %u, %u->%u)\n",
5016 powerClient
->getCStringNoCopy(),
5017 (uint32_t) service
->getPowerState(),
5018 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5020 if (powerClient
== gIOPMPowerClientDevice
)
5022 if ((newPowerState
> oldPowerState
) &&
5023 (newPowerState
== kWranglerPowerStateMax
) &&
5024 (service
->getPowerState() == kWranglerPowerStateMax
))
5026 evaluatePolicy( kStimulusEnterUserActiveState
);
5029 if ((newPowerState
< oldPowerState
) &&
5030 (newPowerState
<= kWranglerPowerStateSleep
))
5032 evaluatePolicy( kStimulusLeaveUserActiveState
);
5038 //******************************************************************************
5039 // User active state management
5040 //******************************************************************************
5042 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5045 _preventUserActive
= prevent
;
5046 if (wrangler
&& !_preventUserActive
)
5048 // Allowing transition to user active, but the wrangler may have
5049 // already powered ON in case of sleep cancel/revert. Poll the
5050 // same conditions checked for in displayWranglerNotification()
5051 // to bring the user active state up to date.
5053 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5054 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5055 kWranglerPowerStateMax
))
5057 evaluatePolicy( kStimulusEnterUserActiveState
);
5063 //******************************************************************************
5064 // Approve usage of delayed child notification by PM.
5065 //******************************************************************************
5067 bool IOPMrootDomain::shouldDelayChildNotification(
5068 IOService
* service
)
5070 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5071 (kFullWakeReasonNone
== fullWakeReason
) &&
5072 (kSystemTransitionWake
== _systemTransitionType
))
5074 DLOG("%s: delay child notify\n", service
->getName());
5080 //******************************************************************************
5081 // PM actions for PCI device.
5082 //******************************************************************************
5084 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5085 IOService
* service
,
5086 IOPMActions
* actions
,
5087 IOPMPowerStateIndex powerState
,
5088 IOPMPowerChangeFlags
* inOutChangeFlags
)
5090 pmTracer
->tracePCIPowerChange(
5091 PMTraceWorker::kPowerChangeStart
,
5092 service
, *inOutChangeFlags
,
5093 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5096 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5097 IOService
* service
,
5098 IOPMActions
* actions
,
5099 IOPMPowerStateIndex powerState
,
5100 IOPMPowerChangeFlags changeFlags
)
5102 pmTracer
->tracePCIPowerChange(
5103 PMTraceWorker::kPowerChangeCompleted
,
5104 service
, changeFlags
,
5105 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5108 //******************************************************************************
5111 // Override IOService::registerInterest() to intercept special clients.
5112 //******************************************************************************
5114 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5117 friend class IOPMrootDomain
;
5118 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5121 uint32_t ackTimeoutCnt
;
5125 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5127 IONotifier
* IOPMrootDomain::registerInterest(
5128 const OSSymbol
* typeOfInterest
,
5129 IOServiceInterestHandler handler
,
5130 void * target
, void * ref
)
5132 IOPMServiceInterestNotifier
*notifier
= 0;
5133 bool isSystemCapabilityClient
;
5134 bool isKernelCapabilityClient
;
5135 IOReturn rc
= kIOReturnError
;;
5137 isSystemCapabilityClient
=
5139 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5141 isKernelCapabilityClient
=
5143 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5145 if (isSystemCapabilityClient
)
5146 typeOfInterest
= gIOAppPowerStateInterest
;
5148 notifier
= new IOPMServiceInterestNotifier
;
5149 if (!notifier
) return NULL
;
5151 if (notifier
->init()) {
5152 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5154 if (rc
!= kIOReturnSuccess
) {
5155 notifier
->release();
5158 if (pmPowerStateQueue
)
5160 notifier
->ackTimeoutCnt
= 0;
5161 if (isSystemCapabilityClient
)
5164 if (pmPowerStateQueue
->submitPowerEvent(
5165 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5166 notifier
->release();
5169 if (isKernelCapabilityClient
)
5172 if (pmPowerStateQueue
->submitPowerEvent(
5173 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5174 notifier
->release();
5181 //******************************************************************************
5182 // systemMessageFilter
5184 //******************************************************************************
5186 bool IOPMrootDomain::systemMessageFilter(
5187 void * object
, void * arg1
, void * arg2
, void * arg3
)
5189 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5190 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5191 bool isCapClient
= false;
5195 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5196 (!isCapMsg
|| !_joinedCapabilityClients
||
5197 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5200 // Capability change message for app and kernel clients.
5204 if ((context
->notifyType
== kNotifyPriority
) ||
5205 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5208 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5209 (object
== (void *) systemCapabilityNotifier
))
5215 IOPMSystemCapabilityChangeParameters
* capArgs
=
5216 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5218 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5220 capArgs
->fromCapabilities
= 0;
5221 capArgs
->toCapabilities
= _currentCapability
;
5222 capArgs
->changeFlags
= 0;
5226 capArgs
->fromCapabilities
= _currentCapability
;
5227 capArgs
->toCapabilities
= _pendingCapability
;
5229 if (context
->isPreChange
)
5230 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5232 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5235 // Capability change messages only go to the PM configd plugin.
5236 // Wait for response post-change if capabilitiy is increasing.
5237 // Wait for response pre-change if capability is decreasing.
5239 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5240 ( (capabilityLoss
&& context
->isPreChange
) ||
5241 (!capabilityLoss
&& !context
->isPreChange
) ) )
5243 // app has not replied yet, wait for it
5244 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5251 // Capability client will always see kIOMessageCanSystemSleep,
5252 // even for demand sleep. It will also have a chance to veto
5253 // sleep one last time after all clients have responded to
5254 // kIOMessageSystemWillSleep
5256 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5257 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5259 if (object
== (OSObject
*) systemCapabilityNotifier
)
5265 // Not idle sleep, don't ask apps.
5266 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5272 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5274 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5275 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5276 (fullToDarkReason
== kIOPMSleepReasonIdle
))
5281 // Reject capability change messages for legacy clients.
5282 // Reject legacy system sleep messages for capability client.
5284 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5289 // Filter system sleep messages.
5291 if ((context
->notifyType
== kNotifyApps
) &&
5292 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5294 IOPMServiceInterestNotifier
*notify
;
5297 if ((notify
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
))
5300 if (notify
->ackTimeoutCnt
>= 3)
5301 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5303 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5306 else if ((context
->notifyType
== kNotifyPriority
) &&
5307 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5314 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5316 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5317 if (_joinedCapabilityClients
->getCount() == 0)
5319 DLOG("destroyed capability client set %p\n",
5320 OBFUSCATE(_joinedCapabilityClients
));
5321 _joinedCapabilityClients
->release();
5322 _joinedCapabilityClients
= 0;
5329 //******************************************************************************
5330 // setMaintenanceWakeCalendar
5332 //******************************************************************************
5334 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5335 const IOPMCalendarStruct
* calendar
)
5341 return kIOReturnBadArgument
;
5343 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5345 return kIOReturnNoMemory
;
5347 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5348 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5349 if (kIOReturnSuccess
== ret
)
5350 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5352 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5354 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5355 if (kIOReturnSuccess
== ret
)
5356 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5358 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5365 // MARK: Display Wrangler
5367 //******************************************************************************
5368 // displayWranglerNotification
5370 // Handle the notification when the IODisplayWrangler changes power state.
5371 //******************************************************************************
5373 IOReturn
IOPMrootDomain::displayWranglerNotification(
5374 void * target
, void * refCon
,
5375 UInt32 messageType
, IOService
* service
,
5376 void * messageArgument
, vm_size_t argSize
)
5379 int displayPowerState
;
5380 IOPowerStateChangeNotification
* params
=
5381 (IOPowerStateChangeNotification
*) messageArgument
;
5383 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5384 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5385 return kIOReturnUnsupported
;
5389 return kIOReturnUnsupported
;
5391 displayPowerState
= params
->stateNumber
;
5392 DLOG("wrangler %s ps %d\n",
5393 getIOMessageString(messageType
), displayPowerState
);
5395 switch (messageType
) {
5396 case kIOMessageDeviceWillPowerOff
:
5397 // Display wrangler has dropped power due to display idle
5398 // or force system sleep.
5400 // 4 Display ON kWranglerPowerStateMax
5401 // 3 Display Dim kWranglerPowerStateDim
5402 // 2 Display Sleep kWranglerPowerStateSleep
5403 // 1 Not visible to user
5404 // 0 Not visible to user kWranglerPowerStateMin
5406 if (displayPowerState
<= kWranglerPowerStateSleep
)
5407 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5410 case kIOMessageDeviceHasPoweredOn
:
5411 // Display wrangler has powered on due to user activity
5412 // or wake from sleep.
5414 if (kWranglerPowerStateMax
== displayPowerState
)
5416 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5418 // See comment in handleUpdatePowerClientForDisplayWrangler
5419 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5420 kWranglerPowerStateMax
)
5422 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5428 return kIOReturnUnsupported
;
5431 //******************************************************************************
5432 // displayWranglerMatchPublished
5434 // Receives a notification when the IODisplayWrangler is published.
5435 // When it's published we install a power state change handler.
5436 //******************************************************************************
5438 bool IOPMrootDomain::displayWranglerMatchPublished(
5441 IOService
* newService
,
5442 IONotifier
* notifier __unused
)
5445 // found the display wrangler, now install a handler
5446 if( !newService
->registerInterest( gIOGeneralInterest
,
5447 &displayWranglerNotification
, target
, 0) )
5455 #if defined(__i386__) || defined(__x86_64__)
5457 bool IOPMrootDomain::IONVRAMMatchPublished(
5460 IOService
* newService
,
5461 IONotifier
* notifier
)
5463 unsigned int len
= 0;
5464 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5465 OSNumber
*statusCode
= NULL
;
5467 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5469 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5470 if (statusCode
!= NULL
) {
5471 if (statusCode
->unsigned64BitValue() != 0) {
5472 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5473 MSG("System was rebooted due to Sleep/Wake failure\n");
5476 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5477 MSG("System was non-responsive and was rebooted by watchdog\n");
5481 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5483 if (notifier
) notifier
->remove();
5488 bool IOPMrootDomain::IONVRAMMatchPublished(
5491 IOService
* newService
,
5492 IONotifier
* notifier __unused
)
5499 //******************************************************************************
5502 //******************************************************************************
5504 void IOPMrootDomain::reportUserInput( void )
5511 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5514 wrangler
= (IOService
*) iter
->getNextObject();
5520 wrangler
->activityTickle(0,0);
5524 //******************************************************************************
5525 // latchDisplayWranglerTickle
5526 //******************************************************************************
5528 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5533 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5534 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5535 !checkSystemCanSustainFullWake())
5537 // Currently in dark wake, and not transitioning to full wake.
5538 // Full wake is unsustainable, so latch the tickle to prevent
5539 // the display from lighting up momentarily.
5540 wranglerTickleLatched
= true;
5544 wranglerTickleLatched
= false;
5547 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5549 wranglerTickleLatched
= false;
5551 pmPowerStateQueue
->submitPowerEvent(
5552 kPowerEventPolicyStimulus
,
5553 (void *) kStimulusDarkWakeActivityTickle
);
5556 return wranglerTickleLatched
;
5562 //******************************************************************************
5563 // setDisplayPowerOn
5565 // For root domain user client
5566 //******************************************************************************
5568 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
5570 if (checkSystemCanSustainFullWake())
5572 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
5573 (void *) 0, options
);
5580 //******************************************************************************
5583 // Notification on battery class IOPowerSource appearance
5584 //******************************************************************************
5586 bool IOPMrootDomain::batteryPublished(
5589 IOService
* resourceService
,
5590 IONotifier
* notifier __unused
)
5592 // rdar://2936060&4435589
5593 // All laptops have dimmable LCD displays
5594 // All laptops have batteries
5595 // So if this machine has a battery, publish the fact that the backlight
5596 // supports dimming.
5597 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5603 // MARK: System PM Policy
5605 //******************************************************************************
5606 // checkSystemSleepAllowed
5608 //******************************************************************************
5610 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
5611 uint32_t sleepReason
)
5615 // Conditions that prevent idle and demand system sleep.
5618 if (userDisabledAllSleep
)
5620 err
= 1; // 1. user-space sleep kill switch
5624 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
5626 err
= 2; // 2. restart or shutdown in progress
5633 // Conditions above pegs the system at full wake.
5634 // Conditions below prevent system sleep but does not prevent
5635 // dark wake, and must be called from gated context.
5638 err
= 3; // 3. config does not support sleep
5642 if (lowBatteryCondition
|| thermalWarningState
)
5644 break; // always sleep on low battery or when in thermal warning state
5647 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
5649 break; // always sleep on dark wake thermal emergencies
5652 if (preventSystemSleepList
->getCount() != 0)
5654 err
= 4; // 4. child prevent system sleep clamp
5658 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5659 kIOPMDriverAssertionLevelOn
)
5661 err
= 5; // 5. CPU assertion
5665 if (pciCantSleepValid
)
5667 if (pciCantSleepFlag
)
5668 err
= 6; // 6. PCI card does not support PM (cached)
5671 else if (sleepSupportedPEFunction
&&
5672 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5675 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5676 ret
= getPlatform()->callPlatformFunction(
5677 sleepSupportedPEFunction
, false,
5678 NULL
, NULL
, NULL
, NULL
);
5679 pciCantSleepValid
= true;
5680 pciCantSleepFlag
= false;
5681 if ((platformSleepSupport
& kPCICantSleep
) ||
5682 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5684 err
= 6; // 6. PCI card does not support PM
5685 pciCantSleepFlag
= true;
5694 DLOG("System sleep prevented by %d\n", err
);
5700 bool IOPMrootDomain::checkSystemSleepEnabled( void )
5702 return checkSystemSleepAllowed(0, 0);
5705 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
5708 return checkSystemSleepAllowed(1, sleepReason
);
5711 //******************************************************************************
5712 // checkSystemCanSustainFullWake
5713 //******************************************************************************
5715 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5718 if (lowBatteryCondition
|| thermalWarningState
)
5720 // Low battery wake, or received a low battery notification
5721 // while system is awake. This condition will persist until
5722 // the following wake.
5726 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
5728 // Graphics state is unknown and external display might not be probed.
5729 // Do not incorporate state that requires graphics to be in max power
5730 // such as desktopMode or clamshellDisabled.
5732 if (!acAdaptorConnected
)
5734 DLOG("full wake check: no AC\n");
5742 //******************************************************************************
5745 // Conditions that affect our wake/sleep decision has changed.
5746 // If conditions dictate that the system must remain awake, clamp power
5747 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5748 // is TRUE, then remove the power clamp and allow the power state to drop
5750 //******************************************************************************
5752 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5754 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5755 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5759 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
5761 changePowerStateToPriv(ON_STATE
);
5763 else if ( sleepASAP
)
5765 changePowerStateToPriv(SLEEP_STATE
);
5769 //******************************************************************************
5770 // dispatchPowerEvent
5772 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5773 //******************************************************************************
5775 void IOPMrootDomain::dispatchPowerEvent(
5776 uint32_t event
, void * arg0
, uint64_t arg1
)
5778 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
5783 case kPowerEventFeatureChanged
:
5784 messageClients(kIOPMMessageFeatureChange
, this);
5787 case kPowerEventReceivedPowerNotification
:
5788 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5791 case kPowerEventSystemBootCompleted
:
5794 systemBooting
= false;
5796 if (lowBatteryCondition
)
5798 privateSleepSystem (kIOPMSleepReasonLowPower
);
5800 // The rest is unnecessary since the system is expected
5801 // to sleep immediately. The following wake will update
5806 if (swd_flags
& SWD_VALID_LOGS
) {
5807 if (swd_flags
& SWD_LOGS_IN_MEM
) {
5808 sleepWakeDebugDumpFromMem(swd_logBufMap
);
5809 swd_logBufMap
->release();
5812 else if (swd_flags
& SWD_LOGS_IN_FILE
)
5813 sleepWakeDebugDumpFromFile();
5815 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
5816 // If logs are invalid, write the failure code
5817 sleepWakeDebugDumpFromMem(NULL
);
5819 // If lid is closed, re-send lid closed notification
5820 // now that booting is complete.
5821 if ( clamshellClosed
)
5823 handlePowerNotification(kLocalEvalClamshellCommand
);
5825 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5830 case kPowerEventSystemShutdown
:
5831 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5833 /* We set systemShutdown = true during shutdown
5834 to prevent sleep at unexpected times while loginwindow is trying
5835 to shutdown apps and while the OS is trying to transition to
5838 Set to true during shutdown, as soon as loginwindow shows
5839 the "shutdown countdown dialog", through individual app
5840 termination, and through black screen kernel shutdown.
5842 systemShutdown
= true;
5845 A shutdown was initiated, but then the shutdown
5846 was cancelled, clearing systemShutdown to false here.
5848 systemShutdown
= false;
5852 case kPowerEventUserDisabledSleep
:
5853 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5856 case kPowerEventRegisterSystemCapabilityClient
:
5857 if (systemCapabilityNotifier
)
5859 systemCapabilityNotifier
->release();
5860 systemCapabilityNotifier
= 0;
5864 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5865 systemCapabilityNotifier
->retain();
5867 /* intentional fall-through */
5869 case kPowerEventRegisterKernelCapabilityClient
:
5870 if (!_joinedCapabilityClients
)
5871 _joinedCapabilityClients
= OSSet::withCapacity(8);
5874 IONotifier
* notify
= (IONotifier
*) arg0
;
5875 if (_joinedCapabilityClients
)
5877 _joinedCapabilityClients
->setObject(notify
);
5878 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5884 case kPowerEventPolicyStimulus
:
5887 int stimulus
= (uintptr_t) arg0
;
5888 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5892 case kPowerEventAssertionCreate
:
5894 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5899 case kPowerEventAssertionRelease
:
5901 pmAssertions
->handleReleaseAssertion(arg1
);
5905 case kPowerEventAssertionSetLevel
:
5907 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5911 case kPowerEventQueueSleepWakeUUID
:
5912 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5914 case kPowerEventPublishSleepWakeUUID
:
5915 handlePublishSleepWakeUUID((bool)arg0
);
5918 case kPowerEventSetDisplayPowerOn
:
5919 if (!wrangler
) break;
5922 // Force wrangler to max power state. If system is in dark wake
5923 // this alone won't raise the wrangler's power state.
5925 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
5927 // System in dark wake, always requesting full wake should
5928 // not have any bad side-effects, even if the request fails.
5930 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5932 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
5933 requestFullWake( kFullWakeReasonDisplayOn
);
5938 // Relenquish desire to power up display.
5939 // Must first transition to state 1 since wrangler doesn't
5940 // power off the displays at state 0. At state 0 the root
5941 // domain is removed from the wrangler's power client list.
5943 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
5944 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
5950 //******************************************************************************
5951 // systemPowerEventOccurred
5953 // The power controller is notifying us of a hardware-related power management
5954 // event that we must handle.
5956 // systemPowerEventOccurred covers the same functionality that
5957 // receivePowerNotification does; it simply provides a richer API for conveying
5958 // more information.
5959 //******************************************************************************
5961 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5962 const OSSymbol
*event
,
5965 IOReturn attempt
= kIOReturnSuccess
;
5966 OSNumber
*newNumber
= NULL
;
5969 return kIOReturnBadArgument
;
5971 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5973 return kIOReturnInternalError
;
5975 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5977 newNumber
->release();
5982 void IOPMrootDomain::setThermalState(OSObject
*value
)
5986 if (gIOPMWorkLoop
->inGate() == false) {
5987 gIOPMWorkLoop
->runAction(
5988 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
5994 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
5995 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
5996 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6000 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6001 const OSSymbol
*event
,
6004 OSDictionary
*thermalsDict
= NULL
;
6005 bool shouldUpdate
= true;
6007 if (!event
|| !value
)
6008 return kIOReturnBadArgument
;
6011 // We reuse featuresDict Lock because it already exists and guards
6012 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6013 // of stepping on that lock.
6014 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6016 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6018 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6019 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6021 thermalsDict
= OSDictionary::withCapacity(1);
6024 if (!thermalsDict
) {
6025 shouldUpdate
= false;
6029 thermalsDict
->setObject (event
, value
);
6031 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6033 thermalsDict
->release();
6037 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6041 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6042 setThermalState(value
);
6044 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6047 return kIOReturnSuccess
;
6050 //******************************************************************************
6051 // receivePowerNotification
6053 // The power controller is notifying us of a hardware-related power management
6054 // event that we must handle. This may be a result of an 'environment' interrupt
6055 // from the power mgt micro.
6056 //******************************************************************************
6058 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6060 pmPowerStateQueue
->submitPowerEvent(
6061 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6062 return kIOReturnSuccess
;
6065 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6067 bool eval_clamshell
= false;
6072 * Local (IOPMrootDomain only) eval clamshell command
6074 if (msg
& kLocalEvalClamshellCommand
)
6076 eval_clamshell
= true;
6082 if (msg
& kIOPMOverTemp
)
6084 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6085 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6089 * Sleep if system is in dark wake
6091 if (msg
& kIOPMDWOverTemp
)
6093 DLOG("DarkWake thermal limits message received!\n");
6095 // Inform cap client that we're going to sleep
6096 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6103 if (msg
& kIOPMSleepNow
)
6105 privateSleepSystem (kIOPMSleepReasonSoftware
);
6111 if (msg
& kIOPMPowerEmergency
)
6113 lowBatteryCondition
= true;
6114 privateSleepSystem (kIOPMSleepReasonLowPower
);
6120 if (msg
& kIOPMClamshellOpened
)
6122 // Received clamshel open message from clamshell controlling driver
6123 // Update our internal state and tell general interest clients
6124 clamshellClosed
= false;
6125 clamshellExists
= true;
6127 // Don't issue a hid tickle when lid is open and polled on wake
6128 if (msg
& kIOPMSetValue
)
6130 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6135 informCPUStateChange(kInformLid
, 0);
6137 // Tell general interest clients
6138 sendClientClamshellNotification();
6140 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6141 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6142 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6143 if (aborting
) userActivityCount
++;
6144 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6149 * Send the clamshell interest notification since the lid is closing.
6151 if (msg
& kIOPMClamshellClosed
)
6153 // Received clamshel open message from clamshell controlling driver
6154 // Update our internal state and tell general interest clients
6155 clamshellClosed
= true;
6156 clamshellExists
= true;
6159 informCPUStateChange(kInformLid
, 1);
6161 // Tell general interest clients
6162 sendClientClamshellNotification();
6164 // And set eval_clamshell = so we can attempt
6165 eval_clamshell
= true;
6169 * Set Desktop mode (sent from graphics)
6171 * -> reevaluate lid state
6173 if (msg
& kIOPMSetDesktopMode
)
6175 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6176 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6178 sendClientClamshellNotification();
6180 // Re-evaluate the lid state
6181 eval_clamshell
= true;
6185 * AC Adaptor connected
6187 * -> reevaluate lid state
6189 if (msg
& kIOPMSetACAdaptorConnected
)
6191 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6192 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6195 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6197 // Tell BSD if AC is connected
6198 // 0 == external power source; 1 == on battery
6199 post_sys_powersource(acAdaptorConnected
? 0:1);
6201 sendClientClamshellNotification();
6203 // Re-evaluate the lid state
6204 eval_clamshell
= true;
6206 // Lack of AC may have latched a display wrangler tickle.
6207 // This mirrors the hardware's USB wake event latch, where a latched
6208 // USB wake event followed by an AC attach will trigger a full wake.
6209 latchDisplayWranglerTickle( false );
6212 // AC presence will reset the standy timer delay adjustment.
6213 _standbyTimerResetSeconds
= 0;
6215 if (!userIsActive
) {
6216 // Reset userActivityTime when power supply is changed(rdr 13789330)
6217 clock_get_uptime(&userActivityTime
);
6222 * Enable Clamshell (external display disappear)
6224 * -> reevaluate lid state
6226 if (msg
& kIOPMEnableClamshell
)
6228 // Re-evaluate the lid state
6229 // System should sleep on external display disappearance
6230 // in lid closed operation.
6231 if (true == clamshellDisabled
)
6233 eval_clamshell
= true;
6236 clamshellDisabled
= false;
6237 sendClientClamshellNotification();
6241 * Disable Clamshell (external display appeared)
6242 * We don't bother re-evaluating clamshell state. If the system is awake,
6243 * the lid is probably open.
6245 if (msg
& kIOPMDisableClamshell
)
6247 clamshellDisabled
= true;
6248 sendClientClamshellNotification();
6252 * Evaluate clamshell and SLEEP if appropiate
6254 if (eval_clamshell
&& clamshellClosed
)
6256 if (shouldSleepOnClamshellClosed())
6257 privateSleepSystem (kIOPMSleepReasonClamshell
);
6259 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6265 if (msg
& kIOPMPowerButton
)
6267 if (!wranglerAsleep
)
6269 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6270 // Check that power button sleep is enabled
6272 if( kOSBooleanTrue
!= getProperty(pbs
))
6273 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6281 //******************************************************************************
6284 // Evaluate root-domain policy in response to external changes.
6285 //******************************************************************************
6287 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6291 int idleSleepEnabled
: 1;
6292 int idleSleepDisabled
: 1;
6293 int displaySleep
: 1;
6294 int sleepDelayChanged
: 1;
6295 int evaluateDarkWake
: 1;
6296 int adjustPowerState
: 1;
6297 int userBecameInactive
: 1;
6302 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6309 case kStimulusDisplayWranglerSleep
:
6310 if (!wranglerAsleep
)
6312 // first transition to wrangler sleep or lower
6313 wranglerAsleep
= true;
6314 flags
.bit
.displaySleep
= true;
6318 case kStimulusDisplayWranglerWake
:
6319 displayIdleForDemandSleep
= false;
6320 wranglerAsleep
= false;
6323 case kStimulusEnterUserActiveState
:
6324 if (_preventUserActive
)
6326 DLOG("user active dropped\n");
6331 userIsActive
= true;
6332 userWasActive
= true;
6334 // Stay awake after dropping demand for display power on
6335 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6336 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6338 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6339 messageClients(kIOPMMessageUserIsActiveChanged
);
6341 flags
.bit
.idleSleepDisabled
= true;
6344 case kStimulusLeaveUserActiveState
:
6347 userIsActive
= false;
6348 clock_get_uptime(&userBecameInactiveTime
);
6349 flags
.bit
.userBecameInactive
= true;
6351 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6352 messageClients(kIOPMMessageUserIsActiveChanged
);
6356 case kStimulusAggressivenessChanged
:
6358 unsigned long minutesToIdleSleep
= 0;
6359 unsigned long minutesToDisplayDim
= 0;
6360 unsigned long minutesDelta
= 0;
6362 // Fetch latest display and system sleep slider values.
6363 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6364 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6365 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6366 (uint32_t) sleepSlider
,
6367 (uint32_t) minutesToIdleSleep
,
6368 (uint32_t) minutesToDisplayDim
);
6370 DLOG("idle time -> %ld secs (ena %d)\n",
6371 idleSeconds
, (minutesToIdleSleep
!= 0));
6373 if (0x7fffffff == minutesToIdleSleep
)
6374 minutesToIdleSleep
= idleSeconds
;
6376 // How long to wait before sleeping the system once
6377 // the displays turns off is indicated by 'extraSleepDelay'.
6379 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6380 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6381 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6384 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6385 flags
.bit
.idleSleepEnabled
= true;
6387 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6388 flags
.bit
.idleSleepDisabled
= true;
6390 if (((minutesDelta
!= extraSleepDelay
) ||
6391 (userActivityTime
!= userActivityTime_prev
)) &&
6392 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6393 flags
.bit
.sleepDelayChanged
= true;
6395 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6396 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6398 // Reconsider decision to remain in dark wake
6399 flags
.bit
.evaluateDarkWake
= true;
6402 sleepSlider
= minutesToIdleSleep
;
6403 extraSleepDelay
= minutesDelta
;
6404 userActivityTime_prev
= userActivityTime
;
6407 case kStimulusDemandSystemSleep
:
6408 displayIdleForDemandSleep
= true;
6409 if (wrangler
&& wranglerIdleSettings
)
6411 // Request wrangler idle only when demand sleep is triggered
6413 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6415 wrangler
->setProperties(wranglerIdleSettings
);
6416 DLOG("Requested wrangler idle\n");
6419 // arg = sleepReason
6420 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6423 case kStimulusAllowSystemSleepChanged
:
6424 flags
.bit
.adjustPowerState
= true;
6427 case kStimulusDarkWakeActivityTickle
:
6428 // arg == true implies real and not self generated wrangler tickle.
6429 // Update wake type on PM work loop instead of the tickle thread to
6430 // eliminate the possibility of an early tickle clobbering the wake
6431 // type set by the platform driver.
6433 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6435 if (false == wranglerTickled
)
6437 if (latchDisplayWranglerTickle(true))
6439 DLOG("latched tickle\n");
6443 wranglerTickled
= true;
6444 DLOG("Requesting full wake after dark wake activity tickle\n");
6445 requestFullWake( kFullWakeReasonLocalUser
);
6449 case kStimulusDarkWakeEntry
:
6450 case kStimulusDarkWakeReentry
:
6451 // Any system transitions since the last dark wake transition
6452 // will invalid the stimulus.
6454 if (arg
== _systemStateGeneration
)
6456 DLOG("dark wake entry\n");
6457 systemDarkWake
= true;
6459 // Keep wranglerAsleep an invariant when wrangler is absent
6461 wranglerAsleep
= true;
6463 if (kStimulusDarkWakeEntry
== stimulus
)
6465 clock_get_uptime(&userBecameInactiveTime
);
6466 flags
.bit
.evaluateDarkWake
= true;
6469 // Always accelerate disk spindown while in dark wake,
6470 // even if system does not support/allow sleep.
6472 cancelIdleSleepTimer();
6473 setQuickSpinDownTimeout();
6477 case kStimulusDarkWakeEvaluate
:
6480 flags
.bit
.evaluateDarkWake
= true;
6484 case kStimulusNoIdleSleepPreventers
:
6485 flags
.bit
.adjustPowerState
= true;
6488 } /* switch(stimulus) */
6490 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6492 if (darkWakeToSleepASAP
||
6493 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6495 uint32_t newSleepReason
;
6497 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6499 // System was previously in full wake. Sleep reason from
6500 // full to dark already recorded in fullToDarkReason.
6502 if (lowBatteryCondition
)
6503 newSleepReason
= kIOPMSleepReasonLowPower
;
6505 newSleepReason
= fullToDarkReason
;
6509 // In dark wake from system sleep.
6511 if (darkWakeSleepService
)
6512 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6514 newSleepReason
= kIOPMSleepReasonMaintenance
;
6517 if (checkSystemCanSleep(newSleepReason
))
6519 privateSleepSystem(newSleepReason
);
6522 else // non-maintenance (network) dark wake
6524 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
6526 // Release power clamp, and wait for children idle.
6527 adjustPowerState(true);
6531 changePowerStateToPriv(ON_STATE
);
6538 // The rest are irrelevant while system is in dark wake.
6542 if ((flags
.bit
.displaySleep
) &&
6543 (kFullWakeReasonDisplayOn
== fullWakeReason
))
6545 // kIOPMSleepReasonMaintenance?
6546 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
6549 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
6551 bool cancelQuickSpindown
= false;
6553 if (flags
.bit
.sleepDelayChanged
)
6555 // Cancel existing idle sleep timer and quick disk spindown.
6556 // New settings will be applied by the idleSleepEnabled flag
6557 // handler below if idle sleep is enabled.
6559 DLOG("extra sleep timer changed\n");
6560 cancelIdleSleepTimer();
6561 cancelQuickSpindown
= true;
6565 DLOG("user inactive\n");
6568 if (!userIsActive
&& sleepSlider
)
6570 startIdleSleepTimer(getTimeToIdleSleep());
6573 if (cancelQuickSpindown
)
6574 restoreUserSpinDownTimeout();
6577 if (flags
.bit
.idleSleepEnabled
)
6579 DLOG("idle sleep timer enabled\n");
6582 changePowerStateToPriv(ON_STATE
);
6585 startIdleSleepTimer( idleSeconds
);
6590 // Start idle timer if prefs now allow system sleep
6591 // and user is already inactive. Disk spindown is
6592 // accelerated upon timer expiration.
6596 startIdleSleepTimer(getTimeToIdleSleep());
6601 if (flags
.bit
.idleSleepDisabled
)
6603 DLOG("idle sleep timer disabled\n");
6604 cancelIdleSleepTimer();
6605 restoreUserSpinDownTimeout();
6609 if (flags
.bit
.adjustPowerState
)
6611 bool sleepASAP
= false;
6613 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6617 changePowerStateToPriv(ON_STATE
);
6620 // stay awake for at least idleSeconds
6621 startIdleSleepTimer(idleSeconds
);
6624 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6630 adjustPowerState(sleepASAP
);
6634 //******************************************************************************
6637 // Request transition from dark wake to full wake
6638 //******************************************************************************
6640 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
6642 uint32_t options
= 0;
6643 IOService
* pciRoot
= 0;
6644 bool promotion
= false;
6646 // System must be in dark wake and a valid reason for entering full wake
6647 if ((kFullWakeReasonNone
== reason
) ||
6648 (kFullWakeReasonNone
!= fullWakeReason
) ||
6649 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
6654 // Will clear reason upon exit from full wake
6655 fullWakeReason
= reason
;
6657 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
6658 kIOPMSystemCapabilityAudio
);
6660 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6661 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6662 !graphicsSuppressed
)
6664 // Promote to full wake while waking up to dark wake due to tickle.
6665 // PM will hold off notifying the graphics subsystem about system wake
6666 // as late as possible, so if a HID tickle does arrive, graphics can
6667 // power up on this same wake cycle. The latency to power up graphics
6668 // on the next cycle can be huge on some systems. However, once any
6669 // graphics suppression has taken effect, it is too late. All other
6670 // graphics devices must be similarly suppressed. But the delay till
6671 // the following cycle should be short.
6673 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
6674 kIOPMSystemCapabilityAudio
);
6676 // Immediately bring up audio and graphics
6677 pciRoot
= pciHostBridgeDriver
;
6678 willEnterFullWake();
6682 // Unsafe to cancel once graphics was powered.
6683 // If system woke from dark wake, the return to sleep can
6684 // be cancelled. "awake -> dark -> sleep" transition
6685 // can be canceled also, during the "dark --> sleep" phase
6686 // *prior* to driver power down.
6687 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
6688 _pendingCapability
== 0) {
6689 options
|= kIOPMSyncCancelPowerDown
;
6692 synchronizePowerTree(options
, pciRoot
);
6693 if (kFullWakeReasonLocalUser
== fullWakeReason
)
6695 // IOGraphics doesn't light the display even though graphics is
6696 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
6697 // So, do an explicit activity tickle
6699 wrangler
->activityTickle(0,0);
6702 // Log a timestamp for the initial full wake request.
6703 // System may not always honor this full wake request.
6704 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6709 clock_get_uptime(&now
);
6710 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
6711 absolutetime_to_nanoseconds(now
, &nsec
);
6712 MSG("full wake %s (reason %u) %u ms\n",
6713 promotion
? "promotion" : "request",
6714 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
6718 //******************************************************************************
6719 // willEnterFullWake
6721 // System will enter full wake from sleep, from dark wake, or from dark
6722 // wake promotion. This function aggregate things that are in common to
6723 // all three full wake transitions.
6725 // Assumptions: fullWakeReason was updated
6726 //******************************************************************************
6728 void IOPMrootDomain::willEnterFullWake( void )
6730 hibernateRetry
= false;
6731 sleepToStandby
= false;
6732 sleepTimerMaintenance
= false;
6734 _systemMessageClientMask
= kSystemMessageClientPowerd
|
6735 kSystemMessageClientLegacyApp
;
6737 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
6739 // Initial graphics full power
6740 _systemMessageClientMask
|= kSystemMessageClientKernel
;
6742 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
6743 setProperty(gIOPMUserTriggeredFullWakeKey
,
6744 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
6745 kOSBooleanTrue
: kOSBooleanFalse
);
6748 IOHibernateSetWakeCapabilities(_pendingCapability
);
6751 IOService::setAdvisoryTickleEnable( true );
6752 tellClients(kIOMessageSystemWillPowerOn
);
6753 preventTransitionToUserActive(false);
6756 //******************************************************************************
6757 // fullWakeDelayedWork
6759 // System has already entered full wake. Invoked by a delayed thread call.
6760 //******************************************************************************
6762 void IOPMrootDomain::fullWakeDelayedWork( void )
6764 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
6765 // Not gated, don't modify state
6766 if ((kSystemTransitionNone
== _systemTransitionType
) &&
6767 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6769 receivePowerNotification( kLocalEvalClamshellCommand
);
6774 //******************************************************************************
6775 // evaluateAssertions
6777 //******************************************************************************
6778 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6780 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6782 messageClients(kIOPMMessageDriverAssertionsChanged
);
6784 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6787 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6789 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6790 wrangler
->setIgnoreIdleTimer( value
);
6794 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6795 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6797 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6798 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6800 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6801 updatePreventIdleSleepList(this, true);
6804 DLOG("Driver assertion ReservedBit7 dropped\n");
6805 updatePreventIdleSleepList(this, false);
6813 //******************************************************************************
6816 //******************************************************************************
6818 void IOPMrootDomain::pmStatsRecordEvent(
6820 AbsoluteTime timestamp
)
6822 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6823 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6826 OSData
*publishPMStats
= NULL
;
6828 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6830 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6832 switch (eventIndex
) {
6833 case kIOPMStatsHibernateImageWrite
:
6835 gPMStats
.hibWrite
.start
= nsec
;
6837 gPMStats
.hibWrite
.stop
= nsec
;
6840 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6841 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6844 case kIOPMStatsHibernateImageRead
:
6846 gPMStats
.hibRead
.start
= nsec
;
6848 gPMStats
.hibRead
.stop
= nsec
;
6851 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6852 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6854 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6855 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6856 publishPMStats
->release();
6857 bzero(&gPMStats
, sizeof(gPMStats
));
6864 * Appends a record of the application response to
6865 * IOPMrootDomain::pmStatsAppResponses
6867 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6868 const OSSymbol
*response
,
6874 IOPMPowerStateIndex powerState
)
6876 OSDictionary
*responseDescription
= NULL
;
6877 OSNumber
*delayNum
= NULL
;
6878 OSNumber
*powerCaps
= NULL
;
6879 OSNumber
*pidNum
= NULL
;
6880 OSNumber
*msgNum
= NULL
;
6881 const OSSymbol
*appname
;
6882 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
6883 IOPMServiceInterestNotifier
*notify
= 0;
6885 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
6887 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
6888 notify
->ackTimeoutCnt
++;
6890 notify
->ackTimeoutCnt
= 0;
6894 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
6895 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
6899 responseDescription
= OSDictionary::withCapacity(5);
6900 if (responseDescription
)
6903 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6906 msgNum
= OSNumber::withNumber(messageType
, 32);
6908 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6912 if (name
&& (strlen(name
) > 0))
6914 appname
= OSSymbol::withCString(name
);
6916 responseDescription
->setObject(_statsNameKey
, appname
);
6921 if (app_pid
!= -1) {
6922 pidNum
= OSNumber::withNumber(app_pid
, 32);
6924 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6929 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6931 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6932 delayNum
->release();
6935 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
6936 powerCaps
= OSNumber::withNumber(powerState
, 32);
6938 #if !defined(__i386__) && !defined(__x86_64__)
6939 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
6941 powerState
, delay_ms
);
6946 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
6949 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
6950 powerCaps
->release();
6953 sleep
= OSSymbol::withCString("Sleep");
6954 wake
= OSSymbol::withCString("Wake");
6955 if (_systemTransitionType
== kSystemTransitionSleep
) {
6956 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
6958 else if (_systemTransitionType
== kSystemTransitionWake
) {
6959 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
6961 else if (_systemTransitionType
== kSystemTransitionCapability
) {
6962 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
6963 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
6964 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
6965 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
6967 if (sleep
) sleep
->release();
6968 if (wake
) wake
->release();
6972 IOLockLock(pmStatsLock
);
6973 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
6974 pmStatsAppResponses
->setObject(responseDescription
);
6976 IOLockUnlock(pmStatsLock
);
6978 responseDescription
->release();
6985 // MARK: PMTraceWorker
6987 //******************************************************************************
6988 // TracePoint support
6990 //******************************************************************************
6992 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6993 "IOPMRegisterNVRAMTracePointHandler"
6995 IOReturn
IOPMrootDomain::callPlatformFunction(
6996 const OSSymbol
* functionName
,
6997 bool waitForFunction
,
6998 void * param1
, void * param2
,
6999 void * param3
, void * param4
)
7001 if (pmTracer
&& functionName
&&
7002 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7003 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7005 uint32_t tracePointPhases
, tracePointPCI
;
7006 uint64_t statusCode
;
7008 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7009 pmTracer
->tracePointTarget
= (void *) param2
;
7010 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7011 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7012 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7013 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
7015 MSG("Sleep failure code 0x%08x 0x%08x\n",
7016 tracePointPCI
, tracePointPhases
);
7018 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7019 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7021 return kIOReturnSuccess
;
7024 else if (functionName
&&
7025 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7027 if (gSleepPolicyHandler
)
7028 return kIOReturnExclusiveAccess
;
7030 return kIOReturnBadArgument
;
7031 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7032 gSleepPolicyTarget
= (void *) param2
;
7033 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7034 return kIOReturnSuccess
;
7038 return super::callPlatformFunction(
7039 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7042 void IOPMrootDomain::tracePoint( uint8_t point
)
7044 if (systemBooting
) return;
7046 if (kIOPMTracePointWakeCapabilityClients
== point
)
7047 acceptSystemWakeEvents(false);
7049 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
7050 pmTracer
->tracePoint(point
);
7053 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
7055 if (systemBooting
) return;
7057 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
7058 pmTracer
->tracePoint(point
, data
);
7061 void IOPMrootDomain::traceDetail( uint32_t detail
)
7064 pmTracer
->traceDetail( detail
);
7068 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7069 IOReportConfigureAction action
,
7074 if (action
!= kIOReportGetDimensions
) goto exit
;
7076 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7077 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7078 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7079 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7080 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7085 return super::configureReport(channelList
, action
, result
, destination
);
7089 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7090 IOReportUpdateAction action
,
7096 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7097 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7101 if (action
!= kIOReportCopyChannelData
) goto exit
;
7103 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7104 ch_id
= channelList
->channels
[cnt
].channel_id
;
7106 if ((ch_id
== kSleepCntChID
) ||
7107 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7108 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7112 if (ch_id
== kSleepCntChID
)
7113 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7114 else if (ch_id
== kDarkWkCntChID
)
7115 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7116 else if (ch_id
== kUserWkCntChID
)
7117 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7119 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7120 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7121 dest
->appendBytes(data2cpy
, size2cpy
);
7125 return super::updateReport(channelList
, action
, result
, destination
);
7129 //******************************************************************************
7130 // PMTraceWorker Class
7132 //******************************************************************************
7135 #define super OSObject
7136 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7138 #define kPMBestGuessPCIDevicesCount 25
7139 #define kPMMaxRTCBitfieldSize 32
7141 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7145 me
= OSTypeAlloc( PMTraceWorker
);
7146 if (!me
|| !me
->init())
7151 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7153 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7154 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7155 // this dictionary lazily.
7157 me
->pciDeviceBitMappings
= NULL
;
7158 me
->pciMappingLock
= IOLockAlloc();
7159 me
->tracePhase
= kIOPMTracePointSystemUp
;
7160 me
->loginWindowPhase
= 0;
7161 me
->traceData32
= 0;
7165 void PMTraceWorker::RTC_TRACE(void)
7167 if (tracePointHandler
&& tracePointTarget
)
7171 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
7174 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7175 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7179 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7181 const OSSymbol
* deviceName
;
7184 IOLockLock(pciMappingLock
);
7186 if (!pciDeviceBitMappings
)
7188 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7189 if (!pciDeviceBitMappings
)
7193 // Check for bitmask overflow.
7194 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7197 if ((deviceName
= pciDevice
->copyName()) &&
7198 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7199 pciDeviceBitMappings
->setObject(deviceName
))
7201 index
= pciDeviceBitMappings
->getCount() - 1;
7202 _LOG("PMTrace PCI array: set object %s => %d\n",
7203 deviceName
->getCStringNoCopy(), index
);
7206 deviceName
->release();
7207 if (!addedToRegistry
&& (index
>= 0))
7208 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7211 IOLockUnlock(pciMappingLock
);
7215 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7218 if (pciDeviceBitMappings
)
7220 IOLockLock(pciMappingLock
);
7221 ok
= pciDeviceBitMappings
->serialize(s
);
7222 IOLockUnlock(pciMappingLock
);
7227 void PMTraceWorker::tracePoint(uint8_t phase
)
7229 // clear trace detail when phase begins
7230 if (tracePhase
!= phase
)
7235 DLOG("trace point 0x%02x\n", tracePhase
);
7239 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
7241 // clear trace detail when phase begins
7242 if (tracePhase
!= phase
)
7248 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
7252 void PMTraceWorker::traceDetail(uint32_t detail
)
7254 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
7257 traceData32
= detail
;
7258 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7263 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
7265 loginWindowPhase
= phase
;
7267 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
7271 void PMTraceWorker::tracePCIPowerChange(
7272 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7275 uint32_t expectedFlag
;
7277 // Ignore PCI changes outside of system sleep/wake.
7278 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7279 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7282 // Only record the WillChange transition when going to sleep,
7283 // and the DidChange on the way up.
7284 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7285 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7286 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7287 if (changeFlags
!= expectedFlag
)
7290 // Mark this device off in our bitfield
7291 if (bitNum
< kPMMaxRTCBitfieldSize
)
7293 bitMask
= (1 << bitNum
);
7295 if (kPowerChangeStart
== type
)
7297 traceData32
|= bitMask
;
7298 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7299 service
->getName(), bitNum
, bitMask
, traceData32
);
7303 traceData32
&= ~bitMask
;
7304 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7305 service
->getName(), bitNum
, bitMask
, traceData32
);
7308 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7313 uint64_t PMTraceWorker::getPMStatusCode( )
7315 return (((uint64_t)traceData32
<< 32) | (tracePhase
<< 24) |
7316 (loginWindowPhase
<< 16) | (traceData8
<< 8));
7321 // MARK: PMHaltWorker
7323 //******************************************************************************
7324 // PMHaltWorker Class
7326 //******************************************************************************
7328 static unsigned int gPMHaltBusyCount
;
7329 static unsigned int gPMHaltIdleCount
;
7330 static int gPMHaltDepth
;
7331 static unsigned long gPMHaltEvent
;
7332 static IOLock
* gPMHaltLock
= 0;
7333 static OSArray
* gPMHaltArray
= 0;
7334 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
7336 PMHaltWorker
* PMHaltWorker::worker( void )
7342 me
= OSTypeAlloc( PMHaltWorker
);
7343 if (!me
|| !me
->init())
7346 me
->lock
= IOLockAlloc();
7350 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
7351 me
->retain(); // thread holds extra retain
7352 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
7357 thread_deallocate(thread
);
7362 if (me
) me
->release();
7366 void PMHaltWorker::free( void )
7368 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7374 return OSObject::free();
7377 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
7379 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
7381 IOLockLock( gPMHaltLock
);
7383 me
->depth
= gPMHaltDepth
;
7384 IOLockUnlock( gPMHaltLock
);
7386 while (me
->depth
>= 0)
7388 PMHaltWorker::work( me
);
7390 IOLockLock( gPMHaltLock
);
7391 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
7393 // This is the last thread to finish work on this level,
7394 // inform everyone to start working on next lower level.
7396 me
->depth
= gPMHaltDepth
;
7397 gPMHaltIdleCount
= 0;
7398 thread_wakeup((event_t
) &gPMHaltIdleCount
);
7402 // One or more threads are still working on this level,
7403 // this thread must wait.
7404 me
->depth
= gPMHaltDepth
- 1;
7406 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
7407 } while (me
->depth
!= gPMHaltDepth
);
7409 IOLockUnlock( gPMHaltLock
);
7412 // No more work to do, terminate thread
7413 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
7414 thread_wakeup( &gPMHaltDepth
);
7418 void PMHaltWorker::work( PMHaltWorker
* me
)
7420 IOService
* service
;
7422 AbsoluteTime startTime
;
7431 // Claim an unit of work from the shared pool
7432 IOLockLock( gPMHaltLock
);
7433 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7436 service
= (IOService
*)inner
->getAnyObject();
7440 inner
->removeObject(service
);
7443 IOLockUnlock( gPMHaltLock
);
7445 break; // no more work at this depth
7447 clock_get_uptime(&startTime
);
7449 if (!service
->isInactive() &&
7450 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7452 IOLockLock(me
->lock
);
7453 me
->startTime
= startTime
;
7454 me
->service
= service
;
7455 me
->timeout
= false;
7456 IOLockUnlock(me
->lock
);
7458 service
->systemWillShutdown( gPMHaltEvent
);
7460 // Wait for driver acknowledgement
7461 IOLockLock(me
->lock
);
7462 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7464 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7467 timeout
= me
->timeout
;
7468 IOLockUnlock(me
->lock
);
7471 deltaTime
= computeDeltaTimeMS(&startTime
);
7472 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7473 (gIOKitDebug
& kIOLogPMRootDomain
))
7475 LOG("%s driver %s (%p) took %u ms\n",
7476 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7477 "PowerOff" : "Restart",
7478 service
->getName(), OBFUSCATE(service
),
7479 (uint32_t) deltaTime
);
7487 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7490 AbsoluteTime startTime
;
7491 AbsoluteTime endTime
;
7495 IOLockLock(me
->lock
);
7496 if (me
->service
&& !me
->timeout
)
7498 startTime
= me
->startTime
;
7500 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7502 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7503 absolutetime_to_nanoseconds(endTime
, &nano
);
7505 if (nano
> 3000000000ULL)
7508 MSG("%s still waiting on %s\n",
7509 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7510 "PowerOff" : "Restart",
7511 me
->service
->getName());
7514 IOLockUnlock(me
->lock
);
7518 //******************************************************************************
7519 // acknowledgeSystemWillShutdown
7521 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7522 //******************************************************************************
7524 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7526 PMHaltWorker
* worker
;
7532 //DLOG("%s acknowledged\n", from->getName());
7533 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7536 worker
= (PMHaltWorker
*) prop
;
7537 IOLockLock(worker
->lock
);
7538 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
7539 thread_wakeup((event_t
) worker
);
7540 IOLockUnlock(worker
->lock
);
7545 DLOG("%s acknowledged without worker property\n",
7551 //******************************************************************************
7552 // notifySystemShutdown
7554 // Notify all objects in PM tree that system will shutdown or restart
7555 //******************************************************************************
7558 notifySystemShutdown( IOService
* root
, unsigned long event
)
7560 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
7561 IORegistryIterator
* iter
;
7562 IORegistryEntry
* entry
;
7565 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
7566 AbsoluteTime deadline
;
7567 unsigned int totalNodes
= 0;
7569 unsigned int rootDepth
;
7570 unsigned int numWorkers
;
7576 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
7578 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
7580 // Iterate the entire PM tree starting from root
7582 rootDepth
= root
->getDepth( gIOPowerPlane
);
7583 if (!rootDepth
) goto done
;
7585 // debug - for repeated test runs
7586 while (PMHaltWorker::metaClass
->getInstanceCount())
7591 gPMHaltArray
= OSArray::withCapacity(40);
7592 if (!gPMHaltArray
) goto done
;
7595 gPMHaltArray
->flushCollection();
7599 gPMHaltLock
= IOLockAlloc();
7600 if (!gPMHaltLock
) goto done
;
7603 if (!gPMHaltClientAcknowledgeKey
)
7605 gPMHaltClientAcknowledgeKey
=
7606 OSSymbol::withCStringNoCopy("PMShutdown");
7607 if (!gPMHaltClientAcknowledgeKey
) goto done
;
7610 gPMHaltEvent
= event
;
7612 // Depth-first walk of PM plane
7614 iter
= IORegistryIterator::iterateOver(
7615 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
7619 while ((entry
= iter
->getNextObject()))
7621 node
= OSDynamicCast(IOService
, entry
);
7626 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
7629 depth
= node
->getDepth( gIOPowerPlane
);
7630 if (depth
<= rootDepth
)
7635 // adjust to zero based depth
7636 depth
-= (rootDepth
+ 1);
7638 // gPMHaltArray is an array of containers, each container
7639 // refers to nodes with the same depth.
7641 count
= gPMHaltArray
->getCount();
7642 while (depth
>= count
)
7644 // expand array and insert placeholders
7645 gPMHaltArray
->setObject(PLACEHOLDER
);
7648 count
= gPMHaltArray
->getCount();
7651 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
7652 if (inner
== PLACEHOLDER
)
7654 inner
= OSSet::withCapacity(40);
7657 gPMHaltArray
->replaceObject(depth
, inner
);
7662 // PM nodes that appear more than once in the tree will have
7663 // the same depth, OSSet will refuse to add the node twice.
7665 ok
= inner
->setObject(node
);
7668 DLOG("Skipped PM node %s\n", node
->getName());
7674 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
7677 if (inner
!= PLACEHOLDER
)
7678 count
= inner
->getCount();
7679 DLOG("Nodes at depth %u = %u\n", i
, count
);
7682 // strip placeholders (not all depths are populated)
7684 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
7686 if (inner
== PLACEHOLDER
)
7688 gPMHaltArray
->removeObject(i
);
7691 count
= inner
->getCount();
7692 if (count
> numWorkers
)
7694 totalNodes
+= count
;
7698 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
7701 gPMHaltBusyCount
= 0;
7702 gPMHaltIdleCount
= 0;
7703 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
7705 // Create multiple workers (and threads)
7707 if (numWorkers
> kPMHaltMaxWorkers
)
7708 numWorkers
= kPMHaltMaxWorkers
;
7710 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
7711 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
7713 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7714 workers
[i
] = PMHaltWorker::worker();
7716 // Wait for workers to exhaust all available work
7718 IOLockLock(gPMHaltLock
);
7719 while (gPMHaltDepth
>= 0)
7721 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
7723 waitResult
= IOLockSleepDeadline(
7724 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
7725 if (THREAD_TIMED_OUT
== waitResult
)
7728 clock_get_uptime(&now
);
7730 IOLockUnlock(gPMHaltLock
);
7731 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
7734 PMHaltWorker::checkTimeout(workers
[i
], &now
);
7736 IOLockLock(gPMHaltLock
);
7739 IOLockUnlock(gPMHaltLock
);
7741 // Release all workers
7743 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7746 workers
[i
]->release();
7747 // worker also retained by it's own thread
7751 DLOG("%s done\n", __FUNCTION__
);
7756 // MARK: Kernel Assertion
7758 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7760 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
7761 IOPMDriverAssertionType whichAssertionBits
,
7762 IOPMDriverAssertionLevel assertionLevel
,
7763 IOService
*ownerService
,
7764 const char *ownerDescription
)
7767 IOPMDriverAssertionID newAssertion
;
7772 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
7774 if (kIOReturnSuccess
== ret
)
7775 return newAssertion
;
7780 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
7783 return kIOReturnInternalError
;
7785 return pmAssertions
->releaseAssertion(releaseAssertion
);
7789 IOReturn
IOPMrootDomain::setPMAssertionLevel(
7790 IOPMDriverAssertionID assertionID
,
7791 IOPMDriverAssertionLevel assertionLevel
)
7793 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
7796 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
7798 IOPMDriverAssertionType sysLevels
;
7800 if (!pmAssertions
|| whichAssertion
== 0)
7801 return kIOPMDriverAssertionLevelOff
;
7803 sysLevels
= pmAssertions
->getActivatedAssertions();
7805 // Check that every bit set in argument 'whichAssertion' is asserted
7806 // in the aggregate bits.
7807 if ((sysLevels
& whichAssertion
) == whichAssertion
)
7808 return kIOPMDriverAssertionLevelOn
;
7810 return kIOPMDriverAssertionLevelOff
;
7813 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
7816 return kIOReturnNotFound
;
7818 return pmAssertions
->setUserAssertionLevels(inLevels
);
7821 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
7825 pmAssertions
->publishProperties();
7827 return( IOService::serializeProperties(s
) );
7830 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
7832 OSObject
*obj
= NULL
;
7833 obj
= IOService::copyProperty(aKey
);
7835 if (obj
) return obj
;
7837 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
7838 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
7839 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
7840 return OSBoolean::withBoolean(true);
7842 return OSBoolean::withBoolean(false);
7846 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
7847 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
7848 if (swd_flags
& SWD_VALID_LOGS
)
7849 return OSBoolean::withBoolean(true);
7851 return OSBoolean::withBoolean(false);
7856 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
7857 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
7858 * issued by DisplayWrangler on darkwake.
7860 if (!strcmp(aKey
, "DesktopMode")) {
7862 return OSBoolean::withBoolean(true);
7864 return OSBoolean::withBoolean(false);
7866 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
7867 if (displayIdleForDemandSleep
) {
7868 return OSBoolean::withBoolean(true);
7871 return OSBoolean::withBoolean(false);
7875 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
7877 OSArray
* array
= 0;
7879 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount())
7880 array
= OSArray::withArray(_systemWakeEventsArray
);
7885 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
7887 OSArray
* array
= 0;
7888 IOLockLock(pmStatsLock
);
7889 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
7890 array
= OSArray::withArray(pmStatsAppResponses
);
7891 pmStatsAppResponses
->flushCollection();
7893 IOLockUnlock(pmStatsLock
);
7901 // MARK: Wake Event Reporting
7903 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
7906 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
7910 //******************************************************************************
7911 // acceptSystemWakeEvents
7913 // Private control for the acceptance of driver wake event claims.
7914 //******************************************************************************
7916 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
7918 bool logWakeReason
= false;
7923 gWakeReasonString
[0] = '\0';
7924 if (!_systemWakeEventsArray
)
7925 _systemWakeEventsArray
= OSArray::withCapacity(4);
7926 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
7927 _systemWakeEventsArray
->flushCollection();
7931 _acceptSystemWakeEvents
= false;
7936 MSG("system wake events:%s\n", gWakeReasonString
);
7939 //******************************************************************************
7940 // claimSystemWakeEvent
7942 // For a driver to claim a device is the source/conduit of a system wake event.
7943 //******************************************************************************
7945 void IOPMrootDomain::claimSystemWakeEvent(
7948 const char * reason
,
7949 OSObject
* details
)
7951 const OSSymbol
* deviceName
= 0;
7952 OSNumber
* deviceRegId
= 0;
7953 OSNumber
* claimTime
= 0;
7954 OSData
* flagsData
= 0;
7955 OSString
* reasonString
= 0;
7956 OSDictionary
* d
= 0;
7960 pmEventTimeStamp(×tamp
);
7962 if (!device
|| !reason
) return;
7964 deviceName
= device
->copyName(gIOServicePlane
);
7965 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
7966 claimTime
= OSNumber::withNumber(timestamp
, 64);
7967 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
7968 reasonString
= OSString::withCString(reason
);
7969 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
7970 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
7973 d
->setObject(gIONameKey
, deviceName
);
7974 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
7975 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
7976 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
7977 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
7979 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
7982 if (!gWakeReasonSysctlRegistered
)
7984 // Lazy registration until the platform driver stops registering
7986 gWakeReasonSysctlRegistered
= true;
7988 if (_acceptSystemWakeEvents
)
7990 ok
= _systemWakeEventsArray
->setObject(d
);
7991 if (gWakeReasonString
[0] != '\0')
7992 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
7993 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
7998 if (deviceName
) deviceName
->release();
7999 if (deviceRegId
) deviceRegId
->release();
8000 if (claimTime
) claimTime
->release();
8001 if (flagsData
) flagsData
->release();
8002 if (reasonString
) reasonString
->release();
8003 if (d
) d
->release();
8006 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8009 // MARK: PMSettingHandle
8011 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8013 void PMSettingHandle::free( void )
8017 pmso
->clientHandleFreed();
8026 // MARK: PMSettingObject
8029 #define super OSObject
8030 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8033 * Static constructor/initializer for PMSettingObject
8035 PMSettingObject
*PMSettingObject::pmSettingObject(
8036 IOPMrootDomain
*parent_arg
,
8037 IOPMSettingControllerCallback handler_arg
,
8038 OSObject
*target_arg
,
8039 uintptr_t refcon_arg
,
8040 uint32_t supportedPowerSources
,
8041 const OSSymbol
* settings
[],
8042 OSObject
**handle_obj
)
8044 uint32_t settingCount
= 0;
8045 PMSettingObject
*pmso
= 0;
8046 PMSettingHandle
*pmsh
= 0;
8048 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8051 // count OSSymbol entries in NULL terminated settings array
8052 while (settings
[settingCount
]) {
8055 if (0 == settingCount
)
8058 pmso
= new PMSettingObject
;
8059 if (!pmso
|| !pmso
->init())
8062 pmsh
= new PMSettingHandle
;
8063 if (!pmsh
|| !pmsh
->init())
8066 queue_init(&pmso
->calloutQueue
);
8067 pmso
->parent
= parent_arg
;
8068 pmso
->func
= handler_arg
;
8069 pmso
->target
= target_arg
;
8070 pmso
->refcon
= refcon_arg
;
8071 pmso
->settingCount
= settingCount
;
8073 pmso
->retain(); // handle holds a retain on pmso
8077 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8078 if (pmso
->publishedFeatureID
) {
8079 for (unsigned int i
=0; i
<settingCount
; i
++) {
8080 // Since there is now at least one listener to this setting, publish
8081 // PM root domain support for it.
8082 parent_arg
->publishPMSetting( settings
[i
],
8083 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8091 if (pmso
) pmso
->release();
8092 if (pmsh
) pmsh
->release();
8096 void PMSettingObject::free( void )
8098 if (publishedFeatureID
) {
8099 for (uint32_t i
=0; i
<settingCount
; i
++) {
8100 if (publishedFeatureID
[i
]) {
8101 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8105 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8111 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8113 (*func
)(target
, type
, object
, refcon
);
8116 void PMSettingObject::clientHandleFreed( void )
8118 parent
->deregisterPMSettingObject(this);
8122 // MARK: PMAssertionsTracker
8124 //*********************************************************************************
8125 //*********************************************************************************
8126 //*********************************************************************************
8127 // class PMAssertionsTracker Implementation
8129 #define kAssertUniqueIDStart 500
8131 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8133 PMAssertionsTracker
*myself
;
8135 myself
= new PMAssertionsTracker
;
8139 myself
->owner
= rootDomain
;
8140 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8141 myself
->assertionsArray
= OSArray::withCapacity(5);
8142 myself
->assertionsKernel
= 0;
8143 myself
->assertionsUser
= 0;
8144 myself
->assertionsCombined
= 0;
8145 myself
->assertionsArrayLock
= IOLockAlloc();
8146 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8148 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8156 * - Update assertionsKernel to reflect the state of all
8157 * assertions in the kernel.
8158 * - Update assertionsCombined to reflect both kernel & user space.
8160 void PMAssertionsTracker::tabulate(void)
8164 PMAssertStruct
*_a
= NULL
;
8167 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8168 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8172 assertionsKernel
= 0;
8173 assertionsCombined
= 0;
8175 if (!assertionsArray
)
8178 if ((count
= assertionsArray
->getCount()))
8180 for (i
=0; i
<count
; i
++)
8182 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8185 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8186 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8187 assertionsKernel
|= _a
->assertionBits
;
8192 tabulateProducerCount
++;
8193 assertionsCombined
= assertionsKernel
| assertionsUser
;
8195 if ((assertionsKernel
!= oldKernel
) ||
8196 (assertionsCombined
!= oldCombined
))
8198 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8202 void PMAssertionsTracker::publishProperties( void )
8204 OSArray
*assertionsSummary
= NULL
;
8206 if (tabulateConsumerCount
!= tabulateProducerCount
)
8208 IOLockLock(assertionsArrayLock
);
8210 tabulateConsumerCount
= tabulateProducerCount
;
8212 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8214 assertionsSummary
= copyAssertionsArray();
8215 if (assertionsSummary
)
8217 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8218 assertionsSummary
->release();
8222 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8225 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8227 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8229 IOLockUnlock(assertionsArrayLock
);
8233 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8235 PMAssertStruct
*_a
= NULL
;
8242 && (count
= assertionsArray
->getCount()))
8244 for (i
=0; i
<count
; i
++)
8246 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8249 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8250 if (_a
&& (_id
== _a
->id
)) {
8267 /* PMAssertionsTracker::handleCreateAssertion
8268 * Perform assertion work on the PM workloop. Do not call directly.
8270 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8276 IOLockLock(assertionsArrayLock
);
8277 assertionsArray
->setObject(newAssertion
);
8278 IOLockUnlock(assertionsArrayLock
);
8279 newAssertion
->release();
8283 return kIOReturnSuccess
;
8286 /* PMAssertionsTracker::createAssertion
8287 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8290 IOReturn
PMAssertionsTracker::createAssertion(
8291 IOPMDriverAssertionType which
,
8292 IOPMDriverAssertionLevel level
,
8293 IOService
*serviceID
,
8294 const char *whoItIs
,
8295 IOPMDriverAssertionID
*outID
)
8297 OSData
*dataStore
= NULL
;
8298 PMAssertStruct track
;
8300 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8301 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8302 track
.level
= level
;
8303 track
.assertionBits
= which
;
8304 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8305 track
.ownerService
= serviceID
;
8306 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8307 track
.modifiedTime
= 0;
8308 pmEventTimeStamp(&track
.createdTime
);
8310 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8313 if (track
.ownerString
)
8314 track
.ownerString
->release();
8315 return kIOReturnNoMemory
;
8320 if (owner
&& owner
->pmPowerStateQueue
) {
8321 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8324 return kIOReturnSuccess
;
8327 /* PMAssertionsTracker::handleReleaseAssertion
8328 * Runs in PM workloop. Do not call directly.
8330 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8331 IOPMDriverAssertionID _id
)
8336 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8339 return kIOReturnNotFound
;
8341 IOLockLock(assertionsArrayLock
);
8342 if (assertStruct
->ownerString
)
8343 assertStruct
->ownerString
->release();
8345 assertionsArray
->removeObject(index
);
8346 IOLockUnlock(assertionsArrayLock
);
8349 return kIOReturnSuccess
;
8352 /* PMAssertionsTracker::releaseAssertion
8353 * Releases an assertion and affects system behavior if appropiate.
8354 * Actual work happens on PM workloop.
8356 IOReturn
PMAssertionsTracker::releaseAssertion(
8357 IOPMDriverAssertionID _id
)
8359 if (owner
&& owner
->pmPowerStateQueue
) {
8360 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8362 return kIOReturnSuccess
;
8365 /* PMAssertionsTracker::handleSetAssertionLevel
8366 * Runs in PM workloop. Do not call directly.
8368 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8369 IOPMDriverAssertionID _id
,
8370 IOPMDriverAssertionLevel _level
)
8372 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8376 if (!assertStruct
) {
8377 return kIOReturnNotFound
;
8380 IOLockLock(assertionsArrayLock
);
8381 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8382 assertStruct
->level
= _level
;
8383 IOLockUnlock(assertionsArrayLock
);
8386 return kIOReturnSuccess
;
8389 /* PMAssertionsTracker::setAssertionLevel
8391 IOReturn
PMAssertionsTracker::setAssertionLevel(
8392 IOPMDriverAssertionID _id
,
8393 IOPMDriverAssertionLevel _level
)
8395 if (owner
&& owner
->pmPowerStateQueue
) {
8396 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8397 (void *)(uintptr_t)_level
, _id
);
8400 return kIOReturnSuccess
;
8403 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8405 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8409 if (new_user_levels
!= assertionsUser
)
8411 assertionsUser
= new_user_levels
;
8412 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8416 return kIOReturnSuccess
;
8419 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8420 IOPMDriverAssertionType new_user_levels
)
8422 if (gIOPMWorkLoop
) {
8423 gIOPMWorkLoop
->runAction(
8424 OSMemberFunctionCast(
8427 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8429 (void *) &new_user_levels
, 0, 0, 0);
8432 return kIOReturnSuccess
;
8436 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8440 OSArray
*outArray
= NULL
;
8442 if (!assertionsArray
||
8443 (0 == (count
= assertionsArray
->getCount())) ||
8444 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8449 for (i
=0; i
<count
; i
++)
8451 PMAssertStruct
*_a
= NULL
;
8453 OSDictionary
*details
= NULL
;
8455 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8456 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8458 OSNumber
*_n
= NULL
;
8460 details
= OSDictionary::withCapacity(7);
8464 outArray
->setObject(details
);
8467 _n
= OSNumber::withNumber(_a
->id
, 64);
8469 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8472 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8474 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8477 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8479 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8482 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
8484 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
8487 _n
= OSNumber::withNumber(_a
->level
, 64);
8489 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8492 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8494 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8498 if (_a
->ownerString
) {
8499 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8508 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8510 return assertionsCombined
;
8513 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8514 IOPMDriverAssertionType type
)
8516 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8518 return kIOPMDriverAssertionLevelOn
;
8520 return kIOPMDriverAssertionLevelOff
;
8524 //*********************************************************************************
8525 //*********************************************************************************
8526 //*********************************************************************************
8529 static void pmEventTimeStamp(uint64_t *recordTS
)
8537 // We assume tsec fits into 32 bits; 32 bits holds enough
8538 // seconds for 136 years since the epoch in 1970.
8539 clock_get_calendar_microtime(&tsec
, &tusec
);
8542 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8544 *recordTS
|= (uint32_t)tusec
;
8545 *recordTS
|= ((uint64_t)tsec
<< 32);
8551 // MARK: IORootParent
8553 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8555 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
8557 // The reason that root domain needs a root parent is to facilitate demand
8558 // sleep, since a power change from the root parent cannot be vetoed.
8560 // The above statement is no longer true since root domain now performs
8561 // demand sleep using overrides. But root parent remains to avoid changing
8562 // the power tree stacking. Root parent is parked at the max power state.
8565 static IOPMPowerState patriarchPowerStates
[2] =
8567 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8568 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8571 void IORootParent::initialize( void )
8575 bool IORootParent::start( IOService
* nub
)
8577 IOService::start(nub
);
8578 attachToParent( getRegistryRoot(), gIOPowerPlane
);
8580 registerPowerDriver(this, patriarchPowerStates
, 2);
8585 void IORootParent::shutDownSystem( void )
8589 void IORootParent::restartSystem( void )
8593 void IORootParent::sleepSystem( void )
8597 void IORootParent::dozeSystem( void )
8601 void IORootParent::sleepToDoze( void )
8605 void IORootParent::wakeSystem( void )
8609 OSObject
* IORootParent::copyProperty( const char * aKey
) const
8611 return (IOService::copyProperty(aKey
));
8615 #if defined(__i386__) || defined(__x86_64__)
8616 IOReturn
IOPMrootDomain::restartWithStackshot()
8618 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
8619 return kIOReturnError
;
8621 takeStackshot(true, true);
8623 return kIOReturnSuccess
;
8626 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
8628 takeStackshot(wdogTrigger
, false);
8631 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
)
8633 swd_hdr
* hdr
= NULL
;
8635 uint32_t wdog_panic
= 0;
8642 uint32_t bytesRemaining
;
8644 OSString
* UUIDstring
= NULL
;
8646 IOMemoryMap
* logBufMap
= NULL
;
8648 swd_stackshot_hdr
*stackshotHdr
= NULL
;
8649 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
8653 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
8654 (wdog_panic
== 1)) {
8655 // If boot-arg is set to panic on sleep/wake hang, call panic
8656 panic("Sleep/Wake hang detected\n");
8659 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
8660 // If current boot is due to this watch dog trigger restart in previous boot,
8661 // then don't trigger again until at least 1 successful sleep & wake.
8662 sleepCnt
= displayWakeCnt
= 1;
8663 if (!(sleepCnt
&& displayWakeCnt
)) {
8664 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
8665 PEHaltRestart(kPEHaltCPU
);
8672 if (sleepWakeDebugIsWdogEnabled() == false)
8675 if (swd_buffer
== NULL
) {
8676 sleepWakeDebugMemAlloc();
8677 if (swd_buffer
== NULL
) return;
8680 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
8684 hdr
= (swd_hdr
*)swd_buffer
;
8685 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
8686 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
8688 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
8689 const char *str
= UUIDstring
->getCStringNoCopy();
8690 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
8693 DLOG("Data for current UUID already exists\n");
8698 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
8699 bytesRemaining
= SWD_BUF_SIZE
- hdr
->spindump_offset
;
8701 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
8702 hdr
->is_osx_watchdog
= isOSXWatchdog
;
8704 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
8706 while (bytesRemaining
> sizeof(swd_stackshot_hdr
)) {
8708 stackshotHdr
= (swd_stackshot_hdr
*)dstAddr
;
8709 stackshotHdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
8710 stackshotHdr
->size
= 0;
8711 bytesRemaining
-= sizeof(swd_stackshot_hdr
);
8712 dstAddr
+= sizeof(swd_stackshot_hdr
);
8714 if (isOSXWatchdog
) {
8716 size
= bytesRemaining
;
8717 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
;
8719 else if (cnt
== 0) {
8721 * Take stackshot of all process on first sample. Size is restricted
8722 * to SWD_INITIAL_STACK_SIZE
8725 size
= (bytesRemaining
> SWD_INITIAL_STACK_SIZE
) ? SWD_INITIAL_STACK_SIZE
: bytesRemaining
;
8726 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY
;
8729 /* Take sample of kernel threads only */
8731 size
= bytesRemaining
;
8735 stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, &stackshotHdr
->size
);
8737 dstAddr
+= stackshotHdr
->size
;
8738 bytesRemaining
-= stackshotHdr
->size
;
8740 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt
, stackshotHdr
->size
, bytesRemaining
);
8741 if ((stackshotHdr
->size
== 0) || (++cnt
== 10))
8743 IOSleep(10); // 10 ms
8746 hdr
->spindump_size
= (SWD_BUF_SIZE
- bytesRemaining
- hdr
->spindump_offset
);
8749 memset(hdr
->cps
, 0x20, sizeof(hdr
->cps
));
8750 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "\ncps: %d", ((IOService
*)this)->getPowerState());
8751 code
= pmTracer
->getPMStatusCode();
8752 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
8753 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
8754 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
8755 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
8756 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
8759 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
8760 /* Header & rootdomain log is constantly changing and is not covered by CRC */
8761 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
8762 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
8763 len
= sizeof(addr64_t
)*3;
8764 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
8765 data
[0], data
[1], data
[2]);
8767 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
8769 DLOG("Failed to update nvram boot-args\n");
8775 gRootDomain
->swd_lock
= 0;
8778 IOLog("Restarting to collect Sleep wake debug logs\n");
8779 PEHaltRestart(kPERestartCPU
);
8782 logBufMap
= sleepWakeDebugRetrieve();
8784 sleepWakeDebugDumpFromMem(logBufMap
);
8785 logBufMap
->release();
8791 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
8793 vm_size_t size
= SWD_BUF_SIZE
;
8795 swd_hdr
*hdr
= NULL
;
8797 IOBufferMemoryDescriptor
*memDesc
= NULL
;
8800 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
8803 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
8806 // Try allocating above 4GB. If that fails, try at 2GB
8807 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
8808 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
8809 size
, 0xFFFFFFFF00000000ULL
);
8811 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
8812 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
8813 size
, 0xFFFFFFFF10000000ULL
);
8816 if (memDesc
== NULL
)
8818 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
8823 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
8824 memset(hdr
, 0, sizeof(swd_hdr
));
8826 hdr
->signature
= SWD_HDR_SIGNATURE
;
8827 hdr
->alloc_size
= size
;
8829 hdr
->spindump_offset
= sizeof(swd_hdr
);
8830 swd_buffer
= (void *)hdr
;
8831 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
8834 gRootDomain
->swd_lock
= 0;
8837 void IOPMrootDomain::sleepWakeDebugEnableWdog()
8839 swd_flags
|= SWD_WDOG_ENABLED
;
8841 sleepWakeDebugMemAlloc();
8844 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
8846 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
8847 !systemBooting
&& !systemShutdown
);
8850 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
8852 struct vnode
*vp
= NULL
;
8853 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
8854 kauth_cred_t cred
= vfs_context_ucred(ctx
);
8855 struct vnode_attr va
;
8856 errno_t error
= EIO
;
8858 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
8859 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
8861 IOLog("Failed to open the file %s\n", name
);
8865 VATTR_WANTED(&va
, va_nlink
);
8866 /* Don't dump to non-regular files or files with links. */
8867 if (vp
->v_type
!= VREG
||
8868 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
8869 IOLog("Bailing as this is not a regular file\n");
8873 VATTR_SET(&va
, va_data_size
, 0);
8874 vnode_setattr(vp
, &va
, ctx
);
8877 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
8878 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
8880 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
8882 DLOG("Saved %d bytes to file %s\n",len
, name
);
8885 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
8886 if (ctx
) vfs_context_rele(ctx
);
8892 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
8893 struct vnode
*srcVp
,
8894 vfs_context_t srcCtx
,
8895 char *tmpBuf
, uint64_t tmpBufSize
,
8897 const char *dstFname
,
8901 struct vnode
*vp
= NULL
;
8902 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
8903 struct vnode_attr va
;
8904 errno_t error
= EIO
;
8905 uint64_t bytesToRead
, bytesToWrite
;
8906 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
8907 uint32_t newcrc
= 0;
8909 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
8910 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
8912 DLOG("Failed to open the file %s\n", dstFname
);
8916 VATTR_WANTED(&va
, va_nlink
);
8917 /* Don't dump to non-regular files or files with links. */
8918 if (vp
->v_type
!= VREG
||
8919 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
8920 DLOG("Bailing as this is not a regular file\n");
8924 VATTR_SET(&va
, va_data_size
, 0);
8925 vnode_setattr(vp
, &va
, ctx
);
8927 writeFileOffset
= 0;
8929 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
8930 readFileOffset
= trunc_page(srcOffset
);
8932 DLOG("Read file (numBytes:0x%llx)\n", bytesToRead
);
8933 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
8934 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
8935 vfs_context_ucred(srcCtx
), (int *) 0,
8936 vfs_context_proc(srcCtx
));
8938 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
8942 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
8943 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
8944 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
8947 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
8949 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
8950 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
8951 vfs_context_ucred(ctx
), (int *) 0,
8952 vfs_context_proc(ctx
));
8954 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
8958 writeFileOffset
+= bytesToWrite
;
8959 numBytes
-= bytesToWrite
;
8960 srcOffset
+= bytesToWrite
;
8963 if (crc
!= newcrc
) {
8964 swd_stackshot_hdr
*shdr
= (swd_stackshot_hdr
*)tmpBuf
;;
8966 /* Set statckshot size to 0 if crc doesn't match */
8967 shdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
8970 assert(tmpBufSize
> sizeof(swd_stackshot_hdr
));
8971 bytesToWrite
= round_page(sizeof(swd_stackshot_hdr
));
8972 vn_rdwr(UIO_WRITE
, vp
, (char *)tmpBuf
, bytesToWrite
, 0,
8973 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
8974 vfs_context_ucred(ctx
), (int *) 0,
8975 vfs_context_proc(ctx
));
8977 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
8982 error
= vnode_close(vp
, FWRITE
, ctx
);
8983 DLOG("vnode_close returned 0x%x\n", error
);
8985 if (ctx
) vfs_context_rele(ctx
);
8993 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
8997 char hibernateFilename
[MAXPATHLEN
+1];
8998 char PMStatusCode
[100];
9000 swd_hdr
*hdr
= NULL
;
9001 uint32_t stacksSize
, logSize
;
9002 uint64_t tmpBufSize
;
9003 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9004 errno_t error
= EIO
;
9005 OSObject
*obj
= NULL
;
9006 OSString
*str
= NULL
;
9007 OSNumber
*failStat
= NULL
;
9008 struct vnode
*vp
= NULL
;
9009 vfs_context_t ctx
= NULL
;
9011 struct vnode_attr va
;
9012 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9013 IOHibernateImageHeader
*imageHdr
;
9015 DLOG("sleepWakeDebugDumpFromFile\n");
9016 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9019 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9023 hibernateFilename
[0] = 0;
9024 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9026 if ((str
= OSDynamicCast(OSString
, obj
)))
9027 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9028 sizeof(hibernateFilename
));
9031 if (!hibernateFilename
[0]) {
9032 DMSG("sleepWakeDebugDumpFromFile: Failed to hib file name\n");
9035 DLOG("sleepWakeDebugDumpFromFile: Hib file name %s\n", hibernateFilename
);
9037 /* Allocate a temp buffer to copy data between files */
9038 tmpBufSize
= 2*4096;
9039 tmpBufDesc
= IOBufferMemoryDescriptor::
9040 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9041 tmpBufSize
, PAGE_SIZE
);
9044 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9048 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9050 ctx
= vfs_context_create(vfs_context_current());
9051 if (vnode_open(hibernateFilename
, (FREAD
| O_NOFOLLOW
), 0,
9052 VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9054 DMSG("sleepWakeDebugDumpFromFile: Failed to open the hibernate file %s\n", hibernateFilename
);
9058 VATTR_WANTED(&va
, va_nlink
);
9059 VATTR_WANTED(&va
, va_data_alloc
);
9060 if (vp
->v_type
!= VREG
||
9061 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9062 DMSG("sleepWakeDebugDumpFromFile: Bailing as this is not a regular file\n");
9066 /* Read the sleepimage file header */
9067 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9068 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9069 vfs_context_ucred(ctx
), (int *) 0,
9070 vfs_context_proc(ctx
));
9072 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d)\n", round_page(sizeof(IOHibernateImageHeader
)), rc
);
9076 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9077 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9078 DMSG("sleepWakeDebugDumpFromFile: File header has unexpected value 0x%x\n", imageHdr
->signature
);
9082 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9083 hdrOffset
= imageHdr
->deviceBlockSize
;
9084 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9085 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx)\n", va
.va_data_alloc
);
9089 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9090 /* Read the sleep/wake debug header(swd_hdr) */
9091 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9092 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9093 vfs_context_ucred(ctx
), (int *) 0,
9094 vfs_context_proc(ctx
));
9096 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9097 round_page(sizeof(swd_hdr
)), rc
);
9101 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9102 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9103 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9104 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9105 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9108 stacksSize
= hdr
->spindump_size
;
9110 /* Get stacks & log offsets in the image file */
9111 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9112 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9113 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9115 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9116 getDumpStackFilename(hdr
), stacksSize
, hdr
->crc
);
9117 if (error
== EFAULT
) {
9118 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9121 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9122 getDumpLogFilename(hdr
), logSize
, 0);
9124 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9129 // Write just the SleepWakeLog.dump with failure code
9132 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9133 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9134 fcode
= failStat
->unsigned64BitValue();
9135 fname
= kSleepWakeLogFilename
;
9138 fname
= kAppleOSXWatchdogLogFilename
;
9140 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9141 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9142 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9143 sleepWakeDebugSaveFile(fname
, PMStatusCode
, sizeof(PMStatusCode
));
9145 gRootDomain
->swd_lock
= 0;
9147 if (vp
) vnode_close(vp
, FREAD
, ctx
);
9148 if (ctx
) vfs_context_rele(ctx
);
9149 if (tmpBufDesc
) tmpBufDesc
->release();
9153 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
9155 IOVirtualAddress srcBuf
= NULL
;
9156 char *stackBuf
= NULL
, *logOffset
= NULL
;
9159 errno_t error
= EIO
;
9160 uint64_t bufSize
= 0;
9161 swd_hdr
*hdr
= NULL
;
9162 char PMStatusCode
[100];
9163 OSNumber
*failStat
= NULL
;
9165 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9168 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
9170 DLOG("Nothing saved to dump to file\n");
9174 hdr
= (swd_hdr
*)srcBuf
;
9175 bufSize
= logBufMap
->getLength();
9176 if (bufSize
<= sizeof(swd_hdr
))
9178 IOLog("SleepWake log buffer contents are invalid\n");
9182 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
9184 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
9185 if (error
) goto exit
;
9187 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9188 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9190 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
9191 if (error
) goto exit
;
9193 hdr
->spindump_size
= 0;
9198 // Write just the SleepWakeLog.dump with failure code
9200 const char *sname
, *lname
;
9201 swd_stackshot_hdr shdr
;
9203 /* Try writing an empty stacks file */
9204 shdr
.magic
= SWD_STACKSHOTHDR_MAGIC
;
9208 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9209 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9210 fcode
= failStat
->unsigned64BitValue();
9211 lname
= kSleepWakeLogFilename
;
9212 sname
= kSleepWakeStackFilename
;
9215 lname
= kAppleOSXWatchdogLogFilename
;
9216 sname
= kAppleOSXWatchdogStackFilename
;
9219 sleepWakeDebugSaveFile(sname
, (char*)(&shdr
), sizeof(shdr
));
9220 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9221 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9222 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9223 sleepWakeDebugSaveFile(lname
, PMStatusCode
, sizeof(PMStatusCode
));
9225 gRootDomain
->swd_lock
= 0;
9228 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9230 IOVirtualAddress vaddr
= NULL
;
9231 IOMemoryDescriptor
* desc
= NULL
;
9232 IOMemoryMap
* logBufMap
= NULL
;
9236 uint64_t bufSize
= 0;
9238 uint64_t newcrc
= 0;
9240 swd_hdr
*hdr
= NULL
;
9245 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9248 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
9249 DLOG("No sleepWakeDebug note to read\n");
9253 if (len
== strlen("sleepimage")) {
9255 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
9257 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
9258 DLOG("sleepWakeDebugRetrieve: in file logs\n");
9259 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
9263 else if (len
== sizeof(addr64_t
)*3)
9264 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
9266 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
9272 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9273 data
[0], data
[1], data
[2]);
9274 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
9278 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
9280 IOLog("SleepWake log buffer contents are invalid\n");
9284 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9285 bufSize
, crc
, paddr
);
9288 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
9289 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
9292 IOLog("Fail to map SleepWake log buffer\n");
9296 logBufMap
= desc
->map();
9298 vaddr
= logBufMap
->getVirtualAddress();
9301 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
9302 IOLog("Fail to map SleepWake log buffer\n");
9306 hdr
= (swd_hdr
*)vaddr
;
9307 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
9309 IOLog("SleepWake log buffer contents are invalid\n");
9314 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
9315 hdr
->spindump_size
);
9316 if (newcrc
!= crc
) {
9317 IOLog("SleepWake log buffer contents are invalid\n");
9322 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
9326 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
9328 if (logBufMap
) logBufMap
->release();
9331 if (desc
) desc
->release();
9332 gRootDomain
->swd_lock
= 0;
9339 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
9343 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
)
9345 #pragma unused(restart)
9346 #pragma unused(isOSXWatchdog)
9349 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9352 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
9355 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9356 struct vnode
*srcVp
,
9357 vfs_context_t srcCtx
,
9358 char *tmpBuf
, uint64_t tmpBufSize
,
9360 const char *dstFname
,
9367 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
9371 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9376 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9380 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9385 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)