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