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