]> git.saurik.com Git - apple/xnu.git/blame_incremental - iokit/Kernel/IOPMrootDomain.cpp
xnu-3789.60.24.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
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"
51#if HIBERNATION
52#include <IOKit/IOHibernatePrivate.h>
53#endif
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>
60
61#include <sys/time.h>
62#include "IOServicePrivate.h" // _IOServiceInterestNotifier
63#include "IOServicePMPrivate.h"
64
65__BEGIN_DECLS
66#include <mach/shared_region.h>
67#include <kern/clock.h>
68__END_DECLS
69
70#if defined(__i386__) || defined(__x86_64__)
71__BEGIN_DECLS
72#include "IOPMrootDomainInternal.h"
73__END_DECLS
74#endif
75
76#define kIOPMrootDomainClass "IOPMrootDomain"
77#define LOG_PREFIX "PMRD: "
78
79
80#define MSG(x...) \
81 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
82
83#define LOG(x...) \
84 do { kprintf(LOG_PREFIX x); } while (false)
85
86#define DLOG(x...) do { \
87 if (kIOLogPMRootDomain & gIOKitDebug) \
88 kprintf(LOG_PREFIX x); \
89} while (false)
90
91#define DMSG(x...) do { \
92 if (kIOLogPMRootDomain & gIOKitDebug) { \
93 kprintf(LOG_PREFIX x); IOLog(x); \
94 } \
95} while (false)
96
97
98#define _LOG(x...)
99
100#define CHECK_THREAD_CONTEXT
101#ifdef CHECK_THREAD_CONTEXT
102static IOWorkLoop * gIOPMWorkLoop = 0;
103#define ASSERT_GATED() \
104do { \
105 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
106 panic("RootDomain: not inside PM gate"); \
107 } \
108} while(false)
109#else
110#define ASSERT_GATED()
111#endif /* CHECK_THREAD_CONTEXT */
112
113#define CAP_LOSS(c) \
114 (((_pendingCapability & (c)) == 0) && \
115 ((_currentCapability & (c)) != 0))
116
117#define CAP_GAIN(c) \
118 (((_currentCapability & (c)) == 0) && \
119 ((_pendingCapability & (c)) != 0))
120
121#define CAP_CHANGE(c) \
122 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
123
124#define CAP_CURRENT(c) \
125 ((_currentCapability & (c)) != 0)
126
127#define CAP_HIGHEST(c) \
128 ((_highestCapability & (c)) != 0)
129
130#if defined(__i386__) || defined(__x86_64__)
131#define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
132#endif
133
134// Event types for IOPMPowerStateQueue::submitPowerEvent()
135enum {
136 kPowerEventFeatureChanged = 1, // 1
137 kPowerEventReceivedPowerNotification, // 2
138 kPowerEventSystemBootCompleted, // 3
139 kPowerEventSystemShutdown, // 4
140 kPowerEventUserDisabledSleep, // 5
141 kPowerEventRegisterSystemCapabilityClient, // 6
142 kPowerEventRegisterKernelCapabilityClient, // 7
143 kPowerEventPolicyStimulus, // 8
144 kPowerEventAssertionCreate, // 9
145 kPowerEventAssertionRelease, // 10
146 kPowerEventAssertionSetLevel, // 11
147 kPowerEventQueueSleepWakeUUID, // 12
148 kPowerEventPublishSleepWakeUUID, // 13
149 kPowerEventSetDisplayPowerOn // 14
150};
151
152// For evaluatePolicy()
153// List of stimuli that affects the root domain policy.
154enum {
155 kStimulusDisplayWranglerSleep, // 0
156 kStimulusDisplayWranglerWake, // 1
157 kStimulusAggressivenessChanged, // 2
158 kStimulusDemandSystemSleep, // 3
159 kStimulusAllowSystemSleepChanged, // 4
160 kStimulusDarkWakeActivityTickle, // 5
161 kStimulusDarkWakeEntry, // 6
162 kStimulusDarkWakeReentry, // 7
163 kStimulusDarkWakeEvaluate, // 8
164 kStimulusNoIdleSleepPreventers, // 9
165 kStimulusEnterUserActiveState, // 10
166 kStimulusLeaveUserActiveState // 11
167};
168
169extern "C" {
170IOReturn OSKextSystemSleepOrWake( UInt32 );
171}
172extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
173extern "C" addr64_t kvtophys(vm_offset_t va);
174
175static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
176static void notifySystemShutdown( IOService * root, uint32_t messageType );
177static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
178static void pmEventTimeStamp(uint64_t *recordTS);
179
180// "IOPMSetSleepSupported" callPlatformFunction name
181static const OSSymbol *sleepSupportedPEFunction = NULL;
182static const OSSymbol *sleepMessagePEFunction = NULL;
183
184#define kIOSleepSupportedKey "IOSleepSupported"
185#define kIOPMSystemCapabilitiesKey "System Capabilities"
186
187#define kIORequestWranglerIdleKey "IORequestIdle"
188#define kDefaultWranglerIdlePeriod 25 // in milliseconds
189
190#define kIOSleepWakeDebugKey "Persistent-memory-note"
191#define kIOEFIBootRomFailureKey "wake-failure"
192
193#define kRD_AllPowerSources (kIOPMSupportedOnAC \
194 | kIOPMSupportedOnBatt \
195 | kIOPMSupportedOnUPS)
196
197#define kLocalEvalClamshellCommand (1 << 15)
198#define kIdleSleepRetryInterval (3 * 60)
199
200enum {
201 kWranglerPowerStateMin = 0,
202 kWranglerPowerStateSleep = 2,
203 kWranglerPowerStateDim = 3,
204 kWranglerPowerStateMax = 4
205};
206
207enum {
208 OFF_STATE = 0,
209 RESTART_STATE = 1,
210 SLEEP_STATE = 2,
211 ON_STATE = 3,
212 NUM_POWER_STATES
213};
214
215#define ON_POWER kIOPMPowerOn
216#define RESTART_POWER kIOPMRestart
217#define SLEEP_POWER kIOPMAuxPowerOn
218
219static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
220{
221 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
222 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
223 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
224 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
225};
226
227#define kIOPMRootDomainWakeTypeSleepService "SleepService"
228#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
229#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
230#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
231#define kIOPMRootDomainWakeTypeUser "User"
232#define kIOPMRootDomainWakeTypeAlarm "Alarm"
233#define kIOPMRootDomainWakeTypeNetwork "Network"
234#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
235#define kIOPMRootDomainWakeTypeNotification "Notification"
236#define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
237
238// Special interest that entitles the interested client from receiving
239// all system messages. Only used by powerd.
240//
241#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
242
243#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
244#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
245
246/*
247 * Aggressiveness
248 */
249#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
250#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
251
252#define kAggressivesMinValue 1
253
254enum {
255 kAggressivesStateBusy = 0x01,
256 kAggressivesStateQuickSpindown = 0x02
257};
258
259struct AggressivesRecord {
260 uint32_t flags;
261 uint32_t type;
262 uint32_t value;
263};
264
265struct AggressivesRequest {
266 queue_chain_t chain;
267 uint32_t options;
268 uint32_t dataType;
269 union {
270 IOService * service;
271 AggressivesRecord record;
272 } data;
273};
274
275enum {
276 kAggressivesRequestTypeService = 1,
277 kAggressivesRequestTypeRecord
278};
279
280enum {
281 kAggressivesOptionSynchronous = 0x00000001,
282 kAggressivesOptionQuickSpindownEnable = 0x00000100,
283 kAggressivesOptionQuickSpindownDisable = 0x00000200,
284 kAggressivesOptionQuickSpindownMask = 0x00000300
285};
286
287enum {
288 kAggressivesRecordFlagModified = 0x00000001,
289 kAggressivesRecordFlagMinValue = 0x00000002
290};
291
292// gDarkWakeFlags
293enum {
294 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression
295 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression
296 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted
297 kDarkWakeFlagHIDTickleMask = 0x03,
298 kDarkWakeFlagAlarmIsDark = 0x0100,
299 kDarkWakeFlagGraphicsPowerState1 = 0x0200,
300 kDarkWakeFlagAudioNotSuppressed = 0x0400
301};
302
303static IOPMrootDomain * gRootDomain;
304static IONotifier * gSysPowerDownNotifier = 0;
305static UInt32 gSleepOrShutdownPending = 0;
306static UInt32 gWillShutdown = 0;
307static UInt32 gPagingOff = 0;
308static UInt32 gSleepWakeUUIDIsSet = false;
309static uint32_t gAggressivesState = 0;
310
311uuid_string_t bootsessionuuid_string;
312
313static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
314static uint32_t gNoIdleFlag = 0;
315static PMStatsStruct gPMStats;
316
317#if HIBERNATION
318static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0;
319static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
320static void * gSleepPolicyTarget;
321#endif
322
323struct timeval gIOLastSleepTime;
324struct timeval gIOLastWakeTime;
325
326static char gWakeReasonString[128];
327static bool gWakeReasonSysctlRegistered = false;
328static AbsoluteTime gIOLastWakeAbsTime;
329static AbsoluteTime gIOLastSleepAbsTime;
330
331#if defined(__i386__) || defined(__x86_64__)
332static bool gSpinDumpBufferFull = false;
333#endif
334
335static unsigned int gPMHaltBusyCount;
336static unsigned int gPMHaltIdleCount;
337static int gPMHaltDepth;
338static uint32_t gPMHaltMessageType;
339static IOLock * gPMHaltLock = 0;
340static OSArray * gPMHaltArray = 0;
341static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
342static bool gPMQuiesced;
343
344// Constants used as arguments to IOPMrootDomain::informCPUStateChange
345#define kCPUUnknownIndex 9999999
346enum {
347 kInformAC = 0,
348 kInformLid = 1,
349 kInformableCount = 2
350};
351
352const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
353const OSSymbol *gIOPMStatsApplicationResponseCancel;
354const OSSymbol *gIOPMStatsApplicationResponseSlow;
355const OSSymbol *gIOPMStatsApplicationResponsePrompt;
356const OSSymbol *gIOPMStatsDriverPSChangeSlow;
357
358#define kBadPMFeatureID 0
359
360/*
361 * PMSettingHandle
362 * Opaque handle passed to clients of registerPMSettingController()
363 */
364class PMSettingHandle : public OSObject
365{
366 OSDeclareFinalStructors( PMSettingHandle )
367 friend class PMSettingObject;
368
369private:
370 PMSettingObject *pmso;
371 void free(void) APPLE_KEXT_OVERRIDE;
372};
373
374/*
375 * PMSettingObject
376 * Internal object to track each PM setting controller
377 */
378class PMSettingObject : public OSObject
379{
380 OSDeclareFinalStructors( PMSettingObject )
381 friend class IOPMrootDomain;
382
383private:
384 queue_head_t calloutQueue;
385 thread_t waitThread;
386 IOPMrootDomain *parent;
387 PMSettingHandle *pmsh;
388 IOPMSettingControllerCallback func;
389 OSObject *target;
390 uintptr_t refcon;
391 uint32_t *publishedFeatureID;
392 uint32_t settingCount;
393 bool disabled;
394
395 void free(void) APPLE_KEXT_OVERRIDE;
396
397public:
398 static PMSettingObject *pmSettingObject(
399 IOPMrootDomain *parent_arg,
400 IOPMSettingControllerCallback handler_arg,
401 OSObject *target_arg,
402 uintptr_t refcon_arg,
403 uint32_t supportedPowerSources,
404 const OSSymbol *settings[],
405 OSObject **handle_obj);
406
407 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
408 void clientHandleFreed(void);
409};
410
411struct PMSettingCallEntry {
412 queue_chain_t link;
413 thread_t thread;
414};
415
416#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
417#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
418#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
419#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
420
421/*
422 * PMTraceWorker
423 * Internal helper object for logging trace points to RTC
424 * IOPMrootDomain and only IOPMrootDomain should instantiate
425 * exactly one of these.
426 */
427
428typedef void (*IOPMTracePointHandler)(
429 void * target, uint32_t code, uint32_t data );
430
431class PMTraceWorker : public OSObject
432{
433 OSDeclareDefaultStructors(PMTraceWorker)
434public:
435 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
436
437 static PMTraceWorker *tracer( IOPMrootDomain * );
438 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
439 void tracePoint(uint8_t phase);
440 void traceDetail(uint32_t detail);
441 void traceComponentWakeProgress(uint32_t component, uint32_t data);
442 int recordTopLevelPCIDevice(IOService *);
443 void RTC_TRACE(void);
444 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
445
446 IOPMTracePointHandler tracePointHandler;
447 void * tracePointTarget;
448 uint64_t getPMStatusCode();
449 uint8_t getTracePhase();
450 uint32_t getTraceData();
451private:
452 IOPMrootDomain *owner;
453 IOLock *pmTraceWorkerLock;
454 OSArray *pciDeviceBitMappings;
455
456 uint8_t addedToRegistry;
457 uint8_t tracePhase;
458 uint32_t traceData32;
459 uint8_t loginWindowData;
460 uint8_t coreDisplayData;
461 uint8_t coreGraphicsData;
462};
463
464/*
465 * PMAssertionsTracker
466 * Tracks kernel and user space PM assertions
467 */
468class PMAssertionsTracker : public OSObject
469{
470 OSDeclareFinalStructors(PMAssertionsTracker)
471public:
472 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
473
474 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
475 IOReturn releaseAssertion(IOPMDriverAssertionID);
476 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
477 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
478
479 OSArray *copyAssertionsArray(void);
480 IOPMDriverAssertionType getActivatedAssertions(void);
481 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
482
483 IOReturn handleCreateAssertion(OSData *);
484 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
485 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
486 IOReturn handleSetUserAssertionLevels(void * arg0);
487 void publishProperties(void);
488
489private:
490 typedef struct {
491 IOPMDriverAssertionID id;
492 IOPMDriverAssertionType assertionBits;
493 uint64_t createdTime;
494 uint64_t modifiedTime;
495 const OSSymbol *ownerString;
496 IOService *ownerService;
497 uint64_t registryEntryID;
498 IOPMDriverAssertionLevel level;
499 } PMAssertStruct;
500
501 uint32_t tabulateProducerCount;
502 uint32_t tabulateConsumerCount;
503
504 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
505 void tabulate(void);
506
507 IOPMrootDomain *owner;
508 OSArray *assertionsArray;
509 IOLock *assertionsArrayLock;
510 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
511 IOPMDriverAssertionType assertionsKernel;
512 IOPMDriverAssertionType assertionsUser;
513 IOPMDriverAssertionType assertionsCombined;
514};
515
516OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
517
518/*
519 * PMHaltWorker
520 * Internal helper object for Shutdown/Restart notifications.
521 */
522#define kPMHaltMaxWorkers 8
523#define kPMHaltTimeoutMS 100
524
525class PMHaltWorker : public OSObject
526{
527 OSDeclareFinalStructors( PMHaltWorker )
528
529public:
530 IOService * service; // service being worked on
531 AbsoluteTime startTime; // time when work started
532 int depth; // work on nubs at this PM-tree depth
533 int visits; // number of nodes visited (debug)
534 IOLock * lock;
535 bool timeout; // service took too long
536
537 static PMHaltWorker * worker( void );
538 static void main( void * arg, wait_result_t waitResult );
539 static void work( PMHaltWorker * me );
540 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
541 virtual void free( void ) APPLE_KEXT_OVERRIDE;
542};
543
544OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
545
546
547#define super IOService
548OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
549
550static void IOPMRootDomainWillShutdown(void)
551{
552 if (OSCompareAndSwap(0, 1, &gWillShutdown))
553 {
554 OSKext::willShutdown();
555 for (int i = 0; i < 100; i++)
556 {
557 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
558 IOSleep( 100 );
559 }
560 }
561}
562
563extern "C"
564{
565 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
566 {
567 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
568 }
569
570 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
571 {
572 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
573 }
574
575 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
576 {
577 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
578 }
579
580 IOReturn vetoSleepWakeNotification(void * PMrefcon)
581 {
582 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
583 }
584
585 IOReturn rootDomainRestart ( void )
586 {
587 return gRootDomain->restartSystem();
588 }
589
590 IOReturn rootDomainShutdown ( void )
591 {
592 return gRootDomain->shutdownSystem();
593 }
594
595 void IOSystemShutdownNotification(void)
596 {
597 IOPMRootDomainWillShutdown();
598#if HIBERNATION
599 IOHibernateSystemPostWake();
600#endif
601 if (OSCompareAndSwap(0, 1, &gPagingOff))
602 {
603 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
604 }
605 }
606
607 int sync_internal(void);
608}
609
610/*
611A device is always in the highest power state which satisfies its driver,
612its policy-maker, and any power children it has, but within the constraint
613of the power state provided by its parent. The driver expresses its desire by
614calling changePowerStateTo(), the policy-maker expresses its desire by calling
615changePowerStateToPriv(), and the children express their desires by calling
616requestPowerDomainState().
617
618The Root Power Domain owns the policy for idle and demand sleep for the system.
619It is a power-managed IOService just like the others in the system.
620It implements several power states which map to what we see as Sleep and On.
621
622The sleep policy is as follows:
6231. Sleep is prevented if the case is open so that nobody will think the machine
624 is off and plug/unplug cards.
6252. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
6263. System cannot Sleep if some object in the tree is in a power state marked
627 kIOPMPreventSystemSleep.
628
629These three conditions are enforced using the "driver clamp" by calling
630changePowerStateTo(). For example, if the case is opened,
631changePowerStateTo(ON_STATE) is called to hold the system on regardless
632of the desires of the children of the root or the state of the other clamp.
633
634Demand Sleep is initiated by pressing the front panel power button, closing
635the clamshell, or selecting the menu item. In this case the root's parent
636actually initiates the power state change so that the root domain has no
637choice and does not give applications the opportunity to veto the change.
638
639Idle Sleep occurs if no objects in the tree are in a state marked
640kIOPMPreventIdleSleep. When this is true, the root's children are not holding
641the root on, so it sets the "policy-maker clamp" by calling
642changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
643This timer is set for the difference between the sleep timeout slider and the
644display dim timeout slider. When the timer expires, it releases its clamp and
645now nothing is holding it awake, so it falls asleep.
646
647Demand sleep is prevented when the system is booting. When preferences are
648transmitted by the loginwindow at the end of boot, a flag is cleared,
649and this allows subsequent Demand Sleep.
650*/
651
652//******************************************************************************
653
654IOPMrootDomain * IOPMrootDomain::construct( void )
655{
656 IOPMrootDomain *root;
657
658 root = new IOPMrootDomain;
659 if( root)
660 root->init();
661
662 return( root );
663}
664
665//******************************************************************************
666// updateConsoleUsersCallout
667//
668//******************************************************************************
669
670static void updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
671{
672 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
673 rootDomain->updateConsoleUsers();
674}
675
676void IOPMrootDomain::updateConsoleUsers(void)
677{
678 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
679 if (tasksSuspended)
680 {
681 tasksSuspended = FALSE;
682 tasks_system_suspend(tasksSuspended);
683 }
684}
685
686//******************************************************************************
687
688static void swdDebugSetupCallout( thread_call_param_t p0, thread_call_param_t p1 )
689{
690 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
691 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
692
693 rootDomain->swdDebugSetup();
694
695 if (p1) {
696 rootDomain->allowPowerChange(notifyRef);
697 }
698 DLOG("swdDebugSetupCallout finish\n");
699}
700
701void IOPMrootDomain::swdDebugSetup( )
702{
703#if HIBERNATION
704 static int32_t mem_only = -1;
705 if ((mem_only == -1) &&
706 (PE_parse_boot_argn("swd_mem_only", &mem_only, sizeof(mem_only)) == false)) {
707 mem_only = 0;
708 }
709
710 if ((mem_only == 1) || (gRootDomain->sleepWakeDebugIsWdogEnabled() == false)) {
711 return;
712 }
713 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup);
714 if (swd_DebugImageSetup == FALSE) {
715 swd_DebugImageSetup = TRUE;
716 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
717 (CAP_LOSS(kIOPMSystemCapabilityGraphics))) {
718 IOHibernateSystemPostWakeTrim((void*)1, NULL);
719 }
720 IOOpenDebugDataFile(kSleepWakeStackBinFilename, SWD_BUF_SIZE);
721 }
722#endif
723
724
725}
726
727static void swdDebugTeardownCallout( thread_call_param_t p0, thread_call_param_t p1 )
728{
729 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
730 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
731
732 rootDomain->swdDebugTeardown();
733 if (p1) {
734 rootDomain->allowPowerChange(notifyRef);
735 }
736 DLOG("swdDebugTeardownCallout finish\n");
737}
738
739void IOPMrootDomain::swdDebugTeardown( )
740{
741
742#if HIBERNATION
743 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup);
744 if (swd_DebugImageSetup == TRUE) {
745 swd_DebugImageSetup = FALSE;
746 IOCloseDebugDataFile();
747 }
748#endif
749
750
751}
752//******************************************************************************
753
754
755static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
756{
757 IOService * rootDomain = (IOService *) p0;
758 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
759 uint32_t powerState = rootDomain->getPowerState();
760
761 DLOG("disk_sync_callout ps=%u\n", powerState);
762
763 if (ON_STATE == powerState)
764 {
765 sync_internal();
766 swdDebugSetupCallout(p0, NULL);
767 }
768#if HIBERNATION
769 else
770 {
771 swdDebugTeardownCallout(p0, NULL);
772 IOHibernateSystemPostWake();
773
774 if (gRootDomain)
775 gRootDomain->sleepWakeDebugSaveSpinDumpFile();
776 }
777#endif
778
779 rootDomain->allowPowerChange(notifyRef);
780 DLOG("disk_sync_callout finish\n");
781}
782
783//******************************************************************************
784static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
785{
786 AbsoluteTime endTime;
787 UInt64 nano = 0;
788
789 clock_get_uptime(&endTime);
790 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
791 {
792 SUB_ABSOLUTETIME(&endTime, startTime);
793 absolutetime_to_nanoseconds(endTime, &nano);
794 }
795
796 return (UInt32)(nano / 1000000ULL);
797}
798
799//******************************************************************************
800
801static int
802sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
803{
804 struct timeval *swt = (struct timeval *)arg1;
805 struct proc *p = req->p;
806
807 if (p == kernproc) {
808 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
809 } else if(proc_is64bit(p)) {
810 struct user64_timeval t;
811 t.tv_sec = swt->tv_sec;
812 t.tv_usec = swt->tv_usec;
813 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
814 } else {
815 struct user32_timeval t;
816 t.tv_sec = swt->tv_sec;
817 t.tv_usec = swt->tv_usec;
818 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
819 }
820}
821
822static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
823 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
824 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
825
826static SYSCTL_PROC(_kern, OID_AUTO, waketime,
827 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
828 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
829
830SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
831SYSCTL_QUAD(_kern, OID_AUTO, sleep_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastSleepAbsTime, "");
832
833static int
834sysctl_willshutdown
835(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
836{
837 int new_value, changed;
838 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
839 if (changed) {
840 if (!gWillShutdown && (new_value == 1)) {
841 IOPMRootDomainWillShutdown();
842 } else
843 error = EINVAL;
844 }
845 return(error);
846}
847
848static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
849 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
850 0, 0, sysctl_willshutdown, "I", "");
851
852extern struct sysctl_oid sysctl__kern_iokittest;
853
854
855static int
856sysctl_progressmeterenable
857(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
858{
859 int error;
860 int new_value, changed;
861
862 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
863
864 if (changed) vc_enable_progressmeter(new_value);
865
866 return (error);
867}
868
869static int
870sysctl_progressmeter
871(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
872{
873 int error;
874 int new_value, changed;
875
876 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
877
878 if (changed) vc_set_progressmeter(new_value);
879
880 return (error);
881}
882
883static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
884 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
885 0, 0, sysctl_progressmeterenable, "I", "");
886
887static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
888 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
889 0, 0, sysctl_progressmeter, "I", "");
890
891
892
893
894static int
895sysctl_consoleoptions
896(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
897{
898 int error, changed;
899 uint32_t new_value;
900
901 error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
902
903 if (changed) vc_user_options.options = new_value;
904
905 return (error);
906}
907
908static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
909 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
910 0, 0, sysctl_consoleoptions, "I", "");
911
912
913static int
914sysctl_progressoptions SYSCTL_HANDLER_ARGS
915{
916 return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
917}
918
919static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
920 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
921 NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
922
923
924static int
925sysctl_wakereason SYSCTL_HANDLER_ARGS
926{
927 char wr[ sizeof(gWakeReasonString) ];
928
929 wr[0] = '\0';
930 if (gRootDomain)
931 gRootDomain->copyWakeReasonString(wr, sizeof(wr));
932
933 return sysctl_io_string(req, wr, 0, 0, NULL);
934}
935
936SYSCTL_PROC(_kern, OID_AUTO, wakereason,
937 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
938 NULL, 0, sysctl_wakereason, "A", "wakereason");
939
940static int
941sysctl_targettype SYSCTL_HANDLER_ARGS
942{
943 IOService * root;
944 OSObject * obj;
945 OSData * data;
946 char tt[32];
947
948 tt[0] = '\0';
949 root = IOService::getServiceRoot();
950 if (root && (obj = root->copyProperty(gIODTTargetTypeKey)))
951 {
952 if ((data = OSDynamicCast(OSData, obj)))
953 {
954 strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
955 }
956 obj->release();
957 }
958 return sysctl_io_string(req, tt, 0, 0, NULL);
959}
960
961SYSCTL_PROC(_hw, OID_AUTO, targettype,
962 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
963 NULL, 0, sysctl_targettype, "A", "targettype");
964
965static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
966static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
967
968static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
969static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
970static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
971static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
972static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
973static const OSSymbol * gIOPMSettingSilentRunningKey;
974static const OSSymbol * gIOPMUserTriggeredFullWakeKey;
975static const OSSymbol * gIOPMUserIsActiveKey;
976
977//******************************************************************************
978// start
979//
980//******************************************************************************
981
982#define kRootDomainSettingsCount 17
983
984bool IOPMrootDomain::start( IOService * nub )
985{
986 OSIterator *psIterator;
987 OSDictionary *tmpDict;
988 IORootParent * patriarch;
989#if defined(__i386__) || defined(__x86_64__)
990 IONotifier * notifier;
991#endif
992
993 super::start(nub);
994
995 gRootDomain = this;
996 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
997 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
998 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
999 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
1000 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
1001 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
1002 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
1003 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
1004
1005 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
1006 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
1007 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
1008 gIOPMStatsApplicationResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
1009 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
1010
1011 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
1012 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
1013
1014 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
1015 {
1016 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
1017 gIOPMSettingAutoWakeSecondsKey,
1018 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
1019 gIOPMSettingAutoWakeCalendarKey,
1020 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
1021 gIOPMSettingDebugWakeRelativeKey,
1022 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
1023 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
1024 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
1025 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
1026 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
1027 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
1028 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
1029 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
1030 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
1031 OSSymbol::withCString(kIOPMStateConsoleShutdown),
1032 gIOPMSettingSilentRunningKey
1033 };
1034
1035 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
1036 PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
1037
1038 queue_init(&aggressivesQueue);
1039 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
1040 aggressivesData = OSData::withCapacity(
1041 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
1042
1043 featuresDictLock = IOLockAlloc();
1044 settingsCtrlLock = IOLockAlloc();
1045 wakeEventLock = IOLockAlloc();
1046 setPMRootDomain(this);
1047
1048 extraSleepTimer = thread_call_allocate(
1049 idleSleepTimerExpired,
1050 (thread_call_param_t) this);
1051
1052 diskSyncCalloutEntry = thread_call_allocate(
1053 &disk_sync_callout,
1054 (thread_call_param_t) this);
1055 swdDebugSetupEntry = thread_call_allocate(
1056 &swdDebugSetupCallout,
1057 (thread_call_param_t) this);
1058 swdDebugTearDownEntry = thread_call_allocate(
1059 &swdDebugTeardownCallout,
1060 (thread_call_param_t) this);
1061 updateConsoleUsersEntry = thread_call_allocate(
1062 &updateConsoleUsersCallout,
1063 (thread_call_param_t) this);
1064
1065#if DARK_TO_FULL_EVALUATE_CLAMSHELL
1066 fullWakeThreadCall = thread_call_allocate(
1067 OSMemberFunctionCast(thread_call_func_t, this,
1068 &IOPMrootDomain::fullWakeDelayedWork),
1069 (thread_call_param_t) this);
1070#endif
1071
1072 setProperty(kIOSleepSupportedKey, true);
1073
1074 bzero(&gPMStats, sizeof(gPMStats));
1075
1076 pmTracer = PMTraceWorker::tracer(this);
1077
1078 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1079
1080 userDisabledAllSleep = false;
1081 systemBooting = true;
1082 idleSleepEnabled = false;
1083 sleepSlider = 0;
1084 idleSleepTimerPending = false;
1085 wrangler = NULL;
1086 clamshellClosed = false;
1087 clamshellExists = false;
1088 clamshellDisabled = true;
1089 acAdaptorConnected = true;
1090 clamshellSleepDisabled = false;
1091 gWakeReasonString[0] = '\0';
1092
1093 // Initialize to user active.
1094 // Will never transition to user inactive w/o wrangler.
1095 fullWakeReason = kFullWakeReasonLocalUser;
1096 userIsActive = userWasActive = true;
1097 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
1098
1099 // Set the default system capabilities at boot.
1100 _currentCapability = kIOPMSystemCapabilityCPU |
1101 kIOPMSystemCapabilityGraphics |
1102 kIOPMSystemCapabilityAudio |
1103 kIOPMSystemCapabilityNetwork;
1104
1105 _pendingCapability = _currentCapability;
1106 _desiredCapability = _currentCapability;
1107 _highestCapability = _currentCapability;
1108 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
1109
1110 queuedSleepWakeUUIDString = NULL;
1111 initializeBootSessionUUID();
1112 pmStatsAppResponses = OSArray::withCapacity(5);
1113 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
1114 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
1115 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
1116 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
1117 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
1118 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
1119 assertOnWakeSecs = -1; // Invalid value to prevent updates
1120
1121 pmStatsLock = IOLockAlloc();
1122 idxPMCPUClamshell = kCPUUnknownIndex;
1123 idxPMCPULimitedPower = kCPUUnknownIndex;
1124
1125 tmpDict = OSDictionary::withCapacity(1);
1126 setProperty(kRootDomainSupportedFeatures, tmpDict);
1127 tmpDict->release();
1128
1129 settingsCallbacks = OSDictionary::withCapacity(1);
1130
1131 // Create a list of the valid PM settings that we'll relay to
1132 // interested clients in setProperties() => setPMSetting()
1133 allowedPMSettings = OSArray::withObjects(
1134 (const OSObject **)settingsArr,
1135 kRootDomainSettingsCount,
1136 0);
1137
1138 // List of PM settings that should not automatically publish itself
1139 // as a feature when registered by a listener.
1140 noPublishPMSettings = OSArray::withObjects(
1141 (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
1142
1143 fPMSettingsDict = OSDictionary::withCapacity(5);
1144 preventIdleSleepList = OSSet::withCapacity(8);
1145 preventSystemSleepList = OSSet::withCapacity(2);
1146
1147 PMinit(); // creates gIOPMWorkLoop
1148 gIOPMWorkLoop = getIOPMWorkloop();
1149
1150 // Create IOPMPowerStateQueue used to queue external power
1151 // events, and to handle those events on the PM work loop.
1152 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
1153 this, OSMemberFunctionCast(IOEventSource::Action, this,
1154 &IOPMrootDomain::dispatchPowerEvent));
1155 gIOPMWorkLoop->addEventSource(pmPowerStateQueue);
1156
1157 // create our power parent
1158 patriarch = new IORootParent;
1159 patriarch->init();
1160 patriarch->attach(this);
1161 patriarch->start(this);
1162 patriarch->addPowerChild(this);
1163
1164 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
1165 changePowerStateToPriv(ON_STATE);
1166
1167 // install power change handler
1168 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
1169
1170#if !NO_KERNEL_HID
1171 // Register for a notification when IODisplayWrangler is published
1172 if ((tmpDict = serviceMatching("IODisplayWrangler")))
1173 {
1174 _displayWranglerNotifier = addMatchingNotification(
1175 gIOPublishNotification, tmpDict,
1176 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
1177 this, 0);
1178 tmpDict->release();
1179 }
1180#endif
1181
1182#if defined(__i386__) || defined(__x86_64__)
1183
1184 if ((tmpDict = serviceMatching("IODTNVRAM")))
1185 {
1186 notifier = addMatchingNotification(
1187 gIOFirstPublishNotification, tmpDict,
1188 (IOServiceMatchingNotificationHandler) &IONVRAMMatchPublished,
1189 this, 0);
1190 tmpDict->release();
1191 }
1192
1193 wranglerIdleSettings = NULL;
1194 OSNumber * wranglerIdlePeriod = NULL;
1195 wranglerIdleSettings = OSDictionary::withCapacity(1);
1196 wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
1197
1198 if(wranglerIdleSettings && wranglerIdlePeriod)
1199 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
1200 wranglerIdlePeriod);
1201
1202 if(wranglerIdlePeriod)
1203 wranglerIdlePeriod->release();
1204#endif
1205
1206 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
1207 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
1208 ucClassName->release();
1209
1210 // IOBacklightDisplay can take a long time to load at boot, or it may
1211 // not load at all if you're booting with clamshell closed. We publish
1212 // 'DisplayDims' here redundantly to get it published early and at all.
1213 OSDictionary * matching;
1214 matching = serviceMatching("IOPMPowerSource");
1215 psIterator = getMatchingServices( matching );
1216 if (matching) matching->release();
1217 if( psIterator && psIterator->getNextObject() )
1218 {
1219 // There's at least one battery on the system, so we publish
1220 // 'DisplayDims' support for the LCD.
1221 publishFeature("DisplayDims");
1222 }
1223 if(psIterator) {
1224 psIterator->release();
1225 }
1226
1227 sysctl_register_oid(&sysctl__kern_sleeptime);
1228 sysctl_register_oid(&sysctl__kern_waketime);
1229 sysctl_register_oid(&sysctl__kern_willshutdown);
1230 sysctl_register_oid(&sysctl__kern_iokittest);
1231 sysctl_register_oid(&sysctl__hw_targettype);
1232
1233 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1234 sysctl_register_oid(&sysctl__kern_progressmeter);
1235 sysctl_register_oid(&sysctl__kern_wakereason);
1236 sysctl_register_oid(&sysctl__kern_consoleoptions);
1237 sysctl_register_oid(&sysctl__kern_progressoptions);
1238
1239#if HIBERNATION
1240 IOHibernateSystemInit(this);
1241#endif
1242
1243 registerService(); // let clients find us
1244
1245 return true;
1246}
1247
1248//******************************************************************************
1249// setProperties
1250//
1251// Receive a setProperty call
1252// The "System Boot" property means the system is completely booted.
1253//******************************************************************************
1254
1255IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1256{
1257 IOReturn return_value = kIOReturnSuccess;
1258 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1259 OSBoolean *b;
1260 OSNumber *n;
1261 const OSSymbol *key;
1262 OSObject *obj;
1263 OSCollectionIterator * iter = 0;
1264
1265 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1266 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
1267 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1268 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1269 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1270 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1271 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1272 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1273 const OSSymbol *loginwindow_progress_string = OSSymbol::withCString(kIOPMLoginWindowProgressKey);
1274 const OSSymbol *coredisplay_progress_string = OSSymbol::withCString(kIOPMCoreDisplayProgressKey);
1275 const OSSymbol *coregraphics_progress_string = OSSymbol::withCString(kIOPMCoreGraphicsProgressKey);
1276#if HIBERNATION
1277 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1278 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1279 const OSSymbol *hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1280 const OSSymbol *hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
1281 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1282 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
1283#endif
1284
1285 if (!dict)
1286 {
1287 return_value = kIOReturnBadArgument;
1288 goto exit;
1289 }
1290
1291 iter = OSCollectionIterator::withCollection(dict);
1292 if (!iter)
1293 {
1294 return_value = kIOReturnNoMemory;
1295 goto exit;
1296 }
1297
1298 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1299 (obj = dict->getObject(key)))
1300 {
1301 if (key->isEqualTo(publish_simulated_battery_string))
1302 {
1303 if (OSDynamicCast(OSBoolean, obj))
1304 publishResource(key, kOSBooleanTrue);
1305 }
1306 else if (key->isEqualTo(idle_seconds_string))
1307 {
1308 if ((n = OSDynamicCast(OSNumber, obj)))
1309 {
1310 setProperty(key, n);
1311 idleSeconds = n->unsigned32BitValue();
1312 }
1313 }
1314 else if (key->isEqualTo(boot_complete_string))
1315 {
1316 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
1317 }
1318 else if (key->isEqualTo(sys_shutdown_string))
1319 {
1320 if ((b = OSDynamicCast(OSBoolean, obj)))
1321 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1322 }
1323 else if (key->isEqualTo(battery_warning_disabled_string))
1324 {
1325 setProperty(key, obj);
1326 }
1327#if HIBERNATION
1328 else if (key->isEqualTo(hibernatemode_string) ||
1329 key->isEqualTo(hibernatefilemin_string) ||
1330 key->isEqualTo(hibernatefilemax_string) ||
1331 key->isEqualTo(hibernatefreeratio_string) ||
1332 key->isEqualTo(hibernatefreetime_string))
1333 {
1334 if ((n = OSDynamicCast(OSNumber, obj)))
1335 setProperty(key, n);
1336 }
1337 else if (key->isEqualTo(hibernatefile_string))
1338 {
1339 OSString * str = OSDynamicCast(OSString, obj);
1340 if (str) setProperty(key, str);
1341 }
1342#endif
1343 else if (key->isEqualTo(sleepdisabled_string))
1344 {
1345 if ((b = OSDynamicCast(OSBoolean, obj)))
1346 {
1347 setProperty(key, b);
1348 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1349 }
1350 }
1351 else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
1352 {
1353 obj->retain();
1354 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
1355 }
1356 else if (key->isEqualTo(loginwindow_progress_string))
1357 {
1358 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1359 uint32_t data = n->unsigned32BitValue();
1360 pmTracer->traceComponentWakeProgress(kIOPMLoginWindowProgress, data);
1361 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMLoginWindowProgress, data);
1362 }
1363 }
1364 else if (key->isEqualTo(coredisplay_progress_string))
1365 {
1366 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1367 uint32_t data = n->unsigned32BitValue();
1368 pmTracer->traceComponentWakeProgress(kIOPMCoreDisplayProgress, data);
1369 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreDisplayProgress, data);
1370 }
1371 }
1372 else if (key->isEqualTo(coregraphics_progress_string))
1373 {
1374 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1375 uint32_t data = n->unsigned32BitValue();
1376 pmTracer->traceComponentWakeProgress(kIOPMCoreGraphicsProgress, data);
1377 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreGraphicsProgress, data);
1378 }
1379 }
1380 else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1381 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1382 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
1383 key->isEqualTo(stall_halt_string))
1384 {
1385 if ((b = OSDynamicCast(OSBoolean, obj)))
1386 setProperty(key, b);
1387 }
1388 else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
1389 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1390 key->isEqualTo(kIOPMAutoPowerOffTimerKey))
1391 {
1392 if ((n = OSDynamicCast(OSNumber, obj)))
1393 setProperty(key, n);
1394 }
1395 else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
1396 {
1397 if (kOSBooleanTrue == obj)
1398 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1399 else
1400 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1401 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm);
1402 }
1403
1404 // Relay our allowed PM settings onto our registered PM clients
1405 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
1406 {
1407 return_value = setPMSetting(key, obj);
1408 if (kIOReturnSuccess != return_value)
1409 break;
1410
1411 if (gIOPMSettingDebugWakeRelativeKey == key)
1412 {
1413 if ((n = OSDynamicCast(OSNumber, obj)) &&
1414 (_debugWakeSeconds = n->unsigned32BitValue()))
1415 {
1416 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1417 }
1418 else
1419 {
1420 _debugWakeSeconds = 0;
1421 OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1422 }
1423 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1424 }
1425 else if (gIOPMSettingAutoWakeCalendarKey == key)
1426 {
1427 OSData * data;
1428 if ((data = OSDynamicCast(OSData, obj)) &&
1429 (data->getLength() == sizeof(IOPMCalendarStruct)))
1430 {
1431 const IOPMCalendarStruct * cs =
1432 (const IOPMCalendarStruct *) data->getBytesNoCopy();
1433
1434 if (cs->year)
1435 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1436 else
1437 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1438 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1439 }
1440 }
1441 }
1442 else
1443 {
1444 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
1445 }
1446 }
1447
1448exit:
1449 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
1450 if(boot_complete_string) boot_complete_string->release();
1451 if(sys_shutdown_string) sys_shutdown_string->release();
1452 if(stall_halt_string) stall_halt_string->release();
1453 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
1454 if(idle_seconds_string) idle_seconds_string->release();
1455 if(sleepdisabled_string) sleepdisabled_string->release();
1456 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
1457 if(loginwindow_progress_string) loginwindow_progress_string->release();
1458 if(coredisplay_progress_string) coredisplay_progress_string->release();
1459 if(coregraphics_progress_string) coregraphics_progress_string->release();
1460#if HIBERNATION
1461 if(hibernatemode_string) hibernatemode_string->release();
1462 if(hibernatefile_string) hibernatefile_string->release();
1463 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1464 if(hibernatefreetime_string) hibernatefreetime_string->release();
1465#endif
1466 if (iter) iter->release();
1467 return return_value;
1468}
1469
1470// MARK: -
1471// MARK: Aggressiveness
1472
1473//******************************************************************************
1474// setAggressiveness
1475//
1476// Override IOService::setAggressiveness()
1477//******************************************************************************
1478
1479IOReturn IOPMrootDomain::setAggressiveness(
1480 unsigned long type,
1481 unsigned long value )
1482{
1483 return setAggressiveness( type, value, 0 );
1484}
1485
1486/*
1487 * Private setAggressiveness() with an internal options argument.
1488 */
1489IOReturn IOPMrootDomain::setAggressiveness(
1490 unsigned long type,
1491 unsigned long value,
1492 IOOptionBits options )
1493{
1494 AggressivesRequest * entry;
1495 AggressivesRequest * request;
1496 bool found = false;
1497
1498 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1499 (uint32_t) options, (uint32_t) type, (uint32_t) value);
1500
1501 request = IONew(AggressivesRequest, 1);
1502 if (!request)
1503 return kIOReturnNoMemory;
1504
1505 memset(request, 0, sizeof(*request));
1506 request->options = options;
1507 request->dataType = kAggressivesRequestTypeRecord;
1508 request->data.record.type = (uint32_t) type;
1509 request->data.record.value = (uint32_t) value;
1510
1511 AGGRESSIVES_LOCK();
1512
1513 // Update disk quick spindown flag used by getAggressiveness().
1514 // Never merge requests with quick spindown flags set.
1515
1516 if (options & kAggressivesOptionQuickSpindownEnable)
1517 gAggressivesState |= kAggressivesStateQuickSpindown;
1518 else if (options & kAggressivesOptionQuickSpindownDisable)
1519 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1520 else
1521 {
1522 // Coalesce requests with identical aggressives types.
1523 // Deal with callers that calls us too "aggressively".
1524
1525 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1526 {
1527 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1528 (entry->data.record.type == type) &&
1529 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1530 {
1531 entry->data.record.value = value;
1532 found = true;
1533 break;
1534 }
1535 }
1536 }
1537
1538 if (!found)
1539 {
1540 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1541 }
1542
1543 AGGRESSIVES_UNLOCK();
1544
1545 if (found)
1546 IODelete(request, AggressivesRequest, 1);
1547
1548 if (options & kAggressivesOptionSynchronous)
1549 handleAggressivesRequests(); // not truly synchronous
1550 else
1551 thread_call_enter(aggressivesThreadCall);
1552
1553 return kIOReturnSuccess;
1554}
1555
1556//******************************************************************************
1557// getAggressiveness
1558//
1559// Override IOService::setAggressiveness()
1560// Fetch the aggressiveness factor with the given type.
1561//******************************************************************************
1562
1563IOReturn IOPMrootDomain::getAggressiveness (
1564 unsigned long type,
1565 unsigned long * outLevel )
1566{
1567 uint32_t value = 0;
1568 int source = 0;
1569
1570 if (!outLevel)
1571 return kIOReturnBadArgument;
1572
1573 AGGRESSIVES_LOCK();
1574
1575 // Disk quick spindown in effect, report value = 1
1576
1577 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1578 (type == kPMMinutesToSpinDown))
1579 {
1580 value = kAggressivesMinValue;
1581 source = 1;
1582 }
1583
1584 // Consult the pending request queue.
1585
1586 if (!source)
1587 {
1588 AggressivesRequest * entry;
1589
1590 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1591 {
1592 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1593 (entry->data.record.type == type) &&
1594 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1595 {
1596 value = entry->data.record.value;
1597 source = 2;
1598 break;
1599 }
1600 }
1601 }
1602
1603 // Consult the backend records.
1604
1605 if (!source && aggressivesData)
1606 {
1607 AggressivesRecord * record;
1608 int i, count;
1609
1610 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1611 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1612
1613 for (i = 0; i < count; i++, record++)
1614 {
1615 if (record->type == type)
1616 {
1617 value = record->value;
1618 source = 3;
1619 break;
1620 }
1621 }
1622 }
1623
1624 AGGRESSIVES_UNLOCK();
1625
1626 if (source)
1627 {
1628 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1629 source, (uint32_t) type, value);
1630 *outLevel = (unsigned long) value;
1631 return kIOReturnSuccess;
1632 }
1633 else
1634 {
1635 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1636 *outLevel = 0; // default return = 0, driver may not check for error
1637 return kIOReturnInvalid;
1638 }
1639}
1640
1641//******************************************************************************
1642// joinAggressiveness
1643//
1644// Request from IOService to join future aggressiveness broadcasts.
1645//******************************************************************************
1646
1647IOReturn IOPMrootDomain::joinAggressiveness(
1648 IOService * service )
1649{
1650 AggressivesRequest * request;
1651
1652 if (!service || (service == this))
1653 return kIOReturnBadArgument;
1654
1655 DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
1656
1657 request = IONew(AggressivesRequest, 1);
1658 if (!request)
1659 return kIOReturnNoMemory;
1660
1661 service->retain(); // released by synchronizeAggressives()
1662
1663 memset(request, 0, sizeof(*request));
1664 request->dataType = kAggressivesRequestTypeService;
1665 request->data.service = service;
1666
1667 AGGRESSIVES_LOCK();
1668 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1669 AGGRESSIVES_UNLOCK();
1670
1671 thread_call_enter(aggressivesThreadCall);
1672
1673 return kIOReturnSuccess;
1674}
1675
1676//******************************************************************************
1677// handleAggressivesRequests
1678//
1679// Backend thread processes all incoming aggressiveness requests in the queue.
1680//******************************************************************************
1681
1682static void
1683handleAggressivesFunction(
1684 thread_call_param_t param1,
1685 thread_call_param_t param2 )
1686{
1687 if (param1)
1688 {
1689 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1690 }
1691}
1692
1693void IOPMrootDomain::handleAggressivesRequests( void )
1694{
1695 AggressivesRecord * start;
1696 AggressivesRecord * record;
1697 AggressivesRequest * request;
1698 queue_head_t joinedQueue;
1699 int i, count;
1700 bool broadcast;
1701 bool found;
1702 bool pingSelf = false;
1703
1704 AGGRESSIVES_LOCK();
1705
1706 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1707 queue_empty(&aggressivesQueue))
1708 goto unlock_done;
1709
1710 gAggressivesState |= kAggressivesStateBusy;
1711 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1712 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1713
1714 do
1715 {
1716 broadcast = false;
1717 queue_init(&joinedQueue);
1718
1719 do
1720 {
1721 // Remove request from the incoming queue in FIFO order.
1722 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1723 switch (request->dataType)
1724 {
1725 case kAggressivesRequestTypeRecord:
1726 // Update existing record if found.
1727 found = false;
1728 for (i = 0, record = start; i < count; i++, record++)
1729 {
1730 if (record->type == request->data.record.type)
1731 {
1732 found = true;
1733
1734 if (request->options & kAggressivesOptionQuickSpindownEnable)
1735 {
1736 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1737 {
1738 broadcast = true;
1739 record->flags |= (kAggressivesRecordFlagMinValue |
1740 kAggressivesRecordFlagModified);
1741 DLOG("disk spindown accelerated, was %u min\n",
1742 record->value);
1743 }
1744 }
1745 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1746 {
1747 if (record->flags & kAggressivesRecordFlagMinValue)
1748 {
1749 broadcast = true;
1750 record->flags |= kAggressivesRecordFlagModified;
1751 record->flags &= ~kAggressivesRecordFlagMinValue;
1752 DLOG("disk spindown restored to %u min\n",
1753 record->value);
1754 }
1755 }
1756 else if (record->value != request->data.record.value)
1757 {
1758 record->value = request->data.record.value;
1759 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1760 {
1761 broadcast = true;
1762 record->flags |= kAggressivesRecordFlagModified;
1763 }
1764 }
1765 break;
1766 }
1767 }
1768
1769 // No matching record, append a new record.
1770 if (!found &&
1771 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1772 {
1773 AggressivesRecord newRecord;
1774
1775 newRecord.flags = kAggressivesRecordFlagModified;
1776 newRecord.type = request->data.record.type;
1777 newRecord.value = request->data.record.value;
1778 if (request->options & kAggressivesOptionQuickSpindownEnable)
1779 {
1780 newRecord.flags |= kAggressivesRecordFlagMinValue;
1781 DLOG("disk spindown accelerated\n");
1782 }
1783
1784 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1785
1786 // OSData may have switched to another (larger) buffer.
1787 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1788 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1789 broadcast = true;
1790 }
1791
1792 // Finished processing the request, release it.
1793 IODelete(request, AggressivesRequest, 1);
1794 break;
1795
1796 case kAggressivesRequestTypeService:
1797 // synchronizeAggressives() will free request.
1798 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1799 break;
1800
1801 default:
1802 panic("bad aggressives request type %x\n", request->dataType);
1803 break;
1804 }
1805 } while (!queue_empty(&aggressivesQueue));
1806
1807 // Release the lock to perform work, with busy flag set.
1808 if (!queue_empty(&joinedQueue) || broadcast)
1809 {
1810 AGGRESSIVES_UNLOCK();
1811 if (!queue_empty(&joinedQueue))
1812 synchronizeAggressives(&joinedQueue, start, count);
1813 if (broadcast)
1814 broadcastAggressives(start, count);
1815 AGGRESSIVES_LOCK();
1816 }
1817
1818 // Remove the modified flag from all records.
1819 for (i = 0, record = start; i < count; i++, record++)
1820 {
1821 if ((record->flags & kAggressivesRecordFlagModified) &&
1822 ((record->type == kPMMinutesToDim) ||
1823 (record->type == kPMMinutesToSleep)))
1824 pingSelf = true;
1825
1826 record->flags &= ~kAggressivesRecordFlagModified;
1827 }
1828
1829 // Check the incoming queue again since new entries may have been
1830 // added while lock was released above.
1831
1832 } while (!queue_empty(&aggressivesQueue));
1833
1834 gAggressivesState &= ~kAggressivesStateBusy;
1835
1836unlock_done:
1837 AGGRESSIVES_UNLOCK();
1838
1839 // Root domain is interested in system and display sleep slider changes.
1840 // Submit a power event to handle those changes on the PM work loop.
1841
1842 if (pingSelf && pmPowerStateQueue) {
1843 pmPowerStateQueue->submitPowerEvent(
1844 kPowerEventPolicyStimulus,
1845 (void *) kStimulusAggressivenessChanged );
1846 }
1847}
1848
1849//******************************************************************************
1850// synchronizeAggressives
1851//
1852// Push all known aggressiveness records to one or more IOService.
1853//******************************************************************************
1854
1855void IOPMrootDomain::synchronizeAggressives(
1856 queue_head_t * joinedQueue,
1857 const AggressivesRecord * array,
1858 int count )
1859{
1860 IOService * service;
1861 AggressivesRequest * request;
1862 const AggressivesRecord * record;
1863 IOPMDriverCallEntry callEntry;
1864 uint32_t value;
1865 int i;
1866
1867 while (!queue_empty(joinedQueue))
1868 {
1869 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1870 if (request->dataType == kAggressivesRequestTypeService)
1871 service = request->data.service;
1872 else
1873 service = 0;
1874
1875 IODelete(request, AggressivesRequest, 1);
1876 request = 0;
1877
1878 if (service)
1879 {
1880 if (service->assertPMDriverCall(&callEntry))
1881 {
1882 for (i = 0, record = array; i < count; i++, record++)
1883 {
1884 value = record->value;
1885 if (record->flags & kAggressivesRecordFlagMinValue)
1886 value = kAggressivesMinValue;
1887
1888 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1889 record->type, value, service->getName());
1890 service->setAggressiveness(record->type, value);
1891 }
1892 service->deassertPMDriverCall(&callEntry);
1893 }
1894 service->release(); // retained by joinAggressiveness()
1895 }
1896 }
1897}
1898
1899//******************************************************************************
1900// broadcastAggressives
1901//
1902// Traverse PM tree and call setAggressiveness() for records that have changed.
1903//******************************************************************************
1904
1905void IOPMrootDomain::broadcastAggressives(
1906 const AggressivesRecord * array,
1907 int count )
1908{
1909 IORegistryIterator * iter;
1910 IORegistryEntry * entry;
1911 IOPowerConnection * connect;
1912 IOService * service;
1913 const AggressivesRecord * record;
1914 IOPMDriverCallEntry callEntry;
1915 uint32_t value;
1916 int i;
1917
1918 iter = IORegistryIterator::iterateOver(
1919 this, gIOPowerPlane, kIORegistryIterateRecursively);
1920 if (iter)
1921 {
1922 do
1923 {
1924 iter->reset();
1925 while ((entry = iter->getNextObject()))
1926 {
1927 connect = OSDynamicCast(IOPowerConnection, entry);
1928 if (!connect || !connect->getReadyFlag())
1929 continue;
1930
1931 if ((service = OSDynamicCast(IOService, connect->copyChildEntry(gIOPowerPlane))))
1932 {
1933 if (service->assertPMDriverCall(&callEntry))
1934 {
1935 for (i = 0, record = array; i < count; i++, record++)
1936 {
1937 if (record->flags & kAggressivesRecordFlagModified)
1938 {
1939 value = record->value;
1940 if (record->flags & kAggressivesRecordFlagMinValue)
1941 value = kAggressivesMinValue;
1942 _LOG("broadcastAggressives %x = %u to %s\n",
1943 record->type, value, service->getName());
1944 service->setAggressiveness(record->type, value);
1945 }
1946 }
1947 service->deassertPMDriverCall(&callEntry);
1948 }
1949 service->release();
1950 }
1951 }
1952 }
1953 while (!entry && !iter->isValid());
1954 iter->release();
1955 }
1956}
1957
1958// MARK: -
1959// MARK: System Sleep
1960
1961//******************************************************************************
1962// startIdleSleepTimer
1963//
1964//******************************************************************************
1965
1966void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1967{
1968 AbsoluteTime deadline;
1969
1970 ASSERT_GATED();
1971 if (gNoIdleFlag) {
1972 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
1973 return;
1974 }
1975 if (inSeconds)
1976 {
1977 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
1978 thread_call_enter_delayed(extraSleepTimer, deadline);
1979 idleSleepTimerPending = true;
1980 }
1981 else
1982 {
1983 thread_call_enter(extraSleepTimer);
1984 }
1985 DLOG("idle timer set for %u seconds\n", inSeconds);
1986}
1987
1988//******************************************************************************
1989// cancelIdleSleepTimer
1990//
1991//******************************************************************************
1992
1993void IOPMrootDomain::cancelIdleSleepTimer( void )
1994{
1995 ASSERT_GATED();
1996 if (idleSleepTimerPending)
1997 {
1998 DLOG("idle timer cancelled\n");
1999 thread_call_cancel(extraSleepTimer);
2000 idleSleepTimerPending = false;
2001
2002 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
2003 AbsoluteTime now;
2004 clock_usec_t microsecs;
2005 clock_get_uptime(&now);
2006 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2007 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2008 if (assertOnWakeReport) {
2009 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2010 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2011 }
2012 }
2013 }
2014}
2015
2016//******************************************************************************
2017// idleSleepTimerExpired
2018//
2019//******************************************************************************
2020
2021static void idleSleepTimerExpired(
2022 thread_call_param_t us, thread_call_param_t )
2023{
2024 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
2025}
2026
2027//******************************************************************************
2028// handleSleepTimerExpiration
2029//
2030// The time between the sleep idle timeout and the next longest one has elapsed.
2031// It's time to sleep. Start that by removing the clamp that's holding us awake.
2032//******************************************************************************
2033
2034void IOPMrootDomain::handleSleepTimerExpiration( void )
2035{
2036 if (!gIOPMWorkLoop->inGate())
2037 {
2038 gIOPMWorkLoop->runAction(
2039 OSMemberFunctionCast(IOWorkLoop::Action, this,
2040 &IOPMrootDomain::handleSleepTimerExpiration),
2041 this);
2042 return;
2043 }
2044
2045 AbsoluteTime time;
2046
2047 DLOG("sleep timer expired\n");
2048 ASSERT_GATED();
2049
2050 idleSleepTimerPending = false;
2051
2052 clock_get_uptime(&time);
2053 setQuickSpinDownTimeout();
2054 adjustPowerState(true);
2055}
2056
2057//******************************************************************************
2058// getTimeToIdleSleep
2059//
2060// Returns number of seconds left before going into idle sleep.
2061// Caller has to make sure that idle sleep is allowed at the time of calling
2062// this function
2063//******************************************************************************
2064
2065uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2066{
2067
2068 AbsoluteTime now, lastActivityTime;
2069 uint64_t nanos;
2070 uint32_t minutesSinceUserInactive = 0;
2071 uint32_t sleepDelay = 0;
2072
2073 if (!idleSleepEnabled)
2074 return 0xffffffff;
2075
2076 if (userActivityTime)
2077 lastActivityTime = userActivityTime;
2078 else
2079 lastActivityTime = userBecameInactiveTime;
2080
2081 clock_get_uptime(&now);
2082 if (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)
2083 {
2084 SUB_ABSOLUTETIME(&now, &lastActivityTime);
2085 absolutetime_to_nanoseconds(now, &nanos);
2086 minutesSinceUserInactive = nanos / (60000000000ULL);
2087
2088 if (minutesSinceUserInactive >= sleepSlider)
2089 sleepDelay = 0;
2090 else
2091 sleepDelay = sleepSlider - minutesSinceUserInactive;
2092 }
2093 else
2094 {
2095 sleepDelay = sleepSlider;
2096 }
2097
2098 DLOG("user inactive %u min, time to idle sleep %u min\n",
2099 minutesSinceUserInactive, sleepDelay);
2100
2101 return (sleepDelay * 60);
2102}
2103
2104//******************************************************************************
2105// setQuickSpinDownTimeout
2106//
2107//******************************************************************************
2108
2109void IOPMrootDomain::setQuickSpinDownTimeout( void )
2110{
2111 ASSERT_GATED();
2112 setAggressiveness(
2113 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
2114}
2115
2116//******************************************************************************
2117// restoreUserSpinDownTimeout
2118//
2119//******************************************************************************
2120
2121void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2122{
2123 ASSERT_GATED();
2124 setAggressiveness(
2125 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
2126}
2127
2128//******************************************************************************
2129// sleepSystem
2130//
2131//******************************************************************************
2132
2133/* public */
2134IOReturn IOPMrootDomain::sleepSystem( void )
2135{
2136 return sleepSystemOptions(NULL);
2137}
2138
2139/* private */
2140IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2141{
2142 OSObject *obj = NULL;
2143 OSString *reason = NULL;
2144 /* sleepSystem is a public function, and may be called by any kernel driver.
2145 * And that's bad - drivers should sleep the system by calling
2146 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2147 *
2148 * Note that user space app calls to IOPMSleepSystem() will also travel
2149 * this code path and thus be correctly identified as software sleeps.
2150 */
2151
2152 if (options && options->getObject("OSSwitch"))
2153 {
2154 // Log specific sleep cause for OS Switch hibernation
2155 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2156 }
2157
2158 if (options && (obj = options->getObject("Sleep Reason")))
2159 {
2160 reason = OSDynamicCast(OSString, obj);
2161 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey))
2162 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
2163 }
2164
2165 return privateSleepSystem( kIOPMSleepReasonSoftware);
2166}
2167
2168/* private */
2169IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2170{
2171 /* Called from both gated and non-gated context */
2172
2173 if (!checkSystemSleepEnabled() || !pmPowerStateQueue)
2174 {
2175 return kIOReturnNotPermitted;
2176 }
2177
2178 pmPowerStateQueue->submitPowerEvent(
2179 kPowerEventPolicyStimulus,
2180 (void *) kStimulusDemandSystemSleep,
2181 sleepReason);
2182
2183 return kIOReturnSuccess;
2184}
2185
2186//******************************************************************************
2187// powerChangeDone
2188//
2189// This overrides powerChangeDone in IOService.
2190//******************************************************************************
2191
2192void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
2193{
2194 uint64_t now;
2195 ASSERT_GATED();
2196 DLOG("PowerChangeDone: %u->%u\n",
2197 (uint32_t) previousPowerState, (uint32_t) getPowerState());
2198
2199 switch ( getPowerState() )
2200 {
2201 case SLEEP_STATE: {
2202 if (previousPowerState != ON_STATE)
2203 break;
2204
2205 acceptSystemWakeEvents(true);
2206
2207 // re-enable this timer for next sleep
2208 cancelIdleSleepTimer();
2209
2210 clock_sec_t secs;
2211 clock_usec_t microsecs;
2212 clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &now);
2213 logtime(secs);
2214 gIOLastSleepTime.tv_sec = secs;
2215 gIOLastSleepTime.tv_usec = microsecs;
2216 gIOLastWakeTime.tv_sec = 0;
2217 gIOLastWakeTime.tv_usec = 0;
2218 gIOLastSleepAbsTime = now;
2219
2220 if (wake2DarkwakeDelay && sleepDelaysReport) {
2221 clock_usec_t microsecs;
2222 clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
2223 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2224
2225 SUB_ABSOLUTETIME(&now, &ts_sleepStart);
2226 absolutetime_to_microtime(now, &darkwake2SleepSecs, &microsecs);
2227 absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, &microsecs);
2228 HISTREPORT_TALLYVALUE(sleepDelaysReport,
2229 (int64_t)(wake2DarkwakeSecs+darkwake2SleepSecs));
2230
2231 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
2232 wake2DarkwakeDelay = 0;
2233 }
2234#if HIBERNATION
2235 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2236
2237 IOHibernateSystemHasSlept();
2238
2239 evaluateSystemSleepPolicyFinal();
2240#else
2241 LOG("System Sleep\n");
2242#endif
2243 if (thermalWarningState) {
2244 const OSSymbol *event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
2245 if (event) {
2246 systemPowerEventOccurred(event, kIOPMThermalLevelUnknown);
2247 event->release();
2248 }
2249 }
2250 assertOnWakeSecs = 0;
2251 ((IOService *)this)->stop_watchdog_timer(); //14456299
2252 lowBatteryCondition = false;
2253
2254 getPlatform()->sleepKernel();
2255
2256 // The CPU(s) are off at this point,
2257 // Code will resume execution here upon wake.
2258
2259 clock_get_uptime(&gIOLastWakeAbsTime);
2260 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
2261 _highestCapability = 0;
2262
2263 ((IOService *)this)->start_watchdog_timer(); //14456299
2264#if HIBERNATION
2265 IOHibernateSystemWake();
2266#endif
2267
2268 // sleep transition complete
2269 gSleepOrShutdownPending = 0;
2270
2271 // trip the reset of the calendar clock
2272 {
2273 clock_sec_t wakeSecs;
2274 clock_usec_t wakeMicrosecs;
2275
2276 clock_initialize_calendar();
2277
2278 clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
2279 gIOLastWakeTime.tv_sec = wakeSecs;
2280 gIOLastWakeTime.tv_usec = wakeMicrosecs;
2281 }
2282
2283#if HIBERNATION
2284 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2285#endif
2286
2287 lastSleepReason = 0;
2288
2289 _lastDebugWakeSeconds = _debugWakeSeconds;
2290 _debugWakeSeconds = 0;
2291 _scheduledAlarms = 0;
2292
2293#if defined(__i386__) || defined(__x86_64__)
2294 kdebugTrace(kPMLogSystemWake, 0, 0, 0);
2295 wranglerTickled = false;
2296 graphicsSuppressed = false;
2297 darkWakePostTickle = false;
2298 darkWakeHibernateError = false;
2299 darkWakeToSleepASAP = true;
2300 logGraphicsClamp = true;
2301 sleepTimerMaintenance = false;
2302 sleepToStandby = false;
2303 wranglerTickleLatched = false;
2304 userWasActive = false;
2305 fullWakeReason = kFullWakeReasonNone;
2306
2307 OSString * wakeType = OSDynamicCast(
2308 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2309 OSString * wakeReason = OSDynamicCast(
2310 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2311
2312 if (wakeReason && (wakeReason->getLength() >= 2) &&
2313 gWakeReasonString[0] == '\0')
2314 {
2315 // Until the platform driver can claim its wake reasons
2316 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
2317 sizeof(gWakeReasonString));
2318 }
2319
2320 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2321 {
2322 lowBatteryCondition = true;
2323 darkWakeMaintenance = true;
2324 }
2325 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2326 {
2327#if HIBERNATION
2328 OSNumber * hibOptions = OSDynamicCast(
2329 OSNumber, getProperty(kIOHibernateOptionsKey));
2330 if (hibernateAborted || ((hibOptions &&
2331 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
2332 {
2333 // Hibernate aborted, or EFI brought up graphics
2334 wranglerTickled = true;
2335 DLOG("hibernation aborted %d, options 0x%x\n",
2336 hibernateAborted,
2337 hibOptions ? hibOptions->unsigned32BitValue() : 0);
2338 }
2339 else
2340#endif
2341 if (wakeType && (
2342 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2343 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
2344 {
2345 // User wake or RTC alarm
2346 wranglerTickled = true;
2347 }
2348 else
2349 if (wakeType &&
2350 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2351 {
2352 // SMC standby timer trumps SleepX
2353 darkWakeMaintenance = true;
2354 sleepTimerMaintenance = true;
2355 }
2356 else
2357 if ((_lastDebugWakeSeconds != 0) &&
2358 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
2359 {
2360 // SleepX before maintenance
2361 wranglerTickled = true;
2362 }
2363 else
2364 if (wakeType &&
2365 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2366 {
2367 darkWakeMaintenance = true;
2368 }
2369 else
2370 if (wakeType &&
2371 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
2372 {
2373 darkWakeMaintenance = true;
2374 darkWakeSleepService = true;
2375#if HIBERNATION
2376 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2377 sleepToStandby = true;
2378 }
2379#endif
2380 }
2381 else
2382 if (wakeType &&
2383 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError))
2384 {
2385 darkWakeMaintenance = true;
2386 darkWakeHibernateError = true;
2387 }
2388 else
2389 {
2390 // Unidentified wake source, resume to full wake if debug
2391 // alarm is pending.
2392
2393 if (_lastDebugWakeSeconds &&
2394 (!wakeReason || wakeReason->isEqualTo("")))
2395 wranglerTickled = true;
2396 }
2397 }
2398 else
2399 {
2400 if (wakeType &&
2401 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2402 {
2403 darkWakeMaintenance = true;
2404 sleepTimerMaintenance = true;
2405 }
2406 else if (hibernateAborted || !wakeType ||
2407 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
2408 !wakeReason || !wakeReason->isEqualTo("RTC"))
2409 {
2410 // Post a HID tickle immediately - except for RTC maintenance wake.
2411 wranglerTickled = true;
2412 }
2413 else
2414 {
2415 darkWakeMaintenance = true;
2416 }
2417 }
2418
2419 if (wranglerTickled)
2420 {
2421 darkWakeToSleepASAP = false;
2422 fullWakeReason = kFullWakeReasonLocalUser;
2423 reportUserInput();
2424 }
2425 else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
2426 {
2427 handleDisplayPowerOn();
2428 }
2429 else if (!darkWakeMaintenance)
2430 {
2431 // Early/late tickle for non-maintenance wake.
2432 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2433 kDarkWakeFlagHIDTickleEarly) ||
2434 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2435 kDarkWakeFlagHIDTickleLate))
2436 {
2437 darkWakePostTickle = true;
2438 }
2439 }
2440#else /* !__i386__ && !__x86_64__ */
2441 kdebugTrace(kPMLogSystemWake, 0, ml_get_wake_timebase() >> 32, ml_get_wake_timebase());
2442 // stay awake for at least 30 seconds
2443 wranglerTickled = true;
2444 fullWakeReason = kFullWakeReasonLocalUser;
2445 startIdleSleepTimer(30);
2446#endif
2447 sleepCnt++;
2448
2449 thread_call_enter(updateConsoleUsersEntry);
2450
2451 changePowerStateToPriv(ON_STATE);
2452 } break;
2453#if !__i386__ && !__x86_64__
2454 case ON_STATE: {
2455 if (previousPowerState != ON_STATE)
2456 {
2457 DLOG("Force re-evaluating aggressiveness\n");
2458 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2459 pmPowerStateQueue->submitPowerEvent(
2460 kPowerEventPolicyStimulus,
2461 (void *) kStimulusNoIdleSleepPreventers );
2462 }
2463 break;
2464 }
2465
2466#endif
2467
2468 }
2469}
2470
2471//******************************************************************************
2472// requestPowerDomainState
2473//
2474// Extend implementation in IOService. Running on PM work loop thread.
2475//******************************************************************************
2476
2477IOReturn IOPMrootDomain::requestPowerDomainState (
2478 IOPMPowerFlags childDesire,
2479 IOPowerConnection * childConnection,
2480 unsigned long specification )
2481{
2482 // Idle and system sleep prevention flags affects driver desire.
2483 // Children desire are irrelevant so they are cleared.
2484
2485 return super::requestPowerDomainState(0, childConnection, specification);
2486}
2487
2488
2489//******************************************************************************
2490// updatePreventIdleSleepList
2491//
2492// Called by IOService on PM work loop.
2493// Returns true if PM policy recognized the driver's desire to prevent idle
2494// sleep and updated the list of idle sleep preventers. Returns false otherwise
2495//******************************************************************************
2496
2497bool IOPMrootDomain::updatePreventIdleSleepList(
2498 IOService * service, bool addNotRemove )
2499{
2500 unsigned int oldCount, newCount;
2501
2502 ASSERT_GATED();
2503
2504#if defined(__i386__) || defined(__x86_64__)
2505 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2506 // idle sleep, except in the case of legacy disk I/O
2507 if ((service != wrangler) && (service != this))
2508 {
2509 return false;
2510 }
2511#endif
2512
2513 oldCount = preventIdleSleepList->getCount();
2514 if (addNotRemove)
2515 {
2516 preventIdleSleepList->setObject(service);
2517 DLOG("prevent idle sleep list: %s+ (%u)\n",
2518 service->getName(), preventIdleSleepList->getCount());
2519 }
2520 else if (preventIdleSleepList->member(service))
2521 {
2522 preventIdleSleepList->removeObject(service);
2523 DLOG("prevent idle sleep list: %s- (%u)\n",
2524 service->getName(), preventIdleSleepList->getCount());
2525 }
2526 newCount = preventIdleSleepList->getCount();
2527
2528 if ((oldCount == 0) && (newCount != 0))
2529 {
2530 // Driver added to empty prevent list.
2531 // Update the driver desire to prevent idle sleep.
2532 // Driver desire does not prevent demand sleep.
2533
2534 changePowerStateTo(ON_STATE);
2535 }
2536 else if ((oldCount != 0) && (newCount == 0))
2537 {
2538 // Last driver removed from prevent list.
2539 // Drop the driver clamp to allow idle sleep.
2540
2541 changePowerStateTo(SLEEP_STATE);
2542 evaluatePolicy( kStimulusNoIdleSleepPreventers );
2543 }
2544 messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier,
2545 &newCount, sizeof(newCount));
2546
2547#if defined(__i386__) || defined(__x86_64__)
2548 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
2549 {
2550 return false; // do not idle-cancel
2551 }
2552#endif
2553
2554 MSG("prevent idle sleep list: %s%c (%u)\n",
2555 service->getName(),
2556 (addNotRemove) ? '+' : '-', newCount);
2557 return true;
2558}
2559
2560//******************************************************************************
2561// preventSystemSleepListUpdate
2562//
2563// Called by IOService on PM work loop.
2564//******************************************************************************
2565
2566void IOPMrootDomain::updatePreventSystemSleepList(
2567 IOService * service, bool addNotRemove )
2568{
2569 unsigned int oldCount, newCount;
2570
2571 ASSERT_GATED();
2572 if (this == service)
2573 return;
2574
2575 oldCount = preventSystemSleepList->getCount();
2576 if (addNotRemove)
2577 {
2578 preventSystemSleepList->setObject(service);
2579 DLOG("prevent system sleep list: %s+ (%u)\n",
2580 service->getName(), preventSystemSleepList->getCount());
2581 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
2582 AbsoluteTime now;
2583 clock_usec_t microsecs;
2584 clock_get_uptime(&now);
2585 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2586 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2587 if (assertOnWakeReport) {
2588 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2589 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2590 }
2591 }
2592 }
2593 else if (preventSystemSleepList->member(service))
2594 {
2595 preventSystemSleepList->removeObject(service);
2596 DLOG("prevent system sleep list: %s- (%u)\n",
2597 service->getName(), preventSystemSleepList->getCount());
2598
2599 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
2600 {
2601 // Lost all system sleep preventers.
2602 // Send stimulus if system sleep was blocked, and is in dark wake.
2603 evaluatePolicy( kStimulusDarkWakeEvaluate );
2604 }
2605 }
2606 newCount = preventSystemSleepList->getCount();
2607 messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier,
2608 &newCount, sizeof(newCount));
2609}
2610
2611void IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
2612{
2613
2614 OSCollectionIterator *iterator = NULL;
2615 OSObject *object = NULL;
2616 OSArray *array = NULL;
2617
2618 if (!gIOPMWorkLoop->inGate())
2619 {
2620 gIOPMWorkLoop->runAction(
2621 OSMemberFunctionCast(IOWorkLoop::Action, this,
2622 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
2623 this, (void *)idleSleepList, (void *)systemSleepList);
2624 return;
2625 }
2626
2627 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0))
2628 {
2629 iterator = OSCollectionIterator::withCollection(preventIdleSleepList);
2630 array = OSArray::withCapacity(5);
2631
2632 while ((object = iterator->getNextObject()))
2633 {
2634 IOService *service = OSDynamicCast(IOService, object);
2635 if (object)
2636 {
2637 array->setObject(OSSymbol::withCString(service->getName()));
2638 }
2639 }
2640
2641 iterator->release();
2642 *idleSleepList = array;
2643 }
2644
2645 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0))
2646 {
2647 iterator = OSCollectionIterator::withCollection(preventSystemSleepList);
2648 array = OSArray::withCapacity(5);
2649
2650 while ((object = iterator->getNextObject()))
2651 {
2652 IOService *service = OSDynamicCast(IOService, object);
2653 if (object)
2654 {
2655 array->setObject(OSSymbol::withCString(service->getName()));
2656 }
2657 }
2658
2659 iterator->release();
2660 *systemSleepList = array;
2661 }
2662}
2663
2664//******************************************************************************
2665// tellChangeDown
2666//
2667// Override the superclass implementation to send a different message type.
2668//******************************************************************************
2669
2670bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
2671{
2672 DLOG("tellChangeDown %u->%u\n",
2673 (uint32_t) getPowerState(), (uint32_t) stateNum);
2674
2675 if (SLEEP_STATE == stateNum)
2676 {
2677 // Legacy apps were already told in the full->dark transition
2678 if (!ignoreTellChangeDown)
2679 tracePoint( kIOPMTracePointSleepApplications );
2680 else
2681 tracePoint( kIOPMTracePointSleepPriorityClients );
2682 }
2683
2684 if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
2685 {
2686 userActivityAtSleep = userActivityCount;
2687 hibernateAborted = false;
2688 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
2689
2690 // Direct callout into OSKext so it can disable kext unloads
2691 // during sleep/wake to prevent deadlocks.
2692 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
2693
2694 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
2695
2696 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2697 // But tellClientsWithResponse() must be called for both.
2698 ignoreTellChangeDown = true;
2699 }
2700
2701 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2702}
2703
2704//******************************************************************************
2705// askChangeDown
2706//
2707// Override the superclass implementation to send a different message type.
2708// This must be idle sleep since we don't ask during any other power change.
2709//******************************************************************************
2710
2711bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
2712{
2713 DLOG("askChangeDown %u->%u\n",
2714 (uint32_t) getPowerState(), (uint32_t) stateNum);
2715
2716 // Don't log for dark wake entry
2717 if (kSystemTransitionSleep == _systemTransitionType)
2718 tracePoint( kIOPMTracePointSleepApplications );
2719
2720 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
2721}
2722
2723//******************************************************************************
2724// askChangeDownDone
2725//
2726// An opportunity for root domain to cancel the power transition,
2727// possibily due to an assertion created by powerd in response to
2728// kIOMessageCanSystemSleep.
2729//
2730// Idle sleep:
2731// full -> dark wake transition
2732// 1. Notify apps and powerd with kIOMessageCanSystemSleep
2733// 2. askChangeDownDone()
2734// dark -> sleep transition
2735// 1. Notify powerd with kIOMessageCanSystemSleep
2736// 2. askChangeDownDone()
2737//
2738// Demand sleep:
2739// full -> dark wake transition
2740// 1. Notify powerd with kIOMessageCanSystemSleep
2741// 2. askChangeDownDone()
2742// dark -> sleep transition
2743// 1. Notify powerd with kIOMessageCanSystemSleep
2744// 2. askChangeDownDone()
2745//******************************************************************************
2746
2747void IOPMrootDomain::askChangeDownDone(
2748 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
2749{
2750 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2751 *inOutChangeFlags, *cancel,
2752 _systemTransitionType,
2753 _currentCapability, _pendingCapability);
2754
2755 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2756 {
2757 // Dark->Sleep transition.
2758 // Check if there are any deny sleep assertions.
2759 // lastSleepReason already set by handleOurPowerChangeStart()
2760
2761 if (!checkSystemCanSleep(lastSleepReason))
2762 {
2763 // Cancel dark wake to sleep transition.
2764 // Must re-scan assertions upon entering dark wake.
2765
2766 *cancel = true;
2767 DLOG("cancel dark->sleep\n");
2768 }
2769 }
2770}
2771
2772//******************************************************************************
2773// systemDidNotSleep
2774//
2775// Work common to both canceled or aborted sleep.
2776//******************************************************************************
2777
2778void IOPMrootDomain::systemDidNotSleep( void )
2779{
2780 // reset console lock state
2781 thread_call_enter(updateConsoleUsersEntry);
2782
2783 if (!wrangler)
2784 {
2785 if (idleSleepEnabled)
2786 {
2787 // stay awake for at least idleSeconds
2788 startIdleSleepTimer(idleSeconds);
2789 }
2790 }
2791 else
2792 {
2793 if (idleSleepEnabled && !userIsActive)
2794 {
2795 // Manually start the idle sleep timer besides waiting for
2796 // the user to become inactive.
2797 startIdleSleepTimer( kIdleSleepRetryInterval );
2798 }
2799 }
2800
2801 preventTransitionToUserActive(false);
2802 IOService::setAdvisoryTickleEnable( true );
2803
2804 // After idle revert and cancel, send a did-change message to powerd
2805 // to balance the previous will-change message. Kernel clients do not
2806 // need this since sleep cannot be canceled once they are notified.
2807
2808 if (toldPowerdCapWillChange && systemCapabilityNotifier &&
2809 (_pendingCapability != _currentCapability) &&
2810 ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0))
2811 {
2812 // Differs from a real capability gain change where notifyRef != 0,
2813 // but it is zero here since no response is expected.
2814
2815 IOPMSystemCapabilityChangeParameters params;
2816
2817 bzero(&params, sizeof(params));
2818 params.fromCapabilities = _pendingCapability;
2819 params.toCapabilities = _currentCapability;
2820 params.changeFlags = kIOPMSystemCapabilityDidChange;
2821
2822 DLOG("MESG cap %x->%x did change\n",
2823 params.fromCapabilities, params.toCapabilities);
2824 messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier,
2825 &params, sizeof(params));
2826 }
2827}
2828
2829//******************************************************************************
2830// tellNoChangeDown
2831//
2832// Notify registered applications and kernel clients that we are not dropping
2833// power.
2834//
2835// We override the superclass implementation so we can send a different message
2836// type to the client or application being notified.
2837//
2838// This must be a vetoed idle sleep, since no other power change can be vetoed.
2839//******************************************************************************
2840
2841void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2842{
2843 DLOG("tellNoChangeDown %u->%u\n",
2844 (uint32_t) getPowerState(), (uint32_t) stateNum);
2845
2846 // Sleep canceled, clear the sleep trace point.
2847 tracePoint(kIOPMTracePointSystemUp);
2848
2849 systemDidNotSleep();
2850 return tellClients( kIOMessageSystemWillNotSleep );
2851}
2852
2853//******************************************************************************
2854// tellChangeUp
2855//
2856// Notify registered applications and kernel clients that we are raising power.
2857//
2858// We override the superclass implementation so we can send a different message
2859// type to the client or application being notified.
2860//******************************************************************************
2861
2862void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
2863{
2864 DLOG("tellChangeUp %u->%u\n",
2865 (uint32_t) getPowerState(), (uint32_t) stateNum);
2866
2867 ignoreTellChangeDown = false;
2868
2869 if ( stateNum == ON_STATE )
2870 {
2871 // Direct callout into OSKext so it can disable kext unloads
2872 // during sleep/wake to prevent deadlocks.
2873 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2874
2875 // Notify platform that sleep was cancelled or resumed.
2876 getPlatform()->callPlatformFunction(
2877 sleepMessagePEFunction, false,
2878 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
2879 NULL, NULL, NULL);
2880
2881 if (getPowerState() == ON_STATE)
2882 {
2883 // this is a quick wake from aborted sleep
2884 systemDidNotSleep();
2885 tellClients( kIOMessageSystemWillPowerOn );
2886 }
2887
2888 tracePoint( kIOPMTracePointWakeApplications );
2889 tellClients( kIOMessageSystemHasPoweredOn );
2890 }
2891}
2892
2893#define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2894 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2895 ((params)->fromCapabilities & (flag)) && \
2896 (((params)->toCapabilities & (flag)) == 0))
2897
2898#define CAP_DID_CHANGE_TO_ON(params, flag) \
2899 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2900 ((params)->toCapabilities & (flag)) && \
2901 (((params)->fromCapabilities & (flag)) == 0))
2902
2903#define CAP_DID_CHANGE_TO_OFF(params, flag) \
2904 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2905 ((params)->fromCapabilities & (flag)) && \
2906 (((params)->toCapabilities & (flag)) == 0))
2907
2908#define CAP_WILL_CHANGE_TO_ON(params, flag) \
2909 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2910 ((params)->toCapabilities & (flag)) && \
2911 (((params)->fromCapabilities & (flag)) == 0))
2912
2913//******************************************************************************
2914// sysPowerDownHandler
2915//
2916// Perform a vfs sync before system sleep.
2917//******************************************************************************
2918
2919IOReturn IOPMrootDomain::sysPowerDownHandler(
2920 void * target, void * refCon,
2921 UInt32 messageType, IOService * service,
2922 void * messageArgs, vm_size_t argSize )
2923{
2924 IOReturn ret = 0;
2925
2926 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
2927
2928 if (!gRootDomain)
2929 return kIOReturnUnsupported;
2930
2931 if (messageType == kIOMessageSystemWillSleep)
2932 {
2933#if HIBERNATION
2934 IOPowerStateChangeNotification *notify =
2935 (IOPowerStateChangeNotification *)messageArgs;
2936
2937 notify->returnValue = 30 * 1000 * 1000;
2938 thread_call_enter1(
2939 gRootDomain->swdDebugSetupEntry,
2940 (thread_call_param_t)(uintptr_t) notify->powerRef);
2941#endif
2942 }
2943 else if (messageType == kIOMessageSystemCapabilityChange)
2944 {
2945 IOPMSystemCapabilityChangeParameters * params =
2946 (IOPMSystemCapabilityChangeParameters *) messageArgs;
2947
2948 // Interested applications have been notified of an impending power
2949 // change and have acked (when applicable).
2950 // This is our chance to save whatever state we can before powering
2951 // down.
2952 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2953 // via callout
2954
2955 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2956 params->fromCapabilities, params->toCapabilities,
2957 params->changeFlags);
2958
2959 if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU))
2960 {
2961 // We will ack within 20 seconds
2962 params->maxWaitForReply = 20 * 1000 * 1000;
2963
2964 // Remove EFI/BootRom's previous wake's failure data
2965 PERemoveNVRAMProperty(kIOEFIBootRomFailureKey);
2966
2967#if HIBERNATION
2968 gRootDomain->evaluateSystemSleepPolicyEarly();
2969
2970 // add in time we could spend freeing pages
2971 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
2972 {
2973 params->maxWaitForReply = kCapabilityClientMaxWait;
2974 }
2975 DLOG("sysPowerDownHandler max wait %d s\n",
2976 (int) (params->maxWaitForReply / 1000 / 1000));
2977#endif
2978
2979 // Notify platform that sleep has begun, after the early
2980 // sleep policy evaluation.
2981 getPlatform()->callPlatformFunction(
2982 sleepMessagePEFunction, false,
2983 (void *)(uintptr_t) kIOMessageSystemWillSleep,
2984 NULL, NULL, NULL);
2985
2986 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2987 {
2988 // Purposely delay the ack and hope that shutdown occurs quickly.
2989 // Another option is not to schedule the thread and wait for
2990 // ack timeout...
2991 AbsoluteTime deadline;
2992 clock_interval_to_deadline( 30, kSecondScale, &deadline );
2993 thread_call_enter1_delayed(
2994 gRootDomain->diskSyncCalloutEntry,
2995 (thread_call_param_t)(uintptr_t) params->notifyRef,
2996 deadline );
2997 }
2998 else
2999 thread_call_enter1(
3000 gRootDomain->diskSyncCalloutEntry,
3001 (thread_call_param_t)(uintptr_t) params->notifyRef);
3002 }
3003#if HIBERNATION
3004 else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU))
3005 {
3006 // We will ack within 110 seconds
3007 params->maxWaitForReply = 110 * 1000 * 1000;
3008
3009 thread_call_enter1(
3010 gRootDomain->diskSyncCalloutEntry,
3011 (thread_call_param_t)(uintptr_t) params->notifyRef);
3012 }
3013 else if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityGraphics) ||
3014 CAP_WILL_CHANGE_TO_ON(params, kIOPMSystemCapabilityGraphics))
3015 {
3016 // WillChange for Full wake -> Darkwake
3017 params->maxWaitForReply = 30 * 1000 * 1000;
3018 thread_call_enter1(
3019 gRootDomain->swdDebugSetupEntry,
3020 (thread_call_param_t)(uintptr_t) params->notifyRef);
3021 }
3022 else if (CAP_DID_CHANGE_TO_OFF(params, kIOPMSystemCapabilityGraphics) ||
3023 CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityGraphics))
3024 {
3025 // DidChange for Full wake -> Darkwake
3026 params->maxWaitForReply = 30 * 1000 * 1000;
3027 thread_call_enter1(
3028 gRootDomain->swdDebugTearDownEntry,
3029 (thread_call_param_t)(uintptr_t) params->notifyRef);
3030
3031 }
3032#endif
3033 ret = kIOReturnSuccess;
3034 }
3035
3036 return ret;
3037}
3038
3039//******************************************************************************
3040// handleQueueSleepWakeUUID
3041//
3042// Called from IOPMrootDomain when we're initiating a sleep,
3043// or indirectly from PM configd when PM decides to clear the UUID.
3044// PM clears the UUID several minutes after successful wake from sleep,
3045// so that we might associate App spindumps with the immediately previous
3046// sleep/wake.
3047//
3048// @param obj has a retain on it. We're responsible for releasing that retain.
3049//******************************************************************************
3050
3051void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
3052{
3053 OSString *str = NULL;
3054
3055 if (kOSBooleanFalse == obj)
3056 {
3057 handlePublishSleepWakeUUID(NULL);
3058 }
3059 else if ((str = OSDynamicCast(OSString, obj)))
3060 {
3061 // This branch caches the UUID for an upcoming sleep/wake
3062 if (queuedSleepWakeUUIDString) {
3063 queuedSleepWakeUUIDString->release();
3064 queuedSleepWakeUUIDString = NULL;
3065 }
3066 queuedSleepWakeUUIDString = str;
3067 queuedSleepWakeUUIDString->retain();
3068
3069 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
3070 }
3071
3072 if (obj) {
3073 obj->release();
3074 }
3075 return;
3076
3077}
3078//******************************************************************************
3079// handlePublishSleepWakeUUID
3080//
3081// Called from IOPMrootDomain when we're initiating a sleep,
3082// or indirectly from PM configd when PM decides to clear the UUID.
3083// PM clears the UUID several minutes after successful wake from sleep,
3084// so that we might associate App spindumps with the immediately previous
3085// sleep/wake.
3086//******************************************************************************
3087
3088void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
3089{
3090 ASSERT_GATED();
3091
3092 /*
3093 * Clear the current UUID
3094 */
3095 if (gSleepWakeUUIDIsSet)
3096 {
3097 DLOG("SleepWake UUID cleared\n");
3098
3099 gSleepWakeUUIDIsSet = false;
3100
3101 removeProperty(kIOPMSleepWakeUUIDKey);
3102 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
3103 }
3104
3105 /*
3106 * Optionally, publish a new UUID
3107 */
3108 if (queuedSleepWakeUUIDString && shouldPublish) {
3109
3110 OSString *publishThisUUID = NULL;
3111
3112 publishThisUUID = queuedSleepWakeUUIDString;
3113 publishThisUUID->retain();
3114
3115 if (publishThisUUID)
3116 {
3117 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
3118 publishThisUUID->release();
3119 }
3120
3121 gSleepWakeUUIDIsSet = true;
3122 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
3123
3124 queuedSleepWakeUUIDString->release();
3125 queuedSleepWakeUUIDString = NULL;
3126 }
3127}
3128
3129//******************************************************************************
3130// initializeBootSessionUUID
3131//
3132// Initialize the boot session uuid at boot up and sets it into registry.
3133//******************************************************************************
3134
3135void IOPMrootDomain::initializeBootSessionUUID(void)
3136{
3137 uuid_t new_uuid;
3138 uuid_string_t new_uuid_string;
3139
3140 uuid_generate(new_uuid);
3141 uuid_unparse_upper(new_uuid, new_uuid_string);
3142 memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
3143
3144 setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
3145}
3146
3147//******************************************************************************
3148// changePowerStateTo & changePowerStateToPriv
3149//
3150// Override of these methods for logging purposes.
3151//******************************************************************************
3152
3153IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
3154{
3155 DLOG("changePowerStateTo(%lu)\n", ordinal);
3156
3157 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3158 return kIOReturnUnsupported;
3159
3160 return super::changePowerStateTo(ordinal);
3161}
3162
3163IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
3164{
3165 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
3166
3167 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3168 return kIOReturnUnsupported;
3169
3170 return super::changePowerStateToPriv(ordinal);
3171}
3172
3173//******************************************************************************
3174// activity detect
3175//
3176//******************************************************************************
3177
3178bool IOPMrootDomain::activitySinceSleep(void)
3179{
3180 return (userActivityCount != userActivityAtSleep);
3181}
3182
3183bool IOPMrootDomain::abortHibernation(void)
3184{
3185 bool ret = activitySinceSleep();
3186
3187 if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
3188 {
3189 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
3190 hibernateAborted = true;
3191 }
3192 return (ret);
3193}
3194
3195extern "C" int
3196hibernate_should_abort(void)
3197{
3198 if (gRootDomain)
3199 return (gRootDomain->abortHibernation());
3200 else
3201 return (0);
3202}
3203
3204//******************************************************************************
3205// willNotifyPowerChildren
3206//
3207// Called after all interested drivers have all acknowledged the power change,
3208// but before any power children is informed. Dispatched though a thread call,
3209// so it is safe to perform work that might block on a sleeping disk. PM state
3210// machine (not thread) will block w/o timeout until this function returns.
3211//******************************************************************************
3212
3213void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
3214{
3215 OSDictionary *dict;
3216 OSNumber *secs;
3217
3218 if (SLEEP_STATE == newPowerState)
3219 {
3220 if (!tasksSuspended)
3221 {
3222 AbsoluteTime deadline;
3223 tasksSuspended = TRUE;
3224 tasks_system_suspend(tasksSuspended);
3225
3226 clock_interval_to_deadline(10, kSecondScale, &deadline);
3227 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
3228 }
3229
3230#if HIBERNATION
3231 IOHibernateSystemSleep();
3232 IOHibernateIOKitSleep();
3233#endif
3234 if (gRootDomain->activitySinceSleep()) {
3235 dict = OSDictionary::withCapacity(1);
3236 secs = OSNumber::withNumber(1, 32);
3237
3238 if (dict && secs) {
3239 dict->setObject(gIOPMSettingDebugWakeRelativeKey, secs);
3240 gRootDomain->setProperties(dict);
3241 MSG("Reverting sleep with relative wake\n");
3242 }
3243 if (dict) dict->release();
3244 if (secs) secs->release();
3245 }
3246
3247 }
3248}
3249
3250//******************************************************************************
3251// sleepOnClamshellClosed
3252//
3253// contains the logic to determine if the system should sleep when the clamshell
3254// is closed.
3255//******************************************************************************
3256
3257bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3258{
3259 if (!clamshellExists)
3260 return false;
3261
3262 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3263 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
3264
3265 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
3266}
3267
3268void IOPMrootDomain::sendClientClamshellNotification( void )
3269{
3270 /* Only broadcast clamshell alert if clamshell exists. */
3271 if (!clamshellExists)
3272 return;
3273
3274 setProperty(kAppleClamshellStateKey,
3275 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
3276
3277 setProperty(kAppleClamshellCausesSleepKey,
3278 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
3279
3280 /* Argument to message is a bitfiel of
3281 * ( kClamshellStateBit | kClamshellSleepBit )
3282 */
3283 messageClients(kIOPMMessageClamshellStateChange,
3284 (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0)
3285 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
3286}
3287
3288//******************************************************************************
3289// getSleepSupported
3290//
3291// Deprecated
3292//******************************************************************************
3293
3294IOOptionBits IOPMrootDomain::getSleepSupported( void )
3295{
3296 return( platformSleepSupport );
3297}
3298
3299//******************************************************************************
3300// setSleepSupported
3301//
3302// Deprecated
3303//******************************************************************************
3304
3305void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
3306{
3307 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
3308 OSBitOrAtomic(flags, &platformSleepSupport);
3309}
3310
3311//******************************************************************************
3312// setDisableClamShellSleep
3313//
3314//******************************************************************************
3315
3316void IOPMrootDomain::setDisableClamShellSleep( bool val )
3317{
3318 if (gIOPMWorkLoop->inGate() == false) {
3319
3320 gIOPMWorkLoop->runAction(
3321 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
3322 (OSObject *)this,
3323 (void *)val);
3324
3325 return;
3326 }
3327 else {
3328 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
3329 if ( clamshellSleepDisabled != val )
3330 {
3331 clamshellSleepDisabled = val;
3332 // If clamshellSleepDisabled is reset to 0, reevaluate if
3333 // system need to go to sleep due to clamshell state
3334 if ( !clamshellSleepDisabled && clamshellClosed)
3335 handlePowerNotification(kLocalEvalClamshellCommand);
3336 }
3337 }
3338}
3339
3340//******************************************************************************
3341// wakeFromDoze
3342//
3343// Deprecated.
3344//******************************************************************************
3345
3346void IOPMrootDomain::wakeFromDoze( void )
3347{
3348 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3349}
3350
3351// MARK: -
3352// MARK: Features
3353
3354//******************************************************************************
3355// publishFeature
3356//
3357// Adds a new feature to the supported features dictionary
3358//******************************************************************************
3359
3360void IOPMrootDomain::publishFeature( const char * feature )
3361{
3362 publishFeature(feature, kRD_AllPowerSources, NULL);
3363}
3364
3365//******************************************************************************
3366// publishFeature (with supported power source specified)
3367//
3368// Adds a new feature to the supported features dictionary
3369//******************************************************************************
3370
3371void IOPMrootDomain::publishFeature(
3372 const char *feature,
3373 uint32_t supportedWhere,
3374 uint32_t *uniqueFeatureID)
3375{
3376 static uint16_t next_feature_id = 500;
3377
3378 OSNumber *new_feature_data = NULL;
3379 OSNumber *existing_feature = NULL;
3380 OSArray *existing_feature_arr = NULL;
3381 OSObject *osObj = NULL;
3382 uint32_t feature_value = 0;
3383
3384 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
3385
3386 if(!supportedWhere) {
3387 // Feature isn't supported anywhere!
3388 return;
3389 }
3390
3391 if(next_feature_id > 5000) {
3392 // Far, far too many features!
3393 return;
3394 }
3395
3396 if(featuresDictLock) IOLockLock(featuresDictLock);
3397
3398 OSDictionary *features =
3399 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3400
3401 // Create new features dict if necessary
3402 if ( features && OSDynamicCast(OSDictionary, features)) {
3403 features = OSDictionary::withDictionary(features);
3404 } else {
3405 features = OSDictionary::withCapacity(1);
3406 }
3407
3408 // Create OSNumber to track new feature
3409
3410 next_feature_id += 1;
3411 if( uniqueFeatureID ) {
3412 // We don't really mind if the calling kext didn't give us a place
3413 // to stash their unique id. Many kexts don't plan to unload, and thus
3414 // have no need to remove themselves later.
3415 *uniqueFeatureID = next_feature_id;
3416 }
3417
3418 feature_value = (uint32_t)next_feature_id;
3419 feature_value <<= 16;
3420 feature_value += supportedWhere;
3421
3422 new_feature_data = OSNumber::withNumber(
3423 (unsigned long long)feature_value, 32);
3424
3425 // Does features object already exist?
3426 if( (osObj = features->getObject(feature)) )
3427 {
3428 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
3429 {
3430 // We need to create an OSArray to hold the now 2 elements.
3431 existing_feature_arr = OSArray::withObjects(
3432 (const OSObject **)&existing_feature, 1, 2);
3433 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
3434 {
3435 // Add object to existing array
3436 existing_feature_arr = OSArray::withArray(
3437 existing_feature_arr,
3438 existing_feature_arr->getCount() + 1);
3439 }
3440
3441 if (existing_feature_arr)
3442 {
3443 existing_feature_arr->setObject(new_feature_data);
3444 features->setObject(feature, existing_feature_arr);
3445 existing_feature_arr->release();
3446 existing_feature_arr = 0;
3447 }
3448 } else {
3449 // The easy case: no previously existing features listed. We simply
3450 // set the OSNumber at key 'feature' and we're on our way.
3451 features->setObject(feature, new_feature_data);
3452 }
3453
3454 new_feature_data->release();
3455
3456 setProperty(kRootDomainSupportedFeatures, features);
3457
3458 features->release();
3459
3460 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3461
3462 // Notify EnergySaver and all those in user space so they might
3463 // re-populate their feature specific UI
3464 if(pmPowerStateQueue) {
3465 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3466 }
3467}
3468
3469//******************************************************************************
3470// removePublishedFeature
3471//
3472// Removes previously published feature
3473//******************************************************************************
3474
3475IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
3476{
3477 IOReturn ret = kIOReturnError;
3478 uint32_t feature_value = 0;
3479 uint16_t feature_id = 0;
3480 bool madeAChange = false;
3481
3482 OSSymbol *dictKey = NULL;
3483 OSCollectionIterator *dictIterator = NULL;
3484 OSArray *arrayMember = NULL;
3485 OSNumber *numberMember = NULL;
3486 OSObject *osObj = NULL;
3487 OSNumber *osNum = NULL;
3488 OSArray *arrayMemberCopy;
3489
3490 if (kBadPMFeatureID == removeFeatureID)
3491 return kIOReturnNotFound;
3492
3493 if(featuresDictLock) IOLockLock(featuresDictLock);
3494
3495 OSDictionary *features =
3496 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3497
3498 if ( features && OSDynamicCast(OSDictionary, features) )
3499 {
3500 // Any modifications to the dictionary are made to the copy to prevent
3501 // races & crashes with userland clients. Dictionary updated
3502 // automically later.
3503 features = OSDictionary::withDictionary(features);
3504 } else {
3505 features = NULL;
3506 ret = kIOReturnNotFound;
3507 goto exit;
3508 }
3509
3510 // We iterate 'features' dictionary looking for an entry tagged
3511 // with 'removeFeatureID'. If found, we remove it from our tracking
3512 // structures and notify the OS via a general interest message.
3513
3514 dictIterator = OSCollectionIterator::withCollection(features);
3515 if(!dictIterator) {
3516 goto exit;
3517 }
3518
3519 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
3520 {
3521 osObj = features->getObject(dictKey);
3522
3523 // Each Feature is either tracked by an OSNumber
3524 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
3525 {
3526 feature_value = numberMember->unsigned32BitValue();
3527 feature_id = (uint16_t)(feature_value >> 16);
3528
3529 if( feature_id == (uint16_t)removeFeatureID )
3530 {
3531 // Remove this node
3532 features->removeObject(dictKey);
3533 madeAChange = true;
3534 break;
3535 }
3536
3537 // Or tracked by an OSArray of OSNumbers
3538 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
3539 {
3540 unsigned int arrayCount = arrayMember->getCount();
3541
3542 for(unsigned int i=0; i<arrayCount; i++)
3543 {
3544 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
3545 if(!osNum) {
3546 continue;
3547 }
3548
3549 feature_value = osNum->unsigned32BitValue();
3550 feature_id = (uint16_t)(feature_value >> 16);
3551
3552 if( feature_id == (uint16_t)removeFeatureID )
3553 {
3554 // Remove this node
3555 if( 1 == arrayCount ) {
3556 // If the array only contains one element, remove
3557 // the whole thing.
3558 features->removeObject(dictKey);
3559 } else {
3560 // Otherwise remove the element from a copy of the array.
3561 arrayMemberCopy = OSArray::withArray(arrayMember);
3562 if (arrayMemberCopy)
3563 {
3564 arrayMemberCopy->removeObject(i);
3565 features->setObject(dictKey, arrayMemberCopy);
3566 arrayMemberCopy->release();
3567 }
3568 }
3569
3570 madeAChange = true;
3571 break;
3572 }
3573 }
3574 }
3575 }
3576
3577 dictIterator->release();
3578
3579 if( madeAChange )
3580 {
3581 ret = kIOReturnSuccess;
3582
3583 setProperty(kRootDomainSupportedFeatures, features);
3584
3585 // Notify EnergySaver and all those in user space so they might
3586 // re-populate their feature specific UI
3587 if(pmPowerStateQueue) {
3588 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3589 }
3590 } else {
3591 ret = kIOReturnNotFound;
3592 }
3593
3594exit:
3595 if(features) features->release();
3596 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3597 return ret;
3598}
3599
3600//******************************************************************************
3601// publishPMSetting (private)
3602//
3603// Should only be called by PMSettingObject to publish a PM Setting as a
3604// supported feature.
3605//******************************************************************************
3606
3607void IOPMrootDomain::publishPMSetting(
3608 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
3609{
3610 if (noPublishPMSettings &&
3611 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
3612 {
3613 // Setting found in noPublishPMSettings array
3614 *featureID = kBadPMFeatureID;
3615 return;
3616 }
3617
3618 publishFeature(
3619 feature->getCStringNoCopy(), where, featureID);
3620}
3621
3622//******************************************************************************
3623// setPMSetting (private)
3624//
3625// Internal helper to relay PM settings changes from user space to individual
3626// drivers. Should be called only by IOPMrootDomain::setProperties.
3627//******************************************************************************
3628
3629IOReturn IOPMrootDomain::setPMSetting(
3630 const OSSymbol *type,
3631 OSObject *object )
3632{
3633 PMSettingCallEntry *entries = 0;
3634 OSArray *chosen = 0;
3635 const OSArray *array;
3636 PMSettingObject *pmso;
3637 thread_t thisThread;
3638 int i, j, count, capacity;
3639
3640 if (NULL == type)
3641 return kIOReturnBadArgument;
3642
3643 PMSETTING_LOCK();
3644
3645 // Update settings dict so changes are visible from copyPMSetting().
3646 fPMSettingsDict->setObject(type, object);
3647
3648 // Prep all PMSetting objects with the given 'type' for callout.
3649 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
3650 if (!array || ((capacity = array->getCount()) == 0))
3651 goto unlock_exit;
3652
3653 // Array to retain PMSetting objects targeted for callout.
3654 chosen = OSArray::withCapacity(capacity);
3655 if (!chosen)
3656 goto unlock_exit; // error
3657
3658 entries = IONew(PMSettingCallEntry, capacity);
3659 if (!entries)
3660 goto unlock_exit; // error
3661 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3662
3663 thisThread = current_thread();
3664
3665 for (i = 0, j = 0; i<capacity; i++)
3666 {
3667 pmso = (PMSettingObject *) array->getObject(i);
3668 if (pmso->disabled)
3669 continue;
3670 entries[j].thread = thisThread;
3671 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3672 chosen->setObject(pmso);
3673 j++;
3674 }
3675 count = j;
3676 if (!count)
3677 goto unlock_exit;
3678
3679 PMSETTING_UNLOCK();
3680
3681 // Call each pmso in the chosen array.
3682 for (i=0; i<count; i++)
3683 {
3684 pmso = (PMSettingObject *) chosen->getObject(i);
3685 pmso->dispatchPMSetting(type, object);
3686 }
3687
3688 PMSETTING_LOCK();
3689 for (i=0; i<count; i++)
3690 {
3691 pmso = (PMSettingObject *) chosen->getObject(i);
3692 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3693 if (pmso->waitThread)
3694 {
3695 PMSETTING_WAKEUP(pmso);
3696 }
3697 }
3698unlock_exit:
3699 PMSETTING_UNLOCK();
3700
3701 if (chosen) chosen->release();
3702 if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3703
3704 return kIOReturnSuccess;
3705}
3706
3707//******************************************************************************
3708// copyPMSetting (public)
3709//
3710// Allows kexts to safely read setting values, without being subscribed to
3711// notifications.
3712//******************************************************************************
3713
3714OSObject * IOPMrootDomain::copyPMSetting(
3715 OSSymbol *whichSetting)
3716{
3717 OSObject *obj = NULL;
3718
3719 if(!whichSetting) return NULL;
3720
3721 PMSETTING_LOCK();
3722 obj = fPMSettingsDict->getObject(whichSetting);
3723 if(obj) {
3724 obj->retain();
3725 }
3726 PMSETTING_UNLOCK();
3727
3728 return obj;
3729}
3730
3731//******************************************************************************
3732// registerPMSettingController (public)
3733//
3734// direct wrapper to registerPMSettingController with uint32_t power source arg
3735//******************************************************************************
3736
3737IOReturn IOPMrootDomain::registerPMSettingController(
3738 const OSSymbol * settings[],
3739 IOPMSettingControllerCallback func,
3740 OSObject *target,
3741 uintptr_t refcon,
3742 OSObject **handle)
3743{
3744 return registerPMSettingController(
3745 settings,
3746 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3747 func, target, refcon, handle);
3748}
3749
3750//******************************************************************************
3751// registerPMSettingController (public)
3752//
3753// Kexts may register for notifications when a particular setting is changed.
3754// A list of settings is available in IOPM.h.
3755// Arguments:
3756// * settings - An OSArray containing OSSymbols. Caller should populate this
3757// array with a list of settings caller wants notifications from.
3758// * func - A C function callback of the type IOPMSettingControllerCallback
3759// * target - caller may provide an OSObject *, which PM will pass as an
3760// target to calls to "func"
3761// * refcon - caller may provide an void *, which PM will pass as an
3762// argument to calls to "func"
3763// * handle - This is a return argument. We will populate this pointer upon
3764// call success. Hold onto this and pass this argument to
3765// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3766// Returns:
3767// kIOReturnSuccess on success
3768//******************************************************************************
3769
3770IOReturn IOPMrootDomain::registerPMSettingController(
3771 const OSSymbol * settings[],
3772 uint32_t supportedPowerSources,
3773 IOPMSettingControllerCallback func,
3774 OSObject *target,
3775 uintptr_t refcon,
3776 OSObject **handle)
3777{
3778 PMSettingObject *pmso = NULL;
3779 OSObject *pmsh = NULL;
3780 OSArray *list = NULL;
3781 int i;
3782
3783 if (NULL == settings ||
3784 NULL == func ||
3785 NULL == handle)
3786 {
3787 return kIOReturnBadArgument;
3788 }
3789
3790 pmso = PMSettingObject::pmSettingObject(
3791 (IOPMrootDomain *) this, func, target,
3792 refcon, supportedPowerSources, settings, &pmsh);
3793
3794 if (!pmso) {
3795 *handle = NULL;
3796 return kIOReturnInternalError;
3797 }
3798
3799 PMSETTING_LOCK();
3800 for (i=0; settings[i]; i++)
3801 {
3802 list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
3803 if (!list) {
3804 // New array of callbacks for this setting
3805 list = OSArray::withCapacity(1);
3806 settingsCallbacks->setObject(settings[i], list);
3807 list->release();
3808 }
3809
3810 // Add caller to the callback list
3811 list->setObject(pmso);
3812 }
3813 PMSETTING_UNLOCK();
3814
3815 // Return handle to the caller, the setting object is private.
3816 *handle = pmsh;
3817
3818 return kIOReturnSuccess;
3819}
3820
3821//******************************************************************************
3822// deregisterPMSettingObject (private)
3823//
3824// Only called from PMSettingObject.
3825//******************************************************************************
3826
3827void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3828{
3829 thread_t thisThread = current_thread();
3830 PMSettingCallEntry *callEntry;
3831 OSCollectionIterator *iter;
3832 OSSymbol *sym;
3833 OSArray *array;
3834 int index;
3835 bool wait;
3836
3837 PMSETTING_LOCK();
3838
3839 pmso->disabled = true;
3840
3841 // Wait for all callout threads to finish.
3842 do {
3843 wait = false;
3844 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3845 {
3846 if (callEntry->thread != thisThread)
3847 {
3848 wait = true;
3849 break;
3850 }
3851 }
3852 if (wait)
3853 {
3854 assert(0 == pmso->waitThread);
3855 pmso->waitThread = thisThread;
3856 PMSETTING_WAIT(pmso);
3857 pmso->waitThread = 0;
3858 }
3859 } while (wait);
3860
3861 // Search each PM settings array in the kernel.
3862 iter = OSCollectionIterator::withCollection(settingsCallbacks);
3863 if (iter)
3864 {
3865 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3866 {
3867 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
3868 index = array->getNextIndexOfObject(pmso, 0);
3869 if (-1 != index) {
3870 array->removeObject(index);
3871 }
3872 }
3873 iter->release();
3874 }
3875
3876 PMSETTING_UNLOCK();
3877
3878 pmso->release();
3879}
3880
3881//******************************************************************************
3882// informCPUStateChange
3883//
3884// Call into PM CPU code so that CPU power savings may dynamically adjust for
3885// running on battery, with the lid closed, etc.
3886//
3887// informCPUStateChange is a no-op on non x86 systems
3888// only x86 has explicit support in the IntelCPUPowerManagement kext
3889//******************************************************************************
3890
3891void IOPMrootDomain::informCPUStateChange(
3892 uint32_t type,
3893 uint32_t value )
3894{
3895#if defined(__i386__) || defined(__x86_64__)
3896
3897 pmioctlVariableInfo_t varInfoStruct;
3898 int pmCPUret = 0;
3899 const char *varNameStr = NULL;
3900 int32_t *varIndex = NULL;
3901
3902 if (kInformAC == type) {
3903 varNameStr = kIOPMRootDomainBatPowerCString;
3904 varIndex = &idxPMCPULimitedPower;
3905 } else if (kInformLid == type) {
3906 varNameStr = kIOPMRootDomainLidCloseCString;
3907 varIndex = &idxPMCPUClamshell;
3908 } else {
3909 return;
3910 }
3911
3912 // Set the new value!
3913 // pmCPUControl will assign us a new ID if one doesn't exist yet
3914 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
3915 varInfoStruct.varID = *varIndex;
3916 varInfoStruct.varType = vBool;
3917 varInfoStruct.varInitValue = value;
3918 varInfoStruct.varCurValue = value;
3919 strlcpy( (char *)varInfoStruct.varName,
3920 (const char *)varNameStr,
3921 sizeof(varInfoStruct.varName));
3922
3923 // Set!
3924 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
3925
3926 // pmCPU only assigns numerical id's when a new varName is specified
3927 if ((0 == pmCPUret)
3928 && (*varIndex == kCPUUnknownIndex))
3929 {
3930 // pmCPUControl has assigned us a new variable ID.
3931 // Let's re-read the structure we just SET to learn that ID.
3932 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
3933
3934 if (0 == pmCPUret)
3935 {
3936 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3937 *varIndex = varInfoStruct.varID;
3938 }
3939 }
3940
3941 return;
3942
3943#endif /* __i386__ || __x86_64__ */
3944}
3945
3946// MARK: -
3947// MARK: Deep Sleep Policy
3948
3949#if HIBERNATION
3950
3951//******************************************************************************
3952// evaluateSystemSleepPolicy
3953//******************************************************************************
3954
3955#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3956
3957// Sleep flags
3958enum {
3959 kIOPMSleepFlagHibernate = 0x00000001,
3960 kIOPMSleepFlagSleepTimerEnable = 0x00000002
3961};
3962
3963struct IOPMSystemSleepPolicyEntry
3964{
3965 uint32_t factorMask;
3966 uint32_t factorBits;
3967 uint32_t sleepFlags;
3968 uint32_t wakeEvents;
3969} __attribute__((packed));
3970
3971struct IOPMSystemSleepPolicyTable
3972{
3973 uint32_t signature;
3974 uint16_t version;
3975 uint16_t entryCount;
3976 IOPMSystemSleepPolicyEntry entries[];
3977} __attribute__((packed));
3978
3979enum {
3980 kIOPMSleepAttributeHibernateSetup = 0x00000001,
3981 kIOPMSleepAttributeHibernateSleep = 0x00000002
3982};
3983
3984static uint32_t
3985getSleepTypeAttributes( uint32_t sleepType )
3986{
3987 static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] =
3988 {
3989 /* invalid */ 0,
3990 /* abort */ 0,
3991 /* normal */ 0,
3992 /* safesleep */ kIOPMSleepAttributeHibernateSetup,
3993 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3994 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3995 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3996 /* deepidle */ 0
3997 };
3998
3999 if (sleepType >= kIOPMSleepTypeLast)
4000 return 0;
4001
4002 return sleepTypeAttributes[sleepType];
4003}
4004
4005bool IOPMrootDomain::evaluateSystemSleepPolicy(
4006 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
4007{
4008 const IOPMSystemSleepPolicyTable * pt;
4009 OSObject * prop = 0;
4010 OSData * policyData;
4011 uint64_t currentFactors = 0;
4012 uint32_t standbyDelay = 0;
4013 uint32_t powerOffDelay = 0;
4014 uint32_t powerOffTimer = 0;
4015 uint32_t mismatch;
4016 bool standbyEnabled;
4017 bool powerOffEnabled;
4018 bool found = false;
4019
4020 // Get platform's sleep policy table
4021 if (!gSleepPolicyHandler)
4022 {
4023 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
4024 if (!prop) goto done;
4025 }
4026
4027 // Fetch additional settings
4028 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
4029 && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
4030 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
4031 && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
4032 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
4033 powerOffTimer = powerOffDelay;
4034
4035 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4036 sleepPhase, standbyEnabled, standbyDelay,
4037 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
4038
4039 // pmset level overrides
4040 if ((*hibMode & kIOHibernateModeOn) == 0)
4041 {
4042 if (!gSleepPolicyHandler)
4043 {
4044 standbyEnabled = false;
4045 powerOffEnabled = false;
4046 }
4047 }
4048 else if (!(*hibMode & kIOHibernateModeSleep))
4049 {
4050 // Force hibernate (i.e. mode 25)
4051 // If standby is enabled, force standy.
4052 // If poweroff is enabled, force poweroff.
4053 if (standbyEnabled)
4054 currentFactors |= kIOPMSleepFactorStandbyForced;
4055 else if (powerOffEnabled)
4056 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
4057 else
4058 currentFactors |= kIOPMSleepFactorHibernateForced;
4059 }
4060
4061 // Current factors based on environment and assertions
4062 if (sleepTimerMaintenance)
4063 currentFactors |= kIOPMSleepFactorSleepTimerWake;
4064 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler)
4065 currentFactors |= kIOPMSleepFactorSleepTimerWake;
4066 if (!clamshellClosed)
4067 currentFactors |= kIOPMSleepFactorLidOpen;
4068 if (acAdaptorConnected)
4069 currentFactors |= kIOPMSleepFactorACPower;
4070 if (lowBatteryCondition)
4071 currentFactors |= kIOPMSleepFactorBatteryLow;
4072 if (!standbyDelay)
4073 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
4074 if (standbyNixed || !standbyEnabled)
4075 currentFactors |= kIOPMSleepFactorStandbyDisabled;
4076 if (resetTimers)
4077 {
4078 currentFactors |= kIOPMSleepFactorLocalUserActivity;
4079 currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
4080 }
4081 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
4082 kIOPMDriverAssertionLevelOff)
4083 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
4084 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
4085 kIOPMDriverAssertionLevelOff)
4086 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
4087 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
4088 kIOPMDriverAssertionLevelOff)
4089 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
4090 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
4091 kIOPMDriverAssertionLevelOff)
4092 currentFactors |= kIOPMSleepFactorThunderboltDevice;
4093 if (_scheduledAlarms != 0)
4094 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
4095 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
4096 kIOPMDriverAssertionLevelOff)
4097 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
4098#define TCPKEEPALIVE 1
4099#if TCPKEEPALIVE
4100 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
4101 kIOPMDriverAssertionLevelOff)
4102 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
4103#endif
4104 if (!powerOffEnabled)
4105 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
4106 if (desktopMode)
4107 currentFactors |= kIOPMSleepFactorExternalDisplay;
4108 if (userWasActive)
4109 currentFactors |= kIOPMSleepFactorLocalUserActivity;
4110 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4111 currentFactors |= kIOPMSleepFactorHibernateFailed;
4112 if (thermalWarningState)
4113 currentFactors |= kIOPMSleepFactorThermalWarning;
4114
4115 DLOG("sleep factors 0x%llx\n", currentFactors);
4116
4117 if (gSleepPolicyHandler)
4118 {
4119 uint32_t savedHibernateMode;
4120 IOReturn result;
4121
4122 if (!gSleepPolicyVars)
4123 {
4124 gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
4125 if (!gSleepPolicyVars)
4126 goto done;
4127 bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
4128 }
4129 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
4130 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
4131 gSleepPolicyVars->currentCapability = _currentCapability;
4132 gSleepPolicyVars->highestCapability = _highestCapability;
4133 gSleepPolicyVars->sleepFactors = currentFactors;
4134 gSleepPolicyVars->sleepReason = lastSleepReason;
4135 gSleepPolicyVars->sleepPhase = sleepPhase;
4136 gSleepPolicyVars->standbyDelay = standbyDelay;
4137 gSleepPolicyVars->poweroffDelay = powerOffDelay;
4138 gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm;
4139 gSleepPolicyVars->poweroffTimer = powerOffTimer;
4140
4141 if (kIOPMSleepPhase0 == sleepPhase)
4142 {
4143 // preserve hibernateMode
4144 savedHibernateMode = gSleepPolicyVars->hibernateMode;
4145 gSleepPolicyVars->hibernateMode = *hibMode;
4146 }
4147 else if (kIOPMSleepPhase1 == sleepPhase)
4148 {
4149 // use original hibernateMode for phase2
4150 gSleepPolicyVars->hibernateMode = *hibMode;
4151 }
4152
4153 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
4154
4155 if (kIOPMSleepPhase0 == sleepPhase)
4156 {
4157 // restore hibernateMode
4158 gSleepPolicyVars->hibernateMode = savedHibernateMode;
4159 }
4160
4161 if ((result != kIOReturnSuccess) ||
4162 (kIOPMSleepTypeInvalid == params->sleepType) ||
4163 (params->sleepType >= kIOPMSleepTypeLast) ||
4164 (kIOPMSystemSleepParametersVersion != params->version))
4165 {
4166 MSG("sleep policy handler error\n");
4167 goto done;
4168 }
4169
4170 if ((getSleepTypeAttributes(params->sleepType) &
4171 kIOPMSleepAttributeHibernateSetup) &&
4172 ((*hibMode & kIOHibernateModeOn) == 0))
4173 {
4174 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
4175 }
4176
4177 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4178 params->version, params->sleepType, params->sleepFlags,
4179 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
4180 found = true;
4181 goto done;
4182 }
4183
4184 // Policy table is meaningless without standby enabled
4185 if (!standbyEnabled)
4186 goto done;
4187
4188 // Validate the sleep policy table
4189 policyData = OSDynamicCast(OSData, prop);
4190 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
4191 goto done;
4192
4193 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
4194 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
4195 (pt->version != 1) || (0 == pt->entryCount))
4196 goto done;
4197
4198 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
4199 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
4200 goto done;
4201
4202 for (uint32_t i = 0; i < pt->entryCount; i++)
4203 {
4204 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
4205 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
4206
4207 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4208 entry->factorMask, entry->factorBits,
4209 entry->sleepFlags, entry->wakeEvents, mismatch);
4210 if (mismatch)
4211 continue;
4212
4213 DLOG("^ found match\n");
4214 found = true;
4215
4216 params->version = kIOPMSystemSleepParametersVersion;
4217 params->reserved1 = 1;
4218 if (entry->sleepFlags & kIOPMSleepFlagHibernate)
4219 params->sleepType = kIOPMSleepTypeStandby;
4220 else
4221 params->sleepType = kIOPMSleepTypeNormalSleep;
4222
4223 params->ecWakeEvents = entry->wakeEvents;
4224 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
4225 {
4226 if (kIOPMSleepPhase2 == sleepPhase)
4227 {
4228 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
4229
4230 if (!_standbyTimerResetSeconds ||
4231 (now_secs <= _standbyTimerResetSeconds))
4232 {
4233 // Reset standby timer adjustment
4234 _standbyTimerResetSeconds = now_secs;
4235 DLOG("standby delay %u, reset %u\n",
4236 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
4237 }
4238 else if (standbyDelay)
4239 {
4240 // Shorten the standby delay timer
4241 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
4242 if (standbyDelay > elapsed)
4243 standbyDelay -= elapsed;
4244 else
4245 standbyDelay = 1; // must be > 0
4246
4247 DLOG("standby delay %u, elapsed %u\n",
4248 standbyDelay, (uint32_t) elapsed);
4249 }
4250 }
4251 params->ecWakeTimer = standbyDelay;
4252 }
4253 else if (kIOPMSleepPhase2 == sleepPhase)
4254 {
4255 // A sleep that does not enable the sleep timer will reset
4256 // the standby delay adjustment.
4257 _standbyTimerResetSeconds = 0;
4258 }
4259 break;
4260 }
4261
4262done:
4263 if (prop)
4264 prop->release();
4265
4266 return found;
4267}
4268
4269static IOPMSystemSleepParameters gEarlySystemSleepParams;
4270
4271void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4272{
4273 // Evaluate early (priority interest phase), before drivers sleep.
4274
4275 DLOG("%s\n", __FUNCTION__);
4276 removeProperty(kIOPMSystemSleepParametersKey);
4277
4278 // Full wake resets the standby timer delay adjustment
4279 if (_highestCapability & kIOPMSystemCapabilityGraphics)
4280 _standbyTimerResetSeconds = 0;
4281
4282 hibernateDisabled = false;
4283 hibernateMode = 0;
4284 getSleepOption(kIOHibernateModeKey, &hibernateMode);
4285
4286 // Save for late evaluation if sleep is aborted
4287 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
4288
4289 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
4290 &hibernateMode))
4291 {
4292 if (!hibernateRetry &&
4293 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
4294 kIOPMSleepAttributeHibernateSetup) == 0))
4295 {
4296 // skip hibernate setup
4297 hibernateDisabled = true;
4298 }
4299 }
4300
4301 // Publish IOPMSystemSleepType
4302 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
4303 if (sleepType == kIOPMSleepTypeInvalid)
4304 {
4305 // no sleep policy
4306 sleepType = kIOPMSleepTypeNormalSleep;
4307 if (hibernateMode & kIOHibernateModeOn)
4308 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
4309 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
4310 }
4311 else if ((sleepType == kIOPMSleepTypeStandby) &&
4312 (gEarlySystemSleepParams.ecPoweroffTimer))
4313 {
4314 // report the lowest possible sleep state
4315 sleepType = kIOPMSleepTypePowerOff;
4316 }
4317
4318 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
4319}
4320
4321void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4322{
4323 IOPMSystemSleepParameters params;
4324 OSData * paramsData;
4325 bool wakeNow;
4326 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4327
4328 DLOG("%s\n", __FUNCTION__);
4329
4330 bzero(&params, sizeof(params));
4331 wakeNow = false;
4332 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode))
4333 {
4334 if ((kIOPMSleepTypeStandby == params.sleepType)
4335 && gIOHibernateStandbyDisabled
4336 && (!(kIOPMSleepFactorStandbyForced & gSleepPolicyVars->sleepFactors)))
4337 {
4338 standbyNixed = true;
4339 wakeNow = true;
4340 }
4341 if (wakeNow
4342 || ((hibernateDisabled || hibernateAborted) &&
4343 (getSleepTypeAttributes(params.sleepType) &
4344 kIOPMSleepAttributeHibernateSetup)))
4345 {
4346 // Final evaluation picked a state requiring hibernation,
4347 // but hibernate isn't going to proceed. Arm a short sleep using
4348 // the early non-hibernate sleep parameters.
4349 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
4350 params.sleepType = kIOPMSleepTypeAbortedSleep;
4351 params.ecWakeTimer = 1;
4352 if (standbyNixed)
4353 {
4354 resetTimers = true;
4355 }
4356 else
4357 {
4358 // Set hibernateRetry flag to force hibernate setup on the
4359 // next sleep.
4360 hibernateRetry = true;
4361 }
4362 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4363 params.ecWakeTimer, hibernateDisabled, hibernateAborted, standbyNixed);
4364 }
4365 else
4366 {
4367 hibernateRetry = false;
4368 }
4369
4370 if (kIOPMSleepTypeAbortedSleep != params.sleepType)
4371 {
4372 resetTimers = false;
4373 }
4374
4375 paramsData = OSData::withBytes(&params, sizeof(params));
4376 if (paramsData)
4377 {
4378 setProperty(kIOPMSystemSleepParametersKey, paramsData);
4379 paramsData->release();
4380 }
4381
4382 if (getSleepTypeAttributes(params.sleepType) &
4383 kIOPMSleepAttributeHibernateSleep)
4384 {
4385 // Disable sleep to force hibernation
4386 gIOHibernateMode &= ~kIOHibernateModeSleep;
4387 }
4388 }
4389}
4390
4391bool IOPMrootDomain::getHibernateSettings(
4392 uint32_t * hibernateModePtr,
4393 uint32_t * hibernateFreeRatio,
4394 uint32_t * hibernateFreeTime )
4395{
4396 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4397 // has updated the hibernateDisabled flag.
4398
4399 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
4400 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
4401 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
4402 if (hibernateDisabled)
4403 *hibernateModePtr = 0;
4404 else if (gSleepPolicyHandler)
4405 *hibernateModePtr = hibernateMode;
4406 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
4407 return ok;
4408}
4409
4410bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
4411{
4412 OSObject * optionsProp;
4413 OSDictionary * optionsDict;
4414 OSObject * obj = 0;
4415 OSNumber * num;
4416 bool ok = false;
4417
4418 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
4419 optionsDict = OSDynamicCast(OSDictionary, optionsProp);
4420
4421 if (optionsDict)
4422 {
4423 obj = optionsDict->getObject(key);
4424 if (obj) obj->retain();
4425 }
4426 if (!obj)
4427 {
4428 obj = copyProperty(key);
4429 }
4430 if (obj)
4431 {
4432 if ((num = OSDynamicCast(OSNumber, obj)))
4433 {
4434 *option = num->unsigned32BitValue();
4435 ok = true;
4436 }
4437 else if (OSDynamicCast(OSBoolean, obj))
4438 {
4439 *option = (obj == kOSBooleanTrue) ? 1 : 0;
4440 ok = true;
4441 }
4442 }
4443
4444 if (obj)
4445 obj->release();
4446 if (optionsProp)
4447 optionsProp->release();
4448
4449 return true;
4450}
4451#endif /* HIBERNATION */
4452
4453IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
4454{
4455#if HIBERNATION
4456 IOPMSystemSleepParameters params;
4457 uint32_t hibMode = 0;
4458 bool ok;
4459
4460 if (gIOPMWorkLoop->inGate() == false)
4461 {
4462 IOReturn ret = gIOPMWorkLoop->runAction(
4463 OSMemberFunctionCast(IOWorkLoop::Action, this,
4464 &IOPMrootDomain::getSystemSleepType),
4465 (OSObject *) this,
4466 (void *) sleepType);
4467 return ret;
4468 }
4469
4470 getSleepOption(kIOHibernateModeKey, &hibMode);
4471 bzero(&params, sizeof(params));
4472
4473 ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
4474 if (ok)
4475 {
4476 *sleepType = params.sleepType;
4477 return kIOReturnSuccess;
4478 }
4479#endif
4480
4481 return kIOReturnUnsupported;
4482}
4483
4484// MARK: -
4485// MARK: Shutdown and Restart
4486
4487//******************************************************************************
4488// handlePlatformHaltRestart
4489//
4490//******************************************************************************
4491
4492struct HaltRestartApplierContext {
4493 IOPMrootDomain * RootDomain;
4494 unsigned long PowerState;
4495 IOPMPowerFlags PowerFlags;
4496 UInt32 MessageType;
4497 UInt32 Counter;
4498 const char * LogString;
4499};
4500
4501static void
4502platformHaltRestartApplier( OSObject * object, void * context )
4503{
4504 IOPowerStateChangeNotification notify;
4505 HaltRestartApplierContext * ctx;
4506 AbsoluteTime startTime;
4507 uint32_t deltaTime;
4508
4509 ctx = (HaltRestartApplierContext *) context;
4510
4511 memset(&notify, 0, sizeof(notify));
4512 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
4513 notify.returnValue = 0;
4514 notify.stateNumber = ctx->PowerState;
4515 notify.stateFlags = ctx->PowerFlags;
4516
4517 clock_get_uptime(&startTime);
4518 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
4519 deltaTime = computeDeltaTimeMS(&startTime);
4520
4521 if ((deltaTime > kPMHaltTimeoutMS) ||
4522 (gIOKitDebug & kIOLogPMRootDomain))
4523 {
4524 _IOServiceInterestNotifier * notifier;
4525 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
4526
4527 // IOService children of IOPMrootDomain are not instrumented.
4528 // Only IORootParent currently falls under that group.
4529
4530 if (notifier)
4531 {
4532 LOG("%s handler %p took %u ms\n",
4533 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
4534 }
4535 }
4536
4537 ctx->Counter++;
4538}
4539
4540static void quiescePowerTreeCallback( void * target, void * param )
4541{
4542 IOLockLock(gPMHaltLock);
4543 gPMQuiesced = true;
4544 thread_wakeup(param);
4545 IOLockUnlock(gPMHaltLock);
4546}
4547
4548void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
4549{
4550 HaltRestartApplierContext ctx;
4551 AbsoluteTime startTime;
4552 uint32_t deltaTime;
4553
4554 memset(&ctx, 0, sizeof(ctx));
4555 ctx.RootDomain = this;
4556
4557 clock_get_uptime(&startTime);
4558 switch (pe_type)
4559 {
4560 case kPEHaltCPU:
4561 case kPEUPSDelayHaltCPU:
4562 ctx.PowerState = OFF_STATE;
4563 ctx.MessageType = kIOMessageSystemWillPowerOff;
4564 ctx.LogString = "PowerOff";
4565 break;
4566
4567 case kPERestartCPU:
4568 ctx.PowerState = RESTART_STATE;
4569 ctx.MessageType = kIOMessageSystemWillRestart;
4570 ctx.LogString = "Restart";
4571 break;
4572
4573 case kPEPagingOff:
4574 ctx.PowerState = ON_STATE;
4575 ctx.MessageType = kIOMessageSystemPagingOff;
4576 ctx.LogString = "PagingOff";
4577 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
4578#if HIBERNATION
4579 IOHibernateSystemRestart();
4580#endif
4581 break;
4582
4583 default:
4584 return;
4585 }
4586
4587 // Notify legacy clients
4588 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
4589
4590 // For normal shutdown, turn off File Server Mode.
4591 if (kPEHaltCPU == pe_type)
4592 {
4593 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
4594 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
4595 if (setting && num)
4596 {
4597 setPMSetting(setting, num);
4598 setting->release();
4599 num->release();
4600 }
4601 }
4602
4603 if (kPEPagingOff != pe_type)
4604 {
4605 // Notify in power tree order
4606 notifySystemShutdown(this, ctx.MessageType);
4607 }
4608
4609 IOCPURunPlatformHaltRestartActions(pe_type);
4610
4611 // Wait for PM to quiesce
4612 if ((kPEPagingOff != pe_type) && gPMHaltLock)
4613 {
4614 AbsoluteTime quiesceTime = mach_absolute_time();
4615
4616 IOLockLock(gPMHaltLock);
4617 gPMQuiesced = false;
4618 if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
4619 kIOReturnSuccess)
4620 {
4621 while (!gPMQuiesced)
4622 {
4623 IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
4624 }
4625 }
4626 IOLockUnlock(gPMHaltLock);
4627
4628 deltaTime = computeDeltaTimeMS(&quiesceTime);
4629 DLOG("PM quiesce took %u ms\n", deltaTime);
4630 }
4631
4632 deltaTime = computeDeltaTimeMS(&startTime);
4633 LOG("%s all drivers took %u ms\n", ctx.LogString, deltaTime);
4634}
4635
4636//******************************************************************************
4637// shutdownSystem
4638//
4639//******************************************************************************
4640
4641IOReturn IOPMrootDomain::shutdownSystem( void )
4642{
4643 return kIOReturnUnsupported;
4644}
4645
4646//******************************************************************************
4647// restartSystem
4648//
4649//******************************************************************************
4650
4651IOReturn IOPMrootDomain::restartSystem( void )
4652{
4653 return kIOReturnUnsupported;
4654}
4655
4656// MARK: -
4657// MARK: System Capability
4658
4659//******************************************************************************
4660// tagPowerPlaneService
4661//
4662// Running on PM work loop thread.
4663//******************************************************************************
4664
4665void IOPMrootDomain::tagPowerPlaneService(
4666 IOService * service,
4667 IOPMActions * actions )
4668{
4669 uint32_t flags = 0;
4670 bool isDisplayWrangler;
4671
4672 memset(actions, 0, sizeof(*actions));
4673 actions->target = this;
4674
4675 if (service == this)
4676 {
4677 actions->actionPowerChangeStart =
4678 OSMemberFunctionCast(
4679 IOPMActionPowerChangeStart, this,
4680 &IOPMrootDomain::handleOurPowerChangeStart);
4681
4682 actions->actionPowerChangeDone =
4683 OSMemberFunctionCast(
4684 IOPMActionPowerChangeDone, this,
4685 &IOPMrootDomain::handleOurPowerChangeDone);
4686
4687 actions->actionPowerChangeOverride =
4688 OSMemberFunctionCast(
4689 IOPMActionPowerChangeOverride, this,
4690 &IOPMrootDomain::overrideOurPowerChange);
4691 return;
4692 }
4693
4694#if !NO_KERNEL_HID
4695 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
4696 if (isDisplayWrangler)
4697 {
4698 wrangler = service;
4699 }
4700#else
4701 isDisplayWrangler = false;
4702#endif
4703
4704#if defined(__i386__) || defined(__x86_64__)
4705 if (isDisplayWrangler)
4706 flags |= kPMActionsFlagIsDisplayWrangler;
4707 if (service->getProperty("IOPMStrictTreeOrder"))
4708 flags |= kPMActionsFlagIsGraphicsDevice;
4709 if (service->getProperty("IOPMUnattendedWakePowerState"))
4710 flags |= kPMActionsFlagIsAudioDevice;
4711#endif
4712
4713 // Find the power connection object that is a child of the PCI host
4714 // bridge, and has a graphics/audio device attached below. Mark the
4715 // power branch for delayed child notifications.
4716
4717 if (flags)
4718 {
4719 IORegistryEntry * child = service;
4720 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
4721
4722 while (child != this)
4723 {
4724 if ((parent == pciHostBridgeDriver) ||
4725 (parent == this))
4726 {
4727 if (OSDynamicCast(IOPowerConnection, child))
4728 {
4729 IOPowerConnection * conn = (IOPowerConnection *) child;
4730 conn->delayChildNotification = true;
4731 }
4732 break;
4733 }
4734 child = parent;
4735 parent = child->getParentEntry(gIOPowerPlane);
4736 }
4737 }
4738
4739 if (flags)
4740 {
4741 DLOG("%s tag flags %x\n", service->getName(), flags);
4742 actions->parameter |= flags;
4743 actions->actionPowerChangeOverride =
4744 OSMemberFunctionCast(
4745 IOPMActionPowerChangeOverride, this,
4746 &IOPMrootDomain::overridePowerChangeForUIService);
4747
4748 if (flags & kPMActionsFlagIsDisplayWrangler)
4749 {
4750 actions->actionActivityTickle =
4751 OSMemberFunctionCast(
4752 IOPMActionActivityTickle, this,
4753 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
4754
4755 actions->actionUpdatePowerClient =
4756 OSMemberFunctionCast(
4757 IOPMActionUpdatePowerClient, this,
4758 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
4759 }
4760 return;
4761 }
4762
4763 // Locate the first PCI host bridge for PMTrace.
4764 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
4765 {
4766 IOService * provider = service->getProvider();
4767 if (OSDynamicCast(IOPlatformDevice, provider) &&
4768 provider->inPlane(gIODTPlane))
4769 {
4770 pciHostBridgeDevice = provider;
4771 pciHostBridgeDriver = service;
4772 DLOG("PMTrace found PCI host bridge %s->%s\n",
4773 provider->getName(), service->getName());
4774 }
4775 }
4776
4777 // Tag top-level PCI devices. The order of PMinit() call does not
4778 // change across boots and is used as the PCI bit number.
4779 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
4780 {
4781 // Would prefer to check built-in property, but tagPowerPlaneService()
4782 // is called before pciDevice->registerService().
4783 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
4784 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
4785 {
4786 int bit = pmTracer->recordTopLevelPCIDevice( service );
4787 if (bit >= 0)
4788 {
4789 // Save the assigned bit for fast lookup.
4790 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4791
4792 actions->actionPowerChangeStart =
4793 OSMemberFunctionCast(
4794 IOPMActionPowerChangeStart, this,
4795 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4796
4797 actions->actionPowerChangeDone =
4798 OSMemberFunctionCast(
4799 IOPMActionPowerChangeDone, this,
4800 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
4801 }
4802 }
4803 }
4804}
4805
4806//******************************************************************************
4807// PM actions for root domain
4808//******************************************************************************
4809
4810void IOPMrootDomain::overrideOurPowerChange(
4811 IOService * service,
4812 IOPMActions * actions,
4813 IOPMPowerStateIndex * inOutPowerState,
4814 IOPMPowerChangeFlags * inOutChangeFlags,
4815 IOPMRequestTag requestTag )
4816{
4817 uint32_t powerState = (uint32_t) *inOutPowerState;
4818 uint32_t changeFlags = *inOutChangeFlags;
4819 uint32_t currentPowerState = (uint32_t) getPowerState();
4820
4821 if (changeFlags & kIOPMParentInitiated)
4822 {
4823 // Root parent is permanently pegged at max power,
4824 // a parent initiated power change is unexpected.
4825 *inOutChangeFlags |= kIOPMNotDone;
4826 return;
4827 }
4828
4829 if (powerState < currentPowerState)
4830 {
4831 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
4832 {
4833 // Root domain is dropping power state ON->SLEEP.
4834 // If system is in full wake, first enter dark wake by
4835 // converting the power drop to a capability change.
4836 // Once in dark wake, transition to sleep state ASAP.
4837
4838 darkWakeToSleepASAP = true;
4839
4840 // Drop graphics and audio capability
4841 _desiredCapability &= ~(
4842 kIOPMSystemCapabilityGraphics |
4843 kIOPMSystemCapabilityAudio );
4844
4845 // Convert to capability change (ON->ON)
4846 *inOutPowerState = ON_STATE;
4847 *inOutChangeFlags |= kIOPMSynchronize;
4848
4849 // Revert device desire from SLEEP to ON
4850 changePowerStateToPriv(ON_STATE);
4851 }
4852 else
4853 {
4854 // System is in dark wake, ok to drop power state.
4855 // Broadcast root powering down to entire tree.
4856 *inOutChangeFlags |= kIOPMRootChangeDown;
4857 }
4858 }
4859 else if (powerState > currentPowerState)
4860 {
4861 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
4862 {
4863 // Broadcast power up when waking from sleep, but not for the
4864 // initial power change at boot by checking for cpu capability.
4865 *inOutChangeFlags |= kIOPMRootChangeUp;
4866 }
4867 }
4868}
4869
4870void IOPMrootDomain::handleOurPowerChangeStart(
4871 IOService * service,
4872 IOPMActions * actions,
4873 IOPMPowerStateIndex powerState,
4874 IOPMPowerChangeFlags * inOutChangeFlags,
4875 IOPMRequestTag requestTag )
4876{
4877 uint32_t changeFlags = *inOutChangeFlags;
4878 uint32_t currentPowerState = (uint32_t) getPowerState();
4879 uint32_t sleepReason = requestTag ? requestTag : kIOPMSleepReasonIdle;
4880 bool publishSleepReason = false;
4881
4882 _systemTransitionType = kSystemTransitionNone;
4883 _systemMessageClientMask = 0;
4884 capabilityLoss = false;
4885 toldPowerdCapWillChange = false;
4886
4887 if (lowBatteryCondition)
4888 {
4889 // Low battery notification may arrive after the initial sleep request
4890 // has been queued. Override the sleep reason so powerd and others can
4891 // treat this as an emergency sleep.
4892 sleepReason = kIOPMSleepReasonLowPower;
4893 }
4894
4895 // 1. Explicit capability change.
4896
4897 if (changeFlags & kIOPMSynchronize)
4898 {
4899 if (powerState == ON_STATE)
4900 {
4901 if (changeFlags & kIOPMSyncNoChildNotify)
4902 _systemTransitionType = kSystemTransitionNewCapClient;
4903 else
4904 _systemTransitionType = kSystemTransitionCapability;
4905 }
4906 }
4907
4908 // 2. Going to sleep (cancellation still possible).
4909
4910 else if (powerState < currentPowerState)
4911 _systemTransitionType = kSystemTransitionSleep;
4912
4913 // 3. Woke from (idle or demand) sleep.
4914
4915 else if (!systemBooting &&
4916 (changeFlags & kIOPMSelfInitiated) &&
4917 (powerState > currentPowerState))
4918 {
4919 _systemTransitionType = kSystemTransitionWake;
4920 _desiredCapability = kIOPMSystemCapabilityCPU |
4921 kIOPMSystemCapabilityNetwork;
4922
4923 // Early exit from dark wake to full (e.g. LID open)
4924 if (kFullWakeReasonNone != fullWakeReason)
4925 {
4926 _desiredCapability |= (
4927 kIOPMSystemCapabilityGraphics |
4928 kIOPMSystemCapabilityAudio );
4929 }
4930#if HIBERNATION
4931 IOHibernateSetWakeCapabilities(_desiredCapability);
4932#endif
4933 }
4934
4935 // Update pending wake capability at the beginning of every
4936 // state transition (including synchronize). This will become
4937 // the current capability at the end of the transition.
4938
4939 if (kSystemTransitionSleep == _systemTransitionType)
4940 {
4941 _pendingCapability = 0;
4942 capabilityLoss = true;
4943
4944 }
4945 else if (kSystemTransitionNewCapClient != _systemTransitionType)
4946 {
4947 _pendingCapability = _desiredCapability |
4948 kIOPMSystemCapabilityCPU |
4949 kIOPMSystemCapabilityNetwork;
4950
4951 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4952 _pendingCapability |= kIOPMSystemCapabilityAudio;
4953
4954 if ((kSystemTransitionCapability == _systemTransitionType) &&
4955 (_pendingCapability == _currentCapability))
4956 {
4957 // Cancel the PM state change.
4958 _systemTransitionType = kSystemTransitionNone;
4959 *inOutChangeFlags |= kIOPMNotDone;
4960 }
4961 if (__builtin_popcount(_pendingCapability) <
4962 __builtin_popcount(_currentCapability))
4963 capabilityLoss = true;
4964 }
4965
4966 // 1. Capability change.
4967
4968 if (kSystemTransitionCapability == _systemTransitionType)
4969 {
4970 // Dark to Full transition.
4971 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4972 {
4973 tracePoint( kIOPMTracePointDarkWakeExit );
4974
4975 willEnterFullWake();
4976 }
4977
4978 // Full to Dark transition.
4979 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4980 {
4981 // Clear previous stats
4982 IOLockLock(pmStatsLock);
4983 if (pmStatsAppResponses)
4984 {
4985 pmStatsAppResponses->release();
4986 pmStatsAppResponses = OSArray::withCapacity(5);
4987 }
4988 IOLockUnlock(pmStatsLock);
4989
4990
4991 tracePoint( kIOPMTracePointDarkWakeEntry );
4992 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
4993 _systemMessageClientMask = kSystemMessageClientPowerd |
4994 kSystemMessageClientLegacyApp;
4995
4996
4997 // rdar://15971327
4998 // Prevent user active transitions before notifying clients
4999 // that system will sleep.
5000 preventTransitionToUserActive(true);
5001
5002 IOService::setAdvisoryTickleEnable( false );
5003
5004 // Publish the sleep reason for full to dark wake
5005 publishSleepReason = true;
5006 lastSleepReason = fullToDarkReason = sleepReason;
5007
5008 // Publish a UUID for the Sleep --> Wake cycle
5009 handlePublishSleepWakeUUID(true);
5010 if (sleepDelaysReport) {
5011 clock_get_uptime(&ts_sleepStart);
5012 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
5013 }
5014
5015 wranglerTickled = false;
5016 }
5017 }
5018
5019 // 2. System sleep.
5020
5021 else if (kSystemTransitionSleep == _systemTransitionType)
5022 {
5023 // Beginning of a system sleep transition.
5024 // Cancellation is still possible.
5025 tracePoint( kIOPMTracePointSleepStarted );
5026
5027 _systemMessageClientMask = kSystemMessageClientAll;
5028 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
5029 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
5030 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
5031 _systemMessageClientMask &= ~kSystemMessageClientKernel;
5032#if HIBERNATION
5033 gIOHibernateState = 0;
5034#endif
5035
5036 // Record the reason for dark wake back to sleep
5037 // System may not have ever achieved full wake
5038
5039 publishSleepReason = true;
5040 lastSleepReason = sleepReason;
5041 if (sleepDelaysReport) {
5042 clock_get_uptime(&ts_sleepStart);
5043 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
5044 }
5045 }
5046
5047 // 3. System wake.
5048
5049 else if (kSystemTransitionWake == _systemTransitionType)
5050 {
5051 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
5052 // Clear stats about sleep
5053
5054 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5055 {
5056 willEnterFullWake();
5057 }
5058 else
5059 {
5060 // Message powerd only
5061 _systemMessageClientMask = kSystemMessageClientPowerd;
5062 tellClients(kIOMessageSystemWillPowerOn);
5063 }
5064 }
5065
5066 // The only location where the sleep reason is published. At this point
5067 // sleep can still be cancelled, but sleep reason should be published
5068 // early for logging purposes.
5069
5070 if (publishSleepReason)
5071 {
5072 static const char * IOPMSleepReasons[] =
5073 {
5074 kIOPMClamshellSleepKey,
5075 kIOPMPowerButtonSleepKey,
5076 kIOPMSoftwareSleepKey,
5077 kIOPMOSSwitchHibernationKey,
5078 kIOPMIdleSleepKey,
5079 kIOPMLowPowerSleepKey,
5080 kIOPMThermalEmergencySleepKey,
5081 kIOPMMaintenanceSleepKey,
5082 kIOPMSleepServiceExitKey,
5083 kIOPMDarkWakeThermalEmergencyKey
5084 };
5085
5086 // Record sleep cause in IORegistry
5087 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
5088 if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
5089 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
5090 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
5091 }
5092 }
5093
5094 if ((kSystemTransitionNone != _systemTransitionType) &&
5095 (kSystemTransitionNewCapClient != _systemTransitionType))
5096 {
5097 _systemStateGeneration++;
5098 systemDarkWake = false;
5099
5100 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5101 "dcp %x:%x:%x\n",
5102 currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
5103 _systemTransitionType, _systemStateGeneration,
5104 _systemMessageClientMask,
5105 _desiredCapability, _currentCapability, _pendingCapability);
5106 }
5107}
5108
5109void IOPMrootDomain::handleOurPowerChangeDone(
5110 IOService * service,
5111 IOPMActions * actions,
5112 IOPMPowerStateIndex powerState,
5113 IOPMPowerChangeFlags changeFlags,
5114 IOPMRequestTag requestTag __unused )
5115{
5116 if (kSystemTransitionNewCapClient == _systemTransitionType)
5117 {
5118 _systemTransitionType = kSystemTransitionNone;
5119 return;
5120 }
5121
5122 if (_systemTransitionType != kSystemTransitionNone)
5123 {
5124 uint32_t currentPowerState = (uint32_t) getPowerState();
5125
5126 if (changeFlags & kIOPMNotDone)
5127 {
5128 // Power down was cancelled or vetoed.
5129 _pendingCapability = _currentCapability;
5130 lastSleepReason = 0;
5131
5132 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
5133 CAP_CURRENT(kIOPMSystemCapabilityCPU))
5134 {
5135 pmPowerStateQueue->submitPowerEvent(
5136 kPowerEventPolicyStimulus,
5137 (void *) kStimulusDarkWakeReentry,
5138 _systemStateGeneration );
5139 }
5140
5141 // Revert device desire to max.
5142 changePowerStateToPriv(ON_STATE);
5143 }
5144 else
5145 {
5146 // Send message on dark wake to full wake promotion.
5147 // tellChangeUp() handles the normal SLEEP->ON case.
5148
5149 if (kSystemTransitionCapability == _systemTransitionType)
5150 {
5151 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5152 {
5153 lastSleepReason = 0; // stop logging wrangler tickles
5154 tellClients(kIOMessageSystemHasPoweredOn);
5155 }
5156 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
5157 {
5158 // Going dark, reset full wake state
5159 // userIsActive will be cleared by wrangler powering down
5160 fullWakeReason = kFullWakeReasonNone;
5161
5162 if (ts_sleepStart) {
5163 clock_get_uptime(&wake2DarkwakeDelay);
5164 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
5165 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
5166 ts_sleepStart = 0;
5167 }
5168 }
5169 }
5170
5171 // Reset state after exiting from dark wake.
5172
5173 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
5174 CAP_LOSS(kIOPMSystemCapabilityCPU))
5175 {
5176 darkWakeMaintenance = false;
5177 darkWakeToSleepASAP = false;
5178 pciCantSleepValid = false;
5179 darkWakeSleepService = false;
5180
5181 if (CAP_LOSS(kIOPMSystemCapabilityCPU))
5182 {
5183 // Remove the influence of display power assertion
5184 // before next system wake.
5185 if (wrangler) wrangler->changePowerStateForRootDomain(
5186 kWranglerPowerStateMin );
5187 removeProperty(gIOPMUserTriggeredFullWakeKey);
5188 }
5189 }
5190
5191 // Entered dark mode.
5192
5193 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5194 (_pendingCapability & kIOPMSystemCapabilityCPU))
5195 {
5196 // Queue an evaluation of whether to remain in dark wake,
5197 // and for how long. This serves the purpose of draining
5198 // any assertions from the queue.
5199
5200 pmPowerStateQueue->submitPowerEvent(
5201 kPowerEventPolicyStimulus,
5202 (void *) kStimulusDarkWakeEntry,
5203 _systemStateGeneration );
5204 }
5205 }
5206
5207 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5208 "dcp %x:%x:%x, dbgtimer %u\n",
5209 currentPowerState, (uint32_t) powerState, changeFlags,
5210 _systemTransitionType, _systemStateGeneration,
5211 _systemMessageClientMask,
5212 _desiredCapability, _currentCapability, _pendingCapability,
5213 _lastDebugWakeSeconds);
5214
5215 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5216 {
5217 displayWakeCnt++;
5218#if DARK_TO_FULL_EVALUATE_CLAMSHELL
5219 if (clamshellExists && fullWakeThreadCall &&
5220 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5221 {
5222 // Not the initial graphics full power, graphics won't
5223 // send a power notification to trigger a lid state
5224 // evaluation.
5225
5226 AbsoluteTime deadline;
5227 clock_interval_to_deadline(45, kSecondScale, &deadline);
5228 thread_call_enter_delayed(fullWakeThreadCall, deadline);
5229 }
5230#endif
5231 }
5232 else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
5233 darkWakeCnt++;
5234
5235 // Update current system capability.
5236 if (_currentCapability != _pendingCapability)
5237 _currentCapability = _pendingCapability;
5238
5239 // Update highest system capability.
5240
5241 _highestCapability |= _currentCapability;
5242
5243 if (darkWakePostTickle &&
5244 (kSystemTransitionWake == _systemTransitionType) &&
5245 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5246 kDarkWakeFlagHIDTickleLate)
5247 {
5248 darkWakePostTickle = false;
5249 reportUserInput();
5250 }
5251 else if (wranglerTickled) {
5252 requestFullWake( kFullWakeReasonLocalUser );
5253 }
5254
5255 // Reset tracepoint at completion of capability change,
5256 // completion of wake transition, and aborted sleep transition.
5257
5258 if ((_systemTransitionType == kSystemTransitionCapability) ||
5259 (_systemTransitionType == kSystemTransitionWake) ||
5260 ((_systemTransitionType == kSystemTransitionSleep) &&
5261 (changeFlags & kIOPMNotDone)))
5262 {
5263 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
5264 tracePoint( kIOPMTracePointSystemUp );
5265 }
5266
5267 _systemTransitionType = kSystemTransitionNone;
5268 _systemMessageClientMask = 0;
5269 toldPowerdCapWillChange = false;
5270
5271 logGraphicsClamp = false;
5272
5273 if (lowBatteryCondition) {
5274 privateSleepSystem (kIOPMSleepReasonLowPower);
5275 }
5276 else if ((fullWakeReason == kFullWakeReasonDisplayOn) && (!displayPowerOnRequested)) {
5277 // Request for full wake is removed while system is waking up to full wake
5278 DLOG("DisplayOn fullwake request is removed\n");
5279 handleDisplayPowerOn();
5280 }
5281
5282 }
5283}
5284
5285//******************************************************************************
5286// PM actions for graphics and audio.
5287//******************************************************************************
5288
5289void IOPMrootDomain::overridePowerChangeForUIService(
5290 IOService * service,
5291 IOPMActions * actions,
5292 IOPMPowerStateIndex * inOutPowerState,
5293 IOPMPowerChangeFlags * inOutChangeFlags )
5294{
5295 uint32_t powerState = (uint32_t) *inOutPowerState;
5296 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
5297
5298 if (kSystemTransitionNone == _systemTransitionType)
5299 {
5300 // Not in midst of a system transition.
5301 // Do not modify power limit enable state.
5302 }
5303 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5304 {
5305 // Activate power limiter.
5306
5307 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5308 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5309 (changeFlags & kIOPMSynchronize))
5310 {
5311 actions->parameter |= kPMActionsFlagLimitPower;
5312 }
5313 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5314 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
5315 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
5316 (changeFlags & kIOPMSynchronize))
5317 {
5318 actions->parameter |= kPMActionsFlagLimitPower;
5319 }
5320 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
5321 (_systemTransitionType == kSystemTransitionSleep))
5322 {
5323 // For graphics devices, arm the limiter when entering
5324 // system sleep. Not when dropping to dark wake.
5325 actions->parameter |= kPMActionsFlagLimitPower;
5326 }
5327
5328 if (actions->parameter & kPMActionsFlagLimitPower)
5329 {
5330 DLOG("+ plimit %s %p\n",
5331 service->getName(), OBFUSCATE(service));
5332 }
5333 }
5334 else
5335 {
5336 // Remove power limit.
5337
5338 if ((actions->parameter & (
5339 kPMActionsFlagIsDisplayWrangler |
5340 kPMActionsFlagIsGraphicsDevice )) &&
5341 (_pendingCapability & kIOPMSystemCapabilityGraphics))
5342 {
5343 actions->parameter &= ~kPMActionsFlagLimitPower;
5344 }
5345 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5346 (_pendingCapability & kIOPMSystemCapabilityAudio))
5347 {
5348 actions->parameter &= ~kPMActionsFlagLimitPower;
5349 }
5350
5351 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5352 {
5353 DLOG("- plimit %s %p\n",
5354 service->getName(), OBFUSCATE(service));
5355 }
5356 }
5357
5358 if (actions->parameter & kPMActionsFlagLimitPower)
5359 {
5360 uint32_t maxPowerState = (uint32_t)(-1);
5361
5362 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
5363 {
5364 // Enforce limit for system power/cap transitions.
5365
5366 maxPowerState = 0;
5367 if ((service->getPowerState() > maxPowerState) &&
5368 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
5369 {
5370 maxPowerState++;
5371
5372 // Remove lingering effects of any tickle before entering
5373 // dark wake. It will take a new tickle to return to full
5374 // wake, so the existing tickle state is useless.
5375
5376 if (changeFlags & kIOPMDomainDidChange)
5377 *inOutChangeFlags |= kIOPMExpireIdleTimer;
5378 }
5379 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
5380 {
5381 maxPowerState++;
5382 }
5383 }
5384 else
5385 {
5386 // Deny all self-initiated changes when power is limited.
5387 // Wrangler tickle should never defeat the limiter.
5388
5389 maxPowerState = service->getPowerState();
5390 }
5391
5392 if (powerState > maxPowerState)
5393 {
5394 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5395 service->getName(), OBFUSCATE(service), powerState, maxPowerState,
5396 changeFlags);
5397 *inOutPowerState = maxPowerState;
5398
5399 if (darkWakePostTickle &&
5400 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5401 (changeFlags & kIOPMDomainWillChange) &&
5402 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5403 kDarkWakeFlagHIDTickleEarly))
5404 {
5405 darkWakePostTickle = false;
5406 reportUserInput();
5407 }
5408 }
5409
5410 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
5411 {
5412 if (logGraphicsClamp)
5413 {
5414 AbsoluteTime now;
5415 uint64_t nsec;
5416
5417 clock_get_uptime(&now);
5418 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
5419 absolutetime_to_nanoseconds(now, &nsec);
5420 if (kIOLogPMRootDomain & gIOKitDebug)
5421 MSG("Graphics suppressed %u ms\n",
5422 ((int)((nsec) / 1000000ULL)));
5423 }
5424 graphicsSuppressed = true;
5425 }
5426 }
5427}
5428
5429void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5430 IOService * service,
5431 IOPMActions * actions )
5432{
5433#if !NO_KERNEL_HID
5434 // Warning: Not running in PM work loop context - don't modify state !!!
5435 // Trap tickle directed to IODisplayWrangler while running with graphics
5436 // capability suppressed.
5437
5438 assert(service == wrangler);
5439
5440 clock_get_uptime(&userActivityTime);
5441 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
5442 || (lastSleepReason == kIOPMSleepReasonMaintenance)
5443 || (lastSleepReason == kIOPMSleepReasonSoftware));
5444 if (aborting) {
5445 userActivityCount++;
5446 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5447 userActivityCount, lastSleepReason);
5448 }
5449
5450 if (!wranglerTickled &&
5451 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
5452 {
5453 DLOG("display wrangler tickled\n");
5454 if (kIOLogPMRootDomain & gIOKitDebug)
5455 OSReportWithBacktrace("Dark wake display tickle");
5456 if (pmPowerStateQueue)
5457 {
5458 pmPowerStateQueue->submitPowerEvent(
5459 kPowerEventPolicyStimulus,
5460 (void *) kStimulusDarkWakeActivityTickle,
5461 true /* set wake type */ );
5462 }
5463 }
5464#endif
5465}
5466
5467void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5468 IOService * service,
5469 IOPMActions * actions,
5470 const OSSymbol * powerClient,
5471 IOPMPowerStateIndex oldPowerState,
5472 IOPMPowerStateIndex newPowerState )
5473{
5474#if !NO_KERNEL_HID
5475 assert(service == wrangler);
5476
5477 // This function implements half of the user active detection
5478 // by monitoring changes to the display wrangler's device desire.
5479 //
5480 // User becomes active when either:
5481 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5482 // in max power state. This desire change in absence of a power state
5483 // change is detected within. This handles the case when user becomes
5484 // active while the display is already lit by setDisplayPowerOn().
5485 //
5486 // 2. Power state change to max, and DeviceDesire is also at max.
5487 // Handled by displayWranglerNotification().
5488 //
5489 // User becomes inactive when DeviceDesire drops to sleep state or below.
5490
5491 DLOG("wrangler %s (ps %u, %u->%u)\n",
5492 powerClient->getCStringNoCopy(),
5493 (uint32_t) service->getPowerState(),
5494 (uint32_t) oldPowerState, (uint32_t) newPowerState);
5495
5496 if (powerClient == gIOPMPowerClientDevice)
5497 {
5498 if ((newPowerState > oldPowerState) &&
5499 (newPowerState == kWranglerPowerStateMax) &&
5500 (service->getPowerState() == kWranglerPowerStateMax))
5501 {
5502 evaluatePolicy( kStimulusEnterUserActiveState );
5503 }
5504 else
5505 if ((newPowerState < oldPowerState) &&
5506 (newPowerState <= kWranglerPowerStateSleep))
5507 {
5508 evaluatePolicy( kStimulusLeaveUserActiveState );
5509 }
5510 }
5511
5512 if (newPowerState <= kWranglerPowerStateSleep) {
5513 evaluatePolicy( kStimulusDisplayWranglerSleep );
5514 }
5515 else if (newPowerState == kWranglerPowerStateMax) {
5516 evaluatePolicy( kStimulusDisplayWranglerWake );
5517 }
5518#endif
5519}
5520
5521//******************************************************************************
5522// User active state management
5523//******************************************************************************
5524
5525void IOPMrootDomain::preventTransitionToUserActive( bool prevent )
5526{
5527#if !NO_KERNEL_HID
5528 _preventUserActive = prevent;
5529 if (wrangler && !_preventUserActive)
5530 {
5531 // Allowing transition to user active, but the wrangler may have
5532 // already powered ON in case of sleep cancel/revert. Poll the
5533 // same conditions checked for in displayWranglerNotification()
5534 // to bring the user active state up to date.
5535
5536 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
5537 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
5538 kWranglerPowerStateMax))
5539 {
5540 evaluatePolicy( kStimulusEnterUserActiveState );
5541 }
5542 }
5543#endif
5544}
5545
5546//******************************************************************************
5547// Approve usage of delayed child notification by PM.
5548//******************************************************************************
5549
5550bool IOPMrootDomain::shouldDelayChildNotification(
5551 IOService * service )
5552{
5553 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
5554 (kFullWakeReasonNone == fullWakeReason) &&
5555 (kSystemTransitionWake == _systemTransitionType))
5556 {
5557 DLOG("%s: delay child notify\n", service->getName());
5558 return true;
5559 }
5560 return false;
5561}
5562
5563//******************************************************************************
5564// PM actions for PCI device.
5565//******************************************************************************
5566
5567void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5568 IOService * service,
5569 IOPMActions * actions,
5570 IOPMPowerStateIndex powerState,
5571 IOPMPowerChangeFlags * inOutChangeFlags )
5572{
5573 pmTracer->tracePCIPowerChange(
5574 PMTraceWorker::kPowerChangeStart,
5575 service, *inOutChangeFlags,
5576 (actions->parameter & kPMActionsPCIBitNumberMask));
5577}
5578
5579void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5580 IOService * service,
5581 IOPMActions * actions,
5582 IOPMPowerStateIndex powerState,
5583 IOPMPowerChangeFlags changeFlags )
5584{
5585 pmTracer->tracePCIPowerChange(
5586 PMTraceWorker::kPowerChangeCompleted,
5587 service, changeFlags,
5588 (actions->parameter & kPMActionsPCIBitNumberMask));
5589}
5590
5591//******************************************************************************
5592// registerInterest
5593//
5594// Override IOService::registerInterest() to intercept special clients.
5595//******************************************************************************
5596
5597class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
5598{
5599
5600 friend class IOPMrootDomain;
5601 OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
5602
5603protected:
5604 uint32_t ackTimeoutCnt;
5605 uint32_t msgType; // Message pending ack
5606
5607};
5608
5609OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
5610
5611IONotifier * IOPMrootDomain::registerInterest(
5612 const OSSymbol * typeOfInterest,
5613 IOServiceInterestHandler handler,
5614 void * target, void * ref )
5615{
5616 IOPMServiceInterestNotifier *notifier = 0;
5617 bool isSystemCapabilityClient;
5618 bool isKernelCapabilityClient;
5619 IOReturn rc = kIOReturnError;;
5620
5621 isSystemCapabilityClient =
5622 typeOfInterest &&
5623 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
5624
5625 isKernelCapabilityClient =
5626 typeOfInterest &&
5627 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
5628
5629 if (isSystemCapabilityClient)
5630 typeOfInterest = gIOAppPowerStateInterest;
5631
5632 notifier = new IOPMServiceInterestNotifier;
5633 if (!notifier) return NULL;
5634
5635 if (notifier->init()) {
5636 rc = super::registerInterestForNotifer(notifier, typeOfInterest, handler, target, ref);
5637 }
5638 if (rc != kIOReturnSuccess) {
5639 notifier->release();
5640 notifier = 0;
5641
5642 return NULL;
5643 }
5644 if (pmPowerStateQueue)
5645 {
5646 notifier->ackTimeoutCnt = 0;
5647 if (isSystemCapabilityClient)
5648 {
5649 notifier->retain();
5650 if (pmPowerStateQueue->submitPowerEvent(
5651 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
5652 notifier->release();
5653 }
5654
5655 if (isKernelCapabilityClient)
5656 {
5657 notifier->retain();
5658 if (pmPowerStateQueue->submitPowerEvent(
5659 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
5660 notifier->release();
5661 }
5662 }
5663
5664 return notifier;
5665}
5666
5667//******************************************************************************
5668// systemMessageFilter
5669//
5670//******************************************************************************
5671
5672bool IOPMrootDomain::systemMessageFilter(
5673 void * object, void * arg1, void * arg2, void * arg3 )
5674{
5675 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
5676 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
5677 bool isCapClient = false;
5678 bool allow = false;
5679 IOPMServiceInterestNotifier *notifier;
5680
5681 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
5682 do {
5683 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
5684 (!isCapMsg || !_joinedCapabilityClients ||
5685 !_joinedCapabilityClients->containsObject((OSObject *) object)))
5686 break;
5687
5688 // Capability change message for app and kernel clients.
5689
5690 if (isCapMsg)
5691 {
5692 if ((context->notifyType == kNotifyPriority) ||
5693 (context->notifyType == kNotifyCapabilityChangePriority))
5694 isCapClient = true;
5695
5696 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5697 (object == (void *) systemCapabilityNotifier))
5698 isCapClient = true;
5699 }
5700
5701 if (isCapClient)
5702 {
5703 IOPMSystemCapabilityChangeParameters * capArgs =
5704 (IOPMSystemCapabilityChangeParameters *) arg2;
5705
5706 if (kSystemTransitionNewCapClient == _systemTransitionType)
5707 {
5708 capArgs->fromCapabilities = 0;
5709 capArgs->toCapabilities = _currentCapability;
5710 capArgs->changeFlags = 0;
5711 }
5712 else
5713 {
5714 capArgs->fromCapabilities = _currentCapability;
5715 capArgs->toCapabilities = _pendingCapability;
5716
5717 if (context->isPreChange)
5718 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
5719 else
5720 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
5721
5722 if ((object == (void *) systemCapabilityNotifier) &&
5723 context->isPreChange)
5724 {
5725 toldPowerdCapWillChange = true;
5726 }
5727 }
5728
5729 // Capability change messages only go to the PM configd plugin.
5730 // Wait for response post-change if capabilitiy is increasing.
5731 // Wait for response pre-change if capability is decreasing.
5732
5733 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5734 ( (capabilityLoss && context->isPreChange) ||
5735 (!capabilityLoss && !context->isPreChange) ) )
5736 {
5737 // app has not replied yet, wait for it
5738 *((OSObject **) arg3) = kOSBooleanFalse;
5739
5740 if (notifier) {
5741 notifier->msgType = context->messageType;
5742 }
5743 }
5744
5745 allow = true;
5746 break;
5747 }
5748
5749 // Capability client will always see kIOMessageCanSystemSleep,
5750 // even for demand sleep. It will also have a chance to veto
5751 // sleep one last time after all clients have responded to
5752 // kIOMessageSystemWillSleep
5753
5754 if ((kIOMessageCanSystemSleep == context->messageType) ||
5755 (kIOMessageSystemWillNotSleep == context->messageType))
5756 {
5757 if (object == (OSObject *) systemCapabilityNotifier)
5758 {
5759 allow = true;
5760 if (notifier) {
5761 notifier->msgType = context->messageType;
5762 }
5763 break;
5764 }
5765
5766 // Not idle sleep, don't ask apps.
5767 if (context->changeFlags & kIOPMSkipAskPowerDown)
5768 {
5769 break;
5770 }
5771 }
5772
5773 if (kIOPMMessageLastCallBeforeSleep == context->messageType)
5774 {
5775 if ((object == (OSObject *) systemCapabilityNotifier) &&
5776 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
5777 (fullToDarkReason == kIOPMSleepReasonIdle)) {
5778 if (notifier) {
5779 notifier->msgType = context->messageType;
5780 }
5781 allow = true;
5782 }
5783 break;
5784 }
5785
5786 // Reject capability change messages for legacy clients.
5787 // Reject legacy system sleep messages for capability client.
5788
5789 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
5790 {
5791 break;
5792 }
5793
5794 // Filter system sleep messages.
5795
5796 if ((context->notifyType == kNotifyApps) &&
5797 (_systemMessageClientMask & kSystemMessageClientLegacyApp))
5798 {
5799 allow = true;
5800
5801 if (notifier) {
5802 if (arg3) {
5803 if (notifier->ackTimeoutCnt >= 3)
5804 *((OSObject **) arg3) = kOSBooleanFalse;
5805 else
5806 *((OSObject **) arg3) = kOSBooleanTrue;
5807 }
5808
5809 notifier->msgType = context->messageType;
5810 }
5811 }
5812 else if ((context->notifyType == kNotifyPriority) &&
5813 (_systemMessageClientMask & kSystemMessageClientKernel))
5814 {
5815 allow = true;
5816 }
5817 }
5818 while (false);
5819
5820 if (allow && isCapMsg && _joinedCapabilityClients)
5821 {
5822 _joinedCapabilityClients->removeObject((OSObject *) object);
5823 if (_joinedCapabilityClients->getCount() == 0)
5824 {
5825 DLOG("destroyed capability client set %p\n",
5826 OBFUSCATE(_joinedCapabilityClients));
5827 _joinedCapabilityClients->release();
5828 _joinedCapabilityClients = 0;
5829 }
5830 }
5831
5832 return allow;
5833}
5834
5835//******************************************************************************
5836// setMaintenanceWakeCalendar
5837//
5838//******************************************************************************
5839
5840IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
5841 const IOPMCalendarStruct * calendar )
5842{
5843 OSData * data;
5844 IOReturn ret = 0;
5845
5846 if (!calendar)
5847 return kIOReturnBadArgument;
5848
5849 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
5850 if (!data)
5851 return kIOReturnNoMemory;
5852
5853 if (kPMCalendarTypeMaintenance == calendar->selector) {
5854 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
5855 if (kIOReturnSuccess == ret)
5856 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
5857 } else
5858 if (kPMCalendarTypeSleepService == calendar->selector)
5859 {
5860 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
5861 if (kIOReturnSuccess == ret)
5862 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
5863 }
5864 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
5865
5866 data->release();
5867 return ret;
5868}
5869
5870// MARK: -
5871// MARK: Display Wrangler
5872
5873//******************************************************************************
5874// displayWranglerNotification
5875//
5876// Handle the notification when the IODisplayWrangler changes power state.
5877//******************************************************************************
5878
5879IOReturn IOPMrootDomain::displayWranglerNotification(
5880 void * target, void * refCon,
5881 UInt32 messageType, IOService * service,
5882 void * messageArgument, vm_size_t argSize )
5883{
5884#if !NO_KERNEL_HID
5885 int displayPowerState;
5886 IOPowerStateChangeNotification * params =
5887 (IOPowerStateChangeNotification *) messageArgument;
5888
5889 if ((messageType != kIOMessageDeviceWillPowerOff) &&
5890 (messageType != kIOMessageDeviceHasPoweredOn))
5891 return kIOReturnUnsupported;
5892
5893 ASSERT_GATED();
5894 if (!gRootDomain)
5895 return kIOReturnUnsupported;
5896
5897 displayPowerState = params->stateNumber;
5898 DLOG("wrangler %s ps %d\n",
5899 getIOMessageString(messageType), displayPowerState);
5900
5901 switch (messageType) {
5902 case kIOMessageDeviceWillPowerOff:
5903 // Display wrangler has dropped power due to display idle
5904 // or force system sleep.
5905 //
5906 // 4 Display ON kWranglerPowerStateMax
5907 // 3 Display Dim kWranglerPowerStateDim
5908 // 2 Display Sleep kWranglerPowerStateSleep
5909 // 1 Not visible to user
5910 // 0 Not visible to user kWranglerPowerStateMin
5911
5912 if (displayPowerState <= kWranglerPowerStateSleep)
5913 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
5914 break;
5915
5916 case kIOMessageDeviceHasPoweredOn:
5917 // Display wrangler has powered on due to user activity
5918 // or wake from sleep.
5919
5920 if (kWranglerPowerStateMax == displayPowerState)
5921 {
5922 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
5923
5924 // See comment in handleUpdatePowerClientForDisplayWrangler
5925 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
5926 kWranglerPowerStateMax)
5927 {
5928 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
5929 }
5930 }
5931 break;
5932 }
5933#endif
5934 return kIOReturnUnsupported;
5935}
5936
5937//******************************************************************************
5938// displayWranglerMatchPublished
5939//
5940// Receives a notification when the IODisplayWrangler is published.
5941// When it's published we install a power state change handler.
5942//******************************************************************************
5943
5944bool IOPMrootDomain::displayWranglerMatchPublished(
5945 void * target,
5946 void * refCon,
5947 IOService * newService,
5948 IONotifier * notifier __unused)
5949{
5950#if !NO_KERNEL_HID
5951 // found the display wrangler, now install a handler
5952 if( !newService->registerInterest( gIOGeneralInterest,
5953 &displayWranglerNotification, target, 0) )
5954 {
5955 return false;
5956 }
5957#endif
5958 return true;
5959}
5960
5961#if defined(__i386__) || defined(__x86_64__)
5962
5963bool IOPMrootDomain::IONVRAMMatchPublished(
5964 void * target,
5965 void * refCon,
5966 IOService * newService,
5967 IONotifier * notifier)
5968{
5969 unsigned int len = 0;
5970 IOPMrootDomain *rd = (IOPMrootDomain *)target;
5971 OSNumber *statusCode = NULL;
5972
5973 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey, NULL, &len))
5974 {
5975 statusCode = OSDynamicCast(OSNumber, rd->getProperty(kIOPMSleepWakeFailureCodeKey));
5976 if (statusCode != NULL) {
5977 if (statusCode->unsigned64BitValue() != 0) {
5978 rd->swd_flags |= SWD_BOOT_BY_SW_WDOG;
5979 MSG("System was rebooted due to Sleep/Wake failure\n");
5980 }
5981 else {
5982 rd->swd_flags |= SWD_BOOT_BY_OSX_WDOG;
5983 MSG("System was non-responsive and was rebooted by watchdog\n");
5984 }
5985 }
5986
5987 rd->swd_logBufMap = rd->sleepWakeDebugRetrieve();
5988 }
5989 if (notifier) notifier->remove();
5990 return true;
5991}
5992
5993#else
5994bool IOPMrootDomain::IONVRAMMatchPublished(
5995 void * target,
5996 void * refCon,
5997 IOService * newService,
5998 IONotifier * notifier __unused)
5999{
6000 return false;
6001}
6002
6003#endif
6004
6005//******************************************************************************
6006// reportUserInput
6007//
6008//******************************************************************************
6009
6010void IOPMrootDomain::reportUserInput( void )
6011{
6012#if !NO_KERNEL_HID
6013 OSIterator * iter;
6014 OSDictionary * matching;
6015
6016 if(!wrangler)
6017 {
6018 matching = serviceMatching("IODisplayWrangler");
6019 iter = getMatchingServices(matching);
6020 if (matching) matching->release();
6021 if(iter)
6022 {
6023 wrangler = OSDynamicCast(IOService, iter->getNextObject());
6024 iter->release();
6025 }
6026 }
6027
6028 if(wrangler)
6029 wrangler->activityTickle(0,0);
6030#endif
6031}
6032
6033//******************************************************************************
6034// latchDisplayWranglerTickle
6035//******************************************************************************
6036
6037bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
6038{
6039#if !NO_KERNEL_HID
6040 if (latch)
6041 {
6042 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
6043 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
6044 !checkSystemCanSustainFullWake())
6045 {
6046 // Currently in dark wake, and not transitioning to full wake.
6047 // Full wake is unsustainable, so latch the tickle to prevent
6048 // the display from lighting up momentarily.
6049 wranglerTickleLatched = true;
6050 }
6051 else
6052 {
6053 wranglerTickleLatched = false;
6054 }
6055 }
6056 else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
6057 {
6058 wranglerTickleLatched = false;
6059
6060 pmPowerStateQueue->submitPowerEvent(
6061 kPowerEventPolicyStimulus,
6062 (void *) kStimulusDarkWakeActivityTickle );
6063 }
6064
6065 return wranglerTickleLatched;
6066#else
6067 return false;
6068#endif
6069}
6070
6071//******************************************************************************
6072// setDisplayPowerOn
6073//
6074// For root domain user client
6075//******************************************************************************
6076
6077void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
6078{
6079 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
6080 (void *) 0, options );
6081}
6082
6083// MARK: -
6084// MARK: Battery
6085
6086//******************************************************************************
6087// batteryPublished
6088//
6089// Notification on battery class IOPowerSource appearance
6090//******************************************************************************
6091
6092bool IOPMrootDomain::batteryPublished(
6093 void * target,
6094 void * root_domain,
6095 IOService * resourceService,
6096 IONotifier * notifier __unused )
6097{
6098 // rdar://2936060&4435589
6099 // All laptops have dimmable LCD displays
6100 // All laptops have batteries
6101 // So if this machine has a battery, publish the fact that the backlight
6102 // supports dimming.
6103 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
6104
6105 return (true);
6106}
6107
6108// MARK: -
6109// MARK: System PM Policy
6110
6111//******************************************************************************
6112// checkSystemSleepAllowed
6113//
6114//******************************************************************************
6115
6116bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
6117 uint32_t sleepReason )
6118{
6119 int err = 0;
6120
6121 // Conditions that prevent idle and demand system sleep.
6122
6123 do {
6124 if (userDisabledAllSleep)
6125 {
6126 err = 1; // 1. user-space sleep kill switch
6127 break;
6128 }
6129
6130 if (systemBooting || systemShutdown || gWillShutdown)
6131 {
6132 err = 2; // 2. restart or shutdown in progress
6133 break;
6134 }
6135
6136 if (options == 0)
6137 break;
6138
6139 // Conditions above pegs the system at full wake.
6140 // Conditions below prevent system sleep but does not prevent
6141 // dark wake, and must be called from gated context.
6142
6143#if !CONFIG_SLEEP
6144 err = 3; // 3. config does not support sleep
6145 break;
6146#endif
6147
6148 if (lowBatteryCondition || thermalWarningState)
6149 {
6150 break; // always sleep on low battery or when in thermal warning state
6151 }
6152
6153 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
6154 {
6155 break; // always sleep on dark wake thermal emergencies
6156 }
6157
6158 if (preventSystemSleepList->getCount() != 0)
6159 {
6160 err = 4; // 4. child prevent system sleep clamp
6161 break;
6162 }
6163
6164 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
6165 kIOPMDriverAssertionLevelOn)
6166 {
6167 err = 5; // 5. CPU assertion
6168 break;
6169 }
6170
6171 if (pciCantSleepValid)
6172 {
6173 if (pciCantSleepFlag)
6174 err = 6; // 6. PCI card does not support PM (cached)
6175 break;
6176 }
6177 else if (sleepSupportedPEFunction &&
6178 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6179 {
6180 IOReturn ret;
6181 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
6182 ret = getPlatform()->callPlatformFunction(
6183 sleepSupportedPEFunction, false,
6184 NULL, NULL, NULL, NULL);
6185 pciCantSleepValid = true;
6186 pciCantSleepFlag = false;
6187 if ((platformSleepSupport & kPCICantSleep) ||
6188 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
6189 {
6190 err = 6; // 6. PCI card does not support PM
6191 pciCantSleepFlag = true;
6192 break;
6193 }
6194 }
6195 }
6196 while (false);
6197
6198 if (err)
6199 {
6200 DLOG("System sleep prevented by %d\n", err);
6201 return false;
6202 }
6203 return true;
6204}
6205
6206bool IOPMrootDomain::checkSystemSleepEnabled( void )
6207{
6208 return checkSystemSleepAllowed(0, 0);
6209}
6210
6211bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
6212{
6213 ASSERT_GATED();
6214 return checkSystemSleepAllowed(1, sleepReason);
6215}
6216
6217//******************************************************************************
6218// checkSystemCanSustainFullWake
6219//******************************************************************************
6220
6221bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6222{
6223#if !NO_KERNEL_HID
6224 if (lowBatteryCondition || thermalWarningState)
6225 {
6226 // Low battery wake, or received a low battery notification
6227 // while system is awake. This condition will persist until
6228 // the following wake.
6229 return false;
6230 }
6231
6232 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
6233 {
6234 // Graphics state is unknown and external display might not be probed.
6235 // Do not incorporate state that requires graphics to be in max power
6236 // such as desktopMode or clamshellDisabled.
6237
6238 if (!acAdaptorConnected)
6239 {
6240 DLOG("full wake check: no AC\n");
6241 return false;
6242 }
6243 }
6244#endif
6245 return true;
6246}
6247
6248//******************************************************************************
6249// mustHibernate
6250//******************************************************************************
6251
6252#if HIBERNATION
6253
6254bool IOPMrootDomain::mustHibernate( void )
6255{
6256 return (lowBatteryCondition || thermalWarningState);
6257}
6258
6259#endif /* HIBERNATION */
6260
6261//******************************************************************************
6262// adjustPowerState
6263//
6264// Conditions that affect our wake/sleep decision has changed.
6265// If conditions dictate that the system must remain awake, clamp power
6266// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6267// is TRUE, then remove the power clamp and allow the power state to drop
6268// to SLEEP_STATE.
6269//******************************************************************************
6270
6271void IOPMrootDomain::adjustPowerState( bool sleepASAP )
6272{
6273 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6274 (uint32_t) getPowerState(), sleepASAP, idleSleepEnabled);
6275
6276 ASSERT_GATED();
6277
6278 if ((!idleSleepEnabled) || !checkSystemSleepEnabled())
6279 {
6280 changePowerStateToPriv(ON_STATE);
6281 }
6282 else if ( sleepASAP )
6283 {
6284 changePowerStateToPriv(SLEEP_STATE);
6285 }
6286}
6287
6288void IOPMrootDomain::handleDisplayPowerOn( )
6289{
6290 if (!wrangler) return;
6291 if (displayPowerOnRequested)
6292 {
6293 if (!checkSystemCanSustainFullWake()) return;
6294
6295 // Force wrangler to max power state. If system is in dark wake
6296 // this alone won't raise the wrangler's power state.
6297
6298 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
6299
6300 // System in dark wake, always requesting full wake should
6301 // not have any bad side-effects, even if the request fails.
6302
6303 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6304 {
6305 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
6306 requestFullWake( kFullWakeReasonDisplayOn );
6307 }
6308 }
6309 else
6310 {
6311 // Relenquish desire to power up display.
6312 // Must first transition to state 1 since wrangler doesn't
6313 // power off the displays at state 0. At state 0 the root
6314 // domain is removed from the wrangler's power client list.
6315
6316 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
6317 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
6318
6319 }
6320
6321}
6322
6323//******************************************************************************
6324// dispatchPowerEvent
6325//
6326// IOPMPowerStateQueue callback function. Running on PM work loop thread.
6327//******************************************************************************
6328
6329void IOPMrootDomain::dispatchPowerEvent(
6330 uint32_t event, void * arg0, uint64_t arg1 )
6331{
6332 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6333 ASSERT_GATED();
6334
6335 switch (event)
6336 {
6337 case kPowerEventFeatureChanged:
6338 messageClients(kIOPMMessageFeatureChange, this);
6339 break;
6340
6341 case kPowerEventReceivedPowerNotification:
6342 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
6343 break;
6344
6345 case kPowerEventSystemBootCompleted:
6346 if (systemBooting)
6347 {
6348 systemBooting = false;
6349
6350 if (lowBatteryCondition)
6351 {
6352 privateSleepSystem (kIOPMSleepReasonLowPower);
6353
6354 // The rest is unnecessary since the system is expected
6355 // to sleep immediately. The following wake will update
6356 // everything.
6357 break;
6358 }
6359
6360 if (swd_flags & SWD_VALID_LOGS) {
6361 if (swd_flags & SWD_LOGS_IN_MEM) {
6362 sleepWakeDebugDumpFromMem(swd_logBufMap);
6363 swd_logBufMap->release();
6364 swd_logBufMap = 0;
6365 }
6366 else if (swd_flags & SWD_LOGS_IN_FILE)
6367 sleepWakeDebugDumpFromFile();
6368 }
6369 else if (swd_flags & (SWD_BOOT_BY_SW_WDOG|SWD_BOOT_BY_OSX_WDOG)) {
6370 // If logs are invalid, write the failure code
6371 sleepWakeDebugDumpFromMem(NULL);
6372 }
6373 // If lid is closed, re-send lid closed notification
6374 // now that booting is complete.
6375 if ( clamshellClosed )
6376 {
6377 handlePowerNotification(kLocalEvalClamshellCommand);
6378 }
6379 evaluatePolicy( kStimulusAllowSystemSleepChanged );
6380
6381 }
6382 break;
6383
6384 case kPowerEventSystemShutdown:
6385 if (kOSBooleanTrue == (OSBoolean *) arg0)
6386 {
6387 /* We set systemShutdown = true during shutdown
6388 to prevent sleep at unexpected times while loginwindow is trying
6389 to shutdown apps and while the OS is trying to transition to
6390 complete power of.
6391
6392 Set to true during shutdown, as soon as loginwindow shows
6393 the "shutdown countdown dialog", through individual app
6394 termination, and through black screen kernel shutdown.
6395 */
6396 systemShutdown = true;
6397 } else {
6398 /*
6399 A shutdown was initiated, but then the shutdown
6400 was cancelled, clearing systemShutdown to false here.
6401 */
6402 systemShutdown = false;
6403 }
6404 break;
6405
6406 case kPowerEventUserDisabledSleep:
6407 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
6408 break;
6409
6410 case kPowerEventRegisterSystemCapabilityClient:
6411 if (systemCapabilityNotifier)
6412 {
6413 systemCapabilityNotifier->release();
6414 systemCapabilityNotifier = 0;
6415 }
6416 if (arg0)
6417 {
6418 systemCapabilityNotifier = (IONotifier *) arg0;
6419 systemCapabilityNotifier->retain();
6420 }
6421 /* intentional fall-through */
6422 [[clang::fallthrough]];
6423
6424 case kPowerEventRegisterKernelCapabilityClient:
6425 if (!_joinedCapabilityClients)
6426 _joinedCapabilityClients = OSSet::withCapacity(8);
6427 if (arg0)
6428 {
6429 IONotifier * notify = (IONotifier *) arg0;
6430 if (_joinedCapabilityClients)
6431 {
6432 _joinedCapabilityClients->setObject(notify);
6433 synchronizePowerTree( kIOPMSyncNoChildNotify );
6434 }
6435 notify->release();
6436 }
6437 break;
6438
6439 case kPowerEventPolicyStimulus:
6440 if (arg0)
6441 {
6442 int stimulus = (uintptr_t) arg0;
6443 evaluatePolicy( stimulus, (uint32_t) arg1 );
6444 }
6445 break;
6446
6447 case kPowerEventAssertionCreate:
6448 if (pmAssertions) {
6449 pmAssertions->handleCreateAssertion((OSData *)arg0);
6450 }
6451 break;
6452
6453
6454 case kPowerEventAssertionRelease:
6455 if (pmAssertions) {
6456 pmAssertions->handleReleaseAssertion(arg1);
6457 }
6458 break;
6459
6460 case kPowerEventAssertionSetLevel:
6461 if (pmAssertions) {
6462 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
6463 }
6464 break;
6465
6466 case kPowerEventQueueSleepWakeUUID:
6467 handleQueueSleepWakeUUID((OSObject *)arg0);
6468 break;
6469 case kPowerEventPublishSleepWakeUUID:
6470 handlePublishSleepWakeUUID((bool)arg0);
6471 break;
6472
6473 case kPowerEventSetDisplayPowerOn:
6474 if (!wrangler) break;
6475 if (arg1 != 0)
6476 {
6477 displayPowerOnRequested = true;
6478 }
6479 else
6480 {
6481 displayPowerOnRequested = false;
6482 }
6483 handleDisplayPowerOn();
6484 break;
6485 }
6486}
6487
6488//******************************************************************************
6489// systemPowerEventOccurred
6490//
6491// The power controller is notifying us of a hardware-related power management
6492// event that we must handle.
6493//
6494// systemPowerEventOccurred covers the same functionality that
6495// receivePowerNotification does; it simply provides a richer API for conveying
6496// more information.
6497//******************************************************************************
6498
6499IOReturn IOPMrootDomain::systemPowerEventOccurred(
6500 const OSSymbol *event,
6501 uint32_t intValue)
6502{
6503 IOReturn attempt = kIOReturnSuccess;
6504 OSNumber *newNumber = NULL;
6505
6506 if (!event)
6507 return kIOReturnBadArgument;
6508
6509 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
6510 if (!newNumber)
6511 return kIOReturnInternalError;
6512
6513 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
6514
6515 newNumber->release();
6516
6517 return attempt;
6518}
6519
6520void IOPMrootDomain::setThermalState(OSObject *value)
6521{
6522 OSNumber * num;
6523
6524 if (gIOPMWorkLoop->inGate() == false) {
6525 gIOPMWorkLoop->runAction(
6526 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
6527 (OSObject *)this,
6528 (void *)value);
6529
6530 return;
6531 }
6532 if (value && (num = OSDynamicCast(OSNumber, value))) {
6533 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
6534 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
6535 }
6536}
6537
6538IOReturn IOPMrootDomain::systemPowerEventOccurred(
6539 const OSSymbol *event,
6540 OSObject *value)
6541{
6542 OSDictionary *thermalsDict = NULL;
6543 bool shouldUpdate = true;
6544
6545 if (!event || !value)
6546 return kIOReturnBadArgument;
6547
6548 // LOCK
6549 // We reuse featuresDict Lock because it already exists and guards
6550 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6551 // of stepping on that lock.
6552 if (featuresDictLock) IOLockLock(featuresDictLock);
6553
6554 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
6555
6556 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
6557 thermalsDict = OSDictionary::withDictionary(thermalsDict);
6558 } else {
6559 thermalsDict = OSDictionary::withCapacity(1);
6560 }
6561
6562 if (!thermalsDict) {
6563 shouldUpdate = false;
6564 goto exit;
6565 }
6566
6567 thermalsDict->setObject (event, value);
6568
6569 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
6570
6571 thermalsDict->release();
6572
6573exit:
6574 // UNLOCK
6575 if (featuresDictLock) IOLockUnlock(featuresDictLock);
6576
6577 if (shouldUpdate) {
6578 if (event &&
6579 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
6580 setThermalState(value);
6581 }
6582 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
6583 }
6584
6585 return kIOReturnSuccess;
6586}
6587
6588//******************************************************************************
6589// receivePowerNotification
6590//
6591// The power controller is notifying us of a hardware-related power management
6592// event that we must handle. This may be a result of an 'environment' interrupt
6593// from the power mgt micro.
6594//******************************************************************************
6595
6596IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
6597{
6598 pmPowerStateQueue->submitPowerEvent(
6599 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6600 return kIOReturnSuccess;
6601}
6602
6603void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6604{
6605 bool eval_clamshell = false;
6606
6607 ASSERT_GATED();
6608
6609 /*
6610 * Local (IOPMrootDomain only) eval clamshell command
6611 */
6612 if (msg & kLocalEvalClamshellCommand)
6613 {
6614 eval_clamshell = true;
6615 }
6616
6617 /*
6618 * Overtemp
6619 */
6620 if (msg & kIOPMOverTemp)
6621 {
6622 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6623 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
6624 }
6625
6626 /*
6627 * Forward DW thermal notification to client, if system is not going to sleep
6628 */
6629 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
6630 {
6631 DLOG("DarkWake thermal limits message received!\n");
6632
6633 messageClients(kIOPMMessageDarkWakeThermalEmergency);
6634 }
6635
6636 /*
6637 * Sleep Now!
6638 */
6639 if (msg & kIOPMSleepNow)
6640 {
6641 privateSleepSystem (kIOPMSleepReasonSoftware);
6642 }
6643
6644 /*
6645 * Power Emergency
6646 */
6647 if (msg & kIOPMPowerEmergency)
6648 {
6649 lowBatteryCondition = true;
6650 privateSleepSystem (kIOPMSleepReasonLowPower);
6651 }
6652
6653 /*
6654 * Clamshell OPEN
6655 */
6656 if (msg & kIOPMClamshellOpened)
6657 {
6658 // Received clamshel open message from clamshell controlling driver
6659 // Update our internal state and tell general interest clients
6660 clamshellClosed = false;
6661 clamshellExists = true;
6662
6663 // Don't issue a hid tickle when lid is open and polled on wake
6664 if (msg & kIOPMSetValue)
6665 {
6666 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6667 reportUserInput();
6668 }
6669
6670 // Tell PMCPU
6671 informCPUStateChange(kInformLid, 0);
6672
6673 // Tell general interest clients
6674 sendClientClamshellNotification();
6675
6676 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
6677 || (lastSleepReason == kIOPMSleepReasonIdle)
6678 || (lastSleepReason == kIOPMSleepReasonMaintenance));
6679 if (aborting) userActivityCount++;
6680 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
6681 }
6682
6683 /*
6684 * Clamshell CLOSED
6685 * Send the clamshell interest notification since the lid is closing.
6686 */
6687 if (msg & kIOPMClamshellClosed)
6688 {
6689 // Received clamshel open message from clamshell controlling driver
6690 // Update our internal state and tell general interest clients
6691 clamshellClosed = true;
6692 clamshellExists = true;
6693
6694 // Tell PMCPU
6695 informCPUStateChange(kInformLid, 1);
6696
6697 // Tell general interest clients
6698 sendClientClamshellNotification();
6699
6700 // And set eval_clamshell = so we can attempt
6701 eval_clamshell = true;
6702 }
6703
6704 /*
6705 * Set Desktop mode (sent from graphics)
6706 *
6707 * -> reevaluate lid state
6708 */
6709 if (msg & kIOPMSetDesktopMode)
6710 {
6711 desktopMode = (0 != (msg & kIOPMSetValue));
6712 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
6713
6714 sendClientClamshellNotification();
6715
6716 // Re-evaluate the lid state
6717 eval_clamshell = true;
6718 }
6719
6720 /*
6721 * AC Adaptor connected
6722 *
6723 * -> reevaluate lid state
6724 */
6725 if (msg & kIOPMSetACAdaptorConnected)
6726 {
6727 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6728 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
6729
6730 // Tell CPU PM
6731 informCPUStateChange(kInformAC, !acAdaptorConnected);
6732
6733 // Tell BSD if AC is connected
6734 // 0 == external power source; 1 == on battery
6735 post_sys_powersource(acAdaptorConnected ? 0:1);
6736
6737 sendClientClamshellNotification();
6738
6739 // Re-evaluate the lid state
6740 eval_clamshell = true;
6741
6742 // Lack of AC may have latched a display wrangler tickle.
6743 // This mirrors the hardware's USB wake event latch, where a latched
6744 // USB wake event followed by an AC attach will trigger a full wake.
6745 latchDisplayWranglerTickle( false );
6746
6747#if HIBERNATION
6748 // AC presence will reset the standy timer delay adjustment.
6749 _standbyTimerResetSeconds = 0;
6750#endif
6751 if (!userIsActive) {
6752 // Reset userActivityTime when power supply is changed(rdr 13789330)
6753 clock_get_uptime(&userActivityTime);
6754 }
6755 }
6756
6757 /*
6758 * Enable Clamshell (external display disappear)
6759 *
6760 * -> reevaluate lid state
6761 */
6762 if (msg & kIOPMEnableClamshell)
6763 {
6764 // Re-evaluate the lid state
6765 // System should sleep on external display disappearance
6766 // in lid closed operation.
6767 if (true == clamshellDisabled)
6768 {
6769 eval_clamshell = true;
6770 }
6771
6772 clamshellDisabled = false;
6773 sendClientClamshellNotification();
6774 }
6775
6776 /*
6777 * Disable Clamshell (external display appeared)
6778 * We don't bother re-evaluating clamshell state. If the system is awake,
6779 * the lid is probably open.
6780 */
6781 if (msg & kIOPMDisableClamshell)
6782 {
6783 clamshellDisabled = true;
6784 sendClientClamshellNotification();
6785 }
6786
6787 /*
6788 * Evaluate clamshell and SLEEP if appropiate
6789 */
6790 if (eval_clamshell && clamshellClosed)
6791 {
6792 if (shouldSleepOnClamshellClosed())
6793 privateSleepSystem (kIOPMSleepReasonClamshell);
6794 else
6795 evaluatePolicy( kStimulusDarkWakeEvaluate );
6796 }
6797
6798 /*
6799 * Power Button
6800 */
6801 if (msg & kIOPMPowerButton)
6802 {
6803 if (!wranglerAsleep)
6804 {
6805 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
6806 // Check that power button sleep is enabled
6807 if( pbs ) {
6808 if( kOSBooleanTrue != getProperty(pbs))
6809 privateSleepSystem (kIOPMSleepReasonPowerButton);
6810 }
6811 }
6812 else
6813 reportUserInput();
6814 }
6815}
6816
6817//******************************************************************************
6818// evaluatePolicy
6819//
6820// Evaluate root-domain policy in response to external changes.
6821//******************************************************************************
6822
6823void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
6824{
6825 union {
6826 struct {
6827 int idleSleepEnabled : 1;
6828 int idleSleepDisabled : 1;
6829 int displaySleep : 1;
6830 int sleepDelayChanged : 1;
6831 int evaluateDarkWake : 1;
6832 int adjustPowerState : 1;
6833 int userBecameInactive : 1;
6834 } bit;
6835 uint32_t u32;
6836 } flags;
6837
6838 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6839
6840 ASSERT_GATED();
6841 flags.u32 = 0;
6842
6843 switch (stimulus)
6844 {
6845 case kStimulusDisplayWranglerSleep:
6846 if (!wranglerAsleep)
6847 {
6848 // first transition to wrangler sleep or lower
6849 flags.bit.displaySleep = true;
6850 }
6851 break;
6852
6853 case kStimulusDisplayWranglerWake:
6854 displayIdleForDemandSleep = false;
6855 wranglerAsleep = false;
6856 break;
6857
6858 case kStimulusEnterUserActiveState:
6859 if (_preventUserActive)
6860 {
6861 DLOG("user active dropped\n");
6862 break;
6863 }
6864 if (!userIsActive)
6865 {
6866 userIsActive = true;
6867 userWasActive = true;
6868
6869 // Stay awake after dropping demand for display power on
6870 if (kFullWakeReasonDisplayOn == fullWakeReason) {
6871 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
6872 DLOG("User activity while in notification wake\n");
6873 changePowerStateWithOverrideTo( ON_STATE, 0);
6874 }
6875
6876 kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
6877 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
6878 messageClients(kIOPMMessageUserIsActiveChanged);
6879 }
6880 flags.bit.idleSleepDisabled = true;
6881 break;
6882
6883 case kStimulusLeaveUserActiveState:
6884 if (userIsActive)
6885 {
6886 userIsActive = false;
6887 clock_get_uptime(&userBecameInactiveTime);
6888 flags.bit.userBecameInactive = true;
6889
6890 kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
6891 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
6892 messageClients(kIOPMMessageUserIsActiveChanged);
6893 }
6894 break;
6895
6896 case kStimulusAggressivenessChanged:
6897 {
6898 unsigned long minutesToIdleSleep = 0;
6899 unsigned long minutesToDisplayDim = 0;
6900 unsigned long minutesDelta = 0;
6901
6902 // Fetch latest display and system sleep slider values.
6903 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
6904 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
6905 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6906 (uint32_t) sleepSlider,
6907 (uint32_t) minutesToIdleSleep,
6908 (uint32_t) minutesToDisplayDim);
6909
6910 DLOG("idle time -> %ld secs (ena %d)\n",
6911 idleSeconds, (minutesToIdleSleep != 0));
6912
6913
6914 // How long to wait before sleeping the system once
6915 // the displays turns off is indicated by 'extraSleepDelay'.
6916
6917 if ( minutesToIdleSleep > minutesToDisplayDim )
6918 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
6919 else if ( minutesToIdleSleep == minutesToDisplayDim )
6920 minutesDelta = 1;
6921
6922 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0))
6923 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
6924
6925 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
6926 flags.bit.idleSleepDisabled = true;
6927 idleSleepEnabled = false;
6928 }
6929 if (0x7fffffff == minutesToIdleSleep)
6930 minutesToIdleSleep = idleSeconds;
6931
6932 if (((minutesDelta != extraSleepDelay) ||
6933 (userActivityTime != userActivityTime_prev)) &&
6934 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
6935 flags.bit.sleepDelayChanged = true;
6936
6937 if (systemDarkWake && !darkWakeToSleepASAP &&
6938 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
6939 {
6940 // Reconsider decision to remain in dark wake
6941 flags.bit.evaluateDarkWake = true;
6942 }
6943
6944 sleepSlider = minutesToIdleSleep;
6945 extraSleepDelay = minutesDelta;
6946 userActivityTime_prev = userActivityTime;
6947 } break;
6948
6949 case kStimulusDemandSystemSleep:
6950 displayIdleForDemandSleep = true;
6951 if (wrangler && wranglerIdleSettings)
6952 {
6953 // Request wrangler idle only when demand sleep is triggered
6954 // from full wake.
6955 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6956 {
6957 wrangler->setProperties(wranglerIdleSettings);
6958 DLOG("Requested wrangler idle\n");
6959 }
6960 }
6961 // arg = sleepReason
6962 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
6963 break;
6964
6965 case kStimulusAllowSystemSleepChanged:
6966 flags.bit.adjustPowerState = true;
6967 break;
6968
6969 case kStimulusDarkWakeActivityTickle:
6970 // arg == true implies real and not self generated wrangler tickle.
6971 // Update wake type on PM work loop instead of the tickle thread to
6972 // eliminate the possibility of an early tickle clobbering the wake
6973 // type set by the platform driver.
6974 if (arg == true)
6975 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
6976
6977 if (false == wranglerTickled)
6978 {
6979 if (latchDisplayWranglerTickle(true))
6980 {
6981 DLOG("latched tickle\n");
6982 break;
6983 }
6984
6985 wranglerTickled = true;
6986 DLOG("Requesting full wake after dark wake activity tickle\n");
6987 requestFullWake( kFullWakeReasonLocalUser );
6988 }
6989 break;
6990
6991 case kStimulusDarkWakeEntry:
6992 case kStimulusDarkWakeReentry:
6993 // Any system transitions since the last dark wake transition
6994 // will invalid the stimulus.
6995
6996 if (arg == _systemStateGeneration)
6997 {
6998 DLOG("dark wake entry\n");
6999 systemDarkWake = true;
7000
7001 // Keep wranglerAsleep an invariant when wrangler is absent
7002 if (wrangler)
7003 wranglerAsleep = true;
7004
7005 if (kStimulusDarkWakeEntry == stimulus)
7006 {
7007 clock_get_uptime(&userBecameInactiveTime);
7008 flags.bit.evaluateDarkWake = true;
7009 }
7010
7011 // Always accelerate disk spindown while in dark wake,
7012 // even if system does not support/allow sleep.
7013
7014 cancelIdleSleepTimer();
7015 setQuickSpinDownTimeout();
7016 }
7017 break;
7018
7019 case kStimulusDarkWakeEvaluate:
7020 if (systemDarkWake)
7021 {
7022 flags.bit.evaluateDarkWake = true;
7023 }
7024 break;
7025
7026 case kStimulusNoIdleSleepPreventers:
7027 flags.bit.adjustPowerState = true;
7028 break;
7029
7030 } /* switch(stimulus) */
7031
7032 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
7033 {
7034 if (darkWakeToSleepASAP ||
7035 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
7036 {
7037 uint32_t newSleepReason;
7038
7039 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
7040 {
7041 // System was previously in full wake. Sleep reason from
7042 // full to dark already recorded in fullToDarkReason.
7043
7044 if (lowBatteryCondition)
7045 newSleepReason = kIOPMSleepReasonLowPower;
7046 else
7047 newSleepReason = fullToDarkReason;
7048 }
7049 else
7050 {
7051 // In dark wake from system sleep.
7052
7053 if (darkWakeSleepService)
7054 newSleepReason = kIOPMSleepReasonSleepServiceExit;
7055 else
7056 newSleepReason = kIOPMSleepReasonMaintenance;
7057 }
7058
7059 if (checkSystemCanSleep(newSleepReason))
7060 {
7061 privateSleepSystem(newSleepReason);
7062 }
7063 }
7064 else // non-maintenance (network) dark wake
7065 {
7066 if (checkSystemCanSleep(kIOPMSleepReasonIdle))
7067 {
7068 // Release power clamp, and wait for children idle.
7069 adjustPowerState(true);
7070 }
7071 else
7072 {
7073 changePowerStateToPriv(ON_STATE);
7074 }
7075 }
7076 }
7077
7078 if (systemDarkWake)
7079 {
7080 // The rest are irrelevant while system is in dark wake.
7081 flags.u32 = 0;
7082 }
7083
7084 if ((flags.bit.displaySleep) &&
7085 (kFullWakeReasonDisplayOn == fullWakeReason))
7086 {
7087 // kIOPMSleepReasonMaintenance?
7088 DLOG("Display sleep while in notification wake\n");
7089 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
7090 }
7091
7092 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
7093 {
7094 bool cancelQuickSpindown = false;
7095
7096 if (flags.bit.sleepDelayChanged)
7097 {
7098 // Cancel existing idle sleep timer and quick disk spindown.
7099 // New settings will be applied by the idleSleepEnabled flag
7100 // handler below if idle sleep is enabled.
7101
7102 DLOG("extra sleep timer changed\n");
7103 cancelIdleSleepTimer();
7104 cancelQuickSpindown = true;
7105 }
7106 else
7107 {
7108 DLOG("user inactive\n");
7109 }
7110
7111 if (!userIsActive && idleSleepEnabled)
7112 {
7113 startIdleSleepTimer(getTimeToIdleSleep());
7114 }
7115
7116 if (cancelQuickSpindown)
7117 restoreUserSpinDownTimeout();
7118 }
7119
7120 if (flags.bit.idleSleepEnabled)
7121 {
7122 DLOG("idle sleep timer enabled\n");
7123 if (!wrangler)
7124 {
7125 changePowerStateToPriv(ON_STATE);
7126 startIdleSleepTimer( idleSeconds );
7127 }
7128 else
7129 {
7130 // Start idle timer if prefs now allow system sleep
7131 // and user is already inactive. Disk spindown is
7132 // accelerated upon timer expiration.
7133
7134 if (!userIsActive)
7135 {
7136 startIdleSleepTimer(getTimeToIdleSleep());
7137 }
7138 }
7139 }
7140
7141 if (flags.bit.idleSleepDisabled)
7142 {
7143 DLOG("idle sleep timer disabled\n");
7144 cancelIdleSleepTimer();
7145 restoreUserSpinDownTimeout();
7146 adjustPowerState();
7147 }
7148
7149 if (flags.bit.adjustPowerState)
7150 {
7151 bool sleepASAP = false;
7152
7153 if (!systemBooting && (preventIdleSleepList->getCount() == 0))
7154 {
7155 if (!wrangler)
7156 {
7157 changePowerStateToPriv(ON_STATE);
7158 if (idleSleepEnabled)
7159 {
7160 // stay awake for at least idleSeconds
7161 startIdleSleepTimer(idleSeconds);
7162 }
7163 }
7164 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
7165 {
7166 sleepASAP = true;
7167 }
7168 }
7169
7170 adjustPowerState(sleepASAP);
7171 }
7172}
7173
7174//******************************************************************************
7175// requestFullWake
7176//
7177// Request transition from dark wake to full wake
7178//******************************************************************************
7179
7180void IOPMrootDomain::requestFullWake( FullWakeReason reason )
7181{
7182 uint32_t options = 0;
7183 IOService * pciRoot = 0;
7184 bool promotion = false;
7185
7186 // System must be in dark wake and a valid reason for entering full wake
7187 if ((kFullWakeReasonNone == reason) ||
7188 (kFullWakeReasonNone != fullWakeReason) ||
7189 (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
7190 {
7191 return;
7192 }
7193
7194 // Will clear reason upon exit from full wake
7195 fullWakeReason = reason;
7196
7197 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
7198 kIOPMSystemCapabilityAudio);
7199
7200 if ((kSystemTransitionWake == _systemTransitionType) &&
7201 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7202 !graphicsSuppressed)
7203 {
7204 // Promote to full wake while waking up to dark wake due to tickle.
7205 // PM will hold off notifying the graphics subsystem about system wake
7206 // as late as possible, so if a HID tickle does arrive, graphics can
7207 // power up on this same wake cycle. The latency to power up graphics
7208 // on the next cycle can be huge on some systems. However, once any
7209 // graphics suppression has taken effect, it is too late. All other
7210 // graphics devices must be similarly suppressed. But the delay till
7211 // the following cycle should be short.
7212
7213 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
7214 kIOPMSystemCapabilityAudio);
7215
7216 // Immediately bring up audio and graphics
7217 pciRoot = pciHostBridgeDriver;
7218 willEnterFullWake();
7219 promotion = true;
7220 }
7221
7222 // Unsafe to cancel once graphics was powered.
7223 // If system woke from dark wake, the return to sleep can
7224 // be cancelled. "awake -> dark -> sleep" transition
7225 // can be canceled also, during the "dark --> sleep" phase
7226 // *prior* to driver power down.
7227 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
7228 _pendingCapability == 0) {
7229 options |= kIOPMSyncCancelPowerDown;
7230 }
7231
7232 synchronizePowerTree(options, pciRoot);
7233 if (kFullWakeReasonLocalUser == fullWakeReason)
7234 {
7235 // IOGraphics doesn't light the display even though graphics is
7236 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7237 // So, do an explicit activity tickle
7238 if (wrangler)
7239 wrangler->activityTickle(0,0);
7240 }
7241
7242 // Log a timestamp for the initial full wake request.
7243 // System may not always honor this full wake request.
7244 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
7245 {
7246 AbsoluteTime now;
7247 uint64_t nsec;
7248
7249 clock_get_uptime(&now);
7250 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
7251 absolutetime_to_nanoseconds(now, &nsec);
7252 MSG("full wake %s (reason %u) %u ms\n",
7253 promotion ? "promotion" : "request",
7254 fullWakeReason, ((int)((nsec) / 1000000ULL)));
7255 }
7256}
7257
7258//******************************************************************************
7259// willEnterFullWake
7260//
7261// System will enter full wake from sleep, from dark wake, or from dark
7262// wake promotion. This function aggregate things that are in common to
7263// all three full wake transitions.
7264//
7265// Assumptions: fullWakeReason was updated
7266//******************************************************************************
7267
7268void IOPMrootDomain::willEnterFullWake( void )
7269{
7270 hibernateRetry = false;
7271 sleepToStandby = false;
7272 standbyNixed = false;
7273 resetTimers = false;
7274 sleepTimerMaintenance = false;
7275
7276 _systemMessageClientMask = kSystemMessageClientPowerd |
7277 kSystemMessageClientLegacyApp;
7278
7279 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
7280 {
7281 // Initial graphics full power
7282 _systemMessageClientMask |= kSystemMessageClientKernel;
7283
7284 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7285 setProperty(gIOPMUserTriggeredFullWakeKey,
7286 (kFullWakeReasonLocalUser == fullWakeReason) ?
7287 kOSBooleanTrue : kOSBooleanFalse);
7288 }
7289#if HIBERNATION
7290 IOHibernateSetWakeCapabilities(_pendingCapability);
7291#endif
7292
7293 IOService::setAdvisoryTickleEnable( true );
7294 tellClients(kIOMessageSystemWillPowerOn);
7295 preventTransitionToUserActive(false);
7296}
7297
7298//******************************************************************************
7299// fullWakeDelayedWork
7300//
7301// System has already entered full wake. Invoked by a delayed thread call.
7302//******************************************************************************
7303
7304void IOPMrootDomain::fullWakeDelayedWork( void )
7305{
7306#if DARK_TO_FULL_EVALUATE_CLAMSHELL
7307 // Not gated, don't modify state
7308 if ((kSystemTransitionNone == _systemTransitionType) &&
7309 CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7310 {
7311 receivePowerNotification( kLocalEvalClamshellCommand );
7312 }
7313#endif
7314}
7315
7316//******************************************************************************
7317// evaluateAssertions
7318//
7319//******************************************************************************
7320void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
7321{
7322 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
7323
7324 messageClients(kIOPMMessageDriverAssertionsChanged);
7325
7326 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
7327
7328 if (wrangler) {
7329 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
7330
7331 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
7332 wrangler->setIgnoreIdleTimer( value );
7333 }
7334 }
7335
7336 if (changedBits & kIOPMDriverAssertionCPUBit) {
7337 evaluatePolicy(kStimulusDarkWakeEvaluate);
7338 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
7339 AbsoluteTime now;
7340 clock_usec_t microsecs;
7341 clock_get_uptime(&now);
7342 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
7343 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
7344 if (assertOnWakeReport) {
7345 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
7346 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
7347 }
7348 }
7349 }
7350
7351 if (changedBits & kIOPMDriverAssertionReservedBit7) {
7352 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
7353 if (value) {
7354 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7355 updatePreventIdleSleepList(this, true);
7356 }
7357 else {
7358 DLOG("Driver assertion ReservedBit7 dropped\n");
7359 updatePreventIdleSleepList(this, false);
7360 }
7361 }
7362}
7363
7364// MARK: -
7365// MARK: Statistics
7366
7367//******************************************************************************
7368// pmStats
7369//
7370//******************************************************************************
7371
7372void IOPMrootDomain::pmStatsRecordEvent(
7373 int eventIndex,
7374 AbsoluteTime timestamp)
7375{
7376 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
7377 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
7378 uint64_t delta;
7379 uint64_t nsec;
7380 OSData *publishPMStats = NULL;
7381
7382 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
7383
7384 absolutetime_to_nanoseconds(timestamp, &nsec);
7385
7386 switch (eventIndex) {
7387 case kIOPMStatsHibernateImageWrite:
7388 if (starting)
7389 gPMStats.hibWrite.start = nsec;
7390 else if (stopping)
7391 gPMStats.hibWrite.stop = nsec;
7392
7393 if (stopping) {
7394 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
7395 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
7396 }
7397 break;
7398 case kIOPMStatsHibernateImageRead:
7399 if (starting)
7400 gPMStats.hibRead.start = nsec;
7401 else if (stopping)
7402 gPMStats.hibRead.stop = nsec;
7403
7404 if (stopping) {
7405 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
7406 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
7407
7408 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
7409 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
7410 publishPMStats->release();
7411 bzero(&gPMStats, sizeof(gPMStats));
7412 }
7413 break;
7414 }
7415}
7416
7417/*
7418 * Appends a record of the application response to
7419 * IOPMrootDomain::pmStatsAppResponses
7420 */
7421void IOPMrootDomain::pmStatsRecordApplicationResponse(
7422 const OSSymbol *response,
7423 const char *name,
7424 int messageType,
7425 uint32_t delay_ms,
7426 uint64_t id,
7427 OSObject *object,
7428 IOPMPowerStateIndex powerState)
7429{
7430 OSDictionary *responseDescription = NULL;
7431 OSNumber *delayNum = NULL;
7432 OSNumber *powerCaps = NULL;
7433 OSNumber *pidNum = NULL;
7434 OSNumber *msgNum = NULL;
7435 const OSSymbol *appname;
7436 const OSSymbol *sleep = NULL, *wake = NULL;
7437 IOPMServiceInterestNotifier *notify = 0;
7438
7439 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
7440 {
7441 if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut))
7442 notify->ackTimeoutCnt++;
7443 else
7444 notify->ackTimeoutCnt = 0;
7445
7446 }
7447
7448 if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) ||
7449 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
7450 return;
7451
7452
7453 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7454 kdebugTrace(kPMLogDrvResponseDelay, id, messageType, delay_ms);
7455 }
7456 else if (notify) {
7457 kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
7458 notify->msgType = 0;
7459 }
7460
7461 responseDescription = OSDictionary::withCapacity(5);
7462 if (responseDescription)
7463 {
7464 if (response) {
7465 responseDescription->setObject(_statsResponseTypeKey, response);
7466 }
7467
7468 msgNum = OSNumber::withNumber(messageType, 32);
7469 if (msgNum) {
7470 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7471 msgNum->release();
7472 }
7473
7474 if (name && (strlen(name) > 0))
7475 {
7476 appname = OSSymbol::withCString(name);
7477 if (appname) {
7478 responseDescription->setObject(_statsNameKey, appname);
7479 appname->release();
7480 }
7481 }
7482
7483 if (id != 0) {
7484 pidNum = OSNumber::withNumber(id, 32);
7485 if (pidNum) {
7486 responseDescription->setObject(_statsPIDKey, pidNum);
7487 pidNum->release();
7488 }
7489 }
7490
7491 delayNum = OSNumber::withNumber(delay_ms, 32);
7492 if (delayNum) {
7493 responseDescription->setObject(_statsTimeMSKey, delayNum);
7494 delayNum->release();
7495 }
7496
7497 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7498 powerCaps = OSNumber::withNumber(powerState, 32);
7499
7500#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7501 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7502 name, messageType,
7503 powerState, delay_ms);
7504#endif
7505
7506 }
7507 else {
7508 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
7509 }
7510 if (powerCaps) {
7511 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7512 powerCaps->release();
7513 }
7514
7515 sleep = OSSymbol::withCString("Sleep");
7516 wake = OSSymbol::withCString("Wake");
7517 if (_systemTransitionType == kSystemTransitionSleep) {
7518 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7519 }
7520 else if (_systemTransitionType == kSystemTransitionWake) {
7521 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7522 }
7523 else if (_systemTransitionType == kSystemTransitionCapability) {
7524 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
7525 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7526 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
7527 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7528 }
7529 if (sleep) sleep->release();
7530 if (wake) wake->release();
7531
7532
7533
7534 IOLockLock(pmStatsLock);
7535 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
7536 pmStatsAppResponses->setObject(responseDescription);
7537 }
7538 IOLockUnlock(pmStatsLock);
7539
7540 responseDescription->release();
7541 }
7542
7543 return;
7544}
7545
7546// MARK: -
7547// MARK: PMTraceWorker
7548
7549//******************************************************************************
7550// TracePoint support
7551//
7552//******************************************************************************
7553
7554#define kIOPMRegisterNVRAMTracePointHandlerKey \
7555 "IOPMRegisterNVRAMTracePointHandler"
7556
7557IOReturn IOPMrootDomain::callPlatformFunction(
7558 const OSSymbol * functionName,
7559 bool waitForFunction,
7560 void * param1, void * param2,
7561 void * param3, void * param4 )
7562{
7563 uint32_t bootFailureCode = 0xffffffff;
7564 unsigned int len = sizeof(bootFailureCode);
7565 if (pmTracer && functionName &&
7566 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7567 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7568 {
7569 uint32_t tracePointPhases, tracePointPCI;
7570 uint64_t statusCode;
7571
7572 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7573 pmTracer->tracePointTarget = (void *) param2;
7574 tracePointPCI = (uint32_t)(uintptr_t) param3;
7575 tracePointPhases = (uint32_t)(uintptr_t) param4;
7576 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
7577 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey, &bootFailureCode, &len)) {
7578 MSG("Failed to read failure code from NVRam\n");
7579 }
7580 // Failure code from EFI/BootRom is a four byte structure
7581 tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
7582 }
7583 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
7584 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
7585 MSG("Sleep failure code 0x%08x 0x%08x\n",
7586 tracePointPCI, tracePointPhases);
7587 }
7588 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
7589 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7590
7591 return kIOReturnSuccess;
7592 }
7593#if HIBERNATION
7594 else if (functionName &&
7595 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
7596 {
7597 if (gSleepPolicyHandler)
7598 return kIOReturnExclusiveAccess;
7599 if (!param1)
7600 return kIOReturnBadArgument;
7601 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
7602 gSleepPolicyTarget = (void *) param2;
7603 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
7604 return kIOReturnSuccess;
7605 }
7606#endif
7607
7608 return super::callPlatformFunction(
7609 functionName, waitForFunction, param1, param2, param3, param4);
7610}
7611
7612void IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
7613 uintptr_t param1, uintptr_t param2, uintptr_t param3)
7614{
7615 uint32_t code = IODBG_POWER(event);
7616 uint64_t regId = id;
7617 if (regId == 0) {
7618 regId = getRegistryEntryID();
7619 }
7620 IOTimeStampConstant(code, (uintptr_t) regId, param1, param2, param3);
7621}
7622
7623
7624void IOPMrootDomain::tracePoint( uint8_t point )
7625{
7626 if (systemBooting) return;
7627
7628 if (kIOPMTracePointWakeCapabilityClients == point)
7629 acceptSystemWakeEvents(false);
7630
7631 kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
7632 pmTracer->tracePoint(point);
7633}
7634
7635void IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uintptr_t handler)
7636{
7637 if (!systemBooting) {
7638 uint32_t detail = ((msgIndex & 0xff) << 24) |
7639 ((msgType & 0xfff) << 12) |
7640 (handler & 0xfff);
7641 pmTracer->traceDetail( detail );
7642 kdebugTrace(kPMLogSleepWakeTracePoint, 0, pmTracer->getTracePhase(), msgType, handler & 0xfff);
7643 }
7644}
7645
7646
7647void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
7648{
7649 size_t reportSize;
7650 void **report = NULL;
7651 uint32_t bktCnt;
7652 uint32_t bktSize;
7653 uint32_t *clientCnt;
7654
7655 ASSERT_GATED();
7656
7657 report = NULL;
7658 if (channel_id == kAssertDelayChID) {
7659 report = &assertOnWakeReport;
7660 bktCnt = kAssertDelayBcktCnt;
7661 bktSize = kAssertDelayBcktSize;
7662 clientCnt = &assertOnWakeClientCnt;
7663 }
7664 else if (channel_id == kSleepDelaysChID) {
7665 report = &sleepDelaysReport;
7666 bktCnt = kSleepDelaysBcktCnt;
7667 bktSize = kSleepDelaysBcktSize;
7668 clientCnt = &sleepDelaysClientCnt;
7669 }
7670
7671 switch (action)
7672 {
7673 case kIOReportEnable:
7674
7675 if (*report) {
7676 (*clientCnt)++;
7677 break;
7678 }
7679
7680 reportSize = HISTREPORT_BUFSIZE(bktCnt);
7681 *report = IOMalloc(reportSize);
7682 if (*report == NULL) {
7683 break;
7684 }
7685 bzero(*report, reportSize);
7686 HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
7687 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
7688
7689 if (channel_id == kAssertDelayChID)
7690 assertOnWakeSecs = 0;
7691
7692 break;
7693
7694 case kIOReportDisable:
7695 if (*clientCnt == 0) {
7696 break;
7697 }
7698 if (*clientCnt == 1)
7699 {
7700 IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
7701 *report = NULL;
7702 }
7703 (*clientCnt)--;
7704
7705 if (channel_id == kAssertDelayChID)
7706 assertOnWakeSecs = -1; // Invalid value to prevent updates
7707
7708 break;
7709
7710 case kIOReportGetDimensions:
7711 if (*report) {
7712 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
7713 }
7714 break;
7715 }
7716
7717 return;
7718}
7719
7720IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
7721 IOReportConfigureAction action,
7722 void *result,
7723 void *destination)
7724{
7725 unsigned cnt;
7726 uint64_t configAction = (uint64_t)action;
7727
7728 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7729 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
7730 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
7731 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
7732 if (action != kIOReportGetDimensions) continue;
7733 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7734 }
7735 else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
7736 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
7737 gIOPMWorkLoop->runAction(
7738 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
7739 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
7740 (void *)configAction, (void *)result);
7741 }
7742 }
7743
7744 return super::configureReport(channelList, action, result, destination);
7745}
7746
7747IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
7748{
7749
7750 uint32_t size2cpy;
7751 void *data2cpy;
7752 void **report;
7753
7754 ASSERT_GATED();
7755
7756 report = NULL;
7757 if (ch_id == kAssertDelayChID) {
7758 report = &assertOnWakeReport;
7759 }
7760 else if (ch_id == kSleepDelaysChID) {
7761 report = &sleepDelaysReport;
7762 }
7763
7764 if (*report == NULL) {
7765 return kIOReturnNotOpen;
7766 }
7767
7768 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
7769 if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
7770 return kIOReturnOverrun;
7771 }
7772
7773 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
7774 dest->appendBytes(data2cpy, size2cpy);
7775
7776 return kIOReturnSuccess;
7777}
7778
7779IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
7780 IOReportUpdateAction action,
7781 void *result,
7782 void *destination)
7783{
7784 uint32_t size2cpy;
7785 void *data2cpy;
7786 uint8_t buf[SIMPLEREPORT_BUFSIZE];
7787 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7788 unsigned cnt;
7789 uint64_t ch_id;
7790
7791 if (action != kIOReportCopyChannelData) goto exit;
7792
7793 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7794 ch_id = channelList->channels[cnt].channel_id ;
7795
7796 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
7797 gIOPMWorkLoop->runAction(
7798 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
7799 (OSObject *)this, (void *)ch_id,
7800 (void *)result, (void *)dest);
7801 continue;
7802
7803 }
7804 else if ((ch_id == kSleepCntChID) ||
7805 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
7806 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
7807 }
7808 else continue;
7809
7810 if (ch_id == kSleepCntChID)
7811 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
7812 else if (ch_id == kDarkWkCntChID)
7813 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
7814 else if (ch_id == kUserWkCntChID)
7815 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
7816
7817 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7818 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7819 dest->appendBytes(data2cpy, size2cpy);
7820 }
7821
7822exit:
7823 return super::updateReport(channelList, action, result, destination);
7824}
7825
7826
7827//******************************************************************************
7828// PMTraceWorker Class
7829//
7830//******************************************************************************
7831
7832#undef super
7833#define super OSObject
7834OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
7835
7836#define kPMBestGuessPCIDevicesCount 25
7837#define kPMMaxRTCBitfieldSize 32
7838
7839PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
7840{
7841 PMTraceWorker *me;
7842
7843 me = OSTypeAlloc( PMTraceWorker );
7844 if (!me || !me->init())
7845 {
7846 return NULL;
7847 }
7848
7849 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
7850
7851 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7852 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7853 // this dictionary lazily.
7854 me->owner = owner;
7855 me->pciDeviceBitMappings = NULL;
7856 me->pmTraceWorkerLock = IOLockAlloc();
7857 me->tracePhase = kIOPMTracePointSystemUp;
7858 me->traceData32 = 0;
7859 me->loginWindowData = 0;
7860 me->coreDisplayData = 0;
7861 me->coreGraphicsData = 0;
7862 return me;
7863}
7864
7865void PMTraceWorker::RTC_TRACE(void)
7866{
7867 if (tracePointHandler && tracePointTarget)
7868 {
7869 uint32_t wordA;
7870
7871 IOLockLock(pmTraceWorkerLock);
7872 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
7873 (coreGraphicsData << 8) | tracePhase;
7874 IOLockUnlock(pmTraceWorkerLock);
7875
7876 tracePointHandler( tracePointTarget, traceData32, wordA );
7877 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
7878 }
7879}
7880
7881int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
7882{
7883 const OSSymbol * deviceName;
7884 int index = -1;
7885
7886 IOLockLock(pmTraceWorkerLock);
7887
7888 if (!pciDeviceBitMappings)
7889 {
7890 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
7891 if (!pciDeviceBitMappings)
7892 goto exit;
7893 }
7894
7895 // Check for bitmask overflow.
7896 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
7897 goto exit;
7898
7899 if ((deviceName = pciDevice->copyName()) &&
7900 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
7901 pciDeviceBitMappings->setObject(deviceName))
7902 {
7903 index = pciDeviceBitMappings->getCount() - 1;
7904 _LOG("PMTrace PCI array: set object %s => %d\n",
7905 deviceName->getCStringNoCopy(), index);
7906 }
7907 if (deviceName)
7908 deviceName->release();
7909 if (!addedToRegistry && (index >= 0))
7910 addedToRegistry = owner->setProperty("PCITopLevel", this);
7911
7912exit:
7913 IOLockUnlock(pmTraceWorkerLock);
7914 return index;
7915}
7916
7917bool PMTraceWorker::serialize(OSSerialize *s) const
7918{
7919 bool ok = false;
7920 if (pciDeviceBitMappings)
7921 {
7922 IOLockLock(pmTraceWorkerLock);
7923 ok = pciDeviceBitMappings->serialize(s);
7924 IOLockUnlock(pmTraceWorkerLock);
7925 }
7926 return ok;
7927}
7928
7929void PMTraceWorker::tracePoint(uint8_t phase)
7930{
7931 // clear trace detail when phase begins
7932 if (tracePhase != phase)
7933 traceData32 = 0;
7934
7935 tracePhase = phase;
7936
7937 DLOG("trace point 0x%02x\n", tracePhase);
7938 RTC_TRACE();
7939}
7940
7941void PMTraceWorker::traceDetail(uint32_t detail)
7942{
7943
7944 traceData32 = detail;
7945 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7946
7947 RTC_TRACE();
7948}
7949
7950void PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
7951{
7952 switch (component) {
7953 case kIOPMLoginWindowProgress:
7954 loginWindowData = data & kIOPMLoginWindowProgressMask;
7955 break;
7956 case kIOPMCoreDisplayProgress:
7957 coreDisplayData = data & kIOPMCoreDisplayProgressMask;
7958 break;
7959 case kIOPMCoreGraphicsProgress:
7960 coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
7961 break;
7962 default:
7963 return;
7964 }
7965
7966 DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
7967 RTC_TRACE();
7968}
7969
7970void PMTraceWorker::tracePCIPowerChange(
7971 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
7972{
7973 uint32_t bitMask;
7974 uint32_t expectedFlag;
7975
7976 // Ignore PCI changes outside of system sleep/wake.
7977 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
7978 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
7979 return;
7980
7981 // Only record the WillChange transition when going to sleep,
7982 // and the DidChange on the way up.
7983 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
7984 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
7985 kIOPMDomainWillChange : kIOPMDomainDidChange;
7986 if (changeFlags != expectedFlag)
7987 return;
7988
7989 // Mark this device off in our bitfield
7990 if (bitNum < kPMMaxRTCBitfieldSize)
7991 {
7992 bitMask = (1 << bitNum);
7993
7994 if (kPowerChangeStart == type)
7995 {
7996 traceData32 |= bitMask;
7997 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7998 service->getName(), bitNum, bitMask, traceData32);
7999 owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
8000 }
8001 else
8002 {
8003 traceData32 &= ~bitMask;
8004 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8005 service->getName(), bitNum, bitMask, traceData32);
8006 owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
8007 }
8008
8009 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
8010 RTC_TRACE();
8011 }
8012}
8013
8014uint64_t PMTraceWorker::getPMStatusCode( )
8015{
8016 return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase));
8017
8018}
8019
8020uint8_t PMTraceWorker::getTracePhase()
8021{
8022 return tracePhase;
8023}
8024
8025uint32_t PMTraceWorker::getTraceData()
8026{
8027 return traceData32;
8028}
8029
8030// MARK: -
8031// MARK: PMHaltWorker
8032
8033//******************************************************************************
8034// PMHaltWorker Class
8035//
8036//******************************************************************************
8037
8038PMHaltWorker * PMHaltWorker::worker( void )
8039{
8040 PMHaltWorker * me;
8041 IOThread thread;
8042
8043 do {
8044 me = OSTypeAlloc( PMHaltWorker );
8045 if (!me || !me->init())
8046 break;
8047
8048 me->lock = IOLockAlloc();
8049 if (!me->lock)
8050 break;
8051
8052 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
8053 me->retain(); // thread holds extra retain
8054 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
8055 {
8056 me->release();
8057 break;
8058 }
8059 thread_deallocate(thread);
8060 return me;
8061
8062 } while (false);
8063
8064 if (me) me->release();
8065 return 0;
8066}
8067
8068void PMHaltWorker::free( void )
8069{
8070 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8071 if (lock)
8072 {
8073 IOLockFree(lock);
8074 lock = 0;
8075 }
8076 return OSObject::free();
8077}
8078
8079void PMHaltWorker::main( void * arg, wait_result_t waitResult )
8080{
8081 PMHaltWorker * me = (PMHaltWorker *) arg;
8082
8083 IOLockLock( gPMHaltLock );
8084 gPMHaltBusyCount++;
8085 me->depth = gPMHaltDepth;
8086 IOLockUnlock( gPMHaltLock );
8087
8088 while (me->depth >= 0)
8089 {
8090 PMHaltWorker::work( me );
8091
8092 IOLockLock( gPMHaltLock );
8093 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
8094 {
8095 // This is the last thread to finish work on this level,
8096 // inform everyone to start working on next lower level.
8097 gPMHaltDepth--;
8098 me->depth = gPMHaltDepth;
8099 gPMHaltIdleCount = 0;
8100 thread_wakeup((event_t) &gPMHaltIdleCount);
8101 }
8102 else
8103 {
8104 // One or more threads are still working on this level,
8105 // this thread must wait.
8106 me->depth = gPMHaltDepth - 1;
8107 do {
8108 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
8109 } while (me->depth != gPMHaltDepth);
8110 }
8111 IOLockUnlock( gPMHaltLock );
8112 }
8113
8114 // No more work to do, terminate thread
8115 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
8116 thread_wakeup( &gPMHaltDepth );
8117 me->release();
8118}
8119
8120void PMHaltWorker::work( PMHaltWorker * me )
8121{
8122 IOService * service;
8123 OSSet * inner;
8124 AbsoluteTime startTime;
8125 UInt32 deltaTime;
8126 bool timeout;
8127
8128 while (true)
8129 {
8130 service = 0;
8131 timeout = false;
8132
8133 // Claim an unit of work from the shared pool
8134 IOLockLock( gPMHaltLock );
8135 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
8136 if (inner)
8137 {
8138 service = OSDynamicCast(IOService, inner->getAnyObject());
8139 if (service)
8140 {
8141 service->retain();
8142 inner->removeObject(service);
8143 }
8144 }
8145 IOLockUnlock( gPMHaltLock );
8146 if (!service)
8147 break; // no more work at this depth
8148
8149 clock_get_uptime(&startTime);
8150
8151 if (!service->isInactive() &&
8152 service->setProperty(gPMHaltClientAcknowledgeKey, me))
8153 {
8154 IOLockLock(me->lock);
8155 me->startTime = startTime;
8156 me->service = service;
8157 me->timeout = false;
8158 IOLockUnlock(me->lock);
8159
8160 service->systemWillShutdown( gPMHaltMessageType );
8161
8162 // Wait for driver acknowledgement
8163 IOLockLock(me->lock);
8164 while (service->getProperty(gPMHaltClientAcknowledgeKey))
8165 {
8166 IOLockSleep(me->lock, me, THREAD_UNINT);
8167 }
8168 me->service = 0;
8169 timeout = me->timeout;
8170 IOLockUnlock(me->lock);
8171 }
8172
8173 deltaTime = computeDeltaTimeMS(&startTime);
8174 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
8175 (gIOKitDebug & kIOLogPMRootDomain))
8176 {
8177 LOG("%s driver %s (0x%llx) took %u ms\n",
8178 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
8179 "PowerOff" : "Restart",
8180 service->getName(), service->getRegistryEntryID(),
8181 (uint32_t) deltaTime );
8182 }
8183
8184 service->release();
8185 me->visits++;
8186 }
8187}
8188
8189void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
8190{
8191 UInt64 nano;
8192 AbsoluteTime startTime;
8193 AbsoluteTime endTime;
8194
8195 endTime = *now;
8196
8197 IOLockLock(me->lock);
8198 if (me->service && !me->timeout)
8199 {
8200 startTime = me->startTime;
8201 nano = 0;
8202 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
8203 {
8204 SUB_ABSOLUTETIME(&endTime, &startTime);
8205 absolutetime_to_nanoseconds(endTime, &nano);
8206 }
8207 if (nano > 3000000000ULL)
8208 {
8209 me->timeout = true;
8210 MSG("%s still waiting on %s\n",
8211 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
8212 "PowerOff" : "Restart",
8213 me->service->getName());
8214 }
8215 }
8216 IOLockUnlock(me->lock);
8217}
8218
8219//******************************************************************************
8220// acknowledgeSystemWillShutdown
8221//
8222// Acknowledgement from drivers that they have prepared for shutdown/restart.
8223//******************************************************************************
8224
8225void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
8226{
8227 PMHaltWorker * worker;
8228 OSObject * prop;
8229
8230 if (!from)
8231 return;
8232
8233 //DLOG("%s acknowledged\n", from->getName());
8234 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
8235 if (prop)
8236 {
8237 worker = (PMHaltWorker *) prop;
8238 IOLockLock(worker->lock);
8239 from->removeProperty( gPMHaltClientAcknowledgeKey );
8240 thread_wakeup((event_t) worker);
8241 IOLockUnlock(worker->lock);
8242 worker->release();
8243 }
8244 else
8245 {
8246 DLOG("%s acknowledged without worker property\n",
8247 from->getName());
8248 }
8249}
8250
8251
8252//******************************************************************************
8253// notifySystemShutdown
8254//
8255// Notify all objects in PM tree that system will shutdown or restart
8256//******************************************************************************
8257
8258static void
8259notifySystemShutdown( IOService * root, uint32_t messageType )
8260{
8261#define PLACEHOLDER ((OSSet *)gPMHaltArray)
8262 IORegistryIterator * iter;
8263 IORegistryEntry * entry;
8264 IOService * node;
8265 OSSet * inner;
8266 PMHaltWorker * workers[kPMHaltMaxWorkers];
8267 AbsoluteTime deadline;
8268 unsigned int totalNodes = 0;
8269 unsigned int depth;
8270 unsigned int rootDepth;
8271 unsigned int numWorkers;
8272 unsigned int count;
8273 int waitResult;
8274 void * baseFunc;
8275 bool ok;
8276
8277 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
8278
8279 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
8280
8281 // Iterate the entire PM tree starting from root
8282
8283 rootDepth = root->getDepth( gIOPowerPlane );
8284 if (!rootDepth) goto done;
8285
8286 // debug - for repeated test runs
8287 while (PMHaltWorker::metaClass->getInstanceCount())
8288 IOSleep(1);
8289
8290 if (!gPMHaltArray)
8291 {
8292 gPMHaltArray = OSArray::withCapacity(40);
8293 if (!gPMHaltArray) goto done;
8294 }
8295 else // debug
8296 gPMHaltArray->flushCollection();
8297
8298 if (!gPMHaltLock)
8299 {
8300 gPMHaltLock = IOLockAlloc();
8301 if (!gPMHaltLock) goto done;
8302 }
8303
8304 if (!gPMHaltClientAcknowledgeKey)
8305 {
8306 gPMHaltClientAcknowledgeKey =
8307 OSSymbol::withCStringNoCopy("PMShutdown");
8308 if (!gPMHaltClientAcknowledgeKey) goto done;
8309 }
8310
8311 gPMHaltMessageType = messageType;
8312
8313 // Depth-first walk of PM plane
8314
8315 iter = IORegistryIterator::iterateOver(
8316 root, gIOPowerPlane, kIORegistryIterateRecursively);
8317
8318 if (iter)
8319 {
8320 while ((entry = iter->getNextObject()))
8321 {
8322 node = OSDynamicCast(IOService, entry);
8323 if (!node)
8324 continue;
8325
8326 if (baseFunc ==
8327 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
8328 continue;
8329
8330 depth = node->getDepth( gIOPowerPlane );
8331 if (depth <= rootDepth)
8332 continue;
8333
8334 ok = false;
8335
8336 // adjust to zero based depth
8337 depth -= (rootDepth + 1);
8338
8339 // gPMHaltArray is an array of containers, each container
8340 // refers to nodes with the same depth.
8341
8342 count = gPMHaltArray->getCount();
8343 while (depth >= count)
8344 {
8345 // expand array and insert placeholders
8346 gPMHaltArray->setObject(PLACEHOLDER);
8347 count++;
8348 }
8349 count = gPMHaltArray->getCount();
8350 if (depth < count)
8351 {
8352 inner = (OSSet *)gPMHaltArray->getObject(depth);
8353 if (inner == PLACEHOLDER)
8354 {
8355 inner = OSSet::withCapacity(40);
8356 if (inner)
8357 {
8358 gPMHaltArray->replaceObject(depth, inner);
8359 inner->release();
8360 }
8361 }
8362
8363 // PM nodes that appear more than once in the tree will have
8364 // the same depth, OSSet will refuse to add the node twice.
8365 if (inner)
8366 ok = inner->setObject(node);
8367 }
8368 if (!ok)
8369 DLOG("Skipped PM node %s\n", node->getName());
8370 }
8371 iter->release();
8372 }
8373
8374 // debug only
8375 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
8376 {
8377 count = 0;
8378 if (inner != PLACEHOLDER)
8379 count = inner->getCount();
8380 DLOG("Nodes at depth %u = %u\n", i, count);
8381 }
8382
8383 // strip placeholders (not all depths are populated)
8384 numWorkers = 0;
8385 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
8386 {
8387 if (inner == PLACEHOLDER)
8388 {
8389 gPMHaltArray->removeObject(i);
8390 continue;
8391 }
8392 count = inner->getCount();
8393 if (count > numWorkers)
8394 numWorkers = count;
8395 totalNodes += count;
8396 i++;
8397 }
8398
8399 if (gPMHaltArray->getCount() == 0 || !numWorkers)
8400 goto done;
8401
8402 gPMHaltBusyCount = 0;
8403 gPMHaltIdleCount = 0;
8404 gPMHaltDepth = gPMHaltArray->getCount() - 1;
8405
8406 // Create multiple workers (and threads)
8407
8408 if (numWorkers > kPMHaltMaxWorkers)
8409 numWorkers = kPMHaltMaxWorkers;
8410
8411 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8412 totalNodes, gPMHaltArray->getCount(), numWorkers);
8413
8414 for (unsigned int i = 0; i < numWorkers; i++)
8415 workers[i] = PMHaltWorker::worker();
8416
8417 // Wait for workers to exhaust all available work
8418
8419 IOLockLock(gPMHaltLock);
8420 while (gPMHaltDepth >= 0)
8421 {
8422 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
8423
8424 waitResult = IOLockSleepDeadline(
8425 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
8426 if (THREAD_TIMED_OUT == waitResult)
8427 {
8428 AbsoluteTime now;
8429 clock_get_uptime(&now);
8430
8431 IOLockUnlock(gPMHaltLock);
8432 for (unsigned int i = 0 ; i < numWorkers; i++)
8433 {
8434 if (workers[i])
8435 PMHaltWorker::checkTimeout(workers[i], &now);
8436 }
8437 IOLockLock(gPMHaltLock);
8438 }
8439 }
8440 IOLockUnlock(gPMHaltLock);
8441
8442 // Release all workers
8443
8444 for (unsigned int i = 0; i < numWorkers; i++)
8445 {
8446 if (workers[i])
8447 workers[i]->release();
8448 // worker also retained by it's own thread
8449 }
8450
8451done:
8452 DLOG("%s done\n", __FUNCTION__);
8453 return;
8454}
8455
8456// MARK: -
8457// MARK: Kernel Assertion
8458
8459/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8460
8461IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
8462 IOPMDriverAssertionType whichAssertionBits,
8463 IOPMDriverAssertionLevel assertionLevel,
8464 IOService *ownerService,
8465 const char *ownerDescription)
8466{
8467 IOReturn ret;
8468 IOPMDriverAssertionID newAssertion;
8469
8470 if (!pmAssertions)
8471 return 0;
8472
8473 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
8474
8475 if (kIOReturnSuccess == ret)
8476 return newAssertion;
8477 else
8478 return 0;
8479}
8480
8481IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
8482{
8483 if (!pmAssertions)
8484 return kIOReturnInternalError;
8485
8486 return pmAssertions->releaseAssertion(releaseAssertion);
8487}
8488
8489
8490IOReturn IOPMrootDomain::setPMAssertionLevel(
8491 IOPMDriverAssertionID assertionID,
8492 IOPMDriverAssertionLevel assertionLevel)
8493{
8494 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8495}
8496
8497IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8498{
8499 IOPMDriverAssertionType sysLevels;
8500
8501 if (!pmAssertions || whichAssertion == 0)
8502 return kIOPMDriverAssertionLevelOff;
8503
8504 sysLevels = pmAssertions->getActivatedAssertions();
8505
8506 // Check that every bit set in argument 'whichAssertion' is asserted
8507 // in the aggregate bits.
8508 if ((sysLevels & whichAssertion) == whichAssertion)
8509 return kIOPMDriverAssertionLevelOn;
8510 else
8511 return kIOPMDriverAssertionLevelOff;
8512}
8513
8514IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
8515{
8516 if (!pmAssertions)
8517 return kIOReturnNotFound;
8518
8519 return pmAssertions->setUserAssertionLevels(inLevels);
8520}
8521
8522bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
8523{
8524 if (pmAssertions)
8525 {
8526 pmAssertions->publishProperties();
8527 }
8528 return( IOService::serializeProperties(s) );
8529}
8530
8531OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8532{
8533 OSObject *obj = NULL;
8534 obj = IOService::copyProperty(aKey);
8535
8536 if (obj) return obj;
8537
8538 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
8539 sizeof(kIOPMSleepWakeWdogRebootKey))) {
8540 if (swd_flags & SWD_BOOT_BY_SW_WDOG)
8541 return kOSBooleanTrue;
8542 else
8543 return kOSBooleanFalse;
8544
8545 }
8546
8547 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
8548 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
8549 if (swd_flags & SWD_VALID_LOGS)
8550 return kOSBooleanTrue;
8551 else
8552 return kOSBooleanFalse;
8553
8554 }
8555
8556 /*
8557 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8558 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8559 * issued by DisplayWrangler on darkwake.
8560 */
8561 if (!strcmp(aKey, "DesktopMode")) {
8562 if (desktopMode)
8563 return kOSBooleanTrue;
8564 else
8565 return kOSBooleanFalse;
8566 }
8567 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8568 if (displayIdleForDemandSleep) {
8569 return kOSBooleanTrue;
8570 }
8571 else {
8572 return kOSBooleanFalse;
8573 }
8574 }
8575
8576 if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
8577 {
8578 OSArray * array = 0;
8579 WAKEEVENT_LOCK();
8580 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
8581 OSCollection *collection = _systemWakeEventsArray->copyCollection();
8582 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8583 collection->release();
8584 }
8585 }
8586 WAKEEVENT_UNLOCK();
8587 return array;
8588 }
8589
8590 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
8591 {
8592 OSArray * array = 0;
8593 IOLockLock(pmStatsLock);
8594 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
8595 OSCollection *collection = pmStatsAppResponses->copyCollection();
8596 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8597 collection->release();
8598 }
8599 pmStatsAppResponses->flushCollection();
8600 }
8601 IOLockUnlock(pmStatsLock);
8602 return array;
8603 }
8604
8605 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
8606 {
8607 OSArray *idleSleepList = NULL;
8608 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
8609 return idleSleepList;
8610 }
8611
8612 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
8613 {
8614 OSArray *systemSleepList = NULL;
8615 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
8616 return systemSleepList;
8617 }
8618
8619 return NULL;
8620}
8621
8622// MARK: -
8623// MARK: Wake Event Reporting
8624
8625void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
8626{
8627 WAKEEVENT_LOCK();
8628 strlcpy(outBuf, gWakeReasonString, bufSize);
8629 WAKEEVENT_UNLOCK();
8630}
8631
8632//******************************************************************************
8633// acceptSystemWakeEvents
8634//
8635// Private control for the acceptance of driver wake event claims.
8636//******************************************************************************
8637
8638void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
8639{
8640 bool logWakeReason = false;
8641
8642 WAKEEVENT_LOCK();
8643 if (accept)
8644 {
8645 gWakeReasonString[0] = '\0';
8646 if (!_systemWakeEventsArray)
8647 _systemWakeEventsArray = OSArray::withCapacity(4);
8648 if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
8649 _systemWakeEventsArray->flushCollection();
8650 }
8651 else
8652 {
8653 _acceptSystemWakeEvents = false;
8654 }
8655 WAKEEVENT_UNLOCK();
8656
8657 if (logWakeReason)
8658 MSG("system wake events:%s\n", gWakeReasonString);
8659}
8660
8661//******************************************************************************
8662// claimSystemWakeEvent
8663//
8664// For a driver to claim a device is the source/conduit of a system wake event.
8665//******************************************************************************
8666
8667void IOPMrootDomain::claimSystemWakeEvent(
8668 IOService * device,
8669 IOOptionBits flags,
8670 const char * reason,
8671 OSObject * details )
8672{
8673 const OSSymbol * deviceName = 0;
8674 OSNumber * deviceRegId = 0;
8675 OSNumber * claimTime = 0;
8676 OSData * flagsData = 0;
8677 OSString * reasonString = 0;
8678 OSDictionary * d = 0;
8679 uint64_t timestamp;
8680 bool ok = false;
8681
8682 pmEventTimeStamp(&timestamp);
8683
8684 if (!device || !reason) return;
8685
8686 deviceName = device->copyName(gIOServicePlane);
8687 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
8688 claimTime = OSNumber::withNumber(timestamp, 64);
8689 flagsData = OSData::withBytes(&flags, sizeof(flags));
8690 reasonString = OSString::withCString(reason);
8691 d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
8692 if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
8693 goto done;
8694
8695 d->setObject(gIONameKey, deviceName);
8696 d->setObject(gIORegistryEntryIDKey, deviceRegId);
8697 d->setObject(kIOPMWakeEventTimeKey, claimTime);
8698 d->setObject(kIOPMWakeEventFlagsKey, flagsData);
8699 d->setObject(kIOPMWakeEventReasonKey, reasonString);
8700 if (details)
8701 d->setObject(kIOPMWakeEventDetailsKey, details);
8702
8703 WAKEEVENT_LOCK();
8704 if (!gWakeReasonSysctlRegistered)
8705 {
8706 // Lazy registration until the platform driver stops registering
8707 // the same name.
8708 gWakeReasonSysctlRegistered = true;
8709 }
8710 if (_acceptSystemWakeEvents)
8711 {
8712 ok = _systemWakeEventsArray->setObject(d);
8713 if (gWakeReasonString[0] != '\0')
8714 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
8715 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
8716 }
8717 WAKEEVENT_UNLOCK();
8718
8719done:
8720 if (deviceName) deviceName->release();
8721 if (deviceRegId) deviceRegId->release();
8722 if (claimTime) claimTime->release();
8723 if (flagsData) flagsData->release();
8724 if (reasonString) reasonString->release();
8725 if (d) d->release();
8726}
8727
8728/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8729
8730// MARK: -
8731// MARK: PMSettingHandle
8732
8733OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
8734
8735void PMSettingHandle::free( void )
8736{
8737 if (pmso)
8738 {
8739 pmso->clientHandleFreed();
8740 pmso->release();
8741 pmso = 0;
8742 }
8743
8744 OSObject::free();
8745}
8746
8747// MARK: -
8748// MARK: PMSettingObject
8749
8750#undef super
8751#define super OSObject
8752OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
8753
8754/*
8755 * Static constructor/initializer for PMSettingObject
8756 */
8757PMSettingObject *PMSettingObject::pmSettingObject(
8758 IOPMrootDomain *parent_arg,
8759 IOPMSettingControllerCallback handler_arg,
8760 OSObject *target_arg,
8761 uintptr_t refcon_arg,
8762 uint32_t supportedPowerSources,
8763 const OSSymbol * settings[],
8764 OSObject **handle_obj)
8765{
8766 uint32_t settingCount = 0;
8767 PMSettingObject *pmso = 0;
8768 PMSettingHandle *pmsh = 0;
8769
8770 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
8771 return NULL;
8772
8773 // count OSSymbol entries in NULL terminated settings array
8774 while (settings[settingCount]) {
8775 settingCount++;
8776 }
8777 if (0 == settingCount)
8778 return NULL;
8779
8780 pmso = new PMSettingObject;
8781 if (!pmso || !pmso->init())
8782 goto fail;
8783
8784 pmsh = new PMSettingHandle;
8785 if (!pmsh || !pmsh->init())
8786 goto fail;
8787
8788 queue_init(&pmso->calloutQueue);
8789 pmso->parent = parent_arg;
8790 pmso->func = handler_arg;
8791 pmso->target = target_arg;
8792 pmso->refcon = refcon_arg;
8793 pmso->settingCount = settingCount;
8794
8795 pmso->retain(); // handle holds a retain on pmso
8796 pmsh->pmso = pmso;
8797 pmso->pmsh = pmsh;
8798
8799 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
8800 if (pmso->publishedFeatureID) {
8801 for (unsigned int i=0; i<settingCount; i++) {
8802 // Since there is now at least one listener to this setting, publish
8803 // PM root domain support for it.
8804 parent_arg->publishPMSetting( settings[i],
8805 supportedPowerSources, &pmso->publishedFeatureID[i] );
8806 }
8807 }
8808
8809 *handle_obj = pmsh;
8810 return pmso;
8811
8812fail:
8813 if (pmso) pmso->release();
8814 if (pmsh) pmsh->release();
8815 return NULL;
8816}
8817
8818void PMSettingObject::free( void )
8819{
8820 if (publishedFeatureID) {
8821 for (uint32_t i=0; i<settingCount; i++) {
8822 if (publishedFeatureID[i]) {
8823 parent->removePublishedFeature( publishedFeatureID[i] );
8824 }
8825 }
8826
8827 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
8828 }
8829
8830 super::free();
8831}
8832
8833void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
8834{
8835 (*func)(target, type, object, refcon);
8836}
8837
8838void PMSettingObject::clientHandleFreed( void )
8839{
8840 parent->deregisterPMSettingObject(this);
8841}
8842
8843// MARK: -
8844// MARK: PMAssertionsTracker
8845
8846//*********************************************************************************
8847//*********************************************************************************
8848//*********************************************************************************
8849// class PMAssertionsTracker Implementation
8850
8851#define kAssertUniqueIDStart 500
8852
8853PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
8854{
8855 PMAssertionsTracker *myself;
8856
8857 myself = new PMAssertionsTracker;
8858
8859 if (myself) {
8860 myself->init();
8861 myself->owner = rootDomain;
8862 myself->issuingUniqueID = kAssertUniqueIDStart;
8863 myself->assertionsArray = OSArray::withCapacity(5);
8864 myself->assertionsKernel = 0;
8865 myself->assertionsUser = 0;
8866 myself->assertionsCombined = 0;
8867 myself->assertionsArrayLock = IOLockAlloc();
8868 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
8869
8870 if (!myself->assertionsArray || !myself->assertionsArrayLock)
8871 myself = NULL;
8872 }
8873
8874 return myself;
8875}
8876
8877/* tabulate
8878 * - Update assertionsKernel to reflect the state of all
8879 * assertions in the kernel.
8880 * - Update assertionsCombined to reflect both kernel & user space.
8881 */
8882void PMAssertionsTracker::tabulate(void)
8883{
8884 int i;
8885 int count;
8886 PMAssertStruct *_a = NULL;
8887 OSData *_d = NULL;
8888
8889 IOPMDriverAssertionType oldKernel = assertionsKernel;
8890 IOPMDriverAssertionType oldCombined = assertionsCombined;
8891
8892 ASSERT_GATED();
8893
8894 assertionsKernel = 0;
8895 assertionsCombined = 0;
8896
8897 if (!assertionsArray)
8898 return;
8899
8900 if ((count = assertionsArray->getCount()))
8901 {
8902 for (i=0; i<count; i++)
8903 {
8904 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8905 if (_d)
8906 {
8907 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8908 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
8909 assertionsKernel |= _a->assertionBits;
8910 }
8911 }
8912 }
8913
8914 tabulateProducerCount++;
8915 assertionsCombined = assertionsKernel | assertionsUser;
8916
8917 if ((assertionsKernel != oldKernel) ||
8918 (assertionsCombined != oldCombined))
8919 {
8920 owner->evaluateAssertions(assertionsCombined, oldCombined);
8921 }
8922}
8923
8924void PMAssertionsTracker::publishProperties( void )
8925{
8926 OSArray *assertionsSummary = NULL;
8927
8928 if (tabulateConsumerCount != tabulateProducerCount)
8929 {
8930 IOLockLock(assertionsArrayLock);
8931
8932 tabulateConsumerCount = tabulateProducerCount;
8933
8934 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8935 */
8936 assertionsSummary = copyAssertionsArray();
8937 if (assertionsSummary)
8938 {
8939 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
8940 assertionsSummary->release();
8941 }
8942 else
8943 {
8944 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
8945 }
8946
8947 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8948 */
8949 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
8950
8951 IOLockUnlock(assertionsArrayLock);
8952 }
8953}
8954
8955PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
8956{
8957 PMAssertStruct *_a = NULL;
8958 OSData *_d = NULL;
8959 int found = -1;
8960 int count = 0;
8961 int i = 0;
8962
8963 if (assertionsArray
8964 && (count = assertionsArray->getCount()))
8965 {
8966 for (i=0; i<count; i++)
8967 {
8968 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8969 if (_d)
8970 {
8971 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8972 if (_a && (_id == _a->id)) {
8973 found = i;
8974 break;
8975 }
8976 }
8977 }
8978 }
8979
8980 if (-1 == found) {
8981 return NULL;
8982 } else {
8983 if (index)
8984 *index = found;
8985 return _a;
8986 }
8987}
8988
8989/* PMAssertionsTracker::handleCreateAssertion
8990 * Perform assertion work on the PM workloop. Do not call directly.
8991 */
8992IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
8993{
8994 ASSERT_GATED();
8995
8996 if (newAssertion)
8997 {
8998 IOLockLock(assertionsArrayLock);
8999 assertionsArray->setObject(newAssertion);
9000 IOLockUnlock(assertionsArrayLock);
9001 newAssertion->release();
9002
9003 tabulate();
9004 }
9005 return kIOReturnSuccess;
9006}
9007
9008/* PMAssertionsTracker::createAssertion
9009 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9010 * appropiate.
9011 */
9012IOReturn PMAssertionsTracker::createAssertion(
9013 IOPMDriverAssertionType which,
9014 IOPMDriverAssertionLevel level,
9015 IOService *serviceID,
9016 const char *whoItIs,
9017 IOPMDriverAssertionID *outID)
9018{
9019 OSData *dataStore = NULL;
9020 PMAssertStruct track;
9021
9022 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9023 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
9024 track.level = level;
9025 track.assertionBits = which;
9026 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
9027 track.ownerService = serviceID;
9028 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
9029 track.modifiedTime = 0;
9030 pmEventTimeStamp(&track.createdTime);
9031
9032 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
9033 if (!dataStore)
9034 {
9035 if (track.ownerString)
9036 track.ownerString->release();
9037 return kIOReturnNoMemory;
9038 }
9039
9040 *outID = track.id;
9041
9042 if (owner && owner->pmPowerStateQueue) {
9043 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
9044 }
9045
9046 return kIOReturnSuccess;
9047}
9048
9049/* PMAssertionsTracker::handleReleaseAssertion
9050 * Runs in PM workloop. Do not call directly.
9051 */
9052IOReturn PMAssertionsTracker::handleReleaseAssertion(
9053 IOPMDriverAssertionID _id)
9054{
9055 ASSERT_GATED();
9056
9057 int index;
9058 PMAssertStruct *assertStruct = detailsForID(_id, &index);
9059
9060 if (!assertStruct)
9061 return kIOReturnNotFound;
9062
9063 IOLockLock(assertionsArrayLock);
9064 if (assertStruct->ownerString)
9065 assertStruct->ownerString->release();
9066
9067 assertionsArray->removeObject(index);
9068 IOLockUnlock(assertionsArrayLock);
9069
9070 tabulate();
9071 return kIOReturnSuccess;
9072}
9073
9074/* PMAssertionsTracker::releaseAssertion
9075 * Releases an assertion and affects system behavior if appropiate.
9076 * Actual work happens on PM workloop.
9077 */
9078IOReturn PMAssertionsTracker::releaseAssertion(
9079 IOPMDriverAssertionID _id)
9080{
9081 if (owner && owner->pmPowerStateQueue) {
9082 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
9083 }
9084 return kIOReturnSuccess;
9085}
9086
9087/* PMAssertionsTracker::handleSetAssertionLevel
9088 * Runs in PM workloop. Do not call directly.
9089 */
9090IOReturn PMAssertionsTracker::handleSetAssertionLevel(
9091 IOPMDriverAssertionID _id,
9092 IOPMDriverAssertionLevel _level)
9093{
9094 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
9095
9096 ASSERT_GATED();
9097
9098 if (!assertStruct) {
9099 return kIOReturnNotFound;
9100 }
9101
9102 IOLockLock(assertionsArrayLock);
9103 pmEventTimeStamp(&assertStruct->modifiedTime);
9104 assertStruct->level = _level;
9105 IOLockUnlock(assertionsArrayLock);
9106
9107 tabulate();
9108 return kIOReturnSuccess;
9109}
9110
9111/* PMAssertionsTracker::setAssertionLevel
9112 */
9113IOReturn PMAssertionsTracker::setAssertionLevel(
9114 IOPMDriverAssertionID _id,
9115 IOPMDriverAssertionLevel _level)
9116{
9117 if (owner && owner->pmPowerStateQueue) {
9118 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
9119 (void *)(uintptr_t)_level, _id);
9120 }
9121
9122 return kIOReturnSuccess;
9123}
9124
9125IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
9126{
9127 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
9128
9129 ASSERT_GATED();
9130
9131 if (new_user_levels != assertionsUser)
9132 {
9133 assertionsUser = new_user_levels;
9134 DLOG("assertionsUser 0x%llx\n", assertionsUser);
9135 }
9136
9137 tabulate();
9138 return kIOReturnSuccess;
9139}
9140
9141IOReturn PMAssertionsTracker::setUserAssertionLevels(
9142 IOPMDriverAssertionType new_user_levels)
9143{
9144 if (gIOPMWorkLoop) {
9145 gIOPMWorkLoop->runAction(
9146 OSMemberFunctionCast(
9147 IOWorkLoop::Action,
9148 this,
9149 &PMAssertionsTracker::handleSetUserAssertionLevels),
9150 this,
9151 (void *) &new_user_levels, 0, 0, 0);
9152 }
9153
9154 return kIOReturnSuccess;
9155}
9156
9157
9158OSArray *PMAssertionsTracker::copyAssertionsArray(void)
9159{
9160 int count;
9161 int i;
9162 OSArray *outArray = NULL;
9163
9164 if (!assertionsArray ||
9165 (0 == (count = assertionsArray->getCount())) ||
9166 (NULL == (outArray = OSArray::withCapacity(count))))
9167 {
9168 goto exit;
9169 }
9170
9171 for (i=0; i<count; i++)
9172 {
9173 PMAssertStruct *_a = NULL;
9174 OSData *_d = NULL;
9175 OSDictionary *details = NULL;
9176
9177 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9178 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
9179 {
9180 OSNumber *_n = NULL;
9181
9182 details = OSDictionary::withCapacity(7);
9183 if (!details)
9184 continue;
9185
9186 outArray->setObject(details);
9187 details->release();
9188
9189 _n = OSNumber::withNumber(_a->id, 64);
9190 if (_n) {
9191 details->setObject(kIOPMDriverAssertionIDKey, _n);
9192 _n->release();
9193 }
9194 _n = OSNumber::withNumber(_a->createdTime, 64);
9195 if (_n) {
9196 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
9197 _n->release();
9198 }
9199 _n = OSNumber::withNumber(_a->modifiedTime, 64);
9200 if (_n) {
9201 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
9202 _n->release();
9203 }
9204 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
9205 if (_n) {
9206 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
9207 _n->release();
9208 }
9209 _n = OSNumber::withNumber(_a->level, 64);
9210 if (_n) {
9211 details->setObject(kIOPMDriverAssertionLevelKey, _n);
9212 _n->release();
9213 }
9214 _n = OSNumber::withNumber(_a->assertionBits, 64);
9215 if (_n) {
9216 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
9217 _n->release();
9218 }
9219
9220 if (_a->ownerString) {
9221 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
9222 }
9223 }
9224 }
9225
9226exit:
9227 return outArray;
9228}
9229
9230IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
9231{
9232 return assertionsCombined;
9233}
9234
9235IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
9236 IOPMDriverAssertionType type)
9237{
9238 if (type && ((type & assertionsKernel) == assertionsKernel))
9239 {
9240 return kIOPMDriverAssertionLevelOn;
9241 } else {
9242 return kIOPMDriverAssertionLevelOff;
9243 }
9244}
9245
9246//*********************************************************************************
9247//*********************************************************************************
9248//*********************************************************************************
9249
9250
9251static void pmEventTimeStamp(uint64_t *recordTS)
9252{
9253 clock_sec_t tsec;
9254 clock_usec_t tusec;
9255
9256 if (!recordTS)
9257 return;
9258
9259 // We assume tsec fits into 32 bits; 32 bits holds enough
9260 // seconds for 136 years since the epoch in 1970.
9261 clock_get_calendar_microtime(&tsec, &tusec);
9262
9263
9264 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9265 *recordTS = 0;
9266 *recordTS |= (uint32_t)tusec;
9267 *recordTS |= ((uint64_t)tsec << 32);
9268
9269 return;
9270}
9271
9272// MARK: -
9273// MARK: IORootParent
9274
9275/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9276
9277OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
9278
9279// The reason that root domain needs a root parent is to facilitate demand
9280// sleep, since a power change from the root parent cannot be vetoed.
9281//
9282// The above statement is no longer true since root domain now performs
9283// demand sleep using overrides. But root parent remains to avoid changing
9284// the power tree stacking. Root parent is parked at the max power state.
9285
9286
9287static IOPMPowerState patriarchPowerStates[2] =
9288{
9289 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9290 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9291};
9292
9293void IORootParent::initialize( void )
9294{
9295}
9296
9297bool IORootParent::start( IOService * nub )
9298{
9299 IOService::start(nub);
9300 attachToParent( getRegistryRoot(), gIOPowerPlane );
9301 PMinit();
9302 registerPowerDriver(this, patriarchPowerStates, 2);
9303 makeUsable();
9304 return true;
9305}
9306
9307void IORootParent::shutDownSystem( void )
9308{
9309}
9310
9311void IORootParent::restartSystem( void )
9312{
9313}
9314
9315void IORootParent::sleepSystem( void )
9316{
9317}
9318
9319void IORootParent::dozeSystem( void )
9320{
9321}
9322
9323void IORootParent::sleepToDoze( void )
9324{
9325}
9326
9327void IORootParent::wakeSystem( void )
9328{
9329}
9330
9331OSObject * IORootParent::copyProperty( const char * aKey) const
9332{
9333 return (IOService::copyProperty(aKey));
9334}
9335
9336
9337#if defined(__i386__) || defined(__x86_64__)
9338IOReturn IOPMrootDomain::restartWithStackshot()
9339{
9340 if ((swd_flags & SWD_WDOG_ENABLED) == 0)
9341 return kIOReturnError;
9342
9343 takeStackshot(true, true, false);
9344
9345 return kIOReturnSuccess;
9346}
9347
9348void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
9349{
9350 takeStackshot(wdogTrigger, false, false);
9351}
9352
9353void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
9354{
9355 swd_hdr * hdr = NULL;
9356 addr64_t data[3];
9357 int wdog_panic = -1;
9358 int cnt = 0;
9359 pid_t pid = 0;
9360 kern_return_t kr = KERN_SUCCESS;
9361 uint32_t flags;
9362
9363 char * dstAddr;
9364 uint32_t size;
9365 uint32_t bytesRemaining;
9366 unsigned bytesWritten = 0;
9367 unsigned totalBytes = 0;
9368 unsigned int len;
9369 OSString * UUIDstring = NULL;
9370 uint64_t code;
9371 IOMemoryMap * logBufMap = NULL;
9372
9373
9374 uint32_t bufSize;
9375 uint32_t initialStackSize;
9376
9377 if (isSpinDump) {
9378 if (_systemTransitionType != kSystemTransitionSleep &&
9379 _systemTransitionType != kSystemTransitionWake)
9380 return;
9381 } else {
9382 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9383 return;
9384 }
9385
9386 if (wdogTrigger) {
9387 PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic));
9388 if (wdog_panic == 1) {
9389 // If boot-arg specifies to panic then panic.
9390 panic("Sleep/Wake hang detected\n");
9391 return;
9392 }
9393 else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9394 // If current boot is due to this watch dog trigger restart in previous boot,
9395 // then don't trigger again until at least 1 successful sleep & wake.
9396 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
9397 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9398 PEHaltRestart(kPEHaltCPU);
9399 return;
9400 }
9401 }
9402
9403 }
9404
9405 if (isSpinDump) {
9406 if (gSpinDumpBufferFull)
9407 return;
9408 if (swd_spindump_buffer == NULL) {
9409 sleepWakeDebugSpinDumpMemAlloc();
9410 if (swd_spindump_buffer == NULL) return;
9411 }
9412
9413 bufSize = SWD_SPINDUMP_SIZE;
9414 initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
9415 } else {
9416 if (sleepWakeDebugIsWdogEnabled() == false)
9417 return;
9418
9419 if (swd_buffer == NULL) {
9420 sleepWakeDebugMemAlloc();
9421 if (swd_buffer == NULL) return;
9422 }
9423
9424 bufSize = SWD_BUF_SIZE;
9425 initialStackSize = SWD_INITIAL_STACK_SIZE;
9426 }
9427
9428 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9429 return;
9430
9431 if (isSpinDump) {
9432 hdr = (swd_hdr *)swd_spindump_buffer;
9433 }
9434 else {
9435 hdr = (swd_hdr *)swd_buffer;
9436 }
9437
9438 memset(hdr->UUID, 0x20, sizeof(hdr->UUID));
9439 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
9440
9441 if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) {
9442 const char *str = UUIDstring->getCStringNoCopy();
9443 snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s", str);
9444 }
9445 else {
9446 DLOG("Data for current UUID already exists\n");
9447 goto exit;
9448 }
9449 }
9450
9451 dstAddr = (char*)hdr + hdr->spindump_offset;
9452 bytesRemaining = bufSize - hdr->spindump_offset;
9453
9454 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9455 hdr->is_osx_watchdog = isOSXWatchdog;
9456
9457 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
9458
9459 flags = STACKSHOT_KCDATA_FORMAT|STACKSHOT_NO_IO_STATS|STACKSHOT_SAVE_KEXT_LOADINFO;
9460 while (kr == KERN_SUCCESS) {
9461
9462 if (cnt == 0) {
9463 /*
9464 * Take stackshot of all process on first sample. Size is restricted
9465 * to SWD_INITIAL_STACK_SIZE
9466 */
9467 pid = -1;
9468 size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
9469 flags |= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY;
9470 }
9471 else {
9472 /* Take sample of kernel threads only */
9473 pid = 0;
9474 size = bytesRemaining;
9475 }
9476
9477 kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, &bytesWritten);
9478 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9479 kr, pid, size, flags, bytesWritten);
9480 if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
9481 if (pid == -1) {
9482 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9483 // Continue to take stackshot of just kernel threads
9484 ++cnt;
9485 kr = KERN_SUCCESS;
9486 continue;
9487 }
9488 else if (totalBytes == 0) {
9489 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr, size, flags);
9490 }
9491 }
9492
9493 dstAddr += bytesWritten;
9494 totalBytes += bytesWritten;
9495 bytesRemaining -= bytesWritten;
9496
9497 if (++cnt == 10) {
9498 break;
9499 }
9500 IOSleep(10); // 10 ms
9501 }
9502
9503 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
9504
9505
9506 memset(hdr->spindump_status, 0x20, sizeof(hdr->spindump_status));
9507 code = pmTracer->getPMStatusCode();
9508 memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode));
9509 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x",
9510 (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
9511 memset(hdr->reason, 0x20, sizeof(hdr->reason));
9512 if (isSpinDump) {
9513 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: PSC Delay\n\n");
9514 gRootDomain->swd_lock = 0;
9515 gSpinDumpBufferFull = true;
9516 return;
9517 }
9518 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
9519
9520
9521 data[0] = round_page(sizeof(swd_hdr) + hdr->spindump_size);
9522 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9523 data[1] = hdr->crc = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size);
9524 data[2] = kvtophys((vm_offset_t)swd_buffer);
9525 len = sizeof(addr64_t)*3;
9526 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9527 data[0], data[1], data[2]);
9528
9529 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false)
9530 {
9531 DLOG("Failed to update nvram boot-args\n");
9532 goto exit;
9533 }
9534
9535exit:
9536
9537 gRootDomain->swd_lock = 0;
9538
9539 if (wdogTrigger) {
9540 IOLog("Restarting to collect Sleep wake debug logs\n");
9541 PEHaltRestart(kPERestartCPU);
9542 }
9543 else {
9544 logBufMap = sleepWakeDebugRetrieve();
9545 if (logBufMap) {
9546 sleepWakeDebugDumpFromMem(logBufMap);
9547 logBufMap->release();
9548 logBufMap = 0;
9549 }
9550 }
9551}
9552
9553void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9554{
9555 vm_size_t size = SWD_BUF_SIZE;
9556
9557 swd_hdr *hdr = NULL;
9558
9559 IOBufferMemoryDescriptor *memDesc = NULL;
9560
9561
9562 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9563 return;
9564
9565 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9566 return;
9567
9568 // Try allocating above 4GB. If that fails, try at 2GB
9569 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9570 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9571 size, 0xFFFFFFFF00000000ULL);
9572 if (!memDesc) {
9573 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9574 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9575 size, 0xFFFFFFFF10000000ULL);
9576 }
9577
9578 if (memDesc == NULL)
9579 {
9580 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9581 goto exit;
9582 }
9583
9584
9585 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9586 memset(hdr, 0, sizeof(swd_hdr));
9587
9588 hdr->signature = SWD_HDR_SIGNATURE;
9589 hdr->alloc_size = size;
9590
9591 hdr->spindump_offset = sizeof(swd_hdr);
9592 swd_buffer = (void *)hdr;
9593 swd_memDesc = memDesc;
9594 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
9595
9596exit:
9597 gRootDomain->swd_lock = 0;
9598}
9599
9600void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9601{
9602 vm_size_t size = SWD_SPINDUMP_SIZE;
9603
9604 swd_hdr *hdr = NULL;
9605
9606 IOBufferMemoryDescriptor *memDesc = NULL;
9607
9608 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9609 return;
9610
9611 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
9612 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
9613 SWD_SPINDUMP_SIZE);
9614
9615 if (memDesc == NULL)
9616 {
9617 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9618 goto exit;
9619 }
9620
9621
9622 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9623 memset(hdr, 0, sizeof(swd_hdr));
9624
9625 hdr->signature = SWD_HDR_SIGNATURE;
9626 hdr->alloc_size = size;
9627
9628 hdr->spindump_offset = sizeof(swd_hdr);
9629 swd_spindump_buffer = (void *)hdr;
9630
9631exit:
9632 gRootDomain->swd_lock = 0;
9633}
9634
9635void IOPMrootDomain::sleepWakeDebugEnableWdog()
9636{
9637 swd_flags |= SWD_WDOG_ENABLED;
9638 if (!swd_buffer)
9639 sleepWakeDebugMemAlloc();
9640}
9641
9642bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9643{
9644 return ((swd_flags & SWD_WDOG_ENABLED) &&
9645 !systemBooting && !systemShutdown && !gWillShutdown);
9646}
9647
9648void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9649{
9650 swd_hdr *hdr = NULL;
9651 errno_t error = EIO;
9652
9653 if (swd_spindump_buffer && gSpinDumpBufferFull) {
9654 hdr = (swd_hdr *)swd_spindump_buffer;
9655
9656 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9657 (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
9658
9659 if (error) return;
9660
9661 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9662 (char*)hdr+offsetof(swd_hdr, UUID),
9663 sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
9664
9665 gSpinDumpBufferFull = false;
9666 }
9667}
9668
9669errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9670{
9671 struct vnode *vp = NULL;
9672 vfs_context_t ctx = vfs_context_create(vfs_context_current());
9673 kauth_cred_t cred = vfs_context_ucred(ctx);
9674 struct vnode_attr va;
9675 errno_t error = EIO;
9676
9677 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
9678 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9679 {
9680 IOLog("Failed to open the file %s\n", name);
9681 swd_flags |= SWD_FILEOP_ERROR;
9682 goto exit;
9683 }
9684 VATTR_INIT(&va);
9685 VATTR_WANTED(&va, va_nlink);
9686 /* Don't dump to non-regular files or files with links. */
9687 if (vp->v_type != VREG ||
9688 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9689 IOLog("Bailing as this is not a regular file\n");
9690 swd_flags |= SWD_FILEOP_ERROR;
9691 goto exit;
9692 }
9693 VATTR_INIT(&va);
9694 VATTR_SET(&va, va_data_size, 0);
9695 vnode_setattr(vp, &va, ctx);
9696
9697
9698 if (buf != NULL) {
9699 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
9700 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx));
9701 if (error != 0) {
9702 IOLog("Failed to save sleep wake log. err 0x%x\n", error);
9703 swd_flags |= SWD_FILEOP_ERROR;
9704 }
9705 else {
9706 DLOG("Saved %d bytes to file %s\n",len, name);
9707 }
9708 }
9709
9710exit:
9711 if (vp) vnode_close(vp, FWRITE, ctx);
9712 if (ctx) vfs_context_rele(ctx);
9713
9714 return error;
9715
9716}
9717
9718errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
9719 struct vnode *srcVp,
9720 vfs_context_t srcCtx,
9721 char *tmpBuf, uint64_t tmpBufSize,
9722 uint64_t srcOffset,
9723 const char *dstFname,
9724 uint64_t numBytes,
9725 uint32_t crc)
9726{
9727 struct vnode *vp = NULL;
9728 vfs_context_t ctx = vfs_context_create(vfs_context_current());
9729 struct vnode_attr va;
9730 errno_t error = EIO;
9731 uint64_t bytesToRead, bytesToWrite;
9732 uint64_t readFileOffset, writeFileOffset, srcDataOffset;
9733 uint32_t newcrc = 0;
9734
9735 if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW),
9736 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9737 {
9738 IOLog("Failed to open the file %s\n", dstFname);
9739 swd_flags |= SWD_FILEOP_ERROR;
9740 goto exit;
9741 }
9742 VATTR_INIT(&va);
9743 VATTR_WANTED(&va, va_nlink);
9744 /* Don't dump to non-regular files or files with links. */
9745 if (vp->v_type != VREG ||
9746 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9747 IOLog("Bailing as this is not a regular file\n");
9748 swd_flags |= SWD_FILEOP_ERROR;
9749 goto exit;
9750 }
9751 VATTR_INIT(&va);
9752 VATTR_SET(&va, va_data_size, 0);
9753 vnode_setattr(vp, &va, ctx);
9754
9755 writeFileOffset = 0;
9756 while(numBytes) {
9757 bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
9758 readFileOffset = trunc_page(srcOffset);
9759
9760 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead, readFileOffset);
9761 error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
9762 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9763 vfs_context_ucred(srcCtx), (int *) 0,
9764 vfs_context_proc(srcCtx));
9765 if (error) {
9766 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
9767 swd_flags |= SWD_FILEOP_ERROR;
9768 break;
9769 }
9770
9771 srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset);
9772 bytesToWrite = bytesToRead - (srcOffset - readFileOffset);
9773 if (bytesToWrite > numBytes) bytesToWrite = numBytes;
9774
9775 if (crc) {
9776 newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
9777 }
9778 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite, writeFileOffset);
9779 error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
9780 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
9781 vfs_context_ucred(ctx), (int *) 0,
9782 vfs_context_proc(ctx));
9783 if (error) {
9784 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
9785 swd_flags |= SWD_FILEOP_ERROR;
9786 break;
9787 }
9788
9789 writeFileOffset += bytesToWrite;
9790 numBytes -= bytesToWrite;
9791 srcOffset += bytesToWrite;
9792
9793 }
9794 if (crc != newcrc) {
9795 /* Set stackshot size to 0 if crc doesn't match */
9796 VATTR_INIT(&va);
9797 VATTR_SET(&va, va_data_size, 0);
9798 vnode_setattr(vp, &va, ctx);
9799
9800 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
9801 swd_flags |= SWD_DATA_CRC_ERROR;
9802 error = EFAULT;
9803 }
9804exit:
9805 if (vp) {
9806 error = vnode_close(vp, FWRITE, ctx);
9807 DLOG("vnode_close on file %s returned 0x%x\n",dstFname, error);
9808 }
9809 if (ctx) vfs_context_rele(ctx);
9810
9811 return error;
9812
9813
9814
9815}
9816uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname, vfs_context_t *ctx,
9817 void *tmpBuf, struct vnode **vp)
9818{
9819 int rc;
9820 uint64_t hdrOffset;
9821 uint32_t error = 0;
9822
9823 struct vnode_attr va;
9824 IOHibernateImageHeader *imageHdr;
9825
9826 *vp = NULL;
9827 if (vnode_open(fname, (FREAD | O_NOFOLLOW), 0,
9828 VNODE_LOOKUP_NOFOLLOW, vp, *ctx) != 0)
9829 {
9830 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname);
9831 goto err;
9832 }
9833 VATTR_INIT(&va);
9834 VATTR_WANTED(&va, va_nlink);
9835 VATTR_WANTED(&va, va_data_alloc);
9836 if ((*vp)->v_type != VREG ||
9837 vnode_getattr((*vp), &va, *ctx) || va.va_nlink != 1) {
9838 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname);
9839 error = SWD_FILEOP_ERROR;
9840 goto err;
9841 }
9842
9843 /* Read the sleepimage file header */
9844 rc = vn_rdwr(UIO_READ, *vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
9845 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9846 vfs_context_ucred(*ctx), (int *) 0,
9847 vfs_context_proc(*ctx));
9848 if (rc != 0) {
9849 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9850 round_page(sizeof(IOHibernateImageHeader)), rc, fname);
9851 error = SWD_FILEOP_ERROR;
9852 goto err;
9853 }
9854
9855 imageHdr = ((IOHibernateImageHeader *)tmpBuf);
9856 if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
9857 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9858 fname, imageHdr->signature);
9859 error = SWD_HDR_SIGNATURE_ERROR;
9860 goto err;
9861 }
9862
9863 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9864 hdrOffset = imageHdr->deviceBlockSize;
9865 if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
9866 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9867 va.va_data_alloc, fname);
9868 error = SWD_HDR_SIZE_ERROR;
9869 goto err;
9870 }
9871
9872 return 0;
9873
9874err:
9875 if (*vp) vnode_close(*vp, FREAD, *ctx);
9876 *vp = NULL;
9877
9878 return error;
9879}
9880
9881void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9882{
9883#if HIBERNATION
9884 int rc;
9885 char hibernateFilename[MAXPATHLEN+1];
9886 void *tmpBuf;
9887 swd_hdr *hdr = NULL;
9888 uint32_t stacksSize, logSize;
9889 uint64_t tmpBufSize;
9890 uint64_t hdrOffset, stacksOffset, logOffset;
9891 errno_t error = EIO;
9892 OSObject *obj = NULL;
9893 OSString *str = NULL;
9894 OSNumber *failStat = NULL;
9895 struct vnode *vp = NULL;
9896 vfs_context_t ctx = NULL;
9897 const char *stacksFname, *logFname;
9898
9899 IOBufferMemoryDescriptor *tmpBufDesc = NULL;
9900
9901 DLOG("sleepWakeDebugDumpFromFile\n");
9902 if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
9903 return;
9904
9905 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9906 return;
9907
9908
9909 /* Allocate a temp buffer to copy data between files */
9910 tmpBufSize = 2*4096;
9911 tmpBufDesc = IOBufferMemoryDescriptor::
9912 inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone,
9913 tmpBufSize, PAGE_SIZE);
9914
9915 if (!tmpBufDesc) {
9916 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9917 goto exit;
9918 }
9919
9920 tmpBuf = tmpBufDesc->getBytesNoCopy();
9921
9922 ctx = vfs_context_create(vfs_context_current());
9923
9924 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9925 swd_flags |= checkForValidDebugData(kSleepWakeStackBinFilename, &ctx, tmpBuf, &vp);
9926 if (vp == NULL) {
9927 /* Check if the debug data is saved to hibernation file */
9928 hibernateFilename[0] = 0;
9929 if ((obj = copyProperty(kIOHibernateFileKey)))
9930 {
9931 if ((str = OSDynamicCast(OSString, obj)))
9932 strlcpy(hibernateFilename, str->getCStringNoCopy(),
9933 sizeof(hibernateFilename));
9934 obj->release();
9935 }
9936 if (!hibernateFilename[0]) {
9937 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9938 goto exit;
9939 }
9940
9941 swd_flags |= checkForValidDebugData(hibernateFilename, &ctx, tmpBuf, &vp);
9942 if (vp == NULL) {
9943 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9944 goto exit;
9945 }
9946 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename);
9947 }
9948 else {
9949 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename);
9950 }
9951
9952 hdrOffset = ((IOHibernateImageHeader *)tmpBuf)->deviceBlockSize;
9953
9954 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
9955 /* Read the sleep/wake debug header(swd_hdr) */
9956 rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
9957 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9958 vfs_context_ucred(ctx), (int *) 0,
9959 vfs_context_proc(ctx));
9960 if (rc != 0) {
9961 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9962 round_page(sizeof(swd_hdr)), rc);
9963 swd_flags |= SWD_FILEOP_ERROR;
9964 goto exit;
9965 }
9966
9967 hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset)));
9968 if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) ||
9969 (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
9970 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9971 hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
9972 swd_flags |= SWD_BUF_SIZE_ERROR;
9973 goto exit;
9974 }
9975 stacksSize = hdr->spindump_size;
9976
9977 /* Get stacks & log offsets in the image file */
9978 stacksOffset = hdrOffset + hdr->spindump_offset;
9979 logOffset = hdrOffset + offsetof(swd_hdr, UUID);
9980 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9981 stacksFname = getDumpStackFilename(hdr);
9982 logFname = getDumpLogFilename(hdr);
9983
9984 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
9985 stacksFname, stacksSize, hdr->crc);
9986 if (error == EFAULT) {
9987 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9988 goto exit;
9989 }
9990 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset,
9991 logFname, logSize, 0);
9992 if (error) {
9993 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
9994 goto exit;
9995 }
9996exit:
9997 if (error) {
9998 // Write just the SleepWakeLog.dump with failure code
9999 uint64_t fcode = 0;
10000 const char *fname;
10001 swd_hdr hdrCopy;
10002 char *offset = NULL;
10003 int size;
10004
10005 hdr = &hdrCopy;
10006 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
10007 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
10008 fcode = failStat->unsigned64BitValue();
10009 fname = kSleepWakeLogFilename;
10010 }
10011 else {
10012 fname = kAppleOSXWatchdogLogFilename;
10013 }
10014
10015 offset = (char*)hdr+offsetof(swd_hdr, UUID);
10016 size = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
10017 memset(offset, 0x20, size); // Fill with spaces
10018
10019
10020 snprintf(hdr->spindump_status, sizeof(hdr->spindump_status), "\nstatus: 0x%x", swd_flags);
10021 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: 0x%llx", fcode);
10022 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
10023 sleepWakeDebugSaveFile(fname, offset, size);
10024
10025 }
10026 gRootDomain->swd_lock = 0;
10027
10028 if (vp) vnode_close(vp, FREAD, ctx);
10029 if (ctx) vfs_context_rele(ctx);
10030 if (tmpBufDesc) tmpBufDesc->release();
10031#endif /* HIBERNATION */
10032}
10033
10034void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
10035{
10036 IOVirtualAddress srcBuf = NULL;
10037 char *stackBuf = NULL, *logOffset = NULL;
10038 int logSize = 0;
10039
10040 errno_t error = EIO;
10041 uint64_t bufSize = 0;
10042 swd_hdr *hdr = NULL;
10043 OSNumber *failStat = NULL;
10044
10045 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10046 return;
10047
10048 if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) )
10049 {
10050 DLOG("Nothing saved to dump to file\n");
10051 goto exit;
10052 }
10053
10054 hdr = (swd_hdr *)srcBuf;
10055 bufSize = logBufMap->getLength();
10056 if (bufSize <= sizeof(swd_hdr))
10057 {
10058 IOLog("SleepWake log buffer size is invalid\n");
10059 swd_flags |= SWD_BUF_SIZE_ERROR;
10060 goto exit;
10061 }
10062
10063 stackBuf = (char*)hdr+hdr->spindump_offset;
10064
10065 error = sleepWakeDebugSaveFile(getDumpStackFilename(hdr), stackBuf, hdr->spindump_size);
10066 if (error) goto exit;
10067
10068 logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
10069 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
10070
10071 error = sleepWakeDebugSaveFile(getDumpLogFilename(hdr), logOffset, logSize);
10072 if (error) goto exit;
10073
10074 hdr->spindump_size = 0;
10075 error = 0;
10076
10077exit:
10078 if (error) {
10079 // Write just the SleepWakeLog.dump with failure code
10080 uint64_t fcode = 0;
10081 const char *sname, *lname;
10082 swd_hdr hdrCopy;
10083
10084 /* Try writing an empty stacks file */
10085 hdr = &hdrCopy;
10086 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
10087 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
10088 fcode = failStat->unsigned64BitValue();
10089 lname = kSleepWakeLogFilename;
10090 sname = kSleepWakeStackFilename;
10091 }
10092 else {
10093 lname = kAppleOSXWatchdogLogFilename;
10094 sname= kAppleOSXWatchdogStackFilename;
10095 }
10096
10097 sleepWakeDebugSaveFile(sname, NULL, 0);
10098
10099 logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
10100 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
10101 memset(logOffset, 0x20, logSize); // Fill with spaces
10102
10103
10104 snprintf(hdr->spindump_status, sizeof(hdr->spindump_status), "\nstatus: 0x%x", swd_flags);
10105 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: 0x%llx", fcode);
10106 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
10107 sleepWakeDebugSaveFile(lname, logOffset, logSize);
10108 }
10109
10110 gRootDomain->swd_lock = 0;
10111}
10112
10113IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
10114{
10115 IOVirtualAddress vaddr = NULL;
10116 IOMemoryDescriptor * desc = NULL;
10117 IOMemoryMap * logBufMap = NULL;
10118
10119 uint32_t len = INT_MAX;
10120 addr64_t data[3];
10121 uint64_t bufSize = 0;
10122 uint64_t crc = 0;
10123 uint64_t newcrc = 0;
10124 uint64_t paddr = 0;
10125 swd_hdr *hdr = NULL;
10126 bool ret = false;
10127 char str[20];
10128
10129
10130 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10131 return NULL;
10132
10133 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, 0, &len)) {
10134 DLOG("No sleepWakeDebug note to read\n");
10135 goto exit;
10136 }
10137
10138 if (len == strlen("sleepimage")) {
10139 str[0] = 0;
10140 PEReadNVRAMProperty(kIOSleepWakeDebugKey, str, &len);
10141
10142 if (!strncmp((char*)str, "sleepimage", strlen("sleepimage"))) {
10143 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10144 swd_flags |= SWD_LOGS_IN_FILE|SWD_VALID_LOGS;
10145 goto exit;
10146 }
10147 }
10148 else if (len == sizeof(addr64_t)*3) {
10149 PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len);
10150 }
10151 else {
10152 DLOG("Invalid sleepWakeDebug note length(%d)\n", len);
10153 goto exit;
10154 }
10155
10156
10157
10158 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10159 data[0], data[1], data[2]);
10160 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10161 bufSize = data[0];
10162 crc = data[1];
10163 paddr = data[2];
10164 if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
10165 {
10166 IOLog("SleepWake log buffer size is invalid\n");
10167 swd_flags |= SWD_BUF_SIZE_ERROR;
10168 return NULL;
10169 }
10170
10171 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10172 bufSize, crc, paddr);
10173
10174
10175 desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize,
10176 kIODirectionOutIn | kIOMemoryMapperNone, NULL);
10177 if (desc == NULL)
10178 {
10179 IOLog("Fail to map SleepWake log buffer\n");
10180 swd_flags |= SWD_INTERNAL_FAILURE;
10181 goto exit;
10182 }
10183
10184 logBufMap = desc->map();
10185
10186 vaddr = logBufMap->getVirtualAddress();
10187
10188
10189 if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
10190 IOLog("Fail to map SleepWake log buffer\n");
10191 swd_flags |= SWD_INTERNAL_FAILURE;
10192 goto exit;
10193 }
10194
10195 hdr = (swd_hdr *)vaddr;
10196 if (hdr->spindump_offset+hdr->spindump_size > bufSize)
10197 {
10198 IOLog("SleepWake log header size is invalid\n");
10199 swd_flags |= SWD_HDR_SIZE_ERROR;
10200 goto exit;
10201 }
10202
10203 hdr->crc = crc;
10204 newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset),
10205 hdr->spindump_size);
10206 if (newcrc != crc) {
10207 IOLog("SleepWake log buffer contents are invalid\n");
10208 swd_flags |= SWD_DATA_CRC_ERROR;
10209 goto exit;
10210 }
10211
10212 ret = true;
10213 swd_flags |= SWD_LOGS_IN_MEM | SWD_VALID_LOGS;
10214
10215
10216exit:
10217 PERemoveNVRAMProperty(kIOSleepWakeDebugKey);
10218 if (!ret) {
10219 if (logBufMap) logBufMap->release();
10220 logBufMap = 0;
10221 }
10222 if (desc) desc->release();
10223 gRootDomain->swd_lock = 0;
10224
10225 return logBufMap;
10226}
10227
10228#else
10229
10230void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
10231{
10232 uint32_t wdog_panic = 1;
10233
10234 if (restart) {
10235 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
10236 (wdog_panic == 0)) {
10237 return;
10238 }
10239 panic("Sleep/Wake hang detected\n");
10240 return;
10241 }
10242}
10243
10244void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
10245{
10246#pragma unused(restart)
10247#pragma unused(isOSXWatchdog)
10248}
10249
10250void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10251{
10252}
10253void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *map)
10254{
10255}
10256errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
10257 struct vnode *srcVp,
10258 vfs_context_t srcCtx,
10259 char *tmpBuf, uint64_t tmpBufSize,
10260 uint64_t srcOffset,
10261 const char *dstFname,
10262 uint64_t numBytes,
10263 uint32_t crc)
10264{
10265 return EIO;
10266}
10267
10268void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10269{
10270}
10271
10272IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
10273{
10274 return NULL;
10275}
10276
10277void IOPMrootDomain::sleepWakeDebugEnableWdog()
10278{
10279}
10280
10281bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10282{
10283 return false;
10284}
10285
10286errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
10287{
10288 return 0;
10289}
10290
10291#endif
10292