2 * Copyright (c) 1998-2017 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
;
362 static uint32_t gIOPMPCIHostBridgeWakeDelay
;
364 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
365 #define kCPUUnknownIndex 9999999
372 const OSSymbol
*gIOPMStatsResponseTimedOut
;
373 const OSSymbol
*gIOPMStatsResponseCancel
;
374 const OSSymbol
*gIOPMStatsResponseSlow
;
375 const OSSymbol
*gIOPMStatsResponsePrompt
;
376 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
378 #define kBadPMFeatureID 0
382 * Opaque handle passed to clients of registerPMSettingController()
384 class PMSettingHandle
: public OSObject
386 OSDeclareFinalStructors( PMSettingHandle
)
387 friend class PMSettingObject
;
390 PMSettingObject
*pmso
;
391 void free(void) APPLE_KEXT_OVERRIDE
;
396 * Internal object to track each PM setting controller
398 class PMSettingObject
: public OSObject
400 OSDeclareFinalStructors( PMSettingObject
)
401 friend class IOPMrootDomain
;
404 queue_head_t calloutQueue
;
406 IOPMrootDomain
*parent
;
407 PMSettingHandle
*pmsh
;
408 IOPMSettingControllerCallback func
;
411 uint32_t *publishedFeatureID
;
412 uint32_t settingCount
;
415 void free(void) APPLE_KEXT_OVERRIDE
;
418 static PMSettingObject
*pmSettingObject(
419 IOPMrootDomain
*parent_arg
,
420 IOPMSettingControllerCallback handler_arg
,
421 OSObject
*target_arg
,
422 uintptr_t refcon_arg
,
423 uint32_t supportedPowerSources
,
424 const OSSymbol
*settings
[],
425 OSObject
**handle_obj
);
427 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
428 void clientHandleFreed(void);
431 struct PMSettingCallEntry
{
436 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
437 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
438 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
439 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
443 * Internal helper object for logging trace points to RTC
444 * IOPMrootDomain and only IOPMrootDomain should instantiate
445 * exactly one of these.
448 typedef void (*IOPMTracePointHandler
)(
449 void * target
, uint32_t code
, uint32_t data
);
451 class PMTraceWorker
: public OSObject
453 OSDeclareDefaultStructors(PMTraceWorker
)
455 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
457 static PMTraceWorker
*tracer( IOPMrootDomain
* );
458 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
459 void tracePoint(uint8_t phase
);
460 void traceDetail(uint32_t detail
);
461 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
462 int recordTopLevelPCIDevice(IOService
*);
463 void RTC_TRACE(void);
464 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
466 IOPMTracePointHandler tracePointHandler
;
467 void * tracePointTarget
;
468 uint64_t getPMStatusCode();
469 uint8_t getTracePhase();
470 uint32_t getTraceData();
472 IOPMrootDomain
*owner
;
473 IOLock
*pmTraceWorkerLock
;
474 OSArray
*pciDeviceBitMappings
;
476 uint8_t addedToRegistry
;
478 uint32_t traceData32
;
479 uint8_t loginWindowData
;
480 uint8_t coreDisplayData
;
481 uint8_t coreGraphicsData
;
485 * PMAssertionsTracker
486 * Tracks kernel and user space PM assertions
488 class PMAssertionsTracker
: public OSObject
490 OSDeclareFinalStructors(PMAssertionsTracker
)
492 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
494 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
495 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
496 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
497 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
499 OSArray
*copyAssertionsArray(void);
500 IOPMDriverAssertionType
getActivatedAssertions(void);
501 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
503 IOReturn
handleCreateAssertion(OSData
*);
504 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
505 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
506 IOReturn
handleSetUserAssertionLevels(void * arg0
);
507 void publishProperties(void);
511 IOPMDriverAssertionID id
;
512 IOPMDriverAssertionType assertionBits
;
513 uint64_t createdTime
;
514 uint64_t modifiedTime
;
515 const OSSymbol
*ownerString
;
516 IOService
*ownerService
;
517 uint64_t registryEntryID
;
518 IOPMDriverAssertionLevel level
;
521 uint32_t tabulateProducerCount
;
522 uint32_t tabulateConsumerCount
;
524 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
527 IOPMrootDomain
*owner
;
528 OSArray
*assertionsArray
;
529 IOLock
*assertionsArrayLock
;
530 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
531 IOPMDriverAssertionType assertionsKernel
;
532 IOPMDriverAssertionType assertionsUser
;
533 IOPMDriverAssertionType assertionsCombined
;
536 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
540 * Internal helper object for Shutdown/Restart notifications.
542 #define kPMHaltMaxWorkers 8
543 #define kPMHaltTimeoutMS 100
545 class PMHaltWorker
: public OSObject
547 OSDeclareFinalStructors( PMHaltWorker
)
550 IOService
* service
; // service being worked on
551 AbsoluteTime startTime
; // time when work started
552 int depth
; // work on nubs at this PM-tree depth
553 int visits
; // number of nodes visited (debug)
555 bool timeout
; // service took too long
557 static PMHaltWorker
* worker( void );
558 static void main( void * arg
, wait_result_t waitResult
);
559 static void work( PMHaltWorker
* me
);
560 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
561 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
564 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
567 #define super IOService
568 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
570 static void IOPMRootDomainWillShutdown(void)
572 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
574 OSKext::willShutdown();
575 for (int i
= 0; i
< 100; i
++)
577 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
583 extern "C" IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
585 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
588 extern "C" IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
590 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
593 extern "C" IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
595 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
598 extern "C" IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
600 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
603 extern "C" IOReturn
rootDomainRestart ( void )
605 return gRootDomain
->restartSystem();
608 extern "C" IOReturn
rootDomainShutdown ( void )
610 return gRootDomain
->shutdownSystem();
613 static void halt_log_putc(char c
)
615 if (gHaltLogPos
>= (kHaltLogSize
- 2)) return;
616 gHaltLog
[gHaltLogPos
++] = c
;
620 _doprnt_log(const char *fmt
,
626 halt_log(const char *fmt
, ...)
630 va_start(listp
, fmt
);
631 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
638 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
640 uint64_t nano
, millis
;
642 if (!gHaltLog
) return;
643 absolutetime_to_nanoseconds(time
, &nano
);
644 millis
= nano
/ NSEC_PER_MSEC
;
645 if (millis
< 100) return;
647 IOLockLock(gHaltLogLock
);
649 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
650 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
651 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
654 halt_log("%s: %qd ms\n", what
, millis
);
657 gHaltLog
[gHaltLogPos
] = 0;
658 IOLockUnlock(gHaltLogLock
);
661 extern uint32_t gFSState
;
663 extern "C" void IOSystemShutdownNotification(int stage
)
667 if (kIOSystemShutdownNotificationStageRootUnmount
== stage
)
670 uint64_t nano
, millis
;
671 startTime
= mach_absolute_time();
672 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
673 absolutetime_to_nanoseconds(mach_absolute_time() - startTime
, &nano
);
674 millis
= nano
/ NSEC_PER_MSEC
;
675 if (gHaltTimeMaxLog
&& (millis
>= gHaltTimeMaxLog
))
677 printf("waitQuiet() for unmount %qd ms\n", millis
);
683 assert(kIOSystemShutdownNotificationStageProcessExit
== stage
);
685 IOLockLock(gHaltLogLock
);
688 gHaltLog
= IONew(char, kHaltLogSize
);
689 gHaltStartTime
= mach_absolute_time();
690 if (gHaltLog
) halt_log_putc('\n');
692 IOLockUnlock(gHaltLogLock
);
694 startTime
= mach_absolute_time();
695 IOPMRootDomainWillShutdown();
696 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime
);
698 startTime
= mach_absolute_time();
699 IOHibernateSystemPostWake(true);
700 gRootDomain
->swdDebugTeardown();
701 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime
);
703 if (OSCompareAndSwap(0, 1, &gPagingOff
))
706 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
712 extern "C" int sync_internal(void);
715 A device is always in the highest power state which satisfies its driver,
716 its policy-maker, and any power children it has, but within the constraint
717 of the power state provided by its parent. The driver expresses its desire by
718 calling changePowerStateTo(), the policy-maker expresses its desire by calling
719 changePowerStateToPriv(), and the children express their desires by calling
720 requestPowerDomainState().
722 The Root Power Domain owns the policy for idle and demand sleep for the system.
723 It is a power-managed IOService just like the others in the system.
724 It implements several power states which map to what we see as Sleep and On.
726 The sleep policy is as follows:
727 1. Sleep is prevented if the case is open so that nobody will think the machine
728 is off and plug/unplug cards.
729 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
730 3. System cannot Sleep if some object in the tree is in a power state marked
731 kIOPMPreventSystemSleep.
733 These three conditions are enforced using the "driver clamp" by calling
734 changePowerStateTo(). For example, if the case is opened,
735 changePowerStateTo(ON_STATE) is called to hold the system on regardless
736 of the desires of the children of the root or the state of the other clamp.
738 Demand Sleep is initiated by pressing the front panel power button, closing
739 the clamshell, or selecting the menu item. In this case the root's parent
740 actually initiates the power state change so that the root domain has no
741 choice and does not give applications the opportunity to veto the change.
743 Idle Sleep occurs if no objects in the tree are in a state marked
744 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
745 the root on, so it sets the "policy-maker clamp" by calling
746 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
747 This timer is set for the difference between the sleep timeout slider and the
748 display dim timeout slider. When the timer expires, it releases its clamp and
749 now nothing is holding it awake, so it falls asleep.
751 Demand sleep is prevented when the system is booting. When preferences are
752 transmitted by the loginwindow at the end of boot, a flag is cleared,
753 and this allows subsequent Demand Sleep.
756 //******************************************************************************
758 IOPMrootDomain
* IOPMrootDomain::construct( void )
760 IOPMrootDomain
*root
;
762 root
= new IOPMrootDomain
;
769 //******************************************************************************
770 // updateConsoleUsersCallout
772 //******************************************************************************
774 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
776 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
777 rootDomain
->updateConsoleUsers();
780 void IOPMrootDomain::updateConsoleUsers(void)
782 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
785 tasksSuspended
= FALSE
;
786 tasks_system_suspend(tasksSuspended
);
790 //******************************************************************************
792 static void swdDebugSetupCallout( thread_call_param_t p0
, thread_call_param_t p1
)
794 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
795 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
797 rootDomain
->swdDebugSetup();
800 rootDomain
->allowPowerChange(notifyRef
);
802 DLOG("swdDebugSetupCallout finish\n");
805 void IOPMrootDomain::swdDebugSetup( )
808 static int32_t noDebugFile
= -1;
809 if (noDebugFile
== -1) {
810 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)
812 else if (PE_parse_boot_argn("swd_mem_only", &noDebugFile
, sizeof(noDebugFile
)) == false)
816 if ((noDebugFile
== 1) || (gRootDomain
->sleepWakeDebugIsWdogEnabled() == false)) {
819 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup
);
820 if (swd_DebugImageSetup
== FALSE
) {
821 swd_DebugImageSetup
= TRUE
;
822 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
823 (CAP_LOSS(kIOPMSystemCapabilityGraphics
))) {
824 IOHibernateSystemPostWake(true);
825 IOCloseDebugDataFile();
827 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
834 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
836 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
837 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
839 rootDomain
->swdDebugTeardown();
841 rootDomain
->allowPowerChange(notifyRef
);
843 DLOG("swdDebugTeardownCallout finish\n");
846 void IOPMrootDomain::swdDebugTeardown( )
850 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
851 if (swd_DebugImageSetup
== TRUE
) {
852 swd_DebugImageSetup
= FALSE
;
853 IOCloseDebugDataFile();
859 //******************************************************************************
862 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
864 IOService
* rootDomain
= (IOService
*) p0
;
865 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
866 uint32_t powerState
= rootDomain
->getPowerState();
868 DLOG("disk_sync_callout ps=%u\n", powerState
);
870 if (ON_STATE
== powerState
)
875 // Block sleep until trim issued on previous wake path is completed.
876 IOHibernateSystemPostWake(true);
878 swdDebugSetupCallout(p0
, NULL
);
883 swdDebugTeardownCallout(p0
, NULL
);
884 IOHibernateSystemPostWake(false);
887 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
891 rootDomain
->allowPowerChange(notifyRef
);
892 DLOG("disk_sync_callout finish\n");
895 //******************************************************************************
896 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
898 AbsoluteTime endTime
;
901 clock_get_uptime(&endTime
);
902 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) *elapsedTime
= 0;
905 SUB_ABSOLUTETIME(&endTime
, startTime
);
906 absolutetime_to_nanoseconds(endTime
, &nano
);
907 *elapsedTime
= endTime
;
910 return (UInt32
)(nano
/ NSEC_PER_MSEC
);
913 //******************************************************************************
916 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
918 struct timeval
*swt
= (struct timeval
*)arg1
;
919 struct proc
*p
= req
->p
;
922 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
923 } else if(proc_is64bit(p
)) {
924 struct user64_timeval t
= {};
925 t
.tv_sec
= swt
->tv_sec
;
926 t
.tv_usec
= swt
->tv_usec
;
927 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
929 struct user32_timeval t
= {};
930 t
.tv_sec
= swt
->tv_sec
;
931 t
.tv_usec
= swt
->tv_usec
;
932 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
936 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
937 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
938 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
940 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
941 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
942 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
944 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
945 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
949 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
951 int new_value
, changed
;
952 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
954 if (!gWillShutdown
&& (new_value
== 1)) {
955 IOPMRootDomainWillShutdown();
962 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
963 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
964 0, 0, sysctl_willshutdown
, "I", "");
966 extern struct sysctl_oid sysctl__kern_iokittest
;
967 extern struct sysctl_oid sysctl__debug_iokit
;
972 sysctl_progressmeterenable
973 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
976 int new_value
, changed
;
978 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
980 if (changed
) vc_enable_progressmeter(new_value
);
987 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
990 int new_value
, changed
;
992 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
994 if (changed
) vc_set_progressmeter(new_value
);
999 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
1000 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1001 0, 0, sysctl_progressmeterenable
, "I", "");
1003 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
1004 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1005 0, 0, sysctl_progressmeter
, "I", "");
1007 #endif /* !CONFIG_EMBEDDED */
1012 sysctl_consoleoptions
1013 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1018 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
1020 if (changed
) vc_user_options
.options
= new_value
;
1025 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
1026 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1027 0, 0, sysctl_consoleoptions
, "I", "");
1031 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1033 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1036 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1037 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1038 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1042 sysctl_wakereason SYSCTL_HANDLER_ARGS
1044 char wr
[ sizeof(gWakeReasonString
) ];
1048 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1050 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1053 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1054 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1055 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1058 sysctl_targettype SYSCTL_HANDLER_ARGS
1066 root
= IOService::getServiceRoot();
1067 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
1069 if ((data
= OSDynamicCast(OSData
, obj
)))
1071 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1075 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1078 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1079 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1080 NULL
, 0, sysctl_targettype
, "A", "targettype");
1082 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1083 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1085 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
1086 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
1087 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
1088 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
1089 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
1090 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
1091 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
1092 static const OSSymbol
* gIOPMUserIsActiveKey
;
1094 //******************************************************************************
1097 //******************************************************************************
1099 #define kRootDomainSettingsCount 17
1101 bool IOPMrootDomain::start( IOService
* nub
)
1103 OSIterator
*psIterator
;
1104 OSDictionary
*tmpDict
;
1105 IORootParent
* patriarch
;
1106 #if defined(__i386__) || defined(__x86_64__)
1107 IONotifier
* notifier
;
1113 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1114 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1115 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1116 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1117 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1118 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1119 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1120 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1122 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1123 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1124 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1125 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1126 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1128 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1129 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1131 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1133 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1134 gIOPMSettingAutoWakeSecondsKey
,
1135 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1136 gIOPMSettingAutoWakeCalendarKey
,
1137 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1138 gIOPMSettingDebugWakeRelativeKey
,
1139 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1140 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1141 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1142 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1143 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1144 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1145 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1146 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1147 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1148 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1149 gIOPMSettingSilentRunningKey
1152 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1153 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1154 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1155 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1156 PE_parse_boot_argn("pcihostbridge_wake_delay", &gIOPMPCIHostBridgeWakeDelay
, sizeof(gIOPMPCIHostBridgeWakeDelay
));
1158 queue_init(&aggressivesQueue
);
1159 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1160 aggressivesData
= OSData::withCapacity(
1161 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1163 featuresDictLock
= IOLockAlloc();
1164 settingsCtrlLock
= IOLockAlloc();
1165 wakeEventLock
= IOLockAlloc();
1166 gHaltLogLock
= IOLockAlloc();
1167 setPMRootDomain(this);
1169 extraSleepTimer
= thread_call_allocate(
1170 idleSleepTimerExpired
,
1171 (thread_call_param_t
) this);
1173 diskSyncCalloutEntry
= thread_call_allocate(
1175 (thread_call_param_t
) this);
1176 swdDebugSetupEntry
= thread_call_allocate(
1177 &swdDebugSetupCallout
,
1178 (thread_call_param_t
) this);
1179 swdDebugTearDownEntry
= thread_call_allocate(
1180 &swdDebugTeardownCallout
,
1181 (thread_call_param_t
) this);
1182 updateConsoleUsersEntry
= thread_call_allocate(
1183 &updateConsoleUsersCallout
,
1184 (thread_call_param_t
) this);
1186 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1187 fullWakeThreadCall
= thread_call_allocate(
1188 OSMemberFunctionCast(thread_call_func_t
, this,
1189 &IOPMrootDomain::fullWakeDelayedWork
),
1190 (thread_call_param_t
) this);
1193 setProperty(kIOSleepSupportedKey
, true);
1195 bzero(&gPMStats
, sizeof(gPMStats
));
1197 pmTracer
= PMTraceWorker::tracer(this);
1199 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1201 userDisabledAllSleep
= false;
1202 systemBooting
= true;
1203 idleSleepEnabled
= false;
1205 idleSleepTimerPending
= false;
1207 clamshellClosed
= false;
1208 clamshellExists
= false;
1209 clamshellDisabled
= true;
1210 acAdaptorConnected
= true;
1211 clamshellSleepDisabled
= false;
1212 gWakeReasonString
[0] = '\0';
1214 // Initialize to user active.
1215 // Will never transition to user inactive w/o wrangler.
1216 fullWakeReason
= kFullWakeReasonLocalUser
;
1217 userIsActive
= userWasActive
= true;
1218 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1220 // Set the default system capabilities at boot.
1221 _currentCapability
= kIOPMSystemCapabilityCPU
|
1222 kIOPMSystemCapabilityGraphics
|
1223 kIOPMSystemCapabilityAudio
|
1224 kIOPMSystemCapabilityNetwork
;
1226 _pendingCapability
= _currentCapability
;
1227 _desiredCapability
= _currentCapability
;
1228 _highestCapability
= _currentCapability
;
1229 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1231 queuedSleepWakeUUIDString
= NULL
;
1232 initializeBootSessionUUID();
1233 pmStatsAppResponses
= OSArray::withCapacity(5);
1234 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1235 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1236 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1237 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1238 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1239 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1240 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1242 pmStatsLock
= IOLockAlloc();
1243 idxPMCPUClamshell
= kCPUUnknownIndex
;
1244 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1246 tmpDict
= OSDictionary::withCapacity(1);
1247 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1250 settingsCallbacks
= OSDictionary::withCapacity(1);
1252 // Create a list of the valid PM settings that we'll relay to
1253 // interested clients in setProperties() => setPMSetting()
1254 allowedPMSettings
= OSArray::withObjects(
1255 (const OSObject
**)settingsArr
,
1256 kRootDomainSettingsCount
,
1259 // List of PM settings that should not automatically publish itself
1260 // as a feature when registered by a listener.
1261 noPublishPMSettings
= OSArray::withObjects(
1262 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1264 fPMSettingsDict
= OSDictionary::withCapacity(5);
1265 preventIdleSleepList
= OSSet::withCapacity(8);
1266 preventSystemSleepList
= OSSet::withCapacity(2);
1268 PMinit(); // creates gIOPMWorkLoop
1269 gIOPMWorkLoop
= getIOPMWorkloop();
1271 // Create IOPMPowerStateQueue used to queue external power
1272 // events, and to handle those events on the PM work loop.
1273 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1274 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1275 &IOPMrootDomain::dispatchPowerEvent
));
1276 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1278 // create our power parent
1279 patriarch
= new IORootParent
;
1281 patriarch
->attach(this);
1282 patriarch
->start(this);
1283 patriarch
->addPowerChild(this);
1285 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1286 changePowerStateToPriv(ON_STATE
);
1288 // install power change handler
1289 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1292 // Register for a notification when IODisplayWrangler is published
1293 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1295 _displayWranglerNotifier
= addMatchingNotification(
1296 gIOPublishNotification
, tmpDict
,
1297 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1303 #if defined(__i386__) || defined(__x86_64__)
1305 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1307 notifier
= addMatchingNotification(
1308 gIOFirstPublishNotification
, tmpDict
,
1309 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1314 wranglerIdleSettings
= NULL
;
1315 OSNumber
* wranglerIdlePeriod
= NULL
;
1316 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1317 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1319 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1320 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1321 wranglerIdlePeriod
);
1323 if(wranglerIdlePeriod
)
1324 wranglerIdlePeriod
->release();
1327 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1328 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1329 ucClassName
->release();
1331 // IOBacklightDisplay can take a long time to load at boot, or it may
1332 // not load at all if you're booting with clamshell closed. We publish
1333 // 'DisplayDims' here redundantly to get it published early and at all.
1334 OSDictionary
* matching
;
1335 matching
= serviceMatching("IOPMPowerSource");
1336 psIterator
= getMatchingServices( matching
);
1337 if (matching
) matching
->release();
1338 if( psIterator
&& psIterator
->getNextObject() )
1340 // There's at least one battery on the system, so we publish
1341 // 'DisplayDims' support for the LCD.
1342 publishFeature("DisplayDims");
1345 psIterator
->release();
1348 sysctl_register_oid(&sysctl__kern_sleeptime
);
1349 sysctl_register_oid(&sysctl__kern_waketime
);
1350 sysctl_register_oid(&sysctl__kern_willshutdown
);
1351 sysctl_register_oid(&sysctl__kern_iokittest
);
1352 sysctl_register_oid(&sysctl__debug_iokit
);
1353 sysctl_register_oid(&sysctl__hw_targettype
);
1355 #if !CONFIG_EMBEDDED
1356 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1357 sysctl_register_oid(&sysctl__kern_progressmeter
);
1358 sysctl_register_oid(&sysctl__kern_wakereason
);
1359 #endif /* !CONFIG_EMBEDDED */
1360 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1361 sysctl_register_oid(&sysctl__kern_progressoptions
);
1364 IOHibernateSystemInit(this);
1367 registerService(); // let clients find us
1372 //******************************************************************************
1375 // Receive a setProperty call
1376 // The "System Boot" property means the system is completely booted.
1377 //******************************************************************************
1379 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1381 IOReturn return_value
= kIOReturnSuccess
;
1382 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1385 const OSSymbol
*key
;
1387 OSCollectionIterator
* iter
= 0;
1389 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1390 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1391 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1392 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1393 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1394 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1395 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1396 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1397 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1398 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1399 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1401 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1402 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1403 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1404 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1405 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1406 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1411 return_value
= kIOReturnBadArgument
;
1415 iter
= OSCollectionIterator::withCollection(dict
);
1418 return_value
= kIOReturnNoMemory
;
1422 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1423 (obj
= dict
->getObject(key
)))
1425 if (key
->isEqualTo(publish_simulated_battery_string
))
1427 if (OSDynamicCast(OSBoolean
, obj
))
1428 publishResource(key
, kOSBooleanTrue
);
1430 else if (key
->isEqualTo(idle_seconds_string
))
1432 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1434 setProperty(key
, n
);
1435 idleSeconds
= n
->unsigned32BitValue();
1438 else if (key
->isEqualTo(boot_complete_string
))
1440 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1442 else if (key
->isEqualTo(sys_shutdown_string
))
1444 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1445 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1447 else if (key
->isEqualTo(battery_warning_disabled_string
))
1449 setProperty(key
, obj
);
1452 else if (key
->isEqualTo(hibernatemode_string
) ||
1453 key
->isEqualTo(hibernatefilemin_string
) ||
1454 key
->isEqualTo(hibernatefilemax_string
) ||
1455 key
->isEqualTo(hibernatefreeratio_string
) ||
1456 key
->isEqualTo(hibernatefreetime_string
))
1458 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1459 setProperty(key
, n
);
1461 else if (key
->isEqualTo(hibernatefile_string
))
1463 OSString
* str
= OSDynamicCast(OSString
, obj
);
1464 if (str
) setProperty(key
, str
);
1467 else if (key
->isEqualTo(sleepdisabled_string
))
1469 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1471 setProperty(key
, b
);
1472 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1475 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1478 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1480 else if (key
->isEqualTo(loginwindow_progress_string
))
1482 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1483 uint32_t data
= n
->unsigned32BitValue();
1484 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1485 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1488 else if (key
->isEqualTo(coredisplay_progress_string
))
1490 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1491 uint32_t data
= n
->unsigned32BitValue();
1492 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1493 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1496 else if (key
->isEqualTo(coregraphics_progress_string
))
1498 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1499 uint32_t data
= n
->unsigned32BitValue();
1500 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1501 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1504 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1505 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1506 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1507 key
->isEqualTo(stall_halt_string
))
1509 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1510 setProperty(key
, b
);
1512 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1513 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1514 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1515 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1517 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1518 setProperty(key
, n
);
1520 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1522 if (kOSBooleanTrue
== obj
)
1523 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1525 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1526 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1529 // Relay our allowed PM settings onto our registered PM clients
1530 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1532 return_value
= setPMSetting(key
, obj
);
1533 if (kIOReturnSuccess
!= return_value
)
1536 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1538 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1539 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1541 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1545 _debugWakeSeconds
= 0;
1546 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1548 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1550 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1553 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1554 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1556 const IOPMCalendarStruct
* cs
=
1557 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1560 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1562 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1563 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1569 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1574 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1575 if(boot_complete_string
) boot_complete_string
->release();
1576 if(sys_shutdown_string
) sys_shutdown_string
->release();
1577 if(stall_halt_string
) stall_halt_string
->release();
1578 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1579 if(idle_seconds_string
) idle_seconds_string
->release();
1580 if(sleepdisabled_string
) sleepdisabled_string
->release();
1581 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1582 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1583 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1584 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1586 if(hibernatemode_string
) hibernatemode_string
->release();
1587 if(hibernatefile_string
) hibernatefile_string
->release();
1588 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1589 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1591 if (iter
) iter
->release();
1592 return return_value
;
1596 // MARK: Aggressiveness
1598 //******************************************************************************
1599 // setAggressiveness
1601 // Override IOService::setAggressiveness()
1602 //******************************************************************************
1604 IOReturn
IOPMrootDomain::setAggressiveness(
1606 unsigned long value
)
1608 return setAggressiveness( type
, value
, 0 );
1612 * Private setAggressiveness() with an internal options argument.
1614 IOReturn
IOPMrootDomain::setAggressiveness(
1616 unsigned long value
,
1617 IOOptionBits options
)
1619 AggressivesRequest
* entry
;
1620 AggressivesRequest
* request
;
1623 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1624 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1626 request
= IONew(AggressivesRequest
, 1);
1628 return kIOReturnNoMemory
;
1630 memset(request
, 0, sizeof(*request
));
1631 request
->options
= options
;
1632 request
->dataType
= kAggressivesRequestTypeRecord
;
1633 request
->data
.record
.type
= (uint32_t) type
;
1634 request
->data
.record
.value
= (uint32_t) value
;
1638 // Update disk quick spindown flag used by getAggressiveness().
1639 // Never merge requests with quick spindown flags set.
1641 if (options
& kAggressivesOptionQuickSpindownEnable
)
1642 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1643 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1644 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1647 // Coalesce requests with identical aggressives types.
1648 // Deal with callers that calls us too "aggressively".
1650 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1652 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1653 (entry
->data
.record
.type
== type
) &&
1654 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1656 entry
->data
.record
.value
= value
;
1665 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1668 AGGRESSIVES_UNLOCK();
1671 IODelete(request
, AggressivesRequest
, 1);
1673 if (options
& kAggressivesOptionSynchronous
)
1674 handleAggressivesRequests(); // not truly synchronous
1676 thread_call_enter(aggressivesThreadCall
);
1678 return kIOReturnSuccess
;
1681 //******************************************************************************
1682 // getAggressiveness
1684 // Override IOService::setAggressiveness()
1685 // Fetch the aggressiveness factor with the given type.
1686 //******************************************************************************
1688 IOReturn
IOPMrootDomain::getAggressiveness (
1690 unsigned long * outLevel
)
1696 return kIOReturnBadArgument
;
1700 // Disk quick spindown in effect, report value = 1
1702 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1703 (type
== kPMMinutesToSpinDown
))
1705 value
= kAggressivesMinValue
;
1709 // Consult the pending request queue.
1713 AggressivesRequest
* entry
;
1715 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1717 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1718 (entry
->data
.record
.type
== type
) &&
1719 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1721 value
= entry
->data
.record
.value
;
1728 // Consult the backend records.
1730 if (!source
&& aggressivesData
)
1732 AggressivesRecord
* record
;
1735 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1736 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1738 for (i
= 0; i
< count
; i
++, record
++)
1740 if (record
->type
== type
)
1742 value
= record
->value
;
1749 AGGRESSIVES_UNLOCK();
1753 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1754 source
, (uint32_t) type
, value
);
1755 *outLevel
= (unsigned long) value
;
1756 return kIOReturnSuccess
;
1760 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1761 *outLevel
= 0; // default return = 0, driver may not check for error
1762 return kIOReturnInvalid
;
1766 //******************************************************************************
1767 // joinAggressiveness
1769 // Request from IOService to join future aggressiveness broadcasts.
1770 //******************************************************************************
1772 IOReturn
IOPMrootDomain::joinAggressiveness(
1773 IOService
* service
)
1775 AggressivesRequest
* request
;
1777 if (!service
|| (service
== this))
1778 return kIOReturnBadArgument
;
1780 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1782 request
= IONew(AggressivesRequest
, 1);
1784 return kIOReturnNoMemory
;
1786 service
->retain(); // released by synchronizeAggressives()
1788 memset(request
, 0, sizeof(*request
));
1789 request
->dataType
= kAggressivesRequestTypeService
;
1790 request
->data
.service
= service
;
1793 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1794 AGGRESSIVES_UNLOCK();
1796 thread_call_enter(aggressivesThreadCall
);
1798 return kIOReturnSuccess
;
1801 //******************************************************************************
1802 // handleAggressivesRequests
1804 // Backend thread processes all incoming aggressiveness requests in the queue.
1805 //******************************************************************************
1808 handleAggressivesFunction(
1809 thread_call_param_t param1
,
1810 thread_call_param_t param2
)
1814 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1818 void IOPMrootDomain::handleAggressivesRequests( void )
1820 AggressivesRecord
* start
;
1821 AggressivesRecord
* record
;
1822 AggressivesRequest
* request
;
1823 queue_head_t joinedQueue
;
1827 bool pingSelf
= false;
1831 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1832 queue_empty(&aggressivesQueue
))
1835 gAggressivesState
|= kAggressivesStateBusy
;
1836 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1837 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1842 queue_init(&joinedQueue
);
1846 // Remove request from the incoming queue in FIFO order.
1847 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1848 switch (request
->dataType
)
1850 case kAggressivesRequestTypeRecord
:
1851 // Update existing record if found.
1853 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1855 if (record
->type
== request
->data
.record
.type
)
1859 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1861 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1864 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1865 kAggressivesRecordFlagModified
);
1866 DLOG("disk spindown accelerated, was %u min\n",
1870 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1872 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1875 record
->flags
|= kAggressivesRecordFlagModified
;
1876 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1877 DLOG("disk spindown restored to %u min\n",
1881 else if (record
->value
!= request
->data
.record
.value
)
1883 record
->value
= request
->data
.record
.value
;
1884 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1887 record
->flags
|= kAggressivesRecordFlagModified
;
1894 // No matching record, append a new record.
1896 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1898 AggressivesRecord newRecord
;
1900 newRecord
.flags
= kAggressivesRecordFlagModified
;
1901 newRecord
.type
= request
->data
.record
.type
;
1902 newRecord
.value
= request
->data
.record
.value
;
1903 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1905 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1906 DLOG("disk spindown accelerated\n");
1909 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1911 // OSData may have switched to another (larger) buffer.
1912 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1913 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1917 // Finished processing the request, release it.
1918 IODelete(request
, AggressivesRequest
, 1);
1921 case kAggressivesRequestTypeService
:
1922 // synchronizeAggressives() will free request.
1923 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1927 panic("bad aggressives request type %x\n", request
->dataType
);
1930 } while (!queue_empty(&aggressivesQueue
));
1932 // Release the lock to perform work, with busy flag set.
1933 if (!queue_empty(&joinedQueue
) || broadcast
)
1935 AGGRESSIVES_UNLOCK();
1936 if (!queue_empty(&joinedQueue
))
1937 synchronizeAggressives(&joinedQueue
, start
, count
);
1939 broadcastAggressives(start
, count
);
1943 // Remove the modified flag from all records.
1944 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1946 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1947 ((record
->type
== kPMMinutesToDim
) ||
1948 (record
->type
== kPMMinutesToSleep
)))
1951 record
->flags
&= ~kAggressivesRecordFlagModified
;
1954 // Check the incoming queue again since new entries may have been
1955 // added while lock was released above.
1957 } while (!queue_empty(&aggressivesQueue
));
1959 gAggressivesState
&= ~kAggressivesStateBusy
;
1962 AGGRESSIVES_UNLOCK();
1964 // Root domain is interested in system and display sleep slider changes.
1965 // Submit a power event to handle those changes on the PM work loop.
1967 if (pingSelf
&& pmPowerStateQueue
) {
1968 pmPowerStateQueue
->submitPowerEvent(
1969 kPowerEventPolicyStimulus
,
1970 (void *) kStimulusAggressivenessChanged
);
1974 //******************************************************************************
1975 // synchronizeAggressives
1977 // Push all known aggressiveness records to one or more IOService.
1978 //******************************************************************************
1980 void IOPMrootDomain::synchronizeAggressives(
1981 queue_head_t
* joinedQueue
,
1982 const AggressivesRecord
* array
,
1985 IOService
* service
;
1986 AggressivesRequest
* request
;
1987 const AggressivesRecord
* record
;
1988 IOPMDriverCallEntry callEntry
;
1992 while (!queue_empty(joinedQueue
))
1994 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1995 if (request
->dataType
== kAggressivesRequestTypeService
)
1996 service
= request
->data
.service
;
2000 IODelete(request
, AggressivesRequest
, 1);
2005 if (service
->assertPMDriverCall(&callEntry
))
2007 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
2009 value
= record
->value
;
2010 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2011 value
= kAggressivesMinValue
;
2013 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2014 record
->type
, value
, service
->getName());
2015 service
->setAggressiveness(record
->type
, value
);
2017 service
->deassertPMDriverCall(&callEntry
);
2019 service
->release(); // retained by joinAggressiveness()
2024 //******************************************************************************
2025 // broadcastAggressives
2027 // Traverse PM tree and call setAggressiveness() for records that have changed.
2028 //******************************************************************************
2030 void IOPMrootDomain::broadcastAggressives(
2031 const AggressivesRecord
* array
,
2034 IORegistryIterator
* iter
;
2035 IORegistryEntry
* entry
;
2036 IOPowerConnection
* connect
;
2037 IOService
* service
;
2038 const AggressivesRecord
* record
;
2039 IOPMDriverCallEntry callEntry
;
2043 iter
= IORegistryIterator::iterateOver(
2044 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2050 while ((entry
= iter
->getNextObject()))
2052 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2053 if (!connect
|| !connect
->getReadyFlag())
2056 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
2058 if (service
->assertPMDriverCall(&callEntry
))
2060 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
2062 if (record
->flags
& kAggressivesRecordFlagModified
)
2064 value
= record
->value
;
2065 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2066 value
= kAggressivesMinValue
;
2067 _LOG("broadcastAggressives %x = %u to %s\n",
2068 record
->type
, value
, service
->getName());
2069 service
->setAggressiveness(record
->type
, value
);
2072 service
->deassertPMDriverCall(&callEntry
);
2078 while (!entry
&& !iter
->isValid());
2084 // MARK: System Sleep
2086 //******************************************************************************
2087 // startIdleSleepTimer
2089 //******************************************************************************
2091 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2093 AbsoluteTime deadline
;
2097 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2102 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2103 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2104 idleSleepTimerPending
= true;
2108 thread_call_enter(extraSleepTimer
);
2110 DLOG("idle timer set for %u seconds\n", inSeconds
);
2113 //******************************************************************************
2114 // cancelIdleSleepTimer
2116 //******************************************************************************
2118 void IOPMrootDomain::cancelIdleSleepTimer( void )
2121 if (idleSleepTimerPending
)
2123 DLOG("idle timer cancelled\n");
2124 thread_call_cancel(extraSleepTimer
);
2125 idleSleepTimerPending
= false;
2127 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2129 clock_usec_t microsecs
;
2130 clock_get_uptime(&now
);
2131 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2132 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2133 if (assertOnWakeReport
) {
2134 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2135 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2141 //******************************************************************************
2142 // idleSleepTimerExpired
2144 //******************************************************************************
2146 static void idleSleepTimerExpired(
2147 thread_call_param_t us
, thread_call_param_t
)
2149 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2152 //******************************************************************************
2153 // handleSleepTimerExpiration
2155 // The time between the sleep idle timeout and the next longest one has elapsed.
2156 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2157 //******************************************************************************
2159 void IOPMrootDomain::handleSleepTimerExpiration( void )
2161 if (!gIOPMWorkLoop
->inGate())
2163 gIOPMWorkLoop
->runAction(
2164 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2165 &IOPMrootDomain::handleSleepTimerExpiration
),
2172 DLOG("sleep timer expired\n");
2175 idleSleepTimerPending
= false;
2177 clock_get_uptime(&time
);
2178 setQuickSpinDownTimeout();
2179 adjustPowerState(true);
2182 //******************************************************************************
2183 // getTimeToIdleSleep
2185 // Returns number of seconds left before going into idle sleep.
2186 // Caller has to make sure that idle sleep is allowed at the time of calling
2188 //******************************************************************************
2190 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2193 AbsoluteTime now
, lastActivityTime
;
2195 uint32_t minutesSinceUserInactive
= 0;
2196 uint32_t sleepDelay
= 0;
2198 if (!idleSleepEnabled
)
2201 if (userActivityTime
)
2202 lastActivityTime
= userActivityTime
;
2204 lastActivityTime
= userBecameInactiveTime
;
2206 clock_get_uptime(&now
);
2207 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2209 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2210 absolutetime_to_nanoseconds(now
, &nanos
);
2211 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2213 if (minutesSinceUserInactive
>= sleepSlider
)
2216 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2220 sleepDelay
= sleepSlider
;
2223 DLOG("user inactive %u min, time to idle sleep %u min\n",
2224 minutesSinceUserInactive
, sleepDelay
);
2226 return (sleepDelay
* 60);
2229 //******************************************************************************
2230 // setQuickSpinDownTimeout
2232 //******************************************************************************
2234 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2238 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2241 //******************************************************************************
2242 // restoreUserSpinDownTimeout
2244 //******************************************************************************
2246 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2250 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2253 //******************************************************************************
2256 //******************************************************************************
2259 IOReturn
IOPMrootDomain::sleepSystem( void )
2261 return sleepSystemOptions(NULL
);
2265 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2267 OSObject
*obj
= NULL
;
2268 OSString
*reason
= NULL
;
2269 /* sleepSystem is a public function, and may be called by any kernel driver.
2270 * And that's bad - drivers should sleep the system by calling
2271 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2273 * Note that user space app calls to IOPMSleepSystem() will also travel
2274 * this code path and thus be correctly identified as software sleeps.
2277 if (options
&& options
->getObject("OSSwitch"))
2279 // Log specific sleep cause for OS Switch hibernation
2280 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2283 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2285 reason
= OSDynamicCast(OSString
, obj
);
2286 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2287 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2290 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2294 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2296 /* Called from both gated and non-gated context */
2298 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2300 return kIOReturnNotPermitted
;
2303 pmPowerStateQueue
->submitPowerEvent(
2304 kPowerEventPolicyStimulus
,
2305 (void *) kStimulusDemandSystemSleep
,
2308 return kIOReturnSuccess
;
2311 //******************************************************************************
2314 // This overrides powerChangeDone in IOService.
2315 //******************************************************************************
2317 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2319 #if !__i386__ && !__x86_64__
2320 uint64_t timeSinceReset
= 0;
2324 DLOG("PowerChangeDone: %u->%u\n",
2325 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2327 switch ( getPowerState() )
2330 if (previousPowerState
!= ON_STATE
)
2333 acceptSystemWakeEvents(true);
2335 // re-enable this timer for next sleep
2336 cancelIdleSleepTimer();
2339 clock_usec_t microsecs
;
2340 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2342 gIOLastSleepTime
.tv_sec
= secs
;
2343 gIOLastSleepTime
.tv_usec
= microsecs
;
2344 gIOLastWakeTime
.tv_sec
= 0;
2345 gIOLastWakeTime
.tv_usec
= 0;
2346 gIOLastSleepAbsTime
= now
;
2348 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2349 clock_usec_t microsecs
;
2350 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2351 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2353 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2354 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2355 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2356 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2357 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2359 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2360 wake2DarkwakeDelay
= 0;
2363 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2365 IOHibernateSystemHasSlept();
2367 evaluateSystemSleepPolicyFinal();
2369 LOG("System Sleep\n");
2371 if (thermalWarningState
) {
2372 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2374 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2378 assertOnWakeSecs
= 0;
2379 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2380 lowBatteryCondition
= false;
2382 #if DEVELOPMENT || DEBUG
2383 extern int g_should_log_clock_adjustments
;
2384 if (g_should_log_clock_adjustments
) {
2385 clock_sec_t secs
= 0;
2386 clock_usec_t microsecs
= 0;
2387 uint64_t now_b
= mach_absolute_time();
2389 PEGetUTCTimeOfDay(&secs
, µsecs
);
2391 uint64_t now_a
= mach_absolute_time();
2392 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2393 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2397 getPlatform()->sleepKernel();
2399 // The CPU(s) are off at this point,
2400 // Code will resume execution here upon wake.
2402 clock_get_uptime(&gIOLastWakeAbsTime
);
2403 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2404 _highestCapability
= 0;
2406 ((IOService
*)this)->start_watchdog_timer(); //14456299
2408 IOHibernateSystemWake();
2411 // sleep transition complete
2412 gSleepOrShutdownPending
= 0;
2414 // trip the reset of the calendar clock
2416 clock_sec_t wakeSecs
;
2417 clock_usec_t wakeMicrosecs
;
2419 clock_wakeup_calendar();
2421 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2422 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2423 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2427 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2430 lastSleepReason
= 0;
2432 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2433 _debugWakeSeconds
= 0;
2434 _scheduledAlarms
= 0;
2436 #if defined(__i386__) || defined(__x86_64__)
2437 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2438 wranglerTickled
= false;
2439 graphicsSuppressed
= false;
2440 darkWakePostTickle
= false;
2441 darkWakeHibernateError
= false;
2442 darkWakeToSleepASAP
= true;
2443 logGraphicsClamp
= true;
2444 sleepTimerMaintenance
= false;
2445 sleepToStandby
= false;
2446 wranglerTickleLatched
= false;
2447 userWasActive
= false;
2448 fullWakeReason
= kFullWakeReasonNone
;
2450 OSString
* wakeType
= OSDynamicCast(
2451 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2452 OSString
* wakeReason
= OSDynamicCast(
2453 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2455 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2456 gWakeReasonString
[0] == '\0')
2458 // Until the platform driver can claim its wake reasons
2459 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2460 sizeof(gWakeReasonString
));
2463 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2465 lowBatteryCondition
= true;
2466 darkWakeMaintenance
= true;
2468 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2471 OSNumber
* hibOptions
= OSDynamicCast(
2472 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2473 if (hibernateAborted
|| ((hibOptions
&&
2474 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2476 // Hibernate aborted, or EFI brought up graphics
2477 wranglerTickled
= true;
2478 DLOG("hibernation aborted %d, options 0x%x\n",
2480 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2485 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2486 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2488 // User wake or RTC alarm
2489 wranglerTickled
= true;
2493 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2495 // SMC standby timer trumps SleepX
2496 darkWakeMaintenance
= true;
2497 sleepTimerMaintenance
= true;
2500 if ((_lastDebugWakeSeconds
!= 0) &&
2501 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2503 // SleepX before maintenance
2504 wranglerTickled
= true;
2508 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2510 darkWakeMaintenance
= true;
2514 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2516 darkWakeMaintenance
= true;
2517 darkWakeSleepService
= true;
2519 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2520 sleepToStandby
= true;
2526 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2528 darkWakeMaintenance
= true;
2529 darkWakeHibernateError
= true;
2533 // Unidentified wake source, resume to full wake if debug
2534 // alarm is pending.
2536 if (_lastDebugWakeSeconds
&&
2537 (!wakeReason
|| wakeReason
->isEqualTo("")))
2538 wranglerTickled
= true;
2544 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2546 darkWakeMaintenance
= true;
2547 sleepTimerMaintenance
= true;
2549 else if (hibernateAborted
|| !wakeType
||
2550 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2551 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2553 // Post a HID tickle immediately - except for RTC maintenance wake.
2554 wranglerTickled
= true;
2558 darkWakeMaintenance
= true;
2562 if (wranglerTickled
)
2564 darkWakeToSleepASAP
= false;
2565 fullWakeReason
= kFullWakeReasonLocalUser
;
2568 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2570 handleDisplayPowerOn();
2572 else if (!darkWakeMaintenance
)
2574 // Early/late tickle for non-maintenance wake.
2575 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2576 kDarkWakeFlagHIDTickleEarly
) ||
2577 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2578 kDarkWakeFlagHIDTickleLate
))
2580 darkWakePostTickle
= true;
2583 #else /* !__i386__ && !__x86_64__ */
2584 timeSinceReset
= ml_get_time_since_reset();
2586 kdebugTrace(kPMLogSystemWake
, 0, timeSinceReset
>> 32, timeSinceReset
);
2587 // stay awake for at least 30 seconds
2588 wranglerTickled
= true;
2589 fullWakeReason
= kFullWakeReasonLocalUser
;
2590 startIdleSleepTimer(30);
2594 thread_call_enter(updateConsoleUsersEntry
);
2596 changePowerStateToPriv(ON_STATE
);
2598 #if !__i386__ && !__x86_64__
2600 if (previousPowerState
!= ON_STATE
)
2602 DLOG("Force re-evaluating aggressiveness\n");
2603 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2604 pmPowerStateQueue
->submitPowerEvent(
2605 kPowerEventPolicyStimulus
,
2606 (void *) kStimulusNoIdleSleepPreventers
);
2616 //******************************************************************************
2617 // requestPowerDomainState
2619 // Extend implementation in IOService. Running on PM work loop thread.
2620 //******************************************************************************
2622 IOReturn
IOPMrootDomain::requestPowerDomainState (
2623 IOPMPowerFlags childDesire
,
2624 IOPowerConnection
* childConnection
,
2625 unsigned long specification
)
2627 // Idle and system sleep prevention flags affects driver desire.
2628 // Children desire are irrelevant so they are cleared.
2630 return super::requestPowerDomainState(0, childConnection
, specification
);
2634 //******************************************************************************
2635 // updatePreventIdleSleepList
2637 // Called by IOService on PM work loop.
2638 // Returns true if PM policy recognized the driver's desire to prevent idle
2639 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2640 //******************************************************************************
2642 bool IOPMrootDomain::updatePreventIdleSleepList(
2643 IOService
* service
, bool addNotRemove
)
2645 unsigned int oldCount
, newCount
;
2649 #if defined(__i386__) || defined(__x86_64__)
2650 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2651 // idle sleep, except in the case of legacy disk I/O
2652 if ((service
!= wrangler
) && (service
!= this))
2658 oldCount
= preventIdleSleepList
->getCount();
2661 preventIdleSleepList
->setObject(service
);
2662 DLOG("prevent idle sleep list: %s+ (%u)\n",
2663 service
->getName(), preventIdleSleepList
->getCount());
2665 else if (preventIdleSleepList
->member(service
))
2667 preventIdleSleepList
->removeObject(service
);
2668 DLOG("prevent idle sleep list: %s- (%u)\n",
2669 service
->getName(), preventIdleSleepList
->getCount());
2671 newCount
= preventIdleSleepList
->getCount();
2673 if ((oldCount
== 0) && (newCount
!= 0))
2675 // Driver added to empty prevent list.
2676 // Update the driver desire to prevent idle sleep.
2677 // Driver desire does not prevent demand sleep.
2679 changePowerStateTo(ON_STATE
);
2681 else if ((oldCount
!= 0) && (newCount
== 0))
2683 // Last driver removed from prevent list.
2684 // Drop the driver clamp to allow idle sleep.
2686 changePowerStateTo(SLEEP_STATE
);
2687 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2689 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2690 &newCount
, sizeof(newCount
));
2692 #if defined(__i386__) || defined(__x86_64__)
2693 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2695 DLOG("Cannot cancel idle sleep\n");
2696 return false; // do not idle-cancel
2703 //******************************************************************************
2705 //******************************************************************************
2707 void IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
2709 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
2712 //******************************************************************************
2713 // preventSystemSleepListUpdate
2715 // Called by IOService on PM work loop.
2716 //******************************************************************************
2718 void IOPMrootDomain::updatePreventSystemSleepList(
2719 IOService
* service
, bool addNotRemove
)
2721 unsigned int oldCount
, newCount
;
2724 if (this == service
)
2727 oldCount
= preventSystemSleepList
->getCount();
2730 preventSystemSleepList
->setObject(service
);
2731 DLOG("prevent system sleep list: %s+ (%u)\n",
2732 service
->getName(), preventSystemSleepList
->getCount());
2733 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2735 clock_usec_t microsecs
;
2736 clock_get_uptime(&now
);
2737 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2738 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2739 if (assertOnWakeReport
) {
2740 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2741 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2745 else if (preventSystemSleepList
->member(service
))
2747 preventSystemSleepList
->removeObject(service
);
2748 DLOG("prevent system sleep list: %s- (%u)\n",
2749 service
->getName(), preventSystemSleepList
->getCount());
2751 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2753 // Lost all system sleep preventers.
2754 // Send stimulus if system sleep was blocked, and is in dark wake.
2755 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2758 newCount
= preventSystemSleepList
->getCount();
2759 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2760 &newCount
, sizeof(newCount
));
2763 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2766 OSCollectionIterator
*iterator
= NULL
;
2767 OSObject
*object
= NULL
;
2768 OSArray
*array
= NULL
;
2770 if (!gIOPMWorkLoop
->inGate())
2772 gIOPMWorkLoop
->runAction(
2773 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2774 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2775 this, (void *)idleSleepList
, (void *)systemSleepList
);
2779 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2781 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2782 array
= OSArray::withCapacity(5);
2784 while ((object
= iterator
->getNextObject()))
2786 IOService
*service
= OSDynamicCast(IOService
, object
);
2789 array
->setObject(OSSymbol::withCString(service
->getName()));
2793 iterator
->release();
2794 *idleSleepList
= array
;
2797 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2799 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2800 array
= OSArray::withCapacity(5);
2802 while ((object
= iterator
->getNextObject()))
2804 IOService
*service
= OSDynamicCast(IOService
, object
);
2807 array
->setObject(OSSymbol::withCString(service
->getName()));
2811 iterator
->release();
2812 *systemSleepList
= array
;
2816 //******************************************************************************
2819 // Override the superclass implementation to send a different message type.
2820 //******************************************************************************
2822 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2824 DLOG("tellChangeDown %u->%u\n",
2825 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2827 if (SLEEP_STATE
== stateNum
)
2829 // Legacy apps were already told in the full->dark transition
2830 if (!ignoreTellChangeDown
)
2831 tracePoint( kIOPMTracePointSleepApplications
);
2833 tracePoint( kIOPMTracePointSleepPriorityClients
);
2836 if (!ignoreTellChangeDown
) {
2837 userActivityAtSleep
= userActivityCount
;
2838 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2840 if (SLEEP_STATE
== stateNum
) {
2841 hibernateAborted
= false;
2843 // Direct callout into OSKext so it can disable kext unloads
2844 // during sleep/wake to prevent deadlocks.
2845 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2847 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2849 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2850 // But tellClientsWithResponse() must be called for both.
2851 ignoreTellChangeDown
= true;
2855 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2858 //******************************************************************************
2861 // Override the superclass implementation to send a different message type.
2862 // This must be idle sleep since we don't ask during any other power change.
2863 //******************************************************************************
2865 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2867 DLOG("askChangeDown %u->%u\n",
2868 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2870 // Don't log for dark wake entry
2871 if (kSystemTransitionSleep
== _systemTransitionType
)
2872 tracePoint( kIOPMTracePointSleepApplications
);
2874 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2877 //******************************************************************************
2878 // askChangeDownDone
2880 // An opportunity for root domain to cancel the power transition,
2881 // possibily due to an assertion created by powerd in response to
2882 // kIOMessageCanSystemSleep.
2885 // full -> dark wake transition
2886 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2887 // 2. askChangeDownDone()
2888 // dark -> sleep transition
2889 // 1. Notify powerd with kIOMessageCanSystemSleep
2890 // 2. askChangeDownDone()
2893 // full -> dark wake transition
2894 // 1. Notify powerd with kIOMessageCanSystemSleep
2895 // 2. askChangeDownDone()
2896 // dark -> sleep transition
2897 // 1. Notify powerd with kIOMessageCanSystemSleep
2898 // 2. askChangeDownDone()
2899 //******************************************************************************
2901 void IOPMrootDomain::askChangeDownDone(
2902 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2904 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2905 *inOutChangeFlags
, *cancel
,
2906 _systemTransitionType
,
2907 _currentCapability
, _pendingCapability
);
2909 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2911 // Dark->Sleep transition.
2912 // Check if there are any deny sleep assertions.
2913 // lastSleepReason already set by handleOurPowerChangeStart()
2915 if (!checkSystemCanSleep(lastSleepReason
))
2917 // Cancel dark wake to sleep transition.
2918 // Must re-scan assertions upon entering dark wake.
2921 DLOG("cancel dark->sleep\n");
2926 //******************************************************************************
2927 // systemDidNotSleep
2929 // Work common to both canceled or aborted sleep.
2930 //******************************************************************************
2932 void IOPMrootDomain::systemDidNotSleep( void )
2934 // reset console lock state
2935 thread_call_enter(updateConsoleUsersEntry
);
2939 if (idleSleepEnabled
)
2941 // stay awake for at least idleSeconds
2942 startIdleSleepTimer(idleSeconds
);
2947 if (idleSleepEnabled
&& !userIsActive
)
2949 // Manually start the idle sleep timer besides waiting for
2950 // the user to become inactive.
2951 startIdleSleepTimer( kIdleSleepRetryInterval
);
2955 preventTransitionToUserActive(false);
2956 IOService::setAdvisoryTickleEnable( true );
2958 // After idle revert and cancel, send a did-change message to powerd
2959 // to balance the previous will-change message. Kernel clients do not
2960 // need this since sleep cannot be canceled once they are notified.
2962 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2963 (_pendingCapability
!= _currentCapability
) &&
2964 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2966 // Differs from a real capability gain change where notifyRef != 0,
2967 // but it is zero here since no response is expected.
2969 IOPMSystemCapabilityChangeParameters params
;
2971 bzero(¶ms
, sizeof(params
));
2972 params
.fromCapabilities
= _pendingCapability
;
2973 params
.toCapabilities
= _currentCapability
;
2974 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2976 DLOG("MESG cap %x->%x did change\n",
2977 params
.fromCapabilities
, params
.toCapabilities
);
2978 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2979 ¶ms
, sizeof(params
));
2983 //******************************************************************************
2986 // Notify registered applications and kernel clients that we are not dropping
2989 // We override the superclass implementation so we can send a different message
2990 // type to the client or application being notified.
2992 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2993 //******************************************************************************
2995 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2997 DLOG("tellNoChangeDown %u->%u\n",
2998 (uint32_t) getPowerState(), (uint32_t) stateNum
);
3000 // Sleep canceled, clear the sleep trace point.
3001 tracePoint(kIOPMTracePointSystemUp
);
3003 systemDidNotSleep();
3004 return tellClients( kIOMessageSystemWillNotSleep
);
3007 //******************************************************************************
3010 // Notify registered applications and kernel clients that we are raising power.
3012 // We override the superclass implementation so we can send a different message
3013 // type to the client or application being notified.
3014 //******************************************************************************
3016 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3018 DLOG("tellChangeUp %u->%u\n",
3019 (uint32_t) getPowerState(), (uint32_t) stateNum
);
3021 ignoreTellChangeDown
= false;
3023 if ( stateNum
== ON_STATE
)
3025 // Direct callout into OSKext so it can disable kext unloads
3026 // during sleep/wake to prevent deadlocks.
3027 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3029 // Notify platform that sleep was cancelled or resumed.
3030 getPlatform()->callPlatformFunction(
3031 sleepMessagePEFunction
, false,
3032 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3035 if (getPowerState() == ON_STATE
)
3037 // this is a quick wake from aborted sleep
3038 systemDidNotSleep();
3039 tellClients( kIOMessageSystemWillPowerOn
);
3042 tracePoint( kIOPMTracePointWakeApplications
);
3043 tellClients( kIOMessageSystemHasPoweredOn
);
3047 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3048 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3049 ((params)->fromCapabilities & (flag)) && \
3050 (((params)->toCapabilities & (flag)) == 0))
3052 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3053 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3054 ((params)->toCapabilities & (flag)) && \
3055 (((params)->fromCapabilities & (flag)) == 0))
3057 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3058 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3059 ((params)->fromCapabilities & (flag)) && \
3060 (((params)->toCapabilities & (flag)) == 0))
3062 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3063 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3064 ((params)->toCapabilities & (flag)) && \
3065 (((params)->fromCapabilities & (flag)) == 0))
3067 //******************************************************************************
3068 // sysPowerDownHandler
3070 // Perform a vfs sync before system sleep.
3071 //******************************************************************************
3073 IOReturn
IOPMrootDomain::sysPowerDownHandler(
3074 void * target
, void * refCon
,
3075 UInt32 messageType
, IOService
* service
,
3076 void * messageArgs
, vm_size_t argSize
)
3080 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3083 return kIOReturnUnsupported
;
3085 if (messageType
== kIOMessageSystemWillSleep
)
3088 IOPowerStateChangeNotification
*notify
=
3089 (IOPowerStateChangeNotification
*)messageArgs
;
3091 notify
->returnValue
= 30 * 1000 * 1000;
3093 gRootDomain
->swdDebugSetupEntry
,
3094 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
3097 else if (messageType
== kIOMessageSystemCapabilityChange
)
3099 IOPMSystemCapabilityChangeParameters
* params
=
3100 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3102 // Interested applications have been notified of an impending power
3103 // change and have acked (when applicable).
3104 // This is our chance to save whatever state we can before powering
3106 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3109 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3110 params
->fromCapabilities
, params
->toCapabilities
,
3111 params
->changeFlags
);
3113 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
3115 // We will ack within 20 seconds
3116 params
->maxWaitForReply
= 20 * 1000 * 1000;
3119 gRootDomain
->evaluateSystemSleepPolicyEarly();
3121 // add in time we could spend freeing pages
3122 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
3124 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3126 DLOG("sysPowerDownHandler max wait %d s\n",
3127 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3130 // Notify platform that sleep has begun, after the early
3131 // sleep policy evaluation.
3132 getPlatform()->callPlatformFunction(
3133 sleepMessagePEFunction
, false,
3134 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3137 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3139 // Purposely delay the ack and hope that shutdown occurs quickly.
3140 // Another option is not to schedule the thread and wait for
3142 AbsoluteTime deadline
;
3143 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3144 thread_call_enter1_delayed(
3145 gRootDomain
->diskSyncCalloutEntry
,
3146 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3151 gRootDomain
->diskSyncCalloutEntry
,
3152 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3155 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3157 // We will ack within 110 seconds
3158 params
->maxWaitForReply
= 110 * 1000 * 1000;
3161 gRootDomain
->diskSyncCalloutEntry
,
3162 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3164 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3165 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3167 // WillChange for Full wake -> Darkwake
3168 params
->maxWaitForReply
= 30 * 1000 * 1000;
3170 gRootDomain
->swdDebugSetupEntry
,
3171 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3173 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3174 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3176 // DidChange for Full wake -> Darkwake
3177 params
->maxWaitForReply
= 30 * 1000 * 1000;
3179 gRootDomain
->swdDebugTearDownEntry
,
3180 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3184 ret
= kIOReturnSuccess
;
3190 //******************************************************************************
3191 // handleQueueSleepWakeUUID
3193 // Called from IOPMrootDomain when we're initiating a sleep,
3194 // or indirectly from PM configd when PM decides to clear the UUID.
3195 // PM clears the UUID several minutes after successful wake from sleep,
3196 // so that we might associate App spindumps with the immediately previous
3199 // @param obj has a retain on it. We're responsible for releasing that retain.
3200 //******************************************************************************
3202 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3204 OSString
*str
= NULL
;
3206 if (kOSBooleanFalse
== obj
)
3208 handlePublishSleepWakeUUID(NULL
);
3210 else if ((str
= OSDynamicCast(OSString
, obj
)))
3212 // This branch caches the UUID for an upcoming sleep/wake
3213 if (queuedSleepWakeUUIDString
) {
3214 queuedSleepWakeUUIDString
->release();
3215 queuedSleepWakeUUIDString
= NULL
;
3217 queuedSleepWakeUUIDString
= str
;
3218 queuedSleepWakeUUIDString
->retain();
3220 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3229 //******************************************************************************
3230 // handlePublishSleepWakeUUID
3232 // Called from IOPMrootDomain when we're initiating a sleep,
3233 // or indirectly from PM configd when PM decides to clear the UUID.
3234 // PM clears the UUID several minutes after successful wake from sleep,
3235 // so that we might associate App spindumps with the immediately previous
3237 //******************************************************************************
3239 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3244 * Clear the current UUID
3246 if (gSleepWakeUUIDIsSet
)
3248 DLOG("SleepWake UUID cleared\n");
3250 gSleepWakeUUIDIsSet
= false;
3252 removeProperty(kIOPMSleepWakeUUIDKey
);
3253 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3257 * Optionally, publish a new UUID
3259 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3261 OSString
*publishThisUUID
= NULL
;
3263 publishThisUUID
= queuedSleepWakeUUIDString
;
3264 publishThisUUID
->retain();
3266 if (publishThisUUID
)
3268 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3269 publishThisUUID
->release();
3272 gSleepWakeUUIDIsSet
= true;
3273 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3275 queuedSleepWakeUUIDString
->release();
3276 queuedSleepWakeUUIDString
= NULL
;
3280 //******************************************************************************
3281 // IOPMGetSleepWakeUUIDKey
3283 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3284 // To get the full key -- a C string -- the buffer must large enough for
3285 // the end-of-string character.
3286 // The key is expected to be an UUID string
3287 //******************************************************************************
3290 IOPMCopySleepWakeUUIDKey(char *buffer
, size_t buf_len
)
3292 if (!gSleepWakeUUIDIsSet
) {
3296 if (buffer
!= NULL
) {
3299 string
= (OSString
*)
3300 gRootDomain
->copyProperty(kIOPMSleepWakeUUIDKey
);
3302 if (string
== NULL
) {
3305 strlcpy(buffer
, string
->getCStringNoCopy(), buf_len
);
3314 //******************************************************************************
3315 // initializeBootSessionUUID
3317 // Initialize the boot session uuid at boot up and sets it into registry.
3318 //******************************************************************************
3320 void IOPMrootDomain::initializeBootSessionUUID(void)
3323 uuid_string_t new_uuid_string
;
3325 uuid_generate(new_uuid
);
3326 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3327 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3329 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3332 //******************************************************************************
3333 // changePowerStateTo & changePowerStateToPriv
3335 // Override of these methods for logging purposes.
3336 //******************************************************************************
3338 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3340 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3342 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3343 return kIOReturnUnsupported
;
3345 return super::changePowerStateTo(ordinal
);
3348 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3350 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3352 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3353 return kIOReturnUnsupported
;
3355 return super::changePowerStateToPriv(ordinal
);
3358 //******************************************************************************
3361 //******************************************************************************
3363 bool IOPMrootDomain::activitySinceSleep(void)
3365 return (userActivityCount
!= userActivityAtSleep
);
3368 bool IOPMrootDomain::abortHibernation(void)
3370 bool ret
= activitySinceSleep();
3372 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3374 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3375 hibernateAborted
= true;
3381 hibernate_should_abort(void)
3384 return (gRootDomain
->abortHibernation());
3389 //******************************************************************************
3390 // willNotifyPowerChildren
3392 // Called after all interested drivers have all acknowledged the power change,
3393 // but before any power children is informed. Dispatched though a thread call,
3394 // so it is safe to perform work that might block on a sleeping disk. PM state
3395 // machine (not thread) will block w/o timeout until this function returns.
3396 //******************************************************************************
3398 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3403 if (SLEEP_STATE
== newPowerState
)
3405 if (!tasksSuspended
)
3407 AbsoluteTime deadline
;
3408 tasksSuspended
= TRUE
;
3409 tasks_system_suspend(tasksSuspended
);
3411 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3412 #if !CONFIG_EMBEDDED
3413 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3414 #endif /* !CONFIG_EMBEDDED */
3418 IOHibernateSystemSleep();
3419 IOHibernateIOKitSleep();
3421 if (gRootDomain
->activitySinceSleep()) {
3422 dict
= OSDictionary::withCapacity(1);
3423 secs
= OSNumber::withNumber(1, 32);
3426 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3427 gRootDomain
->setProperties(dict
);
3428 MSG("Reverting sleep with relative wake\n");
3430 if (dict
) dict
->release();
3431 if (secs
) secs
->release();
3437 //******************************************************************************
3438 // sleepOnClamshellClosed
3440 // contains the logic to determine if the system should sleep when the clamshell
3442 //******************************************************************************
3444 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3446 if (!clamshellExists
)
3449 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3450 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3452 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3455 void IOPMrootDomain::sendClientClamshellNotification( void )
3457 /* Only broadcast clamshell alert if clamshell exists. */
3458 if (!clamshellExists
)
3461 setProperty(kAppleClamshellStateKey
,
3462 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3464 setProperty(kAppleClamshellCausesSleepKey
,
3465 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3467 /* Argument to message is a bitfiel of
3468 * ( kClamshellStateBit | kClamshellSleepBit )
3470 messageClients(kIOPMMessageClamshellStateChange
,
3471 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3472 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3475 //******************************************************************************
3476 // getSleepSupported
3479 //******************************************************************************
3481 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3483 return( platformSleepSupport
);
3486 //******************************************************************************
3487 // setSleepSupported
3490 //******************************************************************************
3492 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3494 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3495 OSBitOrAtomic(flags
, &platformSleepSupport
);
3498 //******************************************************************************
3499 // setDisableClamShellSleep
3501 //******************************************************************************
3503 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3505 if (gIOPMWorkLoop
->inGate() == false) {
3507 gIOPMWorkLoop
->runAction(
3508 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3515 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3516 if ( clamshellSleepDisabled
!= val
)
3518 clamshellSleepDisabled
= val
;
3519 // If clamshellSleepDisabled is reset to 0, reevaluate if
3520 // system need to go to sleep due to clamshell state
3521 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3522 handlePowerNotification(kLocalEvalClamshellCommand
);
3527 //******************************************************************************
3531 //******************************************************************************
3533 void IOPMrootDomain::wakeFromDoze( void )
3535 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3541 //******************************************************************************
3544 // Adds a new feature to the supported features dictionary
3545 //******************************************************************************
3547 void IOPMrootDomain::publishFeature( const char * feature
)
3549 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3552 //******************************************************************************
3553 // publishFeature (with supported power source specified)
3555 // Adds a new feature to the supported features dictionary
3556 //******************************************************************************
3558 void IOPMrootDomain::publishFeature(
3559 const char *feature
,
3560 uint32_t supportedWhere
,
3561 uint32_t *uniqueFeatureID
)
3563 static uint16_t next_feature_id
= 500;
3565 OSNumber
*new_feature_data
= NULL
;
3566 OSNumber
*existing_feature
= NULL
;
3567 OSArray
*existing_feature_arr
= NULL
;
3568 OSObject
*osObj
= NULL
;
3569 uint32_t feature_value
= 0;
3571 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3573 if(!supportedWhere
) {
3574 // Feature isn't supported anywhere!
3578 if(next_feature_id
> 5000) {
3579 // Far, far too many features!
3583 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3585 OSDictionary
*features
=
3586 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3588 // Create new features dict if necessary
3589 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3590 features
= OSDictionary::withDictionary(features
);
3592 features
= OSDictionary::withCapacity(1);
3595 // Create OSNumber to track new feature
3597 next_feature_id
+= 1;
3598 if( uniqueFeatureID
) {
3599 // We don't really mind if the calling kext didn't give us a place
3600 // to stash their unique id. Many kexts don't plan to unload, and thus
3601 // have no need to remove themselves later.
3602 *uniqueFeatureID
= next_feature_id
;
3605 feature_value
= (uint32_t)next_feature_id
;
3606 feature_value
<<= 16;
3607 feature_value
+= supportedWhere
;
3609 new_feature_data
= OSNumber::withNumber(
3610 (unsigned long long)feature_value
, 32);
3612 // Does features object already exist?
3613 if( (osObj
= features
->getObject(feature
)) )
3615 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3617 // We need to create an OSArray to hold the now 2 elements.
3618 existing_feature_arr
= OSArray::withObjects(
3619 (const OSObject
**)&existing_feature
, 1, 2);
3620 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3622 // Add object to existing array
3623 existing_feature_arr
= OSArray::withArray(
3624 existing_feature_arr
,
3625 existing_feature_arr
->getCount() + 1);
3628 if (existing_feature_arr
)
3630 existing_feature_arr
->setObject(new_feature_data
);
3631 features
->setObject(feature
, existing_feature_arr
);
3632 existing_feature_arr
->release();
3633 existing_feature_arr
= 0;
3636 // The easy case: no previously existing features listed. We simply
3637 // set the OSNumber at key 'feature' and we're on our way.
3638 features
->setObject(feature
, new_feature_data
);
3641 new_feature_data
->release();
3643 setProperty(kRootDomainSupportedFeatures
, features
);
3645 features
->release();
3647 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3649 // Notify EnergySaver and all those in user space so they might
3650 // re-populate their feature specific UI
3651 if(pmPowerStateQueue
) {
3652 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3656 //******************************************************************************
3657 // removePublishedFeature
3659 // Removes previously published feature
3660 //******************************************************************************
3662 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3664 IOReturn ret
= kIOReturnError
;
3665 uint32_t feature_value
= 0;
3666 uint16_t feature_id
= 0;
3667 bool madeAChange
= false;
3669 OSSymbol
*dictKey
= NULL
;
3670 OSCollectionIterator
*dictIterator
= NULL
;
3671 OSArray
*arrayMember
= NULL
;
3672 OSNumber
*numberMember
= NULL
;
3673 OSObject
*osObj
= NULL
;
3674 OSNumber
*osNum
= NULL
;
3675 OSArray
*arrayMemberCopy
;
3677 if (kBadPMFeatureID
== removeFeatureID
)
3678 return kIOReturnNotFound
;
3680 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3682 OSDictionary
*features
=
3683 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3685 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3687 // Any modifications to the dictionary are made to the copy to prevent
3688 // races & crashes with userland clients. Dictionary updated
3689 // automically later.
3690 features
= OSDictionary::withDictionary(features
);
3693 ret
= kIOReturnNotFound
;
3697 // We iterate 'features' dictionary looking for an entry tagged
3698 // with 'removeFeatureID'. If found, we remove it from our tracking
3699 // structures and notify the OS via a general interest message.
3701 dictIterator
= OSCollectionIterator::withCollection(features
);
3706 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3708 osObj
= features
->getObject(dictKey
);
3710 // Each Feature is either tracked by an OSNumber
3711 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3713 feature_value
= numberMember
->unsigned32BitValue();
3714 feature_id
= (uint16_t)(feature_value
>> 16);
3716 if( feature_id
== (uint16_t)removeFeatureID
)
3719 features
->removeObject(dictKey
);
3724 // Or tracked by an OSArray of OSNumbers
3725 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3727 unsigned int arrayCount
= arrayMember
->getCount();
3729 for(unsigned int i
=0; i
<arrayCount
; i
++)
3731 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3736 feature_value
= osNum
->unsigned32BitValue();
3737 feature_id
= (uint16_t)(feature_value
>> 16);
3739 if( feature_id
== (uint16_t)removeFeatureID
)
3742 if( 1 == arrayCount
) {
3743 // If the array only contains one element, remove
3745 features
->removeObject(dictKey
);
3747 // Otherwise remove the element from a copy of the array.
3748 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3749 if (arrayMemberCopy
)
3751 arrayMemberCopy
->removeObject(i
);
3752 features
->setObject(dictKey
, arrayMemberCopy
);
3753 arrayMemberCopy
->release();
3764 dictIterator
->release();
3768 ret
= kIOReturnSuccess
;
3770 setProperty(kRootDomainSupportedFeatures
, features
);
3772 // Notify EnergySaver and all those in user space so they might
3773 // re-populate their feature specific UI
3774 if(pmPowerStateQueue
) {
3775 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3778 ret
= kIOReturnNotFound
;
3782 if(features
) features
->release();
3783 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3787 //******************************************************************************
3788 // publishPMSetting (private)
3790 // Should only be called by PMSettingObject to publish a PM Setting as a
3791 // supported feature.
3792 //******************************************************************************
3794 void IOPMrootDomain::publishPMSetting(
3795 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3797 if (noPublishPMSettings
&&
3798 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3800 // Setting found in noPublishPMSettings array
3801 *featureID
= kBadPMFeatureID
;
3806 feature
->getCStringNoCopy(), where
, featureID
);
3809 //******************************************************************************
3810 // setPMSetting (private)
3812 // Internal helper to relay PM settings changes from user space to individual
3813 // drivers. Should be called only by IOPMrootDomain::setProperties.
3814 //******************************************************************************
3816 IOReturn
IOPMrootDomain::setPMSetting(
3817 const OSSymbol
*type
,
3820 PMSettingCallEntry
*entries
= 0;
3821 OSArray
*chosen
= 0;
3822 const OSArray
*array
;
3823 PMSettingObject
*pmso
;
3824 thread_t thisThread
;
3825 int i
, j
, count
, capacity
;
3828 return kIOReturnBadArgument
;
3832 // Update settings dict so changes are visible from copyPMSetting().
3833 fPMSettingsDict
->setObject(type
, object
);
3835 // Prep all PMSetting objects with the given 'type' for callout.
3836 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3837 if (!array
|| ((capacity
= array
->getCount()) == 0))
3840 // Array to retain PMSetting objects targeted for callout.
3841 chosen
= OSArray::withCapacity(capacity
);
3843 goto unlock_exit
; // error
3845 entries
= IONew(PMSettingCallEntry
, capacity
);
3847 goto unlock_exit
; // error
3848 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3850 thisThread
= current_thread();
3852 for (i
= 0, j
= 0; i
<capacity
; i
++)
3854 pmso
= (PMSettingObject
*) array
->getObject(i
);
3857 entries
[j
].thread
= thisThread
;
3858 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3859 chosen
->setObject(pmso
);
3868 // Call each pmso in the chosen array.
3869 for (i
=0; i
<count
; i
++)
3871 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3872 pmso
->dispatchPMSetting(type
, object
);
3876 for (i
=0; i
<count
; i
++)
3878 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3879 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3880 if (pmso
->waitThread
)
3882 PMSETTING_WAKEUP(pmso
);
3888 if (chosen
) chosen
->release();
3889 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3891 return kIOReturnSuccess
;
3894 //******************************************************************************
3895 // copyPMSetting (public)
3897 // Allows kexts to safely read setting values, without being subscribed to
3899 //******************************************************************************
3901 OSObject
* IOPMrootDomain::copyPMSetting(
3902 OSSymbol
*whichSetting
)
3904 OSObject
*obj
= NULL
;
3906 if(!whichSetting
) return NULL
;
3909 obj
= fPMSettingsDict
->getObject(whichSetting
);
3918 //******************************************************************************
3919 // registerPMSettingController (public)
3921 // direct wrapper to registerPMSettingController with uint32_t power source arg
3922 //******************************************************************************
3924 IOReturn
IOPMrootDomain::registerPMSettingController(
3925 const OSSymbol
* settings
[],
3926 IOPMSettingControllerCallback func
,
3931 return registerPMSettingController(
3933 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3934 func
, target
, refcon
, handle
);
3937 //******************************************************************************
3938 // registerPMSettingController (public)
3940 // Kexts may register for notifications when a particular setting is changed.
3941 // A list of settings is available in IOPM.h.
3943 // * settings - An OSArray containing OSSymbols. Caller should populate this
3944 // array with a list of settings caller wants notifications from.
3945 // * func - A C function callback of the type IOPMSettingControllerCallback
3946 // * target - caller may provide an OSObject *, which PM will pass as an
3947 // target to calls to "func"
3948 // * refcon - caller may provide an void *, which PM will pass as an
3949 // argument to calls to "func"
3950 // * handle - This is a return argument. We will populate this pointer upon
3951 // call success. Hold onto this and pass this argument to
3952 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3954 // kIOReturnSuccess on success
3955 //******************************************************************************
3957 IOReturn
IOPMrootDomain::registerPMSettingController(
3958 const OSSymbol
* settings
[],
3959 uint32_t supportedPowerSources
,
3960 IOPMSettingControllerCallback func
,
3965 PMSettingObject
*pmso
= NULL
;
3966 OSObject
*pmsh
= NULL
;
3967 OSArray
*list
= NULL
;
3970 if (NULL
== settings
||
3974 return kIOReturnBadArgument
;
3977 pmso
= PMSettingObject::pmSettingObject(
3978 (IOPMrootDomain
*) this, func
, target
,
3979 refcon
, supportedPowerSources
, settings
, &pmsh
);
3983 return kIOReturnInternalError
;
3987 for (i
=0; settings
[i
]; i
++)
3989 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3991 // New array of callbacks for this setting
3992 list
= OSArray::withCapacity(1);
3993 settingsCallbacks
->setObject(settings
[i
], list
);
3997 // Add caller to the callback list
3998 list
->setObject(pmso
);
4002 // Return handle to the caller, the setting object is private.
4005 return kIOReturnSuccess
;
4008 //******************************************************************************
4009 // deregisterPMSettingObject (private)
4011 // Only called from PMSettingObject.
4012 //******************************************************************************
4014 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
4016 thread_t thisThread
= current_thread();
4017 PMSettingCallEntry
*callEntry
;
4018 OSCollectionIterator
*iter
;
4026 pmso
->disabled
= true;
4028 // Wait for all callout threads to finish.
4031 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
4033 if (callEntry
->thread
!= thisThread
)
4041 assert(0 == pmso
->waitThread
);
4042 pmso
->waitThread
= thisThread
;
4043 PMSETTING_WAIT(pmso
);
4044 pmso
->waitThread
= 0;
4048 // Search each PM settings array in the kernel.
4049 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
4052 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
4054 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
4055 index
= array
->getNextIndexOfObject(pmso
, 0);
4057 array
->removeObject(index
);
4068 //******************************************************************************
4069 // informCPUStateChange
4071 // Call into PM CPU code so that CPU power savings may dynamically adjust for
4072 // running on battery, with the lid closed, etc.
4074 // informCPUStateChange is a no-op on non x86 systems
4075 // only x86 has explicit support in the IntelCPUPowerManagement kext
4076 //******************************************************************************
4078 void IOPMrootDomain::informCPUStateChange(
4082 #if defined(__i386__) || defined(__x86_64__)
4084 pmioctlVariableInfo_t varInfoStruct
;
4086 const char *varNameStr
= NULL
;
4087 int32_t *varIndex
= NULL
;
4089 if (kInformAC
== type
) {
4090 varNameStr
= kIOPMRootDomainBatPowerCString
;
4091 varIndex
= &idxPMCPULimitedPower
;
4092 } else if (kInformLid
== type
) {
4093 varNameStr
= kIOPMRootDomainLidCloseCString
;
4094 varIndex
= &idxPMCPUClamshell
;
4099 // Set the new value!
4100 // pmCPUControl will assign us a new ID if one doesn't exist yet
4101 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4102 varInfoStruct
.varID
= *varIndex
;
4103 varInfoStruct
.varType
= vBool
;
4104 varInfoStruct
.varInitValue
= value
;
4105 varInfoStruct
.varCurValue
= value
;
4106 strlcpy( (char *)varInfoStruct
.varName
,
4107 (const char *)varNameStr
,
4108 sizeof(varInfoStruct
.varName
));
4111 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4113 // pmCPU only assigns numerical id's when a new varName is specified
4115 && (*varIndex
== kCPUUnknownIndex
))
4117 // pmCPUControl has assigned us a new variable ID.
4118 // Let's re-read the structure we just SET to learn that ID.
4119 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4123 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4124 *varIndex
= varInfoStruct
.varID
;
4130 #endif /* __i386__ || __x86_64__ */
4134 // MARK: Deep Sleep Policy
4138 //******************************************************************************
4139 // evaluateSystemSleepPolicy
4140 //******************************************************************************
4142 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4146 kIOPMSleepFlagHibernate
= 0x00000001,
4147 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
4150 struct IOPMSystemSleepPolicyEntry
4152 uint32_t factorMask
;
4153 uint32_t factorBits
;
4154 uint32_t sleepFlags
;
4155 uint32_t wakeEvents
;
4156 } __attribute__((packed
));
4158 struct IOPMSystemSleepPolicyTable
4162 uint16_t entryCount
;
4163 IOPMSystemSleepPolicyEntry entries
[];
4164 } __attribute__((packed
));
4167 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
4168 kIOPMSleepAttributeHibernateSleep
= 0x00000002
4172 getSleepTypeAttributes( uint32_t sleepType
)
4174 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
4179 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
4180 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4181 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4182 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4186 if (sleepType
>= kIOPMSleepTypeLast
)
4189 return sleepTypeAttributes
[sleepType
];
4192 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4193 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4195 const IOPMSystemSleepPolicyTable
* pt
;
4196 OSObject
* prop
= 0;
4197 OSData
* policyData
;
4198 uint64_t currentFactors
= 0;
4199 uint32_t standbyDelay
= 0;
4200 uint32_t powerOffDelay
= 0;
4201 uint32_t powerOffTimer
= 0;
4202 uint32_t standbyTimer
= 0;
4204 bool standbyEnabled
;
4205 bool powerOffEnabled
;
4208 // Get platform's sleep policy table
4209 if (!gSleepPolicyHandler
)
4211 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4212 if (!prop
) goto done
;
4215 // Fetch additional settings
4216 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4217 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4218 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4219 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4220 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4221 powerOffTimer
= powerOffDelay
;
4222 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
))
4223 standbyTimer
= standbyDelay
;
4225 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4226 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
4227 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4229 // pmset level overrides
4230 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4232 if (!gSleepPolicyHandler
)
4234 standbyEnabled
= false;
4235 powerOffEnabled
= false;
4238 else if (!(*hibMode
& kIOHibernateModeSleep
))
4240 // Force hibernate (i.e. mode 25)
4241 // If standby is enabled, force standy.
4242 // If poweroff is enabled, force poweroff.
4244 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4245 else if (powerOffEnabled
)
4246 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4248 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4251 // Current factors based on environment and assertions
4252 if (sleepTimerMaintenance
)
4253 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4254 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4255 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4256 if (!clamshellClosed
)
4257 currentFactors
|= kIOPMSleepFactorLidOpen
;
4258 if (acAdaptorConnected
)
4259 currentFactors
|= kIOPMSleepFactorACPower
;
4260 if (lowBatteryCondition
)
4261 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4262 if (!standbyDelay
|| !standbyTimer
)
4263 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4264 if (standbyNixed
|| !standbyEnabled
)
4265 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4268 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4269 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4271 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4272 kIOPMDriverAssertionLevelOff
)
4273 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4274 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4275 kIOPMDriverAssertionLevelOff
)
4276 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4277 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4278 kIOPMDriverAssertionLevelOff
)
4279 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4280 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4281 kIOPMDriverAssertionLevelOff
)
4282 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4283 if (_scheduledAlarms
!= 0)
4284 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4285 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4286 kIOPMDriverAssertionLevelOff
)
4287 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4288 #define TCPKEEPALIVE 1
4290 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4291 kIOPMDriverAssertionLevelOff
)
4292 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4294 if (!powerOffEnabled
)
4295 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4297 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4299 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4300 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4301 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4302 if (thermalWarningState
)
4303 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4305 DLOG("sleep factors 0x%llx\n", currentFactors
);
4307 if (gSleepPolicyHandler
)
4309 uint32_t savedHibernateMode
;
4312 if (!gSleepPolicyVars
)
4314 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4315 if (!gSleepPolicyVars
)
4317 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4319 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4320 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4321 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4322 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4323 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4324 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4325 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4326 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4327 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
4328 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4329 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4330 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4332 if (kIOPMSleepPhase0
== sleepPhase
)
4334 // preserve hibernateMode
4335 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4336 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4338 else if (kIOPMSleepPhase1
== sleepPhase
)
4340 // use original hibernateMode for phase2
4341 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4344 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4346 if (kIOPMSleepPhase0
== sleepPhase
)
4348 // restore hibernateMode
4349 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4352 if ((result
!= kIOReturnSuccess
) ||
4353 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4354 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4355 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4357 MSG("sleep policy handler error\n");
4361 if ((getSleepTypeAttributes(params
->sleepType
) &
4362 kIOPMSleepAttributeHibernateSetup
) &&
4363 ((*hibMode
& kIOHibernateModeOn
) == 0))
4365 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4368 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4369 params
->version
, params
->sleepType
, params
->sleepFlags
,
4370 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4375 // Policy table is meaningless without standby enabled
4376 if (!standbyEnabled
)
4379 // Validate the sleep policy table
4380 policyData
= OSDynamicCast(OSData
, prop
);
4381 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4384 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4385 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4386 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4389 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4390 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4393 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4395 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4396 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4398 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4399 entry
->factorMask
, entry
->factorBits
,
4400 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4404 DLOG("^ found match\n");
4407 params
->version
= kIOPMSystemSleepParametersVersion
;
4408 params
->reserved1
= 1;
4409 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4410 params
->sleepType
= kIOPMSleepTypeStandby
;
4412 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4414 params
->ecWakeEvents
= entry
->wakeEvents
;
4415 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4417 if (kIOPMSleepPhase2
== sleepPhase
)
4419 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4421 if (!_standbyTimerResetSeconds
||
4422 (now_secs
<= _standbyTimerResetSeconds
))
4424 // Reset standby timer adjustment
4425 _standbyTimerResetSeconds
= now_secs
;
4426 DLOG("standby delay %u, reset %u\n",
4427 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4429 else if (standbyDelay
)
4431 // Shorten the standby delay timer
4432 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4433 if (standbyDelay
> elapsed
)
4434 standbyDelay
-= elapsed
;
4436 standbyDelay
= 1; // must be > 0
4438 DLOG("standby delay %u, elapsed %u\n",
4439 standbyDelay
, (uint32_t) elapsed
);
4442 params
->ecWakeTimer
= standbyDelay
;
4444 else if (kIOPMSleepPhase2
== sleepPhase
)
4446 // A sleep that does not enable the sleep timer will reset
4447 // the standby delay adjustment.
4448 _standbyTimerResetSeconds
= 0;
4460 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4462 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4464 // Evaluate early (priority interest phase), before drivers sleep.
4466 DLOG("%s\n", __FUNCTION__
);
4467 removeProperty(kIOPMSystemSleepParametersKey
);
4469 // Full wake resets the standby timer delay adjustment
4470 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4471 _standbyTimerResetSeconds
= 0;
4473 hibernateDisabled
= false;
4475 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4477 // Save for late evaluation if sleep is aborted
4478 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4480 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4483 if (!hibernateRetry
&&
4484 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4485 kIOPMSleepAttributeHibernateSetup
) == 0))
4487 // skip hibernate setup
4488 hibernateDisabled
= true;
4492 // Publish IOPMSystemSleepType
4493 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4494 if (sleepType
== kIOPMSleepTypeInvalid
)
4497 sleepType
= kIOPMSleepTypeNormalSleep
;
4498 if (hibernateMode
& kIOHibernateModeOn
)
4499 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4500 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4502 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4503 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4505 // report the lowest possible sleep state
4506 sleepType
= kIOPMSleepTypePowerOff
;
4509 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4512 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4514 IOPMSystemSleepParameters params
;
4515 OSData
* paramsData
;
4517 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4519 DLOG("%s\n", __FUNCTION__
);
4521 bzero(¶ms
, sizeof(params
));
4523 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4525 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4526 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
4527 && (!(kIOPMSleepFactorStandbyForced
& gSleepPolicyVars
->sleepFactors
)))
4529 standbyNixed
= true;
4533 || ((hibernateDisabled
|| hibernateAborted
) &&
4534 (getSleepTypeAttributes(params
.sleepType
) &
4535 kIOPMSleepAttributeHibernateSetup
)))
4537 // Final evaluation picked a state requiring hibernation,
4538 // but hibernate isn't going to proceed. Arm a short sleep using
4539 // the early non-hibernate sleep parameters.
4540 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4541 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4542 params
.ecWakeTimer
= 1;
4549 // Set hibernateRetry flag to force hibernate setup on the
4551 hibernateRetry
= true;
4553 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4554 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4558 hibernateRetry
= false;
4561 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4563 resetTimers
= false;
4566 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4569 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4570 paramsData
->release();
4573 if (getSleepTypeAttributes(params
.sleepType
) &
4574 kIOPMSleepAttributeHibernateSleep
)
4576 // Disable sleep to force hibernation
4577 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4582 bool IOPMrootDomain::getHibernateSettings(
4583 uint32_t * hibernateModePtr
,
4584 uint32_t * hibernateFreeRatio
,
4585 uint32_t * hibernateFreeTime
)
4587 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4588 // has updated the hibernateDisabled flag.
4590 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4591 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4592 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4593 if (hibernateDisabled
)
4594 *hibernateModePtr
= 0;
4595 else if (gSleepPolicyHandler
)
4596 *hibernateModePtr
= hibernateMode
;
4597 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4601 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4603 OSObject
* optionsProp
;
4604 OSDictionary
* optionsDict
;
4609 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4610 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4614 obj
= optionsDict
->getObject(key
);
4615 if (obj
) obj
->retain();
4619 obj
= copyProperty(key
);
4623 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4625 *option
= num
->unsigned32BitValue();
4628 else if (OSDynamicCast(OSBoolean
, obj
))
4630 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4638 optionsProp
->release();
4642 #endif /* HIBERNATION */
4644 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
4647 IOPMSystemSleepParameters params
;
4648 uint32_t hibMode
= 0;
4651 if (gIOPMWorkLoop
->inGate() == false)
4653 IOReturn ret
= gIOPMWorkLoop
->runAction(
4654 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4655 &IOPMrootDomain::getSystemSleepType
),
4657 (void *) sleepType
, (void *) standbyTimer
);
4661 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4662 bzero(¶ms
, sizeof(params
));
4664 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4667 *sleepType
= params
.sleepType
;
4668 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
4669 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
4670 DLOG("Standby delay is not set\n");
4673 return kIOReturnSuccess
;
4677 return kIOReturnUnsupported
;
4681 // MARK: Shutdown and Restart
4683 //******************************************************************************
4684 // handlePlatformHaltRestart
4686 //******************************************************************************
4688 // Phases while performing shutdown/restart
4691 kNotifyPriorityClients
= 0x10,
4692 kNotifyPowerPlaneDrivers
= 0x20,
4693 kNotifyHaltRestartAction
= 0x30,
4698 struct HaltRestartApplierContext
{
4699 IOPMrootDomain
* RootDomain
;
4700 unsigned long PowerState
;
4701 IOPMPowerFlags PowerFlags
;
4704 const char * LogString
;
4705 shutdownPhase_t phase
;
4707 IOServiceInterestHandler handler
;
4710 const char *shutdownPhase2String(shutdownPhase_t phase
)
4714 return "Notifications completed";
4715 case kNotifyPriorityClients
:
4716 return "Notifying priority clients";
4717 case kNotifyPowerPlaneDrivers
:
4718 return "Notifying power plane drivers";
4719 case kNotifyHaltRestartAction
:
4720 return "Notifying HaltRestart action handlers";
4722 return "Quiescing PM";
4730 platformHaltRestartApplier( OSObject
* object
, void * context
)
4732 IOPowerStateChangeNotification notify
;
4733 HaltRestartApplierContext
* ctx
;
4734 AbsoluteTime startTime
, elapsedTime
;
4737 ctx
= (HaltRestartApplierContext
*) context
;
4739 _IOServiceInterestNotifier
* notifier
;
4740 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4741 memset(¬ify
, 0, sizeof(notify
));
4742 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4743 notify
.returnValue
= 0;
4744 notify
.stateNumber
= ctx
->PowerState
;
4745 notify
.stateFlags
= ctx
->PowerFlags
;
4748 ctx
->handler
= notifier
->handler
;
4751 clock_get_uptime(&startTime
);
4752 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4753 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4755 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
4757 LOG("%s handler %p took %u ms\n",
4758 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4759 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
4766 static void quiescePowerTreeCallback( void * target
, void * param
)
4768 IOLockLock(gPMHaltLock
);
4770 thread_wakeup(param
);
4771 IOLockUnlock(gPMHaltLock
);
4774 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4776 AbsoluteTime startTime
, elapsedTime
;
4779 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
4780 gHaltRestartCtx
.RootDomain
= this;
4782 clock_get_uptime(&startTime
);
4786 case kPEUPSDelayHaltCPU
:
4787 gHaltRestartCtx
.PowerState
= OFF_STATE
;
4788 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
4789 gHaltRestartCtx
.LogString
= "PowerOff";
4793 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
4794 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
4795 gHaltRestartCtx
.LogString
= "Restart";
4799 gHaltRestartCtx
.PowerState
= ON_STATE
;
4800 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
4801 gHaltRestartCtx
.LogString
= "PagingOff";
4802 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4804 IOHibernateSystemRestart();
4812 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
4813 // Notify legacy clients
4814 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
4816 // For normal shutdown, turn off File Server Mode.
4817 if (kPEHaltCPU
== pe_type
)
4819 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4820 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4823 setPMSetting(setting
, num
);
4830 if (kPEPagingOff
!= pe_type
)
4832 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
4833 // Notify in power tree order
4834 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
4837 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
4838 IOCPURunPlatformHaltRestartActions(pe_type
);
4840 // Wait for PM to quiesce
4841 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4843 gHaltRestartCtx
.phase
= kQuiescePM
;
4844 AbsoluteTime quiesceTime
= mach_absolute_time();
4846 IOLockLock(gPMHaltLock
);
4847 gPMQuiesced
= false;
4848 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4851 while (!gPMQuiesced
)
4853 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4856 IOLockUnlock(gPMHaltLock
);
4857 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
4858 DLOG("PM quiesce took %u ms\n", deltaTime
);
4859 halt_log_enter("Quiesce", NULL
, elapsedTime
);
4861 gHaltRestartCtx
.phase
= kNotifyDone
;
4863 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4864 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4866 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
4868 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4869 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4871 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
))
4873 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
4876 checkShutdownTimeout();
4879 bool IOPMrootDomain::checkShutdownTimeout()
4881 AbsoluteTime elapsedTime
;
4882 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4884 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
4890 void IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
4893 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
4894 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
4896 panic("%s timed out in phase '%s'. Total %d ms:%s",
4897 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
4900 panic("%s timed out in phase \'%s\'. Total %d ms",
4901 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
4905 //******************************************************************************
4908 //******************************************************************************
4910 IOReturn
IOPMrootDomain::shutdownSystem( void )
4912 return kIOReturnUnsupported
;
4915 //******************************************************************************
4918 //******************************************************************************
4920 IOReturn
IOPMrootDomain::restartSystem( void )
4922 return kIOReturnUnsupported
;
4926 // MARK: System Capability
4928 SYSCTL_UINT(_kern
, OID_AUTO
, pcihostbridge_wake_delay
, CTLFLAG_RD
| CTLFLAG_KERN
| CTLFLAG_LOCKED
, (uint32_t *)&gIOPMPCIHostBridgeWakeDelay
, 0, "");
4930 //******************************************************************************
4931 // tagPowerPlaneService
4933 // Running on PM work loop thread.
4934 //******************************************************************************
4936 void IOPMrootDomain::tagPowerPlaneService(
4937 IOService
* service
,
4938 IOPMActions
* actions
)
4941 bool isDisplayWrangler
;
4943 memset(actions
, 0, sizeof(*actions
));
4944 actions
->target
= this;
4946 if (service
== this)
4948 actions
->actionPowerChangeStart
=
4949 OSMemberFunctionCast(
4950 IOPMActionPowerChangeStart
, this,
4951 &IOPMrootDomain::handleOurPowerChangeStart
);
4953 actions
->actionPowerChangeDone
=
4954 OSMemberFunctionCast(
4955 IOPMActionPowerChangeDone
, this,
4956 &IOPMrootDomain::handleOurPowerChangeDone
);
4958 actions
->actionPowerChangeOverride
=
4959 OSMemberFunctionCast(
4960 IOPMActionPowerChangeOverride
, this,
4961 &IOPMrootDomain::overrideOurPowerChange
);
4966 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4967 if (isDisplayWrangler
)
4970 // found the display wrangler, check for any display assertions already created
4971 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
4972 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
4973 wrangler
->setIgnoreIdleTimer( true );
4977 isDisplayWrangler
= false;
4980 #if defined(__i386__) || defined(__x86_64__)
4981 if (isDisplayWrangler
)
4982 flags
|= kPMActionsFlagIsDisplayWrangler
;
4983 if (service
->getProperty("IOPMStrictTreeOrder"))
4984 flags
|= kPMActionsFlagIsGraphicsDevice
;
4985 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4986 flags
|= kPMActionsFlagIsAudioDevice
;
4989 // Find the power connection object that is a child of the PCI host
4990 // bridge, and has a graphics/audio device attached below. Mark the
4991 // power branch for delayed child notifications.
4995 IORegistryEntry
* child
= service
;
4996 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4998 while (child
!= this)
5000 if ((gIOPMPCIHostBridgeWakeDelay
? (parent
== pciHostBridgeDriver
) : (parent
->metaCast("IOPCIDevice") != NULL
)) ||
5003 if (OSDynamicCast(IOPowerConnection
, child
))
5005 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
5006 conn
->delayChildNotification
= true;
5007 DLOG("delayChildNotification for 0x%llx\n", conn
->getRegistryEntryID());
5012 parent
= child
->getParentEntry(gIOPowerPlane
);
5018 DLOG("%s tag flags %x\n", service
->getName(), flags
);
5019 actions
->parameter
|= flags
;
5020 actions
->actionPowerChangeOverride
=
5021 OSMemberFunctionCast(
5022 IOPMActionPowerChangeOverride
, this,
5023 &IOPMrootDomain::overridePowerChangeForUIService
);
5025 if (flags
& kPMActionsFlagIsDisplayWrangler
)
5027 actions
->actionActivityTickle
=
5028 OSMemberFunctionCast(
5029 IOPMActionActivityTickle
, this,
5030 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
5032 actions
->actionUpdatePowerClient
=
5033 OSMemberFunctionCast(
5034 IOPMActionUpdatePowerClient
, this,
5035 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
5040 // Locate the first PCI host bridge for PMTrace.
5041 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
5043 IOService
* provider
= service
->getProvider();
5044 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
5045 provider
->inPlane(gIODTPlane
))
5047 pciHostBridgeDevice
= provider
;
5048 pciHostBridgeDriver
= service
;
5049 DLOG("PMTrace found PCI host bridge %s->%s\n",
5050 provider
->getName(), service
->getName());
5054 // Tag top-level PCI devices. The order of PMinit() call does not
5055 // change across boots and is used as the PCI bit number.
5056 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
5058 // Would prefer to check built-in property, but tagPowerPlaneService()
5059 // is called before pciDevice->registerService().
5060 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
5061 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
5063 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
5066 // Save the assigned bit for fast lookup.
5067 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
5069 actions
->actionPowerChangeStart
=
5070 OSMemberFunctionCast(
5071 IOPMActionPowerChangeStart
, this,
5072 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
5074 actions
->actionPowerChangeDone
=
5075 OSMemberFunctionCast(
5076 IOPMActionPowerChangeDone
, this,
5077 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
5083 //******************************************************************************
5084 // PM actions for root domain
5085 //******************************************************************************
5087 void IOPMrootDomain::overrideOurPowerChange(
5088 IOService
* service
,
5089 IOPMActions
* actions
,
5090 IOPMPowerStateIndex
* inOutPowerState
,
5091 IOPMPowerChangeFlags
* inOutChangeFlags
,
5092 IOPMRequestTag requestTag
)
5094 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5095 uint32_t changeFlags
= *inOutChangeFlags
;
5096 uint32_t currentPowerState
= (uint32_t) getPowerState();
5098 if (changeFlags
& kIOPMParentInitiated
)
5100 // Root parent is permanently pegged at max power,
5101 // a parent initiated power change is unexpected.
5102 *inOutChangeFlags
|= kIOPMNotDone
;
5106 if (powerState
< currentPowerState
)
5108 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5110 // Root domain is dropping power state ON->SLEEP.
5111 // If system is in full wake, first enter dark wake by
5112 // converting the power drop to a capability change.
5113 // Once in dark wake, transition to sleep state ASAP.
5115 darkWakeToSleepASAP
= true;
5117 // Drop graphics and audio capability
5118 _desiredCapability
&= ~(
5119 kIOPMSystemCapabilityGraphics
|
5120 kIOPMSystemCapabilityAudio
);
5122 // Convert to capability change (ON->ON)
5123 *inOutPowerState
= ON_STATE
;
5124 *inOutChangeFlags
|= kIOPMSynchronize
;
5126 // Revert device desire from SLEEP to ON
5127 changePowerStateToPriv(ON_STATE
);
5131 // System is in dark wake, ok to drop power state.
5132 // Broadcast root powering down to entire tree.
5133 *inOutChangeFlags
|= kIOPMRootChangeDown
;
5136 else if (powerState
> currentPowerState
)
5138 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
5140 // Broadcast power up when waking from sleep, but not for the
5141 // initial power change at boot by checking for cpu capability.
5142 *inOutChangeFlags
|= kIOPMRootChangeUp
;
5147 void IOPMrootDomain::handleOurPowerChangeStart(
5148 IOService
* service
,
5149 IOPMActions
* actions
,
5150 IOPMPowerStateIndex powerState
,
5151 IOPMPowerChangeFlags
* inOutChangeFlags
,
5152 IOPMRequestTag requestTag
)
5154 uint32_t changeFlags
= *inOutChangeFlags
;
5155 uint32_t currentPowerState
= (uint32_t) getPowerState();
5156 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
5157 bool publishSleepReason
= false;
5159 _systemTransitionType
= kSystemTransitionNone
;
5160 _systemMessageClientMask
= 0;
5161 capabilityLoss
= false;
5162 toldPowerdCapWillChange
= false;
5164 if (lowBatteryCondition
)
5166 // Low battery notification may arrive after the initial sleep request
5167 // has been queued. Override the sleep reason so powerd and others can
5168 // treat this as an emergency sleep.
5169 sleepReason
= kIOPMSleepReasonLowPower
;
5172 // 1. Explicit capability change.
5174 if (changeFlags
& kIOPMSynchronize
)
5176 if (powerState
== ON_STATE
)
5178 if (changeFlags
& kIOPMSyncNoChildNotify
)
5179 _systemTransitionType
= kSystemTransitionNewCapClient
;
5181 _systemTransitionType
= kSystemTransitionCapability
;
5185 // 2. Going to sleep (cancellation still possible).
5187 else if (powerState
< currentPowerState
)
5188 _systemTransitionType
= kSystemTransitionSleep
;
5190 // 3. Woke from (idle or demand) sleep.
5192 else if (!systemBooting
&&
5193 (changeFlags
& kIOPMSelfInitiated
) &&
5194 (powerState
> currentPowerState
))
5196 _systemTransitionType
= kSystemTransitionWake
;
5197 _desiredCapability
= kIOPMSystemCapabilityCPU
|
5198 kIOPMSystemCapabilityNetwork
;
5200 // Early exit from dark wake to full (e.g. LID open)
5201 if (kFullWakeReasonNone
!= fullWakeReason
)
5203 _desiredCapability
|= (
5204 kIOPMSystemCapabilityGraphics
|
5205 kIOPMSystemCapabilityAudio
);
5208 IOHibernateSetWakeCapabilities(_desiredCapability
);
5212 // Update pending wake capability at the beginning of every
5213 // state transition (including synchronize). This will become
5214 // the current capability at the end of the transition.
5216 if (kSystemTransitionSleep
== _systemTransitionType
)
5218 _pendingCapability
= 0;
5219 capabilityLoss
= true;
5222 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
5224 _pendingCapability
= _desiredCapability
|
5225 kIOPMSystemCapabilityCPU
|
5226 kIOPMSystemCapabilityNetwork
;
5228 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5229 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
5231 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
5232 (_pendingCapability
== _currentCapability
))
5234 // Cancel the PM state change.
5235 _systemTransitionType
= kSystemTransitionNone
;
5236 *inOutChangeFlags
|= kIOPMNotDone
;
5238 if (__builtin_popcount(_pendingCapability
) <
5239 __builtin_popcount(_currentCapability
))
5240 capabilityLoss
= true;
5243 // 1. Capability change.
5245 if (kSystemTransitionCapability
== _systemTransitionType
)
5247 // Dark to Full transition.
5248 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5250 tracePoint( kIOPMTracePointDarkWakeExit
);
5252 willEnterFullWake();
5255 // Full to Dark transition.
5256 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5258 // Clear previous stats
5259 IOLockLock(pmStatsLock
);
5260 if (pmStatsAppResponses
)
5262 pmStatsAppResponses
->release();
5263 pmStatsAppResponses
= OSArray::withCapacity(5);
5265 IOLockUnlock(pmStatsLock
);
5268 tracePoint( kIOPMTracePointDarkWakeEntry
);
5269 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
5270 _systemMessageClientMask
= kSystemMessageClientPowerd
|
5271 kSystemMessageClientLegacyApp
;
5275 // Prevent user active transitions before notifying clients
5276 // that system will sleep.
5277 preventTransitionToUserActive(true);
5279 IOService::setAdvisoryTickleEnable( false );
5281 // Publish the sleep reason for full to dark wake
5282 publishSleepReason
= true;
5283 lastSleepReason
= fullToDarkReason
= sleepReason
;
5285 // Publish a UUID for the Sleep --> Wake cycle
5286 handlePublishSleepWakeUUID(true);
5287 if (sleepDelaysReport
) {
5288 clock_get_uptime(&ts_sleepStart
);
5289 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5292 wranglerTickled
= false;
5298 else if (kSystemTransitionSleep
== _systemTransitionType
)
5300 // Beginning of a system sleep transition.
5301 // Cancellation is still possible.
5302 tracePoint( kIOPMTracePointSleepStarted
);
5304 _systemMessageClientMask
= kSystemMessageClientAll
;
5305 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5306 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5307 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5308 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5310 gIOHibernateState
= 0;
5313 // Record the reason for dark wake back to sleep
5314 // System may not have ever achieved full wake
5316 publishSleepReason
= true;
5317 lastSleepReason
= sleepReason
;
5318 if (sleepDelaysReport
) {
5319 clock_get_uptime(&ts_sleepStart
);
5320 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5326 else if (kSystemTransitionWake
== _systemTransitionType
)
5328 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5329 // Clear stats about sleep
5331 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5333 willEnterFullWake();
5337 // Message powerd only
5338 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5339 tellClients(kIOMessageSystemWillPowerOn
);
5343 // The only location where the sleep reason is published. At this point
5344 // sleep can still be cancelled, but sleep reason should be published
5345 // early for logging purposes.
5347 if (publishSleepReason
)
5349 static const char * IOPMSleepReasons
[] =
5351 kIOPMClamshellSleepKey
,
5352 kIOPMPowerButtonSleepKey
,
5353 kIOPMSoftwareSleepKey
,
5354 kIOPMOSSwitchHibernationKey
,
5356 kIOPMLowPowerSleepKey
,
5357 kIOPMThermalEmergencySleepKey
,
5358 kIOPMMaintenanceSleepKey
,
5359 kIOPMSleepServiceExitKey
,
5360 kIOPMDarkWakeThermalEmergencyKey
5363 // Record sleep cause in IORegistry
5364 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5365 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5366 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5367 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5371 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5372 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5374 _systemStateGeneration
++;
5375 systemDarkWake
= false;
5377 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5379 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5380 _systemTransitionType
, _systemStateGeneration
,
5381 _systemMessageClientMask
,
5382 _desiredCapability
, _currentCapability
, _pendingCapability
);
5386 void IOPMrootDomain::handleOurPowerChangeDone(
5387 IOService
* service
,
5388 IOPMActions
* actions
,
5389 IOPMPowerStateIndex powerState
,
5390 IOPMPowerChangeFlags changeFlags
,
5391 IOPMRequestTag requestTag __unused
)
5393 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5395 _systemTransitionType
= kSystemTransitionNone
;
5399 if (_systemTransitionType
!= kSystemTransitionNone
)
5401 uint32_t currentPowerState
= (uint32_t) getPowerState();
5403 if (changeFlags
& kIOPMNotDone
)
5405 // Power down was cancelled or vetoed.
5406 _pendingCapability
= _currentCapability
;
5407 lastSleepReason
= 0;
5409 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5410 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5412 #if !CONFIG_EMBEDDED
5413 pmPowerStateQueue
->submitPowerEvent(
5414 kPowerEventPolicyStimulus
,
5415 (void *) kStimulusDarkWakeReentry
,
5416 _systemStateGeneration
);
5418 // On embedded, there are no factors that can prolong a
5419 // "darkWake" when a power down is vetoed. We need to
5420 // promote to "fullWake" at least once so that factors
5421 // that prevent idle sleep can assert themselves if required
5422 pmPowerStateQueue
->submitPowerEvent(
5423 kPowerEventPolicyStimulus
,
5424 (void *) kStimulusDarkWakeActivityTickle
);
5428 // Revert device desire to max.
5429 changePowerStateToPriv(ON_STATE
);
5433 // Send message on dark wake to full wake promotion.
5434 // tellChangeUp() handles the normal SLEEP->ON case.
5436 if (kSystemTransitionCapability
== _systemTransitionType
)
5438 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5440 lastSleepReason
= 0; // stop logging wrangler tickles
5441 tellClients(kIOMessageSystemHasPoweredOn
);
5443 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5445 // Going dark, reset full wake state
5446 // userIsActive will be cleared by wrangler powering down
5447 fullWakeReason
= kFullWakeReasonNone
;
5449 if (ts_sleepStart
) {
5450 clock_get_uptime(&wake2DarkwakeDelay
);
5451 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5452 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5458 // Reset state after exiting from dark wake.
5460 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5461 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5463 darkWakeMaintenance
= false;
5464 darkWakeToSleepASAP
= false;
5465 pciCantSleepValid
= false;
5466 darkWakeSleepService
= false;
5468 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5470 // Remove the influence of display power assertion
5471 // before next system wake.
5472 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5473 kWranglerPowerStateMin
);
5474 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5478 // Entered dark mode.
5480 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5481 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5483 // Queue an evaluation of whether to remain in dark wake,
5484 // and for how long. This serves the purpose of draining
5485 // any assertions from the queue.
5487 pmPowerStateQueue
->submitPowerEvent(
5488 kPowerEventPolicyStimulus
,
5489 (void *) kStimulusDarkWakeEntry
,
5490 _systemStateGeneration
);
5494 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5495 "dcp %x:%x:%x, dbgtimer %u\n",
5496 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5497 _systemTransitionType
, _systemStateGeneration
,
5498 _systemMessageClientMask
,
5499 _desiredCapability
, _currentCapability
, _pendingCapability
,
5500 _lastDebugWakeSeconds
);
5502 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5505 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5506 if (clamshellExists
&& fullWakeThreadCall
&&
5507 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5509 // Not the initial graphics full power, graphics won't
5510 // send a power notification to trigger a lid state
5513 AbsoluteTime deadline
;
5514 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5515 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5519 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5522 // Update current system capability.
5523 if (_currentCapability
!= _pendingCapability
)
5524 _currentCapability
= _pendingCapability
;
5526 // Update highest system capability.
5528 _highestCapability
|= _currentCapability
;
5530 if (darkWakePostTickle
&&
5531 (kSystemTransitionWake
== _systemTransitionType
) &&
5532 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5533 kDarkWakeFlagHIDTickleLate
)
5535 darkWakePostTickle
= false;
5538 else if (wranglerTickled
) {
5539 requestFullWake( kFullWakeReasonLocalUser
);
5542 // Reset tracepoint at completion of capability change,
5543 // completion of wake transition, and aborted sleep transition.
5545 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5546 (_systemTransitionType
== kSystemTransitionWake
) ||
5547 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5548 (changeFlags
& kIOPMNotDone
)))
5550 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5551 tracePoint( kIOPMTracePointSystemUp
);
5554 _systemTransitionType
= kSystemTransitionNone
;
5555 _systemMessageClientMask
= 0;
5556 toldPowerdCapWillChange
= false;
5558 logGraphicsClamp
= false;
5560 if (lowBatteryCondition
) {
5561 privateSleepSystem (kIOPMSleepReasonLowPower
);
5563 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5564 // Request for full wake is removed while system is waking up to full wake
5565 DLOG("DisplayOn fullwake request is removed\n");
5566 handleDisplayPowerOn();
5572 //******************************************************************************
5573 // PM actions for graphics and audio.
5574 //******************************************************************************
5576 void IOPMrootDomain::overridePowerChangeForUIService(
5577 IOService
* service
,
5578 IOPMActions
* actions
,
5579 IOPMPowerStateIndex
* inOutPowerState
,
5580 IOPMPowerChangeFlags
* inOutChangeFlags
)
5582 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5583 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5585 if (kSystemTransitionNone
== _systemTransitionType
)
5587 // Not in midst of a system transition.
5588 // Do not modify power limit enable state.
5590 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5592 // Activate power limiter.
5594 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5595 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5596 (changeFlags
& kIOPMSynchronize
))
5598 actions
->parameter
|= kPMActionsFlagLimitPower
;
5600 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5601 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5602 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5603 (changeFlags
& kIOPMSynchronize
))
5605 actions
->parameter
|= kPMActionsFlagLimitPower
;
5607 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5608 (_systemTransitionType
== kSystemTransitionSleep
))
5610 // For graphics devices, arm the limiter when entering
5611 // system sleep. Not when dropping to dark wake.
5612 actions
->parameter
|= kPMActionsFlagLimitPower
;
5615 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5617 DLOG("+ plimit %s %p\n",
5618 service
->getName(), OBFUSCATE(service
));
5623 // Remove power limit.
5625 if ((actions
->parameter
& (
5626 kPMActionsFlagIsDisplayWrangler
|
5627 kPMActionsFlagIsGraphicsDevice
)) &&
5628 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5630 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5632 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5633 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5635 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5638 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5640 DLOG("- plimit %s %p\n",
5641 service
->getName(), OBFUSCATE(service
));
5645 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5647 uint32_t maxPowerState
= (uint32_t)(-1);
5649 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5651 // Enforce limit for system power/cap transitions.
5654 if ((service
->getPowerState() > maxPowerState
) &&
5655 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5659 // Remove lingering effects of any tickle before entering
5660 // dark wake. It will take a new tickle to return to full
5661 // wake, so the existing tickle state is useless.
5663 if (changeFlags
& kIOPMDomainDidChange
)
5664 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5666 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5673 // Deny all self-initiated changes when power is limited.
5674 // Wrangler tickle should never defeat the limiter.
5676 maxPowerState
= service
->getPowerState();
5679 if (powerState
> maxPowerState
)
5681 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5682 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5684 *inOutPowerState
= maxPowerState
;
5686 if (darkWakePostTickle
&&
5687 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5688 (changeFlags
& kIOPMDomainWillChange
) &&
5689 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5690 kDarkWakeFlagHIDTickleEarly
))
5692 darkWakePostTickle
= false;
5697 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5699 if (logGraphicsClamp
)
5704 clock_get_uptime(&now
);
5705 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5706 absolutetime_to_nanoseconds(now
, &nsec
);
5707 if (kIOLogPMRootDomain
& gIOKitDebug
)
5708 MSG("Graphics suppressed %u ms\n",
5709 ((int)((nsec
) / NSEC_PER_MSEC
)));
5711 graphicsSuppressed
= true;
5716 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5717 IOService
* service
,
5718 IOPMActions
* actions
)
5721 // Warning: Not running in PM work loop context - don't modify state !!!
5722 // Trap tickle directed to IODisplayWrangler while running with graphics
5723 // capability suppressed.
5725 assert(service
== wrangler
);
5727 clock_get_uptime(&userActivityTime
);
5728 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5729 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5730 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5732 userActivityCount
++;
5733 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5734 userActivityCount
, lastSleepReason
);
5737 if (!wranglerTickled
&&
5738 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5740 DLOG("display wrangler tickled\n");
5741 if (kIOLogPMRootDomain
& gIOKitDebug
)
5742 OSReportWithBacktrace("Dark wake display tickle");
5743 if (pmPowerStateQueue
)
5745 pmPowerStateQueue
->submitPowerEvent(
5746 kPowerEventPolicyStimulus
,
5747 (void *) kStimulusDarkWakeActivityTickle
,
5748 true /* set wake type */ );
5754 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5755 IOService
* service
,
5756 IOPMActions
* actions
,
5757 const OSSymbol
* powerClient
,
5758 IOPMPowerStateIndex oldPowerState
,
5759 IOPMPowerStateIndex newPowerState
)
5762 assert(service
== wrangler
);
5764 // This function implements half of the user active detection
5765 // by monitoring changes to the display wrangler's device desire.
5767 // User becomes active when either:
5768 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5769 // in max power state. This desire change in absence of a power state
5770 // change is detected within. This handles the case when user becomes
5771 // active while the display is already lit by setDisplayPowerOn().
5773 // 2. Power state change to max, and DeviceDesire is also at max.
5774 // Handled by displayWranglerNotification().
5776 // User becomes inactive when DeviceDesire drops to sleep state or below.
5778 DLOG("wrangler %s (ps %u, %u->%u)\n",
5779 powerClient
->getCStringNoCopy(),
5780 (uint32_t) service
->getPowerState(),
5781 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5783 if (powerClient
== gIOPMPowerClientDevice
)
5785 if ((newPowerState
> oldPowerState
) &&
5786 (newPowerState
== kWranglerPowerStateMax
) &&
5787 (service
->getPowerState() == kWranglerPowerStateMax
))
5789 evaluatePolicy( kStimulusEnterUserActiveState
);
5792 if ((newPowerState
< oldPowerState
) &&
5793 (newPowerState
<= kWranglerPowerStateSleep
))
5795 evaluatePolicy( kStimulusLeaveUserActiveState
);
5799 if (newPowerState
<= kWranglerPowerStateSleep
) {
5800 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5802 else if (newPowerState
== kWranglerPowerStateMax
) {
5803 evaluatePolicy( kStimulusDisplayWranglerWake
);
5808 //******************************************************************************
5809 // User active state management
5810 //******************************************************************************
5812 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5815 _preventUserActive
= prevent
;
5816 if (wrangler
&& !_preventUserActive
)
5818 // Allowing transition to user active, but the wrangler may have
5819 // already powered ON in case of sleep cancel/revert. Poll the
5820 // same conditions checked for in displayWranglerNotification()
5821 // to bring the user active state up to date.
5823 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5824 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5825 kWranglerPowerStateMax
))
5827 evaluatePolicy( kStimulusEnterUserActiveState
);
5833 //******************************************************************************
5834 // Approve usage of delayed child notification by PM.
5835 //******************************************************************************
5837 bool IOPMrootDomain::shouldDelayChildNotification(
5838 IOService
* service
)
5840 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5841 (kFullWakeReasonNone
== fullWakeReason
) &&
5842 (kSystemTransitionWake
== _systemTransitionType
))
5844 DLOG("%s: delay child notify\n", service
->getName());
5850 //******************************************************************************
5851 // PM actions for PCI device.
5852 //******************************************************************************
5854 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5855 IOService
* service
,
5856 IOPMActions
* actions
,
5857 IOPMPowerStateIndex powerState
,
5858 IOPMPowerChangeFlags
* inOutChangeFlags
)
5860 pmTracer
->tracePCIPowerChange(
5861 PMTraceWorker::kPowerChangeStart
,
5862 service
, *inOutChangeFlags
,
5863 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5866 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5867 IOService
* service
,
5868 IOPMActions
* actions
,
5869 IOPMPowerStateIndex powerState
,
5870 IOPMPowerChangeFlags changeFlags
)
5872 pmTracer
->tracePCIPowerChange(
5873 PMTraceWorker::kPowerChangeCompleted
,
5874 service
, changeFlags
,
5875 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5878 //******************************************************************************
5881 // Override IOService::registerInterest() to intercept special clients.
5882 //******************************************************************************
5884 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5887 friend class IOPMrootDomain
;
5888 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5891 uint32_t ackTimeoutCnt
;
5892 uint32_t msgType
; // Message pending ack
5896 const OSSymbol
*identifier
;
5899 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5901 IONotifier
* IOPMrootDomain::registerInterest(
5902 const OSSymbol
* typeOfInterest
,
5903 IOServiceInterestHandler handler
,
5904 void * target
, void * ref
)
5906 IOPMServiceInterestNotifier
*notifier
= 0;
5907 bool isSystemCapabilityClient
;
5908 bool isKernelCapabilityClient
;
5909 IOReturn rc
= kIOReturnError
;;
5911 isSystemCapabilityClient
=
5913 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5915 isKernelCapabilityClient
=
5917 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5919 if (isSystemCapabilityClient
)
5920 typeOfInterest
= gIOAppPowerStateInterest
;
5922 notifier
= new IOPMServiceInterestNotifier
;
5923 if (!notifier
) return NULL
;
5925 if (notifier
->init()) {
5926 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
5928 if (rc
!= kIOReturnSuccess
) {
5929 notifier
->release();
5934 if (pmPowerStateQueue
)
5936 notifier
->ackTimeoutCnt
= 0;
5937 if (isSystemCapabilityClient
)
5940 if (pmPowerStateQueue
->submitPowerEvent(
5941 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5942 notifier
->release();
5945 if (isKernelCapabilityClient
)
5948 if (pmPowerStateQueue
->submitPowerEvent(
5949 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5950 notifier
->release();
5954 OSData
*data
= NULL
;
5955 uint8_t *uuid
= NULL
;
5956 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
5958 data
= kext
->copyUUID();
5960 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
5961 uuid
= (uint8_t *)(data
->getBytesNoCopy());
5963 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40)|
5964 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
5965 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
5966 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40)|
5967 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
5968 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
5970 notifier
->identifier
= kext
->getIdentifier();
5973 if (kext
) kext
->release();
5974 if (data
) data
->release();
5979 //******************************************************************************
5980 // systemMessageFilter
5982 //******************************************************************************
5984 bool IOPMrootDomain::systemMessageFilter(
5985 void * object
, void * arg1
, void * arg2
, void * arg3
)
5987 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5988 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5989 bool isCapClient
= false;
5991 IOPMServiceInterestNotifier
*notifier
;
5993 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5995 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5996 (!isCapMsg
|| !_joinedCapabilityClients
||
5997 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
6000 // Capability change message for app and kernel clients.
6004 if ((context
->notifyType
== kNotifyPriority
) ||
6005 (context
->notifyType
== kNotifyCapabilityChangePriority
))
6008 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
6009 (object
== (void *) systemCapabilityNotifier
))
6015 IOPMSystemCapabilityChangeParameters
* capArgs
=
6016 (IOPMSystemCapabilityChangeParameters
*) arg2
;
6018 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
6020 capArgs
->fromCapabilities
= 0;
6021 capArgs
->toCapabilities
= _currentCapability
;
6022 capArgs
->changeFlags
= 0;
6026 capArgs
->fromCapabilities
= _currentCapability
;
6027 capArgs
->toCapabilities
= _pendingCapability
;
6029 if (context
->isPreChange
)
6030 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
6032 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
6034 if ((object
== (void *) systemCapabilityNotifier
) &&
6035 context
->isPreChange
)
6037 toldPowerdCapWillChange
= true;
6041 // Capability change messages only go to the PM configd plugin.
6042 // Wait for response post-change if capabilitiy is increasing.
6043 // Wait for response pre-change if capability is decreasing.
6045 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
6046 ( (capabilityLoss
&& context
->isPreChange
) ||
6047 (!capabilityLoss
&& !context
->isPreChange
) ) )
6049 // app has not replied yet, wait for it
6050 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6058 // Capability client will always see kIOMessageCanSystemSleep,
6059 // even for demand sleep. It will also have a chance to veto
6060 // sleep one last time after all clients have responded to
6061 // kIOMessageSystemWillSleep
6063 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
6064 (kIOMessageSystemWillNotSleep
== context
->messageType
))
6066 if (object
== (OSObject
*) systemCapabilityNotifier
)
6072 // Not idle sleep, don't ask apps.
6073 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
6079 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
6081 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
6082 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
6083 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
6089 // Reject capability change messages for legacy clients.
6090 // Reject legacy system sleep messages for capability client.
6092 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
6097 // Filter system sleep messages.
6099 if ((context
->notifyType
== kNotifyApps
) &&
6100 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
6106 if (notifier
->ackTimeoutCnt
>= 3)
6107 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6109 *((OSObject
**) arg3
) = kOSBooleanTrue
;
6113 else if ((context
->notifyType
== kNotifyPriority
) &&
6114 (_systemMessageClientMask
& kSystemMessageClientKernel
))
6121 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
6123 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
6124 if (_joinedCapabilityClients
->getCount() == 0)
6126 DLOG("destroyed capability client set %p\n",
6127 OBFUSCATE(_joinedCapabilityClients
));
6128 _joinedCapabilityClients
->release();
6129 _joinedCapabilityClients
= 0;
6133 notifier
->msgType
= context
->messageType
;
6139 //******************************************************************************
6140 // setMaintenanceWakeCalendar
6142 //******************************************************************************
6144 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
6145 const IOPMCalendarStruct
* calendar
)
6151 return kIOReturnBadArgument
;
6153 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
6155 return kIOReturnNoMemory
;
6157 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
6158 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
6159 if (kIOReturnSuccess
== ret
)
6160 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
6162 if (kPMCalendarTypeSleepService
== calendar
->selector
)
6164 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
6165 if (kIOReturnSuccess
== ret
)
6166 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
6168 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
6175 // MARK: Display Wrangler
6177 //******************************************************************************
6178 // displayWranglerNotification
6180 // Handle the notification when the IODisplayWrangler changes power state.
6181 //******************************************************************************
6183 IOReturn
IOPMrootDomain::displayWranglerNotification(
6184 void * target
, void * refCon
,
6185 UInt32 messageType
, IOService
* service
,
6186 void * messageArgument
, vm_size_t argSize
)
6189 int displayPowerState
;
6190 IOPowerStateChangeNotification
* params
=
6191 (IOPowerStateChangeNotification
*) messageArgument
;
6193 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
6194 (messageType
!= kIOMessageDeviceHasPoweredOn
))
6195 return kIOReturnUnsupported
;
6199 return kIOReturnUnsupported
;
6201 displayPowerState
= params
->stateNumber
;
6202 DLOG("wrangler %s ps %d\n",
6203 getIOMessageString(messageType
), displayPowerState
);
6205 switch (messageType
) {
6206 case kIOMessageDeviceWillPowerOff
:
6207 // Display wrangler has dropped power due to display idle
6208 // or force system sleep.
6210 // 4 Display ON kWranglerPowerStateMax
6211 // 3 Display Dim kWranglerPowerStateDim
6212 // 2 Display Sleep kWranglerPowerStateSleep
6213 // 1 Not visible to user
6214 // 0 Not visible to user kWranglerPowerStateMin
6216 if (displayPowerState
<= kWranglerPowerStateSleep
)
6217 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
6220 case kIOMessageDeviceHasPoweredOn
:
6221 // Display wrangler has powered on due to user activity
6222 // or wake from sleep.
6224 if (kWranglerPowerStateMax
== displayPowerState
)
6226 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
6228 // See comment in handleUpdatePowerClientForDisplayWrangler
6229 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6230 kWranglerPowerStateMax
)
6232 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
6238 return kIOReturnUnsupported
;
6241 //******************************************************************************
6242 // displayWranglerMatchPublished
6244 // Receives a notification when the IODisplayWrangler is published.
6245 // When it's published we install a power state change handler.
6246 //******************************************************************************
6248 bool IOPMrootDomain::displayWranglerMatchPublished(
6251 IOService
* newService
,
6252 IONotifier
* notifier __unused
)
6255 // install a handler
6256 if( !newService
->registerInterest( gIOGeneralInterest
,
6257 &displayWranglerNotification
, target
, 0) )
6265 #if defined(__i386__) || defined(__x86_64__)
6267 bool IOPMrootDomain::IONVRAMMatchPublished(
6270 IOService
* newService
,
6271 IONotifier
* notifier
)
6273 unsigned int len
= 0;
6274 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
6275 OSNumber
*statusCode
= NULL
;
6277 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
6279 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
6280 if (statusCode
!= NULL
) {
6281 if (statusCode
->unsigned64BitValue() != 0) {
6282 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
6283 MSG("System was rebooted due to Sleep/Wake failure\n");
6286 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
6287 MSG("System was non-responsive and was rebooted by watchdog\n");
6291 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
6293 if (notifier
) notifier
->remove();
6298 bool IOPMrootDomain::IONVRAMMatchPublished(
6301 IOService
* newService
,
6302 IONotifier
* notifier __unused
)
6309 //******************************************************************************
6312 //******************************************************************************
6314 void IOPMrootDomain::reportUserInput( void )
6318 OSDictionary
* matching
;
6322 matching
= serviceMatching("IODisplayWrangler");
6323 iter
= getMatchingServices(matching
);
6324 if (matching
) matching
->release();
6327 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6333 wrangler
->activityTickle(0,0);
6337 //******************************************************************************
6338 // latchDisplayWranglerTickle
6339 //******************************************************************************
6341 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6346 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6347 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6348 !checkSystemCanSustainFullWake())
6350 // Currently in dark wake, and not transitioning to full wake.
6351 // Full wake is unsustainable, so latch the tickle to prevent
6352 // the display from lighting up momentarily.
6353 wranglerTickleLatched
= true;
6357 wranglerTickleLatched
= false;
6360 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6362 wranglerTickleLatched
= false;
6364 pmPowerStateQueue
->submitPowerEvent(
6365 kPowerEventPolicyStimulus
,
6366 (void *) kStimulusDarkWakeActivityTickle
);
6369 return wranglerTickleLatched
;
6375 //******************************************************************************
6376 // setDisplayPowerOn
6378 // For root domain user client
6379 //******************************************************************************
6381 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6383 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6384 (void *) 0, options
);
6390 //******************************************************************************
6393 // Notification on battery class IOPowerSource appearance
6394 //******************************************************************************
6396 bool IOPMrootDomain::batteryPublished(
6399 IOService
* resourceService
,
6400 IONotifier
* notifier __unused
)
6402 // rdar://2936060&4435589
6403 // All laptops have dimmable LCD displays
6404 // All laptops have batteries
6405 // So if this machine has a battery, publish the fact that the backlight
6406 // supports dimming.
6407 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6413 // MARK: System PM Policy
6415 //******************************************************************************
6416 // checkSystemSleepAllowed
6418 //******************************************************************************
6420 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6421 uint32_t sleepReason
)
6425 // Conditions that prevent idle and demand system sleep.
6428 if (userDisabledAllSleep
)
6430 err
= 1; // 1. user-space sleep kill switch
6434 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6436 err
= 2; // 2. restart or shutdown in progress
6443 // Conditions above pegs the system at full wake.
6444 // Conditions below prevent system sleep but does not prevent
6445 // dark wake, and must be called from gated context.
6448 err
= 3; // 3. config does not support sleep
6452 if (lowBatteryCondition
|| thermalWarningState
)
6454 break; // always sleep on low battery or when in thermal warning state
6457 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6459 break; // always sleep on dark wake thermal emergencies
6462 if (preventSystemSleepList
->getCount() != 0)
6464 err
= 4; // 4. child prevent system sleep clamp
6468 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6469 kIOPMDriverAssertionLevelOn
)
6471 err
= 5; // 5. CPU assertion
6475 if (pciCantSleepValid
)
6477 if (pciCantSleepFlag
)
6478 err
= 6; // 6. PCI card does not support PM (cached)
6481 else if (sleepSupportedPEFunction
&&
6482 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6485 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6486 ret
= getPlatform()->callPlatformFunction(
6487 sleepSupportedPEFunction
, false,
6488 NULL
, NULL
, NULL
, NULL
);
6489 pciCantSleepValid
= true;
6490 pciCantSleepFlag
= false;
6491 if ((platformSleepSupport
& kPCICantSleep
) ||
6492 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6494 err
= 6; // 6. PCI card does not support PM
6495 pciCantSleepFlag
= true;
6504 DLOG("System sleep prevented by %d\n", err
);
6510 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6512 return checkSystemSleepAllowed(0, 0);
6515 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6518 return checkSystemSleepAllowed(1, sleepReason
);
6521 //******************************************************************************
6522 // checkSystemCanSustainFullWake
6523 //******************************************************************************
6525 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6528 if (lowBatteryCondition
|| thermalWarningState
)
6530 // Low battery wake, or received a low battery notification
6531 // while system is awake. This condition will persist until
6532 // the following wake.
6536 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6538 // Graphics state is unknown and external display might not be probed.
6539 // Do not incorporate state that requires graphics to be in max power
6540 // such as desktopMode or clamshellDisabled.
6542 if (!acAdaptorConnected
)
6544 DLOG("full wake check: no AC\n");
6552 //******************************************************************************
6554 //******************************************************************************
6558 bool IOPMrootDomain::mustHibernate( void )
6560 return (lowBatteryCondition
|| thermalWarningState
);
6563 #endif /* HIBERNATION */
6565 //******************************************************************************
6568 // Conditions that affect our wake/sleep decision has changed.
6569 // If conditions dictate that the system must remain awake, clamp power
6570 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6571 // is TRUE, then remove the power clamp and allow the power state to drop
6573 //******************************************************************************
6575 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6577 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6578 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6582 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6584 changePowerStateToPriv(ON_STATE
);
6586 else if ( sleepASAP
)
6588 changePowerStateToPriv(SLEEP_STATE
);
6592 void IOPMrootDomain::handleDisplayPowerOn( )
6594 if (!wrangler
) return;
6595 if (displayPowerOnRequested
)
6597 if (!checkSystemCanSustainFullWake()) return;
6599 // Force wrangler to max power state. If system is in dark wake
6600 // this alone won't raise the wrangler's power state.
6602 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6604 // System in dark wake, always requesting full wake should
6605 // not have any bad side-effects, even if the request fails.
6607 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6609 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6610 requestFullWake( kFullWakeReasonDisplayOn
);
6615 // Relenquish desire to power up display.
6616 // Must first transition to state 1 since wrangler doesn't
6617 // power off the displays at state 0. At state 0 the root
6618 // domain is removed from the wrangler's power client list.
6620 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6621 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6627 //******************************************************************************
6628 // dispatchPowerEvent
6630 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6631 //******************************************************************************
6633 void IOPMrootDomain::dispatchPowerEvent(
6634 uint32_t event
, void * arg0
, uint64_t arg1
)
6640 case kPowerEventFeatureChanged
:
6641 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6642 messageClients(kIOPMMessageFeatureChange
, this);
6645 case kPowerEventReceivedPowerNotification
:
6646 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6647 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6650 case kPowerEventSystemBootCompleted
:
6651 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6654 systemBooting
= false;
6656 if (lowBatteryCondition
)
6658 privateSleepSystem (kIOPMSleepReasonLowPower
);
6660 // The rest is unnecessary since the system is expected
6661 // to sleep immediately. The following wake will update
6666 if (swd_flags
& SWD_VALID_LOGS
) {
6667 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6668 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6669 swd_logBufMap
->release();
6672 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6673 sleepWakeDebugDumpFromFile();
6675 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6676 // If logs are invalid, write the failure code
6677 sleepWakeDebugDumpFromMem(NULL
);
6679 // If lid is closed, re-send lid closed notification
6680 // now that booting is complete.
6681 if ( clamshellClosed
)
6683 handlePowerNotification(kLocalEvalClamshellCommand
);
6685 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6690 case kPowerEventSystemShutdown
:
6691 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6692 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6694 /* We set systemShutdown = true during shutdown
6695 to prevent sleep at unexpected times while loginwindow is trying
6696 to shutdown apps and while the OS is trying to transition to
6699 Set to true during shutdown, as soon as loginwindow shows
6700 the "shutdown countdown dialog", through individual app
6701 termination, and through black screen kernel shutdown.
6703 systemShutdown
= true;
6706 A shutdown was initiated, but then the shutdown
6707 was cancelled, clearing systemShutdown to false here.
6709 systemShutdown
= false;
6713 case kPowerEventUserDisabledSleep
:
6714 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6715 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6718 case kPowerEventRegisterSystemCapabilityClient
:
6719 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6720 if (systemCapabilityNotifier
)
6722 systemCapabilityNotifier
->release();
6723 systemCapabilityNotifier
= 0;
6727 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6728 systemCapabilityNotifier
->retain();
6730 /* intentional fall-through */
6731 [[clang::fallthrough]];
6733 case kPowerEventRegisterKernelCapabilityClient
:
6734 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6735 if (!_joinedCapabilityClients
)
6736 _joinedCapabilityClients
= OSSet::withCapacity(8);
6739 IONotifier
* notify
= (IONotifier
*) arg0
;
6740 if (_joinedCapabilityClients
)
6742 _joinedCapabilityClients
->setObject(notify
);
6743 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6749 case kPowerEventPolicyStimulus
:
6750 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6753 int stimulus
= (uintptr_t) arg0
;
6754 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6758 case kPowerEventAssertionCreate
:
6759 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6761 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6766 case kPowerEventAssertionRelease
:
6767 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6769 pmAssertions
->handleReleaseAssertion(arg1
);
6773 case kPowerEventAssertionSetLevel
:
6774 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6776 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6780 case kPowerEventQueueSleepWakeUUID
:
6781 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6782 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6784 case kPowerEventPublishSleepWakeUUID
:
6785 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6786 handlePublishSleepWakeUUID((bool)arg0
);
6789 case kPowerEventSetDisplayPowerOn
:
6790 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6791 if (!wrangler
) break;
6794 displayPowerOnRequested
= true;
6798 displayPowerOnRequested
= false;
6800 handleDisplayPowerOn();
6805 //******************************************************************************
6806 // systemPowerEventOccurred
6808 // The power controller is notifying us of a hardware-related power management
6809 // event that we must handle.
6811 // systemPowerEventOccurred covers the same functionality that
6812 // receivePowerNotification does; it simply provides a richer API for conveying
6813 // more information.
6814 //******************************************************************************
6816 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6817 const OSSymbol
*event
,
6820 IOReturn attempt
= kIOReturnSuccess
;
6821 OSNumber
*newNumber
= NULL
;
6824 return kIOReturnBadArgument
;
6826 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6828 return kIOReturnInternalError
;
6830 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6832 newNumber
->release();
6837 void IOPMrootDomain::setThermalState(OSObject
*value
)
6841 if (gIOPMWorkLoop
->inGate() == false) {
6842 gIOPMWorkLoop
->runAction(
6843 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6849 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6850 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6851 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6855 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6856 const OSSymbol
*event
,
6859 OSDictionary
*thermalsDict
= NULL
;
6860 bool shouldUpdate
= true;
6862 if (!event
|| !value
)
6863 return kIOReturnBadArgument
;
6866 // We reuse featuresDict Lock because it already exists and guards
6867 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6868 // of stepping on that lock.
6869 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6871 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6873 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6874 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6876 thermalsDict
= OSDictionary::withCapacity(1);
6879 if (!thermalsDict
) {
6880 shouldUpdate
= false;
6884 thermalsDict
->setObject (event
, value
);
6886 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6888 thermalsDict
->release();
6892 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6896 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6897 setThermalState(value
);
6899 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6902 return kIOReturnSuccess
;
6905 //******************************************************************************
6906 // receivePowerNotification
6908 // The power controller is notifying us of a hardware-related power management
6909 // event that we must handle. This may be a result of an 'environment' interrupt
6910 // from the power mgt micro.
6911 //******************************************************************************
6913 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6915 pmPowerStateQueue
->submitPowerEvent(
6916 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6917 return kIOReturnSuccess
;
6920 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6922 bool eval_clamshell
= false;
6927 * Local (IOPMrootDomain only) eval clamshell command
6929 if (msg
& kLocalEvalClamshellCommand
)
6931 eval_clamshell
= true;
6937 if (msg
& kIOPMOverTemp
)
6939 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6940 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6944 * Forward DW thermal notification to client, if system is not going to sleep
6946 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6948 DLOG("DarkWake thermal limits message received!\n");
6950 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6956 if (msg
& kIOPMSleepNow
)
6958 privateSleepSystem (kIOPMSleepReasonSoftware
);
6964 if (msg
& kIOPMPowerEmergency
)
6966 lowBatteryCondition
= true;
6967 privateSleepSystem (kIOPMSleepReasonLowPower
);
6973 if (msg
& kIOPMClamshellOpened
)
6975 DLOG("Clamshell opened\n");
6976 // Received clamshel open message from clamshell controlling driver
6977 // Update our internal state and tell general interest clients
6978 clamshellClosed
= false;
6979 clamshellExists
= true;
6981 // Don't issue a hid tickle when lid is open and polled on wake
6982 if (msg
& kIOPMSetValue
)
6984 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6989 informCPUStateChange(kInformLid
, 0);
6991 // Tell general interest clients
6992 sendClientClamshellNotification();
6994 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6995 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6996 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6997 if (aborting
) userActivityCount
++;
6998 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
7003 * Send the clamshell interest notification since the lid is closing.
7005 if (msg
& kIOPMClamshellClosed
)
7007 DLOG("Clamshell closed\n");
7008 // Received clamshel open message from clamshell controlling driver
7009 // Update our internal state and tell general interest clients
7010 clamshellClosed
= true;
7011 clamshellExists
= true;
7014 informCPUStateChange(kInformLid
, 1);
7016 // Tell general interest clients
7017 sendClientClamshellNotification();
7019 // And set eval_clamshell = so we can attempt
7020 eval_clamshell
= true;
7024 * Set Desktop mode (sent from graphics)
7026 * -> reevaluate lid state
7028 if (msg
& kIOPMSetDesktopMode
)
7030 DLOG("Desktop mode\n");
7031 desktopMode
= (0 != (msg
& kIOPMSetValue
));
7032 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
7034 sendClientClamshellNotification();
7036 // Re-evaluate the lid state
7037 eval_clamshell
= true;
7041 * AC Adaptor connected
7043 * -> reevaluate lid state
7045 if (msg
& kIOPMSetACAdaptorConnected
)
7047 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
7048 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
7051 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
7053 // Tell BSD if AC is connected
7054 // 0 == external power source; 1 == on battery
7055 post_sys_powersource(acAdaptorConnected
? 0:1);
7057 sendClientClamshellNotification();
7059 // Re-evaluate the lid state
7060 eval_clamshell
= true;
7062 // Lack of AC may have latched a display wrangler tickle.
7063 // This mirrors the hardware's USB wake event latch, where a latched
7064 // USB wake event followed by an AC attach will trigger a full wake.
7065 latchDisplayWranglerTickle( false );
7068 // AC presence will reset the standy timer delay adjustment.
7069 _standbyTimerResetSeconds
= 0;
7071 if (!userIsActive
) {
7072 // Reset userActivityTime when power supply is changed(rdr 13789330)
7073 clock_get_uptime(&userActivityTime
);
7078 * Enable Clamshell (external display disappear)
7080 * -> reevaluate lid state
7082 if (msg
& kIOPMEnableClamshell
)
7084 DLOG("Clamshell enabled\n");
7085 // Re-evaluate the lid state
7086 // System should sleep on external display disappearance
7087 // in lid closed operation.
7088 if (true == clamshellDisabled
)
7090 eval_clamshell
= true;
7093 clamshellDisabled
= false;
7094 sendClientClamshellNotification();
7098 * Disable Clamshell (external display appeared)
7099 * We don't bother re-evaluating clamshell state. If the system is awake,
7100 * the lid is probably open.
7102 if (msg
& kIOPMDisableClamshell
)
7104 DLOG("Clamshell disabled\n");
7105 clamshellDisabled
= true;
7106 sendClientClamshellNotification();
7110 * Evaluate clamshell and SLEEP if appropiate
7112 if (eval_clamshell
&& clamshellClosed
)
7114 if (shouldSleepOnClamshellClosed())
7115 privateSleepSystem (kIOPMSleepReasonClamshell
);
7117 evaluatePolicy( kStimulusDarkWakeEvaluate
);
7123 if (msg
& kIOPMPowerButton
)
7125 DLOG("Powerbutton press\n");
7126 if (!wranglerAsleep
)
7128 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
7129 // Check that power button sleep is enabled
7131 if( kOSBooleanTrue
!= getProperty(pbs
))
7132 privateSleepSystem (kIOPMSleepReasonPowerButton
);
7140 //******************************************************************************
7143 // Evaluate root-domain policy in response to external changes.
7144 //******************************************************************************
7146 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
7150 int idleSleepEnabled
: 1;
7151 int idleSleepDisabled
: 1;
7152 int displaySleep
: 1;
7153 int sleepDelayChanged
: 1;
7154 int evaluateDarkWake
: 1;
7155 int adjustPowerState
: 1;
7156 int userBecameInactive
: 1;
7167 case kStimulusDisplayWranglerSleep
:
7168 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7169 if (!wranglerAsleep
)
7171 // first transition to wrangler sleep or lower
7172 flags
.bit
.displaySleep
= true;
7176 case kStimulusDisplayWranglerWake
:
7177 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7178 displayIdleForDemandSleep
= false;
7179 wranglerAsleep
= false;
7182 case kStimulusEnterUserActiveState
:
7183 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7184 if (_preventUserActive
)
7186 DLOG("user active dropped\n");
7191 userIsActive
= true;
7192 userWasActive
= true;
7194 // Stay awake after dropping demand for display power on
7195 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
7196 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
7197 DLOG("User activity while in notification wake\n");
7198 changePowerStateWithOverrideTo( ON_STATE
, 0);
7201 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
7202 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
7203 messageClients(kIOPMMessageUserIsActiveChanged
);
7205 flags
.bit
.idleSleepDisabled
= true;
7208 case kStimulusLeaveUserActiveState
:
7209 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7212 userIsActive
= false;
7213 clock_get_uptime(&userBecameInactiveTime
);
7214 flags
.bit
.userBecameInactive
= true;
7216 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
7217 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
7218 messageClients(kIOPMMessageUserIsActiveChanged
);
7222 case kStimulusAggressivenessChanged
:
7224 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7225 unsigned long minutesToIdleSleep
= 0;
7226 unsigned long minutesToDisplayDim
= 0;
7227 unsigned long minutesDelta
= 0;
7229 // Fetch latest display and system sleep slider values.
7230 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
7231 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
7232 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7233 (uint32_t) sleepSlider
,
7234 (uint32_t) minutesToIdleSleep
,
7235 (uint32_t) minutesToDisplayDim
);
7237 DLOG("idle time -> %ld secs (ena %d)\n",
7238 idleSeconds
, (minutesToIdleSleep
!= 0));
7241 // How long to wait before sleeping the system once
7242 // the displays turns off is indicated by 'extraSleepDelay'.
7244 if ( minutesToIdleSleep
> minutesToDisplayDim
)
7245 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
7246 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
7249 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
7250 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
7252 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
7253 flags
.bit
.idleSleepDisabled
= true;
7254 idleSleepEnabled
= false;
7256 if (0x7fffffff == minutesToIdleSleep
)
7257 minutesToIdleSleep
= idleSeconds
;
7259 if (((minutesDelta
!= extraSleepDelay
) ||
7260 (userActivityTime
!= userActivityTime_prev
)) &&
7261 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
7262 flags
.bit
.sleepDelayChanged
= true;
7264 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
7265 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
7267 // Reconsider decision to remain in dark wake
7268 flags
.bit
.evaluateDarkWake
= true;
7271 sleepSlider
= minutesToIdleSleep
;
7272 extraSleepDelay
= minutesDelta
;
7273 userActivityTime_prev
= userActivityTime
;
7276 case kStimulusDemandSystemSleep
:
7277 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7278 displayIdleForDemandSleep
= true;
7279 if (wrangler
&& wranglerIdleSettings
)
7281 // Request wrangler idle only when demand sleep is triggered
7283 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7285 wrangler
->setProperties(wranglerIdleSettings
);
7286 DLOG("Requested wrangler idle\n");
7289 // arg = sleepReason
7290 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
7293 case kStimulusAllowSystemSleepChanged
:
7294 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7295 flags
.bit
.adjustPowerState
= true;
7298 case kStimulusDarkWakeActivityTickle
:
7299 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7300 // arg == true implies real and not self generated wrangler tickle.
7301 // Update wake type on PM work loop instead of the tickle thread to
7302 // eliminate the possibility of an early tickle clobbering the wake
7303 // type set by the platform driver.
7305 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
7307 if (false == wranglerTickled
)
7309 if (latchDisplayWranglerTickle(true))
7311 DLOG("latched tickle\n");
7315 wranglerTickled
= true;
7316 DLOG("Requesting full wake after dark wake activity tickle\n");
7317 requestFullWake( kFullWakeReasonLocalUser
);
7321 case kStimulusDarkWakeEntry
:
7322 case kStimulusDarkWakeReentry
:
7323 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7324 // Any system transitions since the last dark wake transition
7325 // will invalid the stimulus.
7327 if (arg
== _systemStateGeneration
)
7329 DLOG("dark wake entry\n");
7330 systemDarkWake
= true;
7332 // Keep wranglerAsleep an invariant when wrangler is absent
7334 wranglerAsleep
= true;
7336 if (kStimulusDarkWakeEntry
== stimulus
)
7338 clock_get_uptime(&userBecameInactiveTime
);
7339 flags
.bit
.evaluateDarkWake
= true;
7340 if (activitySinceSleep()) {
7341 DLOG("User activity recorded while going to darkwake\n");
7346 // Always accelerate disk spindown while in dark wake,
7347 // even if system does not support/allow sleep.
7349 cancelIdleSleepTimer();
7350 setQuickSpinDownTimeout();
7354 case kStimulusDarkWakeEvaluate
:
7355 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7358 flags
.bit
.evaluateDarkWake
= true;
7362 case kStimulusNoIdleSleepPreventers
:
7363 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7364 flags
.bit
.adjustPowerState
= true;
7367 } /* switch(stimulus) */
7369 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7371 if (darkWakeToSleepASAP
||
7372 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7374 uint32_t newSleepReason
;
7376 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7378 // System was previously in full wake. Sleep reason from
7379 // full to dark already recorded in fullToDarkReason.
7381 if (lowBatteryCondition
)
7382 newSleepReason
= kIOPMSleepReasonLowPower
;
7384 newSleepReason
= fullToDarkReason
;
7388 // In dark wake from system sleep.
7390 if (darkWakeSleepService
)
7391 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7393 newSleepReason
= kIOPMSleepReasonMaintenance
;
7396 if (checkSystemCanSleep(newSleepReason
))
7398 privateSleepSystem(newSleepReason
);
7401 else // non-maintenance (network) dark wake
7403 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7405 // Release power clamp, and wait for children idle.
7406 adjustPowerState(true);
7410 changePowerStateToPriv(ON_STATE
);
7417 // The rest are irrelevant while system is in dark wake.
7421 if ((flags
.bit
.displaySleep
) &&
7422 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7424 // kIOPMSleepReasonMaintenance?
7425 DLOG("Display sleep while in notification wake\n");
7426 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7429 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7431 bool cancelQuickSpindown
= false;
7433 if (flags
.bit
.sleepDelayChanged
)
7435 // Cancel existing idle sleep timer and quick disk spindown.
7436 // New settings will be applied by the idleSleepEnabled flag
7437 // handler below if idle sleep is enabled.
7439 DLOG("extra sleep timer changed\n");
7440 cancelIdleSleepTimer();
7441 cancelQuickSpindown
= true;
7445 DLOG("user inactive\n");
7448 if (!userIsActive
&& idleSleepEnabled
)
7450 startIdleSleepTimer(getTimeToIdleSleep());
7453 if (cancelQuickSpindown
)
7454 restoreUserSpinDownTimeout();
7457 if (flags
.bit
.idleSleepEnabled
)
7459 DLOG("idle sleep timer enabled\n");
7462 changePowerStateToPriv(ON_STATE
);
7463 startIdleSleepTimer( idleSeconds
);
7467 // Start idle timer if prefs now allow system sleep
7468 // and user is already inactive. Disk spindown is
7469 // accelerated upon timer expiration.
7473 startIdleSleepTimer(getTimeToIdleSleep());
7478 if (flags
.bit
.idleSleepDisabled
)
7480 DLOG("idle sleep timer disabled\n");
7481 cancelIdleSleepTimer();
7482 restoreUserSpinDownTimeout();
7486 if (flags
.bit
.adjustPowerState
)
7488 bool sleepASAP
= false;
7490 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7494 changePowerStateToPriv(ON_STATE
);
7495 if (idleSleepEnabled
)
7497 // stay awake for at least idleSeconds
7498 startIdleSleepTimer(idleSeconds
);
7501 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7507 adjustPowerState(sleepASAP
);
7511 //******************************************************************************
7514 // Request transition from dark wake to full wake
7515 //******************************************************************************
7517 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7519 uint32_t options
= 0;
7520 IOService
* pciRoot
= 0;
7521 bool promotion
= false;
7523 // System must be in dark wake and a valid reason for entering full wake
7524 if ((kFullWakeReasonNone
== reason
) ||
7525 (kFullWakeReasonNone
!= fullWakeReason
) ||
7526 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7531 // Will clear reason upon exit from full wake
7532 fullWakeReason
= reason
;
7534 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7535 kIOPMSystemCapabilityAudio
);
7537 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7538 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7539 !graphicsSuppressed
)
7541 // Promote to full wake while waking up to dark wake due to tickle.
7542 // PM will hold off notifying the graphics subsystem about system wake
7543 // as late as possible, so if a HID tickle does arrive, graphics can
7544 // power up on this same wake cycle. The latency to power up graphics
7545 // on the next cycle can be huge on some systems. However, once any
7546 // graphics suppression has taken effect, it is too late. All other
7547 // graphics devices must be similarly suppressed. But the delay till
7548 // the following cycle should be short.
7550 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7551 kIOPMSystemCapabilityAudio
);
7553 // Immediately bring up audio and graphics
7554 pciRoot
= pciHostBridgeDriver
;
7555 willEnterFullWake();
7559 // Unsafe to cancel once graphics was powered.
7560 // If system woke from dark wake, the return to sleep can
7561 // be cancelled. "awake -> dark -> sleep" transition
7562 // can be canceled also, during the "dark --> sleep" phase
7563 // *prior* to driver power down.
7564 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7565 _pendingCapability
== 0) {
7566 options
|= kIOPMSyncCancelPowerDown
;
7569 synchronizePowerTree(options
, pciRoot
);
7570 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7572 // IOGraphics doesn't light the display even though graphics is
7573 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7574 // So, do an explicit activity tickle
7576 wrangler
->activityTickle(0,0);
7579 // Log a timestamp for the initial full wake request.
7580 // System may not always honor this full wake request.
7581 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7586 clock_get_uptime(&now
);
7587 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7588 absolutetime_to_nanoseconds(now
, &nsec
);
7589 MSG("full wake %s (reason %u) %u ms\n",
7590 promotion
? "promotion" : "request",
7591 fullWakeReason
, ((int)((nsec
) / NSEC_PER_MSEC
)));
7595 //******************************************************************************
7596 // willEnterFullWake
7598 // System will enter full wake from sleep, from dark wake, or from dark
7599 // wake promotion. This function aggregate things that are in common to
7600 // all three full wake transitions.
7602 // Assumptions: fullWakeReason was updated
7603 //******************************************************************************
7605 void IOPMrootDomain::willEnterFullWake( void )
7607 hibernateRetry
= false;
7608 sleepToStandby
= false;
7609 standbyNixed
= false;
7610 resetTimers
= false;
7611 sleepTimerMaintenance
= false;
7613 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7614 kSystemMessageClientLegacyApp
;
7616 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7618 // Initial graphics full power
7619 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7621 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7622 setProperty(gIOPMUserTriggeredFullWakeKey
,
7623 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7624 kOSBooleanTrue
: kOSBooleanFalse
);
7627 IOHibernateSetWakeCapabilities(_pendingCapability
);
7630 IOService::setAdvisoryTickleEnable( true );
7631 tellClients(kIOMessageSystemWillPowerOn
);
7632 preventTransitionToUserActive(false);
7635 //******************************************************************************
7636 // fullWakeDelayedWork
7638 // System has already entered full wake. Invoked by a delayed thread call.
7639 //******************************************************************************
7641 void IOPMrootDomain::fullWakeDelayedWork( void )
7643 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7644 // Not gated, don't modify state
7645 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7646 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7648 receivePowerNotification( kLocalEvalClamshellCommand
);
7653 //******************************************************************************
7654 // evaluateAssertions
7656 //******************************************************************************
7657 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7659 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7661 messageClients(kIOPMMessageDriverAssertionsChanged
);
7663 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7666 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7668 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7669 wrangler
->setIgnoreIdleTimer( value
);
7673 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7674 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7675 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7677 clock_usec_t microsecs
;
7678 clock_get_uptime(&now
);
7679 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7680 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7681 if (assertOnWakeReport
) {
7682 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7683 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7688 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7689 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7691 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7692 updatePreventIdleSleepList(this, true);
7695 DLOG("Driver assertion ReservedBit7 dropped\n");
7696 updatePreventIdleSleepList(this, false);
7704 //******************************************************************************
7707 //******************************************************************************
7709 void IOPMrootDomain::pmStatsRecordEvent(
7711 AbsoluteTime timestamp
)
7713 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7714 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7717 OSData
*publishPMStats
= NULL
;
7719 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7721 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7723 switch (eventIndex
) {
7724 case kIOPMStatsHibernateImageWrite
:
7726 gPMStats
.hibWrite
.start
= nsec
;
7728 gPMStats
.hibWrite
.stop
= nsec
;
7731 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7732 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/NSEC_PER_MSEC
);
7735 case kIOPMStatsHibernateImageRead
:
7737 gPMStats
.hibRead
.start
= nsec
;
7739 gPMStats
.hibRead
.stop
= nsec
;
7742 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7743 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/NSEC_PER_MSEC
);
7745 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7746 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7747 publishPMStats
->release();
7748 bzero(&gPMStats
, sizeof(gPMStats
));
7755 * Appends a record of the application response to
7756 * IOPMrootDomain::pmStatsAppResponses
7758 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7759 const OSSymbol
*response
,
7765 IOPMPowerStateIndex powerState
)
7767 OSDictionary
*responseDescription
= NULL
;
7768 OSNumber
*delayNum
= NULL
;
7769 OSNumber
*powerCaps
= NULL
;
7770 OSNumber
*pidNum
= NULL
;
7771 OSNumber
*msgNum
= NULL
;
7772 const OSSymbol
*appname
;
7773 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7774 IOPMServiceInterestNotifier
*notify
= 0;
7776 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7778 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
))
7779 notify
->ackTimeoutCnt
++;
7781 notify
->ackTimeoutCnt
= 0;
7785 if (response
->isEqualTo(gIOPMStatsResponsePrompt
) ||
7786 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7790 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7791 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
7794 // User space app or kernel capability client
7796 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7799 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
7801 notify
->msgType
= 0;
7804 responseDescription
= OSDictionary::withCapacity(5);
7805 if (responseDescription
)
7808 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7811 msgNum
= OSNumber::withNumber(messageType
, 32);
7813 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7817 if (!name
&& notify
&& notify
->identifier
) {
7818 name
= notify
->identifier
->getCStringNoCopy();
7821 if (name
&& (strlen(name
) > 0))
7823 appname
= OSSymbol::withCString(name
);
7825 responseDescription
->setObject(_statsNameKey
, appname
);
7830 if (!id
&& notify
) {
7834 pidNum
= OSNumber::withNumber(id
, 64);
7836 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7841 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7843 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7844 delayNum
->release();
7847 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7848 powerCaps
= OSNumber::withNumber(powerState
, 32);
7850 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7851 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7853 powerState
, delay_ms
);
7858 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7861 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7862 powerCaps
->release();
7865 sleep
= OSSymbol::withCString("Sleep");
7866 wake
= OSSymbol::withCString("Wake");
7867 if (_systemTransitionType
== kSystemTransitionSleep
) {
7868 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7870 else if (_systemTransitionType
== kSystemTransitionWake
) {
7871 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7873 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7874 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7875 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7876 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7877 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7879 if (sleep
) sleep
->release();
7880 if (wake
) wake
->release();
7884 IOLockLock(pmStatsLock
);
7885 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7886 pmStatsAppResponses
->setObject(responseDescription
);
7888 IOLockUnlock(pmStatsLock
);
7890 responseDescription
->release();
7897 // MARK: PMTraceWorker
7899 //******************************************************************************
7900 // TracePoint support
7902 //******************************************************************************
7904 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7905 "IOPMRegisterNVRAMTracePointHandler"
7907 IOReturn
IOPMrootDomain::callPlatformFunction(
7908 const OSSymbol
* functionName
,
7909 bool waitForFunction
,
7910 void * param1
, void * param2
,
7911 void * param3
, void * param4
)
7913 uint32_t bootFailureCode
= 0xffffffff;
7914 if (pmTracer
&& functionName
&&
7915 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7916 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7918 uint32_t tracePointPhases
, tracePointPCI
;
7919 uint64_t statusCode
;
7921 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7922 pmTracer
->tracePointTarget
= (void *) param2
;
7923 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7924 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7925 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7927 IORegistryEntry
*node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
7929 OSData
*data
= OSDynamicCast( OSData
, node
->getProperty(kIOEFIBootRomFailureKey
) );
7930 if ( data
&& data
->getLength() == sizeof(bootFailureCode
) ) {
7931 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
7935 // Failure code from EFI/BootRom is a four byte structure
7936 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7938 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7939 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7940 MSG("Sleep failure code 0x%08x 0x%08x\n",
7941 tracePointPCI
, tracePointPhases
);
7943 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7944 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7946 return kIOReturnSuccess
;
7949 else if (functionName
&&
7950 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7952 if (gSleepPolicyHandler
)
7953 return kIOReturnExclusiveAccess
;
7955 return kIOReturnBadArgument
;
7956 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7957 gSleepPolicyTarget
= (void *) param2
;
7958 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7959 return kIOReturnSuccess
;
7963 return super::callPlatformFunction(
7964 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7967 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7968 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7970 uint32_t code
= IODBG_POWER(event
);
7971 uint64_t regId
= id
;
7973 regId
= getRegistryEntryID();
7975 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7979 void IOPMrootDomain::tracePoint( uint8_t point
)
7981 if (systemBooting
) return;
7983 if (kIOPMTracePointWakeCapabilityClients
== point
)
7984 acceptSystemWakeEvents(false);
7986 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7987 pmTracer
->tracePoint(point
);
7990 void IOPMrootDomain::traceDetail(OSObject
*object
)
7992 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7994 DLOG("Unknown notifier\n");
7998 if (!systemBooting
) {
7999 pmTracer
->traceDetail( notifier
->uuid0
>> 32 );
8000 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(), notifier
->msgType
, notifier
->uuid0
, notifier
->uuid1
);
8001 if (notifier
->identifier
) {
8002 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer
->getTracePhase(), notifier
->msgType
,
8003 notifier
->identifier
->getCStringNoCopy());
8006 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer
->getTracePhase(), notifier
->msgType
);
8013 void IOPMrootDomain::traceAckDelay(OSObject
*object
, uint32_t response
, uint32_t delay_ms
)
8015 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
8017 DLOG("Unknown notifier\n");
8021 if (!systemBooting
) {
8022 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
, notifier
->uuid1
, response
, delay_ms
);
8023 if (notifier
->identifier
) {
8024 DLOG("Response from %s took %d ms(response:%d)\n",
8025 notifier
->identifier
->getCStringNoCopy(), delay_ms
, response
);
8028 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
8029 notifier
->uuid0
, notifier
->uuid1
, delay_ms
, response
);
8034 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
8036 if (!systemBooting
) {
8037 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
8038 pmTracer
->traceDetail( detail
);
8039 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
8040 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
8045 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
8048 void **report
= NULL
;
8051 uint32_t *clientCnt
;
8056 if (channel_id
== kAssertDelayChID
) {
8057 report
= &assertOnWakeReport
;
8058 bktCnt
= kAssertDelayBcktCnt
;
8059 bktSize
= kAssertDelayBcktSize
;
8060 clientCnt
= &assertOnWakeClientCnt
;
8062 else if (channel_id
== kSleepDelaysChID
) {
8063 report
= &sleepDelaysReport
;
8064 bktCnt
= kSleepDelaysBcktCnt
;
8065 bktSize
= kSleepDelaysBcktSize
;
8066 clientCnt
= &sleepDelaysClientCnt
;
8071 case kIOReportEnable
:
8078 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
8079 *report
= IOMalloc(reportSize
);
8080 if (*report
== NULL
) {
8083 bzero(*report
, reportSize
);
8084 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
8085 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
8087 if (channel_id
== kAssertDelayChID
)
8088 assertOnWakeSecs
= 0;
8092 case kIOReportDisable
:
8093 if (*clientCnt
== 0) {
8096 if (*clientCnt
== 1)
8098 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
8103 if (channel_id
== kAssertDelayChID
)
8104 assertOnWakeSecs
= -1; // Invalid value to prevent updates
8108 case kIOReportGetDimensions
:
8110 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
8118 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
8119 IOReportConfigureAction action
,
8124 uint64_t configAction
= (uint64_t)action
;
8126 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8127 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
8128 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
8129 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
8130 if (action
!= kIOReportGetDimensions
) continue;
8131 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
8133 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
8134 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
8135 gIOPMWorkLoop
->runAction(
8136 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
8137 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
8138 (void *)configAction
, (void *)result
);
8142 return super::configureReport(channelList
, action
, result
, destination
);
8145 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
8155 if (ch_id
== kAssertDelayChID
) {
8156 report
= &assertOnWakeReport
;
8158 else if (ch_id
== kSleepDelaysChID
) {
8159 report
= &sleepDelaysReport
;
8162 if (*report
== NULL
) {
8163 return kIOReturnNotOpen
;
8166 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
8167 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
8168 return kIOReturnOverrun
;
8171 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
8172 dest
->appendBytes(data2cpy
, size2cpy
);
8174 return kIOReturnSuccess
;
8177 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
8178 IOReportUpdateAction action
,
8184 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
8185 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
8189 if (action
!= kIOReportCopyChannelData
) goto exit
;
8191 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8192 ch_id
= channelList
->channels
[cnt
].channel_id
;
8194 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
8195 gIOPMWorkLoop
->runAction(
8196 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
8197 (OSObject
*)this, (void *)ch_id
,
8198 (void *)result
, (void *)dest
);
8202 else if ((ch_id
== kSleepCntChID
) ||
8203 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
8204 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
8208 if (ch_id
== kSleepCntChID
)
8209 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
8210 else if (ch_id
== kDarkWkCntChID
)
8211 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
8212 else if (ch_id
== kUserWkCntChID
)
8213 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
8215 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
8216 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
8217 dest
->appendBytes(data2cpy
, size2cpy
);
8221 return super::updateReport(channelList
, action
, result
, destination
);
8225 //******************************************************************************
8226 // PMTraceWorker Class
8228 //******************************************************************************
8231 #define super OSObject
8232 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
8234 #define kPMBestGuessPCIDevicesCount 25
8235 #define kPMMaxRTCBitfieldSize 32
8237 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
8241 me
= OSTypeAlloc( PMTraceWorker
);
8242 if (!me
|| !me
->init())
8247 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
8249 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8250 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8251 // this dictionary lazily.
8253 me
->pciDeviceBitMappings
= NULL
;
8254 me
->pmTraceWorkerLock
= IOLockAlloc();
8255 me
->tracePhase
= kIOPMTracePointSystemUp
;
8256 me
->traceData32
= 0;
8257 me
->loginWindowData
= 0;
8258 me
->coreDisplayData
= 0;
8259 me
->coreGraphicsData
= 0;
8263 void PMTraceWorker::RTC_TRACE(void)
8265 if (tracePointHandler
&& tracePointTarget
)
8269 IOLockLock(pmTraceWorkerLock
);
8270 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
8271 (coreGraphicsData
<< 8) | tracePhase
;
8272 IOLockUnlock(pmTraceWorkerLock
);
8274 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
8275 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
8279 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
8281 const OSSymbol
* deviceName
;
8284 IOLockLock(pmTraceWorkerLock
);
8286 if (!pciDeviceBitMappings
)
8288 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
8289 if (!pciDeviceBitMappings
)
8293 // Check for bitmask overflow.
8294 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
8297 if ((deviceName
= pciDevice
->copyName()) &&
8298 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
8299 pciDeviceBitMappings
->setObject(deviceName
))
8301 index
= pciDeviceBitMappings
->getCount() - 1;
8302 _LOG("PMTrace PCI array: set object %s => %d\n",
8303 deviceName
->getCStringNoCopy(), index
);
8306 deviceName
->release();
8307 if (!addedToRegistry
&& (index
>= 0))
8308 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
8311 IOLockUnlock(pmTraceWorkerLock
);
8315 bool PMTraceWorker::serialize(OSSerialize
*s
) const
8318 if (pciDeviceBitMappings
)
8320 IOLockLock(pmTraceWorkerLock
);
8321 ok
= pciDeviceBitMappings
->serialize(s
);
8322 IOLockUnlock(pmTraceWorkerLock
);
8327 void PMTraceWorker::tracePoint(uint8_t phase
)
8329 // clear trace detail when phase begins
8330 if (tracePhase
!= phase
)
8335 DLOG("trace point 0x%02x\n", tracePhase
);
8339 void PMTraceWorker::traceDetail(uint32_t detail
)
8341 if (detail
== traceData32
) {
8344 traceData32
= detail
;
8348 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
8350 switch (component
) {
8351 case kIOPMLoginWindowProgress
:
8352 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
8354 case kIOPMCoreDisplayProgress
:
8355 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
8357 case kIOPMCoreGraphicsProgress
:
8358 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
8364 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
8368 void PMTraceWorker::tracePCIPowerChange(
8369 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
8372 uint32_t expectedFlag
;
8374 // Ignore PCI changes outside of system sleep/wake.
8375 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
8376 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
8379 // Only record the WillChange transition when going to sleep,
8380 // and the DidChange on the way up.
8381 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
8382 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
8383 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
8384 if (changeFlags
!= expectedFlag
)
8387 // Mark this device off in our bitfield
8388 if (bitNum
< kPMMaxRTCBitfieldSize
)
8390 bitMask
= (1 << bitNum
);
8392 if (kPowerChangeStart
== type
)
8394 traceData32
|= bitMask
;
8395 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8396 service
->getName(), bitNum
, bitMask
, traceData32
);
8397 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8401 traceData32
&= ~bitMask
;
8402 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8403 service
->getName(), bitNum
, bitMask
, traceData32
);
8404 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8407 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8412 uint64_t PMTraceWorker::getPMStatusCode( )
8414 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8418 uint8_t PMTraceWorker::getTracePhase()
8423 uint32_t PMTraceWorker::getTraceData()
8429 // MARK: PMHaltWorker
8431 //******************************************************************************
8432 // PMHaltWorker Class
8434 //******************************************************************************
8436 PMHaltWorker
* PMHaltWorker::worker( void )
8442 me
= OSTypeAlloc( PMHaltWorker
);
8443 if (!me
|| !me
->init())
8446 me
->lock
= IOLockAlloc();
8450 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8451 me
->retain(); // thread holds extra retain
8452 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8457 thread_deallocate(thread
);
8462 if (me
) me
->release();
8466 void PMHaltWorker::free( void )
8468 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8474 return OSObject::free();
8477 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8479 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8481 IOLockLock( gPMHaltLock
);
8483 me
->depth
= gPMHaltDepth
;
8484 IOLockUnlock( gPMHaltLock
);
8486 while (me
->depth
>= 0)
8488 PMHaltWorker::work( me
);
8490 IOLockLock( gPMHaltLock
);
8491 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8493 // This is the last thread to finish work on this level,
8494 // inform everyone to start working on next lower level.
8496 me
->depth
= gPMHaltDepth
;
8497 gPMHaltIdleCount
= 0;
8498 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8502 // One or more threads are still working on this level,
8503 // this thread must wait.
8504 me
->depth
= gPMHaltDepth
- 1;
8506 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8507 } while (me
->depth
!= gPMHaltDepth
);
8509 IOLockUnlock( gPMHaltLock
);
8512 // No more work to do, terminate thread
8513 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8514 thread_wakeup( &gPMHaltDepth
);
8518 void PMHaltWorker::work( PMHaltWorker
* me
)
8520 IOService
* service
;
8522 AbsoluteTime startTime
, elapsedTime
;
8531 // Claim an unit of work from the shared pool
8532 IOLockLock( gPMHaltLock
);
8533 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8536 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8540 inner
->removeObject(service
);
8543 IOLockUnlock( gPMHaltLock
);
8545 break; // no more work at this depth
8547 clock_get_uptime(&startTime
);
8549 if (!service
->isInactive() &&
8550 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8552 IOLockLock(me
->lock
);
8553 me
->startTime
= startTime
;
8554 me
->service
= service
;
8555 me
->timeout
= false;
8556 IOLockUnlock(me
->lock
);
8558 service
->systemWillShutdown( gPMHaltMessageType
);
8560 // Wait for driver acknowledgement
8561 IOLockLock(me
->lock
);
8562 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8564 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8567 timeout
= me
->timeout
;
8568 IOLockUnlock(me
->lock
);
8571 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
8572 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
)
8574 LOG("%s driver %s (0x%llx) took %u ms\n",
8575 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8576 "PowerOff" : "Restart",
8577 service
->getName(), service
->getRegistryEntryID(),
8578 (uint32_t) deltaTime
);
8579 halt_log_enter("PowerOff/Restart handler completed",
8580 OSMemberFunctionCast(const void *, service
, &IOService::systemWillShutdown
),
8589 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8592 AbsoluteTime startTime
;
8593 AbsoluteTime endTime
;
8597 IOLockLock(me
->lock
);
8598 if (me
->service
&& !me
->timeout
)
8600 startTime
= me
->startTime
;
8602 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8604 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8605 absolutetime_to_nanoseconds(endTime
, &nano
);
8607 if (nano
> 3000000000ULL)
8611 halt_log_enter("PowerOff/Restart still waiting on handler",
8612 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
8614 MSG("%s still waiting on %s\n",
8615 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
8616 me
->service
->getName());
8619 IOLockUnlock(me
->lock
);
8622 //******************************************************************************
8623 // acknowledgeSystemWillShutdown
8625 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8626 //******************************************************************************
8628 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8630 PMHaltWorker
* worker
;
8636 //DLOG("%s acknowledged\n", from->getName());
8637 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8640 worker
= (PMHaltWorker
*) prop
;
8641 IOLockLock(worker
->lock
);
8642 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8643 thread_wakeup((event_t
) worker
);
8644 IOLockUnlock(worker
->lock
);
8649 DLOG("%s acknowledged without worker property\n",
8655 //******************************************************************************
8656 // notifySystemShutdown
8658 // Notify all objects in PM tree that system will shutdown or restart
8659 //******************************************************************************
8662 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8664 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8665 IORegistryIterator
* iter
;
8666 IORegistryEntry
* entry
;
8669 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8670 AbsoluteTime deadline
;
8671 unsigned int totalNodes
= 0;
8673 unsigned int rootDepth
;
8674 unsigned int numWorkers
;
8680 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8682 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8684 // Iterate the entire PM tree starting from root
8686 rootDepth
= root
->getDepth( gIOPowerPlane
);
8687 if (!rootDepth
) goto done
;
8689 // debug - for repeated test runs
8690 while (PMHaltWorker::metaClass
->getInstanceCount())
8695 gPMHaltArray
= OSArray::withCapacity(40);
8696 if (!gPMHaltArray
) goto done
;
8699 gPMHaltArray
->flushCollection();
8703 gPMHaltLock
= IOLockAlloc();
8704 if (!gPMHaltLock
) goto done
;
8707 if (!gPMHaltClientAcknowledgeKey
)
8709 gPMHaltClientAcknowledgeKey
=
8710 OSSymbol::withCStringNoCopy("PMShutdown");
8711 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8714 gPMHaltMessageType
= messageType
;
8716 // Depth-first walk of PM plane
8718 iter
= IORegistryIterator::iterateOver(
8719 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8723 while ((entry
= iter
->getNextObject()))
8725 node
= OSDynamicCast(IOService
, entry
);
8730 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8733 depth
= node
->getDepth( gIOPowerPlane
);
8734 if (depth
<= rootDepth
)
8739 // adjust to zero based depth
8740 depth
-= (rootDepth
+ 1);
8742 // gPMHaltArray is an array of containers, each container
8743 // refers to nodes with the same depth.
8745 count
= gPMHaltArray
->getCount();
8746 while (depth
>= count
)
8748 // expand array and insert placeholders
8749 gPMHaltArray
->setObject(PLACEHOLDER
);
8752 count
= gPMHaltArray
->getCount();
8755 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8756 if (inner
== PLACEHOLDER
)
8758 inner
= OSSet::withCapacity(40);
8761 gPMHaltArray
->replaceObject(depth
, inner
);
8766 // PM nodes that appear more than once in the tree will have
8767 // the same depth, OSSet will refuse to add the node twice.
8769 ok
= inner
->setObject(node
);
8772 DLOG("Skipped PM node %s\n", node
->getName());
8778 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8781 if (inner
!= PLACEHOLDER
)
8782 count
= inner
->getCount();
8783 DLOG("Nodes at depth %u = %u\n", i
, count
);
8786 // strip placeholders (not all depths are populated)
8788 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8790 if (inner
== PLACEHOLDER
)
8792 gPMHaltArray
->removeObject(i
);
8795 count
= inner
->getCount();
8796 if (count
> numWorkers
)
8798 totalNodes
+= count
;
8802 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8805 gPMHaltBusyCount
= 0;
8806 gPMHaltIdleCount
= 0;
8807 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8809 // Create multiple workers (and threads)
8811 if (numWorkers
> kPMHaltMaxWorkers
)
8812 numWorkers
= kPMHaltMaxWorkers
;
8814 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8815 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8817 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8818 workers
[i
] = PMHaltWorker::worker();
8820 // Wait for workers to exhaust all available work
8822 IOLockLock(gPMHaltLock
);
8823 while (gPMHaltDepth
>= 0)
8825 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8827 waitResult
= IOLockSleepDeadline(
8828 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8829 if (THREAD_TIMED_OUT
== waitResult
)
8832 clock_get_uptime(&now
);
8834 IOLockUnlock(gPMHaltLock
);
8835 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8838 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8840 IOLockLock(gPMHaltLock
);
8843 IOLockUnlock(gPMHaltLock
);
8845 // Release all workers
8847 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8850 workers
[i
]->release();
8851 // worker also retained by it's own thread
8855 DLOG("%s done\n", __FUNCTION__
);
8860 // MARK: Kernel Assertion
8862 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8864 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8865 IOPMDriverAssertionType whichAssertionBits
,
8866 IOPMDriverAssertionLevel assertionLevel
,
8867 IOService
*ownerService
,
8868 const char *ownerDescription
)
8871 IOPMDriverAssertionID newAssertion
;
8876 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8878 if (kIOReturnSuccess
== ret
)
8879 return newAssertion
;
8884 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8887 return kIOReturnInternalError
;
8889 return pmAssertions
->releaseAssertion(releaseAssertion
);
8893 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8894 IOPMDriverAssertionID assertionID
,
8895 IOPMDriverAssertionLevel assertionLevel
)
8897 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8900 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8902 IOPMDriverAssertionType sysLevels
;
8904 if (!pmAssertions
|| whichAssertion
== 0)
8905 return kIOPMDriverAssertionLevelOff
;
8907 sysLevels
= pmAssertions
->getActivatedAssertions();
8909 // Check that every bit set in argument 'whichAssertion' is asserted
8910 // in the aggregate bits.
8911 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8912 return kIOPMDriverAssertionLevelOn
;
8914 return kIOPMDriverAssertionLevelOff
;
8917 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8920 return kIOReturnNotFound
;
8922 return pmAssertions
->setUserAssertionLevels(inLevels
);
8925 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8929 pmAssertions
->publishProperties();
8931 return( IOService::serializeProperties(s
) );
8934 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8936 OSObject
*obj
= NULL
;
8937 obj
= IOService::copyProperty(aKey
);
8939 if (obj
) return obj
;
8941 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8942 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8943 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8944 return kOSBooleanTrue
;
8946 return kOSBooleanFalse
;
8950 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8951 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8952 if (swd_flags
& SWD_VALID_LOGS
)
8953 return kOSBooleanTrue
;
8955 return kOSBooleanFalse
;
8960 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8961 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8962 * issued by DisplayWrangler on darkwake.
8964 if (!strcmp(aKey
, "DesktopMode")) {
8966 return kOSBooleanTrue
;
8968 return kOSBooleanFalse
;
8970 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8971 if (displayIdleForDemandSleep
) {
8972 return kOSBooleanTrue
;
8975 return kOSBooleanFalse
;
8979 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8981 OSArray
* array
= 0;
8983 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8984 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8985 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8986 collection
->release();
8993 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8995 OSArray
* array
= 0;
8996 IOLockLock(pmStatsLock
);
8997 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8998 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8999 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
9000 collection
->release();
9002 pmStatsAppResponses
->flushCollection();
9004 IOLockUnlock(pmStatsLock
);
9008 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
9010 OSArray
*idleSleepList
= NULL
;
9011 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
9012 return idleSleepList
;
9015 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
9017 OSArray
*systemSleepList
= NULL
;
9018 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
9019 return systemSleepList
;
9026 // MARK: Wake Event Reporting
9028 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
9031 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
9035 //******************************************************************************
9036 // acceptSystemWakeEvents
9038 // Private control for the acceptance of driver wake event claims.
9039 //******************************************************************************
9041 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
9043 bool logWakeReason
= false;
9048 gWakeReasonString
[0] = '\0';
9049 if (!_systemWakeEventsArray
)
9050 _systemWakeEventsArray
= OSArray::withCapacity(4);
9051 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
9052 _systemWakeEventsArray
->flushCollection();
9056 _acceptSystemWakeEvents
= false;
9058 logWakeReason
= gWakeReasonSysctlRegistered
;
9060 static int panic_allowed
= -1;
9062 if ((panic_allowed
== -1) &&
9063 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
9067 if (panic_allowed
) {
9069 // Panic if wake reason is null or empty
9070 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
9071 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t'))
9074 if (i
>= strlen(gWakeReasonString
)) {
9075 panic("Wake reason is empty\n");
9084 MSG("system wake events:%s\n", gWakeReasonString
);
9087 //******************************************************************************
9088 // claimSystemWakeEvent
9090 // For a driver to claim a device is the source/conduit of a system wake event.
9091 //******************************************************************************
9093 void IOPMrootDomain::claimSystemWakeEvent(
9096 const char * reason
,
9097 OSObject
* details
)
9099 const OSSymbol
* deviceName
= 0;
9100 OSNumber
* deviceRegId
= 0;
9101 OSNumber
* claimTime
= 0;
9102 OSData
* flagsData
= 0;
9103 OSString
* reasonString
= 0;
9104 OSDictionary
* d
= 0;
9108 pmEventTimeStamp(×tamp
);
9110 if (!device
|| !reason
) return;
9112 deviceName
= device
->copyName(gIOServicePlane
);
9113 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
9114 claimTime
= OSNumber::withNumber(timestamp
, 64);
9115 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
9116 reasonString
= OSString::withCString(reason
);
9117 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
9118 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
9121 d
->setObject(gIONameKey
, deviceName
);
9122 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
9123 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
9124 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
9125 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
9127 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
9130 if (!gWakeReasonSysctlRegistered
)
9132 // Lazy registration until the platform driver stops registering
9134 gWakeReasonSysctlRegistered
= true;
9136 sysctl_register_oid(&sysctl__kern_wakereason
);
9139 if (_acceptSystemWakeEvents
)
9141 ok
= _systemWakeEventsArray
->setObject(d
);
9142 if (gWakeReasonString
[0] != '\0')
9143 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
9144 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
9149 if (deviceName
) deviceName
->release();
9150 if (deviceRegId
) deviceRegId
->release();
9151 if (claimTime
) claimTime
->release();
9152 if (flagsData
) flagsData
->release();
9153 if (reasonString
) reasonString
->release();
9154 if (d
) d
->release();
9157 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9160 // MARK: PMSettingHandle
9162 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
9164 void PMSettingHandle::free( void )
9168 pmso
->clientHandleFreed();
9177 // MARK: PMSettingObject
9180 #define super OSObject
9181 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
9184 * Static constructor/initializer for PMSettingObject
9186 PMSettingObject
*PMSettingObject::pmSettingObject(
9187 IOPMrootDomain
*parent_arg
,
9188 IOPMSettingControllerCallback handler_arg
,
9189 OSObject
*target_arg
,
9190 uintptr_t refcon_arg
,
9191 uint32_t supportedPowerSources
,
9192 const OSSymbol
* settings
[],
9193 OSObject
**handle_obj
)
9195 uint32_t settingCount
= 0;
9196 PMSettingObject
*pmso
= 0;
9197 PMSettingHandle
*pmsh
= 0;
9199 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
9202 // count OSSymbol entries in NULL terminated settings array
9203 while (settings
[settingCount
]) {
9206 if (0 == settingCount
)
9209 pmso
= new PMSettingObject
;
9210 if (!pmso
|| !pmso
->init())
9213 pmsh
= new PMSettingHandle
;
9214 if (!pmsh
|| !pmsh
->init())
9217 queue_init(&pmso
->calloutQueue
);
9218 pmso
->parent
= parent_arg
;
9219 pmso
->func
= handler_arg
;
9220 pmso
->target
= target_arg
;
9221 pmso
->refcon
= refcon_arg
;
9222 pmso
->settingCount
= settingCount
;
9224 pmso
->retain(); // handle holds a retain on pmso
9228 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
9229 if (pmso
->publishedFeatureID
) {
9230 for (unsigned int i
=0; i
<settingCount
; i
++) {
9231 // Since there is now at least one listener to this setting, publish
9232 // PM root domain support for it.
9233 parent_arg
->publishPMSetting( settings
[i
],
9234 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
9242 if (pmso
) pmso
->release();
9243 if (pmsh
) pmsh
->release();
9247 void PMSettingObject::free( void )
9249 if (publishedFeatureID
) {
9250 for (uint32_t i
=0; i
<settingCount
; i
++) {
9251 if (publishedFeatureID
[i
]) {
9252 parent
->removePublishedFeature( publishedFeatureID
[i
] );
9256 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
9262 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
9264 (*func
)(target
, type
, object
, refcon
);
9267 void PMSettingObject::clientHandleFreed( void )
9269 parent
->deregisterPMSettingObject(this);
9273 // MARK: PMAssertionsTracker
9275 //*********************************************************************************
9276 //*********************************************************************************
9277 //*********************************************************************************
9278 // class PMAssertionsTracker Implementation
9280 #define kAssertUniqueIDStart 500
9282 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
9284 PMAssertionsTracker
*myself
;
9286 myself
= new PMAssertionsTracker
;
9290 myself
->owner
= rootDomain
;
9291 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
9292 myself
->assertionsArray
= OSArray::withCapacity(5);
9293 myself
->assertionsKernel
= 0;
9294 myself
->assertionsUser
= 0;
9295 myself
->assertionsCombined
= 0;
9296 myself
->assertionsArrayLock
= IOLockAlloc();
9297 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
9299 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
9307 * - Update assertionsKernel to reflect the state of all
9308 * assertions in the kernel.
9309 * - Update assertionsCombined to reflect both kernel & user space.
9311 void PMAssertionsTracker::tabulate(void)
9315 PMAssertStruct
*_a
= NULL
;
9318 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
9319 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
9323 assertionsKernel
= 0;
9324 assertionsCombined
= 0;
9326 if (!assertionsArray
)
9329 if ((count
= assertionsArray
->getCount()))
9331 for (i
=0; i
<count
; i
++)
9333 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9336 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9337 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
9338 assertionsKernel
|= _a
->assertionBits
;
9343 tabulateProducerCount
++;
9344 assertionsCombined
= assertionsKernel
| assertionsUser
;
9346 if ((assertionsKernel
!= oldKernel
) ||
9347 (assertionsCombined
!= oldCombined
))
9349 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
9353 void PMAssertionsTracker::publishProperties( void )
9355 OSArray
*assertionsSummary
= NULL
;
9357 if (tabulateConsumerCount
!= tabulateProducerCount
)
9359 IOLockLock(assertionsArrayLock
);
9361 tabulateConsumerCount
= tabulateProducerCount
;
9363 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9365 assertionsSummary
= copyAssertionsArray();
9366 if (assertionsSummary
)
9368 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
9369 assertionsSummary
->release();
9373 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
9376 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9378 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
9380 IOLockUnlock(assertionsArrayLock
);
9384 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
9386 PMAssertStruct
*_a
= NULL
;
9393 && (count
= assertionsArray
->getCount()))
9395 for (i
=0; i
<count
; i
++)
9397 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9400 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9401 if (_a
&& (_id
== _a
->id
)) {
9418 /* PMAssertionsTracker::handleCreateAssertion
9419 * Perform assertion work on the PM workloop. Do not call directly.
9421 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
9427 IOLockLock(assertionsArrayLock
);
9428 assertionsArray
->setObject(newAssertion
);
9429 IOLockUnlock(assertionsArrayLock
);
9430 newAssertion
->release();
9434 return kIOReturnSuccess
;
9437 /* PMAssertionsTracker::createAssertion
9438 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9441 IOReturn
PMAssertionsTracker::createAssertion(
9442 IOPMDriverAssertionType which
,
9443 IOPMDriverAssertionLevel level
,
9444 IOService
*serviceID
,
9445 const char *whoItIs
,
9446 IOPMDriverAssertionID
*outID
)
9448 OSData
*dataStore
= NULL
;
9449 PMAssertStruct track
;
9451 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9452 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9453 track
.level
= level
;
9454 track
.assertionBits
= which
;
9455 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9456 track
.ownerService
= serviceID
;
9457 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9458 track
.modifiedTime
= 0;
9459 pmEventTimeStamp(&track
.createdTime
);
9461 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9464 if (track
.ownerString
)
9465 track
.ownerString
->release();
9466 return kIOReturnNoMemory
;
9471 if (owner
&& owner
->pmPowerStateQueue
) {
9472 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9475 return kIOReturnSuccess
;
9478 /* PMAssertionsTracker::handleReleaseAssertion
9479 * Runs in PM workloop. Do not call directly.
9481 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9482 IOPMDriverAssertionID _id
)
9487 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9490 return kIOReturnNotFound
;
9492 IOLockLock(assertionsArrayLock
);
9493 if (assertStruct
->ownerString
)
9494 assertStruct
->ownerString
->release();
9496 assertionsArray
->removeObject(index
);
9497 IOLockUnlock(assertionsArrayLock
);
9500 return kIOReturnSuccess
;
9503 /* PMAssertionsTracker::releaseAssertion
9504 * Releases an assertion and affects system behavior if appropiate.
9505 * Actual work happens on PM workloop.
9507 IOReturn
PMAssertionsTracker::releaseAssertion(
9508 IOPMDriverAssertionID _id
)
9510 if (owner
&& owner
->pmPowerStateQueue
) {
9511 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9513 return kIOReturnSuccess
;
9516 /* PMAssertionsTracker::handleSetAssertionLevel
9517 * Runs in PM workloop. Do not call directly.
9519 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9520 IOPMDriverAssertionID _id
,
9521 IOPMDriverAssertionLevel _level
)
9523 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9527 if (!assertStruct
) {
9528 return kIOReturnNotFound
;
9531 IOLockLock(assertionsArrayLock
);
9532 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9533 assertStruct
->level
= _level
;
9534 IOLockUnlock(assertionsArrayLock
);
9537 return kIOReturnSuccess
;
9540 /* PMAssertionsTracker::setAssertionLevel
9542 IOReturn
PMAssertionsTracker::setAssertionLevel(
9543 IOPMDriverAssertionID _id
,
9544 IOPMDriverAssertionLevel _level
)
9546 if (owner
&& owner
->pmPowerStateQueue
) {
9547 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9548 (void *)(uintptr_t)_level
, _id
);
9551 return kIOReturnSuccess
;
9554 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9556 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9560 if (new_user_levels
!= assertionsUser
)
9562 assertionsUser
= new_user_levels
;
9563 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9567 return kIOReturnSuccess
;
9570 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9571 IOPMDriverAssertionType new_user_levels
)
9573 if (gIOPMWorkLoop
) {
9574 gIOPMWorkLoop
->runAction(
9575 OSMemberFunctionCast(
9578 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9580 (void *) &new_user_levels
, 0, 0, 0);
9583 return kIOReturnSuccess
;
9587 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9591 OSArray
*outArray
= NULL
;
9593 if (!assertionsArray
||
9594 (0 == (count
= assertionsArray
->getCount())) ||
9595 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9600 for (i
=0; i
<count
; i
++)
9602 PMAssertStruct
*_a
= NULL
;
9604 OSDictionary
*details
= NULL
;
9606 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9607 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9609 OSNumber
*_n
= NULL
;
9611 details
= OSDictionary::withCapacity(7);
9615 outArray
->setObject(details
);
9618 _n
= OSNumber::withNumber(_a
->id
, 64);
9620 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9623 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9625 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9628 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9630 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9633 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9635 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9638 _n
= OSNumber::withNumber(_a
->level
, 64);
9640 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9643 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9645 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9649 if (_a
->ownerString
) {
9650 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9659 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9661 return assertionsCombined
;
9664 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9665 IOPMDriverAssertionType type
)
9667 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9669 return kIOPMDriverAssertionLevelOn
;
9671 return kIOPMDriverAssertionLevelOff
;
9675 //*********************************************************************************
9676 //*********************************************************************************
9677 //*********************************************************************************
9680 static void pmEventTimeStamp(uint64_t *recordTS
)
9688 // We assume tsec fits into 32 bits; 32 bits holds enough
9689 // seconds for 136 years since the epoch in 1970.
9690 clock_get_calendar_microtime(&tsec
, &tusec
);
9693 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9695 *recordTS
|= (uint32_t)tusec
;
9696 *recordTS
|= ((uint64_t)tsec
<< 32);
9702 // MARK: IORootParent
9704 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9706 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9708 // The reason that root domain needs a root parent is to facilitate demand
9709 // sleep, since a power change from the root parent cannot be vetoed.
9711 // The above statement is no longer true since root domain now performs
9712 // demand sleep using overrides. But root parent remains to avoid changing
9713 // the power tree stacking. Root parent is parked at the max power state.
9716 static IOPMPowerState patriarchPowerStates
[2] =
9718 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9719 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9722 void IORootParent::initialize( void )
9726 bool IORootParent::start( IOService
* nub
)
9728 IOService::start(nub
);
9729 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9731 registerPowerDriver(this, patriarchPowerStates
, 2);
9736 void IORootParent::shutDownSystem( void )
9740 void IORootParent::restartSystem( void )
9744 void IORootParent::sleepSystem( void )
9748 void IORootParent::dozeSystem( void )
9752 void IORootParent::sleepToDoze( void )
9756 void IORootParent::wakeSystem( void )
9760 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9762 return (IOService::copyProperty(aKey
));
9766 #if defined(__i386__) || defined(__x86_64__)
9767 IOReturn
IOPMrootDomain::restartWithStackshot()
9769 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9770 return kIOReturnError
;
9772 takeStackshot(true, true, false);
9774 return kIOReturnSuccess
;
9777 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9779 takeStackshot(wdogTrigger
, false, false);
9782 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9784 swd_hdr
* hdr
= NULL
;
9786 int wdog_panic
= -1;
9787 int stress_rack
= -1;
9790 kern_return_t kr
= KERN_SUCCESS
;
9795 uint32_t bytesRemaining
;
9796 unsigned bytesWritten
= 0;
9797 unsigned totalBytes
= 0;
9799 OSString
* UUIDstring
= NULL
;
9801 IOMemoryMap
* logBufMap
= NULL
;
9805 uint32_t initialStackSize
;
9808 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9809 _systemTransitionType
!= kSystemTransitionWake
)
9812 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9817 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9818 PE_parse_boot_argn("stress-rack", &stress_rack
, sizeof(stress_rack
));
9819 if ((wdog_panic
== 1) || (stress_rack
== 1) || (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
9820 // If boot-arg specifies to panic then panic.
9821 panic("Sleep/Wake hang detected");
9824 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9825 // If current boot is due to this watch dog trigger restart in previous boot,
9826 // then don't trigger again until at least 1 successful sleep & wake.
9827 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9828 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9829 if (!tasksSuspended
) {
9830 tasksSuspended
= TRUE
;
9831 tasks_system_suspend(true);
9833 PEHaltRestart(kPEHaltCPU
);
9841 if (gSpinDumpBufferFull
)
9843 if (swd_spindump_buffer
== NULL
) {
9844 sleepWakeDebugSpinDumpMemAlloc();
9845 if (swd_spindump_buffer
== NULL
) return;
9848 bufSize
= SWD_SPINDUMP_SIZE
;
9849 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9851 if (sleepWakeDebugIsWdogEnabled() == false)
9854 if (swd_buffer
== NULL
) {
9855 sleepWakeDebugMemAlloc();
9856 if (swd_buffer
== NULL
) return;
9859 bufSize
= SWD_BUF_SIZE
;
9860 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9863 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9867 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9870 hdr
= (swd_hdr
*)swd_buffer
;
9873 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9874 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9876 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9877 const char *str
= UUIDstring
->getCStringNoCopy();
9878 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9881 DLOG("Data for current UUID already exists\n");
9886 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9887 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9889 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9890 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9892 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9894 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9895 while (kr
== KERN_SUCCESS
) {
9899 * Take stackshot of all process on first sample. Size is restricted
9900 * to SWD_INITIAL_STACK_SIZE
9903 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9904 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9907 /* Take sample of kernel threads only */
9909 size
= bytesRemaining
;
9912 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9913 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9914 kr
, pid
, size
, flags
, bytesWritten
);
9915 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9917 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9918 // Continue to take stackshot of just kernel threads
9923 else if (totalBytes
== 0) {
9924 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9928 dstAddr
+= bytesWritten
;
9929 totalBytes
+= bytesWritten
;
9930 bytesRemaining
-= bytesWritten
;
9935 IOSleep(10); // 10 ms
9938 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9941 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9942 code
= pmTracer
->getPMStatusCode();
9943 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9944 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9945 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9946 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9948 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9949 gRootDomain
->swd_lock
= 0;
9950 gSpinDumpBufferFull
= true;
9953 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9956 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9957 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9958 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9959 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9960 len
= sizeof(addr64_t
)*3;
9961 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9962 data
[0], data
[1], data
[2]);
9964 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9966 DLOG("Failed to update nvram boot-args\n");
9972 gRootDomain
->swd_lock
= 0;
9975 IOLog("Restarting to collect Sleep wake debug logs\n");
9976 if (!tasksSuspended
) {
9977 tasksSuspended
= TRUE
;
9978 tasks_system_suspend(true);
9981 PEHaltRestart(kPERestartCPU
);
9984 logBufMap
= sleepWakeDebugRetrieve();
9986 sleepWakeDebugDumpFromMem(logBufMap
);
9987 logBufMap
->release();
9993 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9995 vm_size_t size
= SWD_BUF_SIZE
;
9997 swd_hdr
*hdr
= NULL
;
9999 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10002 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
10005 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)
10008 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10011 // Try allocating above 4GB. If that fails, try at 2GB
10012 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
10013 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
10014 size
, 0xFFFFFFFF00000000ULL
);
10016 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
10017 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
10018 size
, 0xFFFFFFFF10000000ULL
);
10021 if (memDesc
== NULL
)
10023 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
10028 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
10029 memset(hdr
, 0, sizeof(swd_hdr
));
10031 hdr
->signature
= SWD_HDR_SIGNATURE
;
10032 hdr
->alloc_size
= size
;
10034 hdr
->spindump_offset
= sizeof(swd_hdr
);
10035 swd_buffer
= (void *)hdr
;
10036 swd_memDesc
= memDesc
;
10037 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
10040 gRootDomain
->swd_lock
= 0;
10043 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
10045 vm_size_t size
= SWD_SPINDUMP_SIZE
;
10047 swd_hdr
*hdr
= NULL
;
10049 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10051 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10054 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
10055 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
10056 SWD_SPINDUMP_SIZE
);
10058 if (memDesc
== NULL
)
10060 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
10065 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
10066 memset(hdr
, 0, sizeof(swd_hdr
));
10068 hdr
->signature
= SWD_HDR_SIGNATURE
;
10069 hdr
->alloc_size
= size
;
10071 hdr
->spindump_offset
= sizeof(swd_hdr
);
10072 swd_spindump_buffer
= (void *)hdr
;
10075 gRootDomain
->swd_lock
= 0;
10078 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10080 swd_flags
|= SWD_WDOG_ENABLED
;
10082 sleepWakeDebugMemAlloc();
10085 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10087 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
10088 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
10091 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
10093 swd_hdr
*hdr
= NULL
;
10094 errno_t error
= EIO
;
10096 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
10097 hdr
= (swd_hdr
*)swd_spindump_buffer
;
10099 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
10100 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
10104 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
10105 (char*)hdr
+offsetof(swd_hdr
, UUID
),
10106 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
10108 gSpinDumpBufferFull
= false;
10112 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
10114 struct vnode
*vp
= NULL
;
10115 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10116 kauth_cred_t cred
= vfs_context_ucred(ctx
);
10117 struct vnode_attr va
;
10118 errno_t error
= EIO
;
10120 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10121 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10123 IOLog("Failed to open the file %s\n", name
);
10124 swd_flags
|= SWD_FILEOP_ERROR
;
10128 VATTR_WANTED(&va
, va_nlink
);
10129 /* Don't dump to non-regular files or files with links. */
10130 if (vp
->v_type
!= VREG
||
10131 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10132 IOLog("Bailing as this is not a regular file\n");
10133 swd_flags
|= SWD_FILEOP_ERROR
;
10137 VATTR_SET(&va
, va_data_size
, 0);
10138 vnode_setattr(vp
, &va
, ctx
);
10142 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
10143 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
10145 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
10146 swd_flags
|= SWD_FILEOP_ERROR
;
10149 DLOG("Saved %d bytes to file %s\n",len
, name
);
10154 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
10155 if (ctx
) vfs_context_rele(ctx
);
10161 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10162 struct vnode
*srcVp
,
10163 vfs_context_t srcCtx
,
10164 char *tmpBuf
, uint64_t tmpBufSize
,
10165 uint64_t srcOffset
,
10166 const char *dstFname
,
10170 struct vnode
*vp
= NULL
;
10171 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10172 struct vnode_attr va
;
10173 errno_t error
= EIO
;
10174 uint64_t bytesToRead
, bytesToWrite
;
10175 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
10176 uint32_t newcrc
= 0;
10178 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10179 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10181 IOLog("Failed to open the file %s\n", dstFname
);
10182 swd_flags
|= SWD_FILEOP_ERROR
;
10186 VATTR_WANTED(&va
, va_nlink
);
10187 /* Don't dump to non-regular files or files with links. */
10188 if (vp
->v_type
!= VREG
||
10189 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10190 IOLog("Bailing as this is not a regular file\n");
10191 swd_flags
|= SWD_FILEOP_ERROR
;
10195 VATTR_SET(&va
, va_data_size
, 0);
10196 vnode_setattr(vp
, &va
, ctx
);
10198 writeFileOffset
= 0;
10200 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
10201 readFileOffset
= trunc_page(srcOffset
);
10203 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
10204 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
10205 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10206 vfs_context_ucred(srcCtx
), (int *) 0,
10207 vfs_context_proc(srcCtx
));
10209 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
10210 swd_flags
|= SWD_FILEOP_ERROR
;
10214 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
10215 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
10216 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
10219 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
10221 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
10222 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
10223 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
10224 vfs_context_ucred(ctx
), (int *) 0,
10225 vfs_context_proc(ctx
));
10227 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
10228 swd_flags
|= SWD_FILEOP_ERROR
;
10232 writeFileOffset
+= bytesToWrite
;
10233 numBytes
-= bytesToWrite
;
10234 srcOffset
+= bytesToWrite
;
10237 if (crc
!= newcrc
) {
10238 /* Set stackshot size to 0 if crc doesn't match */
10240 VATTR_SET(&va
, va_data_size
, 0);
10241 vnode_setattr(vp
, &va
, ctx
);
10243 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
10244 swd_flags
|= SWD_DATA_CRC_ERROR
;
10249 error
= vnode_close(vp
, FWRITE
, ctx
);
10250 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
10252 if (ctx
) vfs_context_rele(ctx
);
10259 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
10260 void *tmpBuf
, struct vnode
**vp
)
10263 uint64_t hdrOffset
;
10264 uint32_t error
= 0;
10266 struct vnode_attr va
;
10267 IOHibernateImageHeader
*imageHdr
;
10270 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
10271 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
10273 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
10277 VATTR_WANTED(&va
, va_nlink
);
10278 VATTR_WANTED(&va
, va_data_alloc
);
10279 if ((*vp
)->v_type
!= VREG
||
10280 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
10281 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
10282 error
= SWD_FILEOP_ERROR
;
10286 /* Read the sleepimage file header */
10287 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
10288 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10289 vfs_context_ucred(*ctx
), (int *) 0,
10290 vfs_context_proc(*ctx
));
10292 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %llu(rc=%d) from %s\n",
10293 mach_vm_round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
10294 error
= SWD_FILEOP_ERROR
;
10298 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
10299 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
10300 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
10301 fname
, imageHdr
->signature
);
10302 error
= SWD_HDR_SIGNATURE_ERROR
;
10306 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
10307 hdrOffset
= imageHdr
->deviceBlockSize
;
10308 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
10309 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
10310 va
.va_data_alloc
, fname
);
10311 error
= SWD_HDR_SIZE_ERROR
;
10318 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
10324 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
10328 char hibernateFilename
[MAXPATHLEN
+1];
10330 swd_hdr
*hdr
= NULL
;
10331 uint32_t stacksSize
, logSize
;
10332 uint64_t tmpBufSize
;
10333 uint64_t hdrOffset
, stacksOffset
, logOffset
;
10334 errno_t error
= EIO
;
10335 OSObject
*obj
= NULL
;
10336 OSString
*str
= NULL
;
10337 OSNumber
*failStat
= NULL
;
10338 struct vnode
*vp
= NULL
;
10339 vfs_context_t ctx
= NULL
;
10340 const char *stacksFname
, *logFname
;
10342 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
10344 DLOG("sleepWakeDebugDumpFromFile\n");
10345 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
10348 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10352 /* Allocate a temp buffer to copy data between files */
10353 tmpBufSize
= 2*4096;
10354 tmpBufDesc
= IOBufferMemoryDescriptor::
10355 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
10356 tmpBufSize
, PAGE_SIZE
);
10359 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
10363 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
10365 ctx
= vfs_context_create(vfs_context_current());
10367 /* First check if 'kSleepWakeStackBinFilename' has valid data */
10368 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
10370 /* Check if the debug data is saved to hibernation file */
10371 hibernateFilename
[0] = 0;
10372 if ((obj
= copyProperty(kIOHibernateFileKey
)))
10374 if ((str
= OSDynamicCast(OSString
, obj
)))
10375 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
10376 sizeof(hibernateFilename
));
10379 if (!hibernateFilename
[0]) {
10380 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
10384 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
10386 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
10389 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
10392 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
10395 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
10397 DLOG("Reading swd_hdr len 0x%llx offset 0x%lx\n", mach_vm_round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
10398 /* Read the sleep/wake debug header(swd_hdr) */
10399 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
10400 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10401 vfs_context_ucred(ctx
), (int *) 0,
10402 vfs_context_proc(ctx
));
10404 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %llu. rc=%d\n",
10405 mach_vm_round_page(sizeof(swd_hdr
)), rc
);
10406 swd_flags
|= SWD_FILEOP_ERROR
;
10410 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
10411 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
10412 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
10413 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
10414 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
10415 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10418 stacksSize
= hdr
->spindump_size
;
10420 /* Get stacks & log offsets in the image file */
10421 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
10422 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
10423 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10424 stacksFname
= getDumpStackFilename(hdr
);
10425 logFname
= getDumpLogFilename(hdr
);
10427 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
10428 stacksFname
, stacksSize
, hdr
->crc
);
10429 if (error
== EFAULT
) {
10430 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
10433 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
10434 logFname
, logSize
, 0);
10436 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
10441 // Write just the SleepWakeLog.dump with failure code
10442 uint64_t fcode
= 0;
10445 char *offset
= NULL
;
10449 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10450 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10451 fcode
= failStat
->unsigned64BitValue();
10452 fname
= kSleepWakeLogFilename
;
10455 fname
= kAppleOSXWatchdogLogFilename
;
10458 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10459 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10460 memset(offset
, 0x20, size
); // Fill with spaces
10463 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10464 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10465 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10466 sleepWakeDebugSaveFile(fname
, offset
, size
);
10469 gRootDomain
->swd_lock
= 0;
10471 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10472 if (ctx
) vfs_context_rele(ctx
);
10473 if (tmpBufDesc
) tmpBufDesc
->release();
10474 #endif /* HIBERNATION */
10477 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10479 IOVirtualAddress srcBuf
= NULL
;
10480 char *stackBuf
= NULL
, *logOffset
= NULL
;
10483 errno_t error
= EIO
;
10484 uint64_t bufSize
= 0;
10485 swd_hdr
*hdr
= NULL
;
10486 OSNumber
*failStat
= NULL
;
10488 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10491 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10493 DLOG("Nothing saved to dump to file\n");
10497 hdr
= (swd_hdr
*)srcBuf
;
10498 bufSize
= logBufMap
->getLength();
10499 if (bufSize
<= sizeof(swd_hdr
))
10501 IOLog("SleepWake log buffer size is invalid\n");
10502 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10506 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10508 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10509 if (error
) goto exit
;
10511 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10512 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10514 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10515 if (error
) goto exit
;
10517 hdr
->spindump_size
= 0;
10522 // Write just the SleepWakeLog.dump with failure code
10523 uint64_t fcode
= 0;
10524 const char *sname
, *lname
;
10527 /* Try writing an empty stacks file */
10529 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10530 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10531 fcode
= failStat
->unsigned64BitValue();
10532 lname
= kSleepWakeLogFilename
;
10533 sname
= kSleepWakeStackFilename
;
10536 lname
= kAppleOSXWatchdogLogFilename
;
10537 sname
= kAppleOSXWatchdogStackFilename
;
10540 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10542 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10543 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10544 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10547 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10548 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10549 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10550 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10553 gRootDomain
->swd_lock
= 0;
10556 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10558 IOVirtualAddress vaddr
= NULL
;
10559 IOMemoryDescriptor
* desc
= NULL
;
10560 IOMemoryMap
* logBufMap
= NULL
;
10562 uint32_t len
= INT_MAX
;
10564 uint64_t bufSize
= 0;
10566 uint64_t newcrc
= 0;
10567 uint64_t paddr
= 0;
10568 swd_hdr
*hdr
= NULL
;
10573 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10576 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10577 DLOG("No sleepWakeDebug note to read\n");
10581 if (len
== strlen("sleepimage")) {
10583 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10585 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10586 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10587 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10591 else if (len
== sizeof(addr64_t
)*3) {
10592 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10595 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10601 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10602 data
[0], data
[1], data
[2]);
10603 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10607 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10609 IOLog("SleepWake log buffer size is invalid\n");
10610 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10614 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10615 bufSize
, crc
, paddr
);
10618 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10619 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10622 IOLog("Fail to map SleepWake log buffer\n");
10623 swd_flags
|= SWD_INTERNAL_FAILURE
;
10627 logBufMap
= desc
->map();
10629 vaddr
= logBufMap
->getVirtualAddress();
10632 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10633 IOLog("Fail to map SleepWake log buffer\n");
10634 swd_flags
|= SWD_INTERNAL_FAILURE
;
10638 hdr
= (swd_hdr
*)vaddr
;
10639 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10641 IOLog("SleepWake log header size is invalid\n");
10642 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10647 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10648 hdr
->spindump_size
);
10649 if (newcrc
!= crc
) {
10650 IOLog("SleepWake log buffer contents are invalid\n");
10651 swd_flags
|= SWD_DATA_CRC_ERROR
;
10656 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10660 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10662 if (logBufMap
) logBufMap
->release();
10665 if (desc
) desc
->release();
10666 gRootDomain
->swd_lock
= 0;
10673 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10675 uint32_t wdog_panic
= 1;
10678 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10679 (wdog_panic
== 0)) {
10682 panic("Sleep/Wake hang detected");
10687 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10689 #pragma unused(restart)
10690 #pragma unused(isOSXWatchdog)
10693 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10696 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10699 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10700 struct vnode
*srcVp
,
10701 vfs_context_t srcCtx
,
10702 char *tmpBuf
, uint64_t tmpBufSize
,
10703 uint64_t srcOffset
,
10704 const char *dstFname
,
10711 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10715 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10720 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10724 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10729 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)