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