2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOCPU.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOTimeStamp.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/pwr_mgt/IOPMPrivate.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOReturn.h>
44 #include <IOKit/IONVRAM.h>
45 #include "RootDomainUserClient.h"
46 #include "IOKit/pwr_mgt/IOPowerConnection.h"
47 #include "IOPMPowerStateQueue.h"
48 #include <IOKit/IOCatalogue.h>
49 #include <IOKit/IOReportMacros.h>
50 #include "IOKitKernelInternal.h"
52 #include <IOKit/IOHibernatePrivate.h>
54 #include <console/video_console.h>
55 #include <sys/syslog.h>
56 #include <sys/sysctl.h>
57 #include <sys/vnode.h>
58 #include <sys/vnode_internal.h>
59 #include <sys/fcntl.h>
62 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
63 #include "IOServicePMPrivate.h"
66 #include <mach/shared_region.h>
67 #include <kern/clock.h>
70 #if defined(__i386__) || defined(__x86_64__)
72 #include "IOPMrootDomainInternal.h"
76 #define kIOPMrootDomainClass "IOPMrootDomain"
77 #define LOG_PREFIX "PMRD: "
81 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
84 do { kprintf(LOG_PREFIX x); } while (false)
86 #define DLOG(x...) do { \
87 if (kIOLogPMRootDomain & gIOKitDebug) \
88 kprintf(LOG_PREFIX x); \
91 #define DMSG(x...) do { \
92 if (kIOLogPMRootDomain & gIOKitDebug) { \
93 kprintf(LOG_PREFIX x); IOLog(x); \
100 #define CHECK_THREAD_CONTEXT
101 #ifdef CHECK_THREAD_CONTEXT
102 static IOWorkLoop
* gIOPMWorkLoop
= 0;
103 #define ASSERT_GATED() \
105 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
106 panic("RootDomain: not inside PM gate"); \
110 #define ASSERT_GATED()
111 #endif /* CHECK_THREAD_CONTEXT */
113 #define CAP_LOSS(c) \
114 (((_pendingCapability & (c)) == 0) && \
115 ((_currentCapability & (c)) != 0))
117 #define CAP_GAIN(c) \
118 (((_currentCapability & (c)) == 0) && \
119 ((_pendingCapability & (c)) != 0))
121 #define CAP_CHANGE(c) \
122 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
124 #define CAP_CURRENT(c) \
125 ((_currentCapability & (c)) != 0)
127 #define CAP_HIGHEST(c) \
128 ((_highestCapability & (c)) != 0)
130 #if defined(__i386__) || defined(__x86_64__)
131 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
134 // Event types for IOPMPowerStateQueue::submitPowerEvent()
136 kPowerEventFeatureChanged
= 1, // 1
137 kPowerEventReceivedPowerNotification
, // 2
138 kPowerEventSystemBootCompleted
, // 3
139 kPowerEventSystemShutdown
, // 4
140 kPowerEventUserDisabledSleep
, // 5
141 kPowerEventRegisterSystemCapabilityClient
, // 6
142 kPowerEventRegisterKernelCapabilityClient
, // 7
143 kPowerEventPolicyStimulus
, // 8
144 kPowerEventAssertionCreate
, // 9
145 kPowerEventAssertionRelease
, // 10
146 kPowerEventAssertionSetLevel
, // 11
147 kPowerEventQueueSleepWakeUUID
, // 12
148 kPowerEventPublishSleepWakeUUID
, // 13
149 kPowerEventSetDisplayPowerOn
// 14
152 // For evaluatePolicy()
153 // List of stimuli that affects the root domain policy.
155 kStimulusDisplayWranglerSleep
, // 0
156 kStimulusDisplayWranglerWake
, // 1
157 kStimulusAggressivenessChanged
, // 2
158 kStimulusDemandSystemSleep
, // 3
159 kStimulusAllowSystemSleepChanged
, // 4
160 kStimulusDarkWakeActivityTickle
, // 5
161 kStimulusDarkWakeEntry
, // 6
162 kStimulusDarkWakeReentry
, // 7
163 kStimulusDarkWakeEvaluate
, // 8
164 kStimulusNoIdleSleepPreventers
, // 9
165 kStimulusEnterUserActiveState
, // 10
166 kStimulusLeaveUserActiveState
// 11
170 IOReturn
OSKextSystemSleepOrWake( UInt32
);
172 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
173 extern "C" addr64_t
kvtophys(vm_offset_t va
);
174 extern "C" int stack_snapshot_from_kernel(pid_t pid
, void *buf
, uint32_t size
, uint32_t flags
, unsigned *bytesTraced
);
176 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
177 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
178 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
179 static void pmEventTimeStamp(uint64_t *recordTS
);
181 // "IOPMSetSleepSupported" callPlatformFunction name
182 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
183 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
185 #define kIOSleepSupportedKey "IOSleepSupported"
186 #define kIOPMSystemCapabilitiesKey "System Capabilities"
188 #define kIORequestWranglerIdleKey "IORequestIdle"
189 #define kDefaultWranglerIdlePeriod 25 // in milliseconds
191 #define kIOSleepWakeDebugKey "Persistent-memory-note"
193 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
194 | kIOPMSupportedOnBatt \
195 | kIOPMSupportedOnUPS)
197 #define kLocalEvalClamshellCommand (1 << 15)
198 #define kIdleSleepRetryInterval (3 * 60)
201 kWranglerPowerStateMin
= 0,
202 kWranglerPowerStateSleep
= 2,
203 kWranglerPowerStateDim
= 3,
204 kWranglerPowerStateMax
= 4
215 #define ON_POWER kIOPMPowerOn
216 #define RESTART_POWER kIOPMRestart
217 #define SLEEP_POWER kIOPMAuxPowerOn
219 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
221 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
222 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
223 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
224 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
227 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
228 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
229 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
230 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
231 #define kIOPMRootDomainWakeTypeUser "User"
232 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
233 #define kIOPMRootDomainWakeTypeNetwork "Network"
234 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
235 #define kIOPMRootDomainWakeTypeNotification "Notification"
236 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
238 // Special interest that entitles the interested client from receiving
239 // all system messages. Only used by powerd.
241 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
243 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
244 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
249 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
250 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
252 #define kAggressivesMinValue 1
255 kAggressivesStateBusy
= 0x01,
256 kAggressivesStateQuickSpindown
= 0x02
259 struct AggressivesRecord
{
265 struct AggressivesRequest
{
271 AggressivesRecord record
;
276 kAggressivesRequestTypeService
= 1,
277 kAggressivesRequestTypeRecord
281 kAggressivesOptionSynchronous
= 0x00000001,
282 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
283 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
284 kAggressivesOptionQuickSpindownMask
= 0x00000300
288 kAggressivesRecordFlagModified
= 0x00000001,
289 kAggressivesRecordFlagMinValue
= 0x00000002
294 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
295 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
296 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
297 kDarkWakeFlagHIDTickleMask
= 0x03,
298 kDarkWakeFlagAlarmIsDark
= 0x0100,
299 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
300 kDarkWakeFlagAudioNotSuppressed
= 0x0400
303 static IOPMrootDomain
* gRootDomain
;
304 static IONotifier
* gSysPowerDownNotifier
= 0;
305 static UInt32 gSleepOrShutdownPending
= 0;
306 static UInt32 gWillShutdown
= 0;
307 static UInt32 gPagingOff
= 0;
308 static UInt32 gSleepWakeUUIDIsSet
= false;
309 static uint32_t gAggressivesState
= 0;
311 uuid_string_t bootsessionuuid_string
;
313 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
314 static uint32_t gNoIdleFlag
= 0;
315 static PMStatsStruct gPMStats
;
318 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
319 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
320 static void * gSleepPolicyTarget
;
323 struct timeval gIOLastSleepTime
;
324 struct timeval gIOLastWakeTime
;
326 static char gWakeReasonString
[128];
327 static bool gWakeReasonSysctlRegistered
= false;
329 #if defined(__i386__) || defined(__x86_64__)
330 static bool gSpinDumpBufferFull
= false;
333 static unsigned int gPMHaltBusyCount
;
334 static unsigned int gPMHaltIdleCount
;
335 static int gPMHaltDepth
;
336 static uint32_t gPMHaltMessageType
;
337 static IOLock
* gPMHaltLock
= 0;
338 static OSArray
* gPMHaltArray
= 0;
339 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
340 static bool gPMQuiesced
;
342 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
343 #define kCPUUnknownIndex 9999999
350 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
351 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
352 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
353 const OSSymbol
*gIOPMStatsApplicationResponsePrompt
;
354 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
356 #define kBadPMFeatureID 0
360 * Opaque handle passed to clients of registerPMSettingController()
362 class PMSettingHandle
: public OSObject
364 OSDeclareFinalStructors( PMSettingHandle
)
365 friend class PMSettingObject
;
368 PMSettingObject
*pmso
;
369 void free(void) APPLE_KEXT_OVERRIDE
;
374 * Internal object to track each PM setting controller
376 class PMSettingObject
: public OSObject
378 OSDeclareFinalStructors( PMSettingObject
)
379 friend class IOPMrootDomain
;
382 queue_head_t calloutQueue
;
384 IOPMrootDomain
*parent
;
385 PMSettingHandle
*pmsh
;
386 IOPMSettingControllerCallback func
;
389 uint32_t *publishedFeatureID
;
390 uint32_t settingCount
;
393 void free(void) APPLE_KEXT_OVERRIDE
;
396 static PMSettingObject
*pmSettingObject(
397 IOPMrootDomain
*parent_arg
,
398 IOPMSettingControllerCallback handler_arg
,
399 OSObject
*target_arg
,
400 uintptr_t refcon_arg
,
401 uint32_t supportedPowerSources
,
402 const OSSymbol
*settings
[],
403 OSObject
**handle_obj
);
405 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
406 void clientHandleFreed(void);
409 struct PMSettingCallEntry
{
414 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
415 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
416 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
417 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
421 * Internal helper object for logging trace points to RTC
422 * IOPMrootDomain and only IOPMrootDomain should instantiate
423 * exactly one of these.
426 typedef void (*IOPMTracePointHandler
)(
427 void * target
, uint32_t code
, uint32_t data
);
429 class PMTraceWorker
: public OSObject
431 OSDeclareDefaultStructors(PMTraceWorker
)
433 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
435 static PMTraceWorker
*tracer( IOPMrootDomain
* );
436 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
437 void tracePoint(uint8_t phase
);
438 void tracePoint(uint8_t phase
, uint8_t data8
);
439 void traceDetail(uint32_t detail
);
440 void traceLoginWindowPhase(uint8_t phase
);
441 int recordTopLevelPCIDevice(IOService
*);
442 void RTC_TRACE(void);
443 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
445 IOPMTracePointHandler tracePointHandler
;
446 void * tracePointTarget
;
447 uint64_t getPMStatusCode();
449 IOPMrootDomain
*owner
;
450 IOLock
*pciMappingLock
;
451 OSArray
*pciDeviceBitMappings
;
453 uint8_t addedToRegistry
;
455 uint8_t loginWindowPhase
;
457 uint32_t traceData32
;
461 * PMAssertionsTracker
462 * Tracks kernel and user space PM assertions
464 class PMAssertionsTracker
: public OSObject
466 OSDeclareFinalStructors(PMAssertionsTracker
)
468 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
470 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
471 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
472 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
473 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
475 OSArray
*copyAssertionsArray(void);
476 IOPMDriverAssertionType
getActivatedAssertions(void);
477 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
479 IOReturn
handleCreateAssertion(OSData
*);
480 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
481 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
482 IOReturn
handleSetUserAssertionLevels(void * arg0
);
483 void publishProperties(void);
487 IOPMDriverAssertionID id
;
488 IOPMDriverAssertionType assertionBits
;
489 uint64_t createdTime
;
490 uint64_t modifiedTime
;
491 const OSSymbol
*ownerString
;
492 IOService
*ownerService
;
493 uint64_t registryEntryID
;
494 IOPMDriverAssertionLevel level
;
497 uint32_t tabulateProducerCount
;
498 uint32_t tabulateConsumerCount
;
500 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
503 IOPMrootDomain
*owner
;
504 OSArray
*assertionsArray
;
505 IOLock
*assertionsArrayLock
;
506 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
507 IOPMDriverAssertionType assertionsKernel
;
508 IOPMDriverAssertionType assertionsUser
;
509 IOPMDriverAssertionType assertionsCombined
;
512 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
516 * Internal helper object for Shutdown/Restart notifications.
518 #define kPMHaltMaxWorkers 8
519 #define kPMHaltTimeoutMS 100
521 class PMHaltWorker
: public OSObject
523 OSDeclareFinalStructors( PMHaltWorker
)
526 IOService
* service
; // service being worked on
527 AbsoluteTime startTime
; // time when work started
528 int depth
; // work on nubs at this PM-tree depth
529 int visits
; // number of nodes visited (debug)
531 bool timeout
; // service took too long
533 static PMHaltWorker
* worker( void );
534 static void main( void * arg
, wait_result_t waitResult
);
535 static void work( PMHaltWorker
* me
);
536 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
537 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
540 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
543 #define super IOService
544 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
546 static void IOPMRootDomainWillShutdown(void)
548 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
550 OSKext::willShutdown();
551 for (int i
= 0; i
< 100; i
++)
553 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
561 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
563 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
566 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
568 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
571 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
573 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
576 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
578 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
581 IOReturn
rootDomainRestart ( void )
583 return gRootDomain
->restartSystem();
586 IOReturn
rootDomainShutdown ( void )
588 return gRootDomain
->shutdownSystem();
591 void IOSystemShutdownNotification(void)
593 IOPMRootDomainWillShutdown();
595 IOHibernateSystemPostWake();
597 if (OSCompareAndSwap(0, 1, &gPagingOff
))
599 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
603 int sync_internal(void);
607 A device is always in the highest power state which satisfies its driver,
608 its policy-maker, and any power children it has, but within the constraint
609 of the power state provided by its parent. The driver expresses its desire by
610 calling changePowerStateTo(), the policy-maker expresses its desire by calling
611 changePowerStateToPriv(), and the children express their desires by calling
612 requestPowerDomainState().
614 The Root Power Domain owns the policy for idle and demand sleep for the system.
615 It is a power-managed IOService just like the others in the system.
616 It implements several power states which map to what we see as Sleep and On.
618 The sleep policy is as follows:
619 1. Sleep is prevented if the case is open so that nobody will think the machine
620 is off and plug/unplug cards.
621 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
622 3. System cannot Sleep if some object in the tree is in a power state marked
623 kIOPMPreventSystemSleep.
625 These three conditions are enforced using the "driver clamp" by calling
626 changePowerStateTo(). For example, if the case is opened,
627 changePowerStateTo(ON_STATE) is called to hold the system on regardless
628 of the desires of the children of the root or the state of the other clamp.
630 Demand Sleep is initiated by pressing the front panel power button, closing
631 the clamshell, or selecting the menu item. In this case the root's parent
632 actually initiates the power state change so that the root domain has no
633 choice and does not give applications the opportunity to veto the change.
635 Idle Sleep occurs if no objects in the tree are in a state marked
636 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
637 the root on, so it sets the "policy-maker clamp" by calling
638 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
639 This timer is set for the difference between the sleep timeout slider and the
640 display dim timeout slider. When the timer expires, it releases its clamp and
641 now nothing is holding it awake, so it falls asleep.
643 Demand sleep is prevented when the system is booting. When preferences are
644 transmitted by the loginwindow at the end of boot, a flag is cleared,
645 and this allows subsequent Demand Sleep.
648 //******************************************************************************
650 IOPMrootDomain
* IOPMrootDomain::construct( void )
652 IOPMrootDomain
*root
;
654 root
= new IOPMrootDomain
;
661 //******************************************************************************
662 // updateConsoleUsersCallout
664 //******************************************************************************
666 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
668 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
669 rootDomain
->updateConsoleUsers();
672 void IOPMrootDomain::updateConsoleUsers(void)
674 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
677 tasksSuspended
= FALSE
;
678 tasks_system_suspend(tasksSuspended
);
682 //******************************************************************************
684 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
686 IOService
* rootDomain
= (IOService
*) p0
;
687 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
688 uint32_t powerState
= rootDomain
->getPowerState();
690 DLOG("disk_sync_callout ps=%u\n", powerState
);
692 if (ON_STATE
== powerState
)
699 IOHibernateSystemPostWake();
702 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
706 rootDomain
->allowPowerChange(notifyRef
);
707 DLOG("disk_sync_callout finish\n");
710 //******************************************************************************
712 static void hib_debugSetup_callout( thread_call_param_t p0
, thread_call_param_t p1
)
714 IOService
* rootDomain
= (IOService
*) p0
;
715 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
718 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
721 rootDomain
->allowPowerChange(notifyRef
);
722 DLOG("hib_debugSetup_callout finish\n");
724 //******************************************************************************
726 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
728 AbsoluteTime endTime
;
731 clock_get_uptime(&endTime
);
732 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
734 SUB_ABSOLUTETIME(&endTime
, startTime
);
735 absolutetime_to_nanoseconds(endTime
, &nano
);
738 return (UInt32
)(nano
/ 1000000ULL);
741 //******************************************************************************
744 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
746 struct timeval
*swt
= (struct timeval
*)arg1
;
747 struct proc
*p
= req
->p
;
750 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
751 } else if(proc_is64bit(p
)) {
752 struct user64_timeval t
;
753 t
.tv_sec
= swt
->tv_sec
;
754 t
.tv_usec
= swt
->tv_usec
;
755 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
757 struct user32_timeval t
;
758 t
.tv_sec
= swt
->tv_sec
;
759 t
.tv_usec
= swt
->tv_usec
;
760 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
764 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
765 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
766 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
768 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
769 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
770 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
775 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
777 int new_value
, changed
;
778 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
780 if (!gWillShutdown
&& (new_value
== 1)) {
781 IOPMRootDomainWillShutdown();
788 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
789 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
790 0, 0, sysctl_willshutdown
, "I", "");
792 extern struct sysctl_oid sysctl__kern_iokittest
;
796 sysctl_progressmeterenable
797 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
800 int new_value
, changed
;
802 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
804 if (changed
) vc_enable_progressmeter(new_value
);
811 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
814 int new_value
, changed
;
816 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
818 if (changed
) vc_set_progressmeter(new_value
);
823 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
824 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
825 0, 0, sysctl_progressmeterenable
, "I", "");
827 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
828 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
829 0, 0, sysctl_progressmeter
, "I", "");
835 sysctl_consoleoptions
836 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
841 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
843 if (changed
) vc_user_options
.options
= new_value
;
848 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
849 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
850 0, 0, sysctl_consoleoptions
, "I", "");
854 sysctl_progressoptions SYSCTL_HANDLER_ARGS
856 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
859 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
860 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
861 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
865 sysctl_wakereason SYSCTL_HANDLER_ARGS
867 char wr
[ sizeof(gWakeReasonString
) ];
871 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
873 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
876 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
877 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
878 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
881 sysctl_targettype SYSCTL_HANDLER_ARGS
889 root
= IOService::getServiceRoot();
890 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
892 if ((data
= OSDynamicCast(OSData
, obj
)))
894 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
898 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
901 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
902 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
903 NULL
, 0, sysctl_targettype
, "A", "targettype");
905 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
906 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
908 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
909 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
910 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
911 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
912 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
913 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
914 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
915 static const OSSymbol
* gIOPMUserIsActiveKey
;
917 //******************************************************************************
920 //******************************************************************************
922 #define kRootDomainSettingsCount 17
924 bool IOPMrootDomain::start( IOService
* nub
)
926 OSIterator
*psIterator
;
927 OSDictionary
*tmpDict
;
928 IORootParent
* patriarch
;
929 #if defined(__i386__) || defined(__x86_64__)
930 IONotifier
* notifier
;
936 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
937 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
938 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
939 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
940 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
941 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
942 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
943 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
945 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
946 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
947 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
948 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
949 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
951 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
952 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
954 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
956 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
957 gIOPMSettingAutoWakeSecondsKey
,
958 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
959 gIOPMSettingAutoWakeCalendarKey
,
960 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
961 gIOPMSettingDebugWakeRelativeKey
,
962 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
963 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
964 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
965 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
966 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
967 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
968 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
969 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
970 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
971 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
972 gIOPMSettingSilentRunningKey
975 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
976 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
978 queue_init(&aggressivesQueue
);
979 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
980 aggressivesData
= OSData::withCapacity(
981 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
983 featuresDictLock
= IOLockAlloc();
984 settingsCtrlLock
= IOLockAlloc();
985 wakeEventLock
= IOLockAlloc();
986 setPMRootDomain(this);
988 extraSleepTimer
= thread_call_allocate(
989 idleSleepTimerExpired
,
990 (thread_call_param_t
) this);
992 diskSyncCalloutEntry
= thread_call_allocate(
994 (thread_call_param_t
) this);
995 hibDebugSetupEntry
= thread_call_allocate(
996 &hib_debugSetup_callout
,
997 (thread_call_param_t
) this);
999 updateConsoleUsersEntry
= thread_call_allocate(
1000 &updateConsoleUsersCallout
,
1001 (thread_call_param_t
) this);
1003 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1004 fullWakeThreadCall
= thread_call_allocate(
1005 OSMemberFunctionCast(thread_call_func_t
, this,
1006 &IOPMrootDomain::fullWakeDelayedWork
),
1007 (thread_call_param_t
) this);
1010 setProperty(kIOSleepSupportedKey
, true);
1012 bzero(&gPMStats
, sizeof(gPMStats
));
1014 pmTracer
= PMTraceWorker::tracer(this);
1016 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1018 userDisabledAllSleep
= false;
1019 systemBooting
= true;
1021 idleSleepTimerPending
= false;
1023 clamshellClosed
= false;
1024 clamshellExists
= false;
1025 clamshellDisabled
= true;
1026 acAdaptorConnected
= true;
1027 clamshellSleepDisabled
= false;
1028 gWakeReasonString
[0] = '\0';
1030 // Initialize to user active.
1031 // Will never transition to user inactive w/o wrangler.
1032 fullWakeReason
= kFullWakeReasonLocalUser
;
1033 userIsActive
= userWasActive
= true;
1034 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1036 // Set the default system capabilities at boot.
1037 _currentCapability
= kIOPMSystemCapabilityCPU
|
1038 kIOPMSystemCapabilityGraphics
|
1039 kIOPMSystemCapabilityAudio
|
1040 kIOPMSystemCapabilityNetwork
;
1042 _pendingCapability
= _currentCapability
;
1043 _desiredCapability
= _currentCapability
;
1044 _highestCapability
= _currentCapability
;
1045 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1047 queuedSleepWakeUUIDString
= NULL
;
1048 initializeBootSessionUUID();
1049 pmStatsAppResponses
= OSArray::withCapacity(5);
1050 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1051 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1052 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1053 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1054 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1055 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1056 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1058 pmStatsLock
= IOLockAlloc();
1059 idxPMCPUClamshell
= kCPUUnknownIndex
;
1060 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1062 tmpDict
= OSDictionary::withCapacity(1);
1063 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1066 settingsCallbacks
= OSDictionary::withCapacity(1);
1068 // Create a list of the valid PM settings that we'll relay to
1069 // interested clients in setProperties() => setPMSetting()
1070 allowedPMSettings
= OSArray::withObjects(
1071 (const OSObject
**)settingsArr
,
1072 kRootDomainSettingsCount
,
1075 // List of PM settings that should not automatically publish itself
1076 // as a feature when registered by a listener.
1077 noPublishPMSettings
= OSArray::withObjects(
1078 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1080 fPMSettingsDict
= OSDictionary::withCapacity(5);
1081 preventIdleSleepList
= OSSet::withCapacity(8);
1082 preventSystemSleepList
= OSSet::withCapacity(2);
1084 PMinit(); // creates gIOPMWorkLoop
1086 // Create IOPMPowerStateQueue used to queue external power
1087 // events, and to handle those events on the PM work loop.
1088 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1089 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1090 &IOPMrootDomain::dispatchPowerEvent
));
1091 getPMworkloop()->addEventSource(pmPowerStateQueue
);
1092 #ifdef CHECK_THREAD_CONTEXT
1093 gIOPMWorkLoop
= getPMworkloop();
1096 // create our power parent
1097 patriarch
= new IORootParent
;
1099 patriarch
->attach(this);
1100 patriarch
->start(this);
1101 patriarch
->addPowerChild(this);
1103 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1104 changePowerStateToPriv(ON_STATE
);
1106 // install power change handler
1107 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1110 // Register for a notification when IODisplayWrangler is published
1111 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1113 _displayWranglerNotifier
= addMatchingNotification(
1114 gIOPublishNotification
, tmpDict
,
1115 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1121 #if defined(__i386__) || defined(__x86_64__)
1123 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1125 notifier
= addMatchingNotification(
1126 gIOFirstPublishNotification
, tmpDict
,
1127 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1132 wranglerIdleSettings
= NULL
;
1133 OSNumber
* wranglerIdlePeriod
= NULL
;
1134 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1135 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1137 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1138 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1139 wranglerIdlePeriod
);
1141 if(wranglerIdlePeriod
)
1142 wranglerIdlePeriod
->release();
1145 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1146 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1147 ucClassName
->release();
1149 // IOBacklightDisplay can take a long time to load at boot, or it may
1150 // not load at all if you're booting with clamshell closed. We publish
1151 // 'DisplayDims' here redundantly to get it published early and at all.
1152 OSDictionary
* matching
;
1153 matching
= serviceMatching("IOPMPowerSource");
1154 psIterator
= getMatchingServices( matching
);
1155 if (matching
) matching
->release();
1156 if( psIterator
&& psIterator
->getNextObject() )
1158 // There's at least one battery on the system, so we publish
1159 // 'DisplayDims' support for the LCD.
1160 publishFeature("DisplayDims");
1163 psIterator
->release();
1166 sysctl_register_oid(&sysctl__kern_sleeptime
);
1167 sysctl_register_oid(&sysctl__kern_waketime
);
1168 sysctl_register_oid(&sysctl__kern_willshutdown
);
1169 sysctl_register_oid(&sysctl__kern_iokittest
);
1170 sysctl_register_oid(&sysctl__hw_targettype
);
1172 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1173 sysctl_register_oid(&sysctl__kern_progressmeter
);
1174 sysctl_register_oid(&sysctl__kern_wakereason
);
1175 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1176 sysctl_register_oid(&sysctl__kern_progressoptions
);
1179 IOHibernateSystemInit(this);
1182 registerService(); // let clients find us
1187 //******************************************************************************
1190 // Receive a setProperty call
1191 // The "System Boot" property means the system is completely booted.
1192 //******************************************************************************
1194 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1196 IOReturn return_value
= kIOReturnSuccess
;
1197 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1200 const OSSymbol
*key
;
1202 OSCollectionIterator
* iter
= 0;
1204 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1205 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1206 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1207 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1208 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1209 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1210 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1211 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1212 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1214 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1215 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1216 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1217 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1218 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1219 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1224 return_value
= kIOReturnBadArgument
;
1228 iter
= OSCollectionIterator::withCollection(dict
);
1231 return_value
= kIOReturnNoMemory
;
1235 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1236 (obj
= dict
->getObject(key
)))
1238 if (key
->isEqualTo(publish_simulated_battery_string
))
1240 if (OSDynamicCast(OSBoolean
, obj
))
1241 publishResource(key
, kOSBooleanTrue
);
1243 else if (key
->isEqualTo(idle_seconds_string
))
1245 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1247 setProperty(key
, n
);
1248 idleSeconds
= n
->unsigned32BitValue();
1251 else if (key
->isEqualTo(boot_complete_string
))
1253 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1255 else if (key
->isEqualTo(sys_shutdown_string
))
1257 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1258 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1260 else if (key
->isEqualTo(battery_warning_disabled_string
))
1262 setProperty(key
, obj
);
1265 else if (key
->isEqualTo(hibernatemode_string
) ||
1266 key
->isEqualTo(hibernatefilemin_string
) ||
1267 key
->isEqualTo(hibernatefilemax_string
) ||
1268 key
->isEqualTo(hibernatefreeratio_string
) ||
1269 key
->isEqualTo(hibernatefreetime_string
))
1271 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1272 setProperty(key
, n
);
1274 else if (key
->isEqualTo(hibernatefile_string
))
1276 OSString
* str
= OSDynamicCast(OSString
, obj
);
1277 if (str
) setProperty(key
, str
);
1280 else if (key
->isEqualTo(sleepdisabled_string
))
1282 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1284 setProperty(key
, b
);
1285 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1288 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1291 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1293 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1295 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1296 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1298 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1299 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1300 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1301 key
->isEqualTo(stall_halt_string
))
1303 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1304 setProperty(key
, b
);
1306 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1307 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1308 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1310 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1311 setProperty(key
, n
);
1313 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1315 if (kOSBooleanTrue
== obj
)
1316 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1318 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1319 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1322 // Relay our allowed PM settings onto our registered PM clients
1323 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1325 return_value
= setPMSetting(key
, obj
);
1326 if (kIOReturnSuccess
!= return_value
)
1329 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1331 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1332 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1334 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1338 _debugWakeSeconds
= 0;
1339 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1341 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1343 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1346 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1347 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1349 const IOPMCalendarStruct
* cs
=
1350 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1353 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1355 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1356 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1362 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1367 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1368 if(boot_complete_string
) boot_complete_string
->release();
1369 if(sys_shutdown_string
) sys_shutdown_string
->release();
1370 if(stall_halt_string
) stall_halt_string
->release();
1371 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1372 if(idle_seconds_string
) idle_seconds_string
->release();
1373 if(sleepdisabled_string
) sleepdisabled_string
->release();
1374 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1375 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1377 if(hibernatemode_string
) hibernatemode_string
->release();
1378 if(hibernatefile_string
) hibernatefile_string
->release();
1379 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1380 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1382 if (iter
) iter
->release();
1383 return return_value
;
1387 // MARK: Aggressiveness
1389 //******************************************************************************
1390 // setAggressiveness
1392 // Override IOService::setAggressiveness()
1393 //******************************************************************************
1395 IOReturn
IOPMrootDomain::setAggressiveness(
1397 unsigned long value
)
1399 return setAggressiveness( type
, value
, 0 );
1403 * Private setAggressiveness() with an internal options argument.
1405 IOReturn
IOPMrootDomain::setAggressiveness(
1407 unsigned long value
,
1408 IOOptionBits options
)
1410 AggressivesRequest
* entry
;
1411 AggressivesRequest
* request
;
1414 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1415 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1417 request
= IONew(AggressivesRequest
, 1);
1419 return kIOReturnNoMemory
;
1421 memset(request
, 0, sizeof(*request
));
1422 request
->options
= options
;
1423 request
->dataType
= kAggressivesRequestTypeRecord
;
1424 request
->data
.record
.type
= (uint32_t) type
;
1425 request
->data
.record
.value
= (uint32_t) value
;
1429 // Update disk quick spindown flag used by getAggressiveness().
1430 // Never merge requests with quick spindown flags set.
1432 if (options
& kAggressivesOptionQuickSpindownEnable
)
1433 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1434 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1435 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1438 // Coalesce requests with identical aggressives types.
1439 // Deal with callers that calls us too "aggressively".
1441 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1443 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1444 (entry
->data
.record
.type
== type
) &&
1445 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1447 entry
->data
.record
.value
= value
;
1456 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1459 AGGRESSIVES_UNLOCK();
1462 IODelete(request
, AggressivesRequest
, 1);
1464 if (options
& kAggressivesOptionSynchronous
)
1465 handleAggressivesRequests(); // not truly synchronous
1467 thread_call_enter(aggressivesThreadCall
);
1469 return kIOReturnSuccess
;
1472 //******************************************************************************
1473 // getAggressiveness
1475 // Override IOService::setAggressiveness()
1476 // Fetch the aggressiveness factor with the given type.
1477 //******************************************************************************
1479 IOReturn
IOPMrootDomain::getAggressiveness (
1481 unsigned long * outLevel
)
1487 return kIOReturnBadArgument
;
1491 // Disk quick spindown in effect, report value = 1
1493 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1494 (type
== kPMMinutesToSpinDown
))
1496 value
= kAggressivesMinValue
;
1500 // Consult the pending request queue.
1504 AggressivesRequest
* entry
;
1506 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1508 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1509 (entry
->data
.record
.type
== type
) &&
1510 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1512 value
= entry
->data
.record
.value
;
1519 // Consult the backend records.
1521 if (!source
&& aggressivesData
)
1523 AggressivesRecord
* record
;
1526 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1527 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1529 for (i
= 0; i
< count
; i
++, record
++)
1531 if (record
->type
== type
)
1533 value
= record
->value
;
1540 AGGRESSIVES_UNLOCK();
1544 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1545 source
, (uint32_t) type
, value
);
1546 *outLevel
= (unsigned long) value
;
1547 return kIOReturnSuccess
;
1551 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1552 *outLevel
= 0; // default return = 0, driver may not check for error
1553 return kIOReturnInvalid
;
1557 //******************************************************************************
1558 // joinAggressiveness
1560 // Request from IOService to join future aggressiveness broadcasts.
1561 //******************************************************************************
1563 IOReturn
IOPMrootDomain::joinAggressiveness(
1564 IOService
* service
)
1566 AggressivesRequest
* request
;
1568 if (!service
|| (service
== this))
1569 return kIOReturnBadArgument
;
1571 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1573 request
= IONew(AggressivesRequest
, 1);
1575 return kIOReturnNoMemory
;
1577 service
->retain(); // released by synchronizeAggressives()
1579 memset(request
, 0, sizeof(*request
));
1580 request
->dataType
= kAggressivesRequestTypeService
;
1581 request
->data
.service
= service
;
1584 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1585 AGGRESSIVES_UNLOCK();
1587 thread_call_enter(aggressivesThreadCall
);
1589 return kIOReturnSuccess
;
1592 //******************************************************************************
1593 // handleAggressivesRequests
1595 // Backend thread processes all incoming aggressiveness requests in the queue.
1596 //******************************************************************************
1599 handleAggressivesFunction(
1600 thread_call_param_t param1
,
1601 thread_call_param_t param2
)
1605 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1609 void IOPMrootDomain::handleAggressivesRequests( void )
1611 AggressivesRecord
* start
;
1612 AggressivesRecord
* record
;
1613 AggressivesRequest
* request
;
1614 queue_head_t joinedQueue
;
1618 bool pingSelf
= false;
1622 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1623 queue_empty(&aggressivesQueue
))
1626 gAggressivesState
|= kAggressivesStateBusy
;
1627 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1628 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1633 queue_init(&joinedQueue
);
1637 // Remove request from the incoming queue in FIFO order.
1638 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1639 switch (request
->dataType
)
1641 case kAggressivesRequestTypeRecord
:
1642 // Update existing record if found.
1644 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1646 if (record
->type
== request
->data
.record
.type
)
1650 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1652 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1655 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1656 kAggressivesRecordFlagModified
);
1657 DLOG("disk spindown accelerated, was %u min\n",
1661 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1663 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1666 record
->flags
|= kAggressivesRecordFlagModified
;
1667 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1668 DLOG("disk spindown restored to %u min\n",
1672 else if (record
->value
!= request
->data
.record
.value
)
1674 record
->value
= request
->data
.record
.value
;
1675 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1678 record
->flags
|= kAggressivesRecordFlagModified
;
1685 // No matching record, append a new record.
1687 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1689 AggressivesRecord newRecord
;
1691 newRecord
.flags
= kAggressivesRecordFlagModified
;
1692 newRecord
.type
= request
->data
.record
.type
;
1693 newRecord
.value
= request
->data
.record
.value
;
1694 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1696 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1697 DLOG("disk spindown accelerated\n");
1700 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1702 // OSData may have switched to another (larger) buffer.
1703 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1704 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1708 // Finished processing the request, release it.
1709 IODelete(request
, AggressivesRequest
, 1);
1712 case kAggressivesRequestTypeService
:
1713 // synchronizeAggressives() will free request.
1714 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1718 panic("bad aggressives request type %x\n", request
->dataType
);
1721 } while (!queue_empty(&aggressivesQueue
));
1723 // Release the lock to perform work, with busy flag set.
1724 if (!queue_empty(&joinedQueue
) || broadcast
)
1726 AGGRESSIVES_UNLOCK();
1727 if (!queue_empty(&joinedQueue
))
1728 synchronizeAggressives(&joinedQueue
, start
, count
);
1730 broadcastAggressives(start
, count
);
1734 // Remove the modified flag from all records.
1735 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1737 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1738 ((record
->type
== kPMMinutesToDim
) ||
1739 (record
->type
== kPMMinutesToSleep
)))
1742 record
->flags
&= ~kAggressivesRecordFlagModified
;
1745 // Check the incoming queue again since new entries may have been
1746 // added while lock was released above.
1748 } while (!queue_empty(&aggressivesQueue
));
1750 gAggressivesState
&= ~kAggressivesStateBusy
;
1753 AGGRESSIVES_UNLOCK();
1755 // Root domain is interested in system and display sleep slider changes.
1756 // Submit a power event to handle those changes on the PM work loop.
1758 if (pingSelf
&& pmPowerStateQueue
) {
1759 pmPowerStateQueue
->submitPowerEvent(
1760 kPowerEventPolicyStimulus
,
1761 (void *) kStimulusAggressivenessChanged
);
1765 //******************************************************************************
1766 // synchronizeAggressives
1768 // Push all known aggressiveness records to one or more IOService.
1769 //******************************************************************************
1771 void IOPMrootDomain::synchronizeAggressives(
1772 queue_head_t
* joinedQueue
,
1773 const AggressivesRecord
* array
,
1776 IOService
* service
;
1777 AggressivesRequest
* request
;
1778 const AggressivesRecord
* record
;
1779 IOPMDriverCallEntry callEntry
;
1783 while (!queue_empty(joinedQueue
))
1785 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1786 if (request
->dataType
== kAggressivesRequestTypeService
)
1787 service
= request
->data
.service
;
1791 IODelete(request
, AggressivesRequest
, 1);
1796 if (service
->assertPMDriverCall(&callEntry
))
1798 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1800 value
= record
->value
;
1801 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1802 value
= kAggressivesMinValue
;
1804 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1805 record
->type
, value
, service
->getName());
1806 service
->setAggressiveness(record
->type
, value
);
1808 service
->deassertPMDriverCall(&callEntry
);
1810 service
->release(); // retained by joinAggressiveness()
1815 //******************************************************************************
1816 // broadcastAggressives
1818 // Traverse PM tree and call setAggressiveness() for records that have changed.
1819 //******************************************************************************
1821 void IOPMrootDomain::broadcastAggressives(
1822 const AggressivesRecord
* array
,
1825 IORegistryIterator
* iter
;
1826 IORegistryEntry
* entry
;
1827 IOPowerConnection
* connect
;
1828 IOService
* service
;
1829 const AggressivesRecord
* record
;
1830 IOPMDriverCallEntry callEntry
;
1834 iter
= IORegistryIterator::iterateOver(
1835 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1841 while ((entry
= iter
->getNextObject()))
1843 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1844 if (!connect
|| !connect
->getReadyFlag())
1847 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1849 if (service
->assertPMDriverCall(&callEntry
))
1851 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1853 if (record
->flags
& kAggressivesRecordFlagModified
)
1855 value
= record
->value
;
1856 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1857 value
= kAggressivesMinValue
;
1858 _LOG("broadcastAggressives %x = %u to %s\n",
1859 record
->type
, value
, service
->getName());
1860 service
->setAggressiveness(record
->type
, value
);
1863 service
->deassertPMDriverCall(&callEntry
);
1869 while (!entry
&& !iter
->isValid());
1875 // MARK: System Sleep
1877 //******************************************************************************
1878 // startIdleSleepTimer
1880 //******************************************************************************
1882 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1884 AbsoluteTime deadline
;
1888 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
1893 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1894 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1895 idleSleepTimerPending
= true;
1899 thread_call_enter(extraSleepTimer
);
1901 DLOG("idle timer set for %u seconds\n", inSeconds
);
1904 //******************************************************************************
1905 // cancelIdleSleepTimer
1907 //******************************************************************************
1909 void IOPMrootDomain::cancelIdleSleepTimer( void )
1912 if (idleSleepTimerPending
)
1914 DLOG("idle timer cancelled\n");
1915 thread_call_cancel(extraSleepTimer
);
1916 idleSleepTimerPending
= false;
1918 if (!assertOnWakeSecs
&& systemWakeTime
) {
1920 clock_usec_t microsecs
;
1921 clock_get_uptime(&now
);
1922 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
1923 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
1924 if (assertOnWakeReport
) {
1925 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
1926 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
1932 //******************************************************************************
1933 // idleSleepTimerExpired
1935 //******************************************************************************
1937 static void idleSleepTimerExpired(
1938 thread_call_param_t us
, thread_call_param_t
)
1940 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1943 //******************************************************************************
1944 // handleSleepTimerExpiration
1946 // The time between the sleep idle timeout and the next longest one has elapsed.
1947 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1948 //******************************************************************************
1950 void IOPMrootDomain::handleSleepTimerExpiration( void )
1952 if (!getPMworkloop()->inGate())
1954 getPMworkloop()->runAction(
1955 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1956 &IOPMrootDomain::handleSleepTimerExpiration
),
1963 DLOG("sleep timer expired\n");
1966 idleSleepTimerPending
= false;
1968 clock_get_uptime(&time
);
1969 setQuickSpinDownTimeout();
1970 adjustPowerState(true);
1973 //******************************************************************************
1974 // getTimeToIdleSleep
1976 // Returns number of seconds left before going into idle sleep.
1977 // Caller has to make sure that idle sleep is allowed at the time of calling
1979 //******************************************************************************
1981 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
1984 AbsoluteTime now
, lastActivityTime
;
1986 uint32_t minutesSinceUserInactive
= 0;
1987 uint32_t sleepDelay
= 0;
1989 if (sleepSlider
== 0)
1992 if (userActivityTime
)
1993 lastActivityTime
= userActivityTime
;
1995 lastActivityTime
= userBecameInactiveTime
;
1997 clock_get_uptime(&now
);
1998 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2000 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2001 absolutetime_to_nanoseconds(now
, &nanos
);
2002 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2004 if (minutesSinceUserInactive
>= sleepSlider
)
2007 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2011 sleepDelay
= sleepSlider
;
2014 DLOG("user inactive %u min, time to idle sleep %u min\n",
2015 minutesSinceUserInactive
, sleepDelay
);
2017 return (sleepDelay
* 60);
2020 //******************************************************************************
2021 // setQuickSpinDownTimeout
2023 //******************************************************************************
2025 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2029 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2032 //******************************************************************************
2033 // restoreUserSpinDownTimeout
2035 //******************************************************************************
2037 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2041 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2044 //******************************************************************************
2047 //******************************************************************************
2050 IOReturn
IOPMrootDomain::sleepSystem( void )
2052 return sleepSystemOptions(NULL
);
2056 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2058 OSObject
*obj
= NULL
;
2059 OSString
*reason
= NULL
;
2060 /* sleepSystem is a public function, and may be called by any kernel driver.
2061 * And that's bad - drivers should sleep the system by calling
2062 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2064 * Note that user space app calls to IOPMSleepSystem() will also travel
2065 * this code path and thus be correctly identified as software sleeps.
2068 if (options
&& options
->getObject("OSSwitch"))
2070 // Log specific sleep cause for OS Switch hibernation
2071 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2074 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2076 reason
= OSDynamicCast(OSString
, obj
);
2077 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2078 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2081 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2085 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2087 /* Called from both gated and non-gated context */
2089 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2091 return kIOReturnNotPermitted
;
2094 pmPowerStateQueue
->submitPowerEvent(
2095 kPowerEventPolicyStimulus
,
2096 (void *) kStimulusDemandSystemSleep
,
2099 return kIOReturnSuccess
;
2102 //******************************************************************************
2105 // This overrides powerChangeDone in IOService.
2106 //******************************************************************************
2108 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2112 DLOG("PowerChangeDone: %u->%u\n",
2113 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2115 switch ( getPowerState() )
2118 if (previousPowerState
!= ON_STATE
)
2121 acceptSystemWakeEvents(true);
2123 // re-enable this timer for next sleep
2124 cancelIdleSleepTimer();
2127 clock_usec_t microsecs
;
2128 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2130 gIOLastSleepTime
.tv_sec
= secs
;
2131 gIOLastSleepTime
.tv_usec
= microsecs
;
2132 gIOLastWakeTime
.tv_sec
= 0;
2133 gIOLastWakeTime
.tv_usec
= 0;
2135 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2136 clock_usec_t microsecs
;
2137 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2138 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2140 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2141 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2142 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2143 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2144 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2146 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2147 wake2DarkwakeDelay
= 0;
2150 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2152 IOHibernateSystemHasSlept();
2154 evaluateSystemSleepPolicyFinal();
2156 LOG("System Sleep\n");
2158 if (thermalWarningState
) {
2159 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2161 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2165 assertOnWakeSecs
= 0;
2166 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2167 getPlatform()->sleepKernel();
2169 // The CPU(s) are off at this point,
2170 // Code will resume execution here upon wake.
2172 clock_get_uptime(&systemWakeTime
);
2173 _highestCapability
= 0;
2175 ((IOService
*)this)->start_watchdog_timer(); //14456299
2177 IOHibernateSystemWake();
2180 // sleep transition complete
2181 gSleepOrShutdownPending
= 0;
2183 // trip the reset of the calendar clock
2185 clock_sec_t wakeSecs
;
2186 clock_usec_t wakeMicrosecs
;
2188 clock_initialize_calendar();
2190 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2191 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2192 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2196 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2200 PMDebug(kPMLogSystemWake
, 0, 0);
2201 lowBatteryCondition
= false;
2202 lastSleepReason
= 0;
2204 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2205 _debugWakeSeconds
= 0;
2206 _scheduledAlarms
= 0;
2212 #if defined(__i386__) || defined(__x86_64__)
2213 wranglerTickled
= false;
2214 graphicsSuppressed
= false;
2215 darkWakePostTickle
= false;
2216 darkWakeHibernateError
= false;
2217 darkWakeToSleepASAP
= true;
2218 logGraphicsClamp
= true;
2219 sleepTimerMaintenance
= false;
2220 sleepToStandby
= false;
2221 wranglerTickleLatched
= false;
2222 userWasActive
= false;
2223 fullWakeReason
= kFullWakeReasonNone
;
2225 OSString
* wakeType
= OSDynamicCast(
2226 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2227 OSString
* wakeReason
= OSDynamicCast(
2228 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2230 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2231 gWakeReasonString
[0] == '\0')
2233 // Until the platform driver can claim its wake reasons
2234 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2235 sizeof(gWakeReasonString
));
2238 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2240 lowBatteryCondition
= true;
2241 darkWakeMaintenance
= true;
2243 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2246 OSNumber
* hibOptions
= OSDynamicCast(
2247 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2248 if (hibernateAborted
|| ((hibOptions
&&
2249 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2251 // Hibernate aborted, or EFI brought up graphics
2252 wranglerTickled
= true;
2253 DLOG("hibernation aborted %d, options 0x%x\n",
2255 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2260 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2261 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2263 // User wake or RTC alarm
2264 wranglerTickled
= true;
2268 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2270 // SMC standby timer trumps SleepX
2271 darkWakeMaintenance
= true;
2272 sleepTimerMaintenance
= true;
2275 if ((_lastDebugWakeSeconds
!= 0) &&
2276 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2278 // SleepX before maintenance
2279 wranglerTickled
= true;
2283 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2285 darkWakeMaintenance
= true;
2289 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2291 darkWakeMaintenance
= true;
2292 darkWakeSleepService
= true;
2294 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2295 sleepToStandby
= true;
2301 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2303 darkWakeMaintenance
= true;
2304 darkWakeHibernateError
= true;
2308 // Unidentified wake source, resume to full wake if debug
2309 // alarm is pending.
2311 if (_lastDebugWakeSeconds
&&
2312 (!wakeReason
|| wakeReason
->isEqualTo("")))
2313 wranglerTickled
= true;
2319 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2321 darkWakeMaintenance
= true;
2322 sleepTimerMaintenance
= true;
2324 else if (hibernateAborted
|| !wakeType
||
2325 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2326 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2328 // Post a HID tickle immediately - except for RTC maintenance wake.
2329 wranglerTickled
= true;
2333 darkWakeMaintenance
= true;
2337 if (wranglerTickled
)
2339 darkWakeToSleepASAP
= false;
2340 fullWakeReason
= kFullWakeReasonLocalUser
;
2343 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2345 handleDisplayPowerOn();
2347 else if (!darkWakeMaintenance
)
2349 // Early/late tickle for non-maintenance wake.
2350 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2351 kDarkWakeFlagHIDTickleEarly
) ||
2352 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2353 kDarkWakeFlagHIDTickleLate
))
2355 darkWakePostTickle
= true;
2358 #else /* !__i386__ && !__x86_64__ */
2359 // stay awake for at least 30 seconds
2360 wranglerTickled
= true;
2361 fullWakeReason
= kFullWakeReasonLocalUser
;
2362 startIdleSleepTimer(30);
2366 thread_call_enter(updateConsoleUsersEntry
);
2368 changePowerStateToPriv(ON_STATE
);
2370 #if !__i386__ && !__x86_64__
2372 if (previousPowerState
!= ON_STATE
)
2374 DLOG("Force re-evaluating aggressiveness\n");
2375 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2376 pmPowerStateQueue
->submitPowerEvent(
2377 kPowerEventPolicyStimulus
,
2378 (void *) kStimulusNoIdleSleepPreventers
);
2388 //******************************************************************************
2389 // requestPowerDomainState
2391 // Extend implementation in IOService. Running on PM work loop thread.
2392 //******************************************************************************
2394 IOReturn
IOPMrootDomain::requestPowerDomainState (
2395 IOPMPowerFlags childDesire
,
2396 IOPowerConnection
* childConnection
,
2397 unsigned long specification
)
2399 // Idle and system sleep prevention flags affects driver desire.
2400 // Children desire are irrelevant so they are cleared.
2402 return super::requestPowerDomainState(0, childConnection
, specification
);
2406 //******************************************************************************
2407 // updatePreventIdleSleepList
2409 // Called by IOService on PM work loop.
2410 // Returns true if PM policy recognized the driver's desire to prevent idle
2411 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2412 //******************************************************************************
2414 bool IOPMrootDomain::updatePreventIdleSleepList(
2415 IOService
* service
, bool addNotRemove
)
2417 unsigned int oldCount
, newCount
;
2421 #if defined(__i386__) || defined(__x86_64__)
2422 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2423 // idle sleep, except in the case of legacy disk I/O
2424 if ((service
!= wrangler
) && (service
!= this))
2430 oldCount
= preventIdleSleepList
->getCount();
2433 preventIdleSleepList
->setObject(service
);
2434 DLOG("prevent idle sleep list: %s+ (%u)\n",
2435 service
->getName(), preventIdleSleepList
->getCount());
2437 else if (preventIdleSleepList
->member(service
))
2439 preventIdleSleepList
->removeObject(service
);
2440 DLOG("prevent idle sleep list: %s- (%u)\n",
2441 service
->getName(), preventIdleSleepList
->getCount());
2443 newCount
= preventIdleSleepList
->getCount();
2445 if ((oldCount
== 0) && (newCount
!= 0))
2447 // Driver added to empty prevent list.
2448 // Update the driver desire to prevent idle sleep.
2449 // Driver desire does not prevent demand sleep.
2451 changePowerStateTo(ON_STATE
);
2453 else if ((oldCount
!= 0) && (newCount
== 0))
2455 // Last driver removed from prevent list.
2456 // Drop the driver clamp to allow idle sleep.
2458 changePowerStateTo(SLEEP_STATE
);
2459 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2461 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2462 &newCount
, sizeof(newCount
));
2464 #if defined(__i386__) || defined(__x86_64__)
2465 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2467 return false; // do not idle-cancel
2474 //******************************************************************************
2475 // preventSystemSleepListUpdate
2477 // Called by IOService on PM work loop.
2478 //******************************************************************************
2480 void IOPMrootDomain::updatePreventSystemSleepList(
2481 IOService
* service
, bool addNotRemove
)
2483 unsigned int oldCount
, newCount
;
2486 if (this == service
)
2489 oldCount
= preventSystemSleepList
->getCount();
2492 preventSystemSleepList
->setObject(service
);
2493 DLOG("prevent system sleep list: %s+ (%u)\n",
2494 service
->getName(), preventSystemSleepList
->getCount());
2495 if (!assertOnWakeSecs
&& systemWakeTime
) {
2497 clock_usec_t microsecs
;
2498 clock_get_uptime(&now
);
2499 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
2500 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2501 if (assertOnWakeReport
) {
2502 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2503 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2507 else if (preventSystemSleepList
->member(service
))
2509 preventSystemSleepList
->removeObject(service
);
2510 DLOG("prevent system sleep list: %s- (%u)\n",
2511 service
->getName(), preventSystemSleepList
->getCount());
2513 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2515 // Lost all system sleep preventers.
2516 // Send stimulus if system sleep was blocked, and is in dark wake.
2517 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2520 newCount
= preventSystemSleepList
->getCount();
2521 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2522 &newCount
, sizeof(newCount
));
2525 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2528 OSCollectionIterator
*iterator
= NULL
;
2529 OSObject
*object
= NULL
;
2530 OSArray
*array
= NULL
;
2532 if (!getPMworkloop()->inGate())
2534 getPMworkloop()->runAction(
2535 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2536 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2537 this, (void *)idleSleepList
, (void *)systemSleepList
);
2541 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2543 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2544 array
= OSArray::withCapacity(5);
2546 while ((object
= iterator
->getNextObject()))
2548 IOService
*service
= OSDynamicCast(IOService
, object
);
2551 array
->setObject(OSSymbol::withCString(service
->getName()));
2555 iterator
->release();
2556 *idleSleepList
= array
;
2559 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2561 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2562 array
= OSArray::withCapacity(5);
2564 while ((object
= iterator
->getNextObject()))
2566 IOService
*service
= OSDynamicCast(IOService
, object
);
2569 array
->setObject(OSSymbol::withCString(service
->getName()));
2573 iterator
->release();
2574 *systemSleepList
= array
;
2578 //******************************************************************************
2581 // Override the superclass implementation to send a different message type.
2582 //******************************************************************************
2584 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2586 DLOG("tellChangeDown %u->%u\n",
2587 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2589 if (SLEEP_STATE
== stateNum
)
2591 // Legacy apps were already told in the full->dark transition
2592 if (!ignoreTellChangeDown
)
2593 tracePoint( kIOPMTracePointSleepApplications
);
2595 tracePoint( kIOPMTracePointSleepPriorityClients
);
2598 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2600 userActivityAtSleep
= userActivityCount
;
2601 hibernateAborted
= false;
2602 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2604 // Direct callout into OSKext so it can disable kext unloads
2605 // during sleep/wake to prevent deadlocks.
2606 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2608 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2610 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2611 // But tellClientsWithResponse() must be called for both.
2612 ignoreTellChangeDown
= true;
2615 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2618 //******************************************************************************
2621 // Override the superclass implementation to send a different message type.
2622 // This must be idle sleep since we don't ask during any other power change.
2623 //******************************************************************************
2625 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2627 DLOG("askChangeDown %u->%u\n",
2628 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2630 // Don't log for dark wake entry
2631 if (kSystemTransitionSleep
== _systemTransitionType
)
2632 tracePoint( kIOPMTracePointSleepApplications
);
2634 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2637 //******************************************************************************
2638 // askChangeDownDone
2640 // An opportunity for root domain to cancel the power transition,
2641 // possibily due to an assertion created by powerd in response to
2642 // kIOMessageCanSystemSleep.
2645 // full -> dark wake transition
2646 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2647 // 2. askChangeDownDone()
2648 // dark -> sleep transition
2649 // 1. Notify powerd with kIOMessageCanSystemSleep
2650 // 2. askChangeDownDone()
2653 // full -> dark wake transition
2654 // 1. Notify powerd with kIOMessageCanSystemSleep
2655 // 2. askChangeDownDone()
2656 // dark -> sleep transition
2657 // 1. Notify powerd with kIOMessageCanSystemSleep
2658 // 2. askChangeDownDone()
2659 //******************************************************************************
2661 void IOPMrootDomain::askChangeDownDone(
2662 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2664 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2665 *inOutChangeFlags
, *cancel
,
2666 _systemTransitionType
,
2667 _currentCapability
, _pendingCapability
);
2669 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2671 // Dark->Sleep transition.
2672 // Check if there are any deny sleep assertions.
2673 // lastSleepReason already set by handleOurPowerChangeStart()
2675 if (!checkSystemCanSleep(lastSleepReason
))
2677 // Cancel dark wake to sleep transition.
2678 // Must re-scan assertions upon entering dark wake.
2681 DLOG("cancel dark->sleep\n");
2686 //******************************************************************************
2687 // systemDidNotSleep
2689 // Work common to both canceled or aborted sleep.
2690 //******************************************************************************
2692 void IOPMrootDomain::systemDidNotSleep( void )
2694 // reset console lock state
2695 thread_call_enter(updateConsoleUsersEntry
);
2701 // stay awake for at least idleSeconds
2702 startIdleSleepTimer(idleSeconds
);
2707 if (sleepSlider
&& !userIsActive
)
2709 // Manually start the idle sleep timer besides waiting for
2710 // the user to become inactive.
2711 startIdleSleepTimer( kIdleSleepRetryInterval
);
2715 preventTransitionToUserActive(false);
2716 IOService::setAdvisoryTickleEnable( true );
2718 // After idle revert and cancel, send a did-change message to powerd
2719 // to balance the previous will-change message. Kernel clients do not
2720 // need this since sleep cannot be canceled once they are notified.
2722 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2723 (_pendingCapability
!= _currentCapability
) &&
2724 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2726 // Differs from a real capability gain change where notifyRef != 0,
2727 // but it is zero here since no response is expected.
2729 IOPMSystemCapabilityChangeParameters params
;
2731 bzero(¶ms
, sizeof(params
));
2732 params
.fromCapabilities
= _pendingCapability
;
2733 params
.toCapabilities
= _currentCapability
;
2734 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2736 DLOG("MESG cap %x->%x did change\n",
2737 params
.fromCapabilities
, params
.toCapabilities
);
2738 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2739 ¶ms
, sizeof(params
));
2743 //******************************************************************************
2746 // Notify registered applications and kernel clients that we are not dropping
2749 // We override the superclass implementation so we can send a different message
2750 // type to the client or application being notified.
2752 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2753 //******************************************************************************
2755 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2757 DLOG("tellNoChangeDown %u->%u\n",
2758 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2760 // Sleep canceled, clear the sleep trace point.
2761 tracePoint(kIOPMTracePointSystemUp
);
2763 systemDidNotSleep();
2764 return tellClients( kIOMessageSystemWillNotSleep
);
2767 //******************************************************************************
2770 // Notify registered applications and kernel clients that we are raising power.
2772 // We override the superclass implementation so we can send a different message
2773 // type to the client or application being notified.
2774 //******************************************************************************
2776 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2778 DLOG("tellChangeUp %u->%u\n",
2779 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2781 ignoreTellChangeDown
= false;
2783 if ( stateNum
== ON_STATE
)
2785 // Direct callout into OSKext so it can disable kext unloads
2786 // during sleep/wake to prevent deadlocks.
2787 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2789 // Notify platform that sleep was cancelled or resumed.
2790 getPlatform()->callPlatformFunction(
2791 sleepMessagePEFunction
, false,
2792 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2795 if (getPowerState() == ON_STATE
)
2797 // this is a quick wake from aborted sleep
2798 systemDidNotSleep();
2799 tellClients( kIOMessageSystemWillPowerOn
);
2802 tracePoint( kIOPMTracePointWakeApplications
);
2803 tellClients( kIOMessageSystemHasPoweredOn
);
2807 //******************************************************************************
2808 // sysPowerDownHandler
2810 // Perform a vfs sync before system sleep.
2811 //******************************************************************************
2813 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2814 void * target
, void * refCon
,
2815 UInt32 messageType
, IOService
* service
,
2816 void * messageArgs
, vm_size_t argSize
)
2820 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2823 return kIOReturnUnsupported
;
2825 if (messageType
== kIOMessageSystemWillSleep
)
2828 static int32_t mem_only
= -1;
2829 IOPowerStateChangeNotification
*notify
=
2830 (IOPowerStateChangeNotification
*)messageArgs
;
2832 if ((mem_only
== -1) &&
2833 (PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
)) == false)) {
2836 if ((mem_only
!= 1) && (gRootDomain
->sleepWakeDebugIsWdogEnabled()))
2838 notify
->returnValue
= 30 * 1000 * 1000;
2840 gRootDomain
->hibDebugSetupEntry
,
2841 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2845 else if (messageType
== kIOMessageSystemCapabilityChange
)
2847 IOPMSystemCapabilityChangeParameters
* params
=
2848 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2850 // Interested applications have been notified of an impending power
2851 // change and have acked (when applicable).
2852 // This is our chance to save whatever state we can before powering
2854 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2857 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2858 params
->fromCapabilities
, params
->toCapabilities
,
2859 params
->changeFlags
);
2861 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2862 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2863 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2865 // We will ack within 20 seconds
2866 params
->maxWaitForReply
= 20 * 1000 * 1000;
2868 gRootDomain
->evaluateSystemSleepPolicyEarly();
2870 // add in time we could spend freeing pages
2871 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2873 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2875 DLOG("sysPowerDownHandler max wait %d s\n",
2876 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2879 // Notify platform that sleep has begun, after the early
2880 // sleep policy evaluation.
2881 getPlatform()->callPlatformFunction(
2882 sleepMessagePEFunction
, false,
2883 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2886 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2888 // Purposely delay the ack and hope that shutdown occurs quickly.
2889 // Another option is not to schedule the thread and wait for
2891 AbsoluteTime deadline
;
2892 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2893 thread_call_enter1_delayed(
2894 gRootDomain
->diskSyncCalloutEntry
,
2895 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2900 gRootDomain
->diskSyncCalloutEntry
,
2901 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2904 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2905 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2906 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2909 // We will ack within 110 seconds
2910 params
->maxWaitForReply
= 110 * 1000 * 1000;
2913 gRootDomain
->diskSyncCalloutEntry
,
2914 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2917 ret
= kIOReturnSuccess
;
2923 //******************************************************************************
2924 // handleQueueSleepWakeUUID
2926 // Called from IOPMrootDomain when we're initiating a sleep,
2927 // or indirectly from PM configd when PM decides to clear the UUID.
2928 // PM clears the UUID several minutes after successful wake from sleep,
2929 // so that we might associate App spindumps with the immediately previous
2932 // @param obj has a retain on it. We're responsible for releasing that retain.
2933 //******************************************************************************
2935 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2937 OSString
*str
= NULL
;
2939 if (kOSBooleanFalse
== obj
)
2941 handlePublishSleepWakeUUID(NULL
);
2943 else if ((str
= OSDynamicCast(OSString
, obj
)))
2945 // This branch caches the UUID for an upcoming sleep/wake
2946 if (queuedSleepWakeUUIDString
) {
2947 queuedSleepWakeUUIDString
->release();
2948 queuedSleepWakeUUIDString
= NULL
;
2950 queuedSleepWakeUUIDString
= str
;
2951 queuedSleepWakeUUIDString
->retain();
2953 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2962 //******************************************************************************
2963 // handlePublishSleepWakeUUID
2965 // Called from IOPMrootDomain when we're initiating a sleep,
2966 // or indirectly from PM configd when PM decides to clear the UUID.
2967 // PM clears the UUID several minutes after successful wake from sleep,
2968 // so that we might associate App spindumps with the immediately previous
2970 //******************************************************************************
2972 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2977 * Clear the current UUID
2979 if (gSleepWakeUUIDIsSet
)
2981 DLOG("SleepWake UUID cleared\n");
2983 gSleepWakeUUIDIsSet
= false;
2985 removeProperty(kIOPMSleepWakeUUIDKey
);
2986 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2990 * Optionally, publish a new UUID
2992 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2994 OSString
*publishThisUUID
= NULL
;
2996 publishThisUUID
= queuedSleepWakeUUIDString
;
2997 publishThisUUID
->retain();
2999 if (publishThisUUID
)
3001 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3002 publishThisUUID
->release();
3005 gSleepWakeUUIDIsSet
= true;
3006 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3008 queuedSleepWakeUUIDString
->release();
3009 queuedSleepWakeUUIDString
= NULL
;
3013 //******************************************************************************
3014 // initializeBootSessionUUID
3016 // Initialize the boot session uuid at boot up and sets it into registry.
3017 //******************************************************************************
3019 void IOPMrootDomain::initializeBootSessionUUID(void)
3022 uuid_string_t new_uuid_string
;
3024 uuid_generate(new_uuid
);
3025 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3026 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3028 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3031 //******************************************************************************
3032 // changePowerStateTo & changePowerStateToPriv
3034 // Override of these methods for logging purposes.
3035 //******************************************************************************
3037 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3039 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3041 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3042 return kIOReturnUnsupported
;
3044 return super::changePowerStateTo(ordinal
);
3047 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3049 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3051 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3052 return kIOReturnUnsupported
;
3054 return super::changePowerStateToPriv(ordinal
);
3057 //******************************************************************************
3060 //******************************************************************************
3062 bool IOPMrootDomain::activitySinceSleep(void)
3064 return (userActivityCount
!= userActivityAtSleep
);
3067 bool IOPMrootDomain::abortHibernation(void)
3069 bool ret
= activitySinceSleep();
3071 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3073 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3074 hibernateAborted
= true;
3080 hibernate_should_abort(void)
3083 return (gRootDomain
->abortHibernation());
3088 //******************************************************************************
3089 // willNotifyPowerChildren
3091 // Called after all interested drivers have all acknowledged the power change,
3092 // but before any power children is informed. Dispatched though a thread call,
3093 // so it is safe to perform work that might block on a sleeping disk. PM state
3094 // machine (not thread) will block w/o timeout until this function returns.
3095 //******************************************************************************
3097 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3102 if (SLEEP_STATE
== newPowerState
)
3104 if (!tasksSuspended
)
3106 AbsoluteTime deadline
;
3107 tasksSuspended
= TRUE
;
3108 tasks_system_suspend(tasksSuspended
);
3110 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3111 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3115 IOHibernateSystemSleep();
3116 IOHibernateIOKitSleep();
3118 if (gRootDomain
->activitySinceSleep()) {
3119 dict
= OSDictionary::withCapacity(1);
3120 secs
= OSNumber::withNumber(1, 32);
3123 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3124 gRootDomain
->setProperties(dict
);
3125 MSG("Reverting sleep with relative wake\n");
3127 if (dict
) dict
->release();
3128 if (secs
) secs
->release();
3134 //******************************************************************************
3135 // sleepOnClamshellClosed
3137 // contains the logic to determine if the system should sleep when the clamshell
3139 //******************************************************************************
3141 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3143 if (!clamshellExists
)
3146 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3147 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3149 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3152 void IOPMrootDomain::sendClientClamshellNotification( void )
3154 /* Only broadcast clamshell alert if clamshell exists. */
3155 if (!clamshellExists
)
3158 setProperty(kAppleClamshellStateKey
,
3159 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3161 setProperty(kAppleClamshellCausesSleepKey
,
3162 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3164 /* Argument to message is a bitfiel of
3165 * ( kClamshellStateBit | kClamshellSleepBit )
3167 messageClients(kIOPMMessageClamshellStateChange
,
3168 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3169 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3172 //******************************************************************************
3173 // getSleepSupported
3176 //******************************************************************************
3178 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3180 return( platformSleepSupport
);
3183 //******************************************************************************
3184 // setSleepSupported
3187 //******************************************************************************
3189 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3191 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3192 OSBitOrAtomic(flags
, &platformSleepSupport
);
3195 //******************************************************************************
3196 // setDisableClamShellSleep
3198 //******************************************************************************
3200 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3202 if (gIOPMWorkLoop
->inGate() == false) {
3204 gIOPMWorkLoop
->runAction(
3205 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3212 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3213 if ( clamshellSleepDisabled
!= val
)
3215 clamshellSleepDisabled
= val
;
3216 // If clamshellSleepDisabled is reset to 0, reevaluate if
3217 // system need to go to sleep due to clamshell state
3218 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3219 handlePowerNotification(kLocalEvalClamshellCommand
);
3224 //******************************************************************************
3228 //******************************************************************************
3230 void IOPMrootDomain::wakeFromDoze( void )
3232 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3238 //******************************************************************************
3241 // Adds a new feature to the supported features dictionary
3242 //******************************************************************************
3244 void IOPMrootDomain::publishFeature( const char * feature
)
3246 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3249 //******************************************************************************
3250 // publishFeature (with supported power source specified)
3252 // Adds a new feature to the supported features dictionary
3253 //******************************************************************************
3255 void IOPMrootDomain::publishFeature(
3256 const char *feature
,
3257 uint32_t supportedWhere
,
3258 uint32_t *uniqueFeatureID
)
3260 static uint16_t next_feature_id
= 500;
3262 OSNumber
*new_feature_data
= NULL
;
3263 OSNumber
*existing_feature
= NULL
;
3264 OSArray
*existing_feature_arr
= NULL
;
3265 OSObject
*osObj
= NULL
;
3266 uint32_t feature_value
= 0;
3268 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3270 if(!supportedWhere
) {
3271 // Feature isn't supported anywhere!
3275 if(next_feature_id
> 5000) {
3276 // Far, far too many features!
3280 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3282 OSDictionary
*features
=
3283 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3285 // Create new features dict if necessary
3286 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3287 features
= OSDictionary::withDictionary(features
);
3289 features
= OSDictionary::withCapacity(1);
3292 // Create OSNumber to track new feature
3294 next_feature_id
+= 1;
3295 if( uniqueFeatureID
) {
3296 // We don't really mind if the calling kext didn't give us a place
3297 // to stash their unique id. Many kexts don't plan to unload, and thus
3298 // have no need to remove themselves later.
3299 *uniqueFeatureID
= next_feature_id
;
3302 feature_value
= (uint32_t)next_feature_id
;
3303 feature_value
<<= 16;
3304 feature_value
+= supportedWhere
;
3306 new_feature_data
= OSNumber::withNumber(
3307 (unsigned long long)feature_value
, 32);
3309 // Does features object already exist?
3310 if( (osObj
= features
->getObject(feature
)) )
3312 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3314 // We need to create an OSArray to hold the now 2 elements.
3315 existing_feature_arr
= OSArray::withObjects(
3316 (const OSObject
**)&existing_feature
, 1, 2);
3317 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3319 // Add object to existing array
3320 existing_feature_arr
= OSArray::withArray(
3321 existing_feature_arr
,
3322 existing_feature_arr
->getCount() + 1);
3325 if (existing_feature_arr
)
3327 existing_feature_arr
->setObject(new_feature_data
);
3328 features
->setObject(feature
, existing_feature_arr
);
3329 existing_feature_arr
->release();
3330 existing_feature_arr
= 0;
3333 // The easy case: no previously existing features listed. We simply
3334 // set the OSNumber at key 'feature' and we're on our way.
3335 features
->setObject(feature
, new_feature_data
);
3338 new_feature_data
->release();
3340 setProperty(kRootDomainSupportedFeatures
, features
);
3342 features
->release();
3344 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3346 // Notify EnergySaver and all those in user space so they might
3347 // re-populate their feature specific UI
3348 if(pmPowerStateQueue
) {
3349 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3353 //******************************************************************************
3354 // removePublishedFeature
3356 // Removes previously published feature
3357 //******************************************************************************
3359 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3361 IOReturn ret
= kIOReturnError
;
3362 uint32_t feature_value
= 0;
3363 uint16_t feature_id
= 0;
3364 bool madeAChange
= false;
3366 OSSymbol
*dictKey
= NULL
;
3367 OSCollectionIterator
*dictIterator
= NULL
;
3368 OSArray
*arrayMember
= NULL
;
3369 OSNumber
*numberMember
= NULL
;
3370 OSObject
*osObj
= NULL
;
3371 OSNumber
*osNum
= NULL
;
3372 OSArray
*arrayMemberCopy
;
3374 if (kBadPMFeatureID
== removeFeatureID
)
3375 return kIOReturnNotFound
;
3377 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3379 OSDictionary
*features
=
3380 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3382 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3384 // Any modifications to the dictionary are made to the copy to prevent
3385 // races & crashes with userland clients. Dictionary updated
3386 // automically later.
3387 features
= OSDictionary::withDictionary(features
);
3390 ret
= kIOReturnNotFound
;
3394 // We iterate 'features' dictionary looking for an entry tagged
3395 // with 'removeFeatureID'. If found, we remove it from our tracking
3396 // structures and notify the OS via a general interest message.
3398 dictIterator
= OSCollectionIterator::withCollection(features
);
3403 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3405 osObj
= features
->getObject(dictKey
);
3407 // Each Feature is either tracked by an OSNumber
3408 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3410 feature_value
= numberMember
->unsigned32BitValue();
3411 feature_id
= (uint16_t)(feature_value
>> 16);
3413 if( feature_id
== (uint16_t)removeFeatureID
)
3416 features
->removeObject(dictKey
);
3421 // Or tracked by an OSArray of OSNumbers
3422 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3424 unsigned int arrayCount
= arrayMember
->getCount();
3426 for(unsigned int i
=0; i
<arrayCount
; i
++)
3428 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3433 feature_value
= osNum
->unsigned32BitValue();
3434 feature_id
= (uint16_t)(feature_value
>> 16);
3436 if( feature_id
== (uint16_t)removeFeatureID
)
3439 if( 1 == arrayCount
) {
3440 // If the array only contains one element, remove
3442 features
->removeObject(dictKey
);
3444 // Otherwise remove the element from a copy of the array.
3445 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3446 if (arrayMemberCopy
)
3448 arrayMemberCopy
->removeObject(i
);
3449 features
->setObject(dictKey
, arrayMemberCopy
);
3450 arrayMemberCopy
->release();
3461 dictIterator
->release();
3465 ret
= kIOReturnSuccess
;
3467 setProperty(kRootDomainSupportedFeatures
, features
);
3469 // Notify EnergySaver and all those in user space so they might
3470 // re-populate their feature specific UI
3471 if(pmPowerStateQueue
) {
3472 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3475 ret
= kIOReturnNotFound
;
3479 if(features
) features
->release();
3480 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3484 //******************************************************************************
3485 // publishPMSetting (private)
3487 // Should only be called by PMSettingObject to publish a PM Setting as a
3488 // supported feature.
3489 //******************************************************************************
3491 void IOPMrootDomain::publishPMSetting(
3492 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3494 if (noPublishPMSettings
&&
3495 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3497 // Setting found in noPublishPMSettings array
3498 *featureID
= kBadPMFeatureID
;
3503 feature
->getCStringNoCopy(), where
, featureID
);
3506 //******************************************************************************
3507 // setPMSetting (private)
3509 // Internal helper to relay PM settings changes from user space to individual
3510 // drivers. Should be called only by IOPMrootDomain::setProperties.
3511 //******************************************************************************
3513 IOReturn
IOPMrootDomain::setPMSetting(
3514 const OSSymbol
*type
,
3517 PMSettingCallEntry
*entries
= 0;
3518 OSArray
*chosen
= 0;
3519 const OSArray
*array
;
3520 PMSettingObject
*pmso
;
3521 thread_t thisThread
;
3522 int i
, j
, count
, capacity
;
3525 return kIOReturnBadArgument
;
3529 // Update settings dict so changes are visible from copyPMSetting().
3530 fPMSettingsDict
->setObject(type
, object
);
3532 // Prep all PMSetting objects with the given 'type' for callout.
3533 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3534 if (!array
|| ((capacity
= array
->getCount()) == 0))
3537 // Array to retain PMSetting objects targeted for callout.
3538 chosen
= OSArray::withCapacity(capacity
);
3540 goto unlock_exit
; // error
3542 entries
= IONew(PMSettingCallEntry
, capacity
);
3544 goto unlock_exit
; // error
3545 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3547 thisThread
= current_thread();
3549 for (i
= 0, j
= 0; i
<capacity
; i
++)
3551 pmso
= (PMSettingObject
*) array
->getObject(i
);
3554 entries
[j
].thread
= thisThread
;
3555 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3556 chosen
->setObject(pmso
);
3565 // Call each pmso in the chosen array.
3566 for (i
=0; i
<count
; i
++)
3568 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3569 pmso
->dispatchPMSetting(type
, object
);
3573 for (i
=0; i
<count
; i
++)
3575 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3576 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3577 if (pmso
->waitThread
)
3579 PMSETTING_WAKEUP(pmso
);
3585 if (chosen
) chosen
->release();
3586 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3588 return kIOReturnSuccess
;
3591 //******************************************************************************
3592 // copyPMSetting (public)
3594 // Allows kexts to safely read setting values, without being subscribed to
3596 //******************************************************************************
3598 OSObject
* IOPMrootDomain::copyPMSetting(
3599 OSSymbol
*whichSetting
)
3601 OSObject
*obj
= NULL
;
3603 if(!whichSetting
) return NULL
;
3606 obj
= fPMSettingsDict
->getObject(whichSetting
);
3615 //******************************************************************************
3616 // registerPMSettingController (public)
3618 // direct wrapper to registerPMSettingController with uint32_t power source arg
3619 //******************************************************************************
3621 IOReturn
IOPMrootDomain::registerPMSettingController(
3622 const OSSymbol
* settings
[],
3623 IOPMSettingControllerCallback func
,
3628 return registerPMSettingController(
3630 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3631 func
, target
, refcon
, handle
);
3634 //******************************************************************************
3635 // registerPMSettingController (public)
3637 // Kexts may register for notifications when a particular setting is changed.
3638 // A list of settings is available in IOPM.h.
3640 // * settings - An OSArray containing OSSymbols. Caller should populate this
3641 // array with a list of settings caller wants notifications from.
3642 // * func - A C function callback of the type IOPMSettingControllerCallback
3643 // * target - caller may provide an OSObject *, which PM will pass as an
3644 // target to calls to "func"
3645 // * refcon - caller may provide an void *, which PM will pass as an
3646 // argument to calls to "func"
3647 // * handle - This is a return argument. We will populate this pointer upon
3648 // call success. Hold onto this and pass this argument to
3649 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3651 // kIOReturnSuccess on success
3652 //******************************************************************************
3654 IOReturn
IOPMrootDomain::registerPMSettingController(
3655 const OSSymbol
* settings
[],
3656 uint32_t supportedPowerSources
,
3657 IOPMSettingControllerCallback func
,
3662 PMSettingObject
*pmso
= NULL
;
3663 OSObject
*pmsh
= NULL
;
3664 OSArray
*list
= NULL
;
3667 if (NULL
== settings
||
3671 return kIOReturnBadArgument
;
3674 pmso
= PMSettingObject::pmSettingObject(
3675 (IOPMrootDomain
*) this, func
, target
,
3676 refcon
, supportedPowerSources
, settings
, &pmsh
);
3680 return kIOReturnInternalError
;
3684 for (i
=0; settings
[i
]; i
++)
3686 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3688 // New array of callbacks for this setting
3689 list
= OSArray::withCapacity(1);
3690 settingsCallbacks
->setObject(settings
[i
], list
);
3694 // Add caller to the callback list
3695 list
->setObject(pmso
);
3699 // Return handle to the caller, the setting object is private.
3702 return kIOReturnSuccess
;
3705 //******************************************************************************
3706 // deregisterPMSettingObject (private)
3708 // Only called from PMSettingObject.
3709 //******************************************************************************
3711 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3713 thread_t thisThread
= current_thread();
3714 PMSettingCallEntry
*callEntry
;
3715 OSCollectionIterator
*iter
;
3723 pmso
->disabled
= true;
3725 // Wait for all callout threads to finish.
3728 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3730 if (callEntry
->thread
!= thisThread
)
3738 assert(0 == pmso
->waitThread
);
3739 pmso
->waitThread
= thisThread
;
3740 PMSETTING_WAIT(pmso
);
3741 pmso
->waitThread
= 0;
3745 // Search each PM settings array in the kernel.
3746 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3749 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3751 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3752 index
= array
->getNextIndexOfObject(pmso
, 0);
3754 array
->removeObject(index
);
3765 //******************************************************************************
3766 // informCPUStateChange
3768 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3769 // running on battery, with the lid closed, etc.
3771 // informCPUStateChange is a no-op on non x86 systems
3772 // only x86 has explicit support in the IntelCPUPowerManagement kext
3773 //******************************************************************************
3775 void IOPMrootDomain::informCPUStateChange(
3779 #if defined(__i386__) || defined(__x86_64__)
3781 pmioctlVariableInfo_t varInfoStruct
;
3783 const char *varNameStr
= NULL
;
3784 int32_t *varIndex
= NULL
;
3786 if (kInformAC
== type
) {
3787 varNameStr
= kIOPMRootDomainBatPowerCString
;
3788 varIndex
= &idxPMCPULimitedPower
;
3789 } else if (kInformLid
== type
) {
3790 varNameStr
= kIOPMRootDomainLidCloseCString
;
3791 varIndex
= &idxPMCPUClamshell
;
3796 // Set the new value!
3797 // pmCPUControl will assign us a new ID if one doesn't exist yet
3798 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3799 varInfoStruct
.varID
= *varIndex
;
3800 varInfoStruct
.varType
= vBool
;
3801 varInfoStruct
.varInitValue
= value
;
3802 varInfoStruct
.varCurValue
= value
;
3803 strncpy( (char *)varInfoStruct
.varName
,
3804 (const char *)varNameStr
,
3805 strlen(varNameStr
) + 1 );
3808 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3810 // pmCPU only assigns numerical id's when a new varName is specified
3812 && (*varIndex
== kCPUUnknownIndex
))
3814 // pmCPUControl has assigned us a new variable ID.
3815 // Let's re-read the structure we just SET to learn that ID.
3816 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3820 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3821 *varIndex
= varInfoStruct
.varID
;
3827 #endif /* __i386__ || __x86_64__ */
3831 // MARK: Deep Sleep Policy
3835 //******************************************************************************
3836 // evaluateSystemSleepPolicy
3837 //******************************************************************************
3839 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3843 kIOPMSleepFlagHibernate
= 0x00000001,
3844 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3847 struct IOPMSystemSleepPolicyEntry
3849 uint32_t factorMask
;
3850 uint32_t factorBits
;
3851 uint32_t sleepFlags
;
3852 uint32_t wakeEvents
;
3853 } __attribute__((packed
));
3855 struct IOPMSystemSleepPolicyTable
3859 uint16_t entryCount
;
3860 IOPMSystemSleepPolicyEntry entries
[];
3861 } __attribute__((packed
));
3864 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3865 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3869 getSleepTypeAttributes( uint32_t sleepType
)
3871 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3876 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3877 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3878 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3879 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3883 if (sleepType
>= kIOPMSleepTypeLast
)
3886 return sleepTypeAttributes
[sleepType
];
3889 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3890 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3892 const IOPMSystemSleepPolicyTable
* pt
;
3893 OSObject
* prop
= 0;
3894 OSData
* policyData
;
3895 uint64_t currentFactors
= 0;
3896 uint32_t standbyDelay
= 0;
3897 uint32_t powerOffDelay
= 0;
3898 uint32_t powerOffTimer
= 0;
3900 bool standbyEnabled
;
3901 bool powerOffEnabled
;
3904 // Get platform's sleep policy table
3905 if (!gSleepPolicyHandler
)
3907 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3908 if (!prop
) goto done
;
3911 // Fetch additional settings
3912 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3913 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3914 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3915 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3916 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3917 powerOffTimer
= powerOffDelay
;
3919 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3920 sleepPhase
, standbyEnabled
, standbyDelay
,
3921 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3923 // pmset level overrides
3924 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3926 if (!gSleepPolicyHandler
)
3928 standbyEnabled
= false;
3929 powerOffEnabled
= false;
3932 else if (!(*hibMode
& kIOHibernateModeSleep
))
3934 // Force hibernate (i.e. mode 25)
3935 // If standby is enabled, force standy.
3936 // If poweroff is enabled, force poweroff.
3938 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3939 else if (powerOffEnabled
)
3940 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3942 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3945 // Current factors based on environment and assertions
3946 if (sleepTimerMaintenance
)
3947 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3948 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
3949 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3950 if (!clamshellClosed
)
3951 currentFactors
|= kIOPMSleepFactorLidOpen
;
3952 if (acAdaptorConnected
)
3953 currentFactors
|= kIOPMSleepFactorACPower
;
3954 if (lowBatteryCondition
)
3955 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3957 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3958 if (!standbyEnabled
)
3959 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3960 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3961 kIOPMDriverAssertionLevelOff
)
3962 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3963 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3964 kIOPMDriverAssertionLevelOff
)
3965 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3966 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3967 kIOPMDriverAssertionLevelOff
)
3968 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3969 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3970 kIOPMDriverAssertionLevelOff
)
3971 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3972 if (_scheduledAlarms
!= 0)
3973 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3974 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3975 kIOPMDriverAssertionLevelOff
)
3976 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3977 #define TCPKEEPALIVE 1
3979 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
3980 kIOPMDriverAssertionLevelOff
)
3981 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
3983 if (!powerOffEnabled
)
3984 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3986 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3988 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
3989 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
3990 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
3991 if (thermalWarningState
)
3992 currentFactors
|= kIOPMSleepFactorThermalWarning
;
3994 DLOG("sleep factors 0x%llx\n", currentFactors
);
3996 if (gSleepPolicyHandler
)
3998 uint32_t savedHibernateMode
;
4001 if (!gSleepPolicyVars
)
4003 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4004 if (!gSleepPolicyVars
)
4006 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4008 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4009 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4010 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4011 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4012 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4013 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4014 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4015 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4016 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4017 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4018 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4020 if (kIOPMSleepPhase0
== sleepPhase
)
4022 // preserve hibernateMode
4023 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4024 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4026 else if (kIOPMSleepPhase1
== sleepPhase
)
4028 // use original hibernateMode for phase2
4029 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4032 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4034 if (kIOPMSleepPhase0
== sleepPhase
)
4036 // restore hibernateMode
4037 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4040 if ((result
!= kIOReturnSuccess
) ||
4041 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4042 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4043 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4045 MSG("sleep policy handler error\n");
4049 if ((getSleepTypeAttributes(params
->sleepType
) &
4050 kIOPMSleepAttributeHibernateSetup
) &&
4051 ((*hibMode
& kIOHibernateModeOn
) == 0))
4053 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4056 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4057 params
->version
, params
->sleepType
, params
->sleepFlags
,
4058 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4063 // Policy table is meaningless without standby enabled
4064 if (!standbyEnabled
)
4067 // Validate the sleep policy table
4068 policyData
= OSDynamicCast(OSData
, prop
);
4069 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4072 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4073 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4074 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4077 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4078 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4081 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4083 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4084 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4086 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4087 entry
->factorMask
, entry
->factorBits
,
4088 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4092 DLOG("^ found match\n");
4095 params
->version
= kIOPMSystemSleepParametersVersion
;
4096 params
->reserved1
= 1;
4097 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4098 params
->sleepType
= kIOPMSleepTypeStandby
;
4100 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4102 params
->ecWakeEvents
= entry
->wakeEvents
;
4103 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4105 if (kIOPMSleepPhase2
== sleepPhase
)
4107 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4109 if (!_standbyTimerResetSeconds
||
4110 (now_secs
<= _standbyTimerResetSeconds
))
4112 // Reset standby timer adjustment
4113 _standbyTimerResetSeconds
= now_secs
;
4114 DLOG("standby delay %u, reset %u\n",
4115 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4117 else if (standbyDelay
)
4119 // Shorten the standby delay timer
4120 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4121 if (standbyDelay
> elapsed
)
4122 standbyDelay
-= elapsed
;
4124 standbyDelay
= 1; // must be > 0
4126 DLOG("standby delay %u, elapsed %u\n",
4127 standbyDelay
, (uint32_t) elapsed
);
4130 params
->ecWakeTimer
= standbyDelay
;
4132 else if (kIOPMSleepPhase2
== sleepPhase
)
4134 // A sleep that does not enable the sleep timer will reset
4135 // the standby delay adjustment.
4136 _standbyTimerResetSeconds
= 0;
4148 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4150 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4152 // Evaluate early (priority interest phase), before drivers sleep.
4154 DLOG("%s\n", __FUNCTION__
);
4155 removeProperty(kIOPMSystemSleepParametersKey
);
4157 // Full wake resets the standby timer delay adjustment
4158 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4159 _standbyTimerResetSeconds
= 0;
4161 hibernateDisabled
= false;
4163 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4165 // Save for late evaluation if sleep is aborted
4166 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4168 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4171 if (!hibernateRetry
&&
4172 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4173 kIOPMSleepAttributeHibernateSetup
) == 0))
4175 // skip hibernate setup
4176 hibernateDisabled
= true;
4180 // Publish IOPMSystemSleepType
4181 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4182 if (sleepType
== kIOPMSleepTypeInvalid
)
4185 sleepType
= kIOPMSleepTypeNormalSleep
;
4186 if (hibernateMode
& kIOHibernateModeOn
)
4187 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4188 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4190 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4191 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4193 // report the lowest possible sleep state
4194 sleepType
= kIOPMSleepTypePowerOff
;
4197 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4200 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4202 IOPMSystemSleepParameters params
;
4203 OSData
* paramsData
;
4205 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4207 DLOG("%s\n", __FUNCTION__
);
4209 bzero(¶ms
, sizeof(params
));
4210 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4212 if ((hibernateDisabled
|| hibernateAborted
) &&
4213 (getSleepTypeAttributes(params
.sleepType
) &
4214 kIOPMSleepAttributeHibernateSetup
))
4216 // Final evaluation picked a state requiring hibernation,
4217 // but hibernate setup was skipped. Arm a short sleep using
4218 // the early non-hibernate sleep parameters.
4219 // Set hibernateRetry flag to force hibernate setup on the
4222 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4223 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4224 params
.ecWakeTimer
= 1;
4225 hibernateRetry
= true;
4226 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
4227 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
4231 hibernateRetry
= false;
4234 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4237 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4238 paramsData
->release();
4241 if (getSleepTypeAttributes(params
.sleepType
) &
4242 kIOPMSleepAttributeHibernateSleep
)
4244 // Disable sleep to force hibernation
4245 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4250 bool IOPMrootDomain::getHibernateSettings(
4251 uint32_t * hibernateModePtr
,
4252 uint32_t * hibernateFreeRatio
,
4253 uint32_t * hibernateFreeTime
)
4255 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4256 // has updated the hibernateDisabled flag.
4258 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4259 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4260 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4261 if (hibernateDisabled
)
4262 *hibernateModePtr
= 0;
4263 else if (gSleepPolicyHandler
)
4264 *hibernateModePtr
= hibernateMode
;
4265 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4269 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4271 OSObject
* optionsProp
;
4272 OSDictionary
* optionsDict
;
4277 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4278 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4282 obj
= optionsDict
->getObject(key
);
4283 if (obj
) obj
->retain();
4287 obj
= copyProperty(key
);
4291 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4293 *option
= num
->unsigned32BitValue();
4296 else if (OSDynamicCast(OSBoolean
, obj
))
4298 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4306 optionsProp
->release();
4310 #endif /* HIBERNATION */
4312 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4315 IOPMSystemSleepParameters params
;
4316 uint32_t hibMode
= 0;
4319 if (gIOPMWorkLoop
->inGate() == false)
4321 IOReturn ret
= gIOPMWorkLoop
->runAction(
4322 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4323 &IOPMrootDomain::getSystemSleepType
),
4325 (void *) sleepType
);
4329 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4330 bzero(¶ms
, sizeof(params
));
4332 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4335 *sleepType
= params
.sleepType
;
4336 return kIOReturnSuccess
;
4340 return kIOReturnUnsupported
;
4344 // MARK: Shutdown and Restart
4346 //******************************************************************************
4347 // handlePlatformHaltRestart
4349 //******************************************************************************
4351 struct HaltRestartApplierContext
{
4352 IOPMrootDomain
* RootDomain
;
4353 unsigned long PowerState
;
4354 IOPMPowerFlags PowerFlags
;
4357 const char * LogString
;
4361 platformHaltRestartApplier( OSObject
* object
, void * context
)
4363 IOPowerStateChangeNotification notify
;
4364 HaltRestartApplierContext
* ctx
;
4365 AbsoluteTime startTime
;
4368 ctx
= (HaltRestartApplierContext
*) context
;
4370 memset(¬ify
, 0, sizeof(notify
));
4371 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4372 notify
.returnValue
= 0;
4373 notify
.stateNumber
= ctx
->PowerState
;
4374 notify
.stateFlags
= ctx
->PowerFlags
;
4376 clock_get_uptime(&startTime
);
4377 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4378 deltaTime
= computeDeltaTimeMS(&startTime
);
4380 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4381 (gIOKitDebug
& kIOLogPMRootDomain
))
4383 _IOServiceInterestNotifier
* notifier
;
4384 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4386 // IOService children of IOPMrootDomain are not instrumented.
4387 // Only IORootParent currently falls under that group.
4391 LOG("%s handler %p took %u ms\n",
4392 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4399 static void quiescePowerTreeCallback( void * target
, void * param
)
4401 IOLockLock(gPMHaltLock
);
4403 thread_wakeup(param
);
4404 IOLockUnlock(gPMHaltLock
);
4407 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4409 HaltRestartApplierContext ctx
;
4410 AbsoluteTime startTime
;
4413 memset(&ctx
, 0, sizeof(ctx
));
4414 ctx
.RootDomain
= this;
4416 clock_get_uptime(&startTime
);
4420 case kPEUPSDelayHaltCPU
:
4421 ctx
.PowerState
= OFF_STATE
;
4422 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4423 ctx
.LogString
= "PowerOff";
4427 ctx
.PowerState
= RESTART_STATE
;
4428 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4429 ctx
.LogString
= "Restart";
4433 ctx
.PowerState
= ON_STATE
;
4434 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4435 ctx
.LogString
= "PagingOff";
4436 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4438 IOHibernateSystemRestart();
4446 // Notify legacy clients
4447 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4449 // For normal shutdown, turn off File Server Mode.
4450 if (kPEHaltCPU
== pe_type
)
4452 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4453 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4456 setPMSetting(setting
, num
);
4462 if (kPEPagingOff
!= pe_type
)
4464 // Notify in power tree order
4465 notifySystemShutdown(this, ctx
.MessageType
);
4468 IOCPURunPlatformHaltRestartActions(pe_type
);
4470 // Wait for PM to quiesce
4471 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4473 AbsoluteTime quiesceTime
= mach_absolute_time();
4475 IOLockLock(gPMHaltLock
);
4476 gPMQuiesced
= false;
4477 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4480 while (!gPMQuiesced
)
4482 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4485 IOLockUnlock(gPMHaltLock
);
4487 deltaTime
= computeDeltaTimeMS(&quiesceTime
);
4488 DLOG("PM quiesce took %u ms\n", deltaTime
);
4491 deltaTime
= computeDeltaTimeMS(&startTime
);
4492 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4495 //******************************************************************************
4498 //******************************************************************************
4500 IOReturn
IOPMrootDomain::shutdownSystem( void )
4502 return kIOReturnUnsupported
;
4505 //******************************************************************************
4508 //******************************************************************************
4510 IOReturn
IOPMrootDomain::restartSystem( void )
4512 return kIOReturnUnsupported
;
4516 // MARK: System Capability
4518 //******************************************************************************
4519 // tagPowerPlaneService
4521 // Running on PM work loop thread.
4522 //******************************************************************************
4524 void IOPMrootDomain::tagPowerPlaneService(
4525 IOService
* service
,
4526 IOPMActions
* actions
)
4529 bool isDisplayWrangler
;
4531 memset(actions
, 0, sizeof(*actions
));
4532 actions
->target
= this;
4534 if (service
== this)
4536 actions
->actionPowerChangeStart
=
4537 OSMemberFunctionCast(
4538 IOPMActionPowerChangeStart
, this,
4539 &IOPMrootDomain::handleOurPowerChangeStart
);
4541 actions
->actionPowerChangeDone
=
4542 OSMemberFunctionCast(
4543 IOPMActionPowerChangeDone
, this,
4544 &IOPMrootDomain::handleOurPowerChangeDone
);
4546 actions
->actionPowerChangeOverride
=
4547 OSMemberFunctionCast(
4548 IOPMActionPowerChangeOverride
, this,
4549 &IOPMrootDomain::overrideOurPowerChange
);
4554 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4555 if (isDisplayWrangler
)
4560 isDisplayWrangler
= false;
4563 #if defined(__i386__) || defined(__x86_64__)
4564 if (isDisplayWrangler
)
4565 flags
|= kPMActionsFlagIsDisplayWrangler
;
4566 if (service
->getProperty("IOPMStrictTreeOrder"))
4567 flags
|= kPMActionsFlagIsGraphicsDevice
;
4568 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4569 flags
|= kPMActionsFlagIsAudioDevice
;
4572 // Find the power connection object that is a child of the PCI host
4573 // bridge, and has a graphics/audio device attached below. Mark the
4574 // power branch for delayed child notifications.
4578 IORegistryEntry
* child
= service
;
4579 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4581 while (child
!= this)
4583 if ((parent
== pciHostBridgeDriver
) ||
4586 if (OSDynamicCast(IOPowerConnection
, child
))
4588 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4589 conn
->delayChildNotification
= true;
4594 parent
= child
->getParentEntry(gIOPowerPlane
);
4600 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4601 actions
->parameter
|= flags
;
4602 actions
->actionPowerChangeOverride
=
4603 OSMemberFunctionCast(
4604 IOPMActionPowerChangeOverride
, this,
4605 &IOPMrootDomain::overridePowerChangeForUIService
);
4607 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4609 actions
->actionActivityTickle
=
4610 OSMemberFunctionCast(
4611 IOPMActionActivityTickle
, this,
4612 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4614 actions
->actionUpdatePowerClient
=
4615 OSMemberFunctionCast(
4616 IOPMActionUpdatePowerClient
, this,
4617 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4622 // Locate the first PCI host bridge for PMTrace.
4623 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4625 IOService
* provider
= service
->getProvider();
4626 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4627 provider
->inPlane(gIODTPlane
))
4629 pciHostBridgeDevice
= provider
;
4630 pciHostBridgeDriver
= service
;
4631 DLOG("PMTrace found PCI host bridge %s->%s\n",
4632 provider
->getName(), service
->getName());
4636 // Tag top-level PCI devices. The order of PMinit() call does not
4637 // change across boots and is used as the PCI bit number.
4638 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4640 // Would prefer to check built-in property, but tagPowerPlaneService()
4641 // is called before pciDevice->registerService().
4642 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4643 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4645 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4648 // Save the assigned bit for fast lookup.
4649 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4651 actions
->actionPowerChangeStart
=
4652 OSMemberFunctionCast(
4653 IOPMActionPowerChangeStart
, this,
4654 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4656 actions
->actionPowerChangeDone
=
4657 OSMemberFunctionCast(
4658 IOPMActionPowerChangeDone
, this,
4659 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4665 //******************************************************************************
4666 // PM actions for root domain
4667 //******************************************************************************
4669 void IOPMrootDomain::overrideOurPowerChange(
4670 IOService
* service
,
4671 IOPMActions
* actions
,
4672 IOPMPowerStateIndex
* inOutPowerState
,
4673 IOPMPowerChangeFlags
* inOutChangeFlags
,
4674 IOPMRequestTag requestTag
)
4676 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4677 uint32_t changeFlags
= *inOutChangeFlags
;
4678 uint32_t currentPowerState
= (uint32_t) getPowerState();
4680 if (changeFlags
& kIOPMParentInitiated
)
4682 // Root parent is permanently pegged at max power,
4683 // a parent initiated power change is unexpected.
4684 *inOutChangeFlags
|= kIOPMNotDone
;
4688 if (powerState
< currentPowerState
)
4690 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4692 // Root domain is dropping power state ON->SLEEP.
4693 // If system is in full wake, first enter dark wake by
4694 // converting the power drop to a capability change.
4695 // Once in dark wake, transition to sleep state ASAP.
4697 darkWakeToSleepASAP
= true;
4699 // Drop graphics and audio capability
4700 _desiredCapability
&= ~(
4701 kIOPMSystemCapabilityGraphics
|
4702 kIOPMSystemCapabilityAudio
);
4704 // Convert to capability change (ON->ON)
4705 *inOutPowerState
= ON_STATE
;
4706 *inOutChangeFlags
|= kIOPMSynchronize
;
4708 // Revert device desire from SLEEP to ON
4709 changePowerStateToPriv(ON_STATE
);
4713 // System is in dark wake, ok to drop power state.
4714 // Broadcast root powering down to entire tree.
4715 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4718 else if (powerState
> currentPowerState
)
4720 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4722 // Broadcast power up when waking from sleep, but not for the
4723 // initial power change at boot by checking for cpu capability.
4724 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4729 void IOPMrootDomain::handleOurPowerChangeStart(
4730 IOService
* service
,
4731 IOPMActions
* actions
,
4732 IOPMPowerStateIndex powerState
,
4733 IOPMPowerChangeFlags
* inOutChangeFlags
,
4734 IOPMRequestTag requestTag
)
4736 uint32_t changeFlags
= *inOutChangeFlags
;
4737 uint32_t currentPowerState
= (uint32_t) getPowerState();
4738 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4739 bool publishSleepReason
= false;
4741 _systemTransitionType
= kSystemTransitionNone
;
4742 _systemMessageClientMask
= 0;
4743 capabilityLoss
= false;
4744 toldPowerdCapWillChange
= false;
4746 if (lowBatteryCondition
)
4748 // Low battery notification may arrive after the initial sleep request
4749 // has been queued. Override the sleep reason so powerd and others can
4750 // treat this as an emergency sleep.
4751 sleepReason
= kIOPMSleepReasonLowPower
;
4754 // 1. Explicit capability change.
4756 if (changeFlags
& kIOPMSynchronize
)
4758 if (powerState
== ON_STATE
)
4760 if (changeFlags
& kIOPMSyncNoChildNotify
)
4761 _systemTransitionType
= kSystemTransitionNewCapClient
;
4763 _systemTransitionType
= kSystemTransitionCapability
;
4767 // 2. Going to sleep (cancellation still possible).
4769 else if (powerState
< currentPowerState
)
4770 _systemTransitionType
= kSystemTransitionSleep
;
4772 // 3. Woke from (idle or demand) sleep.
4774 else if (!systemBooting
&&
4775 (changeFlags
& kIOPMSelfInitiated
) &&
4776 (powerState
> currentPowerState
))
4778 _systemTransitionType
= kSystemTransitionWake
;
4779 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4780 kIOPMSystemCapabilityNetwork
;
4782 // Early exit from dark wake to full (e.g. LID open)
4783 if (kFullWakeReasonNone
!= fullWakeReason
)
4785 _desiredCapability
|= (
4786 kIOPMSystemCapabilityGraphics
|
4787 kIOPMSystemCapabilityAudio
);
4790 IOHibernateSetWakeCapabilities(_desiredCapability
);
4794 // Update pending wake capability at the beginning of every
4795 // state transition (including synchronize). This will become
4796 // the current capability at the end of the transition.
4798 if (kSystemTransitionSleep
== _systemTransitionType
)
4800 _pendingCapability
= 0;
4801 capabilityLoss
= true;
4803 // Clear previous stats
4804 IOLockLock(pmStatsLock
);
4805 if (pmStatsAppResponses
)
4807 pmStatsAppResponses
->release();
4808 pmStatsAppResponses
= OSArray::withCapacity(5);
4810 IOLockUnlock(pmStatsLock
);
4813 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4815 _pendingCapability
= _desiredCapability
|
4816 kIOPMSystemCapabilityCPU
|
4817 kIOPMSystemCapabilityNetwork
;
4819 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4820 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4822 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4823 (_pendingCapability
== _currentCapability
))
4825 // Cancel the PM state change.
4826 _systemTransitionType
= kSystemTransitionNone
;
4827 *inOutChangeFlags
|= kIOPMNotDone
;
4829 if (__builtin_popcount(_pendingCapability
) <
4830 __builtin_popcount(_currentCapability
))
4831 capabilityLoss
= true;
4834 // 1. Capability change.
4836 if (kSystemTransitionCapability
== _systemTransitionType
)
4838 // Dark to Full transition.
4839 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4841 tracePoint( kIOPMTracePointDarkWakeExit
);
4843 willEnterFullWake();
4846 // Full to Dark transition.
4847 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4849 tracePoint( kIOPMTracePointDarkWakeEntry
);
4850 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4851 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4852 kSystemMessageClientLegacyApp
;
4856 // Prevent user active transitions before notifying clients
4857 // that system will sleep.
4858 preventTransitionToUserActive(true);
4860 IOService::setAdvisoryTickleEnable( false );
4862 // Publish the sleep reason for full to dark wake
4863 publishSleepReason
= true;
4864 lastSleepReason
= fullToDarkReason
= sleepReason
;
4866 // Publish a UUID for the Sleep --> Wake cycle
4867 handlePublishSleepWakeUUID(true);
4868 if (sleepDelaysReport
) {
4869 clock_get_uptime(&ts_sleepStart
);
4870 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
4877 else if (kSystemTransitionSleep
== _systemTransitionType
)
4879 // Beginning of a system sleep transition.
4880 // Cancellation is still possible.
4881 tracePoint( kIOPMTracePointSleepStarted
, sleepReason
);
4883 _systemMessageClientMask
= kSystemMessageClientAll
;
4884 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4885 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
4886 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4887 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4889 // Record the reason for dark wake back to sleep
4890 // System may not have ever achieved full wake
4892 publishSleepReason
= true;
4893 lastSleepReason
= sleepReason
;
4894 if (sleepDelaysReport
) {
4895 clock_get_uptime(&ts_sleepStart
);
4896 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
4902 else if (kSystemTransitionWake
== _systemTransitionType
)
4904 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4905 // Clear stats about sleep
4907 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4909 willEnterFullWake();
4913 // Message powerd only
4914 _systemMessageClientMask
= kSystemMessageClientPowerd
;
4915 tellClients(kIOMessageSystemWillPowerOn
);
4919 // The only location where the sleep reason is published. At this point
4920 // sleep can still be cancelled, but sleep reason should be published
4921 // early for logging purposes.
4923 if (publishSleepReason
)
4925 static const char * IOPMSleepReasons
[] =
4927 kIOPMClamshellSleepKey
,
4928 kIOPMPowerButtonSleepKey
,
4929 kIOPMSoftwareSleepKey
,
4930 kIOPMOSSwitchHibernationKey
,
4932 kIOPMLowPowerSleepKey
,
4933 kIOPMThermalEmergencySleepKey
,
4934 kIOPMMaintenanceSleepKey
,
4935 kIOPMSleepServiceExitKey
,
4936 kIOPMDarkWakeThermalEmergencyKey
4939 // Record sleep cause in IORegistry
4940 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
4941 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
4942 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
4943 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
4947 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4948 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4950 _systemStateGeneration
++;
4951 systemDarkWake
= false;
4953 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4955 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
4956 _systemTransitionType
, _systemStateGeneration
,
4957 _systemMessageClientMask
,
4958 _desiredCapability
, _currentCapability
, _pendingCapability
);
4962 void IOPMrootDomain::handleOurPowerChangeDone(
4963 IOService
* service
,
4964 IOPMActions
* actions
,
4965 IOPMPowerStateIndex powerState
,
4966 IOPMPowerChangeFlags changeFlags
,
4967 IOPMRequestTag requestTag __unused
)
4969 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4971 _systemTransitionType
= kSystemTransitionNone
;
4975 if (_systemTransitionType
!= kSystemTransitionNone
)
4977 uint32_t currentPowerState
= (uint32_t) getPowerState();
4979 if (changeFlags
& kIOPMNotDone
)
4981 // Power down was cancelled or vetoed.
4982 _pendingCapability
= _currentCapability
;
4983 lastSleepReason
= 0;
4985 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
4986 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4988 pmPowerStateQueue
->submitPowerEvent(
4989 kPowerEventPolicyStimulus
,
4990 (void *) kStimulusDarkWakeReentry
,
4991 _systemStateGeneration
);
4994 // Revert device desire to max.
4995 changePowerStateToPriv(ON_STATE
);
4999 // Send message on dark wake to full wake promotion.
5000 // tellChangeUp() handles the normal SLEEP->ON case.
5002 if (kSystemTransitionCapability
== _systemTransitionType
)
5004 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5006 lastSleepReason
= 0; // stop logging wrangler tickles
5007 tellClients(kIOMessageSystemHasPoweredOn
);
5009 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5011 // Going dark, reset full wake state
5012 // userIsActive will be cleared by wrangler powering down
5013 wranglerTickled
= false;
5014 fullWakeReason
= kFullWakeReasonNone
;
5016 if (ts_sleepStart
) {
5017 clock_get_uptime(&wake2DarkwakeDelay
);
5018 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5019 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5025 // Reset state after exiting from dark wake.
5027 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5028 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5030 darkWakeMaintenance
= false;
5031 darkWakeToSleepASAP
= false;
5032 pciCantSleepValid
= false;
5033 darkWakeSleepService
= false;
5035 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5037 // Remove the influence of display power assertion
5038 // before next system wake.
5039 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5040 kWranglerPowerStateMin
);
5041 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5045 // Entered dark mode.
5047 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5048 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5050 // Queue an evaluation of whether to remain in dark wake,
5051 // and for how long. This serves the purpose of draining
5052 // any assertions from the queue.
5054 pmPowerStateQueue
->submitPowerEvent(
5055 kPowerEventPolicyStimulus
,
5056 (void *) kStimulusDarkWakeEntry
,
5057 _systemStateGeneration
);
5061 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5062 "dcp %x:%x:%x, dbgtimer %u\n",
5063 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5064 _systemTransitionType
, _systemStateGeneration
,
5065 _systemMessageClientMask
,
5066 _desiredCapability
, _currentCapability
, _pendingCapability
,
5067 _lastDebugWakeSeconds
);
5069 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5072 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5073 if (clamshellExists
&& fullWakeThreadCall
&&
5074 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5076 // Not the initial graphics full power, graphics won't
5077 // send a power notification to trigger a lid state
5080 AbsoluteTime deadline
;
5081 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5082 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5086 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5089 // Update current system capability.
5090 if (_currentCapability
!= _pendingCapability
)
5091 _currentCapability
= _pendingCapability
;
5093 // Update highest system capability.
5095 _highestCapability
|= _currentCapability
;
5097 if (darkWakePostTickle
&&
5098 (kSystemTransitionWake
== _systemTransitionType
) &&
5099 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5100 kDarkWakeFlagHIDTickleLate
)
5102 darkWakePostTickle
= false;
5106 // Reset tracepoint at completion of capability change,
5107 // completion of wake transition, and aborted sleep transition.
5109 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5110 (_systemTransitionType
== kSystemTransitionWake
) ||
5111 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5112 (changeFlags
& kIOPMNotDone
)))
5114 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5115 tracePoint( kIOPMTracePointSystemUp
, 0 );
5118 _systemTransitionType
= kSystemTransitionNone
;
5119 _systemMessageClientMask
= 0;
5120 toldPowerdCapWillChange
= false;
5122 logGraphicsClamp
= false;
5126 //******************************************************************************
5127 // PM actions for graphics and audio.
5128 //******************************************************************************
5130 void IOPMrootDomain::overridePowerChangeForUIService(
5131 IOService
* service
,
5132 IOPMActions
* actions
,
5133 IOPMPowerStateIndex
* inOutPowerState
,
5134 IOPMPowerChangeFlags
* inOutChangeFlags
)
5136 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5137 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5139 if (kSystemTransitionNone
== _systemTransitionType
)
5141 // Not in midst of a system transition.
5142 // Do not modify power limit enable state.
5144 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5146 // Activate power limiter.
5148 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5149 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5150 (changeFlags
& kIOPMSynchronize
))
5152 actions
->parameter
|= kPMActionsFlagLimitPower
;
5154 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5155 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5156 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5157 (changeFlags
& kIOPMSynchronize
))
5159 actions
->parameter
|= kPMActionsFlagLimitPower
;
5161 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5162 (_systemTransitionType
== kSystemTransitionSleep
))
5164 // For graphics devices, arm the limiter when entering
5165 // system sleep. Not when dropping to dark wake.
5166 actions
->parameter
|= kPMActionsFlagLimitPower
;
5169 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5171 DLOG("+ plimit %s %p\n",
5172 service
->getName(), OBFUSCATE(service
));
5177 // Remove power limit.
5179 if ((actions
->parameter
& (
5180 kPMActionsFlagIsDisplayWrangler
|
5181 kPMActionsFlagIsGraphicsDevice
)) &&
5182 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5184 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5186 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5187 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5189 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5192 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5194 DLOG("- plimit %s %p\n",
5195 service
->getName(), OBFUSCATE(service
));
5199 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5201 uint32_t maxPowerState
= (uint32_t)(-1);
5203 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5205 // Enforce limit for system power/cap transitions.
5208 if ((service
->getPowerState() > maxPowerState
) &&
5209 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5213 // Remove lingering effects of any tickle before entering
5214 // dark wake. It will take a new tickle to return to full
5215 // wake, so the existing tickle state is useless.
5217 if (changeFlags
& kIOPMDomainDidChange
)
5218 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5220 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5227 // Deny all self-initiated changes when power is limited.
5228 // Wrangler tickle should never defeat the limiter.
5230 maxPowerState
= service
->getPowerState();
5233 if (powerState
> maxPowerState
)
5235 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5236 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5238 *inOutPowerState
= maxPowerState
;
5240 if (darkWakePostTickle
&&
5241 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5242 (changeFlags
& kIOPMDomainWillChange
) &&
5243 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5244 kDarkWakeFlagHIDTickleEarly
))
5246 darkWakePostTickle
= false;
5251 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5253 if (logGraphicsClamp
)
5258 clock_get_uptime(&now
);
5259 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5260 absolutetime_to_nanoseconds(now
, &nsec
);
5261 if (kIOLogPMRootDomain
& gIOKitDebug
)
5262 MSG("Graphics suppressed %u ms\n",
5263 ((int)((nsec
) / 1000000ULL)));
5265 graphicsSuppressed
= true;
5270 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5271 IOService
* service
,
5272 IOPMActions
* actions
)
5275 // Warning: Not running in PM work loop context - don't modify state !!!
5276 // Trap tickle directed to IODisplayWrangler while running with graphics
5277 // capability suppressed.
5279 assert(service
== wrangler
);
5281 clock_get_uptime(&userActivityTime
);
5282 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5283 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5284 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5286 userActivityCount
++;
5287 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5288 userActivityCount
, lastSleepReason
);
5291 if (!wranglerTickled
&&
5292 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5294 DLOG("display wrangler tickled\n");
5295 if (kIOLogPMRootDomain
& gIOKitDebug
)
5296 OSReportWithBacktrace("Dark wake display tickle");
5297 if (pmPowerStateQueue
)
5299 pmPowerStateQueue
->submitPowerEvent(
5300 kPowerEventPolicyStimulus
,
5301 (void *) kStimulusDarkWakeActivityTickle
,
5302 true /* set wake type */ );
5308 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5309 IOService
* service
,
5310 IOPMActions
* actions
,
5311 const OSSymbol
* powerClient
,
5312 IOPMPowerStateIndex oldPowerState
,
5313 IOPMPowerStateIndex newPowerState
)
5316 assert(service
== wrangler
);
5318 // This function implements half of the user active detection
5319 // by monitoring changes to the display wrangler's device desire.
5321 // User becomes active when either:
5322 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5323 // in max power state. This desire change in absence of a power state
5324 // change is detected within. This handles the case when user becomes
5325 // active while the display is already lit by setDisplayPowerOn().
5327 // 2. Power state change to max, and DeviceDesire is also at max.
5328 // Handled by displayWranglerNotification().
5330 // User becomes inactive when DeviceDesire drops to sleep state or below.
5332 DLOG("wrangler %s (ps %u, %u->%u)\n",
5333 powerClient
->getCStringNoCopy(),
5334 (uint32_t) service
->getPowerState(),
5335 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5337 if (powerClient
== gIOPMPowerClientDevice
)
5339 if ((newPowerState
> oldPowerState
) &&
5340 (newPowerState
== kWranglerPowerStateMax
) &&
5341 (service
->getPowerState() == kWranglerPowerStateMax
))
5343 evaluatePolicy( kStimulusEnterUserActiveState
);
5346 if ((newPowerState
< oldPowerState
) &&
5347 (newPowerState
<= kWranglerPowerStateSleep
))
5349 evaluatePolicy( kStimulusLeaveUserActiveState
);
5355 //******************************************************************************
5356 // User active state management
5357 //******************************************************************************
5359 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5362 _preventUserActive
= prevent
;
5363 if (wrangler
&& !_preventUserActive
)
5365 // Allowing transition to user active, but the wrangler may have
5366 // already powered ON in case of sleep cancel/revert. Poll the
5367 // same conditions checked for in displayWranglerNotification()
5368 // to bring the user active state up to date.
5370 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5371 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5372 kWranglerPowerStateMax
))
5374 evaluatePolicy( kStimulusEnterUserActiveState
);
5380 //******************************************************************************
5381 // Approve usage of delayed child notification by PM.
5382 //******************************************************************************
5384 bool IOPMrootDomain::shouldDelayChildNotification(
5385 IOService
* service
)
5387 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5388 (kFullWakeReasonNone
== fullWakeReason
) &&
5389 (kSystemTransitionWake
== _systemTransitionType
))
5391 DLOG("%s: delay child notify\n", service
->getName());
5397 //******************************************************************************
5398 // PM actions for PCI device.
5399 //******************************************************************************
5401 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5402 IOService
* service
,
5403 IOPMActions
* actions
,
5404 IOPMPowerStateIndex powerState
,
5405 IOPMPowerChangeFlags
* inOutChangeFlags
)
5407 pmTracer
->tracePCIPowerChange(
5408 PMTraceWorker::kPowerChangeStart
,
5409 service
, *inOutChangeFlags
,
5410 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5413 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5414 IOService
* service
,
5415 IOPMActions
* actions
,
5416 IOPMPowerStateIndex powerState
,
5417 IOPMPowerChangeFlags changeFlags
)
5419 pmTracer
->tracePCIPowerChange(
5420 PMTraceWorker::kPowerChangeCompleted
,
5421 service
, changeFlags
,
5422 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5425 //******************************************************************************
5428 // Override IOService::registerInterest() to intercept special clients.
5429 //******************************************************************************
5431 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5434 friend class IOPMrootDomain
;
5435 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5438 uint32_t ackTimeoutCnt
;
5442 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5444 IONotifier
* IOPMrootDomain::registerInterest(
5445 const OSSymbol
* typeOfInterest
,
5446 IOServiceInterestHandler handler
,
5447 void * target
, void * ref
)
5449 IOPMServiceInterestNotifier
*notifier
= 0;
5450 bool isSystemCapabilityClient
;
5451 bool isKernelCapabilityClient
;
5452 IOReturn rc
= kIOReturnError
;;
5454 isSystemCapabilityClient
=
5456 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5458 isKernelCapabilityClient
=
5460 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5462 if (isSystemCapabilityClient
)
5463 typeOfInterest
= gIOAppPowerStateInterest
;
5465 notifier
= new IOPMServiceInterestNotifier
;
5466 if (!notifier
) return NULL
;
5468 if (notifier
->init()) {
5469 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5471 if (rc
!= kIOReturnSuccess
) {
5472 notifier
->release();
5475 if (pmPowerStateQueue
)
5477 notifier
->ackTimeoutCnt
= 0;
5478 if (isSystemCapabilityClient
)
5481 if (pmPowerStateQueue
->submitPowerEvent(
5482 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5483 notifier
->release();
5486 if (isKernelCapabilityClient
)
5489 if (pmPowerStateQueue
->submitPowerEvent(
5490 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5491 notifier
->release();
5498 //******************************************************************************
5499 // systemMessageFilter
5501 //******************************************************************************
5503 bool IOPMrootDomain::systemMessageFilter(
5504 void * object
, void * arg1
, void * arg2
, void * arg3
)
5506 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5507 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5508 bool isCapClient
= false;
5512 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5513 (!isCapMsg
|| !_joinedCapabilityClients
||
5514 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5517 // Capability change message for app and kernel clients.
5521 if ((context
->notifyType
== kNotifyPriority
) ||
5522 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5525 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5526 (object
== (void *) systemCapabilityNotifier
))
5532 IOPMSystemCapabilityChangeParameters
* capArgs
=
5533 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5535 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5537 capArgs
->fromCapabilities
= 0;
5538 capArgs
->toCapabilities
= _currentCapability
;
5539 capArgs
->changeFlags
= 0;
5543 capArgs
->fromCapabilities
= _currentCapability
;
5544 capArgs
->toCapabilities
= _pendingCapability
;
5546 if (context
->isPreChange
)
5547 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5549 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5551 if ((object
== (void *) systemCapabilityNotifier
) &&
5552 context
->isPreChange
)
5554 toldPowerdCapWillChange
= true;
5558 // Capability change messages only go to the PM configd plugin.
5559 // Wait for response post-change if capabilitiy is increasing.
5560 // Wait for response pre-change if capability is decreasing.
5562 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5563 ( (capabilityLoss
&& context
->isPreChange
) ||
5564 (!capabilityLoss
&& !context
->isPreChange
) ) )
5566 // app has not replied yet, wait for it
5567 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5574 // Capability client will always see kIOMessageCanSystemSleep,
5575 // even for demand sleep. It will also have a chance to veto
5576 // sleep one last time after all clients have responded to
5577 // kIOMessageSystemWillSleep
5579 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5580 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5582 if (object
== (OSObject
*) systemCapabilityNotifier
)
5588 // Not idle sleep, don't ask apps.
5589 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5595 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5597 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5598 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5599 (fullToDarkReason
== kIOPMSleepReasonIdle
))
5604 // Reject capability change messages for legacy clients.
5605 // Reject legacy system sleep messages for capability client.
5607 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5612 // Filter system sleep messages.
5614 if ((context
->notifyType
== kNotifyApps
) &&
5615 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5617 IOPMServiceInterestNotifier
*notify
;
5620 if ((notify
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
))
5623 if (notify
->ackTimeoutCnt
>= 3)
5624 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5626 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5629 else if ((context
->notifyType
== kNotifyPriority
) &&
5630 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5637 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5639 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5640 if (_joinedCapabilityClients
->getCount() == 0)
5642 DLOG("destroyed capability client set %p\n",
5643 OBFUSCATE(_joinedCapabilityClients
));
5644 _joinedCapabilityClients
->release();
5645 _joinedCapabilityClients
= 0;
5652 //******************************************************************************
5653 // setMaintenanceWakeCalendar
5655 //******************************************************************************
5657 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5658 const IOPMCalendarStruct
* calendar
)
5664 return kIOReturnBadArgument
;
5666 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5668 return kIOReturnNoMemory
;
5670 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5671 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5672 if (kIOReturnSuccess
== ret
)
5673 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5675 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5677 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5678 if (kIOReturnSuccess
== ret
)
5679 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5681 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5688 // MARK: Display Wrangler
5690 //******************************************************************************
5691 // displayWranglerNotification
5693 // Handle the notification when the IODisplayWrangler changes power state.
5694 //******************************************************************************
5696 IOReturn
IOPMrootDomain::displayWranglerNotification(
5697 void * target
, void * refCon
,
5698 UInt32 messageType
, IOService
* service
,
5699 void * messageArgument
, vm_size_t argSize
)
5702 int displayPowerState
;
5703 IOPowerStateChangeNotification
* params
=
5704 (IOPowerStateChangeNotification
*) messageArgument
;
5706 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5707 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5708 return kIOReturnUnsupported
;
5712 return kIOReturnUnsupported
;
5714 displayPowerState
= params
->stateNumber
;
5715 DLOG("wrangler %s ps %d\n",
5716 getIOMessageString(messageType
), displayPowerState
);
5718 switch (messageType
) {
5719 case kIOMessageDeviceWillPowerOff
:
5720 // Display wrangler has dropped power due to display idle
5721 // or force system sleep.
5723 // 4 Display ON kWranglerPowerStateMax
5724 // 3 Display Dim kWranglerPowerStateDim
5725 // 2 Display Sleep kWranglerPowerStateSleep
5726 // 1 Not visible to user
5727 // 0 Not visible to user kWranglerPowerStateMin
5729 if (displayPowerState
<= kWranglerPowerStateSleep
)
5730 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5733 case kIOMessageDeviceHasPoweredOn
:
5734 // Display wrangler has powered on due to user activity
5735 // or wake from sleep.
5737 if (kWranglerPowerStateMax
== displayPowerState
)
5739 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5741 // See comment in handleUpdatePowerClientForDisplayWrangler
5742 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5743 kWranglerPowerStateMax
)
5745 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5751 return kIOReturnUnsupported
;
5754 //******************************************************************************
5755 // displayWranglerMatchPublished
5757 // Receives a notification when the IODisplayWrangler is published.
5758 // When it's published we install a power state change handler.
5759 //******************************************************************************
5761 bool IOPMrootDomain::displayWranglerMatchPublished(
5764 IOService
* newService
,
5765 IONotifier
* notifier __unused
)
5768 // found the display wrangler, now install a handler
5769 if( !newService
->registerInterest( gIOGeneralInterest
,
5770 &displayWranglerNotification
, target
, 0) )
5778 #if defined(__i386__) || defined(__x86_64__)
5780 bool IOPMrootDomain::IONVRAMMatchPublished(
5783 IOService
* newService
,
5784 IONotifier
* notifier
)
5786 unsigned int len
= 0;
5787 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5788 OSNumber
*statusCode
= NULL
;
5790 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5792 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5793 if (statusCode
!= NULL
) {
5794 if (statusCode
->unsigned64BitValue() != 0) {
5795 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5796 MSG("System was rebooted due to Sleep/Wake failure\n");
5799 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5800 MSG("System was non-responsive and was rebooted by watchdog\n");
5804 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5806 if (notifier
) notifier
->remove();
5811 bool IOPMrootDomain::IONVRAMMatchPublished(
5814 IOService
* newService
,
5815 IONotifier
* notifier __unused
)
5822 //******************************************************************************
5825 //******************************************************************************
5827 void IOPMrootDomain::reportUserInput( void )
5831 OSDictionary
* matching
;
5835 matching
= serviceMatching("IODisplayWrangler");
5836 iter
= getMatchingServices(matching
);
5837 if (matching
) matching
->release();
5840 wrangler
= (IOService
*) iter
->getNextObject();
5846 wrangler
->activityTickle(0,0);
5850 //******************************************************************************
5851 // latchDisplayWranglerTickle
5852 //******************************************************************************
5854 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5859 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5860 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5861 !checkSystemCanSustainFullWake())
5863 // Currently in dark wake, and not transitioning to full wake.
5864 // Full wake is unsustainable, so latch the tickle to prevent
5865 // the display from lighting up momentarily.
5866 wranglerTickleLatched
= true;
5870 wranglerTickleLatched
= false;
5873 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5875 wranglerTickleLatched
= false;
5877 pmPowerStateQueue
->submitPowerEvent(
5878 kPowerEventPolicyStimulus
,
5879 (void *) kStimulusDarkWakeActivityTickle
);
5882 return wranglerTickleLatched
;
5888 //******************************************************************************
5889 // setDisplayPowerOn
5891 // For root domain user client
5892 //******************************************************************************
5894 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
5896 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
5897 (void *) 0, options
);
5903 //******************************************************************************
5906 // Notification on battery class IOPowerSource appearance
5907 //******************************************************************************
5909 bool IOPMrootDomain::batteryPublished(
5912 IOService
* resourceService
,
5913 IONotifier
* notifier __unused
)
5915 // rdar://2936060&4435589
5916 // All laptops have dimmable LCD displays
5917 // All laptops have batteries
5918 // So if this machine has a battery, publish the fact that the backlight
5919 // supports dimming.
5920 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5926 // MARK: System PM Policy
5928 //******************************************************************************
5929 // checkSystemSleepAllowed
5931 //******************************************************************************
5933 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
5934 uint32_t sleepReason
)
5938 // Conditions that prevent idle and demand system sleep.
5941 if (userDisabledAllSleep
)
5943 err
= 1; // 1. user-space sleep kill switch
5947 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
5949 err
= 2; // 2. restart or shutdown in progress
5956 // Conditions above pegs the system at full wake.
5957 // Conditions below prevent system sleep but does not prevent
5958 // dark wake, and must be called from gated context.
5961 err
= 3; // 3. config does not support sleep
5965 if (lowBatteryCondition
|| thermalWarningState
)
5967 break; // always sleep on low battery or when in thermal warning state
5970 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
5972 break; // always sleep on dark wake thermal emergencies
5975 if (preventSystemSleepList
->getCount() != 0)
5977 err
= 4; // 4. child prevent system sleep clamp
5981 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5982 kIOPMDriverAssertionLevelOn
)
5984 err
= 5; // 5. CPU assertion
5988 if (pciCantSleepValid
)
5990 if (pciCantSleepFlag
)
5991 err
= 6; // 6. PCI card does not support PM (cached)
5994 else if (sleepSupportedPEFunction
&&
5995 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5998 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5999 ret
= getPlatform()->callPlatformFunction(
6000 sleepSupportedPEFunction
, false,
6001 NULL
, NULL
, NULL
, NULL
);
6002 pciCantSleepValid
= true;
6003 pciCantSleepFlag
= false;
6004 if ((platformSleepSupport
& kPCICantSleep
) ||
6005 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6007 err
= 6; // 6. PCI card does not support PM
6008 pciCantSleepFlag
= true;
6017 DLOG("System sleep prevented by %d\n", err
);
6023 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6025 return checkSystemSleepAllowed(0, 0);
6028 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6031 return checkSystemSleepAllowed(1, sleepReason
);
6034 //******************************************************************************
6035 // checkSystemCanSustainFullWake
6036 //******************************************************************************
6038 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6041 if (lowBatteryCondition
|| thermalWarningState
)
6043 // Low battery wake, or received a low battery notification
6044 // while system is awake. This condition will persist until
6045 // the following wake.
6049 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6051 // Graphics state is unknown and external display might not be probed.
6052 // Do not incorporate state that requires graphics to be in max power
6053 // such as desktopMode or clamshellDisabled.
6055 if (!acAdaptorConnected
)
6057 DLOG("full wake check: no AC\n");
6065 //******************************************************************************
6068 // Conditions that affect our wake/sleep decision has changed.
6069 // If conditions dictate that the system must remain awake, clamp power
6070 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6071 // is TRUE, then remove the power clamp and allow the power state to drop
6073 //******************************************************************************
6075 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6077 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
6078 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
6082 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
6084 changePowerStateToPriv(ON_STATE
);
6086 else if ( sleepASAP
)
6088 changePowerStateToPriv(SLEEP_STATE
);
6092 void IOPMrootDomain::handleDisplayPowerOn( )
6094 if (!wrangler
) return;
6095 if (displayPowerOnRequested
)
6097 if (!checkSystemCanSustainFullWake()) return;
6099 // Force wrangler to max power state. If system is in dark wake
6100 // this alone won't raise the wrangler's power state.
6102 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6104 // System in dark wake, always requesting full wake should
6105 // not have any bad side-effects, even if the request fails.
6107 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6109 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6110 requestFullWake( kFullWakeReasonDisplayOn
);
6115 // Relenquish desire to power up display.
6116 // Must first transition to state 1 since wrangler doesn't
6117 // power off the displays at state 0. At state 0 the root
6118 // domain is removed from the wrangler's power client list.
6120 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6121 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6127 //******************************************************************************
6128 // dispatchPowerEvent
6130 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6131 //******************************************************************************
6133 void IOPMrootDomain::dispatchPowerEvent(
6134 uint32_t event
, void * arg0
, uint64_t arg1
)
6136 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6141 case kPowerEventFeatureChanged
:
6142 messageClients(kIOPMMessageFeatureChange
, this);
6145 case kPowerEventReceivedPowerNotification
:
6146 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6149 case kPowerEventSystemBootCompleted
:
6152 systemBooting
= false;
6154 if (lowBatteryCondition
)
6156 privateSleepSystem (kIOPMSleepReasonLowPower
);
6158 // The rest is unnecessary since the system is expected
6159 // to sleep immediately. The following wake will update
6164 if (swd_flags
& SWD_VALID_LOGS
) {
6165 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6166 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6167 swd_logBufMap
->release();
6170 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6171 sleepWakeDebugDumpFromFile();
6173 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6174 // If logs are invalid, write the failure code
6175 sleepWakeDebugDumpFromMem(NULL
);
6177 // If lid is closed, re-send lid closed notification
6178 // now that booting is complete.
6179 if ( clamshellClosed
)
6181 handlePowerNotification(kLocalEvalClamshellCommand
);
6183 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6188 case kPowerEventSystemShutdown
:
6189 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6191 /* We set systemShutdown = true during shutdown
6192 to prevent sleep at unexpected times while loginwindow is trying
6193 to shutdown apps and while the OS is trying to transition to
6196 Set to true during shutdown, as soon as loginwindow shows
6197 the "shutdown countdown dialog", through individual app
6198 termination, and through black screen kernel shutdown.
6200 systemShutdown
= true;
6203 A shutdown was initiated, but then the shutdown
6204 was cancelled, clearing systemShutdown to false here.
6206 systemShutdown
= false;
6210 case kPowerEventUserDisabledSleep
:
6211 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6214 case kPowerEventRegisterSystemCapabilityClient
:
6215 if (systemCapabilityNotifier
)
6217 systemCapabilityNotifier
->release();
6218 systemCapabilityNotifier
= 0;
6222 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6223 systemCapabilityNotifier
->retain();
6225 /* intentional fall-through */
6227 case kPowerEventRegisterKernelCapabilityClient
:
6228 if (!_joinedCapabilityClients
)
6229 _joinedCapabilityClients
= OSSet::withCapacity(8);
6232 IONotifier
* notify
= (IONotifier
*) arg0
;
6233 if (_joinedCapabilityClients
)
6235 _joinedCapabilityClients
->setObject(notify
);
6236 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6242 case kPowerEventPolicyStimulus
:
6245 int stimulus
= (uintptr_t) arg0
;
6246 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6250 case kPowerEventAssertionCreate
:
6252 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6257 case kPowerEventAssertionRelease
:
6259 pmAssertions
->handleReleaseAssertion(arg1
);
6263 case kPowerEventAssertionSetLevel
:
6265 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6269 case kPowerEventQueueSleepWakeUUID
:
6270 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6272 case kPowerEventPublishSleepWakeUUID
:
6273 handlePublishSleepWakeUUID((bool)arg0
);
6276 case kPowerEventSetDisplayPowerOn
:
6277 if (!wrangler
) break;
6280 displayPowerOnRequested
= true;
6284 displayPowerOnRequested
= false;
6286 handleDisplayPowerOn();
6291 //******************************************************************************
6292 // systemPowerEventOccurred
6294 // The power controller is notifying us of a hardware-related power management
6295 // event that we must handle.
6297 // systemPowerEventOccurred covers the same functionality that
6298 // receivePowerNotification does; it simply provides a richer API for conveying
6299 // more information.
6300 //******************************************************************************
6302 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6303 const OSSymbol
*event
,
6306 IOReturn attempt
= kIOReturnSuccess
;
6307 OSNumber
*newNumber
= NULL
;
6310 return kIOReturnBadArgument
;
6312 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6314 return kIOReturnInternalError
;
6316 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6318 newNumber
->release();
6323 void IOPMrootDomain::setThermalState(OSObject
*value
)
6327 if (gIOPMWorkLoop
->inGate() == false) {
6328 gIOPMWorkLoop
->runAction(
6329 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6335 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6336 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6337 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6341 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6342 const OSSymbol
*event
,
6345 OSDictionary
*thermalsDict
= NULL
;
6346 bool shouldUpdate
= true;
6348 if (!event
|| !value
)
6349 return kIOReturnBadArgument
;
6352 // We reuse featuresDict Lock because it already exists and guards
6353 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6354 // of stepping on that lock.
6355 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6357 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6359 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6360 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6362 thermalsDict
= OSDictionary::withCapacity(1);
6365 if (!thermalsDict
) {
6366 shouldUpdate
= false;
6370 thermalsDict
->setObject (event
, value
);
6372 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6374 thermalsDict
->release();
6378 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6382 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6383 setThermalState(value
);
6385 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6388 return kIOReturnSuccess
;
6391 //******************************************************************************
6392 // receivePowerNotification
6394 // The power controller is notifying us of a hardware-related power management
6395 // event that we must handle. This may be a result of an 'environment' interrupt
6396 // from the power mgt micro.
6397 //******************************************************************************
6399 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6401 pmPowerStateQueue
->submitPowerEvent(
6402 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6403 return kIOReturnSuccess
;
6406 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6408 bool eval_clamshell
= false;
6413 * Local (IOPMrootDomain only) eval clamshell command
6415 if (msg
& kLocalEvalClamshellCommand
)
6417 eval_clamshell
= true;
6423 if (msg
& kIOPMOverTemp
)
6425 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6426 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6430 * Forward DW thermal notification to client, if system is not going to sleep
6432 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6434 DLOG("DarkWake thermal limits message received!\n");
6436 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6442 if (msg
& kIOPMSleepNow
)
6444 privateSleepSystem (kIOPMSleepReasonSoftware
);
6450 if (msg
& kIOPMPowerEmergency
)
6452 lowBatteryCondition
= true;
6453 privateSleepSystem (kIOPMSleepReasonLowPower
);
6459 if (msg
& kIOPMClamshellOpened
)
6461 // Received clamshel open message from clamshell controlling driver
6462 // Update our internal state and tell general interest clients
6463 clamshellClosed
= false;
6464 clamshellExists
= true;
6466 // Don't issue a hid tickle when lid is open and polled on wake
6467 if (msg
& kIOPMSetValue
)
6469 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6474 informCPUStateChange(kInformLid
, 0);
6476 // Tell general interest clients
6477 sendClientClamshellNotification();
6479 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6480 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6481 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6482 if (aborting
) userActivityCount
++;
6483 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6488 * Send the clamshell interest notification since the lid is closing.
6490 if (msg
& kIOPMClamshellClosed
)
6492 // Received clamshel open message from clamshell controlling driver
6493 // Update our internal state and tell general interest clients
6494 clamshellClosed
= true;
6495 clamshellExists
= true;
6498 informCPUStateChange(kInformLid
, 1);
6500 // Tell general interest clients
6501 sendClientClamshellNotification();
6503 // And set eval_clamshell = so we can attempt
6504 eval_clamshell
= true;
6508 * Set Desktop mode (sent from graphics)
6510 * -> reevaluate lid state
6512 if (msg
& kIOPMSetDesktopMode
)
6514 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6515 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6517 sendClientClamshellNotification();
6519 // Re-evaluate the lid state
6520 eval_clamshell
= true;
6524 * AC Adaptor connected
6526 * -> reevaluate lid state
6528 if (msg
& kIOPMSetACAdaptorConnected
)
6530 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6531 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6534 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6536 // Tell BSD if AC is connected
6537 // 0 == external power source; 1 == on battery
6538 post_sys_powersource(acAdaptorConnected
? 0:1);
6540 sendClientClamshellNotification();
6542 // Re-evaluate the lid state
6543 eval_clamshell
= true;
6545 // Lack of AC may have latched a display wrangler tickle.
6546 // This mirrors the hardware's USB wake event latch, where a latched
6547 // USB wake event followed by an AC attach will trigger a full wake.
6548 latchDisplayWranglerTickle( false );
6551 // AC presence will reset the standy timer delay adjustment.
6552 _standbyTimerResetSeconds
= 0;
6554 if (!userIsActive
) {
6555 // Reset userActivityTime when power supply is changed(rdr 13789330)
6556 clock_get_uptime(&userActivityTime
);
6561 * Enable Clamshell (external display disappear)
6563 * -> reevaluate lid state
6565 if (msg
& kIOPMEnableClamshell
)
6567 // Re-evaluate the lid state
6568 // System should sleep on external display disappearance
6569 // in lid closed operation.
6570 if (true == clamshellDisabled
)
6572 eval_clamshell
= true;
6575 clamshellDisabled
= false;
6576 sendClientClamshellNotification();
6580 * Disable Clamshell (external display appeared)
6581 * We don't bother re-evaluating clamshell state. If the system is awake,
6582 * the lid is probably open.
6584 if (msg
& kIOPMDisableClamshell
)
6586 clamshellDisabled
= true;
6587 sendClientClamshellNotification();
6591 * Evaluate clamshell and SLEEP if appropiate
6593 if (eval_clamshell
&& clamshellClosed
)
6595 if (shouldSleepOnClamshellClosed())
6596 privateSleepSystem (kIOPMSleepReasonClamshell
);
6598 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6604 if (msg
& kIOPMPowerButton
)
6606 if (!wranglerAsleep
)
6608 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6609 // Check that power button sleep is enabled
6611 if( kOSBooleanTrue
!= getProperty(pbs
))
6612 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6620 //******************************************************************************
6623 // Evaluate root-domain policy in response to external changes.
6624 //******************************************************************************
6626 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6630 int idleSleepEnabled
: 1;
6631 int idleSleepDisabled
: 1;
6632 int displaySleep
: 1;
6633 int sleepDelayChanged
: 1;
6634 int evaluateDarkWake
: 1;
6635 int adjustPowerState
: 1;
6636 int userBecameInactive
: 1;
6641 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6648 case kStimulusDisplayWranglerSleep
:
6649 if (!wranglerAsleep
)
6651 // first transition to wrangler sleep or lower
6652 wranglerAsleep
= true;
6653 flags
.bit
.displaySleep
= true;
6657 case kStimulusDisplayWranglerWake
:
6658 displayIdleForDemandSleep
= false;
6659 wranglerAsleep
= false;
6662 case kStimulusEnterUserActiveState
:
6663 if (_preventUserActive
)
6665 DLOG("user active dropped\n");
6670 userIsActive
= true;
6671 userWasActive
= true;
6673 // Stay awake after dropping demand for display power on
6674 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6675 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6677 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6678 messageClients(kIOPMMessageUserIsActiveChanged
);
6680 flags
.bit
.idleSleepDisabled
= true;
6683 case kStimulusLeaveUserActiveState
:
6686 userIsActive
= false;
6687 clock_get_uptime(&userBecameInactiveTime
);
6688 flags
.bit
.userBecameInactive
= true;
6690 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6691 messageClients(kIOPMMessageUserIsActiveChanged
);
6695 case kStimulusAggressivenessChanged
:
6697 unsigned long minutesToIdleSleep
= 0;
6698 unsigned long minutesToDisplayDim
= 0;
6699 unsigned long minutesDelta
= 0;
6701 // Fetch latest display and system sleep slider values.
6702 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6703 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6704 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6705 (uint32_t) sleepSlider
,
6706 (uint32_t) minutesToIdleSleep
,
6707 (uint32_t) minutesToDisplayDim
);
6709 DLOG("idle time -> %ld secs (ena %d)\n",
6710 idleSeconds
, (minutesToIdleSleep
!= 0));
6712 if (0x7fffffff == minutesToIdleSleep
)
6713 minutesToIdleSleep
= idleSeconds
;
6715 // How long to wait before sleeping the system once
6716 // the displays turns off is indicated by 'extraSleepDelay'.
6718 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6719 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6720 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6723 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6724 flags
.bit
.idleSleepEnabled
= true;
6726 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6727 flags
.bit
.idleSleepDisabled
= true;
6729 if (((minutesDelta
!= extraSleepDelay
) ||
6730 (userActivityTime
!= userActivityTime_prev
)) &&
6731 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6732 flags
.bit
.sleepDelayChanged
= true;
6734 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6735 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6737 // Reconsider decision to remain in dark wake
6738 flags
.bit
.evaluateDarkWake
= true;
6741 sleepSlider
= minutesToIdleSleep
;
6742 extraSleepDelay
= minutesDelta
;
6743 userActivityTime_prev
= userActivityTime
;
6746 case kStimulusDemandSystemSleep
:
6747 displayIdleForDemandSleep
= true;
6748 if (wrangler
&& wranglerIdleSettings
)
6750 // Request wrangler idle only when demand sleep is triggered
6752 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6754 wrangler
->setProperties(wranglerIdleSettings
);
6755 DLOG("Requested wrangler idle\n");
6758 // arg = sleepReason
6759 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6762 case kStimulusAllowSystemSleepChanged
:
6763 flags
.bit
.adjustPowerState
= true;
6766 case kStimulusDarkWakeActivityTickle
:
6767 // arg == true implies real and not self generated wrangler tickle.
6768 // Update wake type on PM work loop instead of the tickle thread to
6769 // eliminate the possibility of an early tickle clobbering the wake
6770 // type set by the platform driver.
6772 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6774 if (false == wranglerTickled
)
6776 if (latchDisplayWranglerTickle(true))
6778 DLOG("latched tickle\n");
6782 wranglerTickled
= true;
6783 DLOG("Requesting full wake after dark wake activity tickle\n");
6784 requestFullWake( kFullWakeReasonLocalUser
);
6788 case kStimulusDarkWakeEntry
:
6789 case kStimulusDarkWakeReentry
:
6790 // Any system transitions since the last dark wake transition
6791 // will invalid the stimulus.
6793 if (arg
== _systemStateGeneration
)
6795 DLOG("dark wake entry\n");
6796 systemDarkWake
= true;
6798 // Keep wranglerAsleep an invariant when wrangler is absent
6800 wranglerAsleep
= true;
6802 if (kStimulusDarkWakeEntry
== stimulus
)
6804 clock_get_uptime(&userBecameInactiveTime
);
6805 flags
.bit
.evaluateDarkWake
= true;
6808 // Always accelerate disk spindown while in dark wake,
6809 // even if system does not support/allow sleep.
6811 cancelIdleSleepTimer();
6812 setQuickSpinDownTimeout();
6816 case kStimulusDarkWakeEvaluate
:
6819 flags
.bit
.evaluateDarkWake
= true;
6823 case kStimulusNoIdleSleepPreventers
:
6824 flags
.bit
.adjustPowerState
= true;
6827 } /* switch(stimulus) */
6829 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6831 if (darkWakeToSleepASAP
||
6832 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6834 uint32_t newSleepReason
;
6836 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6838 // System was previously in full wake. Sleep reason from
6839 // full to dark already recorded in fullToDarkReason.
6841 if (lowBatteryCondition
)
6842 newSleepReason
= kIOPMSleepReasonLowPower
;
6844 newSleepReason
= fullToDarkReason
;
6848 // In dark wake from system sleep.
6850 if (darkWakeSleepService
)
6851 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6853 newSleepReason
= kIOPMSleepReasonMaintenance
;
6856 if (checkSystemCanSleep(newSleepReason
))
6858 privateSleepSystem(newSleepReason
);
6861 else // non-maintenance (network) dark wake
6863 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
6865 // Release power clamp, and wait for children idle.
6866 adjustPowerState(true);
6870 changePowerStateToPriv(ON_STATE
);
6877 // The rest are irrelevant while system is in dark wake.
6881 if ((flags
.bit
.displaySleep
) &&
6882 (kFullWakeReasonDisplayOn
== fullWakeReason
))
6884 // kIOPMSleepReasonMaintenance?
6885 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
6888 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
6890 bool cancelQuickSpindown
= false;
6892 if (flags
.bit
.sleepDelayChanged
)
6894 // Cancel existing idle sleep timer and quick disk spindown.
6895 // New settings will be applied by the idleSleepEnabled flag
6896 // handler below if idle sleep is enabled.
6898 DLOG("extra sleep timer changed\n");
6899 cancelIdleSleepTimer();
6900 cancelQuickSpindown
= true;
6904 DLOG("user inactive\n");
6907 if (!userIsActive
&& sleepSlider
)
6909 startIdleSleepTimer(getTimeToIdleSleep());
6912 if (cancelQuickSpindown
)
6913 restoreUserSpinDownTimeout();
6916 if (flags
.bit
.idleSleepEnabled
)
6918 DLOG("idle sleep timer enabled\n");
6921 changePowerStateToPriv(ON_STATE
);
6924 startIdleSleepTimer( idleSeconds
);
6929 // Start idle timer if prefs now allow system sleep
6930 // and user is already inactive. Disk spindown is
6931 // accelerated upon timer expiration.
6935 startIdleSleepTimer(getTimeToIdleSleep());
6940 if (flags
.bit
.idleSleepDisabled
)
6942 DLOG("idle sleep timer disabled\n");
6943 cancelIdleSleepTimer();
6944 restoreUserSpinDownTimeout();
6948 if (flags
.bit
.adjustPowerState
)
6950 bool sleepASAP
= false;
6952 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6956 changePowerStateToPriv(ON_STATE
);
6959 // stay awake for at least idleSeconds
6960 startIdleSleepTimer(idleSeconds
);
6963 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6969 adjustPowerState(sleepASAP
);
6973 //******************************************************************************
6976 // Request transition from dark wake to full wake
6977 //******************************************************************************
6979 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
6981 uint32_t options
= 0;
6982 IOService
* pciRoot
= 0;
6983 bool promotion
= false;
6985 // System must be in dark wake and a valid reason for entering full wake
6986 if ((kFullWakeReasonNone
== reason
) ||
6987 (kFullWakeReasonNone
!= fullWakeReason
) ||
6988 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
6993 // Will clear reason upon exit from full wake
6994 fullWakeReason
= reason
;
6996 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
6997 kIOPMSystemCapabilityAudio
);
6999 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7000 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7001 !graphicsSuppressed
)
7003 // Promote to full wake while waking up to dark wake due to tickle.
7004 // PM will hold off notifying the graphics subsystem about system wake
7005 // as late as possible, so if a HID tickle does arrive, graphics can
7006 // power up on this same wake cycle. The latency to power up graphics
7007 // on the next cycle can be huge on some systems. However, once any
7008 // graphics suppression has taken effect, it is too late. All other
7009 // graphics devices must be similarly suppressed. But the delay till
7010 // the following cycle should be short.
7012 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7013 kIOPMSystemCapabilityAudio
);
7015 // Immediately bring up audio and graphics
7016 pciRoot
= pciHostBridgeDriver
;
7017 willEnterFullWake();
7021 // Unsafe to cancel once graphics was powered.
7022 // If system woke from dark wake, the return to sleep can
7023 // be cancelled. "awake -> dark -> sleep" transition
7024 // can be canceled also, during the "dark --> sleep" phase
7025 // *prior* to driver power down.
7026 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7027 _pendingCapability
== 0) {
7028 options
|= kIOPMSyncCancelPowerDown
;
7031 synchronizePowerTree(options
, pciRoot
);
7032 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7034 // IOGraphics doesn't light the display even though graphics is
7035 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7036 // So, do an explicit activity tickle
7038 wrangler
->activityTickle(0,0);
7041 // Log a timestamp for the initial full wake request.
7042 // System may not always honor this full wake request.
7043 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7048 clock_get_uptime(&now
);
7049 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
7050 absolutetime_to_nanoseconds(now
, &nsec
);
7051 MSG("full wake %s (reason %u) %u ms\n",
7052 promotion
? "promotion" : "request",
7053 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7057 //******************************************************************************
7058 // willEnterFullWake
7060 // System will enter full wake from sleep, from dark wake, or from dark
7061 // wake promotion. This function aggregate things that are in common to
7062 // all three full wake transitions.
7064 // Assumptions: fullWakeReason was updated
7065 //******************************************************************************
7067 void IOPMrootDomain::willEnterFullWake( void )
7069 hibernateRetry
= false;
7070 sleepToStandby
= false;
7071 sleepTimerMaintenance
= false;
7073 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7074 kSystemMessageClientLegacyApp
;
7076 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7078 // Initial graphics full power
7079 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7081 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7082 setProperty(gIOPMUserTriggeredFullWakeKey
,
7083 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7084 kOSBooleanTrue
: kOSBooleanFalse
);
7087 IOHibernateSetWakeCapabilities(_pendingCapability
);
7090 IOService::setAdvisoryTickleEnable( true );
7091 tellClients(kIOMessageSystemWillPowerOn
);
7092 preventTransitionToUserActive(false);
7095 //******************************************************************************
7096 // fullWakeDelayedWork
7098 // System has already entered full wake. Invoked by a delayed thread call.
7099 //******************************************************************************
7101 void IOPMrootDomain::fullWakeDelayedWork( void )
7103 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7104 // Not gated, don't modify state
7105 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7106 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7108 receivePowerNotification( kLocalEvalClamshellCommand
);
7113 //******************************************************************************
7114 // evaluateAssertions
7116 //******************************************************************************
7117 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7119 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7121 messageClients(kIOPMMessageDriverAssertionsChanged
);
7123 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7126 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7128 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7129 wrangler
->setIgnoreIdleTimer( value
);
7133 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7134 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7135 if (!assertOnWakeSecs
&& systemWakeTime
) {
7137 clock_usec_t microsecs
;
7138 clock_get_uptime(&now
);
7139 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
7140 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7141 if (assertOnWakeReport
) {
7142 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7143 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7148 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7149 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7151 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7152 updatePreventIdleSleepList(this, true);
7155 DLOG("Driver assertion ReservedBit7 dropped\n");
7156 updatePreventIdleSleepList(this, false);
7164 //******************************************************************************
7167 //******************************************************************************
7169 void IOPMrootDomain::pmStatsRecordEvent(
7171 AbsoluteTime timestamp
)
7173 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7174 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7177 OSData
*publishPMStats
= NULL
;
7179 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7181 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7183 switch (eventIndex
) {
7184 case kIOPMStatsHibernateImageWrite
:
7186 gPMStats
.hibWrite
.start
= nsec
;
7188 gPMStats
.hibWrite
.stop
= nsec
;
7191 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7192 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7195 case kIOPMStatsHibernateImageRead
:
7197 gPMStats
.hibRead
.start
= nsec
;
7199 gPMStats
.hibRead
.stop
= nsec
;
7202 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7203 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7205 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7206 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7207 publishPMStats
->release();
7208 bzero(&gPMStats
, sizeof(gPMStats
));
7215 * Appends a record of the application response to
7216 * IOPMrootDomain::pmStatsAppResponses
7218 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7219 const OSSymbol
*response
,
7225 IOPMPowerStateIndex powerState
)
7227 OSDictionary
*responseDescription
= NULL
;
7228 OSNumber
*delayNum
= NULL
;
7229 OSNumber
*powerCaps
= NULL
;
7230 OSNumber
*pidNum
= NULL
;
7231 OSNumber
*msgNum
= NULL
;
7232 const OSSymbol
*appname
;
7233 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7234 IOPMServiceInterestNotifier
*notify
= 0;
7236 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7238 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7239 notify
->ackTimeoutCnt
++;
7241 notify
->ackTimeoutCnt
= 0;
7245 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7246 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7250 responseDescription
= OSDictionary::withCapacity(5);
7251 if (responseDescription
)
7254 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7257 msgNum
= OSNumber::withNumber(messageType
, 32);
7259 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7263 if (name
&& (strlen(name
) > 0))
7265 appname
= OSSymbol::withCString(name
);
7267 responseDescription
->setObject(_statsNameKey
, appname
);
7272 if (app_pid
!= -1) {
7273 pidNum
= OSNumber::withNumber(app_pid
, 32);
7275 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7280 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7282 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7283 delayNum
->release();
7286 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7287 powerCaps
= OSNumber::withNumber(powerState
, 32);
7289 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7290 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7292 powerState
, delay_ms
);
7297 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7300 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7301 powerCaps
->release();
7304 sleep
= OSSymbol::withCString("Sleep");
7305 wake
= OSSymbol::withCString("Wake");
7306 if (_systemTransitionType
== kSystemTransitionSleep
) {
7307 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7309 else if (_systemTransitionType
== kSystemTransitionWake
) {
7310 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7312 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7313 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7314 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7315 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7316 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7318 if (sleep
) sleep
->release();
7319 if (wake
) wake
->release();
7323 IOLockLock(pmStatsLock
);
7324 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7325 pmStatsAppResponses
->setObject(responseDescription
);
7327 IOLockUnlock(pmStatsLock
);
7329 responseDescription
->release();
7336 // MARK: PMTraceWorker
7338 //******************************************************************************
7339 // TracePoint support
7341 //******************************************************************************
7343 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7344 "IOPMRegisterNVRAMTracePointHandler"
7346 IOReturn
IOPMrootDomain::callPlatformFunction(
7347 const OSSymbol
* functionName
,
7348 bool waitForFunction
,
7349 void * param1
, void * param2
,
7350 void * param3
, void * param4
)
7352 if (pmTracer
&& functionName
&&
7353 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7354 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7356 uint32_t tracePointPhases
, tracePointPCI
;
7357 uint64_t statusCode
;
7359 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7360 pmTracer
->tracePointTarget
= (void *) param2
;
7361 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7362 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7363 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7364 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
7366 MSG("Sleep failure code 0x%08x 0x%08x\n",
7367 tracePointPCI
, tracePointPhases
);
7369 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7370 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7372 return kIOReturnSuccess
;
7375 else if (functionName
&&
7376 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7378 if (gSleepPolicyHandler
)
7379 return kIOReturnExclusiveAccess
;
7381 return kIOReturnBadArgument
;
7382 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7383 gSleepPolicyTarget
= (void *) param2
;
7384 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7385 return kIOReturnSuccess
;
7389 return super::callPlatformFunction(
7390 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7393 void IOPMrootDomain::tracePoint( uint8_t point
)
7395 if (systemBooting
) return;
7397 if (kIOPMTracePointWakeCapabilityClients
== point
)
7398 acceptSystemWakeEvents(false);
7400 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
7401 pmTracer
->tracePoint(point
);
7404 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
7406 if (systemBooting
) return;
7408 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
7409 pmTracer
->tracePoint(point
, data
);
7412 void IOPMrootDomain::traceDetail( uint32_t detail
)
7415 pmTracer
->traceDetail( detail
);
7419 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7422 void **report
= NULL
;
7425 uint32_t *clientCnt
;
7430 if (channel_id
== kAssertDelayChID
) {
7431 report
= &assertOnWakeReport
;
7432 bktCnt
= kAssertDelayBcktCnt
;
7433 bktSize
= kAssertDelayBcktSize
;
7434 clientCnt
= &assertOnWakeClientCnt
;
7436 else if (channel_id
== kSleepDelaysChID
) {
7437 report
= &sleepDelaysReport
;
7438 bktCnt
= kSleepDelaysBcktCnt
;
7439 bktSize
= kSleepDelaysBcktSize
;
7440 clientCnt
= &sleepDelaysClientCnt
;
7445 case kIOReportEnable
:
7452 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7453 *report
= IOMalloc(reportSize
);
7454 if (*report
== NULL
) {
7457 bzero(*report
, reportSize
);
7458 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7459 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7461 if (channel_id
== kAssertDelayChID
)
7462 assertOnWakeSecs
= 0;
7466 case kIOReportDisable
:
7467 if (*clientCnt
== 0) {
7470 if (*clientCnt
== 1)
7472 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7477 if (channel_id
== kAssertDelayChID
)
7478 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7482 case kIOReportGetDimensions
:
7484 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7492 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7493 IOReportConfigureAction action
,
7498 uint64_t configAction
= (uint64_t)action
;
7500 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7501 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7502 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7503 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7504 if (action
!= kIOReportGetDimensions
) continue;
7505 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7507 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7508 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7509 gIOPMWorkLoop
->runAction(
7510 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7511 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7512 (void *)configAction
, (void *)result
);
7516 return super::configureReport(channelList
, action
, result
, destination
);
7519 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7529 if (ch_id
== kAssertDelayChID
) {
7530 report
= &assertOnWakeReport
;
7532 else if (ch_id
== kSleepDelaysChID
) {
7533 report
= &sleepDelaysReport
;
7536 if (*report
== NULL
) {
7537 return kIOReturnNotOpen
;
7540 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7541 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7542 return kIOReturnOverrun
;
7545 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7546 dest
->appendBytes(data2cpy
, size2cpy
);
7548 return kIOReturnSuccess
;
7551 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7552 IOReportUpdateAction action
,
7558 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7559 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7563 if (action
!= kIOReportCopyChannelData
) goto exit
;
7565 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7566 ch_id
= channelList
->channels
[cnt
].channel_id
;
7568 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7569 gIOPMWorkLoop
->runAction(
7570 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7571 (OSObject
*)this, (void *)ch_id
,
7572 (void *)result
, (void *)dest
);
7576 else if ((ch_id
== kSleepCntChID
) ||
7577 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7578 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7582 if (ch_id
== kSleepCntChID
)
7583 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7584 else if (ch_id
== kDarkWkCntChID
)
7585 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7586 else if (ch_id
== kUserWkCntChID
)
7587 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7589 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7590 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7591 dest
->appendBytes(data2cpy
, size2cpy
);
7595 return super::updateReport(channelList
, action
, result
, destination
);
7599 //******************************************************************************
7600 // PMTraceWorker Class
7602 //******************************************************************************
7605 #define super OSObject
7606 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7608 #define kPMBestGuessPCIDevicesCount 25
7609 #define kPMMaxRTCBitfieldSize 32
7611 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7615 me
= OSTypeAlloc( PMTraceWorker
);
7616 if (!me
|| !me
->init())
7621 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7623 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7624 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7625 // this dictionary lazily.
7627 me
->pciDeviceBitMappings
= NULL
;
7628 me
->pciMappingLock
= IOLockAlloc();
7629 me
->tracePhase
= kIOPMTracePointSystemUp
;
7630 me
->loginWindowPhase
= 0;
7631 me
->traceData32
= 0;
7635 void PMTraceWorker::RTC_TRACE(void)
7637 if (tracePointHandler
&& tracePointTarget
)
7641 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
7644 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7645 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7649 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7651 const OSSymbol
* deviceName
;
7654 IOLockLock(pciMappingLock
);
7656 if (!pciDeviceBitMappings
)
7658 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7659 if (!pciDeviceBitMappings
)
7663 // Check for bitmask overflow.
7664 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7667 if ((deviceName
= pciDevice
->copyName()) &&
7668 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7669 pciDeviceBitMappings
->setObject(deviceName
))
7671 index
= pciDeviceBitMappings
->getCount() - 1;
7672 _LOG("PMTrace PCI array: set object %s => %d\n",
7673 deviceName
->getCStringNoCopy(), index
);
7676 deviceName
->release();
7677 if (!addedToRegistry
&& (index
>= 0))
7678 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7681 IOLockUnlock(pciMappingLock
);
7685 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7688 if (pciDeviceBitMappings
)
7690 IOLockLock(pciMappingLock
);
7691 ok
= pciDeviceBitMappings
->serialize(s
);
7692 IOLockUnlock(pciMappingLock
);
7697 void PMTraceWorker::tracePoint(uint8_t phase
)
7699 // clear trace detail when phase begins
7700 if (tracePhase
!= phase
)
7705 DLOG("trace point 0x%02x\n", tracePhase
);
7709 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
7711 // clear trace detail when phase begins
7712 if (tracePhase
!= phase
)
7718 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
7722 void PMTraceWorker::traceDetail(uint32_t detail
)
7724 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
7727 traceData32
= detail
;
7728 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7733 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
7735 loginWindowPhase
= phase
;
7737 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
7741 void PMTraceWorker::tracePCIPowerChange(
7742 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7745 uint32_t expectedFlag
;
7747 // Ignore PCI changes outside of system sleep/wake.
7748 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7749 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7752 // Only record the WillChange transition when going to sleep,
7753 // and the DidChange on the way up.
7754 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7755 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7756 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7757 if (changeFlags
!= expectedFlag
)
7760 // Mark this device off in our bitfield
7761 if (bitNum
< kPMMaxRTCBitfieldSize
)
7763 bitMask
= (1 << bitNum
);
7765 if (kPowerChangeStart
== type
)
7767 traceData32
|= bitMask
;
7768 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7769 service
->getName(), bitNum
, bitMask
, traceData32
);
7773 traceData32
&= ~bitMask
;
7774 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7775 service
->getName(), bitNum
, bitMask
, traceData32
);
7778 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7783 uint64_t PMTraceWorker::getPMStatusCode( )
7785 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
<< 24) |
7786 (loginWindowPhase
<< 16) | (traceData8
<< 8));
7791 // MARK: PMHaltWorker
7793 //******************************************************************************
7794 // PMHaltWorker Class
7796 //******************************************************************************
7798 PMHaltWorker
* PMHaltWorker::worker( void )
7804 me
= OSTypeAlloc( PMHaltWorker
);
7805 if (!me
|| !me
->init())
7808 me
->lock
= IOLockAlloc();
7812 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
7813 me
->retain(); // thread holds extra retain
7814 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
7819 thread_deallocate(thread
);
7824 if (me
) me
->release();
7828 void PMHaltWorker::free( void )
7830 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7836 return OSObject::free();
7839 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
7841 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
7843 IOLockLock( gPMHaltLock
);
7845 me
->depth
= gPMHaltDepth
;
7846 IOLockUnlock( gPMHaltLock
);
7848 while (me
->depth
>= 0)
7850 PMHaltWorker::work( me
);
7852 IOLockLock( gPMHaltLock
);
7853 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
7855 // This is the last thread to finish work on this level,
7856 // inform everyone to start working on next lower level.
7858 me
->depth
= gPMHaltDepth
;
7859 gPMHaltIdleCount
= 0;
7860 thread_wakeup((event_t
) &gPMHaltIdleCount
);
7864 // One or more threads are still working on this level,
7865 // this thread must wait.
7866 me
->depth
= gPMHaltDepth
- 1;
7868 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
7869 } while (me
->depth
!= gPMHaltDepth
);
7871 IOLockUnlock( gPMHaltLock
);
7874 // No more work to do, terminate thread
7875 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
7876 thread_wakeup( &gPMHaltDepth
);
7880 void PMHaltWorker::work( PMHaltWorker
* me
)
7882 IOService
* service
;
7884 AbsoluteTime startTime
;
7893 // Claim an unit of work from the shared pool
7894 IOLockLock( gPMHaltLock
);
7895 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7898 service
= (IOService
*)inner
->getAnyObject();
7902 inner
->removeObject(service
);
7905 IOLockUnlock( gPMHaltLock
);
7907 break; // no more work at this depth
7909 clock_get_uptime(&startTime
);
7911 if (!service
->isInactive() &&
7912 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7914 IOLockLock(me
->lock
);
7915 me
->startTime
= startTime
;
7916 me
->service
= service
;
7917 me
->timeout
= false;
7918 IOLockUnlock(me
->lock
);
7920 service
->systemWillShutdown( gPMHaltMessageType
);
7922 // Wait for driver acknowledgement
7923 IOLockLock(me
->lock
);
7924 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7926 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7929 timeout
= me
->timeout
;
7930 IOLockUnlock(me
->lock
);
7933 deltaTime
= computeDeltaTimeMS(&startTime
);
7934 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7935 (gIOKitDebug
& kIOLogPMRootDomain
))
7937 LOG("%s driver %s (0x%llx) took %u ms\n",
7938 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
7939 "PowerOff" : "Restart",
7940 service
->getName(), service
->getRegistryEntryID(),
7941 (uint32_t) deltaTime
);
7949 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7952 AbsoluteTime startTime
;
7953 AbsoluteTime endTime
;
7957 IOLockLock(me
->lock
);
7958 if (me
->service
&& !me
->timeout
)
7960 startTime
= me
->startTime
;
7962 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7964 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7965 absolutetime_to_nanoseconds(endTime
, &nano
);
7967 if (nano
> 3000000000ULL)
7970 MSG("%s still waiting on %s\n",
7971 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
7972 "PowerOff" : "Restart",
7973 me
->service
->getName());
7976 IOLockUnlock(me
->lock
);
7979 //******************************************************************************
7980 // acknowledgeSystemWillShutdown
7982 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7983 //******************************************************************************
7985 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7987 PMHaltWorker
* worker
;
7993 //DLOG("%s acknowledged\n", from->getName());
7994 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7997 worker
= (PMHaltWorker
*) prop
;
7998 IOLockLock(worker
->lock
);
7999 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8000 thread_wakeup((event_t
) worker
);
8001 IOLockUnlock(worker
->lock
);
8006 DLOG("%s acknowledged without worker property\n",
8012 //******************************************************************************
8013 // notifySystemShutdown
8015 // Notify all objects in PM tree that system will shutdown or restart
8016 //******************************************************************************
8019 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8021 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8022 IORegistryIterator
* iter
;
8023 IORegistryEntry
* entry
;
8026 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8027 AbsoluteTime deadline
;
8028 unsigned int totalNodes
= 0;
8030 unsigned int rootDepth
;
8031 unsigned int numWorkers
;
8037 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8039 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8041 // Iterate the entire PM tree starting from root
8043 rootDepth
= root
->getDepth( gIOPowerPlane
);
8044 if (!rootDepth
) goto done
;
8046 // debug - for repeated test runs
8047 while (PMHaltWorker::metaClass
->getInstanceCount())
8052 gPMHaltArray
= OSArray::withCapacity(40);
8053 if (!gPMHaltArray
) goto done
;
8056 gPMHaltArray
->flushCollection();
8060 gPMHaltLock
= IOLockAlloc();
8061 if (!gPMHaltLock
) goto done
;
8064 if (!gPMHaltClientAcknowledgeKey
)
8066 gPMHaltClientAcknowledgeKey
=
8067 OSSymbol::withCStringNoCopy("PMShutdown");
8068 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8071 gPMHaltMessageType
= messageType
;
8073 // Depth-first walk of PM plane
8075 iter
= IORegistryIterator::iterateOver(
8076 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8080 while ((entry
= iter
->getNextObject()))
8082 node
= OSDynamicCast(IOService
, entry
);
8087 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8090 depth
= node
->getDepth( gIOPowerPlane
);
8091 if (depth
<= rootDepth
)
8096 // adjust to zero based depth
8097 depth
-= (rootDepth
+ 1);
8099 // gPMHaltArray is an array of containers, each container
8100 // refers to nodes with the same depth.
8102 count
= gPMHaltArray
->getCount();
8103 while (depth
>= count
)
8105 // expand array and insert placeholders
8106 gPMHaltArray
->setObject(PLACEHOLDER
);
8109 count
= gPMHaltArray
->getCount();
8112 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8113 if (inner
== PLACEHOLDER
)
8115 inner
= OSSet::withCapacity(40);
8118 gPMHaltArray
->replaceObject(depth
, inner
);
8123 // PM nodes that appear more than once in the tree will have
8124 // the same depth, OSSet will refuse to add the node twice.
8126 ok
= inner
->setObject(node
);
8129 DLOG("Skipped PM node %s\n", node
->getName());
8135 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8138 if (inner
!= PLACEHOLDER
)
8139 count
= inner
->getCount();
8140 DLOG("Nodes at depth %u = %u\n", i
, count
);
8143 // strip placeholders (not all depths are populated)
8145 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8147 if (inner
== PLACEHOLDER
)
8149 gPMHaltArray
->removeObject(i
);
8152 count
= inner
->getCount();
8153 if (count
> numWorkers
)
8155 totalNodes
+= count
;
8159 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8162 gPMHaltBusyCount
= 0;
8163 gPMHaltIdleCount
= 0;
8164 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8166 // Create multiple workers (and threads)
8168 if (numWorkers
> kPMHaltMaxWorkers
)
8169 numWorkers
= kPMHaltMaxWorkers
;
8171 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8172 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8174 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8175 workers
[i
] = PMHaltWorker::worker();
8177 // Wait for workers to exhaust all available work
8179 IOLockLock(gPMHaltLock
);
8180 while (gPMHaltDepth
>= 0)
8182 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8184 waitResult
= IOLockSleepDeadline(
8185 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8186 if (THREAD_TIMED_OUT
== waitResult
)
8189 clock_get_uptime(&now
);
8191 IOLockUnlock(gPMHaltLock
);
8192 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8195 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8197 IOLockLock(gPMHaltLock
);
8200 IOLockUnlock(gPMHaltLock
);
8202 // Release all workers
8204 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8207 workers
[i
]->release();
8208 // worker also retained by it's own thread
8212 DLOG("%s done\n", __FUNCTION__
);
8217 // MARK: Kernel Assertion
8219 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8221 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8222 IOPMDriverAssertionType whichAssertionBits
,
8223 IOPMDriverAssertionLevel assertionLevel
,
8224 IOService
*ownerService
,
8225 const char *ownerDescription
)
8228 IOPMDriverAssertionID newAssertion
;
8233 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8235 if (kIOReturnSuccess
== ret
)
8236 return newAssertion
;
8241 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8244 return kIOReturnInternalError
;
8246 return pmAssertions
->releaseAssertion(releaseAssertion
);
8250 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8251 IOPMDriverAssertionID assertionID
,
8252 IOPMDriverAssertionLevel assertionLevel
)
8254 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8257 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8259 IOPMDriverAssertionType sysLevels
;
8261 if (!pmAssertions
|| whichAssertion
== 0)
8262 return kIOPMDriverAssertionLevelOff
;
8264 sysLevels
= pmAssertions
->getActivatedAssertions();
8266 // Check that every bit set in argument 'whichAssertion' is asserted
8267 // in the aggregate bits.
8268 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8269 return kIOPMDriverAssertionLevelOn
;
8271 return kIOPMDriverAssertionLevelOff
;
8274 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8277 return kIOReturnNotFound
;
8279 return pmAssertions
->setUserAssertionLevels(inLevels
);
8282 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8286 pmAssertions
->publishProperties();
8288 return( IOService::serializeProperties(s
) );
8291 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8293 OSObject
*obj
= NULL
;
8294 obj
= IOService::copyProperty(aKey
);
8296 if (obj
) return obj
;
8298 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8299 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8300 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8301 return kOSBooleanTrue
;
8303 return kOSBooleanFalse
;
8307 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8308 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8309 if (swd_flags
& SWD_VALID_LOGS
)
8310 return kOSBooleanTrue
;
8312 return kOSBooleanFalse
;
8317 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8318 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8319 * issued by DisplayWrangler on darkwake.
8321 if (!strcmp(aKey
, "DesktopMode")) {
8323 return kOSBooleanTrue
;
8325 return kOSBooleanFalse
;
8327 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8328 if (displayIdleForDemandSleep
) {
8329 return kOSBooleanTrue
;
8332 return kOSBooleanFalse
;
8336 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8338 OSArray
* array
= 0;
8340 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8341 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8342 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8343 collection
->release();
8350 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8352 OSArray
* array
= 0;
8353 IOLockLock(pmStatsLock
);
8354 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8355 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8356 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8357 collection
->release();
8359 pmStatsAppResponses
->flushCollection();
8361 IOLockUnlock(pmStatsLock
);
8365 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8367 OSArray
*idleSleepList
= NULL
;
8368 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8369 return idleSleepList
;
8372 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8374 OSArray
*systemSleepList
= NULL
;
8375 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8376 return systemSleepList
;
8383 // MARK: Wake Event Reporting
8385 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8388 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8392 //******************************************************************************
8393 // acceptSystemWakeEvents
8395 // Private control for the acceptance of driver wake event claims.
8396 //******************************************************************************
8398 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8400 bool logWakeReason
= false;
8405 gWakeReasonString
[0] = '\0';
8406 if (!_systemWakeEventsArray
)
8407 _systemWakeEventsArray
= OSArray::withCapacity(4);
8408 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8409 _systemWakeEventsArray
->flushCollection();
8413 _acceptSystemWakeEvents
= false;
8418 MSG("system wake events:%s\n", gWakeReasonString
);
8421 //******************************************************************************
8422 // claimSystemWakeEvent
8424 // For a driver to claim a device is the source/conduit of a system wake event.
8425 //******************************************************************************
8427 void IOPMrootDomain::claimSystemWakeEvent(
8430 const char * reason
,
8431 OSObject
* details
)
8433 const OSSymbol
* deviceName
= 0;
8434 OSNumber
* deviceRegId
= 0;
8435 OSNumber
* claimTime
= 0;
8436 OSData
* flagsData
= 0;
8437 OSString
* reasonString
= 0;
8438 OSDictionary
* d
= 0;
8442 pmEventTimeStamp(×tamp
);
8444 if (!device
|| !reason
) return;
8446 deviceName
= device
->copyName(gIOServicePlane
);
8447 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8448 claimTime
= OSNumber::withNumber(timestamp
, 64);
8449 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8450 reasonString
= OSString::withCString(reason
);
8451 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8452 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8455 d
->setObject(gIONameKey
, deviceName
);
8456 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8457 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8458 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8459 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8461 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8464 if (!gWakeReasonSysctlRegistered
)
8466 // Lazy registration until the platform driver stops registering
8468 gWakeReasonSysctlRegistered
= true;
8470 if (_acceptSystemWakeEvents
)
8472 ok
= _systemWakeEventsArray
->setObject(d
);
8473 if (gWakeReasonString
[0] != '\0')
8474 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8475 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8480 if (deviceName
) deviceName
->release();
8481 if (deviceRegId
) deviceRegId
->release();
8482 if (claimTime
) claimTime
->release();
8483 if (flagsData
) flagsData
->release();
8484 if (reasonString
) reasonString
->release();
8485 if (d
) d
->release();
8488 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8491 // MARK: PMSettingHandle
8493 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8495 void PMSettingHandle::free( void )
8499 pmso
->clientHandleFreed();
8508 // MARK: PMSettingObject
8511 #define super OSObject
8512 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8515 * Static constructor/initializer for PMSettingObject
8517 PMSettingObject
*PMSettingObject::pmSettingObject(
8518 IOPMrootDomain
*parent_arg
,
8519 IOPMSettingControllerCallback handler_arg
,
8520 OSObject
*target_arg
,
8521 uintptr_t refcon_arg
,
8522 uint32_t supportedPowerSources
,
8523 const OSSymbol
* settings
[],
8524 OSObject
**handle_obj
)
8526 uint32_t settingCount
= 0;
8527 PMSettingObject
*pmso
= 0;
8528 PMSettingHandle
*pmsh
= 0;
8530 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8533 // count OSSymbol entries in NULL terminated settings array
8534 while (settings
[settingCount
]) {
8537 if (0 == settingCount
)
8540 pmso
= new PMSettingObject
;
8541 if (!pmso
|| !pmso
->init())
8544 pmsh
= new PMSettingHandle
;
8545 if (!pmsh
|| !pmsh
->init())
8548 queue_init(&pmso
->calloutQueue
);
8549 pmso
->parent
= parent_arg
;
8550 pmso
->func
= handler_arg
;
8551 pmso
->target
= target_arg
;
8552 pmso
->refcon
= refcon_arg
;
8553 pmso
->settingCount
= settingCount
;
8555 pmso
->retain(); // handle holds a retain on pmso
8559 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8560 if (pmso
->publishedFeatureID
) {
8561 for (unsigned int i
=0; i
<settingCount
; i
++) {
8562 // Since there is now at least one listener to this setting, publish
8563 // PM root domain support for it.
8564 parent_arg
->publishPMSetting( settings
[i
],
8565 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8573 if (pmso
) pmso
->release();
8574 if (pmsh
) pmsh
->release();
8578 void PMSettingObject::free( void )
8580 if (publishedFeatureID
) {
8581 for (uint32_t i
=0; i
<settingCount
; i
++) {
8582 if (publishedFeatureID
[i
]) {
8583 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8587 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8593 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8595 (*func
)(target
, type
, object
, refcon
);
8598 void PMSettingObject::clientHandleFreed( void )
8600 parent
->deregisterPMSettingObject(this);
8604 // MARK: PMAssertionsTracker
8606 //*********************************************************************************
8607 //*********************************************************************************
8608 //*********************************************************************************
8609 // class PMAssertionsTracker Implementation
8611 #define kAssertUniqueIDStart 500
8613 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8615 PMAssertionsTracker
*myself
;
8617 myself
= new PMAssertionsTracker
;
8621 myself
->owner
= rootDomain
;
8622 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8623 myself
->assertionsArray
= OSArray::withCapacity(5);
8624 myself
->assertionsKernel
= 0;
8625 myself
->assertionsUser
= 0;
8626 myself
->assertionsCombined
= 0;
8627 myself
->assertionsArrayLock
= IOLockAlloc();
8628 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8630 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8638 * - Update assertionsKernel to reflect the state of all
8639 * assertions in the kernel.
8640 * - Update assertionsCombined to reflect both kernel & user space.
8642 void PMAssertionsTracker::tabulate(void)
8646 PMAssertStruct
*_a
= NULL
;
8649 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8650 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8654 assertionsKernel
= 0;
8655 assertionsCombined
= 0;
8657 if (!assertionsArray
)
8660 if ((count
= assertionsArray
->getCount()))
8662 for (i
=0; i
<count
; i
++)
8664 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8667 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8668 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8669 assertionsKernel
|= _a
->assertionBits
;
8674 tabulateProducerCount
++;
8675 assertionsCombined
= assertionsKernel
| assertionsUser
;
8677 if ((assertionsKernel
!= oldKernel
) ||
8678 (assertionsCombined
!= oldCombined
))
8680 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8684 void PMAssertionsTracker::publishProperties( void )
8686 OSArray
*assertionsSummary
= NULL
;
8688 if (tabulateConsumerCount
!= tabulateProducerCount
)
8690 IOLockLock(assertionsArrayLock
);
8692 tabulateConsumerCount
= tabulateProducerCount
;
8694 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8696 assertionsSummary
= copyAssertionsArray();
8697 if (assertionsSummary
)
8699 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8700 assertionsSummary
->release();
8704 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8707 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8709 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8711 IOLockUnlock(assertionsArrayLock
);
8715 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8717 PMAssertStruct
*_a
= NULL
;
8724 && (count
= assertionsArray
->getCount()))
8726 for (i
=0; i
<count
; i
++)
8728 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8731 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8732 if (_a
&& (_id
== _a
->id
)) {
8749 /* PMAssertionsTracker::handleCreateAssertion
8750 * Perform assertion work on the PM workloop. Do not call directly.
8752 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8758 IOLockLock(assertionsArrayLock
);
8759 assertionsArray
->setObject(newAssertion
);
8760 IOLockUnlock(assertionsArrayLock
);
8761 newAssertion
->release();
8765 return kIOReturnSuccess
;
8768 /* PMAssertionsTracker::createAssertion
8769 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8772 IOReturn
PMAssertionsTracker::createAssertion(
8773 IOPMDriverAssertionType which
,
8774 IOPMDriverAssertionLevel level
,
8775 IOService
*serviceID
,
8776 const char *whoItIs
,
8777 IOPMDriverAssertionID
*outID
)
8779 OSData
*dataStore
= NULL
;
8780 PMAssertStruct track
;
8782 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8783 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8784 track
.level
= level
;
8785 track
.assertionBits
= which
;
8786 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8787 track
.ownerService
= serviceID
;
8788 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8789 track
.modifiedTime
= 0;
8790 pmEventTimeStamp(&track
.createdTime
);
8792 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8795 if (track
.ownerString
)
8796 track
.ownerString
->release();
8797 return kIOReturnNoMemory
;
8802 if (owner
&& owner
->pmPowerStateQueue
) {
8803 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8806 return kIOReturnSuccess
;
8809 /* PMAssertionsTracker::handleReleaseAssertion
8810 * Runs in PM workloop. Do not call directly.
8812 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8813 IOPMDriverAssertionID _id
)
8818 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8821 return kIOReturnNotFound
;
8823 IOLockLock(assertionsArrayLock
);
8824 if (assertStruct
->ownerString
)
8825 assertStruct
->ownerString
->release();
8827 assertionsArray
->removeObject(index
);
8828 IOLockUnlock(assertionsArrayLock
);
8831 return kIOReturnSuccess
;
8834 /* PMAssertionsTracker::releaseAssertion
8835 * Releases an assertion and affects system behavior if appropiate.
8836 * Actual work happens on PM workloop.
8838 IOReturn
PMAssertionsTracker::releaseAssertion(
8839 IOPMDriverAssertionID _id
)
8841 if (owner
&& owner
->pmPowerStateQueue
) {
8842 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8844 return kIOReturnSuccess
;
8847 /* PMAssertionsTracker::handleSetAssertionLevel
8848 * Runs in PM workloop. Do not call directly.
8850 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8851 IOPMDriverAssertionID _id
,
8852 IOPMDriverAssertionLevel _level
)
8854 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8858 if (!assertStruct
) {
8859 return kIOReturnNotFound
;
8862 IOLockLock(assertionsArrayLock
);
8863 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8864 assertStruct
->level
= _level
;
8865 IOLockUnlock(assertionsArrayLock
);
8868 return kIOReturnSuccess
;
8871 /* PMAssertionsTracker::setAssertionLevel
8873 IOReturn
PMAssertionsTracker::setAssertionLevel(
8874 IOPMDriverAssertionID _id
,
8875 IOPMDriverAssertionLevel _level
)
8877 if (owner
&& owner
->pmPowerStateQueue
) {
8878 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8879 (void *)(uintptr_t)_level
, _id
);
8882 return kIOReturnSuccess
;
8885 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8887 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8891 if (new_user_levels
!= assertionsUser
)
8893 assertionsUser
= new_user_levels
;
8894 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8898 return kIOReturnSuccess
;
8901 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8902 IOPMDriverAssertionType new_user_levels
)
8904 if (gIOPMWorkLoop
) {
8905 gIOPMWorkLoop
->runAction(
8906 OSMemberFunctionCast(
8909 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8911 (void *) &new_user_levels
, 0, 0, 0);
8914 return kIOReturnSuccess
;
8918 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8922 OSArray
*outArray
= NULL
;
8924 if (!assertionsArray
||
8925 (0 == (count
= assertionsArray
->getCount())) ||
8926 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8931 for (i
=0; i
<count
; i
++)
8933 PMAssertStruct
*_a
= NULL
;
8935 OSDictionary
*details
= NULL
;
8937 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8938 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8940 OSNumber
*_n
= NULL
;
8942 details
= OSDictionary::withCapacity(7);
8946 outArray
->setObject(details
);
8949 _n
= OSNumber::withNumber(_a
->id
, 64);
8951 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8954 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8956 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8959 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8961 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8964 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
8966 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
8969 _n
= OSNumber::withNumber(_a
->level
, 64);
8971 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8974 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8976 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8980 if (_a
->ownerString
) {
8981 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8990 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8992 return assertionsCombined
;
8995 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8996 IOPMDriverAssertionType type
)
8998 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9000 return kIOPMDriverAssertionLevelOn
;
9002 return kIOPMDriverAssertionLevelOff
;
9006 //*********************************************************************************
9007 //*********************************************************************************
9008 //*********************************************************************************
9011 static void pmEventTimeStamp(uint64_t *recordTS
)
9019 // We assume tsec fits into 32 bits; 32 bits holds enough
9020 // seconds for 136 years since the epoch in 1970.
9021 clock_get_calendar_microtime(&tsec
, &tusec
);
9024 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9026 *recordTS
|= (uint32_t)tusec
;
9027 *recordTS
|= ((uint64_t)tsec
<< 32);
9033 // MARK: IORootParent
9035 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9037 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9039 // The reason that root domain needs a root parent is to facilitate demand
9040 // sleep, since a power change from the root parent cannot be vetoed.
9042 // The above statement is no longer true since root domain now performs
9043 // demand sleep using overrides. But root parent remains to avoid changing
9044 // the power tree stacking. Root parent is parked at the max power state.
9047 static IOPMPowerState patriarchPowerStates
[2] =
9049 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9050 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9053 void IORootParent::initialize( void )
9057 bool IORootParent::start( IOService
* nub
)
9059 IOService::start(nub
);
9060 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9062 registerPowerDriver(this, patriarchPowerStates
, 2);
9067 void IORootParent::shutDownSystem( void )
9071 void IORootParent::restartSystem( void )
9075 void IORootParent::sleepSystem( void )
9079 void IORootParent::dozeSystem( void )
9083 void IORootParent::sleepToDoze( void )
9087 void IORootParent::wakeSystem( void )
9091 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9093 return (IOService::copyProperty(aKey
));
9097 #if defined(__i386__) || defined(__x86_64__)
9098 IOReturn
IOPMrootDomain::restartWithStackshot()
9100 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9101 return kIOReturnError
;
9103 takeStackshot(true, true, false);
9105 return kIOReturnSuccess
;
9108 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9110 takeStackshot(wdogTrigger
, false, false);
9113 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9115 swd_hdr
* hdr
= NULL
;
9117 uint32_t wdog_panic
= 0;
9124 uint32_t bytesRemaining
;
9126 OSString
* UUIDstring
= NULL
;
9128 IOMemoryMap
* logBufMap
= NULL
;
9130 swd_stackshot_hdr
*stackshotHdr
= NULL
;
9133 uint32_t initialStackSize
;
9136 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9137 _systemTransitionType
!= kSystemTransitionWake
)
9140 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9145 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
9146 (wdog_panic
== 1)) {
9147 // If boot-arg is set to panic on sleep/wake hang, call panic
9148 panic("Sleep/Wake hang detected\n");
9151 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9152 // If current boot is due to this watch dog trigger restart in previous boot,
9153 // then don't trigger again until at least 1 successful sleep & wake.
9154 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9155 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9156 PEHaltRestart(kPEHaltCPU
);
9164 if (gSpinDumpBufferFull
)
9166 if (swd_spindump_buffer
== NULL
) {
9167 sleepWakeDebugSpinDumpMemAlloc();
9168 if (swd_spindump_buffer
== NULL
) return;
9171 bufSize
= SWD_SPINDUMP_SIZE
;
9172 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9174 if (sleepWakeDebugIsWdogEnabled() == false)
9177 if (swd_buffer
== NULL
) {
9178 sleepWakeDebugMemAlloc();
9179 if (swd_buffer
== NULL
) return;
9182 bufSize
= SWD_BUF_SIZE
;
9183 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9186 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9190 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9192 hdr
= (swd_hdr
*)swd_buffer
;
9193 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9194 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9196 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9197 const char *str
= UUIDstring
->getCStringNoCopy();
9198 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9201 DLOG("Data for current UUID already exists\n");
9206 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9207 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9209 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9210 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9212 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9214 while (bytesRemaining
> sizeof(swd_stackshot_hdr
)) {
9216 stackshotHdr
= (swd_stackshot_hdr
*)dstAddr
;
9217 stackshotHdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
9218 stackshotHdr
->size
= 0;
9219 bytesRemaining
-= sizeof(swd_stackshot_hdr
);
9220 dstAddr
+= sizeof(swd_stackshot_hdr
);
9222 if (isOSXWatchdog
) {
9224 size
= bytesRemaining
;
9225 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
;
9227 else if (cnt
== 0) {
9229 * Take stackshot of all process on first sample. Size is restricted
9230 * to SWD_INITIAL_STACK_SIZE
9233 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9234 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY
;
9237 /* Take sample of kernel threads only */
9239 size
= bytesRemaining
;
9243 stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, &stackshotHdr
->size
);
9245 dstAddr
+= stackshotHdr
->size
;
9246 bytesRemaining
-= stackshotHdr
->size
;
9248 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt
, stackshotHdr
->size
, bytesRemaining
);
9249 if ((stackshotHdr
->size
== 0) || (++cnt
== 10))
9251 IOSleep(10); // 10 ms
9254 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9257 memset(hdr
->cps
, 0x20, sizeof(hdr
->cps
));
9258 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "\ncps: %d", ((IOService
*)this)->getPowerState());
9259 code
= pmTracer
->getPMStatusCode();
9260 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9261 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9262 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9263 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9265 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9266 gRootDomain
->swd_lock
= 0;
9267 gSpinDumpBufferFull
= true;
9270 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9273 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9274 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9275 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9276 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9277 len
= sizeof(addr64_t
)*3;
9278 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9279 data
[0], data
[1], data
[2]);
9281 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9283 DLOG("Failed to update nvram boot-args\n");
9289 gRootDomain
->swd_lock
= 0;
9292 IOLog("Restarting to collect Sleep wake debug logs\n");
9293 PEHaltRestart(kPERestartCPU
);
9296 logBufMap
= sleepWakeDebugRetrieve();
9298 sleepWakeDebugDumpFromMem(logBufMap
);
9299 logBufMap
->release();
9305 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9307 vm_size_t size
= SWD_BUF_SIZE
;
9309 swd_hdr
*hdr
= NULL
;
9311 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9314 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9317 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9320 // Try allocating above 4GB. If that fails, try at 2GB
9321 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9322 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9323 size
, 0xFFFFFFFF00000000ULL
);
9325 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9326 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9327 size
, 0xFFFFFFFF10000000ULL
);
9330 if (memDesc
== NULL
)
9332 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9337 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9338 memset(hdr
, 0, sizeof(swd_hdr
));
9340 hdr
->signature
= SWD_HDR_SIGNATURE
;
9341 hdr
->alloc_size
= size
;
9343 hdr
->spindump_offset
= sizeof(swd_hdr
);
9344 swd_buffer
= (void *)hdr
;
9345 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9348 gRootDomain
->swd_lock
= 0;
9351 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9353 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9355 swd_hdr
*hdr
= NULL
;
9357 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9359 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9362 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9363 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9366 if (memDesc
== NULL
)
9368 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9373 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9374 memset(hdr
, 0, sizeof(swd_hdr
));
9376 hdr
->signature
= SWD_HDR_SIGNATURE
;
9377 hdr
->alloc_size
= size
;
9379 hdr
->spindump_offset
= sizeof(swd_hdr
);
9380 swd_spindump_buffer
= (void *)hdr
;
9383 gRootDomain
->swd_lock
= 0;
9386 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9388 swd_flags
|= SWD_WDOG_ENABLED
;
9390 sleepWakeDebugMemAlloc();
9393 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9395 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9396 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9399 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9401 swd_hdr
*hdr
= NULL
;
9402 errno_t error
= EIO
;
9404 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9405 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9407 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9408 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9412 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9413 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9414 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9416 gSpinDumpBufferFull
= false;
9420 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9422 struct vnode
*vp
= NULL
;
9423 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9424 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9425 struct vnode_attr va
;
9426 errno_t error
= EIO
;
9428 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9429 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9431 IOLog("Failed to open the file %s\n", name
);
9435 VATTR_WANTED(&va
, va_nlink
);
9436 /* Don't dump to non-regular files or files with links. */
9437 if (vp
->v_type
!= VREG
||
9438 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9439 IOLog("Bailing as this is not a regular file\n");
9443 VATTR_SET(&va
, va_data_size
, 0);
9444 vnode_setattr(vp
, &va
, ctx
);
9447 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9448 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9450 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9452 DLOG("Saved %d bytes to file %s\n",len
, name
);
9455 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9456 if (ctx
) vfs_context_rele(ctx
);
9462 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9463 struct vnode
*srcVp
,
9464 vfs_context_t srcCtx
,
9465 char *tmpBuf
, uint64_t tmpBufSize
,
9467 const char *dstFname
,
9471 struct vnode
*vp
= NULL
;
9472 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9473 struct vnode_attr va
;
9474 errno_t error
= EIO
;
9475 uint64_t bytesToRead
, bytesToWrite
;
9476 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9477 uint32_t newcrc
= 0;
9479 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9480 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9482 DLOG("Failed to open the file %s\n", dstFname
);
9486 VATTR_WANTED(&va
, va_nlink
);
9487 /* Don't dump to non-regular files or files with links. */
9488 if (vp
->v_type
!= VREG
||
9489 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9490 DLOG("Bailing as this is not a regular file\n");
9494 VATTR_SET(&va
, va_data_size
, 0);
9495 vnode_setattr(vp
, &va
, ctx
);
9497 writeFileOffset
= 0;
9499 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9500 readFileOffset
= trunc_page(srcOffset
);
9502 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9503 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9504 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9505 vfs_context_ucred(srcCtx
), (int *) 0,
9506 vfs_context_proc(srcCtx
));
9508 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9512 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9513 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9514 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9517 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9519 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9520 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9521 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9522 vfs_context_ucred(ctx
), (int *) 0,
9523 vfs_context_proc(ctx
));
9525 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9529 writeFileOffset
+= bytesToWrite
;
9530 numBytes
-= bytesToWrite
;
9531 srcOffset
+= bytesToWrite
;
9534 if (crc
!= newcrc
) {
9535 swd_stackshot_hdr
*shdr
= (swd_stackshot_hdr
*)tmpBuf
;;
9537 /* Set statckshot size to 0 if crc doesn't match */
9538 shdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
9541 assert(tmpBufSize
> sizeof(swd_stackshot_hdr
));
9542 bytesToWrite
= round_page(sizeof(swd_stackshot_hdr
));
9543 vn_rdwr(UIO_WRITE
, vp
, (char *)tmpBuf
, bytesToWrite
, 0,
9544 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9545 vfs_context_ucred(ctx
), (int *) 0,
9546 vfs_context_proc(ctx
));
9548 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9553 error
= vnode_close(vp
, FWRITE
, ctx
);
9554 DLOG("vnode_close returned 0x%x\n", error
);
9556 if (ctx
) vfs_context_rele(ctx
);
9563 void IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9564 void *tmpBuf
, struct vnode
**vp
)
9569 struct vnode_attr va
;
9570 IOHibernateImageHeader
*imageHdr
;
9573 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9574 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9576 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9580 VATTR_WANTED(&va
, va_nlink
);
9581 VATTR_WANTED(&va
, va_data_alloc
);
9582 if ((*vp
)->v_type
!= VREG
||
9583 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9584 DMSG("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9588 /* Read the sleepimage file header */
9589 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9590 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9591 vfs_context_ucred(*ctx
), (int *) 0,
9592 vfs_context_proc(*ctx
));
9594 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9595 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9599 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9600 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9601 DMSG("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9602 fname
, imageHdr
->signature
);
9606 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9607 hdrOffset
= imageHdr
->deviceBlockSize
;
9608 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9609 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9610 va
.va_data_alloc
, fname
);
9617 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9623 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9627 char hibernateFilename
[MAXPATHLEN
+1];
9628 char PMStatusCode
[100];
9630 swd_hdr
*hdr
= NULL
;
9631 uint32_t stacksSize
, logSize
;
9632 uint64_t tmpBufSize
;
9633 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9634 errno_t error
= EIO
;
9635 OSObject
*obj
= NULL
;
9636 OSString
*str
= NULL
;
9637 OSNumber
*failStat
= NULL
;
9638 struct vnode
*vp
= NULL
;
9639 vfs_context_t ctx
= NULL
;
9641 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9643 DLOG("sleepWakeDebugDumpFromFile\n");
9644 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9647 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9651 /* Allocate a temp buffer to copy data between files */
9652 tmpBufSize
= 2*4096;
9653 tmpBufDesc
= IOBufferMemoryDescriptor::
9654 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9655 tmpBufSize
, PAGE_SIZE
);
9658 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9662 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9664 ctx
= vfs_context_create(vfs_context_current());
9666 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9667 checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9669 /* Check if the debug data is saved to hibernation file */
9670 hibernateFilename
[0] = 0;
9671 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9673 if ((str
= OSDynamicCast(OSString
, obj
)))
9674 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9675 sizeof(hibernateFilename
));
9678 if (!hibernateFilename
[0]) {
9679 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9683 checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9685 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9688 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9691 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9694 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9696 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9697 /* Read the sleep/wake debug header(swd_hdr) */
9698 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9699 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9700 vfs_context_ucred(ctx
), (int *) 0,
9701 vfs_context_proc(ctx
));
9703 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9704 round_page(sizeof(swd_hdr
)), rc
);
9708 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9709 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9710 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9711 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9712 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9715 stacksSize
= hdr
->spindump_size
;
9717 /* Get stacks & log offsets in the image file */
9718 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9719 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9720 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9722 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9723 getDumpStackFilename(hdr
), stacksSize
, hdr
->crc
);
9724 if (error
== EFAULT
) {
9725 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9728 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9729 getDumpLogFilename(hdr
), logSize
, 0);
9731 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9736 // Write just the SleepWakeLog.dump with failure code
9739 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9740 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9741 fcode
= failStat
->unsigned64BitValue();
9742 fname
= kSleepWakeLogFilename
;
9745 fname
= kAppleOSXWatchdogLogFilename
;
9747 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9748 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9749 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9750 sleepWakeDebugSaveFile(fname
, PMStatusCode
, sizeof(PMStatusCode
));
9752 gRootDomain
->swd_lock
= 0;
9754 if (vp
) vnode_close(vp
, FREAD
, ctx
);
9755 if (ctx
) vfs_context_rele(ctx
);
9756 if (tmpBufDesc
) tmpBufDesc
->release();
9757 #endif /* HIBERNATION */
9760 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
9762 IOVirtualAddress srcBuf
= NULL
;
9763 char *stackBuf
= NULL
, *logOffset
= NULL
;
9766 errno_t error
= EIO
;
9767 uint64_t bufSize
= 0;
9768 swd_hdr
*hdr
= NULL
;
9769 char PMStatusCode
[100];
9770 OSNumber
*failStat
= NULL
;
9772 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9775 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
9777 DLOG("Nothing saved to dump to file\n");
9781 hdr
= (swd_hdr
*)srcBuf
;
9782 bufSize
= logBufMap
->getLength();
9783 if (bufSize
<= sizeof(swd_hdr
))
9785 IOLog("SleepWake log buffer contents are invalid\n");
9789 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
9791 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
9792 if (error
) goto exit
;
9794 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9795 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9797 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
9798 if (error
) goto exit
;
9800 hdr
->spindump_size
= 0;
9805 // Write just the SleepWakeLog.dump with failure code
9807 const char *sname
, *lname
;
9808 swd_stackshot_hdr shdr
;
9810 /* Try writing an empty stacks file */
9811 shdr
.magic
= SWD_STACKSHOTHDR_MAGIC
;
9815 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9816 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9817 fcode
= failStat
->unsigned64BitValue();
9818 lname
= kSleepWakeLogFilename
;
9819 sname
= kSleepWakeStackFilename
;
9822 lname
= kAppleOSXWatchdogLogFilename
;
9823 sname
= kAppleOSXWatchdogStackFilename
;
9826 sleepWakeDebugSaveFile(sname
, (char*)(&shdr
), sizeof(shdr
));
9827 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9828 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9829 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9830 sleepWakeDebugSaveFile(lname
, PMStatusCode
, sizeof(PMStatusCode
));
9832 gRootDomain
->swd_lock
= 0;
9835 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9837 IOVirtualAddress vaddr
= NULL
;
9838 IOMemoryDescriptor
* desc
= NULL
;
9839 IOMemoryMap
* logBufMap
= NULL
;
9843 uint64_t bufSize
= 0;
9845 uint64_t newcrc
= 0;
9847 swd_hdr
*hdr
= NULL
;
9852 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9855 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
9856 DLOG("No sleepWakeDebug note to read\n");
9860 if (len
== strlen("sleepimage")) {
9862 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
9864 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
9865 DLOG("sleepWakeDebugRetrieve: in file logs\n");
9866 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
9870 else if (len
== sizeof(addr64_t
)*3)
9871 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
9873 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
9879 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9880 data
[0], data
[1], data
[2]);
9881 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
9885 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
9887 IOLog("SleepWake log buffer contents are invalid\n");
9891 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9892 bufSize
, crc
, paddr
);
9895 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
9896 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
9899 IOLog("Fail to map SleepWake log buffer\n");
9903 logBufMap
= desc
->map();
9905 vaddr
= logBufMap
->getVirtualAddress();
9908 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
9909 IOLog("Fail to map SleepWake log buffer\n");
9913 hdr
= (swd_hdr
*)vaddr
;
9914 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
9916 IOLog("SleepWake log buffer contents are invalid\n");
9921 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
9922 hdr
->spindump_size
);
9923 if (newcrc
!= crc
) {
9924 IOLog("SleepWake log buffer contents are invalid\n");
9929 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
9933 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
9935 if (logBufMap
) logBufMap
->release();
9938 if (desc
) desc
->release();
9939 gRootDomain
->swd_lock
= 0;
9946 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
9950 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
9952 #pragma unused(restart)
9953 #pragma unused(isOSXWatchdog)
9956 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9959 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
9962 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9963 struct vnode
*srcVp
,
9964 vfs_context_t srcCtx
,
9965 char *tmpBuf
, uint64_t tmpBufSize
,
9967 const char *dstFname
,
9974 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
9978 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9983 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9987 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9992 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)