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