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