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>
61 #include <pexpert/protos.h>
64 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
65 #include "IOServicePMPrivate.h"
68 #include <mach/shared_region.h>
69 #include <kern/clock.h>
72 #if defined(__i386__) || defined(__x86_64__)
74 #include "IOPMrootDomainInternal.h"
78 #define kIOPMrootDomainClass "IOPMrootDomain"
79 #define LOG_PREFIX "PMRD: "
83 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
86 do { kprintf(LOG_PREFIX x); } while (false)
89 #define DLOG(x...) do { \
90 if (kIOLogPMRootDomain & gIOKitDebug) \
91 kprintf(LOG_PREFIX x); \
93 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
96 #define DLOG(x...) do { \
97 if (kIOLogPMRootDomain & gIOKitDebug) \
98 kprintf(LOG_PREFIX x); \
102 #define DMSG(x...) do { \
103 if (kIOLogPMRootDomain & gIOKitDebug) { \
104 kprintf(LOG_PREFIX x); \
111 #define CHECK_THREAD_CONTEXT
112 #ifdef CHECK_THREAD_CONTEXT
113 static IOWorkLoop
* gIOPMWorkLoop
= 0;
114 #define ASSERT_GATED() \
116 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
117 panic("RootDomain: not inside PM gate"); \
121 #define ASSERT_GATED()
122 #endif /* CHECK_THREAD_CONTEXT */
124 #define CAP_LOSS(c) \
125 (((_pendingCapability & (c)) == 0) && \
126 ((_currentCapability & (c)) != 0))
128 #define CAP_GAIN(c) \
129 (((_currentCapability & (c)) == 0) && \
130 ((_pendingCapability & (c)) != 0))
132 #define CAP_CHANGE(c) \
133 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
135 #define CAP_CURRENT(c) \
136 ((_currentCapability & (c)) != 0)
138 #define CAP_HIGHEST(c) \
139 ((_highestCapability & (c)) != 0)
141 #if defined(__i386__) || defined(__x86_64__)
142 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
145 // Event types for IOPMPowerStateQueue::submitPowerEvent()
147 kPowerEventFeatureChanged
= 1, // 1
148 kPowerEventReceivedPowerNotification
, // 2
149 kPowerEventSystemBootCompleted
, // 3
150 kPowerEventSystemShutdown
, // 4
151 kPowerEventUserDisabledSleep
, // 5
152 kPowerEventRegisterSystemCapabilityClient
, // 6
153 kPowerEventRegisterKernelCapabilityClient
, // 7
154 kPowerEventPolicyStimulus
, // 8
155 kPowerEventAssertionCreate
, // 9
156 kPowerEventAssertionRelease
, // 10
157 kPowerEventAssertionSetLevel
, // 11
158 kPowerEventQueueSleepWakeUUID
, // 12
159 kPowerEventPublishSleepWakeUUID
, // 13
160 kPowerEventSetDisplayPowerOn
// 14
163 // For evaluatePolicy()
164 // List of stimuli that affects the root domain policy.
166 kStimulusDisplayWranglerSleep
, // 0
167 kStimulusDisplayWranglerWake
, // 1
168 kStimulusAggressivenessChanged
, // 2
169 kStimulusDemandSystemSleep
, // 3
170 kStimulusAllowSystemSleepChanged
, // 4
171 kStimulusDarkWakeActivityTickle
, // 5
172 kStimulusDarkWakeEntry
, // 6
173 kStimulusDarkWakeReentry
, // 7
174 kStimulusDarkWakeEvaluate
, // 8
175 kStimulusNoIdleSleepPreventers
, // 9
176 kStimulusEnterUserActiveState
, // 10
177 kStimulusLeaveUserActiveState
// 11
181 IOReturn
OSKextSystemSleepOrWake( UInt32
);
183 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
184 extern "C" addr64_t
kvtophys(vm_offset_t va
);
186 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
187 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
188 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
189 static void pmEventTimeStamp(uint64_t *recordTS
);
191 // "IOPMSetSleepSupported" callPlatformFunction name
192 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
193 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
195 #define kIOSleepSupportedKey "IOSleepSupported"
196 #define kIOPMSystemCapabilitiesKey "System Capabilities"
198 #define kIORequestWranglerIdleKey "IORequestIdle"
199 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
201 #define kIOSleepWakeDebugKey "Persistent-memory-note"
202 #define kIOEFIBootRomFailureKey "wake-failure"
204 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
205 | kIOPMSupportedOnBatt \
206 | kIOPMSupportedOnUPS)
208 #define kLocalEvalClamshellCommand (1 << 15)
209 #define kIdleSleepRetryInterval (3 * 60)
212 kWranglerPowerStateMin
= 0,
213 kWranglerPowerStateSleep
= 2,
214 kWranglerPowerStateDim
= 3,
215 kWranglerPowerStateMax
= 4
226 #define ON_POWER kIOPMPowerOn
227 #define RESTART_POWER kIOPMRestart
228 #define SLEEP_POWER kIOPMAuxPowerOn
230 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
232 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
233 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
234 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
235 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
238 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
239 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
240 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
241 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
242 #define kIOPMRootDomainWakeTypeUser "User"
243 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
244 #define kIOPMRootDomainWakeTypeNetwork "Network"
245 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
246 #define kIOPMRootDomainWakeTypeNotification "Notification"
247 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
249 // Special interest that entitles the interested client from receiving
250 // all system messages. Only used by powerd.
252 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
254 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
255 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
260 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
261 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
263 #define kAggressivesMinValue 1
266 kAggressivesStateBusy
= 0x01,
267 kAggressivesStateQuickSpindown
= 0x02
270 struct AggressivesRecord
{
276 struct AggressivesRequest
{
282 AggressivesRecord record
;
287 kAggressivesRequestTypeService
= 1,
288 kAggressivesRequestTypeRecord
292 kAggressivesOptionSynchronous
= 0x00000001,
293 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
294 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
295 kAggressivesOptionQuickSpindownMask
= 0x00000300
299 kAggressivesRecordFlagModified
= 0x00000001,
300 kAggressivesRecordFlagMinValue
= 0x00000002
305 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
306 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
307 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
308 kDarkWakeFlagHIDTickleMask
= 0x03,
309 kDarkWakeFlagAlarmIsDark
= 0x0100,
310 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
311 kDarkWakeFlagAudioNotSuppressed
= 0x0400
314 static IOPMrootDomain
* gRootDomain
;
315 static IONotifier
* gSysPowerDownNotifier
= 0;
316 static UInt32 gSleepOrShutdownPending
= 0;
317 static UInt32 gWillShutdown
= 0;
318 static UInt32 gPagingOff
= 0;
319 static UInt32 gSleepWakeUUIDIsSet
= false;
320 static uint32_t gAggressivesState
= 0;
321 static uint32_t gHaltTimeMaxLog
;
322 static uint32_t gHaltTimeMaxPanic
;
323 IOLock
* gHaltLogLock
;
324 static char * gHaltLog
;
325 enum { kHaltLogSize
= 2048 };
326 static size_t gHaltLogPos
;
327 static uint64_t gHaltStartTime
;
330 uuid_string_t bootsessionuuid_string
;
332 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
333 static uint32_t gNoIdleFlag
= 0;
334 static PMStatsStruct gPMStats
;
337 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
338 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
339 static void * gSleepPolicyTarget
;
342 struct timeval gIOLastSleepTime
;
343 struct timeval gIOLastWakeTime
;
345 static char gWakeReasonString
[128];
346 static bool gWakeReasonSysctlRegistered
= false;
347 static AbsoluteTime gIOLastWakeAbsTime
;
348 static AbsoluteTime gIOLastSleepAbsTime
;
350 #if defined(__i386__) || defined(__x86_64__)
351 static bool gSpinDumpBufferFull
= false;
354 static unsigned int gPMHaltBusyCount
;
355 static unsigned int gPMHaltIdleCount
;
356 static int gPMHaltDepth
;
357 static uint32_t gPMHaltMessageType
;
358 static IOLock
* gPMHaltLock
= 0;
359 static OSArray
* gPMHaltArray
= 0;
360 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
361 static bool gPMQuiesced
;
363 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
364 #define kCPUUnknownIndex 9999999
371 const OSSymbol
*gIOPMStatsResponseTimedOut
;
372 const OSSymbol
*gIOPMStatsResponseCancel
;
373 const OSSymbol
*gIOPMStatsResponseSlow
;
374 const OSSymbol
*gIOPMStatsResponsePrompt
;
375 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
377 #define kBadPMFeatureID 0
381 * Opaque handle passed to clients of registerPMSettingController()
383 class PMSettingHandle
: public OSObject
385 OSDeclareFinalStructors( PMSettingHandle
)
386 friend class PMSettingObject
;
389 PMSettingObject
*pmso
;
390 void free(void) APPLE_KEXT_OVERRIDE
;
395 * Internal object to track each PM setting controller
397 class PMSettingObject
: public OSObject
399 OSDeclareFinalStructors( PMSettingObject
)
400 friend class IOPMrootDomain
;
403 queue_head_t calloutQueue
;
405 IOPMrootDomain
*parent
;
406 PMSettingHandle
*pmsh
;
407 IOPMSettingControllerCallback func
;
410 uint32_t *publishedFeatureID
;
411 uint32_t settingCount
;
414 void free(void) APPLE_KEXT_OVERRIDE
;
417 static PMSettingObject
*pmSettingObject(
418 IOPMrootDomain
*parent_arg
,
419 IOPMSettingControllerCallback handler_arg
,
420 OSObject
*target_arg
,
421 uintptr_t refcon_arg
,
422 uint32_t supportedPowerSources
,
423 const OSSymbol
*settings
[],
424 OSObject
**handle_obj
);
426 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
427 void clientHandleFreed(void);
430 struct PMSettingCallEntry
{
435 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
436 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
437 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
438 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
442 * Internal helper object for logging trace points to RTC
443 * IOPMrootDomain and only IOPMrootDomain should instantiate
444 * exactly one of these.
447 typedef void (*IOPMTracePointHandler
)(
448 void * target
, uint32_t code
, uint32_t data
);
450 class PMTraceWorker
: public OSObject
452 OSDeclareDefaultStructors(PMTraceWorker
)
454 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
456 static PMTraceWorker
*tracer( IOPMrootDomain
* );
457 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
458 void tracePoint(uint8_t phase
);
459 void traceDetail(uint32_t detail
);
460 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
461 int recordTopLevelPCIDevice(IOService
*);
462 void RTC_TRACE(void);
463 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
465 IOPMTracePointHandler tracePointHandler
;
466 void * tracePointTarget
;
467 uint64_t getPMStatusCode();
468 uint8_t getTracePhase();
469 uint32_t getTraceData();
471 IOPMrootDomain
*owner
;
472 IOLock
*pmTraceWorkerLock
;
473 OSArray
*pciDeviceBitMappings
;
475 uint8_t addedToRegistry
;
477 uint32_t traceData32
;
478 uint8_t loginWindowData
;
479 uint8_t coreDisplayData
;
480 uint8_t coreGraphicsData
;
484 * PMAssertionsTracker
485 * Tracks kernel and user space PM assertions
487 class PMAssertionsTracker
: public OSObject
489 OSDeclareFinalStructors(PMAssertionsTracker
)
491 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
493 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
494 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
495 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
496 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
498 OSArray
*copyAssertionsArray(void);
499 IOPMDriverAssertionType
getActivatedAssertions(void);
500 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
502 IOReturn
handleCreateAssertion(OSData
*);
503 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
504 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
505 IOReturn
handleSetUserAssertionLevels(void * arg0
);
506 void publishProperties(void);
510 IOPMDriverAssertionID id
;
511 IOPMDriverAssertionType assertionBits
;
512 uint64_t createdTime
;
513 uint64_t modifiedTime
;
514 const OSSymbol
*ownerString
;
515 IOService
*ownerService
;
516 uint64_t registryEntryID
;
517 IOPMDriverAssertionLevel level
;
520 uint32_t tabulateProducerCount
;
521 uint32_t tabulateConsumerCount
;
523 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
526 IOPMrootDomain
*owner
;
527 OSArray
*assertionsArray
;
528 IOLock
*assertionsArrayLock
;
529 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
530 IOPMDriverAssertionType assertionsKernel
;
531 IOPMDriverAssertionType assertionsUser
;
532 IOPMDriverAssertionType assertionsCombined
;
535 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
539 * Internal helper object for Shutdown/Restart notifications.
541 #define kPMHaltMaxWorkers 8
542 #define kPMHaltTimeoutMS 100
544 class PMHaltWorker
: public OSObject
546 OSDeclareFinalStructors( PMHaltWorker
)
549 IOService
* service
; // service being worked on
550 AbsoluteTime startTime
; // time when work started
551 int depth
; // work on nubs at this PM-tree depth
552 int visits
; // number of nodes visited (debug)
554 bool timeout
; // service took too long
556 static PMHaltWorker
* worker( void );
557 static void main( void * arg
, wait_result_t waitResult
);
558 static void work( PMHaltWorker
* me
);
559 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
560 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
563 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
566 #define super IOService
567 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
569 static void IOPMRootDomainWillShutdown(void)
571 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
573 OSKext::willShutdown();
574 for (int i
= 0; i
< 100; i
++)
576 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
582 extern "C" IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
584 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
587 extern "C" IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
589 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
592 extern "C" IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
594 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
597 extern "C" IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
599 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
602 extern "C" IOReturn
rootDomainRestart ( void )
604 return gRootDomain
->restartSystem();
607 extern "C" IOReturn
rootDomainShutdown ( void )
609 return gRootDomain
->shutdownSystem();
612 static void halt_log_putc(char c
)
614 if (gHaltLogPos
>= (kHaltLogSize
- 1)) return;
615 gHaltLog
[gHaltLogPos
++] = c
;
619 _doprnt_log(const char *fmt
,
625 halt_log(const char *fmt
, ...)
629 va_start(listp
, fmt
);
630 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
637 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
639 uint64_t nano
, millis
;
641 if (!gHaltLog
) return;
642 absolutetime_to_nanoseconds(time
, &nano
);
643 millis
= nano
/ 1000000ULL;
644 if (millis
< 100) return;
646 IOLockLock(gHaltLogLock
);
648 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
649 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
650 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
652 halt_log("%s: %qd ms\n", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
654 IOLockUnlock(gHaltLogLock
);
657 extern uint32_t gFSState
;
659 extern "C" void IOSystemShutdownNotification(void)
663 IOLockLock(gHaltLogLock
);
666 gHaltLog
= IONew(char, kHaltLogSize
);
667 gHaltStartTime
= mach_absolute_time();
668 if (gHaltLog
) halt_log_putc('\n');
670 IOLockUnlock(gHaltLogLock
);
672 startTime
= mach_absolute_time();
673 IOPMRootDomainWillShutdown();
674 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime
);
676 startTime
= mach_absolute_time();
677 IOHibernateSystemPostWake(true);
678 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime
);
680 if (OSCompareAndSwap(0, 1, &gPagingOff
))
683 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
689 extern "C" int sync_internal(void);
692 A device is always in the highest power state which satisfies its driver,
693 its policy-maker, and any power children it has, but within the constraint
694 of the power state provided by its parent. The driver expresses its desire by
695 calling changePowerStateTo(), the policy-maker expresses its desire by calling
696 changePowerStateToPriv(), and the children express their desires by calling
697 requestPowerDomainState().
699 The Root Power Domain owns the policy for idle and demand sleep for the system.
700 It is a power-managed IOService just like the others in the system.
701 It implements several power states which map to what we see as Sleep and On.
703 The sleep policy is as follows:
704 1. Sleep is prevented if the case is open so that nobody will think the machine
705 is off and plug/unplug cards.
706 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
707 3. System cannot Sleep if some object in the tree is in a power state marked
708 kIOPMPreventSystemSleep.
710 These three conditions are enforced using the "driver clamp" by calling
711 changePowerStateTo(). For example, if the case is opened,
712 changePowerStateTo(ON_STATE) is called to hold the system on regardless
713 of the desires of the children of the root or the state of the other clamp.
715 Demand Sleep is initiated by pressing the front panel power button, closing
716 the clamshell, or selecting the menu item. In this case the root's parent
717 actually initiates the power state change so that the root domain has no
718 choice and does not give applications the opportunity to veto the change.
720 Idle Sleep occurs if no objects in the tree are in a state marked
721 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
722 the root on, so it sets the "policy-maker clamp" by calling
723 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
724 This timer is set for the difference between the sleep timeout slider and the
725 display dim timeout slider. When the timer expires, it releases its clamp and
726 now nothing is holding it awake, so it falls asleep.
728 Demand sleep is prevented when the system is booting. When preferences are
729 transmitted by the loginwindow at the end of boot, a flag is cleared,
730 and this allows subsequent Demand Sleep.
733 //******************************************************************************
735 IOPMrootDomain
* IOPMrootDomain::construct( void )
737 IOPMrootDomain
*root
;
739 root
= new IOPMrootDomain
;
746 //******************************************************************************
747 // updateConsoleUsersCallout
749 //******************************************************************************
751 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
753 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
754 rootDomain
->updateConsoleUsers();
757 void IOPMrootDomain::updateConsoleUsers(void)
759 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
762 tasksSuspended
= FALSE
;
763 tasks_system_suspend(tasksSuspended
);
767 //******************************************************************************
769 static void swdDebugSetupCallout( thread_call_param_t p0
, thread_call_param_t p1
)
771 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
772 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
774 rootDomain
->swdDebugSetup();
777 rootDomain
->allowPowerChange(notifyRef
);
779 DLOG("swdDebugSetupCallout finish\n");
782 void IOPMrootDomain::swdDebugSetup( )
785 static int32_t mem_only
= -1;
786 if ((mem_only
== -1) &&
787 (PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
)) == false)) {
791 if ((mem_only
== 1) || (gRootDomain
->sleepWakeDebugIsWdogEnabled() == false)) {
794 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup
);
795 if (swd_DebugImageSetup
== FALSE
) {
796 swd_DebugImageSetup
= TRUE
;
797 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
798 (CAP_LOSS(kIOPMSystemCapabilityGraphics
))) {
799 IOHibernateSystemPostWake(true);
801 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
808 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
810 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
811 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
813 rootDomain
->swdDebugTeardown();
815 rootDomain
->allowPowerChange(notifyRef
);
817 DLOG("swdDebugTeardownCallout finish\n");
820 void IOPMrootDomain::swdDebugTeardown( )
824 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
825 if (swd_DebugImageSetup
== TRUE
) {
826 swd_DebugImageSetup
= FALSE
;
827 IOCloseDebugDataFile();
833 //******************************************************************************
836 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
838 IOService
* rootDomain
= (IOService
*) p0
;
839 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
840 uint32_t powerState
= rootDomain
->getPowerState();
842 DLOG("disk_sync_callout ps=%u\n", powerState
);
844 if (ON_STATE
== powerState
)
847 swdDebugSetupCallout(p0
, NULL
);
852 swdDebugTeardownCallout(p0
, NULL
);
853 IOHibernateSystemPostWake(false);
856 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
860 rootDomain
->allowPowerChange(notifyRef
);
861 DLOG("disk_sync_callout finish\n");
864 //******************************************************************************
865 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
867 AbsoluteTime endTime
;
870 clock_get_uptime(&endTime
);
871 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) *elapsedTime
= 0;
874 SUB_ABSOLUTETIME(&endTime
, startTime
);
875 absolutetime_to_nanoseconds(endTime
, &nano
);
876 *elapsedTime
= endTime
;
879 return (UInt32
)(nano
/ 1000000ULL);
882 //******************************************************************************
885 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
887 struct timeval
*swt
= (struct timeval
*)arg1
;
888 struct proc
*p
= req
->p
;
891 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
892 } else if(proc_is64bit(p
)) {
893 struct user64_timeval t
= {};
894 t
.tv_sec
= swt
->tv_sec
;
895 t
.tv_usec
= swt
->tv_usec
;
896 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
898 struct user32_timeval t
= {};
899 t
.tv_sec
= swt
->tv_sec
;
900 t
.tv_usec
= swt
->tv_usec
;
901 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
905 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
906 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
907 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
909 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
910 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
911 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
913 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
914 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
918 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
920 int new_value
, changed
;
921 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
923 if (!gWillShutdown
&& (new_value
== 1)) {
924 IOPMRootDomainWillShutdown();
931 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
932 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
933 0, 0, sysctl_willshutdown
, "I", "");
935 extern struct sysctl_oid sysctl__kern_iokittest
;
936 extern struct sysctl_oid sysctl__debug_iokit
;
941 sysctl_progressmeterenable
942 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
945 int new_value
, changed
;
947 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
949 if (changed
) vc_enable_progressmeter(new_value
);
956 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
959 int new_value
, changed
;
961 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
963 if (changed
) vc_set_progressmeter(new_value
);
968 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
969 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
970 0, 0, sysctl_progressmeterenable
, "I", "");
972 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
973 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
974 0, 0, sysctl_progressmeter
, "I", "");
976 #endif /* !CONFIG_EMBEDDED */
981 sysctl_consoleoptions
982 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
987 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
989 if (changed
) vc_user_options
.options
= new_value
;
994 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
995 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
996 0, 0, sysctl_consoleoptions
, "I", "");
1000 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1002 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1005 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1006 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1007 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1011 sysctl_wakereason SYSCTL_HANDLER_ARGS
1013 char wr
[ sizeof(gWakeReasonString
) ];
1017 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1019 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1022 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1023 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1024 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1027 sysctl_targettype SYSCTL_HANDLER_ARGS
1035 root
= IOService::getServiceRoot();
1036 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
1038 if ((data
= OSDynamicCast(OSData
, obj
)))
1040 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1044 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1047 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1048 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1049 NULL
, 0, sysctl_targettype
, "A", "targettype");
1051 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1052 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1054 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
1055 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
1056 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
1057 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
1058 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
1059 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
1060 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
1061 static const OSSymbol
* gIOPMUserIsActiveKey
;
1063 //******************************************************************************
1066 //******************************************************************************
1068 #define kRootDomainSettingsCount 17
1070 bool IOPMrootDomain::start( IOService
* nub
)
1072 OSIterator
*psIterator
;
1073 OSDictionary
*tmpDict
;
1074 IORootParent
* patriarch
;
1075 #if defined(__i386__) || defined(__x86_64__)
1076 IONotifier
* notifier
;
1082 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1083 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1084 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1085 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1086 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1087 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1088 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1089 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1091 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1092 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1093 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1094 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1095 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1097 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1098 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1100 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1102 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1103 gIOPMSettingAutoWakeSecondsKey
,
1104 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1105 gIOPMSettingAutoWakeCalendarKey
,
1106 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1107 gIOPMSettingDebugWakeRelativeKey
,
1108 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1109 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1110 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1111 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1112 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1113 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1114 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1115 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1116 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1117 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1118 gIOPMSettingSilentRunningKey
1121 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1122 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1123 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1124 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1126 queue_init(&aggressivesQueue
);
1127 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1128 aggressivesData
= OSData::withCapacity(
1129 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1131 featuresDictLock
= IOLockAlloc();
1132 settingsCtrlLock
= IOLockAlloc();
1133 wakeEventLock
= IOLockAlloc();
1134 gHaltLogLock
= IOLockAlloc();
1135 setPMRootDomain(this);
1137 extraSleepTimer
= thread_call_allocate(
1138 idleSleepTimerExpired
,
1139 (thread_call_param_t
) this);
1141 diskSyncCalloutEntry
= thread_call_allocate(
1143 (thread_call_param_t
) this);
1144 swdDebugSetupEntry
= thread_call_allocate(
1145 &swdDebugSetupCallout
,
1146 (thread_call_param_t
) this);
1147 swdDebugTearDownEntry
= thread_call_allocate(
1148 &swdDebugTeardownCallout
,
1149 (thread_call_param_t
) this);
1150 updateConsoleUsersEntry
= thread_call_allocate(
1151 &updateConsoleUsersCallout
,
1152 (thread_call_param_t
) this);
1154 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1155 fullWakeThreadCall
= thread_call_allocate(
1156 OSMemberFunctionCast(thread_call_func_t
, this,
1157 &IOPMrootDomain::fullWakeDelayedWork
),
1158 (thread_call_param_t
) this);
1161 setProperty(kIOSleepSupportedKey
, true);
1163 bzero(&gPMStats
, sizeof(gPMStats
));
1165 pmTracer
= PMTraceWorker::tracer(this);
1167 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1169 userDisabledAllSleep
= false;
1170 systemBooting
= true;
1171 idleSleepEnabled
= false;
1173 idleSleepTimerPending
= false;
1175 clamshellClosed
= false;
1176 clamshellExists
= false;
1177 clamshellDisabled
= true;
1178 acAdaptorConnected
= true;
1179 clamshellSleepDisabled
= false;
1180 gWakeReasonString
[0] = '\0';
1182 // Initialize to user active.
1183 // Will never transition to user inactive w/o wrangler.
1184 fullWakeReason
= kFullWakeReasonLocalUser
;
1185 userIsActive
= userWasActive
= true;
1186 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1188 // Set the default system capabilities at boot.
1189 _currentCapability
= kIOPMSystemCapabilityCPU
|
1190 kIOPMSystemCapabilityGraphics
|
1191 kIOPMSystemCapabilityAudio
|
1192 kIOPMSystemCapabilityNetwork
;
1194 _pendingCapability
= _currentCapability
;
1195 _desiredCapability
= _currentCapability
;
1196 _highestCapability
= _currentCapability
;
1197 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1199 queuedSleepWakeUUIDString
= NULL
;
1200 initializeBootSessionUUID();
1201 pmStatsAppResponses
= OSArray::withCapacity(5);
1202 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1203 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1204 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1205 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1206 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1207 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1208 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1210 pmStatsLock
= IOLockAlloc();
1211 idxPMCPUClamshell
= kCPUUnknownIndex
;
1212 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1214 tmpDict
= OSDictionary::withCapacity(1);
1215 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1218 settingsCallbacks
= OSDictionary::withCapacity(1);
1220 // Create a list of the valid PM settings that we'll relay to
1221 // interested clients in setProperties() => setPMSetting()
1222 allowedPMSettings
= OSArray::withObjects(
1223 (const OSObject
**)settingsArr
,
1224 kRootDomainSettingsCount
,
1227 // List of PM settings that should not automatically publish itself
1228 // as a feature when registered by a listener.
1229 noPublishPMSettings
= OSArray::withObjects(
1230 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1232 fPMSettingsDict
= OSDictionary::withCapacity(5);
1233 preventIdleSleepList
= OSSet::withCapacity(8);
1234 preventSystemSleepList
= OSSet::withCapacity(2);
1236 PMinit(); // creates gIOPMWorkLoop
1237 gIOPMWorkLoop
= getIOPMWorkloop();
1239 // Create IOPMPowerStateQueue used to queue external power
1240 // events, and to handle those events on the PM work loop.
1241 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1242 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1243 &IOPMrootDomain::dispatchPowerEvent
));
1244 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1246 // create our power parent
1247 patriarch
= new IORootParent
;
1249 patriarch
->attach(this);
1250 patriarch
->start(this);
1251 patriarch
->addPowerChild(this);
1253 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1254 changePowerStateToPriv(ON_STATE
);
1256 // install power change handler
1257 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1260 // Register for a notification when IODisplayWrangler is published
1261 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1263 _displayWranglerNotifier
= addMatchingNotification(
1264 gIOPublishNotification
, tmpDict
,
1265 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1271 #if defined(__i386__) || defined(__x86_64__)
1273 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1275 notifier
= addMatchingNotification(
1276 gIOFirstPublishNotification
, tmpDict
,
1277 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1282 wranglerIdleSettings
= NULL
;
1283 OSNumber
* wranglerIdlePeriod
= NULL
;
1284 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1285 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1287 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1288 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1289 wranglerIdlePeriod
);
1291 if(wranglerIdlePeriod
)
1292 wranglerIdlePeriod
->release();
1295 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1296 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1297 ucClassName
->release();
1299 // IOBacklightDisplay can take a long time to load at boot, or it may
1300 // not load at all if you're booting with clamshell closed. We publish
1301 // 'DisplayDims' here redundantly to get it published early and at all.
1302 OSDictionary
* matching
;
1303 matching
= serviceMatching("IOPMPowerSource");
1304 psIterator
= getMatchingServices( matching
);
1305 if (matching
) matching
->release();
1306 if( psIterator
&& psIterator
->getNextObject() )
1308 // There's at least one battery on the system, so we publish
1309 // 'DisplayDims' support for the LCD.
1310 publishFeature("DisplayDims");
1313 psIterator
->release();
1316 sysctl_register_oid(&sysctl__kern_sleeptime
);
1317 sysctl_register_oid(&sysctl__kern_waketime
);
1318 sysctl_register_oid(&sysctl__kern_willshutdown
);
1319 sysctl_register_oid(&sysctl__kern_iokittest
);
1320 sysctl_register_oid(&sysctl__debug_iokit
);
1321 sysctl_register_oid(&sysctl__hw_targettype
);
1323 #if !CONFIG_EMBEDDED
1324 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1325 sysctl_register_oid(&sysctl__kern_progressmeter
);
1326 sysctl_register_oid(&sysctl__kern_wakereason
);
1327 #endif /* !CONFIG_EMBEDDED */
1328 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1329 sysctl_register_oid(&sysctl__kern_progressoptions
);
1332 IOHibernateSystemInit(this);
1335 registerService(); // let clients find us
1340 //******************************************************************************
1343 // Receive a setProperty call
1344 // The "System Boot" property means the system is completely booted.
1345 //******************************************************************************
1347 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1349 IOReturn return_value
= kIOReturnSuccess
;
1350 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1353 const OSSymbol
*key
;
1355 OSCollectionIterator
* iter
= 0;
1357 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1358 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1359 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1360 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1361 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1362 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1363 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1364 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1365 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1366 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1367 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1369 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1370 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1371 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1372 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1373 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1374 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1379 return_value
= kIOReturnBadArgument
;
1383 iter
= OSCollectionIterator::withCollection(dict
);
1386 return_value
= kIOReturnNoMemory
;
1390 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1391 (obj
= dict
->getObject(key
)))
1393 if (key
->isEqualTo(publish_simulated_battery_string
))
1395 if (OSDynamicCast(OSBoolean
, obj
))
1396 publishResource(key
, kOSBooleanTrue
);
1398 else if (key
->isEqualTo(idle_seconds_string
))
1400 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1402 setProperty(key
, n
);
1403 idleSeconds
= n
->unsigned32BitValue();
1406 else if (key
->isEqualTo(boot_complete_string
))
1408 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1410 else if (key
->isEqualTo(sys_shutdown_string
))
1412 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1413 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1415 else if (key
->isEqualTo(battery_warning_disabled_string
))
1417 setProperty(key
, obj
);
1420 else if (key
->isEqualTo(hibernatemode_string
) ||
1421 key
->isEqualTo(hibernatefilemin_string
) ||
1422 key
->isEqualTo(hibernatefilemax_string
) ||
1423 key
->isEqualTo(hibernatefreeratio_string
) ||
1424 key
->isEqualTo(hibernatefreetime_string
))
1426 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1427 setProperty(key
, n
);
1429 else if (key
->isEqualTo(hibernatefile_string
))
1431 OSString
* str
= OSDynamicCast(OSString
, obj
);
1432 if (str
) setProperty(key
, str
);
1435 else if (key
->isEqualTo(sleepdisabled_string
))
1437 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1439 setProperty(key
, b
);
1440 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1443 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1446 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1448 else if (key
->isEqualTo(loginwindow_progress_string
))
1450 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1451 uint32_t data
= n
->unsigned32BitValue();
1452 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1453 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1456 else if (key
->isEqualTo(coredisplay_progress_string
))
1458 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1459 uint32_t data
= n
->unsigned32BitValue();
1460 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1461 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1464 else if (key
->isEqualTo(coregraphics_progress_string
))
1466 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1467 uint32_t data
= n
->unsigned32BitValue();
1468 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1469 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1472 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1473 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1474 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1475 key
->isEqualTo(stall_halt_string
))
1477 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1478 setProperty(key
, b
);
1480 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1481 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1482 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1483 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1485 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1486 setProperty(key
, n
);
1488 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1490 if (kOSBooleanTrue
== obj
)
1491 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1493 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1494 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1497 // Relay our allowed PM settings onto our registered PM clients
1498 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1500 return_value
= setPMSetting(key
, obj
);
1501 if (kIOReturnSuccess
!= return_value
)
1504 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1506 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1507 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1509 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1513 _debugWakeSeconds
= 0;
1514 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1516 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1518 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1521 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1522 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1524 const IOPMCalendarStruct
* cs
=
1525 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1528 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1530 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1531 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1537 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1542 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1543 if(boot_complete_string
) boot_complete_string
->release();
1544 if(sys_shutdown_string
) sys_shutdown_string
->release();
1545 if(stall_halt_string
) stall_halt_string
->release();
1546 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1547 if(idle_seconds_string
) idle_seconds_string
->release();
1548 if(sleepdisabled_string
) sleepdisabled_string
->release();
1549 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1550 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1551 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1552 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1554 if(hibernatemode_string
) hibernatemode_string
->release();
1555 if(hibernatefile_string
) hibernatefile_string
->release();
1556 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1557 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1559 if (iter
) iter
->release();
1560 return return_value
;
1564 // MARK: Aggressiveness
1566 //******************************************************************************
1567 // setAggressiveness
1569 // Override IOService::setAggressiveness()
1570 //******************************************************************************
1572 IOReturn
IOPMrootDomain::setAggressiveness(
1574 unsigned long value
)
1576 return setAggressiveness( type
, value
, 0 );
1580 * Private setAggressiveness() with an internal options argument.
1582 IOReturn
IOPMrootDomain::setAggressiveness(
1584 unsigned long value
,
1585 IOOptionBits options
)
1587 AggressivesRequest
* entry
;
1588 AggressivesRequest
* request
;
1591 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1592 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1594 request
= IONew(AggressivesRequest
, 1);
1596 return kIOReturnNoMemory
;
1598 memset(request
, 0, sizeof(*request
));
1599 request
->options
= options
;
1600 request
->dataType
= kAggressivesRequestTypeRecord
;
1601 request
->data
.record
.type
= (uint32_t) type
;
1602 request
->data
.record
.value
= (uint32_t) value
;
1606 // Update disk quick spindown flag used by getAggressiveness().
1607 // Never merge requests with quick spindown flags set.
1609 if (options
& kAggressivesOptionQuickSpindownEnable
)
1610 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1611 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1612 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1615 // Coalesce requests with identical aggressives types.
1616 // Deal with callers that calls us too "aggressively".
1618 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1620 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1621 (entry
->data
.record
.type
== type
) &&
1622 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1624 entry
->data
.record
.value
= value
;
1633 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1636 AGGRESSIVES_UNLOCK();
1639 IODelete(request
, AggressivesRequest
, 1);
1641 if (options
& kAggressivesOptionSynchronous
)
1642 handleAggressivesRequests(); // not truly synchronous
1644 thread_call_enter(aggressivesThreadCall
);
1646 return kIOReturnSuccess
;
1649 //******************************************************************************
1650 // getAggressiveness
1652 // Override IOService::setAggressiveness()
1653 // Fetch the aggressiveness factor with the given type.
1654 //******************************************************************************
1656 IOReturn
IOPMrootDomain::getAggressiveness (
1658 unsigned long * outLevel
)
1664 return kIOReturnBadArgument
;
1668 // Disk quick spindown in effect, report value = 1
1670 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1671 (type
== kPMMinutesToSpinDown
))
1673 value
= kAggressivesMinValue
;
1677 // Consult the pending request queue.
1681 AggressivesRequest
* entry
;
1683 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1685 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1686 (entry
->data
.record
.type
== type
) &&
1687 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1689 value
= entry
->data
.record
.value
;
1696 // Consult the backend records.
1698 if (!source
&& aggressivesData
)
1700 AggressivesRecord
* record
;
1703 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1704 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1706 for (i
= 0; i
< count
; i
++, record
++)
1708 if (record
->type
== type
)
1710 value
= record
->value
;
1717 AGGRESSIVES_UNLOCK();
1721 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1722 source
, (uint32_t) type
, value
);
1723 *outLevel
= (unsigned long) value
;
1724 return kIOReturnSuccess
;
1728 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1729 *outLevel
= 0; // default return = 0, driver may not check for error
1730 return kIOReturnInvalid
;
1734 //******************************************************************************
1735 // joinAggressiveness
1737 // Request from IOService to join future aggressiveness broadcasts.
1738 //******************************************************************************
1740 IOReturn
IOPMrootDomain::joinAggressiveness(
1741 IOService
* service
)
1743 AggressivesRequest
* request
;
1745 if (!service
|| (service
== this))
1746 return kIOReturnBadArgument
;
1748 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1750 request
= IONew(AggressivesRequest
, 1);
1752 return kIOReturnNoMemory
;
1754 service
->retain(); // released by synchronizeAggressives()
1756 memset(request
, 0, sizeof(*request
));
1757 request
->dataType
= kAggressivesRequestTypeService
;
1758 request
->data
.service
= service
;
1761 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1762 AGGRESSIVES_UNLOCK();
1764 thread_call_enter(aggressivesThreadCall
);
1766 return kIOReturnSuccess
;
1769 //******************************************************************************
1770 // handleAggressivesRequests
1772 // Backend thread processes all incoming aggressiveness requests in the queue.
1773 //******************************************************************************
1776 handleAggressivesFunction(
1777 thread_call_param_t param1
,
1778 thread_call_param_t param2
)
1782 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1786 void IOPMrootDomain::handleAggressivesRequests( void )
1788 AggressivesRecord
* start
;
1789 AggressivesRecord
* record
;
1790 AggressivesRequest
* request
;
1791 queue_head_t joinedQueue
;
1795 bool pingSelf
= false;
1799 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1800 queue_empty(&aggressivesQueue
))
1803 gAggressivesState
|= kAggressivesStateBusy
;
1804 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1805 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1810 queue_init(&joinedQueue
);
1814 // Remove request from the incoming queue in FIFO order.
1815 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1816 switch (request
->dataType
)
1818 case kAggressivesRequestTypeRecord
:
1819 // Update existing record if found.
1821 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1823 if (record
->type
== request
->data
.record
.type
)
1827 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1829 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1832 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1833 kAggressivesRecordFlagModified
);
1834 DLOG("disk spindown accelerated, was %u min\n",
1838 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1840 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1843 record
->flags
|= kAggressivesRecordFlagModified
;
1844 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1845 DLOG("disk spindown restored to %u min\n",
1849 else if (record
->value
!= request
->data
.record
.value
)
1851 record
->value
= request
->data
.record
.value
;
1852 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1855 record
->flags
|= kAggressivesRecordFlagModified
;
1862 // No matching record, append a new record.
1864 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1866 AggressivesRecord newRecord
;
1868 newRecord
.flags
= kAggressivesRecordFlagModified
;
1869 newRecord
.type
= request
->data
.record
.type
;
1870 newRecord
.value
= request
->data
.record
.value
;
1871 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1873 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1874 DLOG("disk spindown accelerated\n");
1877 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1879 // OSData may have switched to another (larger) buffer.
1880 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1881 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1885 // Finished processing the request, release it.
1886 IODelete(request
, AggressivesRequest
, 1);
1889 case kAggressivesRequestTypeService
:
1890 // synchronizeAggressives() will free request.
1891 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1895 panic("bad aggressives request type %x\n", request
->dataType
);
1898 } while (!queue_empty(&aggressivesQueue
));
1900 // Release the lock to perform work, with busy flag set.
1901 if (!queue_empty(&joinedQueue
) || broadcast
)
1903 AGGRESSIVES_UNLOCK();
1904 if (!queue_empty(&joinedQueue
))
1905 synchronizeAggressives(&joinedQueue
, start
, count
);
1907 broadcastAggressives(start
, count
);
1911 // Remove the modified flag from all records.
1912 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1914 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1915 ((record
->type
== kPMMinutesToDim
) ||
1916 (record
->type
== kPMMinutesToSleep
)))
1919 record
->flags
&= ~kAggressivesRecordFlagModified
;
1922 // Check the incoming queue again since new entries may have been
1923 // added while lock was released above.
1925 } while (!queue_empty(&aggressivesQueue
));
1927 gAggressivesState
&= ~kAggressivesStateBusy
;
1930 AGGRESSIVES_UNLOCK();
1932 // Root domain is interested in system and display sleep slider changes.
1933 // Submit a power event to handle those changes on the PM work loop.
1935 if (pingSelf
&& pmPowerStateQueue
) {
1936 pmPowerStateQueue
->submitPowerEvent(
1937 kPowerEventPolicyStimulus
,
1938 (void *) kStimulusAggressivenessChanged
);
1942 //******************************************************************************
1943 // synchronizeAggressives
1945 // Push all known aggressiveness records to one or more IOService.
1946 //******************************************************************************
1948 void IOPMrootDomain::synchronizeAggressives(
1949 queue_head_t
* joinedQueue
,
1950 const AggressivesRecord
* array
,
1953 IOService
* service
;
1954 AggressivesRequest
* request
;
1955 const AggressivesRecord
* record
;
1956 IOPMDriverCallEntry callEntry
;
1960 while (!queue_empty(joinedQueue
))
1962 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1963 if (request
->dataType
== kAggressivesRequestTypeService
)
1964 service
= request
->data
.service
;
1968 IODelete(request
, AggressivesRequest
, 1);
1973 if (service
->assertPMDriverCall(&callEntry
))
1975 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1977 value
= record
->value
;
1978 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1979 value
= kAggressivesMinValue
;
1981 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1982 record
->type
, value
, service
->getName());
1983 service
->setAggressiveness(record
->type
, value
);
1985 service
->deassertPMDriverCall(&callEntry
);
1987 service
->release(); // retained by joinAggressiveness()
1992 //******************************************************************************
1993 // broadcastAggressives
1995 // Traverse PM tree and call setAggressiveness() for records that have changed.
1996 //******************************************************************************
1998 void IOPMrootDomain::broadcastAggressives(
1999 const AggressivesRecord
* array
,
2002 IORegistryIterator
* iter
;
2003 IORegistryEntry
* entry
;
2004 IOPowerConnection
* connect
;
2005 IOService
* service
;
2006 const AggressivesRecord
* record
;
2007 IOPMDriverCallEntry callEntry
;
2011 iter
= IORegistryIterator::iterateOver(
2012 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2018 while ((entry
= iter
->getNextObject()))
2020 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2021 if (!connect
|| !connect
->getReadyFlag())
2024 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
2026 if (service
->assertPMDriverCall(&callEntry
))
2028 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
2030 if (record
->flags
& kAggressivesRecordFlagModified
)
2032 value
= record
->value
;
2033 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2034 value
= kAggressivesMinValue
;
2035 _LOG("broadcastAggressives %x = %u to %s\n",
2036 record
->type
, value
, service
->getName());
2037 service
->setAggressiveness(record
->type
, value
);
2040 service
->deassertPMDriverCall(&callEntry
);
2046 while (!entry
&& !iter
->isValid());
2052 // MARK: System Sleep
2054 //******************************************************************************
2055 // startIdleSleepTimer
2057 //******************************************************************************
2059 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2061 AbsoluteTime deadline
;
2065 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2070 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2071 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2072 idleSleepTimerPending
= true;
2076 thread_call_enter(extraSleepTimer
);
2078 DLOG("idle timer set for %u seconds\n", inSeconds
);
2081 //******************************************************************************
2082 // cancelIdleSleepTimer
2084 //******************************************************************************
2086 void IOPMrootDomain::cancelIdleSleepTimer( void )
2089 if (idleSleepTimerPending
)
2091 DLOG("idle timer cancelled\n");
2092 thread_call_cancel(extraSleepTimer
);
2093 idleSleepTimerPending
= false;
2095 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2097 clock_usec_t microsecs
;
2098 clock_get_uptime(&now
);
2099 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2100 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2101 if (assertOnWakeReport
) {
2102 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2103 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2109 //******************************************************************************
2110 // idleSleepTimerExpired
2112 //******************************************************************************
2114 static void idleSleepTimerExpired(
2115 thread_call_param_t us
, thread_call_param_t
)
2117 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2120 //******************************************************************************
2121 // handleSleepTimerExpiration
2123 // The time between the sleep idle timeout and the next longest one has elapsed.
2124 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2125 //******************************************************************************
2127 void IOPMrootDomain::handleSleepTimerExpiration( void )
2129 if (!gIOPMWorkLoop
->inGate())
2131 gIOPMWorkLoop
->runAction(
2132 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2133 &IOPMrootDomain::handleSleepTimerExpiration
),
2140 DLOG("sleep timer expired\n");
2143 idleSleepTimerPending
= false;
2145 clock_get_uptime(&time
);
2146 setQuickSpinDownTimeout();
2147 adjustPowerState(true);
2150 //******************************************************************************
2151 // getTimeToIdleSleep
2153 // Returns number of seconds left before going into idle sleep.
2154 // Caller has to make sure that idle sleep is allowed at the time of calling
2156 //******************************************************************************
2158 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2161 AbsoluteTime now
, lastActivityTime
;
2163 uint32_t minutesSinceUserInactive
= 0;
2164 uint32_t sleepDelay
= 0;
2166 if (!idleSleepEnabled
)
2169 if (userActivityTime
)
2170 lastActivityTime
= userActivityTime
;
2172 lastActivityTime
= userBecameInactiveTime
;
2174 clock_get_uptime(&now
);
2175 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2177 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2178 absolutetime_to_nanoseconds(now
, &nanos
);
2179 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2181 if (minutesSinceUserInactive
>= sleepSlider
)
2184 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2188 sleepDelay
= sleepSlider
;
2191 DLOG("user inactive %u min, time to idle sleep %u min\n",
2192 minutesSinceUserInactive
, sleepDelay
);
2194 return (sleepDelay
* 60);
2197 //******************************************************************************
2198 // setQuickSpinDownTimeout
2200 //******************************************************************************
2202 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2206 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2209 //******************************************************************************
2210 // restoreUserSpinDownTimeout
2212 //******************************************************************************
2214 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2218 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2221 //******************************************************************************
2224 //******************************************************************************
2227 IOReturn
IOPMrootDomain::sleepSystem( void )
2229 return sleepSystemOptions(NULL
);
2233 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2235 OSObject
*obj
= NULL
;
2236 OSString
*reason
= NULL
;
2237 /* sleepSystem is a public function, and may be called by any kernel driver.
2238 * And that's bad - drivers should sleep the system by calling
2239 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2241 * Note that user space app calls to IOPMSleepSystem() will also travel
2242 * this code path and thus be correctly identified as software sleeps.
2245 if (options
&& options
->getObject("OSSwitch"))
2247 // Log specific sleep cause for OS Switch hibernation
2248 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2251 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2253 reason
= OSDynamicCast(OSString
, obj
);
2254 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2255 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2258 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2262 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2264 /* Called from both gated and non-gated context */
2266 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2268 return kIOReturnNotPermitted
;
2271 pmPowerStateQueue
->submitPowerEvent(
2272 kPowerEventPolicyStimulus
,
2273 (void *) kStimulusDemandSystemSleep
,
2276 return kIOReturnSuccess
;
2279 //******************************************************************************
2282 // This overrides powerChangeDone in IOService.
2283 //******************************************************************************
2285 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2287 #if !__i386__ && !__x86_64__
2288 uint64_t timeSinceReset
= 0;
2292 DLOG("PowerChangeDone: %u->%u\n",
2293 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2295 switch ( getPowerState() )
2298 if (previousPowerState
!= ON_STATE
)
2301 acceptSystemWakeEvents(true);
2303 // re-enable this timer for next sleep
2304 cancelIdleSleepTimer();
2307 clock_usec_t microsecs
;
2308 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2310 gIOLastSleepTime
.tv_sec
= secs
;
2311 gIOLastSleepTime
.tv_usec
= microsecs
;
2312 gIOLastWakeTime
.tv_sec
= 0;
2313 gIOLastWakeTime
.tv_usec
= 0;
2314 gIOLastSleepAbsTime
= now
;
2316 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2317 clock_usec_t microsecs
;
2318 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2319 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2321 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2322 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2323 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2324 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2325 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2327 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2328 wake2DarkwakeDelay
= 0;
2331 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2333 IOHibernateSystemHasSlept();
2335 evaluateSystemSleepPolicyFinal();
2337 LOG("System Sleep\n");
2339 if (thermalWarningState
) {
2340 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2342 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2346 assertOnWakeSecs
= 0;
2347 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2348 lowBatteryCondition
= false;
2350 getPlatform()->sleepKernel();
2352 // The CPU(s) are off at this point,
2353 // Code will resume execution here upon wake.
2355 clock_get_uptime(&gIOLastWakeAbsTime
);
2356 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2357 _highestCapability
= 0;
2359 ((IOService
*)this)->start_watchdog_timer(); //14456299
2361 IOHibernateSystemWake();
2364 // sleep transition complete
2365 gSleepOrShutdownPending
= 0;
2367 // trip the reset of the calendar clock
2369 clock_sec_t wakeSecs
;
2370 clock_usec_t wakeMicrosecs
;
2372 clock_wakeup_calendar();
2374 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2375 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2376 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2380 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2383 lastSleepReason
= 0;
2385 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2386 _debugWakeSeconds
= 0;
2387 _scheduledAlarms
= 0;
2389 #if defined(__i386__) || defined(__x86_64__)
2390 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2391 wranglerTickled
= false;
2392 graphicsSuppressed
= false;
2393 darkWakePostTickle
= false;
2394 darkWakeHibernateError
= false;
2395 darkWakeToSleepASAP
= true;
2396 logGraphicsClamp
= true;
2397 sleepTimerMaintenance
= false;
2398 sleepToStandby
= false;
2399 wranglerTickleLatched
= false;
2400 userWasActive
= false;
2401 fullWakeReason
= kFullWakeReasonNone
;
2403 OSString
* wakeType
= OSDynamicCast(
2404 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2405 OSString
* wakeReason
= OSDynamicCast(
2406 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2408 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2409 gWakeReasonString
[0] == '\0')
2411 // Until the platform driver can claim its wake reasons
2412 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2413 sizeof(gWakeReasonString
));
2416 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2418 lowBatteryCondition
= true;
2419 darkWakeMaintenance
= true;
2421 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2424 OSNumber
* hibOptions
= OSDynamicCast(
2425 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2426 if (hibernateAborted
|| ((hibOptions
&&
2427 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2429 // Hibernate aborted, or EFI brought up graphics
2430 wranglerTickled
= true;
2431 DLOG("hibernation aborted %d, options 0x%x\n",
2433 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2438 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2439 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2441 // User wake or RTC alarm
2442 wranglerTickled
= true;
2446 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2448 // SMC standby timer trumps SleepX
2449 darkWakeMaintenance
= true;
2450 sleepTimerMaintenance
= true;
2453 if ((_lastDebugWakeSeconds
!= 0) &&
2454 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2456 // SleepX before maintenance
2457 wranglerTickled
= true;
2461 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2463 darkWakeMaintenance
= true;
2467 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2469 darkWakeMaintenance
= true;
2470 darkWakeSleepService
= true;
2472 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2473 sleepToStandby
= true;
2479 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2481 darkWakeMaintenance
= true;
2482 darkWakeHibernateError
= true;
2486 // Unidentified wake source, resume to full wake if debug
2487 // alarm is pending.
2489 if (_lastDebugWakeSeconds
&&
2490 (!wakeReason
|| wakeReason
->isEqualTo("")))
2491 wranglerTickled
= true;
2497 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2499 darkWakeMaintenance
= true;
2500 sleepTimerMaintenance
= true;
2502 else if (hibernateAborted
|| !wakeType
||
2503 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2504 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2506 // Post a HID tickle immediately - except for RTC maintenance wake.
2507 wranglerTickled
= true;
2511 darkWakeMaintenance
= true;
2515 if (wranglerTickled
)
2517 darkWakeToSleepASAP
= false;
2518 fullWakeReason
= kFullWakeReasonLocalUser
;
2521 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2523 handleDisplayPowerOn();
2525 else if (!darkWakeMaintenance
)
2527 // Early/late tickle for non-maintenance wake.
2528 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2529 kDarkWakeFlagHIDTickleEarly
) ||
2530 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2531 kDarkWakeFlagHIDTickleLate
))
2533 darkWakePostTickle
= true;
2536 #else /* !__i386__ && !__x86_64__ */
2537 timeSinceReset
= ml_get_time_since_reset();
2539 kdebugTrace(kPMLogSystemWake
, 0, timeSinceReset
>> 32, timeSinceReset
);
2540 // stay awake for at least 30 seconds
2541 wranglerTickled
= true;
2542 fullWakeReason
= kFullWakeReasonLocalUser
;
2543 startIdleSleepTimer(30);
2547 thread_call_enter(updateConsoleUsersEntry
);
2549 changePowerStateToPriv(ON_STATE
);
2551 #if !__i386__ && !__x86_64__
2553 if (previousPowerState
!= ON_STATE
)
2555 DLOG("Force re-evaluating aggressiveness\n");
2556 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2557 pmPowerStateQueue
->submitPowerEvent(
2558 kPowerEventPolicyStimulus
,
2559 (void *) kStimulusNoIdleSleepPreventers
);
2569 //******************************************************************************
2570 // requestPowerDomainState
2572 // Extend implementation in IOService. Running on PM work loop thread.
2573 //******************************************************************************
2575 IOReturn
IOPMrootDomain::requestPowerDomainState (
2576 IOPMPowerFlags childDesire
,
2577 IOPowerConnection
* childConnection
,
2578 unsigned long specification
)
2580 // Idle and system sleep prevention flags affects driver desire.
2581 // Children desire are irrelevant so they are cleared.
2583 return super::requestPowerDomainState(0, childConnection
, specification
);
2587 //******************************************************************************
2588 // updatePreventIdleSleepList
2590 // Called by IOService on PM work loop.
2591 // Returns true if PM policy recognized the driver's desire to prevent idle
2592 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2593 //******************************************************************************
2595 bool IOPMrootDomain::updatePreventIdleSleepList(
2596 IOService
* service
, bool addNotRemove
)
2598 unsigned int oldCount
, newCount
;
2602 #if defined(__i386__) || defined(__x86_64__)
2603 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2604 // idle sleep, except in the case of legacy disk I/O
2605 if ((service
!= wrangler
) && (service
!= this))
2611 oldCount
= preventIdleSleepList
->getCount();
2614 preventIdleSleepList
->setObject(service
);
2615 DLOG("prevent idle sleep list: %s+ (%u)\n",
2616 service
->getName(), preventIdleSleepList
->getCount());
2618 else if (preventIdleSleepList
->member(service
))
2620 preventIdleSleepList
->removeObject(service
);
2621 DLOG("prevent idle sleep list: %s- (%u)\n",
2622 service
->getName(), preventIdleSleepList
->getCount());
2624 newCount
= preventIdleSleepList
->getCount();
2626 if ((oldCount
== 0) && (newCount
!= 0))
2628 // Driver added to empty prevent list.
2629 // Update the driver desire to prevent idle sleep.
2630 // Driver desire does not prevent demand sleep.
2632 changePowerStateTo(ON_STATE
);
2634 else if ((oldCount
!= 0) && (newCount
== 0))
2636 // Last driver removed from prevent list.
2637 // Drop the driver clamp to allow idle sleep.
2639 changePowerStateTo(SLEEP_STATE
);
2640 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2642 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2643 &newCount
, sizeof(newCount
));
2645 #if defined(__i386__) || defined(__x86_64__)
2646 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2648 DLOG("Cannot cancel idle sleep\n");
2649 return false; // do not idle-cancel
2656 //******************************************************************************
2658 //******************************************************************************
2660 void IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
2662 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
2665 //******************************************************************************
2666 // preventSystemSleepListUpdate
2668 // Called by IOService on PM work loop.
2669 //******************************************************************************
2671 void IOPMrootDomain::updatePreventSystemSleepList(
2672 IOService
* service
, bool addNotRemove
)
2674 unsigned int oldCount
, newCount
;
2677 if (this == service
)
2680 oldCount
= preventSystemSleepList
->getCount();
2683 preventSystemSleepList
->setObject(service
);
2684 DLOG("prevent system sleep list: %s+ (%u)\n",
2685 service
->getName(), preventSystemSleepList
->getCount());
2686 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2688 clock_usec_t microsecs
;
2689 clock_get_uptime(&now
);
2690 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2691 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2692 if (assertOnWakeReport
) {
2693 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2694 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2698 else if (preventSystemSleepList
->member(service
))
2700 preventSystemSleepList
->removeObject(service
);
2701 DLOG("prevent system sleep list: %s- (%u)\n",
2702 service
->getName(), preventSystemSleepList
->getCount());
2704 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2706 // Lost all system sleep preventers.
2707 // Send stimulus if system sleep was blocked, and is in dark wake.
2708 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2711 newCount
= preventSystemSleepList
->getCount();
2712 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2713 &newCount
, sizeof(newCount
));
2716 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2719 OSCollectionIterator
*iterator
= NULL
;
2720 OSObject
*object
= NULL
;
2721 OSArray
*array
= NULL
;
2723 if (!gIOPMWorkLoop
->inGate())
2725 gIOPMWorkLoop
->runAction(
2726 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2727 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2728 this, (void *)idleSleepList
, (void *)systemSleepList
);
2732 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2734 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2735 array
= OSArray::withCapacity(5);
2737 while ((object
= iterator
->getNextObject()))
2739 IOService
*service
= OSDynamicCast(IOService
, object
);
2742 array
->setObject(OSSymbol::withCString(service
->getName()));
2746 iterator
->release();
2747 *idleSleepList
= array
;
2750 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2752 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2753 array
= OSArray::withCapacity(5);
2755 while ((object
= iterator
->getNextObject()))
2757 IOService
*service
= OSDynamicCast(IOService
, object
);
2760 array
->setObject(OSSymbol::withCString(service
->getName()));
2764 iterator
->release();
2765 *systemSleepList
= array
;
2769 //******************************************************************************
2772 // Override the superclass implementation to send a different message type.
2773 //******************************************************************************
2775 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2777 DLOG("tellChangeDown %u->%u\n",
2778 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2780 if (SLEEP_STATE
== stateNum
)
2782 // Legacy apps were already told in the full->dark transition
2783 if (!ignoreTellChangeDown
)
2784 tracePoint( kIOPMTracePointSleepApplications
);
2786 tracePoint( kIOPMTracePointSleepPriorityClients
);
2789 if (!ignoreTellChangeDown
) {
2790 userActivityAtSleep
= userActivityCount
;
2791 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2793 if (SLEEP_STATE
== stateNum
) {
2794 hibernateAborted
= false;
2796 // Direct callout into OSKext so it can disable kext unloads
2797 // during sleep/wake to prevent deadlocks.
2798 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2800 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2802 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2803 // But tellClientsWithResponse() must be called for both.
2804 ignoreTellChangeDown
= true;
2808 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2811 //******************************************************************************
2814 // Override the superclass implementation to send a different message type.
2815 // This must be idle sleep since we don't ask during any other power change.
2816 //******************************************************************************
2818 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2820 DLOG("askChangeDown %u->%u\n",
2821 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2823 // Don't log for dark wake entry
2824 if (kSystemTransitionSleep
== _systemTransitionType
)
2825 tracePoint( kIOPMTracePointSleepApplications
);
2827 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2830 //******************************************************************************
2831 // askChangeDownDone
2833 // An opportunity for root domain to cancel the power transition,
2834 // possibily due to an assertion created by powerd in response to
2835 // kIOMessageCanSystemSleep.
2838 // full -> dark wake transition
2839 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2840 // 2. askChangeDownDone()
2841 // dark -> sleep transition
2842 // 1. Notify powerd with kIOMessageCanSystemSleep
2843 // 2. askChangeDownDone()
2846 // full -> dark wake transition
2847 // 1. Notify powerd with kIOMessageCanSystemSleep
2848 // 2. askChangeDownDone()
2849 // dark -> sleep transition
2850 // 1. Notify powerd with kIOMessageCanSystemSleep
2851 // 2. askChangeDownDone()
2852 //******************************************************************************
2854 void IOPMrootDomain::askChangeDownDone(
2855 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2857 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2858 *inOutChangeFlags
, *cancel
,
2859 _systemTransitionType
,
2860 _currentCapability
, _pendingCapability
);
2862 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2864 // Dark->Sleep transition.
2865 // Check if there are any deny sleep assertions.
2866 // lastSleepReason already set by handleOurPowerChangeStart()
2868 if (!checkSystemCanSleep(lastSleepReason
))
2870 // Cancel dark wake to sleep transition.
2871 // Must re-scan assertions upon entering dark wake.
2874 DLOG("cancel dark->sleep\n");
2879 //******************************************************************************
2880 // systemDidNotSleep
2882 // Work common to both canceled or aborted sleep.
2883 //******************************************************************************
2885 void IOPMrootDomain::systemDidNotSleep( void )
2887 // reset console lock state
2888 thread_call_enter(updateConsoleUsersEntry
);
2892 if (idleSleepEnabled
)
2894 // stay awake for at least idleSeconds
2895 startIdleSleepTimer(idleSeconds
);
2900 if (idleSleepEnabled
&& !userIsActive
)
2902 // Manually start the idle sleep timer besides waiting for
2903 // the user to become inactive.
2904 startIdleSleepTimer( kIdleSleepRetryInterval
);
2908 preventTransitionToUserActive(false);
2909 IOService::setAdvisoryTickleEnable( true );
2911 // After idle revert and cancel, send a did-change message to powerd
2912 // to balance the previous will-change message. Kernel clients do not
2913 // need this since sleep cannot be canceled once they are notified.
2915 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2916 (_pendingCapability
!= _currentCapability
) &&
2917 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2919 // Differs from a real capability gain change where notifyRef != 0,
2920 // but it is zero here since no response is expected.
2922 IOPMSystemCapabilityChangeParameters params
;
2924 bzero(¶ms
, sizeof(params
));
2925 params
.fromCapabilities
= _pendingCapability
;
2926 params
.toCapabilities
= _currentCapability
;
2927 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2929 DLOG("MESG cap %x->%x did change\n",
2930 params
.fromCapabilities
, params
.toCapabilities
);
2931 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2932 ¶ms
, sizeof(params
));
2936 //******************************************************************************
2939 // Notify registered applications and kernel clients that we are not dropping
2942 // We override the superclass implementation so we can send a different message
2943 // type to the client or application being notified.
2945 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2946 //******************************************************************************
2948 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2950 DLOG("tellNoChangeDown %u->%u\n",
2951 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2953 // Sleep canceled, clear the sleep trace point.
2954 tracePoint(kIOPMTracePointSystemUp
);
2956 systemDidNotSleep();
2957 return tellClients( kIOMessageSystemWillNotSleep
);
2960 //******************************************************************************
2963 // Notify registered applications and kernel clients that we are raising power.
2965 // We override the superclass implementation so we can send a different message
2966 // type to the client or application being notified.
2967 //******************************************************************************
2969 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2971 DLOG("tellChangeUp %u->%u\n",
2972 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2974 ignoreTellChangeDown
= false;
2976 if ( stateNum
== ON_STATE
)
2978 // Direct callout into OSKext so it can disable kext unloads
2979 // during sleep/wake to prevent deadlocks.
2980 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2982 // Notify platform that sleep was cancelled or resumed.
2983 getPlatform()->callPlatformFunction(
2984 sleepMessagePEFunction
, false,
2985 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2988 if (getPowerState() == ON_STATE
)
2990 // this is a quick wake from aborted sleep
2991 systemDidNotSleep();
2992 tellClients( kIOMessageSystemWillPowerOn
);
2995 tracePoint( kIOPMTracePointWakeApplications
);
2996 tellClients( kIOMessageSystemHasPoweredOn
);
3000 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3001 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3002 ((params)->fromCapabilities & (flag)) && \
3003 (((params)->toCapabilities & (flag)) == 0))
3005 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3006 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3007 ((params)->toCapabilities & (flag)) && \
3008 (((params)->fromCapabilities & (flag)) == 0))
3010 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3011 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3012 ((params)->fromCapabilities & (flag)) && \
3013 (((params)->toCapabilities & (flag)) == 0))
3015 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3016 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3017 ((params)->toCapabilities & (flag)) && \
3018 (((params)->fromCapabilities & (flag)) == 0))
3020 //******************************************************************************
3021 // sysPowerDownHandler
3023 // Perform a vfs sync before system sleep.
3024 //******************************************************************************
3026 IOReturn
IOPMrootDomain::sysPowerDownHandler(
3027 void * target
, void * refCon
,
3028 UInt32 messageType
, IOService
* service
,
3029 void * messageArgs
, vm_size_t argSize
)
3033 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3036 return kIOReturnUnsupported
;
3038 if (messageType
== kIOMessageSystemWillSleep
)
3041 IOPowerStateChangeNotification
*notify
=
3042 (IOPowerStateChangeNotification
*)messageArgs
;
3044 notify
->returnValue
= 30 * 1000 * 1000;
3046 gRootDomain
->swdDebugSetupEntry
,
3047 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
3050 else if (messageType
== kIOMessageSystemCapabilityChange
)
3052 IOPMSystemCapabilityChangeParameters
* params
=
3053 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3055 // Interested applications have been notified of an impending power
3056 // change and have acked (when applicable).
3057 // This is our chance to save whatever state we can before powering
3059 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3062 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3063 params
->fromCapabilities
, params
->toCapabilities
,
3064 params
->changeFlags
);
3066 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
3068 // We will ack within 20 seconds
3069 params
->maxWaitForReply
= 20 * 1000 * 1000;
3071 // Remove EFI/BootRom's previous wake's failure data
3072 PERemoveNVRAMProperty(kIOEFIBootRomFailureKey
);
3075 gRootDomain
->evaluateSystemSleepPolicyEarly();
3077 // add in time we could spend freeing pages
3078 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
3080 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3082 DLOG("sysPowerDownHandler max wait %d s\n",
3083 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3086 // Notify platform that sleep has begun, after the early
3087 // sleep policy evaluation.
3088 getPlatform()->callPlatformFunction(
3089 sleepMessagePEFunction
, false,
3090 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3093 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3095 // Purposely delay the ack and hope that shutdown occurs quickly.
3096 // Another option is not to schedule the thread and wait for
3098 AbsoluteTime deadline
;
3099 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3100 thread_call_enter1_delayed(
3101 gRootDomain
->diskSyncCalloutEntry
,
3102 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3107 gRootDomain
->diskSyncCalloutEntry
,
3108 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3111 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3113 // We will ack within 110 seconds
3114 params
->maxWaitForReply
= 110 * 1000 * 1000;
3117 gRootDomain
->diskSyncCalloutEntry
,
3118 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3120 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3121 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3123 // WillChange for Full wake -> Darkwake
3124 params
->maxWaitForReply
= 30 * 1000 * 1000;
3126 gRootDomain
->swdDebugSetupEntry
,
3127 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3129 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3130 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3132 // DidChange for Full wake -> Darkwake
3133 params
->maxWaitForReply
= 30 * 1000 * 1000;
3135 gRootDomain
->swdDebugTearDownEntry
,
3136 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3140 ret
= kIOReturnSuccess
;
3146 //******************************************************************************
3147 // handleQueueSleepWakeUUID
3149 // Called from IOPMrootDomain when we're initiating a sleep,
3150 // or indirectly from PM configd when PM decides to clear the UUID.
3151 // PM clears the UUID several minutes after successful wake from sleep,
3152 // so that we might associate App spindumps with the immediately previous
3155 // @param obj has a retain on it. We're responsible for releasing that retain.
3156 //******************************************************************************
3158 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3160 OSString
*str
= NULL
;
3162 if (kOSBooleanFalse
== obj
)
3164 handlePublishSleepWakeUUID(NULL
);
3166 else if ((str
= OSDynamicCast(OSString
, obj
)))
3168 // This branch caches the UUID for an upcoming sleep/wake
3169 if (queuedSleepWakeUUIDString
) {
3170 queuedSleepWakeUUIDString
->release();
3171 queuedSleepWakeUUIDString
= NULL
;
3173 queuedSleepWakeUUIDString
= str
;
3174 queuedSleepWakeUUIDString
->retain();
3176 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3185 //******************************************************************************
3186 // handlePublishSleepWakeUUID
3188 // Called from IOPMrootDomain when we're initiating a sleep,
3189 // or indirectly from PM configd when PM decides to clear the UUID.
3190 // PM clears the UUID several minutes after successful wake from sleep,
3191 // so that we might associate App spindumps with the immediately previous
3193 //******************************************************************************
3195 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3200 * Clear the current UUID
3202 if (gSleepWakeUUIDIsSet
)
3204 DLOG("SleepWake UUID cleared\n");
3206 gSleepWakeUUIDIsSet
= false;
3208 removeProperty(kIOPMSleepWakeUUIDKey
);
3209 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3213 * Optionally, publish a new UUID
3215 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3217 OSString
*publishThisUUID
= NULL
;
3219 publishThisUUID
= queuedSleepWakeUUIDString
;
3220 publishThisUUID
->retain();
3222 if (publishThisUUID
)
3224 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3225 publishThisUUID
->release();
3228 gSleepWakeUUIDIsSet
= true;
3229 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3231 queuedSleepWakeUUIDString
->release();
3232 queuedSleepWakeUUIDString
= NULL
;
3236 //******************************************************************************
3237 // initializeBootSessionUUID
3239 // Initialize the boot session uuid at boot up and sets it into registry.
3240 //******************************************************************************
3242 void IOPMrootDomain::initializeBootSessionUUID(void)
3245 uuid_string_t new_uuid_string
;
3247 uuid_generate(new_uuid
);
3248 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3249 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3251 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3254 //******************************************************************************
3255 // changePowerStateTo & changePowerStateToPriv
3257 // Override of these methods for logging purposes.
3258 //******************************************************************************
3260 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3262 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3264 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3265 return kIOReturnUnsupported
;
3267 return super::changePowerStateTo(ordinal
);
3270 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3272 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3274 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3275 return kIOReturnUnsupported
;
3277 return super::changePowerStateToPriv(ordinal
);
3280 //******************************************************************************
3283 //******************************************************************************
3285 bool IOPMrootDomain::activitySinceSleep(void)
3287 return (userActivityCount
!= userActivityAtSleep
);
3290 bool IOPMrootDomain::abortHibernation(void)
3292 bool ret
= activitySinceSleep();
3294 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3296 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3297 hibernateAborted
= true;
3303 hibernate_should_abort(void)
3306 return (gRootDomain
->abortHibernation());
3311 //******************************************************************************
3312 // willNotifyPowerChildren
3314 // Called after all interested drivers have all acknowledged the power change,
3315 // but before any power children is informed. Dispatched though a thread call,
3316 // so it is safe to perform work that might block on a sleeping disk. PM state
3317 // machine (not thread) will block w/o timeout until this function returns.
3318 //******************************************************************************
3320 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3325 if (SLEEP_STATE
== newPowerState
)
3327 if (!tasksSuspended
)
3329 AbsoluteTime deadline
;
3330 tasksSuspended
= TRUE
;
3331 tasks_system_suspend(tasksSuspended
);
3333 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3334 #if !CONFIG_EMBEDDED
3335 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3336 #endif /* !CONFIG_EMBEDDED */
3340 IOHibernateSystemSleep();
3341 IOHibernateIOKitSleep();
3343 if (gRootDomain
->activitySinceSleep()) {
3344 dict
= OSDictionary::withCapacity(1);
3345 secs
= OSNumber::withNumber(1, 32);
3348 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3349 gRootDomain
->setProperties(dict
);
3350 MSG("Reverting sleep with relative wake\n");
3352 if (dict
) dict
->release();
3353 if (secs
) secs
->release();
3359 //******************************************************************************
3360 // sleepOnClamshellClosed
3362 // contains the logic to determine if the system should sleep when the clamshell
3364 //******************************************************************************
3366 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3368 if (!clamshellExists
)
3371 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3372 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3374 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3377 void IOPMrootDomain::sendClientClamshellNotification( void )
3379 /* Only broadcast clamshell alert if clamshell exists. */
3380 if (!clamshellExists
)
3383 setProperty(kAppleClamshellStateKey
,
3384 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3386 setProperty(kAppleClamshellCausesSleepKey
,
3387 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3389 /* Argument to message is a bitfiel of
3390 * ( kClamshellStateBit | kClamshellSleepBit )
3392 messageClients(kIOPMMessageClamshellStateChange
,
3393 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3394 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3397 //******************************************************************************
3398 // getSleepSupported
3401 //******************************************************************************
3403 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3405 return( platformSleepSupport
);
3408 //******************************************************************************
3409 // setSleepSupported
3412 //******************************************************************************
3414 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3416 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3417 OSBitOrAtomic(flags
, &platformSleepSupport
);
3420 //******************************************************************************
3421 // setDisableClamShellSleep
3423 //******************************************************************************
3425 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3427 if (gIOPMWorkLoop
->inGate() == false) {
3429 gIOPMWorkLoop
->runAction(
3430 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3437 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3438 if ( clamshellSleepDisabled
!= val
)
3440 clamshellSleepDisabled
= val
;
3441 // If clamshellSleepDisabled is reset to 0, reevaluate if
3442 // system need to go to sleep due to clamshell state
3443 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3444 handlePowerNotification(kLocalEvalClamshellCommand
);
3449 //******************************************************************************
3453 //******************************************************************************
3455 void IOPMrootDomain::wakeFromDoze( void )
3457 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3463 //******************************************************************************
3466 // Adds a new feature to the supported features dictionary
3467 //******************************************************************************
3469 void IOPMrootDomain::publishFeature( const char * feature
)
3471 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3474 //******************************************************************************
3475 // publishFeature (with supported power source specified)
3477 // Adds a new feature to the supported features dictionary
3478 //******************************************************************************
3480 void IOPMrootDomain::publishFeature(
3481 const char *feature
,
3482 uint32_t supportedWhere
,
3483 uint32_t *uniqueFeatureID
)
3485 static uint16_t next_feature_id
= 500;
3487 OSNumber
*new_feature_data
= NULL
;
3488 OSNumber
*existing_feature
= NULL
;
3489 OSArray
*existing_feature_arr
= NULL
;
3490 OSObject
*osObj
= NULL
;
3491 uint32_t feature_value
= 0;
3493 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3495 if(!supportedWhere
) {
3496 // Feature isn't supported anywhere!
3500 if(next_feature_id
> 5000) {
3501 // Far, far too many features!
3505 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3507 OSDictionary
*features
=
3508 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3510 // Create new features dict if necessary
3511 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3512 features
= OSDictionary::withDictionary(features
);
3514 features
= OSDictionary::withCapacity(1);
3517 // Create OSNumber to track new feature
3519 next_feature_id
+= 1;
3520 if( uniqueFeatureID
) {
3521 // We don't really mind if the calling kext didn't give us a place
3522 // to stash their unique id. Many kexts don't plan to unload, and thus
3523 // have no need to remove themselves later.
3524 *uniqueFeatureID
= next_feature_id
;
3527 feature_value
= (uint32_t)next_feature_id
;
3528 feature_value
<<= 16;
3529 feature_value
+= supportedWhere
;
3531 new_feature_data
= OSNumber::withNumber(
3532 (unsigned long long)feature_value
, 32);
3534 // Does features object already exist?
3535 if( (osObj
= features
->getObject(feature
)) )
3537 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3539 // We need to create an OSArray to hold the now 2 elements.
3540 existing_feature_arr
= OSArray::withObjects(
3541 (const OSObject
**)&existing_feature
, 1, 2);
3542 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3544 // Add object to existing array
3545 existing_feature_arr
= OSArray::withArray(
3546 existing_feature_arr
,
3547 existing_feature_arr
->getCount() + 1);
3550 if (existing_feature_arr
)
3552 existing_feature_arr
->setObject(new_feature_data
);
3553 features
->setObject(feature
, existing_feature_arr
);
3554 existing_feature_arr
->release();
3555 existing_feature_arr
= 0;
3558 // The easy case: no previously existing features listed. We simply
3559 // set the OSNumber at key 'feature' and we're on our way.
3560 features
->setObject(feature
, new_feature_data
);
3563 new_feature_data
->release();
3565 setProperty(kRootDomainSupportedFeatures
, features
);
3567 features
->release();
3569 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3571 // Notify EnergySaver and all those in user space so they might
3572 // re-populate their feature specific UI
3573 if(pmPowerStateQueue
) {
3574 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3578 //******************************************************************************
3579 // removePublishedFeature
3581 // Removes previously published feature
3582 //******************************************************************************
3584 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3586 IOReturn ret
= kIOReturnError
;
3587 uint32_t feature_value
= 0;
3588 uint16_t feature_id
= 0;
3589 bool madeAChange
= false;
3591 OSSymbol
*dictKey
= NULL
;
3592 OSCollectionIterator
*dictIterator
= NULL
;
3593 OSArray
*arrayMember
= NULL
;
3594 OSNumber
*numberMember
= NULL
;
3595 OSObject
*osObj
= NULL
;
3596 OSNumber
*osNum
= NULL
;
3597 OSArray
*arrayMemberCopy
;
3599 if (kBadPMFeatureID
== removeFeatureID
)
3600 return kIOReturnNotFound
;
3602 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3604 OSDictionary
*features
=
3605 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3607 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3609 // Any modifications to the dictionary are made to the copy to prevent
3610 // races & crashes with userland clients. Dictionary updated
3611 // automically later.
3612 features
= OSDictionary::withDictionary(features
);
3615 ret
= kIOReturnNotFound
;
3619 // We iterate 'features' dictionary looking for an entry tagged
3620 // with 'removeFeatureID'. If found, we remove it from our tracking
3621 // structures and notify the OS via a general interest message.
3623 dictIterator
= OSCollectionIterator::withCollection(features
);
3628 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3630 osObj
= features
->getObject(dictKey
);
3632 // Each Feature is either tracked by an OSNumber
3633 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3635 feature_value
= numberMember
->unsigned32BitValue();
3636 feature_id
= (uint16_t)(feature_value
>> 16);
3638 if( feature_id
== (uint16_t)removeFeatureID
)
3641 features
->removeObject(dictKey
);
3646 // Or tracked by an OSArray of OSNumbers
3647 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3649 unsigned int arrayCount
= arrayMember
->getCount();
3651 for(unsigned int i
=0; i
<arrayCount
; i
++)
3653 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3658 feature_value
= osNum
->unsigned32BitValue();
3659 feature_id
= (uint16_t)(feature_value
>> 16);
3661 if( feature_id
== (uint16_t)removeFeatureID
)
3664 if( 1 == arrayCount
) {
3665 // If the array only contains one element, remove
3667 features
->removeObject(dictKey
);
3669 // Otherwise remove the element from a copy of the array.
3670 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3671 if (arrayMemberCopy
)
3673 arrayMemberCopy
->removeObject(i
);
3674 features
->setObject(dictKey
, arrayMemberCopy
);
3675 arrayMemberCopy
->release();
3686 dictIterator
->release();
3690 ret
= kIOReturnSuccess
;
3692 setProperty(kRootDomainSupportedFeatures
, features
);
3694 // Notify EnergySaver and all those in user space so they might
3695 // re-populate their feature specific UI
3696 if(pmPowerStateQueue
) {
3697 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3700 ret
= kIOReturnNotFound
;
3704 if(features
) features
->release();
3705 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3709 //******************************************************************************
3710 // publishPMSetting (private)
3712 // Should only be called by PMSettingObject to publish a PM Setting as a
3713 // supported feature.
3714 //******************************************************************************
3716 void IOPMrootDomain::publishPMSetting(
3717 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3719 if (noPublishPMSettings
&&
3720 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3722 // Setting found in noPublishPMSettings array
3723 *featureID
= kBadPMFeatureID
;
3728 feature
->getCStringNoCopy(), where
, featureID
);
3731 //******************************************************************************
3732 // setPMSetting (private)
3734 // Internal helper to relay PM settings changes from user space to individual
3735 // drivers. Should be called only by IOPMrootDomain::setProperties.
3736 //******************************************************************************
3738 IOReturn
IOPMrootDomain::setPMSetting(
3739 const OSSymbol
*type
,
3742 PMSettingCallEntry
*entries
= 0;
3743 OSArray
*chosen
= 0;
3744 const OSArray
*array
;
3745 PMSettingObject
*pmso
;
3746 thread_t thisThread
;
3747 int i
, j
, count
, capacity
;
3750 return kIOReturnBadArgument
;
3754 // Update settings dict so changes are visible from copyPMSetting().
3755 fPMSettingsDict
->setObject(type
, object
);
3757 // Prep all PMSetting objects with the given 'type' for callout.
3758 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3759 if (!array
|| ((capacity
= array
->getCount()) == 0))
3762 // Array to retain PMSetting objects targeted for callout.
3763 chosen
= OSArray::withCapacity(capacity
);
3765 goto unlock_exit
; // error
3767 entries
= IONew(PMSettingCallEntry
, capacity
);
3769 goto unlock_exit
; // error
3770 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3772 thisThread
= current_thread();
3774 for (i
= 0, j
= 0; i
<capacity
; i
++)
3776 pmso
= (PMSettingObject
*) array
->getObject(i
);
3779 entries
[j
].thread
= thisThread
;
3780 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3781 chosen
->setObject(pmso
);
3790 // Call each pmso in the chosen array.
3791 for (i
=0; i
<count
; i
++)
3793 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3794 pmso
->dispatchPMSetting(type
, object
);
3798 for (i
=0; i
<count
; i
++)
3800 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3801 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3802 if (pmso
->waitThread
)
3804 PMSETTING_WAKEUP(pmso
);
3810 if (chosen
) chosen
->release();
3811 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3813 return kIOReturnSuccess
;
3816 //******************************************************************************
3817 // copyPMSetting (public)
3819 // Allows kexts to safely read setting values, without being subscribed to
3821 //******************************************************************************
3823 OSObject
* IOPMrootDomain::copyPMSetting(
3824 OSSymbol
*whichSetting
)
3826 OSObject
*obj
= NULL
;
3828 if(!whichSetting
) return NULL
;
3831 obj
= fPMSettingsDict
->getObject(whichSetting
);
3840 //******************************************************************************
3841 // registerPMSettingController (public)
3843 // direct wrapper to registerPMSettingController with uint32_t power source arg
3844 //******************************************************************************
3846 IOReturn
IOPMrootDomain::registerPMSettingController(
3847 const OSSymbol
* settings
[],
3848 IOPMSettingControllerCallback func
,
3853 return registerPMSettingController(
3855 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3856 func
, target
, refcon
, handle
);
3859 //******************************************************************************
3860 // registerPMSettingController (public)
3862 // Kexts may register for notifications when a particular setting is changed.
3863 // A list of settings is available in IOPM.h.
3865 // * settings - An OSArray containing OSSymbols. Caller should populate this
3866 // array with a list of settings caller wants notifications from.
3867 // * func - A C function callback of the type IOPMSettingControllerCallback
3868 // * target - caller may provide an OSObject *, which PM will pass as an
3869 // target to calls to "func"
3870 // * refcon - caller may provide an void *, which PM will pass as an
3871 // argument to calls to "func"
3872 // * handle - This is a return argument. We will populate this pointer upon
3873 // call success. Hold onto this and pass this argument to
3874 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3876 // kIOReturnSuccess on success
3877 //******************************************************************************
3879 IOReturn
IOPMrootDomain::registerPMSettingController(
3880 const OSSymbol
* settings
[],
3881 uint32_t supportedPowerSources
,
3882 IOPMSettingControllerCallback func
,
3887 PMSettingObject
*pmso
= NULL
;
3888 OSObject
*pmsh
= NULL
;
3889 OSArray
*list
= NULL
;
3892 if (NULL
== settings
||
3896 return kIOReturnBadArgument
;
3899 pmso
= PMSettingObject::pmSettingObject(
3900 (IOPMrootDomain
*) this, func
, target
,
3901 refcon
, supportedPowerSources
, settings
, &pmsh
);
3905 return kIOReturnInternalError
;
3909 for (i
=0; settings
[i
]; i
++)
3911 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3913 // New array of callbacks for this setting
3914 list
= OSArray::withCapacity(1);
3915 settingsCallbacks
->setObject(settings
[i
], list
);
3919 // Add caller to the callback list
3920 list
->setObject(pmso
);
3924 // Return handle to the caller, the setting object is private.
3927 return kIOReturnSuccess
;
3930 //******************************************************************************
3931 // deregisterPMSettingObject (private)
3933 // Only called from PMSettingObject.
3934 //******************************************************************************
3936 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3938 thread_t thisThread
= current_thread();
3939 PMSettingCallEntry
*callEntry
;
3940 OSCollectionIterator
*iter
;
3948 pmso
->disabled
= true;
3950 // Wait for all callout threads to finish.
3953 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3955 if (callEntry
->thread
!= thisThread
)
3963 assert(0 == pmso
->waitThread
);
3964 pmso
->waitThread
= thisThread
;
3965 PMSETTING_WAIT(pmso
);
3966 pmso
->waitThread
= 0;
3970 // Search each PM settings array in the kernel.
3971 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3974 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3976 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3977 index
= array
->getNextIndexOfObject(pmso
, 0);
3979 array
->removeObject(index
);
3990 //******************************************************************************
3991 // informCPUStateChange
3993 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3994 // running on battery, with the lid closed, etc.
3996 // informCPUStateChange is a no-op on non x86 systems
3997 // only x86 has explicit support in the IntelCPUPowerManagement kext
3998 //******************************************************************************
4000 void IOPMrootDomain::informCPUStateChange(
4004 #if defined(__i386__) || defined(__x86_64__)
4006 pmioctlVariableInfo_t varInfoStruct
;
4008 const char *varNameStr
= NULL
;
4009 int32_t *varIndex
= NULL
;
4011 if (kInformAC
== type
) {
4012 varNameStr
= kIOPMRootDomainBatPowerCString
;
4013 varIndex
= &idxPMCPULimitedPower
;
4014 } else if (kInformLid
== type
) {
4015 varNameStr
= kIOPMRootDomainLidCloseCString
;
4016 varIndex
= &idxPMCPUClamshell
;
4021 // Set the new value!
4022 // pmCPUControl will assign us a new ID if one doesn't exist yet
4023 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4024 varInfoStruct
.varID
= *varIndex
;
4025 varInfoStruct
.varType
= vBool
;
4026 varInfoStruct
.varInitValue
= value
;
4027 varInfoStruct
.varCurValue
= value
;
4028 strlcpy( (char *)varInfoStruct
.varName
,
4029 (const char *)varNameStr
,
4030 sizeof(varInfoStruct
.varName
));
4033 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4035 // pmCPU only assigns numerical id's when a new varName is specified
4037 && (*varIndex
== kCPUUnknownIndex
))
4039 // pmCPUControl has assigned us a new variable ID.
4040 // Let's re-read the structure we just SET to learn that ID.
4041 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4045 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4046 *varIndex
= varInfoStruct
.varID
;
4052 #endif /* __i386__ || __x86_64__ */
4056 // MARK: Deep Sleep Policy
4060 //******************************************************************************
4061 // evaluateSystemSleepPolicy
4062 //******************************************************************************
4064 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4068 kIOPMSleepFlagHibernate
= 0x00000001,
4069 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
4072 struct IOPMSystemSleepPolicyEntry
4074 uint32_t factorMask
;
4075 uint32_t factorBits
;
4076 uint32_t sleepFlags
;
4077 uint32_t wakeEvents
;
4078 } __attribute__((packed
));
4080 struct IOPMSystemSleepPolicyTable
4084 uint16_t entryCount
;
4085 IOPMSystemSleepPolicyEntry entries
[];
4086 } __attribute__((packed
));
4089 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
4090 kIOPMSleepAttributeHibernateSleep
= 0x00000002
4094 getSleepTypeAttributes( uint32_t sleepType
)
4096 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
4101 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
4102 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4103 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4104 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4108 if (sleepType
>= kIOPMSleepTypeLast
)
4111 return sleepTypeAttributes
[sleepType
];
4114 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4115 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4117 const IOPMSystemSleepPolicyTable
* pt
;
4118 OSObject
* prop
= 0;
4119 OSData
* policyData
;
4120 uint64_t currentFactors
= 0;
4121 uint32_t standbyDelay
= 0;
4122 uint32_t powerOffDelay
= 0;
4123 uint32_t powerOffTimer
= 0;
4124 uint32_t standbyTimer
= 0;
4126 bool standbyEnabled
;
4127 bool powerOffEnabled
;
4130 // Get platform's sleep policy table
4131 if (!gSleepPolicyHandler
)
4133 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4134 if (!prop
) goto done
;
4137 // Fetch additional settings
4138 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4139 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4140 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4141 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4142 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4143 powerOffTimer
= powerOffDelay
;
4144 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
))
4145 standbyTimer
= standbyDelay
;
4147 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4148 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
4149 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4151 // pmset level overrides
4152 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4154 if (!gSleepPolicyHandler
)
4156 standbyEnabled
= false;
4157 powerOffEnabled
= false;
4160 else if (!(*hibMode
& kIOHibernateModeSleep
))
4162 // Force hibernate (i.e. mode 25)
4163 // If standby is enabled, force standy.
4164 // If poweroff is enabled, force poweroff.
4166 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4167 else if (powerOffEnabled
)
4168 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4170 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4173 // Current factors based on environment and assertions
4174 if (sleepTimerMaintenance
)
4175 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4176 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4177 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4178 if (!clamshellClosed
)
4179 currentFactors
|= kIOPMSleepFactorLidOpen
;
4180 if (acAdaptorConnected
)
4181 currentFactors
|= kIOPMSleepFactorACPower
;
4182 if (lowBatteryCondition
)
4183 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4184 if (!standbyDelay
|| !standbyTimer
)
4185 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4186 if (standbyNixed
|| !standbyEnabled
)
4187 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4190 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4191 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4193 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4194 kIOPMDriverAssertionLevelOff
)
4195 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4196 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4197 kIOPMDriverAssertionLevelOff
)
4198 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4199 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4200 kIOPMDriverAssertionLevelOff
)
4201 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4202 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4203 kIOPMDriverAssertionLevelOff
)
4204 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4205 if (_scheduledAlarms
!= 0)
4206 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4207 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4208 kIOPMDriverAssertionLevelOff
)
4209 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4210 #define TCPKEEPALIVE 1
4212 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4213 kIOPMDriverAssertionLevelOff
)
4214 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4216 if (!powerOffEnabled
)
4217 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4219 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4221 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4222 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4223 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4224 if (thermalWarningState
)
4225 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4227 DLOG("sleep factors 0x%llx\n", currentFactors
);
4229 if (gSleepPolicyHandler
)
4231 uint32_t savedHibernateMode
;
4234 if (!gSleepPolicyVars
)
4236 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4237 if (!gSleepPolicyVars
)
4239 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4241 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4242 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4243 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4244 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4245 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4246 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4247 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4248 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4249 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
4250 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4251 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4252 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4254 if (kIOPMSleepPhase0
== sleepPhase
)
4256 // preserve hibernateMode
4257 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4258 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4260 else if (kIOPMSleepPhase1
== sleepPhase
)
4262 // use original hibernateMode for phase2
4263 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4266 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4268 if (kIOPMSleepPhase0
== sleepPhase
)
4270 // restore hibernateMode
4271 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4274 if ((result
!= kIOReturnSuccess
) ||
4275 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4276 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4277 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4279 MSG("sleep policy handler error\n");
4283 if ((getSleepTypeAttributes(params
->sleepType
) &
4284 kIOPMSleepAttributeHibernateSetup
) &&
4285 ((*hibMode
& kIOHibernateModeOn
) == 0))
4287 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4290 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4291 params
->version
, params
->sleepType
, params
->sleepFlags
,
4292 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4297 // Policy table is meaningless without standby enabled
4298 if (!standbyEnabled
)
4301 // Validate the sleep policy table
4302 policyData
= OSDynamicCast(OSData
, prop
);
4303 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4306 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4307 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4308 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4311 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4312 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4315 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4317 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4318 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4320 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4321 entry
->factorMask
, entry
->factorBits
,
4322 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4326 DLOG("^ found match\n");
4329 params
->version
= kIOPMSystemSleepParametersVersion
;
4330 params
->reserved1
= 1;
4331 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4332 params
->sleepType
= kIOPMSleepTypeStandby
;
4334 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4336 params
->ecWakeEvents
= entry
->wakeEvents
;
4337 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4339 if (kIOPMSleepPhase2
== sleepPhase
)
4341 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4343 if (!_standbyTimerResetSeconds
||
4344 (now_secs
<= _standbyTimerResetSeconds
))
4346 // Reset standby timer adjustment
4347 _standbyTimerResetSeconds
= now_secs
;
4348 DLOG("standby delay %u, reset %u\n",
4349 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4351 else if (standbyDelay
)
4353 // Shorten the standby delay timer
4354 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4355 if (standbyDelay
> elapsed
)
4356 standbyDelay
-= elapsed
;
4358 standbyDelay
= 1; // must be > 0
4360 DLOG("standby delay %u, elapsed %u\n",
4361 standbyDelay
, (uint32_t) elapsed
);
4364 params
->ecWakeTimer
= standbyDelay
;
4366 else if (kIOPMSleepPhase2
== sleepPhase
)
4368 // A sleep that does not enable the sleep timer will reset
4369 // the standby delay adjustment.
4370 _standbyTimerResetSeconds
= 0;
4382 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4384 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4386 // Evaluate early (priority interest phase), before drivers sleep.
4388 DLOG("%s\n", __FUNCTION__
);
4389 removeProperty(kIOPMSystemSleepParametersKey
);
4391 // Full wake resets the standby timer delay adjustment
4392 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4393 _standbyTimerResetSeconds
= 0;
4395 hibernateDisabled
= false;
4397 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4399 // Save for late evaluation if sleep is aborted
4400 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4402 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4405 if (!hibernateRetry
&&
4406 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4407 kIOPMSleepAttributeHibernateSetup
) == 0))
4409 // skip hibernate setup
4410 hibernateDisabled
= true;
4414 // Publish IOPMSystemSleepType
4415 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4416 if (sleepType
== kIOPMSleepTypeInvalid
)
4419 sleepType
= kIOPMSleepTypeNormalSleep
;
4420 if (hibernateMode
& kIOHibernateModeOn
)
4421 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4422 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4424 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4425 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4427 // report the lowest possible sleep state
4428 sleepType
= kIOPMSleepTypePowerOff
;
4431 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4434 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4436 IOPMSystemSleepParameters params
;
4437 OSData
* paramsData
;
4439 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4441 DLOG("%s\n", __FUNCTION__
);
4443 bzero(¶ms
, sizeof(params
));
4445 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4447 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4448 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
4449 && (!(kIOPMSleepFactorStandbyForced
& gSleepPolicyVars
->sleepFactors
)))
4451 standbyNixed
= true;
4455 || ((hibernateDisabled
|| hibernateAborted
) &&
4456 (getSleepTypeAttributes(params
.sleepType
) &
4457 kIOPMSleepAttributeHibernateSetup
)))
4459 // Final evaluation picked a state requiring hibernation,
4460 // but hibernate isn't going to proceed. Arm a short sleep using
4461 // the early non-hibernate sleep parameters.
4462 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4463 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4464 params
.ecWakeTimer
= 1;
4471 // Set hibernateRetry flag to force hibernate setup on the
4473 hibernateRetry
= true;
4475 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4476 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4480 hibernateRetry
= false;
4483 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4485 resetTimers
= false;
4488 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4491 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4492 paramsData
->release();
4495 if (getSleepTypeAttributes(params
.sleepType
) &
4496 kIOPMSleepAttributeHibernateSleep
)
4498 // Disable sleep to force hibernation
4499 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4504 bool IOPMrootDomain::getHibernateSettings(
4505 uint32_t * hibernateModePtr
,
4506 uint32_t * hibernateFreeRatio
,
4507 uint32_t * hibernateFreeTime
)
4509 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4510 // has updated the hibernateDisabled flag.
4512 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4513 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4514 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4515 if (hibernateDisabled
)
4516 *hibernateModePtr
= 0;
4517 else if (gSleepPolicyHandler
)
4518 *hibernateModePtr
= hibernateMode
;
4519 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4523 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4525 OSObject
* optionsProp
;
4526 OSDictionary
* optionsDict
;
4531 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4532 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4536 obj
= optionsDict
->getObject(key
);
4537 if (obj
) obj
->retain();
4541 obj
= copyProperty(key
);
4545 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4547 *option
= num
->unsigned32BitValue();
4550 else if (OSDynamicCast(OSBoolean
, obj
))
4552 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4560 optionsProp
->release();
4564 #endif /* HIBERNATION */
4566 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
4569 IOPMSystemSleepParameters params
;
4570 uint32_t hibMode
= 0;
4573 if (gIOPMWorkLoop
->inGate() == false)
4575 IOReturn ret
= gIOPMWorkLoop
->runAction(
4576 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4577 &IOPMrootDomain::getSystemSleepType
),
4579 (void *) sleepType
, (void *) standbyTimer
);
4583 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4584 bzero(¶ms
, sizeof(params
));
4586 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4589 *sleepType
= params
.sleepType
;
4590 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
4591 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
4592 DLOG("Standby delay is not set\n");
4595 return kIOReturnSuccess
;
4599 return kIOReturnUnsupported
;
4603 // MARK: Shutdown and Restart
4605 //******************************************************************************
4606 // handlePlatformHaltRestart
4608 //******************************************************************************
4610 struct HaltRestartApplierContext
{
4611 IOPMrootDomain
* RootDomain
;
4612 unsigned long PowerState
;
4613 IOPMPowerFlags PowerFlags
;
4616 const char * LogString
;
4620 platformHaltRestartApplier( OSObject
* object
, void * context
)
4622 IOPowerStateChangeNotification notify
;
4623 HaltRestartApplierContext
* ctx
;
4624 AbsoluteTime startTime
, elapsedTime
;
4627 ctx
= (HaltRestartApplierContext
*) context
;
4629 memset(¬ify
, 0, sizeof(notify
));
4630 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4631 notify
.returnValue
= 0;
4632 notify
.stateNumber
= ctx
->PowerState
;
4633 notify
.stateFlags
= ctx
->PowerFlags
;
4635 clock_get_uptime(&startTime
);
4636 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4637 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4639 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4640 (gIOKitDebug
& kIOLogPMRootDomain
))
4642 _IOServiceInterestNotifier
* notifier
;
4643 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4645 // IOService children of IOPMrootDomain are not instrumented.
4646 // Only IORootParent currently falls under that group.
4650 LOG("%s handler %p took %u ms\n",
4651 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4652 halt_log_enter(ctx
->LogString
, (const void *) notifier
->handler
, elapsedTime
);
4659 static void quiescePowerTreeCallback( void * target
, void * param
)
4661 IOLockLock(gPMHaltLock
);
4663 thread_wakeup(param
);
4664 IOLockUnlock(gPMHaltLock
);
4667 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4669 HaltRestartApplierContext ctx
;
4670 AbsoluteTime startTime
, elapsedTime
;
4673 memset(&ctx
, 0, sizeof(ctx
));
4674 ctx
.RootDomain
= this;
4676 clock_get_uptime(&startTime
);
4680 case kPEUPSDelayHaltCPU
:
4681 ctx
.PowerState
= OFF_STATE
;
4682 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4683 ctx
.LogString
= "PowerOff";
4687 ctx
.PowerState
= RESTART_STATE
;
4688 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4689 ctx
.LogString
= "Restart";
4693 ctx
.PowerState
= ON_STATE
;
4694 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4695 ctx
.LogString
= "PagingOff";
4696 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4698 IOHibernateSystemRestart();
4706 // Notify legacy clients
4707 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4709 // For normal shutdown, turn off File Server Mode.
4710 if (kPEHaltCPU
== pe_type
)
4712 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4713 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4716 setPMSetting(setting
, num
);
4722 if (kPEPagingOff
!= pe_type
)
4724 // Notify in power tree order
4725 notifySystemShutdown(this, ctx
.MessageType
);
4728 IOCPURunPlatformHaltRestartActions(pe_type
);
4730 // Wait for PM to quiesce
4731 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4733 AbsoluteTime quiesceTime
= mach_absolute_time();
4735 IOLockLock(gPMHaltLock
);
4736 gPMQuiesced
= false;
4737 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4740 while (!gPMQuiesced
)
4742 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4745 IOLockUnlock(gPMHaltLock
);
4746 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
4747 DLOG("PM quiesce took %u ms\n", deltaTime
);
4748 halt_log_enter("Quiesce", NULL
, elapsedTime
);
4751 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4752 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4754 halt_log_enter(ctx
.LogString
, NULL
, elapsedTime
);
4755 if (gHaltLog
) gHaltLog
[gHaltLogPos
] = 0;
4757 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4758 LOG("%s total %u ms\n", ctx
.LogString
, deltaTime
);
4760 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
))
4762 printf("%s total %d ms:%s\n", ctx
.LogString
, deltaTime
, gHaltLog
);
4764 if (gHaltLog
&& gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
))
4766 panic("%s total %d ms:%s\n", ctx
.LogString
, deltaTime
, gHaltLog
);
4770 //******************************************************************************
4773 //******************************************************************************
4775 IOReturn
IOPMrootDomain::shutdownSystem( void )
4777 return kIOReturnUnsupported
;
4780 //******************************************************************************
4783 //******************************************************************************
4785 IOReturn
IOPMrootDomain::restartSystem( void )
4787 return kIOReturnUnsupported
;
4791 // MARK: System Capability
4793 //******************************************************************************
4794 // tagPowerPlaneService
4796 // Running on PM work loop thread.
4797 //******************************************************************************
4799 void IOPMrootDomain::tagPowerPlaneService(
4800 IOService
* service
,
4801 IOPMActions
* actions
)
4804 bool isDisplayWrangler
;
4806 memset(actions
, 0, sizeof(*actions
));
4807 actions
->target
= this;
4809 if (service
== this)
4811 actions
->actionPowerChangeStart
=
4812 OSMemberFunctionCast(
4813 IOPMActionPowerChangeStart
, this,
4814 &IOPMrootDomain::handleOurPowerChangeStart
);
4816 actions
->actionPowerChangeDone
=
4817 OSMemberFunctionCast(
4818 IOPMActionPowerChangeDone
, this,
4819 &IOPMrootDomain::handleOurPowerChangeDone
);
4821 actions
->actionPowerChangeOverride
=
4822 OSMemberFunctionCast(
4823 IOPMActionPowerChangeOverride
, this,
4824 &IOPMrootDomain::overrideOurPowerChange
);
4829 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4830 if (isDisplayWrangler
)
4835 isDisplayWrangler
= false;
4838 #if defined(__i386__) || defined(__x86_64__)
4839 if (isDisplayWrangler
)
4840 flags
|= kPMActionsFlagIsDisplayWrangler
;
4841 if (service
->getProperty("IOPMStrictTreeOrder"))
4842 flags
|= kPMActionsFlagIsGraphicsDevice
;
4843 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4844 flags
|= kPMActionsFlagIsAudioDevice
;
4847 // Find the power connection object that is a child of the PCI host
4848 // bridge, and has a graphics/audio device attached below. Mark the
4849 // power branch for delayed child notifications.
4853 IORegistryEntry
* child
= service
;
4854 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4856 while (child
!= this)
4858 if ((parent
== pciHostBridgeDriver
) ||
4861 if (OSDynamicCast(IOPowerConnection
, child
))
4863 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4864 conn
->delayChildNotification
= true;
4869 parent
= child
->getParentEntry(gIOPowerPlane
);
4875 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4876 actions
->parameter
|= flags
;
4877 actions
->actionPowerChangeOverride
=
4878 OSMemberFunctionCast(
4879 IOPMActionPowerChangeOverride
, this,
4880 &IOPMrootDomain::overridePowerChangeForUIService
);
4882 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4884 actions
->actionActivityTickle
=
4885 OSMemberFunctionCast(
4886 IOPMActionActivityTickle
, this,
4887 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4889 actions
->actionUpdatePowerClient
=
4890 OSMemberFunctionCast(
4891 IOPMActionUpdatePowerClient
, this,
4892 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4897 // Locate the first PCI host bridge for PMTrace.
4898 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4900 IOService
* provider
= service
->getProvider();
4901 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4902 provider
->inPlane(gIODTPlane
))
4904 pciHostBridgeDevice
= provider
;
4905 pciHostBridgeDriver
= service
;
4906 DLOG("PMTrace found PCI host bridge %s->%s\n",
4907 provider
->getName(), service
->getName());
4911 // Tag top-level PCI devices. The order of PMinit() call does not
4912 // change across boots and is used as the PCI bit number.
4913 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4915 // Would prefer to check built-in property, but tagPowerPlaneService()
4916 // is called before pciDevice->registerService().
4917 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4918 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4920 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4923 // Save the assigned bit for fast lookup.
4924 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4926 actions
->actionPowerChangeStart
=
4927 OSMemberFunctionCast(
4928 IOPMActionPowerChangeStart
, this,
4929 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4931 actions
->actionPowerChangeDone
=
4932 OSMemberFunctionCast(
4933 IOPMActionPowerChangeDone
, this,
4934 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4940 //******************************************************************************
4941 // PM actions for root domain
4942 //******************************************************************************
4944 void IOPMrootDomain::overrideOurPowerChange(
4945 IOService
* service
,
4946 IOPMActions
* actions
,
4947 IOPMPowerStateIndex
* inOutPowerState
,
4948 IOPMPowerChangeFlags
* inOutChangeFlags
,
4949 IOPMRequestTag requestTag
)
4951 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4952 uint32_t changeFlags
= *inOutChangeFlags
;
4953 uint32_t currentPowerState
= (uint32_t) getPowerState();
4955 if (changeFlags
& kIOPMParentInitiated
)
4957 // Root parent is permanently pegged at max power,
4958 // a parent initiated power change is unexpected.
4959 *inOutChangeFlags
|= kIOPMNotDone
;
4963 if (powerState
< currentPowerState
)
4965 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4967 // Root domain is dropping power state ON->SLEEP.
4968 // If system is in full wake, first enter dark wake by
4969 // converting the power drop to a capability change.
4970 // Once in dark wake, transition to sleep state ASAP.
4972 darkWakeToSleepASAP
= true;
4974 // Drop graphics and audio capability
4975 _desiredCapability
&= ~(
4976 kIOPMSystemCapabilityGraphics
|
4977 kIOPMSystemCapabilityAudio
);
4979 // Convert to capability change (ON->ON)
4980 *inOutPowerState
= ON_STATE
;
4981 *inOutChangeFlags
|= kIOPMSynchronize
;
4983 // Revert device desire from SLEEP to ON
4984 changePowerStateToPriv(ON_STATE
);
4988 // System is in dark wake, ok to drop power state.
4989 // Broadcast root powering down to entire tree.
4990 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4993 else if (powerState
> currentPowerState
)
4995 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4997 // Broadcast power up when waking from sleep, but not for the
4998 // initial power change at boot by checking for cpu capability.
4999 *inOutChangeFlags
|= kIOPMRootChangeUp
;
5004 void IOPMrootDomain::handleOurPowerChangeStart(
5005 IOService
* service
,
5006 IOPMActions
* actions
,
5007 IOPMPowerStateIndex powerState
,
5008 IOPMPowerChangeFlags
* inOutChangeFlags
,
5009 IOPMRequestTag requestTag
)
5011 uint32_t changeFlags
= *inOutChangeFlags
;
5012 uint32_t currentPowerState
= (uint32_t) getPowerState();
5013 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
5014 bool publishSleepReason
= false;
5016 _systemTransitionType
= kSystemTransitionNone
;
5017 _systemMessageClientMask
= 0;
5018 capabilityLoss
= false;
5019 toldPowerdCapWillChange
= false;
5021 if (lowBatteryCondition
)
5023 // Low battery notification may arrive after the initial sleep request
5024 // has been queued. Override the sleep reason so powerd and others can
5025 // treat this as an emergency sleep.
5026 sleepReason
= kIOPMSleepReasonLowPower
;
5029 // 1. Explicit capability change.
5031 if (changeFlags
& kIOPMSynchronize
)
5033 if (powerState
== ON_STATE
)
5035 if (changeFlags
& kIOPMSyncNoChildNotify
)
5036 _systemTransitionType
= kSystemTransitionNewCapClient
;
5038 _systemTransitionType
= kSystemTransitionCapability
;
5042 // 2. Going to sleep (cancellation still possible).
5044 else if (powerState
< currentPowerState
)
5045 _systemTransitionType
= kSystemTransitionSleep
;
5047 // 3. Woke from (idle or demand) sleep.
5049 else if (!systemBooting
&&
5050 (changeFlags
& kIOPMSelfInitiated
) &&
5051 (powerState
> currentPowerState
))
5053 _systemTransitionType
= kSystemTransitionWake
;
5054 _desiredCapability
= kIOPMSystemCapabilityCPU
|
5055 kIOPMSystemCapabilityNetwork
;
5057 // Early exit from dark wake to full (e.g. LID open)
5058 if (kFullWakeReasonNone
!= fullWakeReason
)
5060 _desiredCapability
|= (
5061 kIOPMSystemCapabilityGraphics
|
5062 kIOPMSystemCapabilityAudio
);
5065 IOHibernateSetWakeCapabilities(_desiredCapability
);
5069 // Update pending wake capability at the beginning of every
5070 // state transition (including synchronize). This will become
5071 // the current capability at the end of the transition.
5073 if (kSystemTransitionSleep
== _systemTransitionType
)
5075 _pendingCapability
= 0;
5076 capabilityLoss
= true;
5079 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
5081 _pendingCapability
= _desiredCapability
|
5082 kIOPMSystemCapabilityCPU
|
5083 kIOPMSystemCapabilityNetwork
;
5085 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5086 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
5088 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
5089 (_pendingCapability
== _currentCapability
))
5091 // Cancel the PM state change.
5092 _systemTransitionType
= kSystemTransitionNone
;
5093 *inOutChangeFlags
|= kIOPMNotDone
;
5095 if (__builtin_popcount(_pendingCapability
) <
5096 __builtin_popcount(_currentCapability
))
5097 capabilityLoss
= true;
5100 // 1. Capability change.
5102 if (kSystemTransitionCapability
== _systemTransitionType
)
5104 // Dark to Full transition.
5105 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5107 tracePoint( kIOPMTracePointDarkWakeExit
);
5109 willEnterFullWake();
5112 // Full to Dark transition.
5113 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5115 // Clear previous stats
5116 IOLockLock(pmStatsLock
);
5117 if (pmStatsAppResponses
)
5119 pmStatsAppResponses
->release();
5120 pmStatsAppResponses
= OSArray::withCapacity(5);
5122 IOLockUnlock(pmStatsLock
);
5125 tracePoint( kIOPMTracePointDarkWakeEntry
);
5126 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
5127 _systemMessageClientMask
= kSystemMessageClientPowerd
|
5128 kSystemMessageClientLegacyApp
;
5132 // Prevent user active transitions before notifying clients
5133 // that system will sleep.
5134 preventTransitionToUserActive(true);
5136 IOService::setAdvisoryTickleEnable( false );
5138 // Publish the sleep reason for full to dark wake
5139 publishSleepReason
= true;
5140 lastSleepReason
= fullToDarkReason
= sleepReason
;
5142 // Publish a UUID for the Sleep --> Wake cycle
5143 handlePublishSleepWakeUUID(true);
5144 if (sleepDelaysReport
) {
5145 clock_get_uptime(&ts_sleepStart
);
5146 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5149 wranglerTickled
= false;
5155 else if (kSystemTransitionSleep
== _systemTransitionType
)
5157 // Beginning of a system sleep transition.
5158 // Cancellation is still possible.
5159 tracePoint( kIOPMTracePointSleepStarted
);
5161 _systemMessageClientMask
= kSystemMessageClientAll
;
5162 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5163 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5164 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5165 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5167 gIOHibernateState
= 0;
5170 // Record the reason for dark wake back to sleep
5171 // System may not have ever achieved full wake
5173 publishSleepReason
= true;
5174 lastSleepReason
= sleepReason
;
5175 if (sleepDelaysReport
) {
5176 clock_get_uptime(&ts_sleepStart
);
5177 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5183 else if (kSystemTransitionWake
== _systemTransitionType
)
5185 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5186 // Clear stats about sleep
5188 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5190 willEnterFullWake();
5194 // Message powerd only
5195 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5196 tellClients(kIOMessageSystemWillPowerOn
);
5200 // The only location where the sleep reason is published. At this point
5201 // sleep can still be cancelled, but sleep reason should be published
5202 // early for logging purposes.
5204 if (publishSleepReason
)
5206 static const char * IOPMSleepReasons
[] =
5208 kIOPMClamshellSleepKey
,
5209 kIOPMPowerButtonSleepKey
,
5210 kIOPMSoftwareSleepKey
,
5211 kIOPMOSSwitchHibernationKey
,
5213 kIOPMLowPowerSleepKey
,
5214 kIOPMThermalEmergencySleepKey
,
5215 kIOPMMaintenanceSleepKey
,
5216 kIOPMSleepServiceExitKey
,
5217 kIOPMDarkWakeThermalEmergencyKey
5220 // Record sleep cause in IORegistry
5221 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5222 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5223 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5224 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5228 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5229 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5231 _systemStateGeneration
++;
5232 systemDarkWake
= false;
5234 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5236 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5237 _systemTransitionType
, _systemStateGeneration
,
5238 _systemMessageClientMask
,
5239 _desiredCapability
, _currentCapability
, _pendingCapability
);
5243 void IOPMrootDomain::handleOurPowerChangeDone(
5244 IOService
* service
,
5245 IOPMActions
* actions
,
5246 IOPMPowerStateIndex powerState
,
5247 IOPMPowerChangeFlags changeFlags
,
5248 IOPMRequestTag requestTag __unused
)
5250 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5252 _systemTransitionType
= kSystemTransitionNone
;
5256 if (_systemTransitionType
!= kSystemTransitionNone
)
5258 uint32_t currentPowerState
= (uint32_t) getPowerState();
5260 if (changeFlags
& kIOPMNotDone
)
5262 // Power down was cancelled or vetoed.
5263 _pendingCapability
= _currentCapability
;
5264 lastSleepReason
= 0;
5266 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5267 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5269 #if !CONFIG_EMBEDDED
5270 pmPowerStateQueue
->submitPowerEvent(
5271 kPowerEventPolicyStimulus
,
5272 (void *) kStimulusDarkWakeReentry
,
5273 _systemStateGeneration
);
5275 // On embedded, there are no factors that can prolong a
5276 // "darkWake" when a power down is vetoed. We need to
5277 // promote to "fullWake" at least once so that factors
5278 // that prevent idle sleep can assert themselves if required
5279 pmPowerStateQueue
->submitPowerEvent(
5280 kPowerEventPolicyStimulus
,
5281 (void *) kStimulusDarkWakeActivityTickle
);
5285 // Revert device desire to max.
5286 changePowerStateToPriv(ON_STATE
);
5290 // Send message on dark wake to full wake promotion.
5291 // tellChangeUp() handles the normal SLEEP->ON case.
5293 if (kSystemTransitionCapability
== _systemTransitionType
)
5295 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5297 lastSleepReason
= 0; // stop logging wrangler tickles
5298 tellClients(kIOMessageSystemHasPoweredOn
);
5300 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5302 // Going dark, reset full wake state
5303 // userIsActive will be cleared by wrangler powering down
5304 fullWakeReason
= kFullWakeReasonNone
;
5306 if (ts_sleepStart
) {
5307 clock_get_uptime(&wake2DarkwakeDelay
);
5308 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5309 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5315 // Reset state after exiting from dark wake.
5317 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5318 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5320 darkWakeMaintenance
= false;
5321 darkWakeToSleepASAP
= false;
5322 pciCantSleepValid
= false;
5323 darkWakeSleepService
= false;
5325 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5327 // Remove the influence of display power assertion
5328 // before next system wake.
5329 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5330 kWranglerPowerStateMin
);
5331 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5335 // Entered dark mode.
5337 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5338 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5340 // Queue an evaluation of whether to remain in dark wake,
5341 // and for how long. This serves the purpose of draining
5342 // any assertions from the queue.
5344 pmPowerStateQueue
->submitPowerEvent(
5345 kPowerEventPolicyStimulus
,
5346 (void *) kStimulusDarkWakeEntry
,
5347 _systemStateGeneration
);
5351 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5352 "dcp %x:%x:%x, dbgtimer %u\n",
5353 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5354 _systemTransitionType
, _systemStateGeneration
,
5355 _systemMessageClientMask
,
5356 _desiredCapability
, _currentCapability
, _pendingCapability
,
5357 _lastDebugWakeSeconds
);
5359 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5362 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5363 if (clamshellExists
&& fullWakeThreadCall
&&
5364 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5366 // Not the initial graphics full power, graphics won't
5367 // send a power notification to trigger a lid state
5370 AbsoluteTime deadline
;
5371 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5372 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5376 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5379 // Update current system capability.
5380 if (_currentCapability
!= _pendingCapability
)
5381 _currentCapability
= _pendingCapability
;
5383 // Update highest system capability.
5385 _highestCapability
|= _currentCapability
;
5387 if (darkWakePostTickle
&&
5388 (kSystemTransitionWake
== _systemTransitionType
) &&
5389 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5390 kDarkWakeFlagHIDTickleLate
)
5392 darkWakePostTickle
= false;
5395 else if (wranglerTickled
) {
5396 requestFullWake( kFullWakeReasonLocalUser
);
5399 // Reset tracepoint at completion of capability change,
5400 // completion of wake transition, and aborted sleep transition.
5402 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5403 (_systemTransitionType
== kSystemTransitionWake
) ||
5404 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5405 (changeFlags
& kIOPMNotDone
)))
5407 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5408 tracePoint( kIOPMTracePointSystemUp
);
5411 _systemTransitionType
= kSystemTransitionNone
;
5412 _systemMessageClientMask
= 0;
5413 toldPowerdCapWillChange
= false;
5415 logGraphicsClamp
= false;
5417 if (lowBatteryCondition
) {
5418 privateSleepSystem (kIOPMSleepReasonLowPower
);
5420 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5421 // Request for full wake is removed while system is waking up to full wake
5422 DLOG("DisplayOn fullwake request is removed\n");
5423 handleDisplayPowerOn();
5429 //******************************************************************************
5430 // PM actions for graphics and audio.
5431 //******************************************************************************
5433 void IOPMrootDomain::overridePowerChangeForUIService(
5434 IOService
* service
,
5435 IOPMActions
* actions
,
5436 IOPMPowerStateIndex
* inOutPowerState
,
5437 IOPMPowerChangeFlags
* inOutChangeFlags
)
5439 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5440 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5442 if (kSystemTransitionNone
== _systemTransitionType
)
5444 // Not in midst of a system transition.
5445 // Do not modify power limit enable state.
5447 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5449 // Activate power limiter.
5451 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5452 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5453 (changeFlags
& kIOPMSynchronize
))
5455 actions
->parameter
|= kPMActionsFlagLimitPower
;
5457 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5458 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5459 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5460 (changeFlags
& kIOPMSynchronize
))
5462 actions
->parameter
|= kPMActionsFlagLimitPower
;
5464 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5465 (_systemTransitionType
== kSystemTransitionSleep
))
5467 // For graphics devices, arm the limiter when entering
5468 // system sleep. Not when dropping to dark wake.
5469 actions
->parameter
|= kPMActionsFlagLimitPower
;
5472 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5474 DLOG("+ plimit %s %p\n",
5475 service
->getName(), OBFUSCATE(service
));
5480 // Remove power limit.
5482 if ((actions
->parameter
& (
5483 kPMActionsFlagIsDisplayWrangler
|
5484 kPMActionsFlagIsGraphicsDevice
)) &&
5485 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5487 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5489 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5490 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5492 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5495 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5497 DLOG("- plimit %s %p\n",
5498 service
->getName(), OBFUSCATE(service
));
5502 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5504 uint32_t maxPowerState
= (uint32_t)(-1);
5506 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5508 // Enforce limit for system power/cap transitions.
5511 if ((service
->getPowerState() > maxPowerState
) &&
5512 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5516 // Remove lingering effects of any tickle before entering
5517 // dark wake. It will take a new tickle to return to full
5518 // wake, so the existing tickle state is useless.
5520 if (changeFlags
& kIOPMDomainDidChange
)
5521 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5523 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5530 // Deny all self-initiated changes when power is limited.
5531 // Wrangler tickle should never defeat the limiter.
5533 maxPowerState
= service
->getPowerState();
5536 if (powerState
> maxPowerState
)
5538 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5539 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5541 *inOutPowerState
= maxPowerState
;
5543 if (darkWakePostTickle
&&
5544 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5545 (changeFlags
& kIOPMDomainWillChange
) &&
5546 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5547 kDarkWakeFlagHIDTickleEarly
))
5549 darkWakePostTickle
= false;
5554 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5556 if (logGraphicsClamp
)
5561 clock_get_uptime(&now
);
5562 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5563 absolutetime_to_nanoseconds(now
, &nsec
);
5564 if (kIOLogPMRootDomain
& gIOKitDebug
)
5565 MSG("Graphics suppressed %u ms\n",
5566 ((int)((nsec
) / 1000000ULL)));
5568 graphicsSuppressed
= true;
5573 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5574 IOService
* service
,
5575 IOPMActions
* actions
)
5578 // Warning: Not running in PM work loop context - don't modify state !!!
5579 // Trap tickle directed to IODisplayWrangler while running with graphics
5580 // capability suppressed.
5582 assert(service
== wrangler
);
5584 clock_get_uptime(&userActivityTime
);
5585 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5586 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5587 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5589 userActivityCount
++;
5590 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5591 userActivityCount
, lastSleepReason
);
5594 if (!wranglerTickled
&&
5595 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5597 DLOG("display wrangler tickled\n");
5598 if (kIOLogPMRootDomain
& gIOKitDebug
)
5599 OSReportWithBacktrace("Dark wake display tickle");
5600 if (pmPowerStateQueue
)
5602 pmPowerStateQueue
->submitPowerEvent(
5603 kPowerEventPolicyStimulus
,
5604 (void *) kStimulusDarkWakeActivityTickle
,
5605 true /* set wake type */ );
5611 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5612 IOService
* service
,
5613 IOPMActions
* actions
,
5614 const OSSymbol
* powerClient
,
5615 IOPMPowerStateIndex oldPowerState
,
5616 IOPMPowerStateIndex newPowerState
)
5619 assert(service
== wrangler
);
5621 // This function implements half of the user active detection
5622 // by monitoring changes to the display wrangler's device desire.
5624 // User becomes active when either:
5625 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5626 // in max power state. This desire change in absence of a power state
5627 // change is detected within. This handles the case when user becomes
5628 // active while the display is already lit by setDisplayPowerOn().
5630 // 2. Power state change to max, and DeviceDesire is also at max.
5631 // Handled by displayWranglerNotification().
5633 // User becomes inactive when DeviceDesire drops to sleep state or below.
5635 DLOG("wrangler %s (ps %u, %u->%u)\n",
5636 powerClient
->getCStringNoCopy(),
5637 (uint32_t) service
->getPowerState(),
5638 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5640 if (powerClient
== gIOPMPowerClientDevice
)
5642 if ((newPowerState
> oldPowerState
) &&
5643 (newPowerState
== kWranglerPowerStateMax
) &&
5644 (service
->getPowerState() == kWranglerPowerStateMax
))
5646 evaluatePolicy( kStimulusEnterUserActiveState
);
5649 if ((newPowerState
< oldPowerState
) &&
5650 (newPowerState
<= kWranglerPowerStateSleep
))
5652 evaluatePolicy( kStimulusLeaveUserActiveState
);
5656 if (newPowerState
<= kWranglerPowerStateSleep
) {
5657 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5659 else if (newPowerState
== kWranglerPowerStateMax
) {
5660 evaluatePolicy( kStimulusDisplayWranglerWake
);
5665 //******************************************************************************
5666 // User active state management
5667 //******************************************************************************
5669 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5672 _preventUserActive
= prevent
;
5673 if (wrangler
&& !_preventUserActive
)
5675 // Allowing transition to user active, but the wrangler may have
5676 // already powered ON in case of sleep cancel/revert. Poll the
5677 // same conditions checked for in displayWranglerNotification()
5678 // to bring the user active state up to date.
5680 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5681 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5682 kWranglerPowerStateMax
))
5684 evaluatePolicy( kStimulusEnterUserActiveState
);
5690 //******************************************************************************
5691 // Approve usage of delayed child notification by PM.
5692 //******************************************************************************
5694 bool IOPMrootDomain::shouldDelayChildNotification(
5695 IOService
* service
)
5697 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5698 (kFullWakeReasonNone
== fullWakeReason
) &&
5699 (kSystemTransitionWake
== _systemTransitionType
))
5701 DLOG("%s: delay child notify\n", service
->getName());
5707 //******************************************************************************
5708 // PM actions for PCI device.
5709 //******************************************************************************
5711 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5712 IOService
* service
,
5713 IOPMActions
* actions
,
5714 IOPMPowerStateIndex powerState
,
5715 IOPMPowerChangeFlags
* inOutChangeFlags
)
5717 pmTracer
->tracePCIPowerChange(
5718 PMTraceWorker::kPowerChangeStart
,
5719 service
, *inOutChangeFlags
,
5720 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5723 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5724 IOService
* service
,
5725 IOPMActions
* actions
,
5726 IOPMPowerStateIndex powerState
,
5727 IOPMPowerChangeFlags changeFlags
)
5729 pmTracer
->tracePCIPowerChange(
5730 PMTraceWorker::kPowerChangeCompleted
,
5731 service
, changeFlags
,
5732 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5735 //******************************************************************************
5738 // Override IOService::registerInterest() to intercept special clients.
5739 //******************************************************************************
5741 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5744 friend class IOPMrootDomain
;
5745 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5748 uint32_t ackTimeoutCnt
;
5749 uint32_t msgType
; // Message pending ack
5753 const OSSymbol
*identifier
;
5756 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5758 IONotifier
* IOPMrootDomain::registerInterest(
5759 const OSSymbol
* typeOfInterest
,
5760 IOServiceInterestHandler handler
,
5761 void * target
, void * ref
)
5763 IOPMServiceInterestNotifier
*notifier
= 0;
5764 bool isSystemCapabilityClient
;
5765 bool isKernelCapabilityClient
;
5766 IOReturn rc
= kIOReturnError
;;
5768 isSystemCapabilityClient
=
5770 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5772 isKernelCapabilityClient
=
5774 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5776 if (isSystemCapabilityClient
)
5777 typeOfInterest
= gIOAppPowerStateInterest
;
5779 notifier
= new IOPMServiceInterestNotifier
;
5780 if (!notifier
) return NULL
;
5782 if (notifier
->init()) {
5783 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
5785 if (rc
!= kIOReturnSuccess
) {
5786 notifier
->release();
5791 if (pmPowerStateQueue
)
5793 notifier
->ackTimeoutCnt
= 0;
5794 if (isSystemCapabilityClient
)
5797 if (pmPowerStateQueue
->submitPowerEvent(
5798 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5799 notifier
->release();
5802 if (isKernelCapabilityClient
)
5805 if (pmPowerStateQueue
->submitPowerEvent(
5806 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5807 notifier
->release();
5811 OSData
*data
= NULL
;
5812 uint8_t *uuid
= NULL
;
5813 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
5815 data
= kext
->copyUUID();
5817 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
5818 uuid
= (uint8_t *)(data
->getBytesNoCopy());
5820 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40)|
5821 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
5822 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
5823 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40)|
5824 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
5825 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
5827 notifier
->identifier
= kext
->getIdentifier();
5830 if (kext
) kext
->release();
5831 if (data
) data
->release();
5836 //******************************************************************************
5837 // systemMessageFilter
5839 //******************************************************************************
5841 bool IOPMrootDomain::systemMessageFilter(
5842 void * object
, void * arg1
, void * arg2
, void * arg3
)
5844 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5845 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5846 bool isCapClient
= false;
5848 IOPMServiceInterestNotifier
*notifier
;
5850 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5852 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5853 (!isCapMsg
|| !_joinedCapabilityClients
||
5854 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5857 // Capability change message for app and kernel clients.
5861 if ((context
->notifyType
== kNotifyPriority
) ||
5862 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5865 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5866 (object
== (void *) systemCapabilityNotifier
))
5872 IOPMSystemCapabilityChangeParameters
* capArgs
=
5873 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5875 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5877 capArgs
->fromCapabilities
= 0;
5878 capArgs
->toCapabilities
= _currentCapability
;
5879 capArgs
->changeFlags
= 0;
5883 capArgs
->fromCapabilities
= _currentCapability
;
5884 capArgs
->toCapabilities
= _pendingCapability
;
5886 if (context
->isPreChange
)
5887 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5889 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5891 if ((object
== (void *) systemCapabilityNotifier
) &&
5892 context
->isPreChange
)
5894 toldPowerdCapWillChange
= true;
5898 // Capability change messages only go to the PM configd plugin.
5899 // Wait for response post-change if capabilitiy is increasing.
5900 // Wait for response pre-change if capability is decreasing.
5902 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5903 ( (capabilityLoss
&& context
->isPreChange
) ||
5904 (!capabilityLoss
&& !context
->isPreChange
) ) )
5906 // app has not replied yet, wait for it
5907 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5915 // Capability client will always see kIOMessageCanSystemSleep,
5916 // even for demand sleep. It will also have a chance to veto
5917 // sleep one last time after all clients have responded to
5918 // kIOMessageSystemWillSleep
5920 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5921 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5923 if (object
== (OSObject
*) systemCapabilityNotifier
)
5929 // Not idle sleep, don't ask apps.
5930 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5936 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5938 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5939 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5940 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5946 // Reject capability change messages for legacy clients.
5947 // Reject legacy system sleep messages for capability client.
5949 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5954 // Filter system sleep messages.
5956 if ((context
->notifyType
== kNotifyApps
) &&
5957 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5963 if (notifier
->ackTimeoutCnt
>= 3)
5964 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5966 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5970 else if ((context
->notifyType
== kNotifyPriority
) &&
5971 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5978 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5980 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5981 if (_joinedCapabilityClients
->getCount() == 0)
5983 DLOG("destroyed capability client set %p\n",
5984 OBFUSCATE(_joinedCapabilityClients
));
5985 _joinedCapabilityClients
->release();
5986 _joinedCapabilityClients
= 0;
5990 notifier
->msgType
= context
->messageType
;
5996 //******************************************************************************
5997 // setMaintenanceWakeCalendar
5999 //******************************************************************************
6001 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
6002 const IOPMCalendarStruct
* calendar
)
6008 return kIOReturnBadArgument
;
6010 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
6012 return kIOReturnNoMemory
;
6014 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
6015 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
6016 if (kIOReturnSuccess
== ret
)
6017 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
6019 if (kPMCalendarTypeSleepService
== calendar
->selector
)
6021 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
6022 if (kIOReturnSuccess
== ret
)
6023 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
6025 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
6032 // MARK: Display Wrangler
6034 //******************************************************************************
6035 // displayWranglerNotification
6037 // Handle the notification when the IODisplayWrangler changes power state.
6038 //******************************************************************************
6040 IOReturn
IOPMrootDomain::displayWranglerNotification(
6041 void * target
, void * refCon
,
6042 UInt32 messageType
, IOService
* service
,
6043 void * messageArgument
, vm_size_t argSize
)
6046 int displayPowerState
;
6047 IOPowerStateChangeNotification
* params
=
6048 (IOPowerStateChangeNotification
*) messageArgument
;
6050 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
6051 (messageType
!= kIOMessageDeviceHasPoweredOn
))
6052 return kIOReturnUnsupported
;
6056 return kIOReturnUnsupported
;
6058 displayPowerState
= params
->stateNumber
;
6059 DLOG("wrangler %s ps %d\n",
6060 getIOMessageString(messageType
), displayPowerState
);
6062 switch (messageType
) {
6063 case kIOMessageDeviceWillPowerOff
:
6064 // Display wrangler has dropped power due to display idle
6065 // or force system sleep.
6067 // 4 Display ON kWranglerPowerStateMax
6068 // 3 Display Dim kWranglerPowerStateDim
6069 // 2 Display Sleep kWranglerPowerStateSleep
6070 // 1 Not visible to user
6071 // 0 Not visible to user kWranglerPowerStateMin
6073 if (displayPowerState
<= kWranglerPowerStateSleep
)
6074 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
6077 case kIOMessageDeviceHasPoweredOn
:
6078 // Display wrangler has powered on due to user activity
6079 // or wake from sleep.
6081 if (kWranglerPowerStateMax
== displayPowerState
)
6083 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
6085 // See comment in handleUpdatePowerClientForDisplayWrangler
6086 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6087 kWranglerPowerStateMax
)
6089 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
6095 return kIOReturnUnsupported
;
6098 //******************************************************************************
6099 // displayWranglerMatchPublished
6101 // Receives a notification when the IODisplayWrangler is published.
6102 // When it's published we install a power state change handler.
6103 //******************************************************************************
6105 bool IOPMrootDomain::displayWranglerMatchPublished(
6108 IOService
* newService
,
6109 IONotifier
* notifier __unused
)
6112 // found the display wrangler, now install a handler
6113 if( !newService
->registerInterest( gIOGeneralInterest
,
6114 &displayWranglerNotification
, target
, 0) )
6122 #if defined(__i386__) || defined(__x86_64__)
6124 bool IOPMrootDomain::IONVRAMMatchPublished(
6127 IOService
* newService
,
6128 IONotifier
* notifier
)
6130 unsigned int len
= 0;
6131 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
6132 OSNumber
*statusCode
= NULL
;
6134 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
6136 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
6137 if (statusCode
!= NULL
) {
6138 if (statusCode
->unsigned64BitValue() != 0) {
6139 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
6140 MSG("System was rebooted due to Sleep/Wake failure\n");
6143 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
6144 MSG("System was non-responsive and was rebooted by watchdog\n");
6148 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
6150 if (notifier
) notifier
->remove();
6155 bool IOPMrootDomain::IONVRAMMatchPublished(
6158 IOService
* newService
,
6159 IONotifier
* notifier __unused
)
6166 //******************************************************************************
6169 //******************************************************************************
6171 void IOPMrootDomain::reportUserInput( void )
6175 OSDictionary
* matching
;
6179 matching
= serviceMatching("IODisplayWrangler");
6180 iter
= getMatchingServices(matching
);
6181 if (matching
) matching
->release();
6184 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6190 wrangler
->activityTickle(0,0);
6194 //******************************************************************************
6195 // latchDisplayWranglerTickle
6196 //******************************************************************************
6198 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6203 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6204 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6205 !checkSystemCanSustainFullWake())
6207 // Currently in dark wake, and not transitioning to full wake.
6208 // Full wake is unsustainable, so latch the tickle to prevent
6209 // the display from lighting up momentarily.
6210 wranglerTickleLatched
= true;
6214 wranglerTickleLatched
= false;
6217 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6219 wranglerTickleLatched
= false;
6221 pmPowerStateQueue
->submitPowerEvent(
6222 kPowerEventPolicyStimulus
,
6223 (void *) kStimulusDarkWakeActivityTickle
);
6226 return wranglerTickleLatched
;
6232 //******************************************************************************
6233 // setDisplayPowerOn
6235 // For root domain user client
6236 //******************************************************************************
6238 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6240 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6241 (void *) 0, options
);
6247 //******************************************************************************
6250 // Notification on battery class IOPowerSource appearance
6251 //******************************************************************************
6253 bool IOPMrootDomain::batteryPublished(
6256 IOService
* resourceService
,
6257 IONotifier
* notifier __unused
)
6259 // rdar://2936060&4435589
6260 // All laptops have dimmable LCD displays
6261 // All laptops have batteries
6262 // So if this machine has a battery, publish the fact that the backlight
6263 // supports dimming.
6264 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6270 // MARK: System PM Policy
6272 //******************************************************************************
6273 // checkSystemSleepAllowed
6275 //******************************************************************************
6277 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6278 uint32_t sleepReason
)
6282 // Conditions that prevent idle and demand system sleep.
6285 if (userDisabledAllSleep
)
6287 err
= 1; // 1. user-space sleep kill switch
6291 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6293 err
= 2; // 2. restart or shutdown in progress
6300 // Conditions above pegs the system at full wake.
6301 // Conditions below prevent system sleep but does not prevent
6302 // dark wake, and must be called from gated context.
6305 err
= 3; // 3. config does not support sleep
6309 if (lowBatteryCondition
|| thermalWarningState
)
6311 break; // always sleep on low battery or when in thermal warning state
6314 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6316 break; // always sleep on dark wake thermal emergencies
6319 if (preventSystemSleepList
->getCount() != 0)
6321 err
= 4; // 4. child prevent system sleep clamp
6325 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6326 kIOPMDriverAssertionLevelOn
)
6328 err
= 5; // 5. CPU assertion
6332 if (pciCantSleepValid
)
6334 if (pciCantSleepFlag
)
6335 err
= 6; // 6. PCI card does not support PM (cached)
6338 else if (sleepSupportedPEFunction
&&
6339 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6342 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6343 ret
= getPlatform()->callPlatformFunction(
6344 sleepSupportedPEFunction
, false,
6345 NULL
, NULL
, NULL
, NULL
);
6346 pciCantSleepValid
= true;
6347 pciCantSleepFlag
= false;
6348 if ((platformSleepSupport
& kPCICantSleep
) ||
6349 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6351 err
= 6; // 6. PCI card does not support PM
6352 pciCantSleepFlag
= true;
6361 DLOG("System sleep prevented by %d\n", err
);
6367 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6369 return checkSystemSleepAllowed(0, 0);
6372 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6375 return checkSystemSleepAllowed(1, sleepReason
);
6378 //******************************************************************************
6379 // checkSystemCanSustainFullWake
6380 //******************************************************************************
6382 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6385 if (lowBatteryCondition
|| thermalWarningState
)
6387 // Low battery wake, or received a low battery notification
6388 // while system is awake. This condition will persist until
6389 // the following wake.
6393 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6395 // Graphics state is unknown and external display might not be probed.
6396 // Do not incorporate state that requires graphics to be in max power
6397 // such as desktopMode or clamshellDisabled.
6399 if (!acAdaptorConnected
)
6401 DLOG("full wake check: no AC\n");
6409 //******************************************************************************
6411 //******************************************************************************
6415 bool IOPMrootDomain::mustHibernate( void )
6417 return (lowBatteryCondition
|| thermalWarningState
);
6420 #endif /* HIBERNATION */
6422 //******************************************************************************
6425 // Conditions that affect our wake/sleep decision has changed.
6426 // If conditions dictate that the system must remain awake, clamp power
6427 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6428 // is TRUE, then remove the power clamp and allow the power state to drop
6430 //******************************************************************************
6432 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6434 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6435 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6439 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6441 changePowerStateToPriv(ON_STATE
);
6443 else if ( sleepASAP
)
6445 changePowerStateToPriv(SLEEP_STATE
);
6449 void IOPMrootDomain::handleDisplayPowerOn( )
6451 if (!wrangler
) return;
6452 if (displayPowerOnRequested
)
6454 if (!checkSystemCanSustainFullWake()) return;
6456 // Force wrangler to max power state. If system is in dark wake
6457 // this alone won't raise the wrangler's power state.
6459 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6461 // System in dark wake, always requesting full wake should
6462 // not have any bad side-effects, even if the request fails.
6464 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6466 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6467 requestFullWake( kFullWakeReasonDisplayOn
);
6472 // Relenquish desire to power up display.
6473 // Must first transition to state 1 since wrangler doesn't
6474 // power off the displays at state 0. At state 0 the root
6475 // domain is removed from the wrangler's power client list.
6477 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6478 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6484 //******************************************************************************
6485 // dispatchPowerEvent
6487 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6488 //******************************************************************************
6490 void IOPMrootDomain::dispatchPowerEvent(
6491 uint32_t event
, void * arg0
, uint64_t arg1
)
6497 case kPowerEventFeatureChanged
:
6498 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6499 messageClients(kIOPMMessageFeatureChange
, this);
6502 case kPowerEventReceivedPowerNotification
:
6503 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6504 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6507 case kPowerEventSystemBootCompleted
:
6508 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6511 systemBooting
= false;
6513 if (lowBatteryCondition
)
6515 privateSleepSystem (kIOPMSleepReasonLowPower
);
6517 // The rest is unnecessary since the system is expected
6518 // to sleep immediately. The following wake will update
6523 if (swd_flags
& SWD_VALID_LOGS
) {
6524 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6525 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6526 swd_logBufMap
->release();
6529 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6530 sleepWakeDebugDumpFromFile();
6532 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6533 // If logs are invalid, write the failure code
6534 sleepWakeDebugDumpFromMem(NULL
);
6536 // If lid is closed, re-send lid closed notification
6537 // now that booting is complete.
6538 if ( clamshellClosed
)
6540 handlePowerNotification(kLocalEvalClamshellCommand
);
6542 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6547 case kPowerEventSystemShutdown
:
6548 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6549 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6551 /* We set systemShutdown = true during shutdown
6552 to prevent sleep at unexpected times while loginwindow is trying
6553 to shutdown apps and while the OS is trying to transition to
6556 Set to true during shutdown, as soon as loginwindow shows
6557 the "shutdown countdown dialog", through individual app
6558 termination, and through black screen kernel shutdown.
6560 systemShutdown
= true;
6563 A shutdown was initiated, but then the shutdown
6564 was cancelled, clearing systemShutdown to false here.
6566 systemShutdown
= false;
6570 case kPowerEventUserDisabledSleep
:
6571 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6572 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6575 case kPowerEventRegisterSystemCapabilityClient
:
6576 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6577 if (systemCapabilityNotifier
)
6579 systemCapabilityNotifier
->release();
6580 systemCapabilityNotifier
= 0;
6584 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6585 systemCapabilityNotifier
->retain();
6587 /* intentional fall-through */
6588 [[clang::fallthrough]];
6590 case kPowerEventRegisterKernelCapabilityClient
:
6591 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6592 if (!_joinedCapabilityClients
)
6593 _joinedCapabilityClients
= OSSet::withCapacity(8);
6596 IONotifier
* notify
= (IONotifier
*) arg0
;
6597 if (_joinedCapabilityClients
)
6599 _joinedCapabilityClients
->setObject(notify
);
6600 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6606 case kPowerEventPolicyStimulus
:
6607 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6610 int stimulus
= (uintptr_t) arg0
;
6611 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6615 case kPowerEventAssertionCreate
:
6616 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6618 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6623 case kPowerEventAssertionRelease
:
6624 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6626 pmAssertions
->handleReleaseAssertion(arg1
);
6630 case kPowerEventAssertionSetLevel
:
6631 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6633 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6637 case kPowerEventQueueSleepWakeUUID
:
6638 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6639 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6641 case kPowerEventPublishSleepWakeUUID
:
6642 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6643 handlePublishSleepWakeUUID((bool)arg0
);
6646 case kPowerEventSetDisplayPowerOn
:
6647 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6648 if (!wrangler
) break;
6651 displayPowerOnRequested
= true;
6655 displayPowerOnRequested
= false;
6657 handleDisplayPowerOn();
6662 //******************************************************************************
6663 // systemPowerEventOccurred
6665 // The power controller is notifying us of a hardware-related power management
6666 // event that we must handle.
6668 // systemPowerEventOccurred covers the same functionality that
6669 // receivePowerNotification does; it simply provides a richer API for conveying
6670 // more information.
6671 //******************************************************************************
6673 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6674 const OSSymbol
*event
,
6677 IOReturn attempt
= kIOReturnSuccess
;
6678 OSNumber
*newNumber
= NULL
;
6681 return kIOReturnBadArgument
;
6683 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6685 return kIOReturnInternalError
;
6687 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6689 newNumber
->release();
6694 void IOPMrootDomain::setThermalState(OSObject
*value
)
6698 if (gIOPMWorkLoop
->inGate() == false) {
6699 gIOPMWorkLoop
->runAction(
6700 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6706 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6707 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6708 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6712 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6713 const OSSymbol
*event
,
6716 OSDictionary
*thermalsDict
= NULL
;
6717 bool shouldUpdate
= true;
6719 if (!event
|| !value
)
6720 return kIOReturnBadArgument
;
6723 // We reuse featuresDict Lock because it already exists and guards
6724 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6725 // of stepping on that lock.
6726 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6728 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6730 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6731 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6733 thermalsDict
= OSDictionary::withCapacity(1);
6736 if (!thermalsDict
) {
6737 shouldUpdate
= false;
6741 thermalsDict
->setObject (event
, value
);
6743 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6745 thermalsDict
->release();
6749 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6753 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6754 setThermalState(value
);
6756 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6759 return kIOReturnSuccess
;
6762 //******************************************************************************
6763 // receivePowerNotification
6765 // The power controller is notifying us of a hardware-related power management
6766 // event that we must handle. This may be a result of an 'environment' interrupt
6767 // from the power mgt micro.
6768 //******************************************************************************
6770 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6772 pmPowerStateQueue
->submitPowerEvent(
6773 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6774 return kIOReturnSuccess
;
6777 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6779 bool eval_clamshell
= false;
6784 * Local (IOPMrootDomain only) eval clamshell command
6786 if (msg
& kLocalEvalClamshellCommand
)
6788 eval_clamshell
= true;
6794 if (msg
& kIOPMOverTemp
)
6796 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6797 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6801 * Forward DW thermal notification to client, if system is not going to sleep
6803 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6805 DLOG("DarkWake thermal limits message received!\n");
6807 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6813 if (msg
& kIOPMSleepNow
)
6815 privateSleepSystem (kIOPMSleepReasonSoftware
);
6821 if (msg
& kIOPMPowerEmergency
)
6823 lowBatteryCondition
= true;
6824 privateSleepSystem (kIOPMSleepReasonLowPower
);
6830 if (msg
& kIOPMClamshellOpened
)
6832 DLOG("Clamshell opened\n");
6833 // Received clamshel open message from clamshell controlling driver
6834 // Update our internal state and tell general interest clients
6835 clamshellClosed
= false;
6836 clamshellExists
= true;
6838 // Don't issue a hid tickle when lid is open and polled on wake
6839 if (msg
& kIOPMSetValue
)
6841 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6846 informCPUStateChange(kInformLid
, 0);
6848 // Tell general interest clients
6849 sendClientClamshellNotification();
6851 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6852 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6853 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6854 if (aborting
) userActivityCount
++;
6855 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6860 * Send the clamshell interest notification since the lid is closing.
6862 if (msg
& kIOPMClamshellClosed
)
6864 DLOG("Clamshell closed\n");
6865 // Received clamshel open message from clamshell controlling driver
6866 // Update our internal state and tell general interest clients
6867 clamshellClosed
= true;
6868 clamshellExists
= true;
6871 informCPUStateChange(kInformLid
, 1);
6873 // Tell general interest clients
6874 sendClientClamshellNotification();
6876 // And set eval_clamshell = so we can attempt
6877 eval_clamshell
= true;
6881 * Set Desktop mode (sent from graphics)
6883 * -> reevaluate lid state
6885 if (msg
& kIOPMSetDesktopMode
)
6887 DLOG("Desktop mode\n");
6888 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6889 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6891 sendClientClamshellNotification();
6893 // Re-evaluate the lid state
6894 eval_clamshell
= true;
6898 * AC Adaptor connected
6900 * -> reevaluate lid state
6902 if (msg
& kIOPMSetACAdaptorConnected
)
6904 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6905 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6908 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6910 // Tell BSD if AC is connected
6911 // 0 == external power source; 1 == on battery
6912 post_sys_powersource(acAdaptorConnected
? 0:1);
6914 sendClientClamshellNotification();
6916 // Re-evaluate the lid state
6917 eval_clamshell
= true;
6919 // Lack of AC may have latched a display wrangler tickle.
6920 // This mirrors the hardware's USB wake event latch, where a latched
6921 // USB wake event followed by an AC attach will trigger a full wake.
6922 latchDisplayWranglerTickle( false );
6925 // AC presence will reset the standy timer delay adjustment.
6926 _standbyTimerResetSeconds
= 0;
6928 if (!userIsActive
) {
6929 // Reset userActivityTime when power supply is changed(rdr 13789330)
6930 clock_get_uptime(&userActivityTime
);
6935 * Enable Clamshell (external display disappear)
6937 * -> reevaluate lid state
6939 if (msg
& kIOPMEnableClamshell
)
6941 DLOG("Clamshell enabled\n");
6942 // Re-evaluate the lid state
6943 // System should sleep on external display disappearance
6944 // in lid closed operation.
6945 if (true == clamshellDisabled
)
6947 eval_clamshell
= true;
6950 clamshellDisabled
= false;
6951 sendClientClamshellNotification();
6955 * Disable Clamshell (external display appeared)
6956 * We don't bother re-evaluating clamshell state. If the system is awake,
6957 * the lid is probably open.
6959 if (msg
& kIOPMDisableClamshell
)
6961 DLOG("Clamshell disabled\n");
6962 clamshellDisabled
= true;
6963 sendClientClamshellNotification();
6967 * Evaluate clamshell and SLEEP if appropiate
6969 if (eval_clamshell
&& clamshellClosed
)
6971 if (shouldSleepOnClamshellClosed())
6972 privateSleepSystem (kIOPMSleepReasonClamshell
);
6974 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6980 if (msg
& kIOPMPowerButton
)
6982 DLOG("Powerbutton press\n");
6983 if (!wranglerAsleep
)
6985 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6986 // Check that power button sleep is enabled
6988 if( kOSBooleanTrue
!= getProperty(pbs
))
6989 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6997 //******************************************************************************
7000 // Evaluate root-domain policy in response to external changes.
7001 //******************************************************************************
7003 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
7007 int idleSleepEnabled
: 1;
7008 int idleSleepDisabled
: 1;
7009 int displaySleep
: 1;
7010 int sleepDelayChanged
: 1;
7011 int evaluateDarkWake
: 1;
7012 int adjustPowerState
: 1;
7013 int userBecameInactive
: 1;
7024 case kStimulusDisplayWranglerSleep
:
7025 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7026 if (!wranglerAsleep
)
7028 // first transition to wrangler sleep or lower
7029 flags
.bit
.displaySleep
= true;
7033 case kStimulusDisplayWranglerWake
:
7034 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7035 displayIdleForDemandSleep
= false;
7036 wranglerAsleep
= false;
7039 case kStimulusEnterUserActiveState
:
7040 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7041 if (_preventUserActive
)
7043 DLOG("user active dropped\n");
7048 userIsActive
= true;
7049 userWasActive
= true;
7051 // Stay awake after dropping demand for display power on
7052 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
7053 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
7054 DLOG("User activity while in notification wake\n");
7055 changePowerStateWithOverrideTo( ON_STATE
, 0);
7058 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
7059 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
7060 messageClients(kIOPMMessageUserIsActiveChanged
);
7062 flags
.bit
.idleSleepDisabled
= true;
7065 case kStimulusLeaveUserActiveState
:
7066 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7069 userIsActive
= false;
7070 clock_get_uptime(&userBecameInactiveTime
);
7071 flags
.bit
.userBecameInactive
= true;
7073 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
7074 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
7075 messageClients(kIOPMMessageUserIsActiveChanged
);
7079 case kStimulusAggressivenessChanged
:
7081 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7082 unsigned long minutesToIdleSleep
= 0;
7083 unsigned long minutesToDisplayDim
= 0;
7084 unsigned long minutesDelta
= 0;
7086 // Fetch latest display and system sleep slider values.
7087 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
7088 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
7089 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7090 (uint32_t) sleepSlider
,
7091 (uint32_t) minutesToIdleSleep
,
7092 (uint32_t) minutesToDisplayDim
);
7094 DLOG("idle time -> %ld secs (ena %d)\n",
7095 idleSeconds
, (minutesToIdleSleep
!= 0));
7098 // How long to wait before sleeping the system once
7099 // the displays turns off is indicated by 'extraSleepDelay'.
7101 if ( minutesToIdleSleep
> minutesToDisplayDim
)
7102 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
7103 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
7106 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
7107 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
7109 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
7110 flags
.bit
.idleSleepDisabled
= true;
7111 idleSleepEnabled
= false;
7113 if (0x7fffffff == minutesToIdleSleep
)
7114 minutesToIdleSleep
= idleSeconds
;
7116 if (((minutesDelta
!= extraSleepDelay
) ||
7117 (userActivityTime
!= userActivityTime_prev
)) &&
7118 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
7119 flags
.bit
.sleepDelayChanged
= true;
7121 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
7122 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
7124 // Reconsider decision to remain in dark wake
7125 flags
.bit
.evaluateDarkWake
= true;
7128 sleepSlider
= minutesToIdleSleep
;
7129 extraSleepDelay
= minutesDelta
;
7130 userActivityTime_prev
= userActivityTime
;
7133 case kStimulusDemandSystemSleep
:
7134 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7135 displayIdleForDemandSleep
= true;
7136 if (wrangler
&& wranglerIdleSettings
)
7138 // Request wrangler idle only when demand sleep is triggered
7140 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7142 wrangler
->setProperties(wranglerIdleSettings
);
7143 DLOG("Requested wrangler idle\n");
7146 // arg = sleepReason
7147 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
7150 case kStimulusAllowSystemSleepChanged
:
7151 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7152 flags
.bit
.adjustPowerState
= true;
7155 case kStimulusDarkWakeActivityTickle
:
7156 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7157 // arg == true implies real and not self generated wrangler tickle.
7158 // Update wake type on PM work loop instead of the tickle thread to
7159 // eliminate the possibility of an early tickle clobbering the wake
7160 // type set by the platform driver.
7162 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
7164 if (false == wranglerTickled
)
7166 if (latchDisplayWranglerTickle(true))
7168 DLOG("latched tickle\n");
7172 wranglerTickled
= true;
7173 DLOG("Requesting full wake after dark wake activity tickle\n");
7174 requestFullWake( kFullWakeReasonLocalUser
);
7178 case kStimulusDarkWakeEntry
:
7179 case kStimulusDarkWakeReentry
:
7180 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7181 // Any system transitions since the last dark wake transition
7182 // will invalid the stimulus.
7184 if (arg
== _systemStateGeneration
)
7186 DLOG("dark wake entry\n");
7187 systemDarkWake
= true;
7189 // Keep wranglerAsleep an invariant when wrangler is absent
7191 wranglerAsleep
= true;
7193 if (kStimulusDarkWakeEntry
== stimulus
)
7195 clock_get_uptime(&userBecameInactiveTime
);
7196 flags
.bit
.evaluateDarkWake
= true;
7197 if (activitySinceSleep()) {
7198 DLOG("User activity recorded while going to darkwake\n");
7203 // Always accelerate disk spindown while in dark wake,
7204 // even if system does not support/allow sleep.
7206 cancelIdleSleepTimer();
7207 setQuickSpinDownTimeout();
7211 case kStimulusDarkWakeEvaluate
:
7212 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7215 flags
.bit
.evaluateDarkWake
= true;
7219 case kStimulusNoIdleSleepPreventers
:
7220 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7221 flags
.bit
.adjustPowerState
= true;
7224 } /* switch(stimulus) */
7226 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7228 if (darkWakeToSleepASAP
||
7229 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7231 uint32_t newSleepReason
;
7233 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7235 // System was previously in full wake. Sleep reason from
7236 // full to dark already recorded in fullToDarkReason.
7238 if (lowBatteryCondition
)
7239 newSleepReason
= kIOPMSleepReasonLowPower
;
7241 newSleepReason
= fullToDarkReason
;
7245 // In dark wake from system sleep.
7247 if (darkWakeSleepService
)
7248 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7250 newSleepReason
= kIOPMSleepReasonMaintenance
;
7253 if (checkSystemCanSleep(newSleepReason
))
7255 privateSleepSystem(newSleepReason
);
7258 else // non-maintenance (network) dark wake
7260 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7262 // Release power clamp, and wait for children idle.
7263 adjustPowerState(true);
7267 changePowerStateToPriv(ON_STATE
);
7274 // The rest are irrelevant while system is in dark wake.
7278 if ((flags
.bit
.displaySleep
) &&
7279 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7281 // kIOPMSleepReasonMaintenance?
7282 DLOG("Display sleep while in notification wake\n");
7283 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7286 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7288 bool cancelQuickSpindown
= false;
7290 if (flags
.bit
.sleepDelayChanged
)
7292 // Cancel existing idle sleep timer and quick disk spindown.
7293 // New settings will be applied by the idleSleepEnabled flag
7294 // handler below if idle sleep is enabled.
7296 DLOG("extra sleep timer changed\n");
7297 cancelIdleSleepTimer();
7298 cancelQuickSpindown
= true;
7302 DLOG("user inactive\n");
7305 if (!userIsActive
&& idleSleepEnabled
)
7307 startIdleSleepTimer(getTimeToIdleSleep());
7310 if (cancelQuickSpindown
)
7311 restoreUserSpinDownTimeout();
7314 if (flags
.bit
.idleSleepEnabled
)
7316 DLOG("idle sleep timer enabled\n");
7319 changePowerStateToPriv(ON_STATE
);
7320 startIdleSleepTimer( idleSeconds
);
7324 // Start idle timer if prefs now allow system sleep
7325 // and user is already inactive. Disk spindown is
7326 // accelerated upon timer expiration.
7330 startIdleSleepTimer(getTimeToIdleSleep());
7335 if (flags
.bit
.idleSleepDisabled
)
7337 DLOG("idle sleep timer disabled\n");
7338 cancelIdleSleepTimer();
7339 restoreUserSpinDownTimeout();
7343 if (flags
.bit
.adjustPowerState
)
7345 bool sleepASAP
= false;
7347 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7351 changePowerStateToPriv(ON_STATE
);
7352 if (idleSleepEnabled
)
7354 // stay awake for at least idleSeconds
7355 startIdleSleepTimer(idleSeconds
);
7358 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7364 adjustPowerState(sleepASAP
);
7368 //******************************************************************************
7371 // Request transition from dark wake to full wake
7372 //******************************************************************************
7374 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7376 uint32_t options
= 0;
7377 IOService
* pciRoot
= 0;
7378 bool promotion
= false;
7380 // System must be in dark wake and a valid reason for entering full wake
7381 if ((kFullWakeReasonNone
== reason
) ||
7382 (kFullWakeReasonNone
!= fullWakeReason
) ||
7383 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7388 // Will clear reason upon exit from full wake
7389 fullWakeReason
= reason
;
7391 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7392 kIOPMSystemCapabilityAudio
);
7394 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7395 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7396 !graphicsSuppressed
)
7398 // Promote to full wake while waking up to dark wake due to tickle.
7399 // PM will hold off notifying the graphics subsystem about system wake
7400 // as late as possible, so if a HID tickle does arrive, graphics can
7401 // power up on this same wake cycle. The latency to power up graphics
7402 // on the next cycle can be huge on some systems. However, once any
7403 // graphics suppression has taken effect, it is too late. All other
7404 // graphics devices must be similarly suppressed. But the delay till
7405 // the following cycle should be short.
7407 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7408 kIOPMSystemCapabilityAudio
);
7410 // Immediately bring up audio and graphics
7411 pciRoot
= pciHostBridgeDriver
;
7412 willEnterFullWake();
7416 // Unsafe to cancel once graphics was powered.
7417 // If system woke from dark wake, the return to sleep can
7418 // be cancelled. "awake -> dark -> sleep" transition
7419 // can be canceled also, during the "dark --> sleep" phase
7420 // *prior* to driver power down.
7421 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7422 _pendingCapability
== 0) {
7423 options
|= kIOPMSyncCancelPowerDown
;
7426 synchronizePowerTree(options
, pciRoot
);
7427 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7429 // IOGraphics doesn't light the display even though graphics is
7430 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7431 // So, do an explicit activity tickle
7433 wrangler
->activityTickle(0,0);
7436 // Log a timestamp for the initial full wake request.
7437 // System may not always honor this full wake request.
7438 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7443 clock_get_uptime(&now
);
7444 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7445 absolutetime_to_nanoseconds(now
, &nsec
);
7446 MSG("full wake %s (reason %u) %u ms\n",
7447 promotion
? "promotion" : "request",
7448 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7452 //******************************************************************************
7453 // willEnterFullWake
7455 // System will enter full wake from sleep, from dark wake, or from dark
7456 // wake promotion. This function aggregate things that are in common to
7457 // all three full wake transitions.
7459 // Assumptions: fullWakeReason was updated
7460 //******************************************************************************
7462 void IOPMrootDomain::willEnterFullWake( void )
7464 hibernateRetry
= false;
7465 sleepToStandby
= false;
7466 standbyNixed
= false;
7467 resetTimers
= false;
7468 sleepTimerMaintenance
= false;
7470 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7471 kSystemMessageClientLegacyApp
;
7473 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7475 // Initial graphics full power
7476 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7478 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7479 setProperty(gIOPMUserTriggeredFullWakeKey
,
7480 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7481 kOSBooleanTrue
: kOSBooleanFalse
);
7484 IOHibernateSetWakeCapabilities(_pendingCapability
);
7487 IOService::setAdvisoryTickleEnable( true );
7488 tellClients(kIOMessageSystemWillPowerOn
);
7489 preventTransitionToUserActive(false);
7492 //******************************************************************************
7493 // fullWakeDelayedWork
7495 // System has already entered full wake. Invoked by a delayed thread call.
7496 //******************************************************************************
7498 void IOPMrootDomain::fullWakeDelayedWork( void )
7500 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7501 // Not gated, don't modify state
7502 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7503 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7505 receivePowerNotification( kLocalEvalClamshellCommand
);
7510 //******************************************************************************
7511 // evaluateAssertions
7513 //******************************************************************************
7514 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7516 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7518 messageClients(kIOPMMessageDriverAssertionsChanged
);
7520 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7523 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7525 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7526 wrangler
->setIgnoreIdleTimer( value
);
7530 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7531 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7532 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7534 clock_usec_t microsecs
;
7535 clock_get_uptime(&now
);
7536 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7537 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7538 if (assertOnWakeReport
) {
7539 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7540 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7545 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7546 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7548 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7549 updatePreventIdleSleepList(this, true);
7552 DLOG("Driver assertion ReservedBit7 dropped\n");
7553 updatePreventIdleSleepList(this, false);
7561 //******************************************************************************
7564 //******************************************************************************
7566 void IOPMrootDomain::pmStatsRecordEvent(
7568 AbsoluteTime timestamp
)
7570 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7571 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7574 OSData
*publishPMStats
= NULL
;
7576 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7578 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7580 switch (eventIndex
) {
7581 case kIOPMStatsHibernateImageWrite
:
7583 gPMStats
.hibWrite
.start
= nsec
;
7585 gPMStats
.hibWrite
.stop
= nsec
;
7588 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7589 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7592 case kIOPMStatsHibernateImageRead
:
7594 gPMStats
.hibRead
.start
= nsec
;
7596 gPMStats
.hibRead
.stop
= nsec
;
7599 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7600 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7602 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7603 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7604 publishPMStats
->release();
7605 bzero(&gPMStats
, sizeof(gPMStats
));
7612 * Appends a record of the application response to
7613 * IOPMrootDomain::pmStatsAppResponses
7615 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7616 const OSSymbol
*response
,
7622 IOPMPowerStateIndex powerState
)
7624 OSDictionary
*responseDescription
= NULL
;
7625 OSNumber
*delayNum
= NULL
;
7626 OSNumber
*powerCaps
= NULL
;
7627 OSNumber
*pidNum
= NULL
;
7628 OSNumber
*msgNum
= NULL
;
7629 const OSSymbol
*appname
;
7630 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7631 IOPMServiceInterestNotifier
*notify
= 0;
7633 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7635 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
))
7636 notify
->ackTimeoutCnt
++;
7638 notify
->ackTimeoutCnt
= 0;
7642 if (response
->isEqualTo(gIOPMStatsResponsePrompt
) ||
7643 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7647 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7648 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
7651 // User space app or kernel capability client
7653 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7656 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
7658 notify
->msgType
= 0;
7661 responseDescription
= OSDictionary::withCapacity(5);
7662 if (responseDescription
)
7665 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7668 msgNum
= OSNumber::withNumber(messageType
, 32);
7670 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7674 if (!name
&& notify
&& notify
->identifier
) {
7675 name
= notify
->identifier
->getCStringNoCopy();
7678 if (name
&& (strlen(name
) > 0))
7680 appname
= OSSymbol::withCString(name
);
7682 responseDescription
->setObject(_statsNameKey
, appname
);
7687 if (!id
&& notify
) {
7691 pidNum
= OSNumber::withNumber(id
, 64);
7693 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7698 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7700 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7701 delayNum
->release();
7704 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7705 powerCaps
= OSNumber::withNumber(powerState
, 32);
7707 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7708 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7710 powerState
, delay_ms
);
7715 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7718 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7719 powerCaps
->release();
7722 sleep
= OSSymbol::withCString("Sleep");
7723 wake
= OSSymbol::withCString("Wake");
7724 if (_systemTransitionType
== kSystemTransitionSleep
) {
7725 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7727 else if (_systemTransitionType
== kSystemTransitionWake
) {
7728 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7730 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7731 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7732 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7733 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7734 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7736 if (sleep
) sleep
->release();
7737 if (wake
) wake
->release();
7741 IOLockLock(pmStatsLock
);
7742 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7743 pmStatsAppResponses
->setObject(responseDescription
);
7745 IOLockUnlock(pmStatsLock
);
7747 responseDescription
->release();
7754 // MARK: PMTraceWorker
7756 //******************************************************************************
7757 // TracePoint support
7759 //******************************************************************************
7761 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7762 "IOPMRegisterNVRAMTracePointHandler"
7764 IOReturn
IOPMrootDomain::callPlatformFunction(
7765 const OSSymbol
* functionName
,
7766 bool waitForFunction
,
7767 void * param1
, void * param2
,
7768 void * param3
, void * param4
)
7770 uint32_t bootFailureCode
= 0xffffffff;
7771 unsigned int len
= sizeof(bootFailureCode
);
7772 if (pmTracer
&& functionName
&&
7773 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7774 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7776 uint32_t tracePointPhases
, tracePointPCI
;
7777 uint64_t statusCode
;
7779 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7780 pmTracer
->tracePointTarget
= (void *) param2
;
7781 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7782 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7783 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7784 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey
, &bootFailureCode
, &len
)) {
7785 MSG("Failed to read failure code from NVRam\n");
7787 // Failure code from EFI/BootRom is a four byte structure
7788 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7790 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7791 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7792 MSG("Sleep failure code 0x%08x 0x%08x\n",
7793 tracePointPCI
, tracePointPhases
);
7795 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7796 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7798 return kIOReturnSuccess
;
7801 else if (functionName
&&
7802 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7804 if (gSleepPolicyHandler
)
7805 return kIOReturnExclusiveAccess
;
7807 return kIOReturnBadArgument
;
7808 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7809 gSleepPolicyTarget
= (void *) param2
;
7810 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7811 return kIOReturnSuccess
;
7815 return super::callPlatformFunction(
7816 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7819 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7820 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7822 uint32_t code
= IODBG_POWER(event
);
7823 uint64_t regId
= id
;
7825 regId
= getRegistryEntryID();
7827 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7831 void IOPMrootDomain::tracePoint( uint8_t point
)
7833 if (systemBooting
) return;
7835 if (kIOPMTracePointWakeCapabilityClients
== point
)
7836 acceptSystemWakeEvents(false);
7838 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7839 pmTracer
->tracePoint(point
);
7842 void IOPMrootDomain::traceDetail(OSObject
*object
)
7844 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7846 DLOG("Unknown notifier\n");
7850 if (!systemBooting
) {
7851 pmTracer
->traceDetail( notifier
->uuid0
>> 32 );
7852 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(), notifier
->msgType
, notifier
->uuid0
, notifier
->uuid1
);
7853 if (notifier
->identifier
) {
7854 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer
->getTracePhase(), notifier
->msgType
,
7855 notifier
->identifier
->getCStringNoCopy());
7858 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer
->getTracePhase(), notifier
->msgType
);
7865 void IOPMrootDomain::traceAckDelay(OSObject
*object
, uint32_t response
, uint32_t delay_ms
)
7867 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7869 DLOG("Unknown notifier\n");
7873 if (!systemBooting
) {
7874 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
, notifier
->uuid1
, response
, delay_ms
);
7875 if (notifier
->identifier
) {
7876 DLOG("Response from %s took %d ms(response:%d)\n",
7877 notifier
->identifier
->getCStringNoCopy(), delay_ms
, response
);
7880 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
7881 notifier
->uuid0
, notifier
->uuid1
, delay_ms
, response
);
7886 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
7888 if (!systemBooting
) {
7889 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
7890 pmTracer
->traceDetail( detail
);
7891 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
7892 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
7897 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7900 void **report
= NULL
;
7903 uint32_t *clientCnt
;
7908 if (channel_id
== kAssertDelayChID
) {
7909 report
= &assertOnWakeReport
;
7910 bktCnt
= kAssertDelayBcktCnt
;
7911 bktSize
= kAssertDelayBcktSize
;
7912 clientCnt
= &assertOnWakeClientCnt
;
7914 else if (channel_id
== kSleepDelaysChID
) {
7915 report
= &sleepDelaysReport
;
7916 bktCnt
= kSleepDelaysBcktCnt
;
7917 bktSize
= kSleepDelaysBcktSize
;
7918 clientCnt
= &sleepDelaysClientCnt
;
7923 case kIOReportEnable
:
7930 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7931 *report
= IOMalloc(reportSize
);
7932 if (*report
== NULL
) {
7935 bzero(*report
, reportSize
);
7936 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7937 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7939 if (channel_id
== kAssertDelayChID
)
7940 assertOnWakeSecs
= 0;
7944 case kIOReportDisable
:
7945 if (*clientCnt
== 0) {
7948 if (*clientCnt
== 1)
7950 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7955 if (channel_id
== kAssertDelayChID
)
7956 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7960 case kIOReportGetDimensions
:
7962 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7970 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7971 IOReportConfigureAction action
,
7976 uint64_t configAction
= (uint64_t)action
;
7978 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7979 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7980 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7981 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7982 if (action
!= kIOReportGetDimensions
) continue;
7983 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7985 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7986 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7987 gIOPMWorkLoop
->runAction(
7988 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7989 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7990 (void *)configAction
, (void *)result
);
7994 return super::configureReport(channelList
, action
, result
, destination
);
7997 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
8007 if (ch_id
== kAssertDelayChID
) {
8008 report
= &assertOnWakeReport
;
8010 else if (ch_id
== kSleepDelaysChID
) {
8011 report
= &sleepDelaysReport
;
8014 if (*report
== NULL
) {
8015 return kIOReturnNotOpen
;
8018 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
8019 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
8020 return kIOReturnOverrun
;
8023 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
8024 dest
->appendBytes(data2cpy
, size2cpy
);
8026 return kIOReturnSuccess
;
8029 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
8030 IOReportUpdateAction action
,
8036 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
8037 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
8041 if (action
!= kIOReportCopyChannelData
) goto exit
;
8043 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8044 ch_id
= channelList
->channels
[cnt
].channel_id
;
8046 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
8047 gIOPMWorkLoop
->runAction(
8048 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
8049 (OSObject
*)this, (void *)ch_id
,
8050 (void *)result
, (void *)dest
);
8054 else if ((ch_id
== kSleepCntChID
) ||
8055 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
8056 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
8060 if (ch_id
== kSleepCntChID
)
8061 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
8062 else if (ch_id
== kDarkWkCntChID
)
8063 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
8064 else if (ch_id
== kUserWkCntChID
)
8065 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
8067 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
8068 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
8069 dest
->appendBytes(data2cpy
, size2cpy
);
8073 return super::updateReport(channelList
, action
, result
, destination
);
8077 //******************************************************************************
8078 // PMTraceWorker Class
8080 //******************************************************************************
8083 #define super OSObject
8084 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
8086 #define kPMBestGuessPCIDevicesCount 25
8087 #define kPMMaxRTCBitfieldSize 32
8089 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
8093 me
= OSTypeAlloc( PMTraceWorker
);
8094 if (!me
|| !me
->init())
8099 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
8101 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8102 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8103 // this dictionary lazily.
8105 me
->pciDeviceBitMappings
= NULL
;
8106 me
->pmTraceWorkerLock
= IOLockAlloc();
8107 me
->tracePhase
= kIOPMTracePointSystemUp
;
8108 me
->traceData32
= 0;
8109 me
->loginWindowData
= 0;
8110 me
->coreDisplayData
= 0;
8111 me
->coreGraphicsData
= 0;
8115 void PMTraceWorker::RTC_TRACE(void)
8117 if (tracePointHandler
&& tracePointTarget
)
8121 IOLockLock(pmTraceWorkerLock
);
8122 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
8123 (coreGraphicsData
<< 8) | tracePhase
;
8124 IOLockUnlock(pmTraceWorkerLock
);
8126 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
8127 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
8131 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
8133 const OSSymbol
* deviceName
;
8136 IOLockLock(pmTraceWorkerLock
);
8138 if (!pciDeviceBitMappings
)
8140 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
8141 if (!pciDeviceBitMappings
)
8145 // Check for bitmask overflow.
8146 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
8149 if ((deviceName
= pciDevice
->copyName()) &&
8150 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
8151 pciDeviceBitMappings
->setObject(deviceName
))
8153 index
= pciDeviceBitMappings
->getCount() - 1;
8154 _LOG("PMTrace PCI array: set object %s => %d\n",
8155 deviceName
->getCStringNoCopy(), index
);
8158 deviceName
->release();
8159 if (!addedToRegistry
&& (index
>= 0))
8160 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
8163 IOLockUnlock(pmTraceWorkerLock
);
8167 bool PMTraceWorker::serialize(OSSerialize
*s
) const
8170 if (pciDeviceBitMappings
)
8172 IOLockLock(pmTraceWorkerLock
);
8173 ok
= pciDeviceBitMappings
->serialize(s
);
8174 IOLockUnlock(pmTraceWorkerLock
);
8179 void PMTraceWorker::tracePoint(uint8_t phase
)
8181 // clear trace detail when phase begins
8182 if (tracePhase
!= phase
)
8187 DLOG("trace point 0x%02x\n", tracePhase
);
8191 void PMTraceWorker::traceDetail(uint32_t detail
)
8193 if (detail
== traceData32
) {
8196 traceData32
= detail
;
8200 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
8202 switch (component
) {
8203 case kIOPMLoginWindowProgress
:
8204 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
8206 case kIOPMCoreDisplayProgress
:
8207 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
8209 case kIOPMCoreGraphicsProgress
:
8210 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
8216 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
8220 void PMTraceWorker::tracePCIPowerChange(
8221 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
8224 uint32_t expectedFlag
;
8226 // Ignore PCI changes outside of system sleep/wake.
8227 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
8228 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
8231 // Only record the WillChange transition when going to sleep,
8232 // and the DidChange on the way up.
8233 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
8234 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
8235 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
8236 if (changeFlags
!= expectedFlag
)
8239 // Mark this device off in our bitfield
8240 if (bitNum
< kPMMaxRTCBitfieldSize
)
8242 bitMask
= (1 << bitNum
);
8244 if (kPowerChangeStart
== type
)
8246 traceData32
|= bitMask
;
8247 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8248 service
->getName(), bitNum
, bitMask
, traceData32
);
8249 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8253 traceData32
&= ~bitMask
;
8254 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8255 service
->getName(), bitNum
, bitMask
, traceData32
);
8256 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8259 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8264 uint64_t PMTraceWorker::getPMStatusCode( )
8266 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8270 uint8_t PMTraceWorker::getTracePhase()
8275 uint32_t PMTraceWorker::getTraceData()
8281 // MARK: PMHaltWorker
8283 //******************************************************************************
8284 // PMHaltWorker Class
8286 //******************************************************************************
8288 PMHaltWorker
* PMHaltWorker::worker( void )
8294 me
= OSTypeAlloc( PMHaltWorker
);
8295 if (!me
|| !me
->init())
8298 me
->lock
= IOLockAlloc();
8302 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8303 me
->retain(); // thread holds extra retain
8304 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8309 thread_deallocate(thread
);
8314 if (me
) me
->release();
8318 void PMHaltWorker::free( void )
8320 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8326 return OSObject::free();
8329 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8331 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8333 IOLockLock( gPMHaltLock
);
8335 me
->depth
= gPMHaltDepth
;
8336 IOLockUnlock( gPMHaltLock
);
8338 while (me
->depth
>= 0)
8340 PMHaltWorker::work( me
);
8342 IOLockLock( gPMHaltLock
);
8343 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8345 // This is the last thread to finish work on this level,
8346 // inform everyone to start working on next lower level.
8348 me
->depth
= gPMHaltDepth
;
8349 gPMHaltIdleCount
= 0;
8350 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8354 // One or more threads are still working on this level,
8355 // this thread must wait.
8356 me
->depth
= gPMHaltDepth
- 1;
8358 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8359 } while (me
->depth
!= gPMHaltDepth
);
8361 IOLockUnlock( gPMHaltLock
);
8364 // No more work to do, terminate thread
8365 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8366 thread_wakeup( &gPMHaltDepth
);
8370 void PMHaltWorker::work( PMHaltWorker
* me
)
8372 IOService
* service
;
8374 AbsoluteTime startTime
, elapsedTime
;
8383 // Claim an unit of work from the shared pool
8384 IOLockLock( gPMHaltLock
);
8385 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8388 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8392 inner
->removeObject(service
);
8395 IOLockUnlock( gPMHaltLock
);
8397 break; // no more work at this depth
8399 clock_get_uptime(&startTime
);
8401 if (!service
->isInactive() &&
8402 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8404 IOLockLock(me
->lock
);
8405 me
->startTime
= startTime
;
8406 me
->service
= service
;
8407 me
->timeout
= false;
8408 IOLockUnlock(me
->lock
);
8410 service
->systemWillShutdown( gPMHaltMessageType
);
8412 // Wait for driver acknowledgement
8413 IOLockLock(me
->lock
);
8414 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8416 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8419 timeout
= me
->timeout
;
8420 IOLockUnlock(me
->lock
);
8423 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
8424 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
8425 (gIOKitDebug
& kIOLogPMRootDomain
))
8427 LOG("%s driver %s (0x%llx) took %u ms\n",
8428 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8429 "PowerOff" : "Restart",
8430 service
->getName(), service
->getRegistryEntryID(),
8431 (uint32_t) deltaTime
);
8433 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
8434 OSMemberFunctionCast(const void *, service
, &IOService::systemWillShutdown
),
8443 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8446 AbsoluteTime startTime
;
8447 AbsoluteTime endTime
;
8451 IOLockLock(me
->lock
);
8452 if (me
->service
&& !me
->timeout
)
8454 startTime
= me
->startTime
;
8456 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8458 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8459 absolutetime_to_nanoseconds(endTime
, &nano
);
8461 if (nano
> 3000000000ULL)
8464 MSG("%s still waiting on %s\n",
8465 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8466 "PowerOff" : "Restart",
8467 me
->service
->getName());
8470 IOLockUnlock(me
->lock
);
8473 //******************************************************************************
8474 // acknowledgeSystemWillShutdown
8476 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8477 //******************************************************************************
8479 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8481 PMHaltWorker
* worker
;
8487 //DLOG("%s acknowledged\n", from->getName());
8488 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8491 worker
= (PMHaltWorker
*) prop
;
8492 IOLockLock(worker
->lock
);
8493 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8494 thread_wakeup((event_t
) worker
);
8495 IOLockUnlock(worker
->lock
);
8500 DLOG("%s acknowledged without worker property\n",
8506 //******************************************************************************
8507 // notifySystemShutdown
8509 // Notify all objects in PM tree that system will shutdown or restart
8510 //******************************************************************************
8513 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8515 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8516 IORegistryIterator
* iter
;
8517 IORegistryEntry
* entry
;
8520 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8521 AbsoluteTime deadline
;
8522 unsigned int totalNodes
= 0;
8524 unsigned int rootDepth
;
8525 unsigned int numWorkers
;
8531 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8533 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8535 // Iterate the entire PM tree starting from root
8537 rootDepth
= root
->getDepth( gIOPowerPlane
);
8538 if (!rootDepth
) goto done
;
8540 // debug - for repeated test runs
8541 while (PMHaltWorker::metaClass
->getInstanceCount())
8546 gPMHaltArray
= OSArray::withCapacity(40);
8547 if (!gPMHaltArray
) goto done
;
8550 gPMHaltArray
->flushCollection();
8554 gPMHaltLock
= IOLockAlloc();
8555 if (!gPMHaltLock
) goto done
;
8558 if (!gPMHaltClientAcknowledgeKey
)
8560 gPMHaltClientAcknowledgeKey
=
8561 OSSymbol::withCStringNoCopy("PMShutdown");
8562 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8565 gPMHaltMessageType
= messageType
;
8567 // Depth-first walk of PM plane
8569 iter
= IORegistryIterator::iterateOver(
8570 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8574 while ((entry
= iter
->getNextObject()))
8576 node
= OSDynamicCast(IOService
, entry
);
8581 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8584 depth
= node
->getDepth( gIOPowerPlane
);
8585 if (depth
<= rootDepth
)
8590 // adjust to zero based depth
8591 depth
-= (rootDepth
+ 1);
8593 // gPMHaltArray is an array of containers, each container
8594 // refers to nodes with the same depth.
8596 count
= gPMHaltArray
->getCount();
8597 while (depth
>= count
)
8599 // expand array and insert placeholders
8600 gPMHaltArray
->setObject(PLACEHOLDER
);
8603 count
= gPMHaltArray
->getCount();
8606 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8607 if (inner
== PLACEHOLDER
)
8609 inner
= OSSet::withCapacity(40);
8612 gPMHaltArray
->replaceObject(depth
, inner
);
8617 // PM nodes that appear more than once in the tree will have
8618 // the same depth, OSSet will refuse to add the node twice.
8620 ok
= inner
->setObject(node
);
8623 DLOG("Skipped PM node %s\n", node
->getName());
8629 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8632 if (inner
!= PLACEHOLDER
)
8633 count
= inner
->getCount();
8634 DLOG("Nodes at depth %u = %u\n", i
, count
);
8637 // strip placeholders (not all depths are populated)
8639 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8641 if (inner
== PLACEHOLDER
)
8643 gPMHaltArray
->removeObject(i
);
8646 count
= inner
->getCount();
8647 if (count
> numWorkers
)
8649 totalNodes
+= count
;
8653 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8656 gPMHaltBusyCount
= 0;
8657 gPMHaltIdleCount
= 0;
8658 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8660 // Create multiple workers (and threads)
8662 if (numWorkers
> kPMHaltMaxWorkers
)
8663 numWorkers
= kPMHaltMaxWorkers
;
8665 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8666 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8668 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8669 workers
[i
] = PMHaltWorker::worker();
8671 // Wait for workers to exhaust all available work
8673 IOLockLock(gPMHaltLock
);
8674 while (gPMHaltDepth
>= 0)
8676 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8678 waitResult
= IOLockSleepDeadline(
8679 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8680 if (THREAD_TIMED_OUT
== waitResult
)
8683 clock_get_uptime(&now
);
8685 IOLockUnlock(gPMHaltLock
);
8686 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8689 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8691 IOLockLock(gPMHaltLock
);
8694 IOLockUnlock(gPMHaltLock
);
8696 // Release all workers
8698 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8701 workers
[i
]->release();
8702 // worker also retained by it's own thread
8706 DLOG("%s done\n", __FUNCTION__
);
8711 // MARK: Kernel Assertion
8713 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8715 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8716 IOPMDriverAssertionType whichAssertionBits
,
8717 IOPMDriverAssertionLevel assertionLevel
,
8718 IOService
*ownerService
,
8719 const char *ownerDescription
)
8722 IOPMDriverAssertionID newAssertion
;
8727 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8729 if (kIOReturnSuccess
== ret
)
8730 return newAssertion
;
8735 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8738 return kIOReturnInternalError
;
8740 return pmAssertions
->releaseAssertion(releaseAssertion
);
8744 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8745 IOPMDriverAssertionID assertionID
,
8746 IOPMDriverAssertionLevel assertionLevel
)
8748 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8751 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8753 IOPMDriverAssertionType sysLevels
;
8755 if (!pmAssertions
|| whichAssertion
== 0)
8756 return kIOPMDriverAssertionLevelOff
;
8758 sysLevels
= pmAssertions
->getActivatedAssertions();
8760 // Check that every bit set in argument 'whichAssertion' is asserted
8761 // in the aggregate bits.
8762 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8763 return kIOPMDriverAssertionLevelOn
;
8765 return kIOPMDriverAssertionLevelOff
;
8768 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8771 return kIOReturnNotFound
;
8773 return pmAssertions
->setUserAssertionLevels(inLevels
);
8776 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8780 pmAssertions
->publishProperties();
8782 return( IOService::serializeProperties(s
) );
8785 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8787 OSObject
*obj
= NULL
;
8788 obj
= IOService::copyProperty(aKey
);
8790 if (obj
) return obj
;
8792 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8793 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8794 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8795 return kOSBooleanTrue
;
8797 return kOSBooleanFalse
;
8801 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8802 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8803 if (swd_flags
& SWD_VALID_LOGS
)
8804 return kOSBooleanTrue
;
8806 return kOSBooleanFalse
;
8811 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8812 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8813 * issued by DisplayWrangler on darkwake.
8815 if (!strcmp(aKey
, "DesktopMode")) {
8817 return kOSBooleanTrue
;
8819 return kOSBooleanFalse
;
8821 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8822 if (displayIdleForDemandSleep
) {
8823 return kOSBooleanTrue
;
8826 return kOSBooleanFalse
;
8830 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8832 OSArray
* array
= 0;
8834 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8835 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8836 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8837 collection
->release();
8844 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8846 OSArray
* array
= 0;
8847 IOLockLock(pmStatsLock
);
8848 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8849 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8850 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8851 collection
->release();
8853 pmStatsAppResponses
->flushCollection();
8855 IOLockUnlock(pmStatsLock
);
8859 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8861 OSArray
*idleSleepList
= NULL
;
8862 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8863 return idleSleepList
;
8866 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8868 OSArray
*systemSleepList
= NULL
;
8869 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8870 return systemSleepList
;
8877 // MARK: Wake Event Reporting
8879 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8882 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8886 //******************************************************************************
8887 // acceptSystemWakeEvents
8889 // Private control for the acceptance of driver wake event claims.
8890 //******************************************************************************
8892 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8894 bool logWakeReason
= false;
8899 gWakeReasonString
[0] = '\0';
8900 if (!_systemWakeEventsArray
)
8901 _systemWakeEventsArray
= OSArray::withCapacity(4);
8902 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8903 _systemWakeEventsArray
->flushCollection();
8907 _acceptSystemWakeEvents
= false;
8909 logWakeReason
= gWakeReasonSysctlRegistered
;
8911 static int panic_allowed
= -1;
8913 if ((panic_allowed
== -1) &&
8914 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
8918 if (panic_allowed
) {
8920 // Panic if wake reason is null or empty
8921 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
8922 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t'))
8925 if (i
>= strlen(gWakeReasonString
)) {
8926 panic("Wake reason is empty\n");
8935 MSG("system wake events:%s\n", gWakeReasonString
);
8938 //******************************************************************************
8939 // claimSystemWakeEvent
8941 // For a driver to claim a device is the source/conduit of a system wake event.
8942 //******************************************************************************
8944 void IOPMrootDomain::claimSystemWakeEvent(
8947 const char * reason
,
8948 OSObject
* details
)
8950 const OSSymbol
* deviceName
= 0;
8951 OSNumber
* deviceRegId
= 0;
8952 OSNumber
* claimTime
= 0;
8953 OSData
* flagsData
= 0;
8954 OSString
* reasonString
= 0;
8955 OSDictionary
* d
= 0;
8959 pmEventTimeStamp(×tamp
);
8961 if (!device
|| !reason
) return;
8963 deviceName
= device
->copyName(gIOServicePlane
);
8964 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8965 claimTime
= OSNumber::withNumber(timestamp
, 64);
8966 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8967 reasonString
= OSString::withCString(reason
);
8968 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8969 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8972 d
->setObject(gIONameKey
, deviceName
);
8973 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8974 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8975 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8976 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8978 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8981 if (!gWakeReasonSysctlRegistered
)
8983 // Lazy registration until the platform driver stops registering
8985 gWakeReasonSysctlRegistered
= true;
8987 sysctl_register_oid(&sysctl__kern_wakereason
);
8990 if (_acceptSystemWakeEvents
)
8992 ok
= _systemWakeEventsArray
->setObject(d
);
8993 if (gWakeReasonString
[0] != '\0')
8994 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8995 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
9000 if (deviceName
) deviceName
->release();
9001 if (deviceRegId
) deviceRegId
->release();
9002 if (claimTime
) claimTime
->release();
9003 if (flagsData
) flagsData
->release();
9004 if (reasonString
) reasonString
->release();
9005 if (d
) d
->release();
9008 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9011 // MARK: PMSettingHandle
9013 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
9015 void PMSettingHandle::free( void )
9019 pmso
->clientHandleFreed();
9028 // MARK: PMSettingObject
9031 #define super OSObject
9032 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
9035 * Static constructor/initializer for PMSettingObject
9037 PMSettingObject
*PMSettingObject::pmSettingObject(
9038 IOPMrootDomain
*parent_arg
,
9039 IOPMSettingControllerCallback handler_arg
,
9040 OSObject
*target_arg
,
9041 uintptr_t refcon_arg
,
9042 uint32_t supportedPowerSources
,
9043 const OSSymbol
* settings
[],
9044 OSObject
**handle_obj
)
9046 uint32_t settingCount
= 0;
9047 PMSettingObject
*pmso
= 0;
9048 PMSettingHandle
*pmsh
= 0;
9050 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
9053 // count OSSymbol entries in NULL terminated settings array
9054 while (settings
[settingCount
]) {
9057 if (0 == settingCount
)
9060 pmso
= new PMSettingObject
;
9061 if (!pmso
|| !pmso
->init())
9064 pmsh
= new PMSettingHandle
;
9065 if (!pmsh
|| !pmsh
->init())
9068 queue_init(&pmso
->calloutQueue
);
9069 pmso
->parent
= parent_arg
;
9070 pmso
->func
= handler_arg
;
9071 pmso
->target
= target_arg
;
9072 pmso
->refcon
= refcon_arg
;
9073 pmso
->settingCount
= settingCount
;
9075 pmso
->retain(); // handle holds a retain on pmso
9079 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
9080 if (pmso
->publishedFeatureID
) {
9081 for (unsigned int i
=0; i
<settingCount
; i
++) {
9082 // Since there is now at least one listener to this setting, publish
9083 // PM root domain support for it.
9084 parent_arg
->publishPMSetting( settings
[i
],
9085 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
9093 if (pmso
) pmso
->release();
9094 if (pmsh
) pmsh
->release();
9098 void PMSettingObject::free( void )
9100 if (publishedFeatureID
) {
9101 for (uint32_t i
=0; i
<settingCount
; i
++) {
9102 if (publishedFeatureID
[i
]) {
9103 parent
->removePublishedFeature( publishedFeatureID
[i
] );
9107 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
9113 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
9115 (*func
)(target
, type
, object
, refcon
);
9118 void PMSettingObject::clientHandleFreed( void )
9120 parent
->deregisterPMSettingObject(this);
9124 // MARK: PMAssertionsTracker
9126 //*********************************************************************************
9127 //*********************************************************************************
9128 //*********************************************************************************
9129 // class PMAssertionsTracker Implementation
9131 #define kAssertUniqueIDStart 500
9133 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
9135 PMAssertionsTracker
*myself
;
9137 myself
= new PMAssertionsTracker
;
9141 myself
->owner
= rootDomain
;
9142 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
9143 myself
->assertionsArray
= OSArray::withCapacity(5);
9144 myself
->assertionsKernel
= 0;
9145 myself
->assertionsUser
= 0;
9146 myself
->assertionsCombined
= 0;
9147 myself
->assertionsArrayLock
= IOLockAlloc();
9148 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
9150 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
9158 * - Update assertionsKernel to reflect the state of all
9159 * assertions in the kernel.
9160 * - Update assertionsCombined to reflect both kernel & user space.
9162 void PMAssertionsTracker::tabulate(void)
9166 PMAssertStruct
*_a
= NULL
;
9169 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
9170 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
9174 assertionsKernel
= 0;
9175 assertionsCombined
= 0;
9177 if (!assertionsArray
)
9180 if ((count
= assertionsArray
->getCount()))
9182 for (i
=0; i
<count
; i
++)
9184 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9187 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9188 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
9189 assertionsKernel
|= _a
->assertionBits
;
9194 tabulateProducerCount
++;
9195 assertionsCombined
= assertionsKernel
| assertionsUser
;
9197 if ((assertionsKernel
!= oldKernel
) ||
9198 (assertionsCombined
!= oldCombined
))
9200 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
9204 void PMAssertionsTracker::publishProperties( void )
9206 OSArray
*assertionsSummary
= NULL
;
9208 if (tabulateConsumerCount
!= tabulateProducerCount
)
9210 IOLockLock(assertionsArrayLock
);
9212 tabulateConsumerCount
= tabulateProducerCount
;
9214 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9216 assertionsSummary
= copyAssertionsArray();
9217 if (assertionsSummary
)
9219 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
9220 assertionsSummary
->release();
9224 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
9227 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9229 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
9231 IOLockUnlock(assertionsArrayLock
);
9235 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
9237 PMAssertStruct
*_a
= NULL
;
9244 && (count
= assertionsArray
->getCount()))
9246 for (i
=0; i
<count
; i
++)
9248 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9251 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9252 if (_a
&& (_id
== _a
->id
)) {
9269 /* PMAssertionsTracker::handleCreateAssertion
9270 * Perform assertion work on the PM workloop. Do not call directly.
9272 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
9278 IOLockLock(assertionsArrayLock
);
9279 assertionsArray
->setObject(newAssertion
);
9280 IOLockUnlock(assertionsArrayLock
);
9281 newAssertion
->release();
9285 return kIOReturnSuccess
;
9288 /* PMAssertionsTracker::createAssertion
9289 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9292 IOReturn
PMAssertionsTracker::createAssertion(
9293 IOPMDriverAssertionType which
,
9294 IOPMDriverAssertionLevel level
,
9295 IOService
*serviceID
,
9296 const char *whoItIs
,
9297 IOPMDriverAssertionID
*outID
)
9299 OSData
*dataStore
= NULL
;
9300 PMAssertStruct track
;
9302 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9303 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9304 track
.level
= level
;
9305 track
.assertionBits
= which
;
9306 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9307 track
.ownerService
= serviceID
;
9308 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9309 track
.modifiedTime
= 0;
9310 pmEventTimeStamp(&track
.createdTime
);
9312 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9315 if (track
.ownerString
)
9316 track
.ownerString
->release();
9317 return kIOReturnNoMemory
;
9322 if (owner
&& owner
->pmPowerStateQueue
) {
9323 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9326 return kIOReturnSuccess
;
9329 /* PMAssertionsTracker::handleReleaseAssertion
9330 * Runs in PM workloop. Do not call directly.
9332 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9333 IOPMDriverAssertionID _id
)
9338 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9341 return kIOReturnNotFound
;
9343 IOLockLock(assertionsArrayLock
);
9344 if (assertStruct
->ownerString
)
9345 assertStruct
->ownerString
->release();
9347 assertionsArray
->removeObject(index
);
9348 IOLockUnlock(assertionsArrayLock
);
9351 return kIOReturnSuccess
;
9354 /* PMAssertionsTracker::releaseAssertion
9355 * Releases an assertion and affects system behavior if appropiate.
9356 * Actual work happens on PM workloop.
9358 IOReturn
PMAssertionsTracker::releaseAssertion(
9359 IOPMDriverAssertionID _id
)
9361 if (owner
&& owner
->pmPowerStateQueue
) {
9362 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9364 return kIOReturnSuccess
;
9367 /* PMAssertionsTracker::handleSetAssertionLevel
9368 * Runs in PM workloop. Do not call directly.
9370 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9371 IOPMDriverAssertionID _id
,
9372 IOPMDriverAssertionLevel _level
)
9374 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9378 if (!assertStruct
) {
9379 return kIOReturnNotFound
;
9382 IOLockLock(assertionsArrayLock
);
9383 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9384 assertStruct
->level
= _level
;
9385 IOLockUnlock(assertionsArrayLock
);
9388 return kIOReturnSuccess
;
9391 /* PMAssertionsTracker::setAssertionLevel
9393 IOReturn
PMAssertionsTracker::setAssertionLevel(
9394 IOPMDriverAssertionID _id
,
9395 IOPMDriverAssertionLevel _level
)
9397 if (owner
&& owner
->pmPowerStateQueue
) {
9398 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9399 (void *)(uintptr_t)_level
, _id
);
9402 return kIOReturnSuccess
;
9405 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9407 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9411 if (new_user_levels
!= assertionsUser
)
9413 assertionsUser
= new_user_levels
;
9414 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9418 return kIOReturnSuccess
;
9421 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9422 IOPMDriverAssertionType new_user_levels
)
9424 if (gIOPMWorkLoop
) {
9425 gIOPMWorkLoop
->runAction(
9426 OSMemberFunctionCast(
9429 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9431 (void *) &new_user_levels
, 0, 0, 0);
9434 return kIOReturnSuccess
;
9438 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9442 OSArray
*outArray
= NULL
;
9444 if (!assertionsArray
||
9445 (0 == (count
= assertionsArray
->getCount())) ||
9446 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9451 for (i
=0; i
<count
; i
++)
9453 PMAssertStruct
*_a
= NULL
;
9455 OSDictionary
*details
= NULL
;
9457 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9458 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9460 OSNumber
*_n
= NULL
;
9462 details
= OSDictionary::withCapacity(7);
9466 outArray
->setObject(details
);
9469 _n
= OSNumber::withNumber(_a
->id
, 64);
9471 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9474 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9476 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9479 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9481 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9484 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9486 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9489 _n
= OSNumber::withNumber(_a
->level
, 64);
9491 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9494 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9496 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9500 if (_a
->ownerString
) {
9501 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9510 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9512 return assertionsCombined
;
9515 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9516 IOPMDriverAssertionType type
)
9518 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9520 return kIOPMDriverAssertionLevelOn
;
9522 return kIOPMDriverAssertionLevelOff
;
9526 //*********************************************************************************
9527 //*********************************************************************************
9528 //*********************************************************************************
9531 static void pmEventTimeStamp(uint64_t *recordTS
)
9539 // We assume tsec fits into 32 bits; 32 bits holds enough
9540 // seconds for 136 years since the epoch in 1970.
9541 clock_get_calendar_microtime(&tsec
, &tusec
);
9544 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9546 *recordTS
|= (uint32_t)tusec
;
9547 *recordTS
|= ((uint64_t)tsec
<< 32);
9553 // MARK: IORootParent
9555 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9557 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9559 // The reason that root domain needs a root parent is to facilitate demand
9560 // sleep, since a power change from the root parent cannot be vetoed.
9562 // The above statement is no longer true since root domain now performs
9563 // demand sleep using overrides. But root parent remains to avoid changing
9564 // the power tree stacking. Root parent is parked at the max power state.
9567 static IOPMPowerState patriarchPowerStates
[2] =
9569 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9570 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9573 void IORootParent::initialize( void )
9577 bool IORootParent::start( IOService
* nub
)
9579 IOService::start(nub
);
9580 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9582 registerPowerDriver(this, patriarchPowerStates
, 2);
9587 void IORootParent::shutDownSystem( void )
9591 void IORootParent::restartSystem( void )
9595 void IORootParent::sleepSystem( void )
9599 void IORootParent::dozeSystem( void )
9603 void IORootParent::sleepToDoze( void )
9607 void IORootParent::wakeSystem( void )
9611 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9613 return (IOService::copyProperty(aKey
));
9617 #if defined(__i386__) || defined(__x86_64__)
9618 IOReturn
IOPMrootDomain::restartWithStackshot()
9620 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9621 return kIOReturnError
;
9623 takeStackshot(true, true, false);
9625 return kIOReturnSuccess
;
9628 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9630 takeStackshot(wdogTrigger
, false, false);
9633 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9635 swd_hdr
* hdr
= NULL
;
9637 int wdog_panic
= -1;
9638 int stress_rack
= -1;
9641 kern_return_t kr
= KERN_SUCCESS
;
9646 uint32_t bytesRemaining
;
9647 unsigned bytesWritten
= 0;
9648 unsigned totalBytes
= 0;
9650 OSString
* UUIDstring
= NULL
;
9652 IOMemoryMap
* logBufMap
= NULL
;
9656 uint32_t initialStackSize
;
9659 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9660 _systemTransitionType
!= kSystemTransitionWake
)
9663 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9668 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9669 PE_parse_boot_argn("stress-rack", &stress_rack
, sizeof(stress_rack
));
9670 if ((wdog_panic
== 1) || (stress_rack
== 1)) {
9671 // If boot-arg specifies to panic then panic.
9672 panic("Sleep/Wake hang detected");
9675 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9676 // If current boot is due to this watch dog trigger restart in previous boot,
9677 // then don't trigger again until at least 1 successful sleep & wake.
9678 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9679 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9680 if (!tasksSuspended
) {
9681 tasksSuspended
= TRUE
;
9682 tasks_system_suspend(true);
9684 PEHaltRestart(kPEHaltCPU
);
9692 if (gSpinDumpBufferFull
)
9694 if (swd_spindump_buffer
== NULL
) {
9695 sleepWakeDebugSpinDumpMemAlloc();
9696 if (swd_spindump_buffer
== NULL
) return;
9699 bufSize
= SWD_SPINDUMP_SIZE
;
9700 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9702 if (sleepWakeDebugIsWdogEnabled() == false)
9705 if (swd_buffer
== NULL
) {
9706 sleepWakeDebugMemAlloc();
9707 if (swd_buffer
== NULL
) return;
9710 bufSize
= SWD_BUF_SIZE
;
9711 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9714 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9718 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9721 hdr
= (swd_hdr
*)swd_buffer
;
9724 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9725 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9727 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9728 const char *str
= UUIDstring
->getCStringNoCopy();
9729 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9732 DLOG("Data for current UUID already exists\n");
9737 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9738 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9740 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9741 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9743 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9745 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9746 while (kr
== KERN_SUCCESS
) {
9750 * Take stackshot of all process on first sample. Size is restricted
9751 * to SWD_INITIAL_STACK_SIZE
9754 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9755 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9758 /* Take sample of kernel threads only */
9760 size
= bytesRemaining
;
9763 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9764 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9765 kr
, pid
, size
, flags
, bytesWritten
);
9766 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9768 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9769 // Continue to take stackshot of just kernel threads
9774 else if (totalBytes
== 0) {
9775 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9779 dstAddr
+= bytesWritten
;
9780 totalBytes
+= bytesWritten
;
9781 bytesRemaining
-= bytesWritten
;
9786 IOSleep(10); // 10 ms
9789 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9792 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9793 code
= pmTracer
->getPMStatusCode();
9794 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9795 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9796 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9797 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9799 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9800 gRootDomain
->swd_lock
= 0;
9801 gSpinDumpBufferFull
= true;
9804 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9807 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9808 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9809 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9810 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9811 len
= sizeof(addr64_t
)*3;
9812 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9813 data
[0], data
[1], data
[2]);
9815 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9817 DLOG("Failed to update nvram boot-args\n");
9823 gRootDomain
->swd_lock
= 0;
9826 IOLog("Restarting to collect Sleep wake debug logs\n");
9827 if (!tasksSuspended
) {
9828 tasksSuspended
= TRUE
;
9829 tasks_system_suspend(true);
9832 PEHaltRestart(kPERestartCPU
);
9835 logBufMap
= sleepWakeDebugRetrieve();
9837 sleepWakeDebugDumpFromMem(logBufMap
);
9838 logBufMap
->release();
9844 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9846 vm_size_t size
= SWD_BUF_SIZE
;
9848 swd_hdr
*hdr
= NULL
;
9850 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9853 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9856 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9859 // Try allocating above 4GB. If that fails, try at 2GB
9860 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9861 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9862 size
, 0xFFFFFFFF00000000ULL
);
9864 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9865 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9866 size
, 0xFFFFFFFF10000000ULL
);
9869 if (memDesc
== NULL
)
9871 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9876 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9877 memset(hdr
, 0, sizeof(swd_hdr
));
9879 hdr
->signature
= SWD_HDR_SIGNATURE
;
9880 hdr
->alloc_size
= size
;
9882 hdr
->spindump_offset
= sizeof(swd_hdr
);
9883 swd_buffer
= (void *)hdr
;
9884 swd_memDesc
= memDesc
;
9885 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9888 gRootDomain
->swd_lock
= 0;
9891 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9893 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9895 swd_hdr
*hdr
= NULL
;
9897 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9899 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9902 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9903 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9906 if (memDesc
== NULL
)
9908 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9913 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9914 memset(hdr
, 0, sizeof(swd_hdr
));
9916 hdr
->signature
= SWD_HDR_SIGNATURE
;
9917 hdr
->alloc_size
= size
;
9919 hdr
->spindump_offset
= sizeof(swd_hdr
);
9920 swd_spindump_buffer
= (void *)hdr
;
9923 gRootDomain
->swd_lock
= 0;
9926 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9928 swd_flags
|= SWD_WDOG_ENABLED
;
9930 sleepWakeDebugMemAlloc();
9933 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9935 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9936 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9939 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9941 swd_hdr
*hdr
= NULL
;
9942 errno_t error
= EIO
;
9944 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9945 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9947 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9948 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9952 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9953 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9954 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9956 gSpinDumpBufferFull
= false;
9960 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9962 struct vnode
*vp
= NULL
;
9963 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9964 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9965 struct vnode_attr va
;
9966 errno_t error
= EIO
;
9968 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9969 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9971 IOLog("Failed to open the file %s\n", name
);
9972 swd_flags
|= SWD_FILEOP_ERROR
;
9976 VATTR_WANTED(&va
, va_nlink
);
9977 /* Don't dump to non-regular files or files with links. */
9978 if (vp
->v_type
!= VREG
||
9979 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9980 IOLog("Bailing as this is not a regular file\n");
9981 swd_flags
|= SWD_FILEOP_ERROR
;
9985 VATTR_SET(&va
, va_data_size
, 0);
9986 vnode_setattr(vp
, &va
, ctx
);
9990 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9991 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9993 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9994 swd_flags
|= SWD_FILEOP_ERROR
;
9997 DLOG("Saved %d bytes to file %s\n",len
, name
);
10002 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
10003 if (ctx
) vfs_context_rele(ctx
);
10009 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10010 struct vnode
*srcVp
,
10011 vfs_context_t srcCtx
,
10012 char *tmpBuf
, uint64_t tmpBufSize
,
10013 uint64_t srcOffset
,
10014 const char *dstFname
,
10018 struct vnode
*vp
= NULL
;
10019 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10020 struct vnode_attr va
;
10021 errno_t error
= EIO
;
10022 uint64_t bytesToRead
, bytesToWrite
;
10023 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
10024 uint32_t newcrc
= 0;
10026 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10027 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10029 IOLog("Failed to open the file %s\n", dstFname
);
10030 swd_flags
|= SWD_FILEOP_ERROR
;
10034 VATTR_WANTED(&va
, va_nlink
);
10035 /* Don't dump to non-regular files or files with links. */
10036 if (vp
->v_type
!= VREG
||
10037 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10038 IOLog("Bailing as this is not a regular file\n");
10039 swd_flags
|= SWD_FILEOP_ERROR
;
10043 VATTR_SET(&va
, va_data_size
, 0);
10044 vnode_setattr(vp
, &va
, ctx
);
10046 writeFileOffset
= 0;
10048 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
10049 readFileOffset
= trunc_page(srcOffset
);
10051 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
10052 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
10053 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10054 vfs_context_ucred(srcCtx
), (int *) 0,
10055 vfs_context_proc(srcCtx
));
10057 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
10058 swd_flags
|= SWD_FILEOP_ERROR
;
10062 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
10063 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
10064 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
10067 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
10069 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
10070 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
10071 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
10072 vfs_context_ucred(ctx
), (int *) 0,
10073 vfs_context_proc(ctx
));
10075 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
10076 swd_flags
|= SWD_FILEOP_ERROR
;
10080 writeFileOffset
+= bytesToWrite
;
10081 numBytes
-= bytesToWrite
;
10082 srcOffset
+= bytesToWrite
;
10085 if (crc
!= newcrc
) {
10086 /* Set stackshot size to 0 if crc doesn't match */
10088 VATTR_SET(&va
, va_data_size
, 0);
10089 vnode_setattr(vp
, &va
, ctx
);
10091 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
10092 swd_flags
|= SWD_DATA_CRC_ERROR
;
10097 error
= vnode_close(vp
, FWRITE
, ctx
);
10098 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
10100 if (ctx
) vfs_context_rele(ctx
);
10107 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
10108 void *tmpBuf
, struct vnode
**vp
)
10111 uint64_t hdrOffset
;
10112 uint32_t error
= 0;
10114 struct vnode_attr va
;
10115 IOHibernateImageHeader
*imageHdr
;
10118 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
10119 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
10121 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
10125 VATTR_WANTED(&va
, va_nlink
);
10126 VATTR_WANTED(&va
, va_data_alloc
);
10127 if ((*vp
)->v_type
!= VREG
||
10128 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
10129 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
10130 error
= SWD_FILEOP_ERROR
;
10134 /* Read the sleepimage file header */
10135 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
10136 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10137 vfs_context_ucred(*ctx
), (int *) 0,
10138 vfs_context_proc(*ctx
));
10140 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %llu(rc=%d) from %s\n",
10141 mach_vm_round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
10142 error
= SWD_FILEOP_ERROR
;
10146 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
10147 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
10148 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
10149 fname
, imageHdr
->signature
);
10150 error
= SWD_HDR_SIGNATURE_ERROR
;
10154 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
10155 hdrOffset
= imageHdr
->deviceBlockSize
;
10156 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
10157 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
10158 va
.va_data_alloc
, fname
);
10159 error
= SWD_HDR_SIZE_ERROR
;
10166 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
10172 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
10176 char hibernateFilename
[MAXPATHLEN
+1];
10178 swd_hdr
*hdr
= NULL
;
10179 uint32_t stacksSize
, logSize
;
10180 uint64_t tmpBufSize
;
10181 uint64_t hdrOffset
, stacksOffset
, logOffset
;
10182 errno_t error
= EIO
;
10183 OSObject
*obj
= NULL
;
10184 OSString
*str
= NULL
;
10185 OSNumber
*failStat
= NULL
;
10186 struct vnode
*vp
= NULL
;
10187 vfs_context_t ctx
= NULL
;
10188 const char *stacksFname
, *logFname
;
10190 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
10192 DLOG("sleepWakeDebugDumpFromFile\n");
10193 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
10196 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10200 /* Allocate a temp buffer to copy data between files */
10201 tmpBufSize
= 2*4096;
10202 tmpBufDesc
= IOBufferMemoryDescriptor::
10203 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
10204 tmpBufSize
, PAGE_SIZE
);
10207 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
10211 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
10213 ctx
= vfs_context_create(vfs_context_current());
10215 /* First check if 'kSleepWakeStackBinFilename' has valid data */
10216 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
10218 /* Check if the debug data is saved to hibernation file */
10219 hibernateFilename
[0] = 0;
10220 if ((obj
= copyProperty(kIOHibernateFileKey
)))
10222 if ((str
= OSDynamicCast(OSString
, obj
)))
10223 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
10224 sizeof(hibernateFilename
));
10227 if (!hibernateFilename
[0]) {
10228 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
10232 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
10234 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
10237 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
10240 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
10243 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
10245 DLOG("Reading swd_hdr len 0x%llx offset 0x%lx\n", mach_vm_round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
10246 /* Read the sleep/wake debug header(swd_hdr) */
10247 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
10248 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10249 vfs_context_ucred(ctx
), (int *) 0,
10250 vfs_context_proc(ctx
));
10252 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %llu. rc=%d\n",
10253 mach_vm_round_page(sizeof(swd_hdr
)), rc
);
10254 swd_flags
|= SWD_FILEOP_ERROR
;
10258 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
10259 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
10260 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
10261 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
10262 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
10263 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10266 stacksSize
= hdr
->spindump_size
;
10268 /* Get stacks & log offsets in the image file */
10269 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
10270 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
10271 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10272 stacksFname
= getDumpStackFilename(hdr
);
10273 logFname
= getDumpLogFilename(hdr
);
10275 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
10276 stacksFname
, stacksSize
, hdr
->crc
);
10277 if (error
== EFAULT
) {
10278 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
10281 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
10282 logFname
, logSize
, 0);
10284 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
10289 // Write just the SleepWakeLog.dump with failure code
10290 uint64_t fcode
= 0;
10293 char *offset
= NULL
;
10297 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10298 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10299 fcode
= failStat
->unsigned64BitValue();
10300 fname
= kSleepWakeLogFilename
;
10303 fname
= kAppleOSXWatchdogLogFilename
;
10306 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10307 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10308 memset(offset
, 0x20, size
); // Fill with spaces
10311 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10312 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10313 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10314 sleepWakeDebugSaveFile(fname
, offset
, size
);
10317 gRootDomain
->swd_lock
= 0;
10319 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10320 if (ctx
) vfs_context_rele(ctx
);
10321 if (tmpBufDesc
) tmpBufDesc
->release();
10322 #endif /* HIBERNATION */
10325 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10327 IOVirtualAddress srcBuf
= NULL
;
10328 char *stackBuf
= NULL
, *logOffset
= NULL
;
10331 errno_t error
= EIO
;
10332 uint64_t bufSize
= 0;
10333 swd_hdr
*hdr
= NULL
;
10334 OSNumber
*failStat
= NULL
;
10336 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10339 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10341 DLOG("Nothing saved to dump to file\n");
10345 hdr
= (swd_hdr
*)srcBuf
;
10346 bufSize
= logBufMap
->getLength();
10347 if (bufSize
<= sizeof(swd_hdr
))
10349 IOLog("SleepWake log buffer size is invalid\n");
10350 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10354 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10356 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10357 if (error
) goto exit
;
10359 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10360 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10362 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10363 if (error
) goto exit
;
10365 hdr
->spindump_size
= 0;
10370 // Write just the SleepWakeLog.dump with failure code
10371 uint64_t fcode
= 0;
10372 const char *sname
, *lname
;
10375 /* Try writing an empty stacks file */
10377 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10378 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10379 fcode
= failStat
->unsigned64BitValue();
10380 lname
= kSleepWakeLogFilename
;
10381 sname
= kSleepWakeStackFilename
;
10384 lname
= kAppleOSXWatchdogLogFilename
;
10385 sname
= kAppleOSXWatchdogStackFilename
;
10388 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10390 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10391 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10392 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10395 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10396 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10397 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10398 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10401 gRootDomain
->swd_lock
= 0;
10404 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10406 IOVirtualAddress vaddr
= NULL
;
10407 IOMemoryDescriptor
* desc
= NULL
;
10408 IOMemoryMap
* logBufMap
= NULL
;
10410 uint32_t len
= INT_MAX
;
10412 uint64_t bufSize
= 0;
10414 uint64_t newcrc
= 0;
10415 uint64_t paddr
= 0;
10416 swd_hdr
*hdr
= NULL
;
10421 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10424 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10425 DLOG("No sleepWakeDebug note to read\n");
10429 if (len
== strlen("sleepimage")) {
10431 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10433 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10434 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10435 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10439 else if (len
== sizeof(addr64_t
)*3) {
10440 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10443 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10449 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10450 data
[0], data
[1], data
[2]);
10451 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10455 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10457 IOLog("SleepWake log buffer size is invalid\n");
10458 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10462 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10463 bufSize
, crc
, paddr
);
10466 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10467 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10470 IOLog("Fail to map SleepWake log buffer\n");
10471 swd_flags
|= SWD_INTERNAL_FAILURE
;
10475 logBufMap
= desc
->map();
10477 vaddr
= logBufMap
->getVirtualAddress();
10480 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10481 IOLog("Fail to map SleepWake log buffer\n");
10482 swd_flags
|= SWD_INTERNAL_FAILURE
;
10486 hdr
= (swd_hdr
*)vaddr
;
10487 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10489 IOLog("SleepWake log header size is invalid\n");
10490 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10495 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10496 hdr
->spindump_size
);
10497 if (newcrc
!= crc
) {
10498 IOLog("SleepWake log buffer contents are invalid\n");
10499 swd_flags
|= SWD_DATA_CRC_ERROR
;
10504 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10508 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10510 if (logBufMap
) logBufMap
->release();
10513 if (desc
) desc
->release();
10514 gRootDomain
->swd_lock
= 0;
10521 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10523 uint32_t wdog_panic
= 1;
10526 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10527 (wdog_panic
== 0)) {
10530 panic("Sleep/Wake hang detected");
10535 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10537 #pragma unused(restart)
10538 #pragma unused(isOSXWatchdog)
10541 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10544 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10547 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10548 struct vnode
*srcVp
,
10549 vfs_context_t srcCtx
,
10550 char *tmpBuf
, uint64_t tmpBufSize
,
10551 uint64_t srcOffset
,
10552 const char *dstFname
,
10559 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10563 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10568 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10572 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10577 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)