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