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
)
839 int new_value
, changed
;
841 error
= sysctl_io_number(req
, vc_user_options
, sizeof(int), &new_value
, &changed
);
843 if (changed
) vc_set_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", "");
853 sysctl_wakereason SYSCTL_HANDLER_ARGS
855 char wr
[ sizeof(gWakeReasonString
) ];
859 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
861 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
864 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
865 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
866 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
869 sysctl_targettype SYSCTL_HANDLER_ARGS
877 root
= IOService::getServiceRoot();
878 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
880 if ((data
= OSDynamicCast(OSData
, obj
)))
882 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
886 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
889 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
890 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
891 NULL
, 0, sysctl_targettype
, "A", "targettype");
893 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
894 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
896 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
897 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
898 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
899 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
900 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
901 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
902 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
903 static const OSSymbol
* gIOPMUserIsActiveKey
;
905 //******************************************************************************
908 //******************************************************************************
910 #define kRootDomainSettingsCount 17
912 bool IOPMrootDomain::start( IOService
* nub
)
914 OSIterator
*psIterator
;
915 OSDictionary
*tmpDict
;
916 IORootParent
* patriarch
;
917 #if defined(__i386__) || defined(__x86_64__)
918 IONotifier
* notifier
;
924 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
925 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
926 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
927 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
928 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
929 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
930 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
931 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
933 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
934 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
935 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
936 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
937 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
939 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
940 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
942 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
944 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
945 gIOPMSettingAutoWakeSecondsKey
,
946 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
947 gIOPMSettingAutoWakeCalendarKey
,
948 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
949 gIOPMSettingDebugWakeRelativeKey
,
950 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
951 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
952 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
953 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
954 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
955 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
956 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
957 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
958 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
959 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
960 gIOPMSettingSilentRunningKey
963 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
964 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
966 queue_init(&aggressivesQueue
);
967 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
968 aggressivesData
= OSData::withCapacity(
969 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
971 featuresDictLock
= IOLockAlloc();
972 settingsCtrlLock
= IOLockAlloc();
973 wakeEventLock
= IOLockAlloc();
974 setPMRootDomain(this);
976 extraSleepTimer
= thread_call_allocate(
977 idleSleepTimerExpired
,
978 (thread_call_param_t
) this);
980 diskSyncCalloutEntry
= thread_call_allocate(
982 (thread_call_param_t
) this);
983 hibDebugSetupEntry
= thread_call_allocate(
984 &hib_debugSetup_callout
,
985 (thread_call_param_t
) this);
987 updateConsoleUsersEntry
= thread_call_allocate(
988 &updateConsoleUsersCallout
,
989 (thread_call_param_t
) this);
991 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
992 fullWakeThreadCall
= thread_call_allocate(
993 OSMemberFunctionCast(thread_call_func_t
, this,
994 &IOPMrootDomain::fullWakeDelayedWork
),
995 (thread_call_param_t
) this);
998 setProperty(kIOSleepSupportedKey
, true);
1000 bzero(&gPMStats
, sizeof(gPMStats
));
1002 pmTracer
= PMTraceWorker::tracer(this);
1004 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1006 userDisabledAllSleep
= false;
1007 systemBooting
= true;
1009 idleSleepTimerPending
= false;
1011 clamshellClosed
= false;
1012 clamshellExists
= false;
1013 clamshellDisabled
= true;
1014 acAdaptorConnected
= true;
1015 clamshellSleepDisabled
= false;
1016 gWakeReasonString
[0] = '\0';
1018 // Initialize to user active.
1019 // Will never transition to user inactive w/o wrangler.
1020 fullWakeReason
= kFullWakeReasonLocalUser
;
1021 userIsActive
= userWasActive
= true;
1022 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1024 // Set the default system capabilities at boot.
1025 _currentCapability
= kIOPMSystemCapabilityCPU
|
1026 kIOPMSystemCapabilityGraphics
|
1027 kIOPMSystemCapabilityAudio
|
1028 kIOPMSystemCapabilityNetwork
;
1030 _pendingCapability
= _currentCapability
;
1031 _desiredCapability
= _currentCapability
;
1032 _highestCapability
= _currentCapability
;
1033 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1035 queuedSleepWakeUUIDString
= NULL
;
1036 initializeBootSessionUUID();
1037 pmStatsAppResponses
= OSArray::withCapacity(5);
1038 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1039 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1040 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1041 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1042 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1043 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1044 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1046 pmStatsLock
= IOLockAlloc();
1047 idxPMCPUClamshell
= kCPUUnknownIndex
;
1048 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1050 tmpDict
= OSDictionary::withCapacity(1);
1051 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1054 settingsCallbacks
= OSDictionary::withCapacity(1);
1056 // Create a list of the valid PM settings that we'll relay to
1057 // interested clients in setProperties() => setPMSetting()
1058 allowedPMSettings
= OSArray::withObjects(
1059 (const OSObject
**)settingsArr
,
1060 kRootDomainSettingsCount
,
1063 // List of PM settings that should not automatically publish itself
1064 // as a feature when registered by a listener.
1065 noPublishPMSettings
= OSArray::withObjects(
1066 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1068 fPMSettingsDict
= OSDictionary::withCapacity(5);
1069 preventIdleSleepList
= OSSet::withCapacity(8);
1070 preventSystemSleepList
= OSSet::withCapacity(2);
1072 PMinit(); // creates gIOPMWorkLoop
1074 // Create IOPMPowerStateQueue used to queue external power
1075 // events, and to handle those events on the PM work loop.
1076 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1077 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1078 &IOPMrootDomain::dispatchPowerEvent
));
1079 getPMworkloop()->addEventSource(pmPowerStateQueue
);
1080 #ifdef CHECK_THREAD_CONTEXT
1081 gIOPMWorkLoop
= getPMworkloop();
1084 // create our power parent
1085 patriarch
= new IORootParent
;
1087 patriarch
->attach(this);
1088 patriarch
->start(this);
1089 patriarch
->addPowerChild(this);
1091 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1092 changePowerStateToPriv(ON_STATE
);
1094 // install power change handler
1095 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1098 // Register for a notification when IODisplayWrangler is published
1099 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1101 _displayWranglerNotifier
= addMatchingNotification(
1102 gIOPublishNotification
, tmpDict
,
1103 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1109 #if defined(__i386__) || defined(__x86_64__)
1111 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1113 notifier
= addMatchingNotification(
1114 gIOFirstPublishNotification
, tmpDict
,
1115 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1120 wranglerIdleSettings
= NULL
;
1121 OSNumber
* wranglerIdlePeriod
= NULL
;
1122 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1123 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1125 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1126 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1127 wranglerIdlePeriod
);
1129 if(wranglerIdlePeriod
)
1130 wranglerIdlePeriod
->release();
1133 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1134 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1135 ucClassName
->release();
1137 // IOBacklightDisplay can take a long time to load at boot, or it may
1138 // not load at all if you're booting with clamshell closed. We publish
1139 // 'DisplayDims' here redundantly to get it published early and at all.
1140 OSDictionary
* matching
;
1141 matching
= serviceMatching("IOPMPowerSource");
1142 psIterator
= getMatchingServices( matching
);
1143 if (matching
) matching
->release();
1144 if( psIterator
&& psIterator
->getNextObject() )
1146 // There's at least one battery on the system, so we publish
1147 // 'DisplayDims' support for the LCD.
1148 publishFeature("DisplayDims");
1151 psIterator
->release();
1154 sysctl_register_oid(&sysctl__kern_sleeptime
);
1155 sysctl_register_oid(&sysctl__kern_waketime
);
1156 sysctl_register_oid(&sysctl__kern_willshutdown
);
1157 sysctl_register_oid(&sysctl__kern_iokittest
);
1158 sysctl_register_oid(&sysctl__hw_targettype
);
1160 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1161 sysctl_register_oid(&sysctl__kern_progressmeter
);
1162 sysctl_register_oid(&sysctl__kern_wakereason
);
1163 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1166 IOHibernateSystemInit(this);
1169 registerService(); // let clients find us
1174 //******************************************************************************
1177 // Receive a setProperty call
1178 // The "System Boot" property means the system is completely booted.
1179 //******************************************************************************
1181 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1183 IOReturn return_value
= kIOReturnSuccess
;
1184 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1187 const OSSymbol
*key
;
1189 OSCollectionIterator
* iter
= 0;
1191 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1192 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1193 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1194 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1195 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1196 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1197 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1198 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1199 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1201 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1202 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1203 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1204 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1205 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1206 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1211 return_value
= kIOReturnBadArgument
;
1215 iter
= OSCollectionIterator::withCollection(dict
);
1218 return_value
= kIOReturnNoMemory
;
1222 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1223 (obj
= dict
->getObject(key
)))
1225 if (key
->isEqualTo(publish_simulated_battery_string
))
1227 if (OSDynamicCast(OSBoolean
, obj
))
1228 publishResource(key
, kOSBooleanTrue
);
1230 else if (key
->isEqualTo(idle_seconds_string
))
1232 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1234 setProperty(key
, n
);
1235 idleSeconds
= n
->unsigned32BitValue();
1238 else if (key
->isEqualTo(boot_complete_string
))
1240 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1242 else if (key
->isEqualTo(sys_shutdown_string
))
1244 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1245 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1247 else if (key
->isEqualTo(battery_warning_disabled_string
))
1249 setProperty(key
, obj
);
1252 else if (key
->isEqualTo(hibernatemode_string
) ||
1253 key
->isEqualTo(hibernatefilemin_string
) ||
1254 key
->isEqualTo(hibernatefilemax_string
) ||
1255 key
->isEqualTo(hibernatefreeratio_string
) ||
1256 key
->isEqualTo(hibernatefreetime_string
))
1258 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1259 setProperty(key
, n
);
1261 else if (key
->isEqualTo(hibernatefile_string
))
1263 OSString
* str
= OSDynamicCast(OSString
, obj
);
1264 if (str
) setProperty(key
, str
);
1267 else if (key
->isEqualTo(sleepdisabled_string
))
1269 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1271 setProperty(key
, b
);
1272 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1275 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1278 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1280 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1282 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1283 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1285 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1286 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1287 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1288 key
->isEqualTo(stall_halt_string
))
1290 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1291 setProperty(key
, b
);
1293 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1294 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1295 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1297 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1298 setProperty(key
, n
);
1300 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1302 if (kOSBooleanTrue
== obj
)
1303 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1305 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1306 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1309 // Relay our allowed PM settings onto our registered PM clients
1310 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1312 return_value
= setPMSetting(key
, obj
);
1313 if (kIOReturnSuccess
!= return_value
)
1316 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1318 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1319 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1321 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1325 _debugWakeSeconds
= 0;
1326 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1328 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1330 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1333 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1334 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1336 const IOPMCalendarStruct
* cs
=
1337 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1340 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1342 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1343 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1349 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1354 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1355 if(boot_complete_string
) boot_complete_string
->release();
1356 if(sys_shutdown_string
) sys_shutdown_string
->release();
1357 if(stall_halt_string
) stall_halt_string
->release();
1358 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1359 if(idle_seconds_string
) idle_seconds_string
->release();
1360 if(sleepdisabled_string
) sleepdisabled_string
->release();
1361 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1362 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1364 if(hibernatemode_string
) hibernatemode_string
->release();
1365 if(hibernatefile_string
) hibernatefile_string
->release();
1366 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1367 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1369 if (iter
) iter
->release();
1370 return return_value
;
1374 // MARK: Aggressiveness
1376 //******************************************************************************
1377 // setAggressiveness
1379 // Override IOService::setAggressiveness()
1380 //******************************************************************************
1382 IOReturn
IOPMrootDomain::setAggressiveness(
1384 unsigned long value
)
1386 return setAggressiveness( type
, value
, 0 );
1390 * Private setAggressiveness() with an internal options argument.
1392 IOReturn
IOPMrootDomain::setAggressiveness(
1394 unsigned long value
,
1395 IOOptionBits options
)
1397 AggressivesRequest
* entry
;
1398 AggressivesRequest
* request
;
1401 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1402 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1404 request
= IONew(AggressivesRequest
, 1);
1406 return kIOReturnNoMemory
;
1408 memset(request
, 0, sizeof(*request
));
1409 request
->options
= options
;
1410 request
->dataType
= kAggressivesRequestTypeRecord
;
1411 request
->data
.record
.type
= (uint32_t) type
;
1412 request
->data
.record
.value
= (uint32_t) value
;
1416 // Update disk quick spindown flag used by getAggressiveness().
1417 // Never merge requests with quick spindown flags set.
1419 if (options
& kAggressivesOptionQuickSpindownEnable
)
1420 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1421 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1422 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1425 // Coalesce requests with identical aggressives types.
1426 // Deal with callers that calls us too "aggressively".
1428 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1430 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1431 (entry
->data
.record
.type
== type
) &&
1432 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1434 entry
->data
.record
.value
= value
;
1443 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1446 AGGRESSIVES_UNLOCK();
1449 IODelete(request
, AggressivesRequest
, 1);
1451 if (options
& kAggressivesOptionSynchronous
)
1452 handleAggressivesRequests(); // not truly synchronous
1454 thread_call_enter(aggressivesThreadCall
);
1456 return kIOReturnSuccess
;
1459 //******************************************************************************
1460 // getAggressiveness
1462 // Override IOService::setAggressiveness()
1463 // Fetch the aggressiveness factor with the given type.
1464 //******************************************************************************
1466 IOReturn
IOPMrootDomain::getAggressiveness (
1468 unsigned long * outLevel
)
1474 return kIOReturnBadArgument
;
1478 // Disk quick spindown in effect, report value = 1
1480 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1481 (type
== kPMMinutesToSpinDown
))
1483 value
= kAggressivesMinValue
;
1487 // Consult the pending request queue.
1491 AggressivesRequest
* entry
;
1493 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1495 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1496 (entry
->data
.record
.type
== type
) &&
1497 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1499 value
= entry
->data
.record
.value
;
1506 // Consult the backend records.
1508 if (!source
&& aggressivesData
)
1510 AggressivesRecord
* record
;
1513 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1514 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1516 for (i
= 0; i
< count
; i
++, record
++)
1518 if (record
->type
== type
)
1520 value
= record
->value
;
1527 AGGRESSIVES_UNLOCK();
1531 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1532 source
, (uint32_t) type
, value
);
1533 *outLevel
= (unsigned long) value
;
1534 return kIOReturnSuccess
;
1538 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1539 *outLevel
= 0; // default return = 0, driver may not check for error
1540 return kIOReturnInvalid
;
1544 //******************************************************************************
1545 // joinAggressiveness
1547 // Request from IOService to join future aggressiveness broadcasts.
1548 //******************************************************************************
1550 IOReturn
IOPMrootDomain::joinAggressiveness(
1551 IOService
* service
)
1553 AggressivesRequest
* request
;
1555 if (!service
|| (service
== this))
1556 return kIOReturnBadArgument
;
1558 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1560 request
= IONew(AggressivesRequest
, 1);
1562 return kIOReturnNoMemory
;
1564 service
->retain(); // released by synchronizeAggressives()
1566 memset(request
, 0, sizeof(*request
));
1567 request
->dataType
= kAggressivesRequestTypeService
;
1568 request
->data
.service
= service
;
1571 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1572 AGGRESSIVES_UNLOCK();
1574 thread_call_enter(aggressivesThreadCall
);
1576 return kIOReturnSuccess
;
1579 //******************************************************************************
1580 // handleAggressivesRequests
1582 // Backend thread processes all incoming aggressiveness requests in the queue.
1583 //******************************************************************************
1586 handleAggressivesFunction(
1587 thread_call_param_t param1
,
1588 thread_call_param_t param2
)
1592 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1596 void IOPMrootDomain::handleAggressivesRequests( void )
1598 AggressivesRecord
* start
;
1599 AggressivesRecord
* record
;
1600 AggressivesRequest
* request
;
1601 queue_head_t joinedQueue
;
1605 bool pingSelf
= false;
1609 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1610 queue_empty(&aggressivesQueue
))
1613 gAggressivesState
|= kAggressivesStateBusy
;
1614 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1615 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1620 queue_init(&joinedQueue
);
1624 // Remove request from the incoming queue in FIFO order.
1625 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1626 switch (request
->dataType
)
1628 case kAggressivesRequestTypeRecord
:
1629 // Update existing record if found.
1631 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1633 if (record
->type
== request
->data
.record
.type
)
1637 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1639 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1642 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1643 kAggressivesRecordFlagModified
);
1644 DLOG("disk spindown accelerated, was %u min\n",
1648 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1650 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1653 record
->flags
|= kAggressivesRecordFlagModified
;
1654 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1655 DLOG("disk spindown restored to %u min\n",
1659 else if (record
->value
!= request
->data
.record
.value
)
1661 record
->value
= request
->data
.record
.value
;
1662 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1665 record
->flags
|= kAggressivesRecordFlagModified
;
1672 // No matching record, append a new record.
1674 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1676 AggressivesRecord newRecord
;
1678 newRecord
.flags
= kAggressivesRecordFlagModified
;
1679 newRecord
.type
= request
->data
.record
.type
;
1680 newRecord
.value
= request
->data
.record
.value
;
1681 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1683 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1684 DLOG("disk spindown accelerated\n");
1687 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1689 // OSData may have switched to another (larger) buffer.
1690 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1691 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1695 // Finished processing the request, release it.
1696 IODelete(request
, AggressivesRequest
, 1);
1699 case kAggressivesRequestTypeService
:
1700 // synchronizeAggressives() will free request.
1701 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1705 panic("bad aggressives request type %x\n", request
->dataType
);
1708 } while (!queue_empty(&aggressivesQueue
));
1710 // Release the lock to perform work, with busy flag set.
1711 if (!queue_empty(&joinedQueue
) || broadcast
)
1713 AGGRESSIVES_UNLOCK();
1714 if (!queue_empty(&joinedQueue
))
1715 synchronizeAggressives(&joinedQueue
, start
, count
);
1717 broadcastAggressives(start
, count
);
1721 // Remove the modified flag from all records.
1722 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1724 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1725 ((record
->type
== kPMMinutesToDim
) ||
1726 (record
->type
== kPMMinutesToSleep
)))
1729 record
->flags
&= ~kAggressivesRecordFlagModified
;
1732 // Check the incoming queue again since new entries may have been
1733 // added while lock was released above.
1735 } while (!queue_empty(&aggressivesQueue
));
1737 gAggressivesState
&= ~kAggressivesStateBusy
;
1740 AGGRESSIVES_UNLOCK();
1742 // Root domain is interested in system and display sleep slider changes.
1743 // Submit a power event to handle those changes on the PM work loop.
1745 if (pingSelf
&& pmPowerStateQueue
) {
1746 pmPowerStateQueue
->submitPowerEvent(
1747 kPowerEventPolicyStimulus
,
1748 (void *) kStimulusAggressivenessChanged
);
1752 //******************************************************************************
1753 // synchronizeAggressives
1755 // Push all known aggressiveness records to one or more IOService.
1756 //******************************************************************************
1758 void IOPMrootDomain::synchronizeAggressives(
1759 queue_head_t
* joinedQueue
,
1760 const AggressivesRecord
* array
,
1763 IOService
* service
;
1764 AggressivesRequest
* request
;
1765 const AggressivesRecord
* record
;
1766 IOPMDriverCallEntry callEntry
;
1770 while (!queue_empty(joinedQueue
))
1772 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1773 if (request
->dataType
== kAggressivesRequestTypeService
)
1774 service
= request
->data
.service
;
1778 IODelete(request
, AggressivesRequest
, 1);
1783 if (service
->assertPMDriverCall(&callEntry
))
1785 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1787 value
= record
->value
;
1788 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1789 value
= kAggressivesMinValue
;
1791 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1792 record
->type
, value
, service
->getName());
1793 service
->setAggressiveness(record
->type
, value
);
1795 service
->deassertPMDriverCall(&callEntry
);
1797 service
->release(); // retained by joinAggressiveness()
1802 //******************************************************************************
1803 // broadcastAggressives
1805 // Traverse PM tree and call setAggressiveness() for records that have changed.
1806 //******************************************************************************
1808 void IOPMrootDomain::broadcastAggressives(
1809 const AggressivesRecord
* array
,
1812 IORegistryIterator
* iter
;
1813 IORegistryEntry
* entry
;
1814 IOPowerConnection
* connect
;
1815 IOService
* service
;
1816 const AggressivesRecord
* record
;
1817 IOPMDriverCallEntry callEntry
;
1821 iter
= IORegistryIterator::iterateOver(
1822 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1828 while ((entry
= iter
->getNextObject()))
1830 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1831 if (!connect
|| !connect
->getReadyFlag())
1834 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1836 if (service
->assertPMDriverCall(&callEntry
))
1838 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1840 if (record
->flags
& kAggressivesRecordFlagModified
)
1842 value
= record
->value
;
1843 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1844 value
= kAggressivesMinValue
;
1845 _LOG("broadcastAggressives %x = %u to %s\n",
1846 record
->type
, value
, service
->getName());
1847 service
->setAggressiveness(record
->type
, value
);
1850 service
->deassertPMDriverCall(&callEntry
);
1856 while (!entry
&& !iter
->isValid());
1862 // MARK: System Sleep
1864 //******************************************************************************
1865 // startIdleSleepTimer
1867 //******************************************************************************
1869 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1871 AbsoluteTime deadline
;
1875 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
1880 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1881 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1882 idleSleepTimerPending
= true;
1886 thread_call_enter(extraSleepTimer
);
1888 DLOG("idle timer set for %u seconds\n", inSeconds
);
1891 //******************************************************************************
1892 // cancelIdleSleepTimer
1894 //******************************************************************************
1896 void IOPMrootDomain::cancelIdleSleepTimer( void )
1899 if (idleSleepTimerPending
)
1901 DLOG("idle timer cancelled\n");
1902 thread_call_cancel(extraSleepTimer
);
1903 idleSleepTimerPending
= false;
1905 if (!assertOnWakeSecs
&& systemWakeTime
) {
1907 clock_usec_t microsecs
;
1908 clock_get_uptime(&now
);
1909 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
1910 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
1911 if (assertOnWakeReport
) {
1912 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
1913 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
1919 //******************************************************************************
1920 // idleSleepTimerExpired
1922 //******************************************************************************
1924 static void idleSleepTimerExpired(
1925 thread_call_param_t us
, thread_call_param_t
)
1927 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1930 //******************************************************************************
1931 // handleSleepTimerExpiration
1933 // The time between the sleep idle timeout and the next longest one has elapsed.
1934 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1935 //******************************************************************************
1937 void IOPMrootDomain::handleSleepTimerExpiration( void )
1939 if (!getPMworkloop()->inGate())
1941 getPMworkloop()->runAction(
1942 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1943 &IOPMrootDomain::handleSleepTimerExpiration
),
1950 DLOG("sleep timer expired\n");
1953 idleSleepTimerPending
= false;
1955 clock_get_uptime(&time
);
1956 setQuickSpinDownTimeout();
1957 adjustPowerState(true);
1960 //******************************************************************************
1961 // getTimeToIdleSleep
1963 // Returns number of seconds left before going into idle sleep.
1964 // Caller has to make sure that idle sleep is allowed at the time of calling
1966 //******************************************************************************
1968 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
1971 AbsoluteTime now
, lastActivityTime
;
1973 uint32_t minutesSinceUserInactive
= 0;
1974 uint32_t sleepDelay
= 0;
1976 if (sleepSlider
== 0)
1979 if (userActivityTime
)
1980 lastActivityTime
= userActivityTime
;
1982 lastActivityTime
= userBecameInactiveTime
;
1984 clock_get_uptime(&now
);
1985 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
1987 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
1988 absolutetime_to_nanoseconds(now
, &nanos
);
1989 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
1991 if (minutesSinceUserInactive
>= sleepSlider
)
1994 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
1998 sleepDelay
= sleepSlider
;
2001 DLOG("user inactive %u min, time to idle sleep %u min\n",
2002 minutesSinceUserInactive
, sleepDelay
);
2004 return (sleepDelay
* 60);
2007 //******************************************************************************
2008 // setQuickSpinDownTimeout
2010 //******************************************************************************
2012 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2016 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2019 //******************************************************************************
2020 // restoreUserSpinDownTimeout
2022 //******************************************************************************
2024 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2028 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2031 //******************************************************************************
2034 //******************************************************************************
2037 IOReturn
IOPMrootDomain::sleepSystem( void )
2039 return sleepSystemOptions(NULL
);
2043 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2045 OSObject
*obj
= NULL
;
2046 OSString
*reason
= NULL
;
2047 /* sleepSystem is a public function, and may be called by any kernel driver.
2048 * And that's bad - drivers should sleep the system by calling
2049 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2051 * Note that user space app calls to IOPMSleepSystem() will also travel
2052 * this code path and thus be correctly identified as software sleeps.
2055 if (options
&& options
->getObject("OSSwitch"))
2057 // Log specific sleep cause for OS Switch hibernation
2058 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2061 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2063 reason
= OSDynamicCast(OSString
, obj
);
2064 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2065 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2068 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2072 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2074 /* Called from both gated and non-gated context */
2076 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2078 return kIOReturnNotPermitted
;
2081 pmPowerStateQueue
->submitPowerEvent(
2082 kPowerEventPolicyStimulus
,
2083 (void *) kStimulusDemandSystemSleep
,
2086 return kIOReturnSuccess
;
2089 //******************************************************************************
2092 // This overrides powerChangeDone in IOService.
2093 //******************************************************************************
2095 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2099 DLOG("PowerChangeDone: %u->%u\n",
2100 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2102 switch ( getPowerState() )
2105 if (previousPowerState
!= ON_STATE
)
2108 acceptSystemWakeEvents(true);
2110 // re-enable this timer for next sleep
2111 cancelIdleSleepTimer();
2114 clock_usec_t microsecs
;
2115 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2117 gIOLastSleepTime
.tv_sec
= secs
;
2118 gIOLastSleepTime
.tv_usec
= microsecs
;
2119 gIOLastWakeTime
.tv_sec
= 0;
2120 gIOLastWakeTime
.tv_usec
= 0;
2122 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2123 clock_usec_t microsecs
;
2124 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2125 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2127 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2128 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2129 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2130 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2131 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2133 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2134 wake2DarkwakeDelay
= 0;
2137 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2139 IOHibernateSystemHasSlept();
2141 evaluateSystemSleepPolicyFinal();
2143 LOG("System Sleep\n");
2145 if (thermalWarningState
) {
2146 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2148 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2152 assertOnWakeSecs
= 0;
2153 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2154 getPlatform()->sleepKernel();
2156 // The CPU(s) are off at this point,
2157 // Code will resume execution here upon wake.
2159 clock_get_uptime(&systemWakeTime
);
2160 _highestCapability
= 0;
2162 ((IOService
*)this)->start_watchdog_timer(); //14456299
2164 IOHibernateSystemWake();
2167 // sleep transition complete
2168 gSleepOrShutdownPending
= 0;
2170 // trip the reset of the calendar clock
2172 clock_sec_t wakeSecs
;
2173 clock_usec_t wakeMicrosecs
;
2175 clock_initialize_calendar();
2177 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2178 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2179 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2183 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2187 PMDebug(kPMLogSystemWake
, 0, 0);
2188 lowBatteryCondition
= false;
2189 lastSleepReason
= 0;
2191 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2192 _debugWakeSeconds
= 0;
2193 _scheduledAlarms
= 0;
2199 #if defined(__i386__) || defined(__x86_64__)
2200 wranglerTickled
= false;
2201 graphicsSuppressed
= false;
2202 darkWakePostTickle
= false;
2203 darkWakeHibernateError
= false;
2204 darkWakeToSleepASAP
= true;
2205 logGraphicsClamp
= true;
2206 sleepTimerMaintenance
= false;
2207 sleepToStandby
= false;
2208 wranglerTickleLatched
= false;
2209 userWasActive
= false;
2210 fullWakeReason
= kFullWakeReasonNone
;
2212 OSString
* wakeType
= OSDynamicCast(
2213 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2214 OSString
* wakeReason
= OSDynamicCast(
2215 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2217 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2218 gWakeReasonString
[0] == '\0')
2220 // Until the platform driver can claim its wake reasons
2221 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2222 sizeof(gWakeReasonString
));
2225 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2227 lowBatteryCondition
= true;
2228 darkWakeMaintenance
= true;
2230 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2233 OSNumber
* hibOptions
= OSDynamicCast(
2234 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2235 if (hibernateAborted
|| ((hibOptions
&&
2236 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2238 // Hibernate aborted, or EFI brought up graphics
2239 wranglerTickled
= true;
2240 DLOG("hibernation aborted %d, options 0x%x\n",
2242 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2247 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2248 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2250 // User wake or RTC alarm
2251 wranglerTickled
= true;
2255 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2257 // SMC standby timer trumps SleepX
2258 darkWakeMaintenance
= true;
2259 sleepTimerMaintenance
= true;
2262 if ((_lastDebugWakeSeconds
!= 0) &&
2263 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2265 // SleepX before maintenance
2266 wranglerTickled
= true;
2270 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2272 darkWakeMaintenance
= true;
2276 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2278 darkWakeMaintenance
= true;
2279 darkWakeSleepService
= true;
2281 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2282 sleepToStandby
= true;
2288 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2290 darkWakeMaintenance
= true;
2291 darkWakeHibernateError
= true;
2295 // Unidentified wake source, resume to full wake if debug
2296 // alarm is pending.
2298 if (_lastDebugWakeSeconds
&&
2299 (!wakeReason
|| wakeReason
->isEqualTo("")))
2300 wranglerTickled
= true;
2306 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2308 darkWakeMaintenance
= true;
2309 sleepTimerMaintenance
= true;
2311 else if (hibernateAborted
|| !wakeType
||
2312 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2313 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2315 // Post a HID tickle immediately - except for RTC maintenance wake.
2316 wranglerTickled
= true;
2320 darkWakeMaintenance
= true;
2324 if (wranglerTickled
)
2326 darkWakeToSleepASAP
= false;
2327 fullWakeReason
= kFullWakeReasonLocalUser
;
2330 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2332 handleDisplayPowerOn();
2334 else if (!darkWakeMaintenance
)
2336 // Early/late tickle for non-maintenance wake.
2337 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2338 kDarkWakeFlagHIDTickleEarly
) ||
2339 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2340 kDarkWakeFlagHIDTickleLate
))
2342 darkWakePostTickle
= true;
2345 #else /* !__i386__ && !__x86_64__ */
2346 // stay awake for at least 30 seconds
2347 wranglerTickled
= true;
2348 fullWakeReason
= kFullWakeReasonLocalUser
;
2349 startIdleSleepTimer(30);
2353 thread_call_enter(updateConsoleUsersEntry
);
2355 changePowerStateToPriv(ON_STATE
);
2357 #if !__i386__ && !__x86_64__
2359 if (previousPowerState
!= ON_STATE
)
2361 DLOG("Force re-evaluating aggressiveness\n");
2362 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2363 pmPowerStateQueue
->submitPowerEvent(
2364 kPowerEventPolicyStimulus
,
2365 (void *) kStimulusNoIdleSleepPreventers
);
2375 //******************************************************************************
2376 // requestPowerDomainState
2378 // Extend implementation in IOService. Running on PM work loop thread.
2379 //******************************************************************************
2381 IOReturn
IOPMrootDomain::requestPowerDomainState (
2382 IOPMPowerFlags childDesire
,
2383 IOPowerConnection
* childConnection
,
2384 unsigned long specification
)
2386 // Idle and system sleep prevention flags affects driver desire.
2387 // Children desire are irrelevant so they are cleared.
2389 return super::requestPowerDomainState(0, childConnection
, specification
);
2393 //******************************************************************************
2394 // updatePreventIdleSleepList
2396 // Called by IOService on PM work loop.
2397 // Returns true if PM policy recognized the driver's desire to prevent idle
2398 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2399 //******************************************************************************
2401 bool IOPMrootDomain::updatePreventIdleSleepList(
2402 IOService
* service
, bool addNotRemove
)
2404 unsigned int oldCount
, newCount
;
2408 #if defined(__i386__) || defined(__x86_64__)
2409 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2410 // idle sleep, except in the case of legacy disk I/O
2411 if ((service
!= wrangler
) && (service
!= this))
2417 oldCount
= preventIdleSleepList
->getCount();
2420 preventIdleSleepList
->setObject(service
);
2421 DLOG("prevent idle sleep list: %s+ (%u)\n",
2422 service
->getName(), preventIdleSleepList
->getCount());
2424 else if (preventIdleSleepList
->member(service
))
2426 preventIdleSleepList
->removeObject(service
);
2427 DLOG("prevent idle sleep list: %s- (%u)\n",
2428 service
->getName(), preventIdleSleepList
->getCount());
2430 newCount
= preventIdleSleepList
->getCount();
2432 if ((oldCount
== 0) && (newCount
!= 0))
2434 // Driver added to empty prevent list.
2435 // Update the driver desire to prevent idle sleep.
2436 // Driver desire does not prevent demand sleep.
2438 changePowerStateTo(ON_STATE
);
2440 else if ((oldCount
!= 0) && (newCount
== 0))
2442 // Last driver removed from prevent list.
2443 // Drop the driver clamp to allow idle sleep.
2445 changePowerStateTo(SLEEP_STATE
);
2446 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2448 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2449 &newCount
, sizeof(newCount
));
2451 #if defined(__i386__) || defined(__x86_64__)
2452 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2454 return false; // do not idle-cancel
2461 //******************************************************************************
2462 // preventSystemSleepListUpdate
2464 // Called by IOService on PM work loop.
2465 //******************************************************************************
2467 void IOPMrootDomain::updatePreventSystemSleepList(
2468 IOService
* service
, bool addNotRemove
)
2470 unsigned int oldCount
, newCount
;
2473 if (this == service
)
2476 oldCount
= preventSystemSleepList
->getCount();
2479 preventSystemSleepList
->setObject(service
);
2480 DLOG("prevent system sleep list: %s+ (%u)\n",
2481 service
->getName(), preventSystemSleepList
->getCount());
2482 if (!assertOnWakeSecs
&& systemWakeTime
) {
2484 clock_usec_t microsecs
;
2485 clock_get_uptime(&now
);
2486 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
2487 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2488 if (assertOnWakeReport
) {
2489 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2490 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2494 else if (preventSystemSleepList
->member(service
))
2496 preventSystemSleepList
->removeObject(service
);
2497 DLOG("prevent system sleep list: %s- (%u)\n",
2498 service
->getName(), preventSystemSleepList
->getCount());
2500 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2502 // Lost all system sleep preventers.
2503 // Send stimulus if system sleep was blocked, and is in dark wake.
2504 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2507 newCount
= preventSystemSleepList
->getCount();
2508 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2509 &newCount
, sizeof(newCount
));
2512 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2515 OSCollectionIterator
*iterator
= NULL
;
2516 OSObject
*object
= NULL
;
2517 OSArray
*array
= NULL
;
2519 if (!getPMworkloop()->inGate())
2521 getPMworkloop()->runAction(
2522 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2523 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2524 this, (void *)idleSleepList
, (void *)systemSleepList
);
2528 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2530 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2531 array
= OSArray::withCapacity(5);
2533 while ((object
= iterator
->getNextObject()))
2535 IOService
*service
= OSDynamicCast(IOService
, object
);
2538 array
->setObject(OSSymbol::withCString(service
->getName()));
2542 iterator
->release();
2543 *idleSleepList
= array
;
2546 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2548 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2549 array
= OSArray::withCapacity(5);
2551 while ((object
= iterator
->getNextObject()))
2553 IOService
*service
= OSDynamicCast(IOService
, object
);
2556 array
->setObject(OSSymbol::withCString(service
->getName()));
2560 iterator
->release();
2561 *systemSleepList
= array
;
2565 //******************************************************************************
2568 // Override the superclass implementation to send a different message type.
2569 //******************************************************************************
2571 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2573 DLOG("tellChangeDown %u->%u\n",
2574 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2576 if (SLEEP_STATE
== stateNum
)
2578 // Legacy apps were already told in the full->dark transition
2579 if (!ignoreTellChangeDown
)
2580 tracePoint( kIOPMTracePointSleepApplications
);
2582 tracePoint( kIOPMTracePointSleepPriorityClients
);
2585 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2587 userActivityAtSleep
= userActivityCount
;
2588 hibernateAborted
= false;
2589 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2591 // Direct callout into OSKext so it can disable kext unloads
2592 // during sleep/wake to prevent deadlocks.
2593 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2595 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2597 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2598 // But tellClientsWithResponse() must be called for both.
2599 ignoreTellChangeDown
= true;
2602 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2605 //******************************************************************************
2608 // Override the superclass implementation to send a different message type.
2609 // This must be idle sleep since we don't ask during any other power change.
2610 //******************************************************************************
2612 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2614 DLOG("askChangeDown %u->%u\n",
2615 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2617 // Don't log for dark wake entry
2618 if (kSystemTransitionSleep
== _systemTransitionType
)
2619 tracePoint( kIOPMTracePointSleepApplications
);
2621 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2624 //******************************************************************************
2625 // askChangeDownDone
2627 // An opportunity for root domain to cancel the power transition,
2628 // possibily due to an assertion created by powerd in response to
2629 // kIOMessageCanSystemSleep.
2632 // full -> dark wake transition
2633 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2634 // 2. askChangeDownDone()
2635 // dark -> sleep transition
2636 // 1. Notify powerd with kIOMessageCanSystemSleep
2637 // 2. askChangeDownDone()
2640 // full -> dark wake transition
2641 // 1. Notify powerd with kIOMessageCanSystemSleep
2642 // 2. askChangeDownDone()
2643 // dark -> sleep transition
2644 // 1. Notify powerd with kIOMessageCanSystemSleep
2645 // 2. askChangeDownDone()
2646 //******************************************************************************
2648 void IOPMrootDomain::askChangeDownDone(
2649 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2651 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2652 *inOutChangeFlags
, *cancel
,
2653 _systemTransitionType
,
2654 _currentCapability
, _pendingCapability
);
2656 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2658 // Dark->Sleep transition.
2659 // Check if there are any deny sleep assertions.
2660 // lastSleepReason already set by handleOurPowerChangeStart()
2662 if (!checkSystemCanSleep(lastSleepReason
))
2664 // Cancel dark wake to sleep transition.
2665 // Must re-scan assertions upon entering dark wake.
2668 DLOG("cancel dark->sleep\n");
2673 //******************************************************************************
2674 // systemDidNotSleep
2676 // Work common to both canceled or aborted sleep.
2677 //******************************************************************************
2679 void IOPMrootDomain::systemDidNotSleep( void )
2681 // reset console lock state
2682 thread_call_enter(updateConsoleUsersEntry
);
2688 // stay awake for at least idleSeconds
2689 startIdleSleepTimer(idleSeconds
);
2694 if (sleepSlider
&& !userIsActive
)
2696 // Manually start the idle sleep timer besides waiting for
2697 // the user to become inactive.
2698 startIdleSleepTimer( kIdleSleepRetryInterval
);
2702 preventTransitionToUserActive(false);
2703 IOService::setAdvisoryTickleEnable( true );
2705 // After idle revert and cancel, send a did-change message to powerd
2706 // to balance the previous will-change message. Kernel clients do not
2707 // need this since sleep cannot be canceled once they are notified.
2709 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2710 (_pendingCapability
!= _currentCapability
) &&
2711 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2713 // Differs from a real capability gain change where notifyRef != 0,
2714 // but it is zero here since no response is expected.
2716 IOPMSystemCapabilityChangeParameters params
;
2718 bzero(¶ms
, sizeof(params
));
2719 params
.fromCapabilities
= _pendingCapability
;
2720 params
.toCapabilities
= _currentCapability
;
2721 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2723 DLOG("MESG cap %x->%x did change\n",
2724 params
.fromCapabilities
, params
.toCapabilities
);
2725 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2726 ¶ms
, sizeof(params
));
2730 //******************************************************************************
2733 // Notify registered applications and kernel clients that we are not dropping
2736 // We override the superclass implementation so we can send a different message
2737 // type to the client or application being notified.
2739 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2740 //******************************************************************************
2742 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2744 DLOG("tellNoChangeDown %u->%u\n",
2745 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2747 // Sleep canceled, clear the sleep trace point.
2748 tracePoint(kIOPMTracePointSystemUp
);
2750 systemDidNotSleep();
2751 return tellClients( kIOMessageSystemWillNotSleep
);
2754 //******************************************************************************
2757 // Notify registered applications and kernel clients that we are raising power.
2759 // We override the superclass implementation so we can send a different message
2760 // type to the client or application being notified.
2761 //******************************************************************************
2763 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2765 DLOG("tellChangeUp %u->%u\n",
2766 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2768 ignoreTellChangeDown
= false;
2770 if ( stateNum
== ON_STATE
)
2772 // Direct callout into OSKext so it can disable kext unloads
2773 // during sleep/wake to prevent deadlocks.
2774 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2776 // Notify platform that sleep was cancelled or resumed.
2777 getPlatform()->callPlatformFunction(
2778 sleepMessagePEFunction
, false,
2779 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2782 if (getPowerState() == ON_STATE
)
2784 // this is a quick wake from aborted sleep
2785 systemDidNotSleep();
2786 tellClients( kIOMessageSystemWillPowerOn
);
2789 tracePoint( kIOPMTracePointWakeApplications
);
2790 tellClients( kIOMessageSystemHasPoweredOn
);
2794 //******************************************************************************
2795 // sysPowerDownHandler
2797 // Perform a vfs sync before system sleep.
2798 //******************************************************************************
2800 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2801 void * target
, void * refCon
,
2802 UInt32 messageType
, IOService
* service
,
2803 void * messageArgs
, vm_size_t argSize
)
2807 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2810 return kIOReturnUnsupported
;
2812 if (messageType
== kIOMessageSystemWillSleep
)
2815 static int32_t mem_only
= -1;
2816 IOPowerStateChangeNotification
*notify
=
2817 (IOPowerStateChangeNotification
*)messageArgs
;
2819 if ((mem_only
== -1) &&
2820 (PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
)) == false)) {
2823 if ((mem_only
!= 1) && (gRootDomain
->sleepWakeDebugIsWdogEnabled()))
2825 notify
->returnValue
= 30 * 1000 * 1000;
2827 gRootDomain
->hibDebugSetupEntry
,
2828 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2832 else if (messageType
== kIOMessageSystemCapabilityChange
)
2834 IOPMSystemCapabilityChangeParameters
* params
=
2835 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2837 // Interested applications have been notified of an impending power
2838 // change and have acked (when applicable).
2839 // This is our chance to save whatever state we can before powering
2841 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2844 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2845 params
->fromCapabilities
, params
->toCapabilities
,
2846 params
->changeFlags
);
2848 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2849 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2850 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2852 // We will ack within 20 seconds
2853 params
->maxWaitForReply
= 20 * 1000 * 1000;
2855 gRootDomain
->evaluateSystemSleepPolicyEarly();
2857 // add in time we could spend freeing pages
2858 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2860 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2862 DLOG("sysPowerDownHandler max wait %d s\n",
2863 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2866 // Notify platform that sleep has begun, after the early
2867 // sleep policy evaluation.
2868 getPlatform()->callPlatformFunction(
2869 sleepMessagePEFunction
, false,
2870 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2873 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2875 // Purposely delay the ack and hope that shutdown occurs quickly.
2876 // Another option is not to schedule the thread and wait for
2878 AbsoluteTime deadline
;
2879 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2880 thread_call_enter1_delayed(
2881 gRootDomain
->diskSyncCalloutEntry
,
2882 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2887 gRootDomain
->diskSyncCalloutEntry
,
2888 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2891 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2892 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2893 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2896 // We will ack within 110 seconds
2897 params
->maxWaitForReply
= 110 * 1000 * 1000;
2900 gRootDomain
->diskSyncCalloutEntry
,
2901 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2904 ret
= kIOReturnSuccess
;
2910 //******************************************************************************
2911 // handleQueueSleepWakeUUID
2913 // Called from IOPMrootDomain when we're initiating a sleep,
2914 // or indirectly from PM configd when PM decides to clear the UUID.
2915 // PM clears the UUID several minutes after successful wake from sleep,
2916 // so that we might associate App spindumps with the immediately previous
2919 // @param obj has a retain on it. We're responsible for releasing that retain.
2920 //******************************************************************************
2922 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2924 OSString
*str
= NULL
;
2926 if (kOSBooleanFalse
== obj
)
2928 handlePublishSleepWakeUUID(NULL
);
2930 else if ((str
= OSDynamicCast(OSString
, obj
)))
2932 // This branch caches the UUID for an upcoming sleep/wake
2933 if (queuedSleepWakeUUIDString
) {
2934 queuedSleepWakeUUIDString
->release();
2935 queuedSleepWakeUUIDString
= NULL
;
2937 queuedSleepWakeUUIDString
= str
;
2938 queuedSleepWakeUUIDString
->retain();
2940 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2949 //******************************************************************************
2950 // handlePublishSleepWakeUUID
2952 // Called from IOPMrootDomain when we're initiating a sleep,
2953 // or indirectly from PM configd when PM decides to clear the UUID.
2954 // PM clears the UUID several minutes after successful wake from sleep,
2955 // so that we might associate App spindumps with the immediately previous
2957 //******************************************************************************
2959 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2964 * Clear the current UUID
2966 if (gSleepWakeUUIDIsSet
)
2968 DLOG("SleepWake UUID cleared\n");
2970 gSleepWakeUUIDIsSet
= false;
2972 removeProperty(kIOPMSleepWakeUUIDKey
);
2973 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2977 * Optionally, publish a new UUID
2979 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2981 OSString
*publishThisUUID
= NULL
;
2983 publishThisUUID
= queuedSleepWakeUUIDString
;
2984 publishThisUUID
->retain();
2986 if (publishThisUUID
)
2988 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2989 publishThisUUID
->release();
2992 gSleepWakeUUIDIsSet
= true;
2993 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2995 queuedSleepWakeUUIDString
->release();
2996 queuedSleepWakeUUIDString
= NULL
;
3000 //******************************************************************************
3001 // initializeBootSessionUUID
3003 // Initialize the boot session uuid at boot up and sets it into registry.
3004 //******************************************************************************
3006 void IOPMrootDomain::initializeBootSessionUUID(void)
3009 uuid_string_t new_uuid_string
;
3011 uuid_generate(new_uuid
);
3012 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3013 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3015 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3018 //******************************************************************************
3019 // changePowerStateTo & changePowerStateToPriv
3021 // Override of these methods for logging purposes.
3022 //******************************************************************************
3024 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3026 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3028 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3029 return kIOReturnUnsupported
;
3031 return super::changePowerStateTo(ordinal
);
3034 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3036 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3038 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3039 return kIOReturnUnsupported
;
3041 return super::changePowerStateToPriv(ordinal
);
3044 //******************************************************************************
3047 //******************************************************************************
3049 bool IOPMrootDomain::activitySinceSleep(void)
3051 return (userActivityCount
!= userActivityAtSleep
);
3054 bool IOPMrootDomain::abortHibernation(void)
3056 bool ret
= activitySinceSleep();
3058 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3060 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3061 hibernateAborted
= true;
3067 hibernate_should_abort(void)
3070 return (gRootDomain
->abortHibernation());
3075 //******************************************************************************
3076 // willNotifyPowerChildren
3078 // Called after all interested drivers have all acknowledged the power change,
3079 // but before any power children is informed. Dispatched though a thread call,
3080 // so it is safe to perform work that might block on a sleeping disk. PM state
3081 // machine (not thread) will block w/o timeout until this function returns.
3082 //******************************************************************************
3084 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3089 if (SLEEP_STATE
== newPowerState
)
3091 if (!tasksSuspended
)
3093 AbsoluteTime deadline
;
3094 tasksSuspended
= TRUE
;
3095 tasks_system_suspend(tasksSuspended
);
3097 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3098 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3102 IOHibernateSystemSleep();
3103 IOHibernateIOKitSleep();
3105 if (gRootDomain
->activitySinceSleep()) {
3106 dict
= OSDictionary::withCapacity(1);
3107 secs
= OSNumber::withNumber(1, 32);
3110 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3111 gRootDomain
->setProperties(dict
);
3112 MSG("Reverting sleep with relative wake\n");
3114 if (dict
) dict
->release();
3115 if (secs
) secs
->release();
3121 //******************************************************************************
3122 // sleepOnClamshellClosed
3124 // contains the logic to determine if the system should sleep when the clamshell
3126 //******************************************************************************
3128 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3130 if (!clamshellExists
)
3133 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3134 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3136 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3139 void IOPMrootDomain::sendClientClamshellNotification( void )
3141 /* Only broadcast clamshell alert if clamshell exists. */
3142 if (!clamshellExists
)
3145 setProperty(kAppleClamshellStateKey
,
3146 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3148 setProperty(kAppleClamshellCausesSleepKey
,
3149 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3151 /* Argument to message is a bitfiel of
3152 * ( kClamshellStateBit | kClamshellSleepBit )
3154 messageClients(kIOPMMessageClamshellStateChange
,
3155 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3156 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3159 //******************************************************************************
3160 // getSleepSupported
3163 //******************************************************************************
3165 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3167 return( platformSleepSupport
);
3170 //******************************************************************************
3171 // setSleepSupported
3174 //******************************************************************************
3176 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3178 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3179 OSBitOrAtomic(flags
, &platformSleepSupport
);
3182 //******************************************************************************
3183 // setDisableClamShellSleep
3185 //******************************************************************************
3187 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3189 if (gIOPMWorkLoop
->inGate() == false) {
3191 gIOPMWorkLoop
->runAction(
3192 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3199 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3200 if ( clamshellSleepDisabled
!= val
)
3202 clamshellSleepDisabled
= val
;
3203 // If clamshellSleepDisabled is reset to 0, reevaluate if
3204 // system need to go to sleep due to clamshell state
3205 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3206 handlePowerNotification(kLocalEvalClamshellCommand
);
3211 //******************************************************************************
3215 //******************************************************************************
3217 void IOPMrootDomain::wakeFromDoze( void )
3219 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3225 //******************************************************************************
3228 // Adds a new feature to the supported features dictionary
3229 //******************************************************************************
3231 void IOPMrootDomain::publishFeature( const char * feature
)
3233 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3236 //******************************************************************************
3237 // publishFeature (with supported power source specified)
3239 // Adds a new feature to the supported features dictionary
3240 //******************************************************************************
3242 void IOPMrootDomain::publishFeature(
3243 const char *feature
,
3244 uint32_t supportedWhere
,
3245 uint32_t *uniqueFeatureID
)
3247 static uint16_t next_feature_id
= 500;
3249 OSNumber
*new_feature_data
= NULL
;
3250 OSNumber
*existing_feature
= NULL
;
3251 OSArray
*existing_feature_arr
= NULL
;
3252 OSObject
*osObj
= NULL
;
3253 uint32_t feature_value
= 0;
3255 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3257 if(!supportedWhere
) {
3258 // Feature isn't supported anywhere!
3262 if(next_feature_id
> 5000) {
3263 // Far, far too many features!
3267 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3269 OSDictionary
*features
=
3270 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3272 // Create new features dict if necessary
3273 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3274 features
= OSDictionary::withDictionary(features
);
3276 features
= OSDictionary::withCapacity(1);
3279 // Create OSNumber to track new feature
3281 next_feature_id
+= 1;
3282 if( uniqueFeatureID
) {
3283 // We don't really mind if the calling kext didn't give us a place
3284 // to stash their unique id. Many kexts don't plan to unload, and thus
3285 // have no need to remove themselves later.
3286 *uniqueFeatureID
= next_feature_id
;
3289 feature_value
= (uint32_t)next_feature_id
;
3290 feature_value
<<= 16;
3291 feature_value
+= supportedWhere
;
3293 new_feature_data
= OSNumber::withNumber(
3294 (unsigned long long)feature_value
, 32);
3296 // Does features object already exist?
3297 if( (osObj
= features
->getObject(feature
)) )
3299 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3301 // We need to create an OSArray to hold the now 2 elements.
3302 existing_feature_arr
= OSArray::withObjects(
3303 (const OSObject
**)&existing_feature
, 1, 2);
3304 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3306 // Add object to existing array
3307 existing_feature_arr
= OSArray::withArray(
3308 existing_feature_arr
,
3309 existing_feature_arr
->getCount() + 1);
3312 if (existing_feature_arr
)
3314 existing_feature_arr
->setObject(new_feature_data
);
3315 features
->setObject(feature
, existing_feature_arr
);
3316 existing_feature_arr
->release();
3317 existing_feature_arr
= 0;
3320 // The easy case: no previously existing features listed. We simply
3321 // set the OSNumber at key 'feature' and we're on our way.
3322 features
->setObject(feature
, new_feature_data
);
3325 new_feature_data
->release();
3327 setProperty(kRootDomainSupportedFeatures
, features
);
3329 features
->release();
3331 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3333 // Notify EnergySaver and all those in user space so they might
3334 // re-populate their feature specific UI
3335 if(pmPowerStateQueue
) {
3336 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3340 //******************************************************************************
3341 // removePublishedFeature
3343 // Removes previously published feature
3344 //******************************************************************************
3346 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3348 IOReturn ret
= kIOReturnError
;
3349 uint32_t feature_value
= 0;
3350 uint16_t feature_id
= 0;
3351 bool madeAChange
= false;
3353 OSSymbol
*dictKey
= NULL
;
3354 OSCollectionIterator
*dictIterator
= NULL
;
3355 OSArray
*arrayMember
= NULL
;
3356 OSNumber
*numberMember
= NULL
;
3357 OSObject
*osObj
= NULL
;
3358 OSNumber
*osNum
= NULL
;
3359 OSArray
*arrayMemberCopy
;
3361 if (kBadPMFeatureID
== removeFeatureID
)
3362 return kIOReturnNotFound
;
3364 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3366 OSDictionary
*features
=
3367 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3369 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3371 // Any modifications to the dictionary are made to the copy to prevent
3372 // races & crashes with userland clients. Dictionary updated
3373 // automically later.
3374 features
= OSDictionary::withDictionary(features
);
3377 ret
= kIOReturnNotFound
;
3381 // We iterate 'features' dictionary looking for an entry tagged
3382 // with 'removeFeatureID'. If found, we remove it from our tracking
3383 // structures and notify the OS via a general interest message.
3385 dictIterator
= OSCollectionIterator::withCollection(features
);
3390 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3392 osObj
= features
->getObject(dictKey
);
3394 // Each Feature is either tracked by an OSNumber
3395 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3397 feature_value
= numberMember
->unsigned32BitValue();
3398 feature_id
= (uint16_t)(feature_value
>> 16);
3400 if( feature_id
== (uint16_t)removeFeatureID
)
3403 features
->removeObject(dictKey
);
3408 // Or tracked by an OSArray of OSNumbers
3409 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3411 unsigned int arrayCount
= arrayMember
->getCount();
3413 for(unsigned int i
=0; i
<arrayCount
; i
++)
3415 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3420 feature_value
= osNum
->unsigned32BitValue();
3421 feature_id
= (uint16_t)(feature_value
>> 16);
3423 if( feature_id
== (uint16_t)removeFeatureID
)
3426 if( 1 == arrayCount
) {
3427 // If the array only contains one element, remove
3429 features
->removeObject(dictKey
);
3431 // Otherwise remove the element from a copy of the array.
3432 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3433 if (arrayMemberCopy
)
3435 arrayMemberCopy
->removeObject(i
);
3436 features
->setObject(dictKey
, arrayMemberCopy
);
3437 arrayMemberCopy
->release();
3448 dictIterator
->release();
3452 ret
= kIOReturnSuccess
;
3454 setProperty(kRootDomainSupportedFeatures
, features
);
3456 // Notify EnergySaver and all those in user space so they might
3457 // re-populate their feature specific UI
3458 if(pmPowerStateQueue
) {
3459 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3462 ret
= kIOReturnNotFound
;
3466 if(features
) features
->release();
3467 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3471 //******************************************************************************
3472 // publishPMSetting (private)
3474 // Should only be called by PMSettingObject to publish a PM Setting as a
3475 // supported feature.
3476 //******************************************************************************
3478 void IOPMrootDomain::publishPMSetting(
3479 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3481 if (noPublishPMSettings
&&
3482 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3484 // Setting found in noPublishPMSettings array
3485 *featureID
= kBadPMFeatureID
;
3490 feature
->getCStringNoCopy(), where
, featureID
);
3493 //******************************************************************************
3494 // setPMSetting (private)
3496 // Internal helper to relay PM settings changes from user space to individual
3497 // drivers. Should be called only by IOPMrootDomain::setProperties.
3498 //******************************************************************************
3500 IOReturn
IOPMrootDomain::setPMSetting(
3501 const OSSymbol
*type
,
3504 PMSettingCallEntry
*entries
= 0;
3505 OSArray
*chosen
= 0;
3506 const OSArray
*array
;
3507 PMSettingObject
*pmso
;
3508 thread_t thisThread
;
3509 int i
, j
, count
, capacity
;
3512 return kIOReturnBadArgument
;
3516 // Update settings dict so changes are visible from copyPMSetting().
3517 fPMSettingsDict
->setObject(type
, object
);
3519 // Prep all PMSetting objects with the given 'type' for callout.
3520 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3521 if (!array
|| ((capacity
= array
->getCount()) == 0))
3524 // Array to retain PMSetting objects targeted for callout.
3525 chosen
= OSArray::withCapacity(capacity
);
3527 goto unlock_exit
; // error
3529 entries
= IONew(PMSettingCallEntry
, capacity
);
3531 goto unlock_exit
; // error
3532 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3534 thisThread
= current_thread();
3536 for (i
= 0, j
= 0; i
<capacity
; i
++)
3538 pmso
= (PMSettingObject
*) array
->getObject(i
);
3541 entries
[j
].thread
= thisThread
;
3542 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3543 chosen
->setObject(pmso
);
3552 // Call each pmso in the chosen array.
3553 for (i
=0; i
<count
; i
++)
3555 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3556 pmso
->dispatchPMSetting(type
, object
);
3560 for (i
=0; i
<count
; i
++)
3562 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3563 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3564 if (pmso
->waitThread
)
3566 PMSETTING_WAKEUP(pmso
);
3572 if (chosen
) chosen
->release();
3573 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3575 return kIOReturnSuccess
;
3578 //******************************************************************************
3579 // copyPMSetting (public)
3581 // Allows kexts to safely read setting values, without being subscribed to
3583 //******************************************************************************
3585 OSObject
* IOPMrootDomain::copyPMSetting(
3586 OSSymbol
*whichSetting
)
3588 OSObject
*obj
= NULL
;
3590 if(!whichSetting
) return NULL
;
3593 obj
= fPMSettingsDict
->getObject(whichSetting
);
3602 //******************************************************************************
3603 // registerPMSettingController (public)
3605 // direct wrapper to registerPMSettingController with uint32_t power source arg
3606 //******************************************************************************
3608 IOReturn
IOPMrootDomain::registerPMSettingController(
3609 const OSSymbol
* settings
[],
3610 IOPMSettingControllerCallback func
,
3615 return registerPMSettingController(
3617 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3618 func
, target
, refcon
, handle
);
3621 //******************************************************************************
3622 // registerPMSettingController (public)
3624 // Kexts may register for notifications when a particular setting is changed.
3625 // A list of settings is available in IOPM.h.
3627 // * settings - An OSArray containing OSSymbols. Caller should populate this
3628 // array with a list of settings caller wants notifications from.
3629 // * func - A C function callback of the type IOPMSettingControllerCallback
3630 // * target - caller may provide an OSObject *, which PM will pass as an
3631 // target to calls to "func"
3632 // * refcon - caller may provide an void *, which PM will pass as an
3633 // argument to calls to "func"
3634 // * handle - This is a return argument. We will populate this pointer upon
3635 // call success. Hold onto this and pass this argument to
3636 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3638 // kIOReturnSuccess on success
3639 //******************************************************************************
3641 IOReturn
IOPMrootDomain::registerPMSettingController(
3642 const OSSymbol
* settings
[],
3643 uint32_t supportedPowerSources
,
3644 IOPMSettingControllerCallback func
,
3649 PMSettingObject
*pmso
= NULL
;
3650 OSObject
*pmsh
= NULL
;
3651 OSArray
*list
= NULL
;
3654 if (NULL
== settings
||
3658 return kIOReturnBadArgument
;
3661 pmso
= PMSettingObject::pmSettingObject(
3662 (IOPMrootDomain
*) this, func
, target
,
3663 refcon
, supportedPowerSources
, settings
, &pmsh
);
3667 return kIOReturnInternalError
;
3671 for (i
=0; settings
[i
]; i
++)
3673 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3675 // New array of callbacks for this setting
3676 list
= OSArray::withCapacity(1);
3677 settingsCallbacks
->setObject(settings
[i
], list
);
3681 // Add caller to the callback list
3682 list
->setObject(pmso
);
3686 // Return handle to the caller, the setting object is private.
3689 return kIOReturnSuccess
;
3692 //******************************************************************************
3693 // deregisterPMSettingObject (private)
3695 // Only called from PMSettingObject.
3696 //******************************************************************************
3698 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3700 thread_t thisThread
= current_thread();
3701 PMSettingCallEntry
*callEntry
;
3702 OSCollectionIterator
*iter
;
3710 pmso
->disabled
= true;
3712 // Wait for all callout threads to finish.
3715 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3717 if (callEntry
->thread
!= thisThread
)
3725 assert(0 == pmso
->waitThread
);
3726 pmso
->waitThread
= thisThread
;
3727 PMSETTING_WAIT(pmso
);
3728 pmso
->waitThread
= 0;
3732 // Search each PM settings array in the kernel.
3733 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3736 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3738 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3739 index
= array
->getNextIndexOfObject(pmso
, 0);
3741 array
->removeObject(index
);
3752 //******************************************************************************
3753 // informCPUStateChange
3755 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3756 // running on battery, with the lid closed, etc.
3758 // informCPUStateChange is a no-op on non x86 systems
3759 // only x86 has explicit support in the IntelCPUPowerManagement kext
3760 //******************************************************************************
3762 void IOPMrootDomain::informCPUStateChange(
3766 #if defined(__i386__) || defined(__x86_64__)
3768 pmioctlVariableInfo_t varInfoStruct
;
3770 const char *varNameStr
= NULL
;
3771 int32_t *varIndex
= NULL
;
3773 if (kInformAC
== type
) {
3774 varNameStr
= kIOPMRootDomainBatPowerCString
;
3775 varIndex
= &idxPMCPULimitedPower
;
3776 } else if (kInformLid
== type
) {
3777 varNameStr
= kIOPMRootDomainLidCloseCString
;
3778 varIndex
= &idxPMCPUClamshell
;
3783 // Set the new value!
3784 // pmCPUControl will assign us a new ID if one doesn't exist yet
3785 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3786 varInfoStruct
.varID
= *varIndex
;
3787 varInfoStruct
.varType
= vBool
;
3788 varInfoStruct
.varInitValue
= value
;
3789 varInfoStruct
.varCurValue
= value
;
3790 strncpy( (char *)varInfoStruct
.varName
,
3791 (const char *)varNameStr
,
3792 strlen(varNameStr
) + 1 );
3795 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3797 // pmCPU only assigns numerical id's when a new varName is specified
3799 && (*varIndex
== kCPUUnknownIndex
))
3801 // pmCPUControl has assigned us a new variable ID.
3802 // Let's re-read the structure we just SET to learn that ID.
3803 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3807 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3808 *varIndex
= varInfoStruct
.varID
;
3814 #endif /* __i386__ || __x86_64__ */
3818 // MARK: Deep Sleep Policy
3822 //******************************************************************************
3823 // evaluateSystemSleepPolicy
3824 //******************************************************************************
3826 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3830 kIOPMSleepFlagHibernate
= 0x00000001,
3831 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3834 struct IOPMSystemSleepPolicyEntry
3836 uint32_t factorMask
;
3837 uint32_t factorBits
;
3838 uint32_t sleepFlags
;
3839 uint32_t wakeEvents
;
3840 } __attribute__((packed
));
3842 struct IOPMSystemSleepPolicyTable
3846 uint16_t entryCount
;
3847 IOPMSystemSleepPolicyEntry entries
[];
3848 } __attribute__((packed
));
3851 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3852 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3856 getSleepTypeAttributes( uint32_t sleepType
)
3858 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3863 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3864 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3865 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3866 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3870 if (sleepType
>= kIOPMSleepTypeLast
)
3873 return sleepTypeAttributes
[sleepType
];
3876 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3877 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3879 const IOPMSystemSleepPolicyTable
* pt
;
3880 OSObject
* prop
= 0;
3881 OSData
* policyData
;
3882 uint64_t currentFactors
= 0;
3883 uint32_t standbyDelay
= 0;
3884 uint32_t powerOffDelay
= 0;
3885 uint32_t powerOffTimer
= 0;
3887 bool standbyEnabled
;
3888 bool powerOffEnabled
;
3891 // Get platform's sleep policy table
3892 if (!gSleepPolicyHandler
)
3894 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3895 if (!prop
) goto done
;
3898 // Fetch additional settings
3899 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3900 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3901 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3902 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3903 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3904 powerOffTimer
= powerOffDelay
;
3906 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3907 sleepPhase
, standbyEnabled
, standbyDelay
,
3908 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3910 // pmset level overrides
3911 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3913 if (!gSleepPolicyHandler
)
3915 standbyEnabled
= false;
3916 powerOffEnabled
= false;
3919 else if (!(*hibMode
& kIOHibernateModeSleep
))
3921 // Force hibernate (i.e. mode 25)
3922 // If standby is enabled, force standy.
3923 // If poweroff is enabled, force poweroff.
3925 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3926 else if (powerOffEnabled
)
3927 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3929 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3932 // Current factors based on environment and assertions
3933 if (sleepTimerMaintenance
)
3934 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3935 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
3936 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3937 if (!clamshellClosed
)
3938 currentFactors
|= kIOPMSleepFactorLidOpen
;
3939 if (acAdaptorConnected
)
3940 currentFactors
|= kIOPMSleepFactorACPower
;
3941 if (lowBatteryCondition
)
3942 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3944 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3945 if (!standbyEnabled
)
3946 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3947 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3948 kIOPMDriverAssertionLevelOff
)
3949 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3950 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3951 kIOPMDriverAssertionLevelOff
)
3952 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3953 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3954 kIOPMDriverAssertionLevelOff
)
3955 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3956 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3957 kIOPMDriverAssertionLevelOff
)
3958 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3959 if (_scheduledAlarms
!= 0)
3960 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3961 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3962 kIOPMDriverAssertionLevelOff
)
3963 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3964 #define TCPKEEPALIVE 1
3966 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
3967 kIOPMDriverAssertionLevelOff
)
3968 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
3970 if (!powerOffEnabled
)
3971 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3973 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3975 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
3976 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
3977 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
3978 if (thermalWarningState
)
3979 currentFactors
|= kIOPMSleepFactorThermalWarning
;
3981 DLOG("sleep factors 0x%llx\n", currentFactors
);
3983 if (gSleepPolicyHandler
)
3985 uint32_t savedHibernateMode
;
3988 if (!gSleepPolicyVars
)
3990 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3991 if (!gSleepPolicyVars
)
3993 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3995 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3996 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3997 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3998 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3999 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4000 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4001 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4002 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4003 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4004 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4005 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4007 if (kIOPMSleepPhase0
== sleepPhase
)
4009 // preserve hibernateMode
4010 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4011 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4013 else if (kIOPMSleepPhase1
== sleepPhase
)
4015 // use original hibernateMode for phase2
4016 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4019 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4021 if (kIOPMSleepPhase0
== sleepPhase
)
4023 // restore hibernateMode
4024 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4027 if ((result
!= kIOReturnSuccess
) ||
4028 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4029 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4030 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4032 MSG("sleep policy handler error\n");
4036 if ((getSleepTypeAttributes(params
->sleepType
) &
4037 kIOPMSleepAttributeHibernateSetup
) &&
4038 ((*hibMode
& kIOHibernateModeOn
) == 0))
4040 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4043 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4044 params
->version
, params
->sleepType
, params
->sleepFlags
,
4045 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4050 // Policy table is meaningless without standby enabled
4051 if (!standbyEnabled
)
4054 // Validate the sleep policy table
4055 policyData
= OSDynamicCast(OSData
, prop
);
4056 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4059 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4060 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4061 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4064 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4065 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4068 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4070 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4071 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4073 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4074 entry
->factorMask
, entry
->factorBits
,
4075 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4079 DLOG("^ found match\n");
4082 params
->version
= kIOPMSystemSleepParametersVersion
;
4083 params
->reserved1
= 1;
4084 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4085 params
->sleepType
= kIOPMSleepTypeStandby
;
4087 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4089 params
->ecWakeEvents
= entry
->wakeEvents
;
4090 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4092 if (kIOPMSleepPhase2
== sleepPhase
)
4094 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4096 if (!_standbyTimerResetSeconds
||
4097 (now_secs
<= _standbyTimerResetSeconds
))
4099 // Reset standby timer adjustment
4100 _standbyTimerResetSeconds
= now_secs
;
4101 DLOG("standby delay %u, reset %u\n",
4102 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4104 else if (standbyDelay
)
4106 // Shorten the standby delay timer
4107 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4108 if (standbyDelay
> elapsed
)
4109 standbyDelay
-= elapsed
;
4111 standbyDelay
= 1; // must be > 0
4113 DLOG("standby delay %u, elapsed %u\n",
4114 standbyDelay
, (uint32_t) elapsed
);
4117 params
->ecWakeTimer
= standbyDelay
;
4119 else if (kIOPMSleepPhase2
== sleepPhase
)
4121 // A sleep that does not enable the sleep timer will reset
4122 // the standby delay adjustment.
4123 _standbyTimerResetSeconds
= 0;
4135 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4137 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4139 // Evaluate early (priority interest phase), before drivers sleep.
4141 DLOG("%s\n", __FUNCTION__
);
4142 removeProperty(kIOPMSystemSleepParametersKey
);
4144 // Full wake resets the standby timer delay adjustment
4145 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4146 _standbyTimerResetSeconds
= 0;
4148 hibernateDisabled
= false;
4150 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4152 // Save for late evaluation if sleep is aborted
4153 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4155 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4158 if (!hibernateRetry
&&
4159 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4160 kIOPMSleepAttributeHibernateSetup
) == 0))
4162 // skip hibernate setup
4163 hibernateDisabled
= true;
4167 // Publish IOPMSystemSleepType
4168 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4169 if (sleepType
== kIOPMSleepTypeInvalid
)
4172 sleepType
= kIOPMSleepTypeNormalSleep
;
4173 if (hibernateMode
& kIOHibernateModeOn
)
4174 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4175 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4177 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4178 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4180 // report the lowest possible sleep state
4181 sleepType
= kIOPMSleepTypePowerOff
;
4184 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4187 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4189 IOPMSystemSleepParameters params
;
4190 OSData
* paramsData
;
4192 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4194 DLOG("%s\n", __FUNCTION__
);
4196 bzero(¶ms
, sizeof(params
));
4197 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4199 if ((hibernateDisabled
|| hibernateAborted
) &&
4200 (getSleepTypeAttributes(params
.sleepType
) &
4201 kIOPMSleepAttributeHibernateSetup
))
4203 // Final evaluation picked a state requiring hibernation,
4204 // but hibernate setup was skipped. Arm a short sleep using
4205 // the early non-hibernate sleep parameters.
4206 // Set hibernateRetry flag to force hibernate setup on the
4209 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4210 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4211 params
.ecWakeTimer
= 1;
4212 hibernateRetry
= true;
4213 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
4214 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
4218 hibernateRetry
= false;
4221 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4224 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4225 paramsData
->release();
4228 if (getSleepTypeAttributes(params
.sleepType
) &
4229 kIOPMSleepAttributeHibernateSleep
)
4231 // Disable sleep to force hibernation
4232 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4237 bool IOPMrootDomain::getHibernateSettings(
4238 uint32_t * hibernateModePtr
,
4239 uint32_t * hibernateFreeRatio
,
4240 uint32_t * hibernateFreeTime
)
4242 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4243 // has updated the hibernateDisabled flag.
4245 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4246 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4247 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4248 if (hibernateDisabled
)
4249 *hibernateModePtr
= 0;
4250 else if (gSleepPolicyHandler
)
4251 *hibernateModePtr
= hibernateMode
;
4252 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4256 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4258 OSObject
* optionsProp
;
4259 OSDictionary
* optionsDict
;
4264 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4265 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4269 obj
= optionsDict
->getObject(key
);
4270 if (obj
) obj
->retain();
4274 obj
= copyProperty(key
);
4278 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4280 *option
= num
->unsigned32BitValue();
4283 else if (OSDynamicCast(OSBoolean
, obj
))
4285 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4293 optionsProp
->release();
4297 #endif /* HIBERNATION */
4299 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4302 IOPMSystemSleepParameters params
;
4303 uint32_t hibMode
= 0;
4306 if (gIOPMWorkLoop
->inGate() == false)
4308 IOReturn ret
= gIOPMWorkLoop
->runAction(
4309 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4310 &IOPMrootDomain::getSystemSleepType
),
4312 (void *) sleepType
);
4316 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4317 bzero(¶ms
, sizeof(params
));
4319 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4322 *sleepType
= params
.sleepType
;
4323 return kIOReturnSuccess
;
4327 return kIOReturnUnsupported
;
4331 // MARK: Shutdown and Restart
4333 //******************************************************************************
4334 // handlePlatformHaltRestart
4336 //******************************************************************************
4338 struct HaltRestartApplierContext
{
4339 IOPMrootDomain
* RootDomain
;
4340 unsigned long PowerState
;
4341 IOPMPowerFlags PowerFlags
;
4344 const char * LogString
;
4348 platformHaltRestartApplier( OSObject
* object
, void * context
)
4350 IOPowerStateChangeNotification notify
;
4351 HaltRestartApplierContext
* ctx
;
4352 AbsoluteTime startTime
;
4355 ctx
= (HaltRestartApplierContext
*) context
;
4357 memset(¬ify
, 0, sizeof(notify
));
4358 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4359 notify
.returnValue
= 0;
4360 notify
.stateNumber
= ctx
->PowerState
;
4361 notify
.stateFlags
= ctx
->PowerFlags
;
4363 clock_get_uptime(&startTime
);
4364 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4365 deltaTime
= computeDeltaTimeMS(&startTime
);
4367 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4368 (gIOKitDebug
& kIOLogPMRootDomain
))
4370 _IOServiceInterestNotifier
* notifier
;
4371 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4373 // IOService children of IOPMrootDomain are not instrumented.
4374 // Only IORootParent currently falls under that group.
4378 LOG("%s handler %p took %u ms\n",
4379 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4386 static void quiescePowerTreeCallback( void * target
, void * param
)
4388 IOLockLock(gPMHaltLock
);
4390 thread_wakeup(param
);
4391 IOLockUnlock(gPMHaltLock
);
4394 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4396 HaltRestartApplierContext ctx
;
4397 AbsoluteTime startTime
;
4400 memset(&ctx
, 0, sizeof(ctx
));
4401 ctx
.RootDomain
= this;
4403 clock_get_uptime(&startTime
);
4407 case kPEUPSDelayHaltCPU
:
4408 ctx
.PowerState
= OFF_STATE
;
4409 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4410 ctx
.LogString
= "PowerOff";
4414 ctx
.PowerState
= RESTART_STATE
;
4415 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4416 ctx
.LogString
= "Restart";
4420 ctx
.PowerState
= ON_STATE
;
4421 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4422 ctx
.LogString
= "PagingOff";
4423 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4425 IOHibernateSystemRestart();
4433 // Notify legacy clients
4434 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4436 // For normal shutdown, turn off File Server Mode.
4437 if (kPEHaltCPU
== pe_type
)
4439 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4440 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4443 setPMSetting(setting
, num
);
4449 if (kPEPagingOff
!= pe_type
)
4451 // Notify in power tree order
4452 notifySystemShutdown(this, ctx
.MessageType
);
4455 IOCPURunPlatformHaltRestartActions(pe_type
);
4457 // Wait for PM to quiesce
4458 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4460 AbsoluteTime quiesceTime
= mach_absolute_time();
4462 IOLockLock(gPMHaltLock
);
4463 gPMQuiesced
= false;
4464 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4467 while (!gPMQuiesced
)
4469 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4472 IOLockUnlock(gPMHaltLock
);
4474 deltaTime
= computeDeltaTimeMS(&quiesceTime
);
4475 DLOG("PM quiesce took %u ms\n", deltaTime
);
4478 deltaTime
= computeDeltaTimeMS(&startTime
);
4479 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4482 //******************************************************************************
4485 //******************************************************************************
4487 IOReturn
IOPMrootDomain::shutdownSystem( void )
4489 return kIOReturnUnsupported
;
4492 //******************************************************************************
4495 //******************************************************************************
4497 IOReturn
IOPMrootDomain::restartSystem( void )
4499 return kIOReturnUnsupported
;
4503 // MARK: System Capability
4505 //******************************************************************************
4506 // tagPowerPlaneService
4508 // Running on PM work loop thread.
4509 //******************************************************************************
4511 void IOPMrootDomain::tagPowerPlaneService(
4512 IOService
* service
,
4513 IOPMActions
* actions
)
4516 bool isDisplayWrangler
;
4518 memset(actions
, 0, sizeof(*actions
));
4519 actions
->target
= this;
4521 if (service
== this)
4523 actions
->actionPowerChangeStart
=
4524 OSMemberFunctionCast(
4525 IOPMActionPowerChangeStart
, this,
4526 &IOPMrootDomain::handleOurPowerChangeStart
);
4528 actions
->actionPowerChangeDone
=
4529 OSMemberFunctionCast(
4530 IOPMActionPowerChangeDone
, this,
4531 &IOPMrootDomain::handleOurPowerChangeDone
);
4533 actions
->actionPowerChangeOverride
=
4534 OSMemberFunctionCast(
4535 IOPMActionPowerChangeOverride
, this,
4536 &IOPMrootDomain::overrideOurPowerChange
);
4541 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4542 if (isDisplayWrangler
)
4547 isDisplayWrangler
= false;
4550 #if defined(__i386__) || defined(__x86_64__)
4551 if (isDisplayWrangler
)
4552 flags
|= kPMActionsFlagIsDisplayWrangler
;
4553 if (service
->getProperty("IOPMStrictTreeOrder"))
4554 flags
|= kPMActionsFlagIsGraphicsDevice
;
4555 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4556 flags
|= kPMActionsFlagIsAudioDevice
;
4559 // Find the power connection object that is a child of the PCI host
4560 // bridge, and has a graphics/audio device attached below. Mark the
4561 // power branch for delayed child notifications.
4565 IORegistryEntry
* child
= service
;
4566 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4568 while (child
!= this)
4570 if ((parent
== pciHostBridgeDriver
) ||
4573 if (OSDynamicCast(IOPowerConnection
, child
))
4575 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4576 conn
->delayChildNotification
= true;
4581 parent
= child
->getParentEntry(gIOPowerPlane
);
4587 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4588 actions
->parameter
|= flags
;
4589 actions
->actionPowerChangeOverride
=
4590 OSMemberFunctionCast(
4591 IOPMActionPowerChangeOverride
, this,
4592 &IOPMrootDomain::overridePowerChangeForUIService
);
4594 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4596 actions
->actionActivityTickle
=
4597 OSMemberFunctionCast(
4598 IOPMActionActivityTickle
, this,
4599 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4601 actions
->actionUpdatePowerClient
=
4602 OSMemberFunctionCast(
4603 IOPMActionUpdatePowerClient
, this,
4604 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4609 // Locate the first PCI host bridge for PMTrace.
4610 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4612 IOService
* provider
= service
->getProvider();
4613 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4614 provider
->inPlane(gIODTPlane
))
4616 pciHostBridgeDevice
= provider
;
4617 pciHostBridgeDriver
= service
;
4618 DLOG("PMTrace found PCI host bridge %s->%s\n",
4619 provider
->getName(), service
->getName());
4623 // Tag top-level PCI devices. The order of PMinit() call does not
4624 // change across boots and is used as the PCI bit number.
4625 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4627 // Would prefer to check built-in property, but tagPowerPlaneService()
4628 // is called before pciDevice->registerService().
4629 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4630 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4632 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4635 // Save the assigned bit for fast lookup.
4636 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4638 actions
->actionPowerChangeStart
=
4639 OSMemberFunctionCast(
4640 IOPMActionPowerChangeStart
, this,
4641 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4643 actions
->actionPowerChangeDone
=
4644 OSMemberFunctionCast(
4645 IOPMActionPowerChangeDone
, this,
4646 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4652 //******************************************************************************
4653 // PM actions for root domain
4654 //******************************************************************************
4656 void IOPMrootDomain::overrideOurPowerChange(
4657 IOService
* service
,
4658 IOPMActions
* actions
,
4659 IOPMPowerStateIndex
* inOutPowerState
,
4660 IOPMPowerChangeFlags
* inOutChangeFlags
,
4661 IOPMRequestTag requestTag
)
4663 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4664 uint32_t changeFlags
= *inOutChangeFlags
;
4665 uint32_t currentPowerState
= (uint32_t) getPowerState();
4667 if (changeFlags
& kIOPMParentInitiated
)
4669 // Root parent is permanently pegged at max power,
4670 // a parent initiated power change is unexpected.
4671 *inOutChangeFlags
|= kIOPMNotDone
;
4675 if (powerState
< currentPowerState
)
4677 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4679 // Root domain is dropping power state ON->SLEEP.
4680 // If system is in full wake, first enter dark wake by
4681 // converting the power drop to a capability change.
4682 // Once in dark wake, transition to sleep state ASAP.
4684 darkWakeToSleepASAP
= true;
4686 // Drop graphics and audio capability
4687 _desiredCapability
&= ~(
4688 kIOPMSystemCapabilityGraphics
|
4689 kIOPMSystemCapabilityAudio
);
4691 // Convert to capability change (ON->ON)
4692 *inOutPowerState
= ON_STATE
;
4693 *inOutChangeFlags
|= kIOPMSynchronize
;
4695 // Revert device desire from SLEEP to ON
4696 changePowerStateToPriv(ON_STATE
);
4700 // System is in dark wake, ok to drop power state.
4701 // Broadcast root powering down to entire tree.
4702 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4705 else if (powerState
> currentPowerState
)
4707 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4709 // Broadcast power up when waking from sleep, but not for the
4710 // initial power change at boot by checking for cpu capability.
4711 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4716 void IOPMrootDomain::handleOurPowerChangeStart(
4717 IOService
* service
,
4718 IOPMActions
* actions
,
4719 IOPMPowerStateIndex powerState
,
4720 IOPMPowerChangeFlags
* inOutChangeFlags
,
4721 IOPMRequestTag requestTag
)
4723 uint32_t changeFlags
= *inOutChangeFlags
;
4724 uint32_t currentPowerState
= (uint32_t) getPowerState();
4725 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4726 bool publishSleepReason
= false;
4728 _systemTransitionType
= kSystemTransitionNone
;
4729 _systemMessageClientMask
= 0;
4730 capabilityLoss
= false;
4731 toldPowerdCapWillChange
= false;
4733 if (lowBatteryCondition
)
4735 // Low battery notification may arrive after the initial sleep request
4736 // has been queued. Override the sleep reason so powerd and others can
4737 // treat this as an emergency sleep.
4738 sleepReason
= kIOPMSleepReasonLowPower
;
4741 // 1. Explicit capability change.
4743 if (changeFlags
& kIOPMSynchronize
)
4745 if (powerState
== ON_STATE
)
4747 if (changeFlags
& kIOPMSyncNoChildNotify
)
4748 _systemTransitionType
= kSystemTransitionNewCapClient
;
4750 _systemTransitionType
= kSystemTransitionCapability
;
4754 // 2. Going to sleep (cancellation still possible).
4756 else if (powerState
< currentPowerState
)
4757 _systemTransitionType
= kSystemTransitionSleep
;
4759 // 3. Woke from (idle or demand) sleep.
4761 else if (!systemBooting
&&
4762 (changeFlags
& kIOPMSelfInitiated
) &&
4763 (powerState
> currentPowerState
))
4765 _systemTransitionType
= kSystemTransitionWake
;
4766 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4767 kIOPMSystemCapabilityNetwork
;
4769 // Early exit from dark wake to full (e.g. LID open)
4770 if (kFullWakeReasonNone
!= fullWakeReason
)
4772 _desiredCapability
|= (
4773 kIOPMSystemCapabilityGraphics
|
4774 kIOPMSystemCapabilityAudio
);
4777 IOHibernateSetWakeCapabilities(_desiredCapability
);
4781 // Update pending wake capability at the beginning of every
4782 // state transition (including synchronize). This will become
4783 // the current capability at the end of the transition.
4785 if (kSystemTransitionSleep
== _systemTransitionType
)
4787 _pendingCapability
= 0;
4788 capabilityLoss
= true;
4790 // Clear previous stats
4791 IOLockLock(pmStatsLock
);
4792 if (pmStatsAppResponses
)
4794 pmStatsAppResponses
->release();
4795 pmStatsAppResponses
= OSArray::withCapacity(5);
4797 IOLockUnlock(pmStatsLock
);
4800 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4802 _pendingCapability
= _desiredCapability
|
4803 kIOPMSystemCapabilityCPU
|
4804 kIOPMSystemCapabilityNetwork
;
4806 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4807 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4809 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4810 (_pendingCapability
== _currentCapability
))
4812 // Cancel the PM state change.
4813 _systemTransitionType
= kSystemTransitionNone
;
4814 *inOutChangeFlags
|= kIOPMNotDone
;
4816 if (__builtin_popcount(_pendingCapability
) <
4817 __builtin_popcount(_currentCapability
))
4818 capabilityLoss
= true;
4821 // 1. Capability change.
4823 if (kSystemTransitionCapability
== _systemTransitionType
)
4825 // Dark to Full transition.
4826 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4828 tracePoint( kIOPMTracePointDarkWakeExit
);
4830 willEnterFullWake();
4833 // Full to Dark transition.
4834 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4836 tracePoint( kIOPMTracePointDarkWakeEntry
);
4837 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4838 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4839 kSystemMessageClientLegacyApp
;
4843 // Prevent user active transitions before notifying clients
4844 // that system will sleep.
4845 preventTransitionToUserActive(true);
4847 IOService::setAdvisoryTickleEnable( false );
4849 // Publish the sleep reason for full to dark wake
4850 publishSleepReason
= true;
4851 lastSleepReason
= fullToDarkReason
= sleepReason
;
4853 // Publish a UUID for the Sleep --> Wake cycle
4854 handlePublishSleepWakeUUID(true);
4855 if (sleepDelaysReport
) {
4856 clock_get_uptime(&ts_sleepStart
);
4857 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
4864 else if (kSystemTransitionSleep
== _systemTransitionType
)
4866 // Beginning of a system sleep transition.
4867 // Cancellation is still possible.
4868 tracePoint( kIOPMTracePointSleepStarted
, sleepReason
);
4870 _systemMessageClientMask
= kSystemMessageClientAll
;
4871 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4872 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
4873 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4874 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4876 // Record the reason for dark wake back to sleep
4877 // System may not have ever achieved full wake
4879 publishSleepReason
= true;
4880 lastSleepReason
= sleepReason
;
4881 if (sleepDelaysReport
) {
4882 clock_get_uptime(&ts_sleepStart
);
4883 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
4889 else if (kSystemTransitionWake
== _systemTransitionType
)
4891 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4892 // Clear stats about sleep
4894 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4896 willEnterFullWake();
4900 // Message powerd only
4901 _systemMessageClientMask
= kSystemMessageClientPowerd
;
4902 tellClients(kIOMessageSystemWillPowerOn
);
4906 // The only location where the sleep reason is published. At this point
4907 // sleep can still be cancelled, but sleep reason should be published
4908 // early for logging purposes.
4910 if (publishSleepReason
)
4912 static const char * IOPMSleepReasons
[] =
4914 kIOPMClamshellSleepKey
,
4915 kIOPMPowerButtonSleepKey
,
4916 kIOPMSoftwareSleepKey
,
4917 kIOPMOSSwitchHibernationKey
,
4919 kIOPMLowPowerSleepKey
,
4920 kIOPMThermalEmergencySleepKey
,
4921 kIOPMMaintenanceSleepKey
,
4922 kIOPMSleepServiceExitKey
,
4923 kIOPMDarkWakeThermalEmergencyKey
4926 // Record sleep cause in IORegistry
4927 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
4928 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
4929 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
4930 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
4934 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4935 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4937 _systemStateGeneration
++;
4938 systemDarkWake
= false;
4940 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4942 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
4943 _systemTransitionType
, _systemStateGeneration
,
4944 _systemMessageClientMask
,
4945 _desiredCapability
, _currentCapability
, _pendingCapability
);
4949 void IOPMrootDomain::handleOurPowerChangeDone(
4950 IOService
* service
,
4951 IOPMActions
* actions
,
4952 IOPMPowerStateIndex powerState
,
4953 IOPMPowerChangeFlags changeFlags
,
4954 IOPMRequestTag requestTag __unused
)
4956 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4958 _systemTransitionType
= kSystemTransitionNone
;
4962 if (_systemTransitionType
!= kSystemTransitionNone
)
4964 uint32_t currentPowerState
= (uint32_t) getPowerState();
4966 if (changeFlags
& kIOPMNotDone
)
4968 // Power down was cancelled or vetoed.
4969 _pendingCapability
= _currentCapability
;
4970 lastSleepReason
= 0;
4972 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
4973 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4975 pmPowerStateQueue
->submitPowerEvent(
4976 kPowerEventPolicyStimulus
,
4977 (void *) kStimulusDarkWakeReentry
,
4978 _systemStateGeneration
);
4981 // Revert device desire to max.
4982 changePowerStateToPriv(ON_STATE
);
4986 // Send message on dark wake to full wake promotion.
4987 // tellChangeUp() handles the normal SLEEP->ON case.
4989 if (kSystemTransitionCapability
== _systemTransitionType
)
4991 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4993 lastSleepReason
= 0; // stop logging wrangler tickles
4994 tellClients(kIOMessageSystemHasPoweredOn
);
4996 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4998 // Going dark, reset full wake state
4999 // userIsActive will be cleared by wrangler powering down
5000 wranglerTickled
= false;
5001 fullWakeReason
= kFullWakeReasonNone
;
5003 if (ts_sleepStart
) {
5004 clock_get_uptime(&wake2DarkwakeDelay
);
5005 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5006 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5012 // Reset state after exiting from dark wake.
5014 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5015 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5017 darkWakeMaintenance
= false;
5018 darkWakeToSleepASAP
= false;
5019 pciCantSleepValid
= false;
5020 darkWakeSleepService
= false;
5022 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5024 // Remove the influence of display power assertion
5025 // before next system wake.
5026 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5027 kWranglerPowerStateMin
);
5028 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5032 // Entered dark mode.
5034 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5035 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5037 // Queue an evaluation of whether to remain in dark wake,
5038 // and for how long. This serves the purpose of draining
5039 // any assertions from the queue.
5041 pmPowerStateQueue
->submitPowerEvent(
5042 kPowerEventPolicyStimulus
,
5043 (void *) kStimulusDarkWakeEntry
,
5044 _systemStateGeneration
);
5048 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5049 "dcp %x:%x:%x, dbgtimer %u\n",
5050 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5051 _systemTransitionType
, _systemStateGeneration
,
5052 _systemMessageClientMask
,
5053 _desiredCapability
, _currentCapability
, _pendingCapability
,
5054 _lastDebugWakeSeconds
);
5056 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5059 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5060 if (clamshellExists
&& fullWakeThreadCall
&&
5061 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5063 // Not the initial graphics full power, graphics won't
5064 // send a power notification to trigger a lid state
5067 AbsoluteTime deadline
;
5068 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5069 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5073 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5076 // Update current system capability.
5077 if (_currentCapability
!= _pendingCapability
)
5078 _currentCapability
= _pendingCapability
;
5080 // Update highest system capability.
5082 _highestCapability
|= _currentCapability
;
5084 if (darkWakePostTickle
&&
5085 (kSystemTransitionWake
== _systemTransitionType
) &&
5086 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5087 kDarkWakeFlagHIDTickleLate
)
5089 darkWakePostTickle
= false;
5093 // Reset tracepoint at completion of capability change,
5094 // completion of wake transition, and aborted sleep transition.
5096 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5097 (_systemTransitionType
== kSystemTransitionWake
) ||
5098 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5099 (changeFlags
& kIOPMNotDone
)))
5101 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5102 tracePoint( kIOPMTracePointSystemUp
, 0 );
5105 _systemTransitionType
= kSystemTransitionNone
;
5106 _systemMessageClientMask
= 0;
5107 toldPowerdCapWillChange
= false;
5109 logGraphicsClamp
= false;
5113 //******************************************************************************
5114 // PM actions for graphics and audio.
5115 //******************************************************************************
5117 void IOPMrootDomain::overridePowerChangeForUIService(
5118 IOService
* service
,
5119 IOPMActions
* actions
,
5120 IOPMPowerStateIndex
* inOutPowerState
,
5121 IOPMPowerChangeFlags
* inOutChangeFlags
)
5123 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5124 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5126 if (kSystemTransitionNone
== _systemTransitionType
)
5128 // Not in midst of a system transition.
5129 // Do not modify power limit enable state.
5131 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5133 // Activate power limiter.
5135 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5136 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5137 (changeFlags
& kIOPMSynchronize
))
5139 actions
->parameter
|= kPMActionsFlagLimitPower
;
5141 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5142 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5143 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5144 (changeFlags
& kIOPMSynchronize
))
5146 actions
->parameter
|= kPMActionsFlagLimitPower
;
5148 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5149 (_systemTransitionType
== kSystemTransitionSleep
))
5151 // For graphics devices, arm the limiter when entering
5152 // system sleep. Not when dropping to dark wake.
5153 actions
->parameter
|= kPMActionsFlagLimitPower
;
5156 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5158 DLOG("+ plimit %s %p\n",
5159 service
->getName(), OBFUSCATE(service
));
5164 // Remove power limit.
5166 if ((actions
->parameter
& (
5167 kPMActionsFlagIsDisplayWrangler
|
5168 kPMActionsFlagIsGraphicsDevice
)) &&
5169 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5171 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5173 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5174 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5176 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5179 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5181 DLOG("- plimit %s %p\n",
5182 service
->getName(), OBFUSCATE(service
));
5186 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5188 uint32_t maxPowerState
= (uint32_t)(-1);
5190 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5192 // Enforce limit for system power/cap transitions.
5195 if ((service
->getPowerState() > maxPowerState
) &&
5196 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5200 // Remove lingering effects of any tickle before entering
5201 // dark wake. It will take a new tickle to return to full
5202 // wake, so the existing tickle state is useless.
5204 if (changeFlags
& kIOPMDomainDidChange
)
5205 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5207 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5214 // Deny all self-initiated changes when power is limited.
5215 // Wrangler tickle should never defeat the limiter.
5217 maxPowerState
= service
->getPowerState();
5220 if (powerState
> maxPowerState
)
5222 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5223 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5225 *inOutPowerState
= maxPowerState
;
5227 if (darkWakePostTickle
&&
5228 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5229 (changeFlags
& kIOPMDomainWillChange
) &&
5230 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5231 kDarkWakeFlagHIDTickleEarly
))
5233 darkWakePostTickle
= false;
5238 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5240 if (logGraphicsClamp
)
5245 clock_get_uptime(&now
);
5246 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5247 absolutetime_to_nanoseconds(now
, &nsec
);
5248 if (kIOLogPMRootDomain
& gIOKitDebug
)
5249 MSG("Graphics suppressed %u ms\n",
5250 ((int)((nsec
) / 1000000ULL)));
5252 graphicsSuppressed
= true;
5257 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5258 IOService
* service
,
5259 IOPMActions
* actions
)
5262 // Warning: Not running in PM work loop context - don't modify state !!!
5263 // Trap tickle directed to IODisplayWrangler while running with graphics
5264 // capability suppressed.
5266 assert(service
== wrangler
);
5268 clock_get_uptime(&userActivityTime
);
5269 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5270 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5271 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5273 userActivityCount
++;
5274 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5275 userActivityCount
, lastSleepReason
);
5278 if (!wranglerTickled
&&
5279 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5281 DLOG("display wrangler tickled\n");
5282 if (kIOLogPMRootDomain
& gIOKitDebug
)
5283 OSReportWithBacktrace("Dark wake display tickle");
5284 if (pmPowerStateQueue
)
5286 pmPowerStateQueue
->submitPowerEvent(
5287 kPowerEventPolicyStimulus
,
5288 (void *) kStimulusDarkWakeActivityTickle
,
5289 true /* set wake type */ );
5295 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5296 IOService
* service
,
5297 IOPMActions
* actions
,
5298 const OSSymbol
* powerClient
,
5299 IOPMPowerStateIndex oldPowerState
,
5300 IOPMPowerStateIndex newPowerState
)
5303 assert(service
== wrangler
);
5305 // This function implements half of the user active detection
5306 // by monitoring changes to the display wrangler's device desire.
5308 // User becomes active when either:
5309 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5310 // in max power state. This desire change in absence of a power state
5311 // change is detected within. This handles the case when user becomes
5312 // active while the display is already lit by setDisplayPowerOn().
5314 // 2. Power state change to max, and DeviceDesire is also at max.
5315 // Handled by displayWranglerNotification().
5317 // User becomes inactive when DeviceDesire drops to sleep state or below.
5319 DLOG("wrangler %s (ps %u, %u->%u)\n",
5320 powerClient
->getCStringNoCopy(),
5321 (uint32_t) service
->getPowerState(),
5322 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5324 if (powerClient
== gIOPMPowerClientDevice
)
5326 if ((newPowerState
> oldPowerState
) &&
5327 (newPowerState
== kWranglerPowerStateMax
) &&
5328 (service
->getPowerState() == kWranglerPowerStateMax
))
5330 evaluatePolicy( kStimulusEnterUserActiveState
);
5333 if ((newPowerState
< oldPowerState
) &&
5334 (newPowerState
<= kWranglerPowerStateSleep
))
5336 evaluatePolicy( kStimulusLeaveUserActiveState
);
5342 //******************************************************************************
5343 // User active state management
5344 //******************************************************************************
5346 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5349 _preventUserActive
= prevent
;
5350 if (wrangler
&& !_preventUserActive
)
5352 // Allowing transition to user active, but the wrangler may have
5353 // already powered ON in case of sleep cancel/revert. Poll the
5354 // same conditions checked for in displayWranglerNotification()
5355 // to bring the user active state up to date.
5357 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5358 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5359 kWranglerPowerStateMax
))
5361 evaluatePolicy( kStimulusEnterUserActiveState
);
5367 //******************************************************************************
5368 // Approve usage of delayed child notification by PM.
5369 //******************************************************************************
5371 bool IOPMrootDomain::shouldDelayChildNotification(
5372 IOService
* service
)
5374 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5375 (kFullWakeReasonNone
== fullWakeReason
) &&
5376 (kSystemTransitionWake
== _systemTransitionType
))
5378 DLOG("%s: delay child notify\n", service
->getName());
5384 //******************************************************************************
5385 // PM actions for PCI device.
5386 //******************************************************************************
5388 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5389 IOService
* service
,
5390 IOPMActions
* actions
,
5391 IOPMPowerStateIndex powerState
,
5392 IOPMPowerChangeFlags
* inOutChangeFlags
)
5394 pmTracer
->tracePCIPowerChange(
5395 PMTraceWorker::kPowerChangeStart
,
5396 service
, *inOutChangeFlags
,
5397 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5400 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5401 IOService
* service
,
5402 IOPMActions
* actions
,
5403 IOPMPowerStateIndex powerState
,
5404 IOPMPowerChangeFlags changeFlags
)
5406 pmTracer
->tracePCIPowerChange(
5407 PMTraceWorker::kPowerChangeCompleted
,
5408 service
, changeFlags
,
5409 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5412 //******************************************************************************
5415 // Override IOService::registerInterest() to intercept special clients.
5416 //******************************************************************************
5418 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5421 friend class IOPMrootDomain
;
5422 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5425 uint32_t ackTimeoutCnt
;
5429 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5431 IONotifier
* IOPMrootDomain::registerInterest(
5432 const OSSymbol
* typeOfInterest
,
5433 IOServiceInterestHandler handler
,
5434 void * target
, void * ref
)
5436 IOPMServiceInterestNotifier
*notifier
= 0;
5437 bool isSystemCapabilityClient
;
5438 bool isKernelCapabilityClient
;
5439 IOReturn rc
= kIOReturnError
;;
5441 isSystemCapabilityClient
=
5443 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5445 isKernelCapabilityClient
=
5447 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5449 if (isSystemCapabilityClient
)
5450 typeOfInterest
= gIOAppPowerStateInterest
;
5452 notifier
= new IOPMServiceInterestNotifier
;
5453 if (!notifier
) return NULL
;
5455 if (notifier
->init()) {
5456 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5458 if (rc
!= kIOReturnSuccess
) {
5459 notifier
->release();
5462 if (pmPowerStateQueue
)
5464 notifier
->ackTimeoutCnt
= 0;
5465 if (isSystemCapabilityClient
)
5468 if (pmPowerStateQueue
->submitPowerEvent(
5469 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5470 notifier
->release();
5473 if (isKernelCapabilityClient
)
5476 if (pmPowerStateQueue
->submitPowerEvent(
5477 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5478 notifier
->release();
5485 //******************************************************************************
5486 // systemMessageFilter
5488 //******************************************************************************
5490 bool IOPMrootDomain::systemMessageFilter(
5491 void * object
, void * arg1
, void * arg2
, void * arg3
)
5493 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5494 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5495 bool isCapClient
= false;
5499 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5500 (!isCapMsg
|| !_joinedCapabilityClients
||
5501 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5504 // Capability change message for app and kernel clients.
5508 if ((context
->notifyType
== kNotifyPriority
) ||
5509 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5512 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5513 (object
== (void *) systemCapabilityNotifier
))
5519 IOPMSystemCapabilityChangeParameters
* capArgs
=
5520 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5522 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5524 capArgs
->fromCapabilities
= 0;
5525 capArgs
->toCapabilities
= _currentCapability
;
5526 capArgs
->changeFlags
= 0;
5530 capArgs
->fromCapabilities
= _currentCapability
;
5531 capArgs
->toCapabilities
= _pendingCapability
;
5533 if (context
->isPreChange
)
5534 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5536 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5538 if ((object
== (void *) systemCapabilityNotifier
) &&
5539 context
->isPreChange
)
5541 toldPowerdCapWillChange
= true;
5545 // Capability change messages only go to the PM configd plugin.
5546 // Wait for response post-change if capabilitiy is increasing.
5547 // Wait for response pre-change if capability is decreasing.
5549 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5550 ( (capabilityLoss
&& context
->isPreChange
) ||
5551 (!capabilityLoss
&& !context
->isPreChange
) ) )
5553 // app has not replied yet, wait for it
5554 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5561 // Capability client will always see kIOMessageCanSystemSleep,
5562 // even for demand sleep. It will also have a chance to veto
5563 // sleep one last time after all clients have responded to
5564 // kIOMessageSystemWillSleep
5566 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5567 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5569 if (object
== (OSObject
*) systemCapabilityNotifier
)
5575 // Not idle sleep, don't ask apps.
5576 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5582 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5584 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5585 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5586 (fullToDarkReason
== kIOPMSleepReasonIdle
))
5591 // Reject capability change messages for legacy clients.
5592 // Reject legacy system sleep messages for capability client.
5594 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5599 // Filter system sleep messages.
5601 if ((context
->notifyType
== kNotifyApps
) &&
5602 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5604 IOPMServiceInterestNotifier
*notify
;
5607 if ((notify
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
))
5610 if (notify
->ackTimeoutCnt
>= 3)
5611 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5613 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5616 else if ((context
->notifyType
== kNotifyPriority
) &&
5617 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5624 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5626 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5627 if (_joinedCapabilityClients
->getCount() == 0)
5629 DLOG("destroyed capability client set %p\n",
5630 OBFUSCATE(_joinedCapabilityClients
));
5631 _joinedCapabilityClients
->release();
5632 _joinedCapabilityClients
= 0;
5639 //******************************************************************************
5640 // setMaintenanceWakeCalendar
5642 //******************************************************************************
5644 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5645 const IOPMCalendarStruct
* calendar
)
5651 return kIOReturnBadArgument
;
5653 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5655 return kIOReturnNoMemory
;
5657 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5658 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5659 if (kIOReturnSuccess
== ret
)
5660 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5662 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5664 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5665 if (kIOReturnSuccess
== ret
)
5666 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5668 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5675 // MARK: Display Wrangler
5677 //******************************************************************************
5678 // displayWranglerNotification
5680 // Handle the notification when the IODisplayWrangler changes power state.
5681 //******************************************************************************
5683 IOReturn
IOPMrootDomain::displayWranglerNotification(
5684 void * target
, void * refCon
,
5685 UInt32 messageType
, IOService
* service
,
5686 void * messageArgument
, vm_size_t argSize
)
5689 int displayPowerState
;
5690 IOPowerStateChangeNotification
* params
=
5691 (IOPowerStateChangeNotification
*) messageArgument
;
5693 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5694 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5695 return kIOReturnUnsupported
;
5699 return kIOReturnUnsupported
;
5701 displayPowerState
= params
->stateNumber
;
5702 DLOG("wrangler %s ps %d\n",
5703 getIOMessageString(messageType
), displayPowerState
);
5705 switch (messageType
) {
5706 case kIOMessageDeviceWillPowerOff
:
5707 // Display wrangler has dropped power due to display idle
5708 // or force system sleep.
5710 // 4 Display ON kWranglerPowerStateMax
5711 // 3 Display Dim kWranglerPowerStateDim
5712 // 2 Display Sleep kWranglerPowerStateSleep
5713 // 1 Not visible to user
5714 // 0 Not visible to user kWranglerPowerStateMin
5716 if (displayPowerState
<= kWranglerPowerStateSleep
)
5717 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5720 case kIOMessageDeviceHasPoweredOn
:
5721 // Display wrangler has powered on due to user activity
5722 // or wake from sleep.
5724 if (kWranglerPowerStateMax
== displayPowerState
)
5726 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5728 // See comment in handleUpdatePowerClientForDisplayWrangler
5729 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5730 kWranglerPowerStateMax
)
5732 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5738 return kIOReturnUnsupported
;
5741 //******************************************************************************
5742 // displayWranglerMatchPublished
5744 // Receives a notification when the IODisplayWrangler is published.
5745 // When it's published we install a power state change handler.
5746 //******************************************************************************
5748 bool IOPMrootDomain::displayWranglerMatchPublished(
5751 IOService
* newService
,
5752 IONotifier
* notifier __unused
)
5755 // found the display wrangler, now install a handler
5756 if( !newService
->registerInterest( gIOGeneralInterest
,
5757 &displayWranglerNotification
, target
, 0) )
5765 #if defined(__i386__) || defined(__x86_64__)
5767 bool IOPMrootDomain::IONVRAMMatchPublished(
5770 IOService
* newService
,
5771 IONotifier
* notifier
)
5773 unsigned int len
= 0;
5774 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5775 OSNumber
*statusCode
= NULL
;
5777 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5779 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5780 if (statusCode
!= NULL
) {
5781 if (statusCode
->unsigned64BitValue() != 0) {
5782 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5783 MSG("System was rebooted due to Sleep/Wake failure\n");
5786 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5787 MSG("System was non-responsive and was rebooted by watchdog\n");
5791 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5793 if (notifier
) notifier
->remove();
5798 bool IOPMrootDomain::IONVRAMMatchPublished(
5801 IOService
* newService
,
5802 IONotifier
* notifier __unused
)
5809 //******************************************************************************
5812 //******************************************************************************
5814 void IOPMrootDomain::reportUserInput( void )
5818 OSDictionary
* matching
;
5822 matching
= serviceMatching("IODisplayWrangler");
5823 iter
= getMatchingServices(matching
);
5824 if (matching
) matching
->release();
5827 wrangler
= (IOService
*) iter
->getNextObject();
5833 wrangler
->activityTickle(0,0);
5837 //******************************************************************************
5838 // latchDisplayWranglerTickle
5839 //******************************************************************************
5841 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5846 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5847 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5848 !checkSystemCanSustainFullWake())
5850 // Currently in dark wake, and not transitioning to full wake.
5851 // Full wake is unsustainable, so latch the tickle to prevent
5852 // the display from lighting up momentarily.
5853 wranglerTickleLatched
= true;
5857 wranglerTickleLatched
= false;
5860 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5862 wranglerTickleLatched
= false;
5864 pmPowerStateQueue
->submitPowerEvent(
5865 kPowerEventPolicyStimulus
,
5866 (void *) kStimulusDarkWakeActivityTickle
);
5869 return wranglerTickleLatched
;
5875 //******************************************************************************
5876 // setDisplayPowerOn
5878 // For root domain user client
5879 //******************************************************************************
5881 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
5883 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
5884 (void *) 0, options
);
5890 //******************************************************************************
5893 // Notification on battery class IOPowerSource appearance
5894 //******************************************************************************
5896 bool IOPMrootDomain::batteryPublished(
5899 IOService
* resourceService
,
5900 IONotifier
* notifier __unused
)
5902 // rdar://2936060&4435589
5903 // All laptops have dimmable LCD displays
5904 // All laptops have batteries
5905 // So if this machine has a battery, publish the fact that the backlight
5906 // supports dimming.
5907 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5913 // MARK: System PM Policy
5915 //******************************************************************************
5916 // checkSystemSleepAllowed
5918 //******************************************************************************
5920 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
5921 uint32_t sleepReason
)
5925 // Conditions that prevent idle and demand system sleep.
5928 if (userDisabledAllSleep
)
5930 err
= 1; // 1. user-space sleep kill switch
5934 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
5936 err
= 2; // 2. restart or shutdown in progress
5943 // Conditions above pegs the system at full wake.
5944 // Conditions below prevent system sleep but does not prevent
5945 // dark wake, and must be called from gated context.
5948 err
= 3; // 3. config does not support sleep
5952 if (lowBatteryCondition
|| thermalWarningState
)
5954 break; // always sleep on low battery or when in thermal warning state
5957 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
5959 break; // always sleep on dark wake thermal emergencies
5962 if (preventSystemSleepList
->getCount() != 0)
5964 err
= 4; // 4. child prevent system sleep clamp
5968 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5969 kIOPMDriverAssertionLevelOn
)
5971 err
= 5; // 5. CPU assertion
5975 if (pciCantSleepValid
)
5977 if (pciCantSleepFlag
)
5978 err
= 6; // 6. PCI card does not support PM (cached)
5981 else if (sleepSupportedPEFunction
&&
5982 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5985 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5986 ret
= getPlatform()->callPlatformFunction(
5987 sleepSupportedPEFunction
, false,
5988 NULL
, NULL
, NULL
, NULL
);
5989 pciCantSleepValid
= true;
5990 pciCantSleepFlag
= false;
5991 if ((platformSleepSupport
& kPCICantSleep
) ||
5992 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5994 err
= 6; // 6. PCI card does not support PM
5995 pciCantSleepFlag
= true;
6004 DLOG("System sleep prevented by %d\n", err
);
6010 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6012 return checkSystemSleepAllowed(0, 0);
6015 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6018 return checkSystemSleepAllowed(1, sleepReason
);
6021 //******************************************************************************
6022 // checkSystemCanSustainFullWake
6023 //******************************************************************************
6025 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6028 if (lowBatteryCondition
|| thermalWarningState
)
6030 // Low battery wake, or received a low battery notification
6031 // while system is awake. This condition will persist until
6032 // the following wake.
6036 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6038 // Graphics state is unknown and external display might not be probed.
6039 // Do not incorporate state that requires graphics to be in max power
6040 // such as desktopMode or clamshellDisabled.
6042 if (!acAdaptorConnected
)
6044 DLOG("full wake check: no AC\n");
6052 //******************************************************************************
6055 // Conditions that affect our wake/sleep decision has changed.
6056 // If conditions dictate that the system must remain awake, clamp power
6057 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6058 // is TRUE, then remove the power clamp and allow the power state to drop
6060 //******************************************************************************
6062 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6064 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
6065 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
6069 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
6071 changePowerStateToPriv(ON_STATE
);
6073 else if ( sleepASAP
)
6075 changePowerStateToPriv(SLEEP_STATE
);
6079 void IOPMrootDomain::handleDisplayPowerOn( )
6081 if (!wrangler
) return;
6082 if (displayPowerOnRequested
)
6084 if (!checkSystemCanSustainFullWake()) return;
6086 // Force wrangler to max power state. If system is in dark wake
6087 // this alone won't raise the wrangler's power state.
6089 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6091 // System in dark wake, always requesting full wake should
6092 // not have any bad side-effects, even if the request fails.
6094 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6096 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6097 requestFullWake( kFullWakeReasonDisplayOn
);
6102 // Relenquish desire to power up display.
6103 // Must first transition to state 1 since wrangler doesn't
6104 // power off the displays at state 0. At state 0 the root
6105 // domain is removed from the wrangler's power client list.
6107 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6108 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6114 //******************************************************************************
6115 // dispatchPowerEvent
6117 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6118 //******************************************************************************
6120 void IOPMrootDomain::dispatchPowerEvent(
6121 uint32_t event
, void * arg0
, uint64_t arg1
)
6123 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6128 case kPowerEventFeatureChanged
:
6129 messageClients(kIOPMMessageFeatureChange
, this);
6132 case kPowerEventReceivedPowerNotification
:
6133 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6136 case kPowerEventSystemBootCompleted
:
6139 systemBooting
= false;
6141 if (lowBatteryCondition
)
6143 privateSleepSystem (kIOPMSleepReasonLowPower
);
6145 // The rest is unnecessary since the system is expected
6146 // to sleep immediately. The following wake will update
6151 if (swd_flags
& SWD_VALID_LOGS
) {
6152 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6153 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6154 swd_logBufMap
->release();
6157 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6158 sleepWakeDebugDumpFromFile();
6160 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6161 // If logs are invalid, write the failure code
6162 sleepWakeDebugDumpFromMem(NULL
);
6164 // If lid is closed, re-send lid closed notification
6165 // now that booting is complete.
6166 if ( clamshellClosed
)
6168 handlePowerNotification(kLocalEvalClamshellCommand
);
6170 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6175 case kPowerEventSystemShutdown
:
6176 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6178 /* We set systemShutdown = true during shutdown
6179 to prevent sleep at unexpected times while loginwindow is trying
6180 to shutdown apps and while the OS is trying to transition to
6183 Set to true during shutdown, as soon as loginwindow shows
6184 the "shutdown countdown dialog", through individual app
6185 termination, and through black screen kernel shutdown.
6187 systemShutdown
= true;
6190 A shutdown was initiated, but then the shutdown
6191 was cancelled, clearing systemShutdown to false here.
6193 systemShutdown
= false;
6197 case kPowerEventUserDisabledSleep
:
6198 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6201 case kPowerEventRegisterSystemCapabilityClient
:
6202 if (systemCapabilityNotifier
)
6204 systemCapabilityNotifier
->release();
6205 systemCapabilityNotifier
= 0;
6209 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6210 systemCapabilityNotifier
->retain();
6212 /* intentional fall-through */
6214 case kPowerEventRegisterKernelCapabilityClient
:
6215 if (!_joinedCapabilityClients
)
6216 _joinedCapabilityClients
= OSSet::withCapacity(8);
6219 IONotifier
* notify
= (IONotifier
*) arg0
;
6220 if (_joinedCapabilityClients
)
6222 _joinedCapabilityClients
->setObject(notify
);
6223 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6229 case kPowerEventPolicyStimulus
:
6232 int stimulus
= (uintptr_t) arg0
;
6233 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6237 case kPowerEventAssertionCreate
:
6239 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6244 case kPowerEventAssertionRelease
:
6246 pmAssertions
->handleReleaseAssertion(arg1
);
6250 case kPowerEventAssertionSetLevel
:
6252 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6256 case kPowerEventQueueSleepWakeUUID
:
6257 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6259 case kPowerEventPublishSleepWakeUUID
:
6260 handlePublishSleepWakeUUID((bool)arg0
);
6263 case kPowerEventSetDisplayPowerOn
:
6264 if (!wrangler
) break;
6267 displayPowerOnRequested
= true;
6271 displayPowerOnRequested
= false;
6273 handleDisplayPowerOn();
6278 //******************************************************************************
6279 // systemPowerEventOccurred
6281 // The power controller is notifying us of a hardware-related power management
6282 // event that we must handle.
6284 // systemPowerEventOccurred covers the same functionality that
6285 // receivePowerNotification does; it simply provides a richer API for conveying
6286 // more information.
6287 //******************************************************************************
6289 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6290 const OSSymbol
*event
,
6293 IOReturn attempt
= kIOReturnSuccess
;
6294 OSNumber
*newNumber
= NULL
;
6297 return kIOReturnBadArgument
;
6299 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6301 return kIOReturnInternalError
;
6303 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6305 newNumber
->release();
6310 void IOPMrootDomain::setThermalState(OSObject
*value
)
6314 if (gIOPMWorkLoop
->inGate() == false) {
6315 gIOPMWorkLoop
->runAction(
6316 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6322 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6323 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6324 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6328 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6329 const OSSymbol
*event
,
6332 OSDictionary
*thermalsDict
= NULL
;
6333 bool shouldUpdate
= true;
6335 if (!event
|| !value
)
6336 return kIOReturnBadArgument
;
6339 // We reuse featuresDict Lock because it already exists and guards
6340 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6341 // of stepping on that lock.
6342 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6344 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6346 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6347 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6349 thermalsDict
= OSDictionary::withCapacity(1);
6352 if (!thermalsDict
) {
6353 shouldUpdate
= false;
6357 thermalsDict
->setObject (event
, value
);
6359 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6361 thermalsDict
->release();
6365 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6369 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6370 setThermalState(value
);
6372 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6375 return kIOReturnSuccess
;
6378 //******************************************************************************
6379 // receivePowerNotification
6381 // The power controller is notifying us of a hardware-related power management
6382 // event that we must handle. This may be a result of an 'environment' interrupt
6383 // from the power mgt micro.
6384 //******************************************************************************
6386 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6388 pmPowerStateQueue
->submitPowerEvent(
6389 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6390 return kIOReturnSuccess
;
6393 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6395 bool eval_clamshell
= false;
6400 * Local (IOPMrootDomain only) eval clamshell command
6402 if (msg
& kLocalEvalClamshellCommand
)
6404 eval_clamshell
= true;
6410 if (msg
& kIOPMOverTemp
)
6412 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6413 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6417 * Forward DW thermal notification to client, if system is not going to sleep
6419 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6421 DLOG("DarkWake thermal limits message received!\n");
6423 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6429 if (msg
& kIOPMSleepNow
)
6431 privateSleepSystem (kIOPMSleepReasonSoftware
);
6437 if (msg
& kIOPMPowerEmergency
)
6439 lowBatteryCondition
= true;
6440 privateSleepSystem (kIOPMSleepReasonLowPower
);
6446 if (msg
& kIOPMClamshellOpened
)
6448 // Received clamshel open message from clamshell controlling driver
6449 // Update our internal state and tell general interest clients
6450 clamshellClosed
= false;
6451 clamshellExists
= true;
6453 // Don't issue a hid tickle when lid is open and polled on wake
6454 if (msg
& kIOPMSetValue
)
6456 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6461 informCPUStateChange(kInformLid
, 0);
6463 // Tell general interest clients
6464 sendClientClamshellNotification();
6466 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6467 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6468 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6469 if (aborting
) userActivityCount
++;
6470 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6475 * Send the clamshell interest notification since the lid is closing.
6477 if (msg
& kIOPMClamshellClosed
)
6479 // Received clamshel open message from clamshell controlling driver
6480 // Update our internal state and tell general interest clients
6481 clamshellClosed
= true;
6482 clamshellExists
= true;
6485 informCPUStateChange(kInformLid
, 1);
6487 // Tell general interest clients
6488 sendClientClamshellNotification();
6490 // And set eval_clamshell = so we can attempt
6491 eval_clamshell
= true;
6495 * Set Desktop mode (sent from graphics)
6497 * -> reevaluate lid state
6499 if (msg
& kIOPMSetDesktopMode
)
6501 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6502 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6504 sendClientClamshellNotification();
6506 // Re-evaluate the lid state
6507 eval_clamshell
= true;
6511 * AC Adaptor connected
6513 * -> reevaluate lid state
6515 if (msg
& kIOPMSetACAdaptorConnected
)
6517 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6518 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6521 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6523 // Tell BSD if AC is connected
6524 // 0 == external power source; 1 == on battery
6525 post_sys_powersource(acAdaptorConnected
? 0:1);
6527 sendClientClamshellNotification();
6529 // Re-evaluate the lid state
6530 eval_clamshell
= true;
6532 // Lack of AC may have latched a display wrangler tickle.
6533 // This mirrors the hardware's USB wake event latch, where a latched
6534 // USB wake event followed by an AC attach will trigger a full wake.
6535 latchDisplayWranglerTickle( false );
6538 // AC presence will reset the standy timer delay adjustment.
6539 _standbyTimerResetSeconds
= 0;
6541 if (!userIsActive
) {
6542 // Reset userActivityTime when power supply is changed(rdr 13789330)
6543 clock_get_uptime(&userActivityTime
);
6548 * Enable Clamshell (external display disappear)
6550 * -> reevaluate lid state
6552 if (msg
& kIOPMEnableClamshell
)
6554 // Re-evaluate the lid state
6555 // System should sleep on external display disappearance
6556 // in lid closed operation.
6557 if (true == clamshellDisabled
)
6559 eval_clamshell
= true;
6562 clamshellDisabled
= false;
6563 sendClientClamshellNotification();
6567 * Disable Clamshell (external display appeared)
6568 * We don't bother re-evaluating clamshell state. If the system is awake,
6569 * the lid is probably open.
6571 if (msg
& kIOPMDisableClamshell
)
6573 clamshellDisabled
= true;
6574 sendClientClamshellNotification();
6578 * Evaluate clamshell and SLEEP if appropiate
6580 if (eval_clamshell
&& clamshellClosed
)
6582 if (shouldSleepOnClamshellClosed())
6583 privateSleepSystem (kIOPMSleepReasonClamshell
);
6585 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6591 if (msg
& kIOPMPowerButton
)
6593 if (!wranglerAsleep
)
6595 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6596 // Check that power button sleep is enabled
6598 if( kOSBooleanTrue
!= getProperty(pbs
))
6599 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6607 //******************************************************************************
6610 // Evaluate root-domain policy in response to external changes.
6611 //******************************************************************************
6613 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6617 int idleSleepEnabled
: 1;
6618 int idleSleepDisabled
: 1;
6619 int displaySleep
: 1;
6620 int sleepDelayChanged
: 1;
6621 int evaluateDarkWake
: 1;
6622 int adjustPowerState
: 1;
6623 int userBecameInactive
: 1;
6628 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6635 case kStimulusDisplayWranglerSleep
:
6636 if (!wranglerAsleep
)
6638 // first transition to wrangler sleep or lower
6639 wranglerAsleep
= true;
6640 flags
.bit
.displaySleep
= true;
6644 case kStimulusDisplayWranglerWake
:
6645 displayIdleForDemandSleep
= false;
6646 wranglerAsleep
= false;
6649 case kStimulusEnterUserActiveState
:
6650 if (_preventUserActive
)
6652 DLOG("user active dropped\n");
6657 userIsActive
= true;
6658 userWasActive
= true;
6660 // Stay awake after dropping demand for display power on
6661 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6662 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6664 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6665 messageClients(kIOPMMessageUserIsActiveChanged
);
6667 flags
.bit
.idleSleepDisabled
= true;
6670 case kStimulusLeaveUserActiveState
:
6673 userIsActive
= false;
6674 clock_get_uptime(&userBecameInactiveTime
);
6675 flags
.bit
.userBecameInactive
= true;
6677 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6678 messageClients(kIOPMMessageUserIsActiveChanged
);
6682 case kStimulusAggressivenessChanged
:
6684 unsigned long minutesToIdleSleep
= 0;
6685 unsigned long minutesToDisplayDim
= 0;
6686 unsigned long minutesDelta
= 0;
6688 // Fetch latest display and system sleep slider values.
6689 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6690 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6691 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6692 (uint32_t) sleepSlider
,
6693 (uint32_t) minutesToIdleSleep
,
6694 (uint32_t) minutesToDisplayDim
);
6696 DLOG("idle time -> %ld secs (ena %d)\n",
6697 idleSeconds
, (minutesToIdleSleep
!= 0));
6699 if (0x7fffffff == minutesToIdleSleep
)
6700 minutesToIdleSleep
= idleSeconds
;
6702 // How long to wait before sleeping the system once
6703 // the displays turns off is indicated by 'extraSleepDelay'.
6705 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6706 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6707 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6710 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6711 flags
.bit
.idleSleepEnabled
= true;
6713 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6714 flags
.bit
.idleSleepDisabled
= true;
6716 if (((minutesDelta
!= extraSleepDelay
) ||
6717 (userActivityTime
!= userActivityTime_prev
)) &&
6718 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6719 flags
.bit
.sleepDelayChanged
= true;
6721 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6722 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6724 // Reconsider decision to remain in dark wake
6725 flags
.bit
.evaluateDarkWake
= true;
6728 sleepSlider
= minutesToIdleSleep
;
6729 extraSleepDelay
= minutesDelta
;
6730 userActivityTime_prev
= userActivityTime
;
6733 case kStimulusDemandSystemSleep
:
6734 displayIdleForDemandSleep
= true;
6735 if (wrangler
&& wranglerIdleSettings
)
6737 // Request wrangler idle only when demand sleep is triggered
6739 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6741 wrangler
->setProperties(wranglerIdleSettings
);
6742 DLOG("Requested wrangler idle\n");
6745 // arg = sleepReason
6746 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6749 case kStimulusAllowSystemSleepChanged
:
6750 flags
.bit
.adjustPowerState
= true;
6753 case kStimulusDarkWakeActivityTickle
:
6754 // arg == true implies real and not self generated wrangler tickle.
6755 // Update wake type on PM work loop instead of the tickle thread to
6756 // eliminate the possibility of an early tickle clobbering the wake
6757 // type set by the platform driver.
6759 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6761 if (false == wranglerTickled
)
6763 if (latchDisplayWranglerTickle(true))
6765 DLOG("latched tickle\n");
6769 wranglerTickled
= true;
6770 DLOG("Requesting full wake after dark wake activity tickle\n");
6771 requestFullWake( kFullWakeReasonLocalUser
);
6775 case kStimulusDarkWakeEntry
:
6776 case kStimulusDarkWakeReentry
:
6777 // Any system transitions since the last dark wake transition
6778 // will invalid the stimulus.
6780 if (arg
== _systemStateGeneration
)
6782 DLOG("dark wake entry\n");
6783 systemDarkWake
= true;
6785 // Keep wranglerAsleep an invariant when wrangler is absent
6787 wranglerAsleep
= true;
6789 if (kStimulusDarkWakeEntry
== stimulus
)
6791 clock_get_uptime(&userBecameInactiveTime
);
6792 flags
.bit
.evaluateDarkWake
= true;
6795 // Always accelerate disk spindown while in dark wake,
6796 // even if system does not support/allow sleep.
6798 cancelIdleSleepTimer();
6799 setQuickSpinDownTimeout();
6803 case kStimulusDarkWakeEvaluate
:
6806 flags
.bit
.evaluateDarkWake
= true;
6810 case kStimulusNoIdleSleepPreventers
:
6811 flags
.bit
.adjustPowerState
= true;
6814 } /* switch(stimulus) */
6816 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6818 if (darkWakeToSleepASAP
||
6819 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6821 uint32_t newSleepReason
;
6823 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6825 // System was previously in full wake. Sleep reason from
6826 // full to dark already recorded in fullToDarkReason.
6828 if (lowBatteryCondition
)
6829 newSleepReason
= kIOPMSleepReasonLowPower
;
6831 newSleepReason
= fullToDarkReason
;
6835 // In dark wake from system sleep.
6837 if (darkWakeSleepService
)
6838 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6840 newSleepReason
= kIOPMSleepReasonMaintenance
;
6843 if (checkSystemCanSleep(newSleepReason
))
6845 privateSleepSystem(newSleepReason
);
6848 else // non-maintenance (network) dark wake
6850 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
6852 // Release power clamp, and wait for children idle.
6853 adjustPowerState(true);
6857 changePowerStateToPriv(ON_STATE
);
6864 // The rest are irrelevant while system is in dark wake.
6868 if ((flags
.bit
.displaySleep
) &&
6869 (kFullWakeReasonDisplayOn
== fullWakeReason
))
6871 // kIOPMSleepReasonMaintenance?
6872 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
6875 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
6877 bool cancelQuickSpindown
= false;
6879 if (flags
.bit
.sleepDelayChanged
)
6881 // Cancel existing idle sleep timer and quick disk spindown.
6882 // New settings will be applied by the idleSleepEnabled flag
6883 // handler below if idle sleep is enabled.
6885 DLOG("extra sleep timer changed\n");
6886 cancelIdleSleepTimer();
6887 cancelQuickSpindown
= true;
6891 DLOG("user inactive\n");
6894 if (!userIsActive
&& sleepSlider
)
6896 startIdleSleepTimer(getTimeToIdleSleep());
6899 if (cancelQuickSpindown
)
6900 restoreUserSpinDownTimeout();
6903 if (flags
.bit
.idleSleepEnabled
)
6905 DLOG("idle sleep timer enabled\n");
6908 changePowerStateToPriv(ON_STATE
);
6911 startIdleSleepTimer( idleSeconds
);
6916 // Start idle timer if prefs now allow system sleep
6917 // and user is already inactive. Disk spindown is
6918 // accelerated upon timer expiration.
6922 startIdleSleepTimer(getTimeToIdleSleep());
6927 if (flags
.bit
.idleSleepDisabled
)
6929 DLOG("idle sleep timer disabled\n");
6930 cancelIdleSleepTimer();
6931 restoreUserSpinDownTimeout();
6935 if (flags
.bit
.adjustPowerState
)
6937 bool sleepASAP
= false;
6939 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6943 changePowerStateToPriv(ON_STATE
);
6946 // stay awake for at least idleSeconds
6947 startIdleSleepTimer(idleSeconds
);
6950 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6956 adjustPowerState(sleepASAP
);
6960 //******************************************************************************
6963 // Request transition from dark wake to full wake
6964 //******************************************************************************
6966 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
6968 uint32_t options
= 0;
6969 IOService
* pciRoot
= 0;
6970 bool promotion
= false;
6972 // System must be in dark wake and a valid reason for entering full wake
6973 if ((kFullWakeReasonNone
== reason
) ||
6974 (kFullWakeReasonNone
!= fullWakeReason
) ||
6975 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
6980 // Will clear reason upon exit from full wake
6981 fullWakeReason
= reason
;
6983 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
6984 kIOPMSystemCapabilityAudio
);
6986 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6987 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6988 !graphicsSuppressed
)
6990 // Promote to full wake while waking up to dark wake due to tickle.
6991 // PM will hold off notifying the graphics subsystem about system wake
6992 // as late as possible, so if a HID tickle does arrive, graphics can
6993 // power up on this same wake cycle. The latency to power up graphics
6994 // on the next cycle can be huge on some systems. However, once any
6995 // graphics suppression has taken effect, it is too late. All other
6996 // graphics devices must be similarly suppressed. But the delay till
6997 // the following cycle should be short.
6999 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7000 kIOPMSystemCapabilityAudio
);
7002 // Immediately bring up audio and graphics
7003 pciRoot
= pciHostBridgeDriver
;
7004 willEnterFullWake();
7008 // Unsafe to cancel once graphics was powered.
7009 // If system woke from dark wake, the return to sleep can
7010 // be cancelled. "awake -> dark -> sleep" transition
7011 // can be canceled also, during the "dark --> sleep" phase
7012 // *prior* to driver power down.
7013 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7014 _pendingCapability
== 0) {
7015 options
|= kIOPMSyncCancelPowerDown
;
7018 synchronizePowerTree(options
, pciRoot
);
7019 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7021 // IOGraphics doesn't light the display even though graphics is
7022 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7023 // So, do an explicit activity tickle
7025 wrangler
->activityTickle(0,0);
7028 // Log a timestamp for the initial full wake request.
7029 // System may not always honor this full wake request.
7030 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7035 clock_get_uptime(&now
);
7036 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
7037 absolutetime_to_nanoseconds(now
, &nsec
);
7038 MSG("full wake %s (reason %u) %u ms\n",
7039 promotion
? "promotion" : "request",
7040 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7044 //******************************************************************************
7045 // willEnterFullWake
7047 // System will enter full wake from sleep, from dark wake, or from dark
7048 // wake promotion. This function aggregate things that are in common to
7049 // all three full wake transitions.
7051 // Assumptions: fullWakeReason was updated
7052 //******************************************************************************
7054 void IOPMrootDomain::willEnterFullWake( void )
7056 hibernateRetry
= false;
7057 sleepToStandby
= false;
7058 sleepTimerMaintenance
= false;
7060 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7061 kSystemMessageClientLegacyApp
;
7063 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7065 // Initial graphics full power
7066 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7068 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7069 setProperty(gIOPMUserTriggeredFullWakeKey
,
7070 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7071 kOSBooleanTrue
: kOSBooleanFalse
);
7074 IOHibernateSetWakeCapabilities(_pendingCapability
);
7077 IOService::setAdvisoryTickleEnable( true );
7078 tellClients(kIOMessageSystemWillPowerOn
);
7079 preventTransitionToUserActive(false);
7082 //******************************************************************************
7083 // fullWakeDelayedWork
7085 // System has already entered full wake. Invoked by a delayed thread call.
7086 //******************************************************************************
7088 void IOPMrootDomain::fullWakeDelayedWork( void )
7090 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7091 // Not gated, don't modify state
7092 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7093 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7095 receivePowerNotification( kLocalEvalClamshellCommand
);
7100 //******************************************************************************
7101 // evaluateAssertions
7103 //******************************************************************************
7104 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7106 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7108 messageClients(kIOPMMessageDriverAssertionsChanged
);
7110 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7113 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7115 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7116 wrangler
->setIgnoreIdleTimer( value
);
7120 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7121 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7122 if (!assertOnWakeSecs
&& systemWakeTime
) {
7124 clock_usec_t microsecs
;
7125 clock_get_uptime(&now
);
7126 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
7127 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7128 if (assertOnWakeReport
) {
7129 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7130 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7135 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7136 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7138 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7139 updatePreventIdleSleepList(this, true);
7142 DLOG("Driver assertion ReservedBit7 dropped\n");
7143 updatePreventIdleSleepList(this, false);
7151 //******************************************************************************
7154 //******************************************************************************
7156 void IOPMrootDomain::pmStatsRecordEvent(
7158 AbsoluteTime timestamp
)
7160 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7161 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7164 OSData
*publishPMStats
= NULL
;
7166 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7168 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7170 switch (eventIndex
) {
7171 case kIOPMStatsHibernateImageWrite
:
7173 gPMStats
.hibWrite
.start
= nsec
;
7175 gPMStats
.hibWrite
.stop
= nsec
;
7178 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7179 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7182 case kIOPMStatsHibernateImageRead
:
7184 gPMStats
.hibRead
.start
= nsec
;
7186 gPMStats
.hibRead
.stop
= nsec
;
7189 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7190 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7192 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7193 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7194 publishPMStats
->release();
7195 bzero(&gPMStats
, sizeof(gPMStats
));
7202 * Appends a record of the application response to
7203 * IOPMrootDomain::pmStatsAppResponses
7205 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7206 const OSSymbol
*response
,
7212 IOPMPowerStateIndex powerState
)
7214 OSDictionary
*responseDescription
= NULL
;
7215 OSNumber
*delayNum
= NULL
;
7216 OSNumber
*powerCaps
= NULL
;
7217 OSNumber
*pidNum
= NULL
;
7218 OSNumber
*msgNum
= NULL
;
7219 const OSSymbol
*appname
;
7220 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7221 IOPMServiceInterestNotifier
*notify
= 0;
7223 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7225 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7226 notify
->ackTimeoutCnt
++;
7228 notify
->ackTimeoutCnt
= 0;
7232 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7233 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7237 responseDescription
= OSDictionary::withCapacity(5);
7238 if (responseDescription
)
7241 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7244 msgNum
= OSNumber::withNumber(messageType
, 32);
7246 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7250 if (name
&& (strlen(name
) > 0))
7252 appname
= OSSymbol::withCString(name
);
7254 responseDescription
->setObject(_statsNameKey
, appname
);
7259 if (app_pid
!= -1) {
7260 pidNum
= OSNumber::withNumber(app_pid
, 32);
7262 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7267 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7269 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7270 delayNum
->release();
7273 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7274 powerCaps
= OSNumber::withNumber(powerState
, 32);
7276 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7277 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7279 powerState
, delay_ms
);
7284 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7287 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7288 powerCaps
->release();
7291 sleep
= OSSymbol::withCString("Sleep");
7292 wake
= OSSymbol::withCString("Wake");
7293 if (_systemTransitionType
== kSystemTransitionSleep
) {
7294 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7296 else if (_systemTransitionType
== kSystemTransitionWake
) {
7297 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7299 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7300 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7301 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7302 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7303 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7305 if (sleep
) sleep
->release();
7306 if (wake
) wake
->release();
7310 IOLockLock(pmStatsLock
);
7311 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7312 pmStatsAppResponses
->setObject(responseDescription
);
7314 IOLockUnlock(pmStatsLock
);
7316 responseDescription
->release();
7323 // MARK: PMTraceWorker
7325 //******************************************************************************
7326 // TracePoint support
7328 //******************************************************************************
7330 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7331 "IOPMRegisterNVRAMTracePointHandler"
7333 IOReturn
IOPMrootDomain::callPlatformFunction(
7334 const OSSymbol
* functionName
,
7335 bool waitForFunction
,
7336 void * param1
, void * param2
,
7337 void * param3
, void * param4
)
7339 if (pmTracer
&& functionName
&&
7340 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7341 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7343 uint32_t tracePointPhases
, tracePointPCI
;
7344 uint64_t statusCode
;
7346 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7347 pmTracer
->tracePointTarget
= (void *) param2
;
7348 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7349 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7350 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7351 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
7353 MSG("Sleep failure code 0x%08x 0x%08x\n",
7354 tracePointPCI
, tracePointPhases
);
7356 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7357 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7359 return kIOReturnSuccess
;
7362 else if (functionName
&&
7363 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7365 if (gSleepPolicyHandler
)
7366 return kIOReturnExclusiveAccess
;
7368 return kIOReturnBadArgument
;
7369 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7370 gSleepPolicyTarget
= (void *) param2
;
7371 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7372 return kIOReturnSuccess
;
7376 return super::callPlatformFunction(
7377 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7380 void IOPMrootDomain::tracePoint( uint8_t point
)
7382 if (systemBooting
) return;
7384 if (kIOPMTracePointWakeCapabilityClients
== point
)
7385 acceptSystemWakeEvents(false);
7387 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
7388 pmTracer
->tracePoint(point
);
7391 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
7393 if (systemBooting
) return;
7395 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
7396 pmTracer
->tracePoint(point
, data
);
7399 void IOPMrootDomain::traceDetail( uint32_t detail
)
7402 pmTracer
->traceDetail( detail
);
7406 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7409 void **report
= NULL
;
7412 uint32_t *clientCnt
;
7417 if (channel_id
== kAssertDelayChID
) {
7418 report
= &assertOnWakeReport
;
7419 bktCnt
= kAssertDelayBcktCnt
;
7420 bktSize
= kAssertDelayBcktSize
;
7421 clientCnt
= &assertOnWakeClientCnt
;
7423 else if (channel_id
== kSleepDelaysChID
) {
7424 report
= &sleepDelaysReport
;
7425 bktCnt
= kSleepDelaysBcktCnt
;
7426 bktSize
= kSleepDelaysBcktSize
;
7427 clientCnt
= &sleepDelaysClientCnt
;
7432 case kIOReportEnable
:
7439 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7440 *report
= IOMalloc(reportSize
);
7441 if (*report
== NULL
) {
7444 bzero(*report
, reportSize
);
7445 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7446 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7448 if (channel_id
== kAssertDelayChID
)
7449 assertOnWakeSecs
= 0;
7453 case kIOReportDisable
:
7454 if (*clientCnt
== 0) {
7457 if (*clientCnt
== 1)
7459 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7464 if (channel_id
== kAssertDelayChID
)
7465 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7469 case kIOReportGetDimensions
:
7471 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7479 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7480 IOReportConfigureAction action
,
7485 uint64_t configAction
= (uint64_t)action
;
7487 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7488 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7489 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7490 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7491 if (action
!= kIOReportGetDimensions
) continue;
7492 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7494 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7495 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7496 gIOPMWorkLoop
->runAction(
7497 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7498 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7499 (void *)configAction
, (void *)result
);
7503 return super::configureReport(channelList
, action
, result
, destination
);
7506 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7516 if (ch_id
== kAssertDelayChID
) {
7517 report
= &assertOnWakeReport
;
7519 else if (ch_id
== kSleepDelaysChID
) {
7520 report
= &sleepDelaysReport
;
7523 if (*report
== NULL
) {
7524 return kIOReturnNotOpen
;
7527 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7528 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7529 return kIOReturnOverrun
;
7532 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7533 dest
->appendBytes(data2cpy
, size2cpy
);
7535 return kIOReturnSuccess
;
7538 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7539 IOReportUpdateAction action
,
7545 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7546 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7550 if (action
!= kIOReportCopyChannelData
) goto exit
;
7552 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7553 ch_id
= channelList
->channels
[cnt
].channel_id
;
7555 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7556 gIOPMWorkLoop
->runAction(
7557 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7558 (OSObject
*)this, (void *)ch_id
,
7559 (void *)result
, (void *)dest
);
7563 else if ((ch_id
== kSleepCntChID
) ||
7564 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7565 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7569 if (ch_id
== kSleepCntChID
)
7570 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7571 else if (ch_id
== kDarkWkCntChID
)
7572 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7573 else if (ch_id
== kUserWkCntChID
)
7574 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7576 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7577 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7578 dest
->appendBytes(data2cpy
, size2cpy
);
7582 return super::updateReport(channelList
, action
, result
, destination
);
7586 //******************************************************************************
7587 // PMTraceWorker Class
7589 //******************************************************************************
7592 #define super OSObject
7593 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7595 #define kPMBestGuessPCIDevicesCount 25
7596 #define kPMMaxRTCBitfieldSize 32
7598 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7602 me
= OSTypeAlloc( PMTraceWorker
);
7603 if (!me
|| !me
->init())
7608 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7610 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7611 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7612 // this dictionary lazily.
7614 me
->pciDeviceBitMappings
= NULL
;
7615 me
->pciMappingLock
= IOLockAlloc();
7616 me
->tracePhase
= kIOPMTracePointSystemUp
;
7617 me
->loginWindowPhase
= 0;
7618 me
->traceData32
= 0;
7622 void PMTraceWorker::RTC_TRACE(void)
7624 if (tracePointHandler
&& tracePointTarget
)
7628 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
7631 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7632 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7636 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7638 const OSSymbol
* deviceName
;
7641 IOLockLock(pciMappingLock
);
7643 if (!pciDeviceBitMappings
)
7645 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7646 if (!pciDeviceBitMappings
)
7650 // Check for bitmask overflow.
7651 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7654 if ((deviceName
= pciDevice
->copyName()) &&
7655 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7656 pciDeviceBitMappings
->setObject(deviceName
))
7658 index
= pciDeviceBitMappings
->getCount() - 1;
7659 _LOG("PMTrace PCI array: set object %s => %d\n",
7660 deviceName
->getCStringNoCopy(), index
);
7663 deviceName
->release();
7664 if (!addedToRegistry
&& (index
>= 0))
7665 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7668 IOLockUnlock(pciMappingLock
);
7672 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7675 if (pciDeviceBitMappings
)
7677 IOLockLock(pciMappingLock
);
7678 ok
= pciDeviceBitMappings
->serialize(s
);
7679 IOLockUnlock(pciMappingLock
);
7684 void PMTraceWorker::tracePoint(uint8_t phase
)
7686 // clear trace detail when phase begins
7687 if (tracePhase
!= phase
)
7692 DLOG("trace point 0x%02x\n", tracePhase
);
7696 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
7698 // clear trace detail when phase begins
7699 if (tracePhase
!= phase
)
7705 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
7709 void PMTraceWorker::traceDetail(uint32_t detail
)
7711 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
7714 traceData32
= detail
;
7715 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7720 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
7722 loginWindowPhase
= phase
;
7724 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
7728 void PMTraceWorker::tracePCIPowerChange(
7729 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7732 uint32_t expectedFlag
;
7734 // Ignore PCI changes outside of system sleep/wake.
7735 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7736 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7739 // Only record the WillChange transition when going to sleep,
7740 // and the DidChange on the way up.
7741 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7742 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7743 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7744 if (changeFlags
!= expectedFlag
)
7747 // Mark this device off in our bitfield
7748 if (bitNum
< kPMMaxRTCBitfieldSize
)
7750 bitMask
= (1 << bitNum
);
7752 if (kPowerChangeStart
== type
)
7754 traceData32
|= bitMask
;
7755 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7756 service
->getName(), bitNum
, bitMask
, traceData32
);
7760 traceData32
&= ~bitMask
;
7761 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7762 service
->getName(), bitNum
, bitMask
, traceData32
);
7765 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7770 uint64_t PMTraceWorker::getPMStatusCode( )
7772 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
<< 24) |
7773 (loginWindowPhase
<< 16) | (traceData8
<< 8));
7778 // MARK: PMHaltWorker
7780 //******************************************************************************
7781 // PMHaltWorker Class
7783 //******************************************************************************
7785 PMHaltWorker
* PMHaltWorker::worker( void )
7791 me
= OSTypeAlloc( PMHaltWorker
);
7792 if (!me
|| !me
->init())
7795 me
->lock
= IOLockAlloc();
7799 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
7800 me
->retain(); // thread holds extra retain
7801 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
7806 thread_deallocate(thread
);
7811 if (me
) me
->release();
7815 void PMHaltWorker::free( void )
7817 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7823 return OSObject::free();
7826 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
7828 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
7830 IOLockLock( gPMHaltLock
);
7832 me
->depth
= gPMHaltDepth
;
7833 IOLockUnlock( gPMHaltLock
);
7835 while (me
->depth
>= 0)
7837 PMHaltWorker::work( me
);
7839 IOLockLock( gPMHaltLock
);
7840 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
7842 // This is the last thread to finish work on this level,
7843 // inform everyone to start working on next lower level.
7845 me
->depth
= gPMHaltDepth
;
7846 gPMHaltIdleCount
= 0;
7847 thread_wakeup((event_t
) &gPMHaltIdleCount
);
7851 // One or more threads are still working on this level,
7852 // this thread must wait.
7853 me
->depth
= gPMHaltDepth
- 1;
7855 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
7856 } while (me
->depth
!= gPMHaltDepth
);
7858 IOLockUnlock( gPMHaltLock
);
7861 // No more work to do, terminate thread
7862 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
7863 thread_wakeup( &gPMHaltDepth
);
7867 void PMHaltWorker::work( PMHaltWorker
* me
)
7869 IOService
* service
;
7871 AbsoluteTime startTime
;
7880 // Claim an unit of work from the shared pool
7881 IOLockLock( gPMHaltLock
);
7882 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7885 service
= (IOService
*)inner
->getAnyObject();
7889 inner
->removeObject(service
);
7892 IOLockUnlock( gPMHaltLock
);
7894 break; // no more work at this depth
7896 clock_get_uptime(&startTime
);
7898 if (!service
->isInactive() &&
7899 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7901 IOLockLock(me
->lock
);
7902 me
->startTime
= startTime
;
7903 me
->service
= service
;
7904 me
->timeout
= false;
7905 IOLockUnlock(me
->lock
);
7907 service
->systemWillShutdown( gPMHaltMessageType
);
7909 // Wait for driver acknowledgement
7910 IOLockLock(me
->lock
);
7911 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7913 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7916 timeout
= me
->timeout
;
7917 IOLockUnlock(me
->lock
);
7920 deltaTime
= computeDeltaTimeMS(&startTime
);
7921 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7922 (gIOKitDebug
& kIOLogPMRootDomain
))
7924 LOG("%s driver %s (0x%llx) took %u ms\n",
7925 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
7926 "PowerOff" : "Restart",
7927 service
->getName(), service
->getRegistryEntryID(),
7928 (uint32_t) deltaTime
);
7936 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7939 AbsoluteTime startTime
;
7940 AbsoluteTime endTime
;
7944 IOLockLock(me
->lock
);
7945 if (me
->service
&& !me
->timeout
)
7947 startTime
= me
->startTime
;
7949 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7951 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7952 absolutetime_to_nanoseconds(endTime
, &nano
);
7954 if (nano
> 3000000000ULL)
7957 MSG("%s still waiting on %s\n",
7958 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
7959 "PowerOff" : "Restart",
7960 me
->service
->getName());
7963 IOLockUnlock(me
->lock
);
7966 //******************************************************************************
7967 // acknowledgeSystemWillShutdown
7969 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7970 //******************************************************************************
7972 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7974 PMHaltWorker
* worker
;
7980 //DLOG("%s acknowledged\n", from->getName());
7981 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7984 worker
= (PMHaltWorker
*) prop
;
7985 IOLockLock(worker
->lock
);
7986 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
7987 thread_wakeup((event_t
) worker
);
7988 IOLockUnlock(worker
->lock
);
7993 DLOG("%s acknowledged without worker property\n",
7999 //******************************************************************************
8000 // notifySystemShutdown
8002 // Notify all objects in PM tree that system will shutdown or restart
8003 //******************************************************************************
8006 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8008 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8009 IORegistryIterator
* iter
;
8010 IORegistryEntry
* entry
;
8013 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8014 AbsoluteTime deadline
;
8015 unsigned int totalNodes
= 0;
8017 unsigned int rootDepth
;
8018 unsigned int numWorkers
;
8024 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8026 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8028 // Iterate the entire PM tree starting from root
8030 rootDepth
= root
->getDepth( gIOPowerPlane
);
8031 if (!rootDepth
) goto done
;
8033 // debug - for repeated test runs
8034 while (PMHaltWorker::metaClass
->getInstanceCount())
8039 gPMHaltArray
= OSArray::withCapacity(40);
8040 if (!gPMHaltArray
) goto done
;
8043 gPMHaltArray
->flushCollection();
8047 gPMHaltLock
= IOLockAlloc();
8048 if (!gPMHaltLock
) goto done
;
8051 if (!gPMHaltClientAcknowledgeKey
)
8053 gPMHaltClientAcknowledgeKey
=
8054 OSSymbol::withCStringNoCopy("PMShutdown");
8055 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8058 gPMHaltMessageType
= messageType
;
8060 // Depth-first walk of PM plane
8062 iter
= IORegistryIterator::iterateOver(
8063 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8067 while ((entry
= iter
->getNextObject()))
8069 node
= OSDynamicCast(IOService
, entry
);
8074 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8077 depth
= node
->getDepth( gIOPowerPlane
);
8078 if (depth
<= rootDepth
)
8083 // adjust to zero based depth
8084 depth
-= (rootDepth
+ 1);
8086 // gPMHaltArray is an array of containers, each container
8087 // refers to nodes with the same depth.
8089 count
= gPMHaltArray
->getCount();
8090 while (depth
>= count
)
8092 // expand array and insert placeholders
8093 gPMHaltArray
->setObject(PLACEHOLDER
);
8096 count
= gPMHaltArray
->getCount();
8099 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8100 if (inner
== PLACEHOLDER
)
8102 inner
= OSSet::withCapacity(40);
8105 gPMHaltArray
->replaceObject(depth
, inner
);
8110 // PM nodes that appear more than once in the tree will have
8111 // the same depth, OSSet will refuse to add the node twice.
8113 ok
= inner
->setObject(node
);
8116 DLOG("Skipped PM node %s\n", node
->getName());
8122 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8125 if (inner
!= PLACEHOLDER
)
8126 count
= inner
->getCount();
8127 DLOG("Nodes at depth %u = %u\n", i
, count
);
8130 // strip placeholders (not all depths are populated)
8132 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8134 if (inner
== PLACEHOLDER
)
8136 gPMHaltArray
->removeObject(i
);
8139 count
= inner
->getCount();
8140 if (count
> numWorkers
)
8142 totalNodes
+= count
;
8146 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8149 gPMHaltBusyCount
= 0;
8150 gPMHaltIdleCount
= 0;
8151 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8153 // Create multiple workers (and threads)
8155 if (numWorkers
> kPMHaltMaxWorkers
)
8156 numWorkers
= kPMHaltMaxWorkers
;
8158 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8159 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8161 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8162 workers
[i
] = PMHaltWorker::worker();
8164 // Wait for workers to exhaust all available work
8166 IOLockLock(gPMHaltLock
);
8167 while (gPMHaltDepth
>= 0)
8169 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8171 waitResult
= IOLockSleepDeadline(
8172 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8173 if (THREAD_TIMED_OUT
== waitResult
)
8176 clock_get_uptime(&now
);
8178 IOLockUnlock(gPMHaltLock
);
8179 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8182 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8184 IOLockLock(gPMHaltLock
);
8187 IOLockUnlock(gPMHaltLock
);
8189 // Release all workers
8191 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8194 workers
[i
]->release();
8195 // worker also retained by it's own thread
8199 DLOG("%s done\n", __FUNCTION__
);
8204 // MARK: Kernel Assertion
8206 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8208 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8209 IOPMDriverAssertionType whichAssertionBits
,
8210 IOPMDriverAssertionLevel assertionLevel
,
8211 IOService
*ownerService
,
8212 const char *ownerDescription
)
8215 IOPMDriverAssertionID newAssertion
;
8220 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8222 if (kIOReturnSuccess
== ret
)
8223 return newAssertion
;
8228 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8231 return kIOReturnInternalError
;
8233 return pmAssertions
->releaseAssertion(releaseAssertion
);
8237 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8238 IOPMDriverAssertionID assertionID
,
8239 IOPMDriverAssertionLevel assertionLevel
)
8241 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8244 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8246 IOPMDriverAssertionType sysLevels
;
8248 if (!pmAssertions
|| whichAssertion
== 0)
8249 return kIOPMDriverAssertionLevelOff
;
8251 sysLevels
= pmAssertions
->getActivatedAssertions();
8253 // Check that every bit set in argument 'whichAssertion' is asserted
8254 // in the aggregate bits.
8255 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8256 return kIOPMDriverAssertionLevelOn
;
8258 return kIOPMDriverAssertionLevelOff
;
8261 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8264 return kIOReturnNotFound
;
8266 return pmAssertions
->setUserAssertionLevels(inLevels
);
8269 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8273 pmAssertions
->publishProperties();
8275 return( IOService::serializeProperties(s
) );
8278 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8280 OSObject
*obj
= NULL
;
8281 obj
= IOService::copyProperty(aKey
);
8283 if (obj
) return obj
;
8285 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8286 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8287 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8288 return kOSBooleanTrue
;
8290 return kOSBooleanFalse
;
8294 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8295 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8296 if (swd_flags
& SWD_VALID_LOGS
)
8297 return kOSBooleanTrue
;
8299 return kOSBooleanFalse
;
8304 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8305 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8306 * issued by DisplayWrangler on darkwake.
8308 if (!strcmp(aKey
, "DesktopMode")) {
8310 return kOSBooleanTrue
;
8312 return kOSBooleanFalse
;
8314 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8315 if (displayIdleForDemandSleep
) {
8316 return kOSBooleanTrue
;
8319 return kOSBooleanFalse
;
8323 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8325 OSArray
* array
= 0;
8327 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8328 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8329 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8330 collection
->release();
8337 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8339 OSArray
* array
= 0;
8340 IOLockLock(pmStatsLock
);
8341 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8342 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8343 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8344 collection
->release();
8346 pmStatsAppResponses
->flushCollection();
8348 IOLockUnlock(pmStatsLock
);
8352 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8354 OSArray
*idleSleepList
= NULL
;
8355 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8356 return idleSleepList
;
8359 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8361 OSArray
*systemSleepList
= NULL
;
8362 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8363 return systemSleepList
;
8370 // MARK: Wake Event Reporting
8372 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8375 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8379 //******************************************************************************
8380 // acceptSystemWakeEvents
8382 // Private control for the acceptance of driver wake event claims.
8383 //******************************************************************************
8385 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8387 bool logWakeReason
= false;
8392 gWakeReasonString
[0] = '\0';
8393 if (!_systemWakeEventsArray
)
8394 _systemWakeEventsArray
= OSArray::withCapacity(4);
8395 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8396 _systemWakeEventsArray
->flushCollection();
8400 _acceptSystemWakeEvents
= false;
8405 MSG("system wake events:%s\n", gWakeReasonString
);
8408 //******************************************************************************
8409 // claimSystemWakeEvent
8411 // For a driver to claim a device is the source/conduit of a system wake event.
8412 //******************************************************************************
8414 void IOPMrootDomain::claimSystemWakeEvent(
8417 const char * reason
,
8418 OSObject
* details
)
8420 const OSSymbol
* deviceName
= 0;
8421 OSNumber
* deviceRegId
= 0;
8422 OSNumber
* claimTime
= 0;
8423 OSData
* flagsData
= 0;
8424 OSString
* reasonString
= 0;
8425 OSDictionary
* d
= 0;
8429 pmEventTimeStamp(×tamp
);
8431 if (!device
|| !reason
) return;
8433 deviceName
= device
->copyName(gIOServicePlane
);
8434 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8435 claimTime
= OSNumber::withNumber(timestamp
, 64);
8436 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8437 reasonString
= OSString::withCString(reason
);
8438 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8439 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8442 d
->setObject(gIONameKey
, deviceName
);
8443 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8444 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8445 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8446 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8448 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8451 if (!gWakeReasonSysctlRegistered
)
8453 // Lazy registration until the platform driver stops registering
8455 gWakeReasonSysctlRegistered
= true;
8457 if (_acceptSystemWakeEvents
)
8459 ok
= _systemWakeEventsArray
->setObject(d
);
8460 if (gWakeReasonString
[0] != '\0')
8461 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8462 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8467 if (deviceName
) deviceName
->release();
8468 if (deviceRegId
) deviceRegId
->release();
8469 if (claimTime
) claimTime
->release();
8470 if (flagsData
) flagsData
->release();
8471 if (reasonString
) reasonString
->release();
8472 if (d
) d
->release();
8475 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8478 // MARK: PMSettingHandle
8480 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8482 void PMSettingHandle::free( void )
8486 pmso
->clientHandleFreed();
8495 // MARK: PMSettingObject
8498 #define super OSObject
8499 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8502 * Static constructor/initializer for PMSettingObject
8504 PMSettingObject
*PMSettingObject::pmSettingObject(
8505 IOPMrootDomain
*parent_arg
,
8506 IOPMSettingControllerCallback handler_arg
,
8507 OSObject
*target_arg
,
8508 uintptr_t refcon_arg
,
8509 uint32_t supportedPowerSources
,
8510 const OSSymbol
* settings
[],
8511 OSObject
**handle_obj
)
8513 uint32_t settingCount
= 0;
8514 PMSettingObject
*pmso
= 0;
8515 PMSettingHandle
*pmsh
= 0;
8517 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8520 // count OSSymbol entries in NULL terminated settings array
8521 while (settings
[settingCount
]) {
8524 if (0 == settingCount
)
8527 pmso
= new PMSettingObject
;
8528 if (!pmso
|| !pmso
->init())
8531 pmsh
= new PMSettingHandle
;
8532 if (!pmsh
|| !pmsh
->init())
8535 queue_init(&pmso
->calloutQueue
);
8536 pmso
->parent
= parent_arg
;
8537 pmso
->func
= handler_arg
;
8538 pmso
->target
= target_arg
;
8539 pmso
->refcon
= refcon_arg
;
8540 pmso
->settingCount
= settingCount
;
8542 pmso
->retain(); // handle holds a retain on pmso
8546 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8547 if (pmso
->publishedFeatureID
) {
8548 for (unsigned int i
=0; i
<settingCount
; i
++) {
8549 // Since there is now at least one listener to this setting, publish
8550 // PM root domain support for it.
8551 parent_arg
->publishPMSetting( settings
[i
],
8552 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8560 if (pmso
) pmso
->release();
8561 if (pmsh
) pmsh
->release();
8565 void PMSettingObject::free( void )
8567 if (publishedFeatureID
) {
8568 for (uint32_t i
=0; i
<settingCount
; i
++) {
8569 if (publishedFeatureID
[i
]) {
8570 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8574 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8580 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8582 (*func
)(target
, type
, object
, refcon
);
8585 void PMSettingObject::clientHandleFreed( void )
8587 parent
->deregisterPMSettingObject(this);
8591 // MARK: PMAssertionsTracker
8593 //*********************************************************************************
8594 //*********************************************************************************
8595 //*********************************************************************************
8596 // class PMAssertionsTracker Implementation
8598 #define kAssertUniqueIDStart 500
8600 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8602 PMAssertionsTracker
*myself
;
8604 myself
= new PMAssertionsTracker
;
8608 myself
->owner
= rootDomain
;
8609 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8610 myself
->assertionsArray
= OSArray::withCapacity(5);
8611 myself
->assertionsKernel
= 0;
8612 myself
->assertionsUser
= 0;
8613 myself
->assertionsCombined
= 0;
8614 myself
->assertionsArrayLock
= IOLockAlloc();
8615 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8617 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8625 * - Update assertionsKernel to reflect the state of all
8626 * assertions in the kernel.
8627 * - Update assertionsCombined to reflect both kernel & user space.
8629 void PMAssertionsTracker::tabulate(void)
8633 PMAssertStruct
*_a
= NULL
;
8636 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8637 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8641 assertionsKernel
= 0;
8642 assertionsCombined
= 0;
8644 if (!assertionsArray
)
8647 if ((count
= assertionsArray
->getCount()))
8649 for (i
=0; i
<count
; i
++)
8651 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8654 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8655 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8656 assertionsKernel
|= _a
->assertionBits
;
8661 tabulateProducerCount
++;
8662 assertionsCombined
= assertionsKernel
| assertionsUser
;
8664 if ((assertionsKernel
!= oldKernel
) ||
8665 (assertionsCombined
!= oldCombined
))
8667 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8671 void PMAssertionsTracker::publishProperties( void )
8673 OSArray
*assertionsSummary
= NULL
;
8675 if (tabulateConsumerCount
!= tabulateProducerCount
)
8677 IOLockLock(assertionsArrayLock
);
8679 tabulateConsumerCount
= tabulateProducerCount
;
8681 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8683 assertionsSummary
= copyAssertionsArray();
8684 if (assertionsSummary
)
8686 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8687 assertionsSummary
->release();
8691 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8694 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8696 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8698 IOLockUnlock(assertionsArrayLock
);
8702 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8704 PMAssertStruct
*_a
= NULL
;
8711 && (count
= assertionsArray
->getCount()))
8713 for (i
=0; i
<count
; i
++)
8715 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8718 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8719 if (_a
&& (_id
== _a
->id
)) {
8736 /* PMAssertionsTracker::handleCreateAssertion
8737 * Perform assertion work on the PM workloop. Do not call directly.
8739 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8745 IOLockLock(assertionsArrayLock
);
8746 assertionsArray
->setObject(newAssertion
);
8747 IOLockUnlock(assertionsArrayLock
);
8748 newAssertion
->release();
8752 return kIOReturnSuccess
;
8755 /* PMAssertionsTracker::createAssertion
8756 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8759 IOReturn
PMAssertionsTracker::createAssertion(
8760 IOPMDriverAssertionType which
,
8761 IOPMDriverAssertionLevel level
,
8762 IOService
*serviceID
,
8763 const char *whoItIs
,
8764 IOPMDriverAssertionID
*outID
)
8766 OSData
*dataStore
= NULL
;
8767 PMAssertStruct track
;
8769 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8770 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8771 track
.level
= level
;
8772 track
.assertionBits
= which
;
8773 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8774 track
.ownerService
= serviceID
;
8775 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8776 track
.modifiedTime
= 0;
8777 pmEventTimeStamp(&track
.createdTime
);
8779 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8782 if (track
.ownerString
)
8783 track
.ownerString
->release();
8784 return kIOReturnNoMemory
;
8789 if (owner
&& owner
->pmPowerStateQueue
) {
8790 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8793 return kIOReturnSuccess
;
8796 /* PMAssertionsTracker::handleReleaseAssertion
8797 * Runs in PM workloop. Do not call directly.
8799 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8800 IOPMDriverAssertionID _id
)
8805 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8808 return kIOReturnNotFound
;
8810 IOLockLock(assertionsArrayLock
);
8811 if (assertStruct
->ownerString
)
8812 assertStruct
->ownerString
->release();
8814 assertionsArray
->removeObject(index
);
8815 IOLockUnlock(assertionsArrayLock
);
8818 return kIOReturnSuccess
;
8821 /* PMAssertionsTracker::releaseAssertion
8822 * Releases an assertion and affects system behavior if appropiate.
8823 * Actual work happens on PM workloop.
8825 IOReturn
PMAssertionsTracker::releaseAssertion(
8826 IOPMDriverAssertionID _id
)
8828 if (owner
&& owner
->pmPowerStateQueue
) {
8829 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8831 return kIOReturnSuccess
;
8834 /* PMAssertionsTracker::handleSetAssertionLevel
8835 * Runs in PM workloop. Do not call directly.
8837 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8838 IOPMDriverAssertionID _id
,
8839 IOPMDriverAssertionLevel _level
)
8841 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8845 if (!assertStruct
) {
8846 return kIOReturnNotFound
;
8849 IOLockLock(assertionsArrayLock
);
8850 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8851 assertStruct
->level
= _level
;
8852 IOLockUnlock(assertionsArrayLock
);
8855 return kIOReturnSuccess
;
8858 /* PMAssertionsTracker::setAssertionLevel
8860 IOReturn
PMAssertionsTracker::setAssertionLevel(
8861 IOPMDriverAssertionID _id
,
8862 IOPMDriverAssertionLevel _level
)
8864 if (owner
&& owner
->pmPowerStateQueue
) {
8865 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8866 (void *)(uintptr_t)_level
, _id
);
8869 return kIOReturnSuccess
;
8872 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8874 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8878 if (new_user_levels
!= assertionsUser
)
8880 assertionsUser
= new_user_levels
;
8881 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8885 return kIOReturnSuccess
;
8888 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8889 IOPMDriverAssertionType new_user_levels
)
8891 if (gIOPMWorkLoop
) {
8892 gIOPMWorkLoop
->runAction(
8893 OSMemberFunctionCast(
8896 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8898 (void *) &new_user_levels
, 0, 0, 0);
8901 return kIOReturnSuccess
;
8905 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8909 OSArray
*outArray
= NULL
;
8911 if (!assertionsArray
||
8912 (0 == (count
= assertionsArray
->getCount())) ||
8913 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8918 for (i
=0; i
<count
; i
++)
8920 PMAssertStruct
*_a
= NULL
;
8922 OSDictionary
*details
= NULL
;
8924 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8925 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8927 OSNumber
*_n
= NULL
;
8929 details
= OSDictionary::withCapacity(7);
8933 outArray
->setObject(details
);
8936 _n
= OSNumber::withNumber(_a
->id
, 64);
8938 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8941 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8943 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8946 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8948 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8951 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
8953 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
8956 _n
= OSNumber::withNumber(_a
->level
, 64);
8958 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8961 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8963 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8967 if (_a
->ownerString
) {
8968 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8977 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8979 return assertionsCombined
;
8982 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8983 IOPMDriverAssertionType type
)
8985 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8987 return kIOPMDriverAssertionLevelOn
;
8989 return kIOPMDriverAssertionLevelOff
;
8993 //*********************************************************************************
8994 //*********************************************************************************
8995 //*********************************************************************************
8998 static void pmEventTimeStamp(uint64_t *recordTS
)
9006 // We assume tsec fits into 32 bits; 32 bits holds enough
9007 // seconds for 136 years since the epoch in 1970.
9008 clock_get_calendar_microtime(&tsec
, &tusec
);
9011 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9013 *recordTS
|= (uint32_t)tusec
;
9014 *recordTS
|= ((uint64_t)tsec
<< 32);
9020 // MARK: IORootParent
9022 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9024 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9026 // The reason that root domain needs a root parent is to facilitate demand
9027 // sleep, since a power change from the root parent cannot be vetoed.
9029 // The above statement is no longer true since root domain now performs
9030 // demand sleep using overrides. But root parent remains to avoid changing
9031 // the power tree stacking. Root parent is parked at the max power state.
9034 static IOPMPowerState patriarchPowerStates
[2] =
9036 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9037 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9040 void IORootParent::initialize( void )
9044 bool IORootParent::start( IOService
* nub
)
9046 IOService::start(nub
);
9047 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9049 registerPowerDriver(this, patriarchPowerStates
, 2);
9054 void IORootParent::shutDownSystem( void )
9058 void IORootParent::restartSystem( void )
9062 void IORootParent::sleepSystem( void )
9066 void IORootParent::dozeSystem( void )
9070 void IORootParent::sleepToDoze( void )
9074 void IORootParent::wakeSystem( void )
9078 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9080 return (IOService::copyProperty(aKey
));
9084 #if defined(__i386__) || defined(__x86_64__)
9085 IOReturn
IOPMrootDomain::restartWithStackshot()
9087 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9088 return kIOReturnError
;
9090 takeStackshot(true, true, false);
9092 return kIOReturnSuccess
;
9095 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9097 takeStackshot(wdogTrigger
, false, false);
9100 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9102 swd_hdr
* hdr
= NULL
;
9104 uint32_t wdog_panic
= 0;
9111 uint32_t bytesRemaining
;
9113 OSString
* UUIDstring
= NULL
;
9115 IOMemoryMap
* logBufMap
= NULL
;
9117 swd_stackshot_hdr
*stackshotHdr
= NULL
;
9120 uint32_t initialStackSize
;
9123 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9124 _systemTransitionType
!= kSystemTransitionWake
)
9127 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9132 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
9133 (wdog_panic
== 1)) {
9134 // If boot-arg is set to panic on sleep/wake hang, call panic
9135 panic("Sleep/Wake hang detected\n");
9138 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9139 // If current boot is due to this watch dog trigger restart in previous boot,
9140 // then don't trigger again until at least 1 successful sleep & wake.
9141 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9142 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9143 PEHaltRestart(kPEHaltCPU
);
9151 if (gSpinDumpBufferFull
)
9153 if (swd_spindump_buffer
== NULL
) {
9154 sleepWakeDebugSpinDumpMemAlloc();
9155 if (swd_spindump_buffer
== NULL
) return;
9158 bufSize
= SWD_SPINDUMP_SIZE
;
9159 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9161 if (sleepWakeDebugIsWdogEnabled() == false)
9164 if (swd_buffer
== NULL
) {
9165 sleepWakeDebugMemAlloc();
9166 if (swd_buffer
== NULL
) return;
9169 bufSize
= SWD_BUF_SIZE
;
9170 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9173 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9177 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9179 hdr
= (swd_hdr
*)swd_buffer
;
9180 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9181 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9183 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9184 const char *str
= UUIDstring
->getCStringNoCopy();
9185 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9188 DLOG("Data for current UUID already exists\n");
9193 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9194 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9196 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9197 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9199 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9201 while (bytesRemaining
> sizeof(swd_stackshot_hdr
)) {
9203 stackshotHdr
= (swd_stackshot_hdr
*)dstAddr
;
9204 stackshotHdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
9205 stackshotHdr
->size
= 0;
9206 bytesRemaining
-= sizeof(swd_stackshot_hdr
);
9207 dstAddr
+= sizeof(swd_stackshot_hdr
);
9209 if (isOSXWatchdog
) {
9211 size
= bytesRemaining
;
9212 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
;
9214 else if (cnt
== 0) {
9216 * Take stackshot of all process on first sample. Size is restricted
9217 * to SWD_INITIAL_STACK_SIZE
9220 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9221 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY
;
9224 /* Take sample of kernel threads only */
9226 size
= bytesRemaining
;
9230 stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, &stackshotHdr
->size
);
9232 dstAddr
+= stackshotHdr
->size
;
9233 bytesRemaining
-= stackshotHdr
->size
;
9235 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt
, stackshotHdr
->size
, bytesRemaining
);
9236 if ((stackshotHdr
->size
== 0) || (++cnt
== 10))
9238 IOSleep(10); // 10 ms
9241 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9244 memset(hdr
->cps
, 0x20, sizeof(hdr
->cps
));
9245 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "\ncps: %d", ((IOService
*)this)->getPowerState());
9246 code
= pmTracer
->getPMStatusCode();
9247 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9248 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9249 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9250 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9252 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9253 gRootDomain
->swd_lock
= 0;
9254 gSpinDumpBufferFull
= true;
9257 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9260 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9261 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9262 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9263 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9264 len
= sizeof(addr64_t
)*3;
9265 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9266 data
[0], data
[1], data
[2]);
9268 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9270 DLOG("Failed to update nvram boot-args\n");
9276 gRootDomain
->swd_lock
= 0;
9279 IOLog("Restarting to collect Sleep wake debug logs\n");
9280 PEHaltRestart(kPERestartCPU
);
9283 logBufMap
= sleepWakeDebugRetrieve();
9285 sleepWakeDebugDumpFromMem(logBufMap
);
9286 logBufMap
->release();
9292 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9294 vm_size_t size
= SWD_BUF_SIZE
;
9296 swd_hdr
*hdr
= NULL
;
9298 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9301 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9304 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9307 // Try allocating above 4GB. If that fails, try at 2GB
9308 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9309 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9310 size
, 0xFFFFFFFF00000000ULL
);
9312 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9313 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9314 size
, 0xFFFFFFFF10000000ULL
);
9317 if (memDesc
== NULL
)
9319 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9324 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9325 memset(hdr
, 0, sizeof(swd_hdr
));
9327 hdr
->signature
= SWD_HDR_SIGNATURE
;
9328 hdr
->alloc_size
= size
;
9330 hdr
->spindump_offset
= sizeof(swd_hdr
);
9331 swd_buffer
= (void *)hdr
;
9332 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9335 gRootDomain
->swd_lock
= 0;
9338 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9340 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9342 swd_hdr
*hdr
= NULL
;
9344 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9346 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9349 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9350 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9353 if (memDesc
== NULL
)
9355 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9360 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9361 memset(hdr
, 0, sizeof(swd_hdr
));
9363 hdr
->signature
= SWD_HDR_SIGNATURE
;
9364 hdr
->alloc_size
= size
;
9366 hdr
->spindump_offset
= sizeof(swd_hdr
);
9367 swd_spindump_buffer
= (void *)hdr
;
9370 gRootDomain
->swd_lock
= 0;
9373 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9375 swd_flags
|= SWD_WDOG_ENABLED
;
9377 sleepWakeDebugMemAlloc();
9380 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9382 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9383 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9386 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9388 swd_hdr
*hdr
= NULL
;
9389 errno_t error
= EIO
;
9391 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9392 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9394 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9395 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9399 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9400 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9401 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9403 gSpinDumpBufferFull
= false;
9407 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9409 struct vnode
*vp
= NULL
;
9410 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9411 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9412 struct vnode_attr va
;
9413 errno_t error
= EIO
;
9415 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9416 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9418 IOLog("Failed to open the file %s\n", name
);
9422 VATTR_WANTED(&va
, va_nlink
);
9423 /* Don't dump to non-regular files or files with links. */
9424 if (vp
->v_type
!= VREG
||
9425 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9426 IOLog("Bailing as this is not a regular file\n");
9430 VATTR_SET(&va
, va_data_size
, 0);
9431 vnode_setattr(vp
, &va
, ctx
);
9434 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9435 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9437 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9439 DLOG("Saved %d bytes to file %s\n",len
, name
);
9442 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9443 if (ctx
) vfs_context_rele(ctx
);
9449 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9450 struct vnode
*srcVp
,
9451 vfs_context_t srcCtx
,
9452 char *tmpBuf
, uint64_t tmpBufSize
,
9454 const char *dstFname
,
9458 struct vnode
*vp
= NULL
;
9459 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9460 struct vnode_attr va
;
9461 errno_t error
= EIO
;
9462 uint64_t bytesToRead
, bytesToWrite
;
9463 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9464 uint32_t newcrc
= 0;
9466 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9467 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9469 DLOG("Failed to open the file %s\n", dstFname
);
9473 VATTR_WANTED(&va
, va_nlink
);
9474 /* Don't dump to non-regular files or files with links. */
9475 if (vp
->v_type
!= VREG
||
9476 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9477 DLOG("Bailing as this is not a regular file\n");
9481 VATTR_SET(&va
, va_data_size
, 0);
9482 vnode_setattr(vp
, &va
, ctx
);
9484 writeFileOffset
= 0;
9486 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9487 readFileOffset
= trunc_page(srcOffset
);
9489 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9490 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9491 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9492 vfs_context_ucred(srcCtx
), (int *) 0,
9493 vfs_context_proc(srcCtx
));
9495 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9499 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9500 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9501 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9504 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9506 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9507 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9508 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9509 vfs_context_ucred(ctx
), (int *) 0,
9510 vfs_context_proc(ctx
));
9512 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9516 writeFileOffset
+= bytesToWrite
;
9517 numBytes
-= bytesToWrite
;
9518 srcOffset
+= bytesToWrite
;
9521 if (crc
!= newcrc
) {
9522 swd_stackshot_hdr
*shdr
= (swd_stackshot_hdr
*)tmpBuf
;;
9524 /* Set statckshot size to 0 if crc doesn't match */
9525 shdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
9528 assert(tmpBufSize
> sizeof(swd_stackshot_hdr
));
9529 bytesToWrite
= round_page(sizeof(swd_stackshot_hdr
));
9530 vn_rdwr(UIO_WRITE
, vp
, (char *)tmpBuf
, bytesToWrite
, 0,
9531 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9532 vfs_context_ucred(ctx
), (int *) 0,
9533 vfs_context_proc(ctx
));
9535 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9540 error
= vnode_close(vp
, FWRITE
, ctx
);
9541 DLOG("vnode_close returned 0x%x\n", error
);
9543 if (ctx
) vfs_context_rele(ctx
);
9550 void IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9551 void *tmpBuf
, struct vnode
**vp
)
9556 struct vnode_attr va
;
9557 IOHibernateImageHeader
*imageHdr
;
9560 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9561 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9563 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9567 VATTR_WANTED(&va
, va_nlink
);
9568 VATTR_WANTED(&va
, va_data_alloc
);
9569 if ((*vp
)->v_type
!= VREG
||
9570 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9571 DMSG("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9575 /* Read the sleepimage file header */
9576 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9577 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9578 vfs_context_ucred(*ctx
), (int *) 0,
9579 vfs_context_proc(*ctx
));
9581 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9582 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9586 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9587 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9588 DMSG("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9589 fname
, imageHdr
->signature
);
9593 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9594 hdrOffset
= imageHdr
->deviceBlockSize
;
9595 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9596 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9597 va
.va_data_alloc
, fname
);
9604 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9610 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9614 char hibernateFilename
[MAXPATHLEN
+1];
9615 char PMStatusCode
[100];
9617 swd_hdr
*hdr
= NULL
;
9618 uint32_t stacksSize
, logSize
;
9619 uint64_t tmpBufSize
;
9620 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9621 errno_t error
= EIO
;
9622 OSObject
*obj
= NULL
;
9623 OSString
*str
= NULL
;
9624 OSNumber
*failStat
= NULL
;
9625 struct vnode
*vp
= NULL
;
9626 vfs_context_t ctx
= NULL
;
9628 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9630 DLOG("sleepWakeDebugDumpFromFile\n");
9631 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9634 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9638 /* Allocate a temp buffer to copy data between files */
9639 tmpBufSize
= 2*4096;
9640 tmpBufDesc
= IOBufferMemoryDescriptor::
9641 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9642 tmpBufSize
, PAGE_SIZE
);
9645 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9649 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9651 ctx
= vfs_context_create(vfs_context_current());
9653 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9654 checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9656 /* Check if the debug data is saved to hibernation file */
9657 hibernateFilename
[0] = 0;
9658 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9660 if ((str
= OSDynamicCast(OSString
, obj
)))
9661 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9662 sizeof(hibernateFilename
));
9665 if (!hibernateFilename
[0]) {
9666 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9670 checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9672 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9675 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9678 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9681 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9683 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9684 /* Read the sleep/wake debug header(swd_hdr) */
9685 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9686 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9687 vfs_context_ucred(ctx
), (int *) 0,
9688 vfs_context_proc(ctx
));
9690 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9691 round_page(sizeof(swd_hdr
)), rc
);
9695 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9696 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9697 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9698 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9699 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9702 stacksSize
= hdr
->spindump_size
;
9704 /* Get stacks & log offsets in the image file */
9705 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9706 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9707 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9709 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9710 getDumpStackFilename(hdr
), stacksSize
, hdr
->crc
);
9711 if (error
== EFAULT
) {
9712 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9715 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9716 getDumpLogFilename(hdr
), logSize
, 0);
9718 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9723 // Write just the SleepWakeLog.dump with failure code
9726 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9727 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9728 fcode
= failStat
->unsigned64BitValue();
9729 fname
= kSleepWakeLogFilename
;
9732 fname
= kAppleOSXWatchdogLogFilename
;
9734 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9735 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9736 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9737 sleepWakeDebugSaveFile(fname
, PMStatusCode
, sizeof(PMStatusCode
));
9739 gRootDomain
->swd_lock
= 0;
9741 if (vp
) vnode_close(vp
, FREAD
, ctx
);
9742 if (ctx
) vfs_context_rele(ctx
);
9743 if (tmpBufDesc
) tmpBufDesc
->release();
9744 #endif /* HIBERNATION */
9747 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
9749 IOVirtualAddress srcBuf
= NULL
;
9750 char *stackBuf
= NULL
, *logOffset
= NULL
;
9753 errno_t error
= EIO
;
9754 uint64_t bufSize
= 0;
9755 swd_hdr
*hdr
= NULL
;
9756 char PMStatusCode
[100];
9757 OSNumber
*failStat
= NULL
;
9759 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9762 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
9764 DLOG("Nothing saved to dump to file\n");
9768 hdr
= (swd_hdr
*)srcBuf
;
9769 bufSize
= logBufMap
->getLength();
9770 if (bufSize
<= sizeof(swd_hdr
))
9772 IOLog("SleepWake log buffer contents are invalid\n");
9776 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
9778 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
9779 if (error
) goto exit
;
9781 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9782 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9784 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
9785 if (error
) goto exit
;
9787 hdr
->spindump_size
= 0;
9792 // Write just the SleepWakeLog.dump with failure code
9794 const char *sname
, *lname
;
9795 swd_stackshot_hdr shdr
;
9797 /* Try writing an empty stacks file */
9798 shdr
.magic
= SWD_STACKSHOTHDR_MAGIC
;
9802 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9803 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9804 fcode
= failStat
->unsigned64BitValue();
9805 lname
= kSleepWakeLogFilename
;
9806 sname
= kSleepWakeStackFilename
;
9809 lname
= kAppleOSXWatchdogLogFilename
;
9810 sname
= kAppleOSXWatchdogStackFilename
;
9813 sleepWakeDebugSaveFile(sname
, (char*)(&shdr
), sizeof(shdr
));
9814 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9815 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9816 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9817 sleepWakeDebugSaveFile(lname
, PMStatusCode
, sizeof(PMStatusCode
));
9819 gRootDomain
->swd_lock
= 0;
9822 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9824 IOVirtualAddress vaddr
= NULL
;
9825 IOMemoryDescriptor
* desc
= NULL
;
9826 IOMemoryMap
* logBufMap
= NULL
;
9830 uint64_t bufSize
= 0;
9832 uint64_t newcrc
= 0;
9834 swd_hdr
*hdr
= NULL
;
9839 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9842 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
9843 DLOG("No sleepWakeDebug note to read\n");
9847 if (len
== strlen("sleepimage")) {
9849 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
9851 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
9852 DLOG("sleepWakeDebugRetrieve: in file logs\n");
9853 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
9857 else if (len
== sizeof(addr64_t
)*3)
9858 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
9860 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
9866 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9867 data
[0], data
[1], data
[2]);
9868 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
9872 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
9874 IOLog("SleepWake log buffer contents are invalid\n");
9878 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9879 bufSize
, crc
, paddr
);
9882 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
9883 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
9886 IOLog("Fail to map SleepWake log buffer\n");
9890 logBufMap
= desc
->map();
9892 vaddr
= logBufMap
->getVirtualAddress();
9895 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
9896 IOLog("Fail to map SleepWake log buffer\n");
9900 hdr
= (swd_hdr
*)vaddr
;
9901 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
9903 IOLog("SleepWake log buffer contents are invalid\n");
9908 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
9909 hdr
->spindump_size
);
9910 if (newcrc
!= crc
) {
9911 IOLog("SleepWake log buffer contents are invalid\n");
9916 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
9920 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
9922 if (logBufMap
) logBufMap
->release();
9925 if (desc
) desc
->release();
9926 gRootDomain
->swd_lock
= 0;
9933 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
9937 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
9939 #pragma unused(restart)
9940 #pragma unused(isOSXWatchdog)
9943 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9946 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
9949 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9950 struct vnode
*srcVp
,
9951 vfs_context_t srcCtx
,
9952 char *tmpBuf
, uint64_t tmpBufSize
,
9954 const char *dstFname
,
9961 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
9965 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9970 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9974 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9979 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)