]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
f2015f3868faf2a60cfed296ca262be3a16b004c
[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 #if HIBERNATION
5025 gIOHibernateState = 0;
5026 #endif
5027
5028 // Record the reason for dark wake back to sleep
5029 // System may not have ever achieved full wake
5030
5031 publishSleepReason = true;
5032 lastSleepReason = sleepReason;
5033 if (sleepDelaysReport) {
5034 clock_get_uptime(&ts_sleepStart);
5035 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
5036 }
5037 }
5038
5039 // 3. System wake.
5040
5041 else if (kSystemTransitionWake == _systemTransitionType)
5042 {
5043 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
5044 // Clear stats about sleep
5045
5046 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5047 {
5048 willEnterFullWake();
5049 }
5050 else
5051 {
5052 // Message powerd only
5053 _systemMessageClientMask = kSystemMessageClientPowerd;
5054 tellClients(kIOMessageSystemWillPowerOn);
5055 }
5056 }
5057
5058 // The only location where the sleep reason is published. At this point
5059 // sleep can still be cancelled, but sleep reason should be published
5060 // early for logging purposes.
5061
5062 if (publishSleepReason)
5063 {
5064 static const char * IOPMSleepReasons[] =
5065 {
5066 kIOPMClamshellSleepKey,
5067 kIOPMPowerButtonSleepKey,
5068 kIOPMSoftwareSleepKey,
5069 kIOPMOSSwitchHibernationKey,
5070 kIOPMIdleSleepKey,
5071 kIOPMLowPowerSleepKey,
5072 kIOPMThermalEmergencySleepKey,
5073 kIOPMMaintenanceSleepKey,
5074 kIOPMSleepServiceExitKey,
5075 kIOPMDarkWakeThermalEmergencyKey
5076 };
5077
5078 // Record sleep cause in IORegistry
5079 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
5080 if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
5081 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
5082 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
5083 }
5084 }
5085
5086 if ((kSystemTransitionNone != _systemTransitionType) &&
5087 (kSystemTransitionNewCapClient != _systemTransitionType))
5088 {
5089 _systemStateGeneration++;
5090 systemDarkWake = false;
5091
5092 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5093 "dcp %x:%x:%x\n",
5094 currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
5095 _systemTransitionType, _systemStateGeneration,
5096 _systemMessageClientMask,
5097 _desiredCapability, _currentCapability, _pendingCapability);
5098 }
5099 }
5100
5101 void IOPMrootDomain::handleOurPowerChangeDone(
5102 IOService * service,
5103 IOPMActions * actions,
5104 IOPMPowerStateIndex powerState,
5105 IOPMPowerChangeFlags changeFlags,
5106 IOPMRequestTag requestTag __unused )
5107 {
5108 if (kSystemTransitionNewCapClient == _systemTransitionType)
5109 {
5110 _systemTransitionType = kSystemTransitionNone;
5111 return;
5112 }
5113
5114 if (_systemTransitionType != kSystemTransitionNone)
5115 {
5116 uint32_t currentPowerState = (uint32_t) getPowerState();
5117
5118 if (changeFlags & kIOPMNotDone)
5119 {
5120 // Power down was cancelled or vetoed.
5121 _pendingCapability = _currentCapability;
5122 lastSleepReason = 0;
5123
5124 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
5125 CAP_CURRENT(kIOPMSystemCapabilityCPU))
5126 {
5127 pmPowerStateQueue->submitPowerEvent(
5128 kPowerEventPolicyStimulus,
5129 (void *) kStimulusDarkWakeReentry,
5130 _systemStateGeneration );
5131 }
5132
5133 // Revert device desire to max.
5134 changePowerStateToPriv(ON_STATE);
5135 }
5136 else
5137 {
5138 // Send message on dark wake to full wake promotion.
5139 // tellChangeUp() handles the normal SLEEP->ON case.
5140
5141 if (kSystemTransitionCapability == _systemTransitionType)
5142 {
5143 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5144 {
5145 lastSleepReason = 0; // stop logging wrangler tickles
5146 tellClients(kIOMessageSystemHasPoweredOn);
5147 }
5148 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
5149 {
5150 // Going dark, reset full wake state
5151 // userIsActive will be cleared by wrangler powering down
5152 wranglerTickled = false;
5153 fullWakeReason = kFullWakeReasonNone;
5154
5155 if (ts_sleepStart) {
5156 clock_get_uptime(&wake2DarkwakeDelay);
5157 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
5158 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
5159 ts_sleepStart = 0;
5160 }
5161 }
5162 }
5163
5164 // Reset state after exiting from dark wake.
5165
5166 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
5167 CAP_LOSS(kIOPMSystemCapabilityCPU))
5168 {
5169 darkWakeMaintenance = false;
5170 darkWakeToSleepASAP = false;
5171 pciCantSleepValid = false;
5172 darkWakeSleepService = false;
5173
5174 if (CAP_LOSS(kIOPMSystemCapabilityCPU))
5175 {
5176 // Remove the influence of display power assertion
5177 // before next system wake.
5178 if (wrangler) wrangler->changePowerStateForRootDomain(
5179 kWranglerPowerStateMin );
5180 removeProperty(gIOPMUserTriggeredFullWakeKey);
5181 }
5182 }
5183
5184 // Entered dark mode.
5185
5186 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5187 (_pendingCapability & kIOPMSystemCapabilityCPU))
5188 {
5189 // Queue an evaluation of whether to remain in dark wake,
5190 // and for how long. This serves the purpose of draining
5191 // any assertions from the queue.
5192
5193 pmPowerStateQueue->submitPowerEvent(
5194 kPowerEventPolicyStimulus,
5195 (void *) kStimulusDarkWakeEntry,
5196 _systemStateGeneration );
5197 }
5198 }
5199
5200 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5201 "dcp %x:%x:%x, dbgtimer %u\n",
5202 currentPowerState, (uint32_t) powerState, changeFlags,
5203 _systemTransitionType, _systemStateGeneration,
5204 _systemMessageClientMask,
5205 _desiredCapability, _currentCapability, _pendingCapability,
5206 _lastDebugWakeSeconds);
5207
5208 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5209 {
5210 displayWakeCnt++;
5211 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5212 if (clamshellExists && fullWakeThreadCall &&
5213 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5214 {
5215 // Not the initial graphics full power, graphics won't
5216 // send a power notification to trigger a lid state
5217 // evaluation.
5218
5219 AbsoluteTime deadline;
5220 clock_interval_to_deadline(45, kSecondScale, &deadline);
5221 thread_call_enter_delayed(fullWakeThreadCall, deadline);
5222 }
5223 #endif
5224 }
5225 else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
5226 darkWakeCnt++;
5227
5228 // Update current system capability.
5229 if (_currentCapability != _pendingCapability)
5230 _currentCapability = _pendingCapability;
5231
5232 // Update highest system capability.
5233
5234 _highestCapability |= _currentCapability;
5235
5236 if (darkWakePostTickle &&
5237 (kSystemTransitionWake == _systemTransitionType) &&
5238 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5239 kDarkWakeFlagHIDTickleLate)
5240 {
5241 darkWakePostTickle = false;
5242 reportUserInput();
5243 }
5244
5245 // Reset tracepoint at completion of capability change,
5246 // completion of wake transition, and aborted sleep transition.
5247
5248 if ((_systemTransitionType == kSystemTransitionCapability) ||
5249 (_systemTransitionType == kSystemTransitionWake) ||
5250 ((_systemTransitionType == kSystemTransitionSleep) &&
5251 (changeFlags & kIOPMNotDone)))
5252 {
5253 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
5254 tracePoint( kIOPMTracePointSystemUp );
5255 }
5256
5257 _systemTransitionType = kSystemTransitionNone;
5258 _systemMessageClientMask = 0;
5259 toldPowerdCapWillChange = false;
5260
5261 logGraphicsClamp = false;
5262
5263 if (lowBatteryCondition) {
5264 privateSleepSystem (kIOPMSleepReasonLowPower);
5265 }
5266 else if ((fullWakeReason == kFullWakeReasonDisplayOn) && (!displayPowerOnRequested)) {
5267 // Request for full wake is removed while system is waking up to full wake
5268 DLOG("DisplayOn fullwake request is removed\n");
5269 handleDisplayPowerOn();
5270 }
5271
5272 }
5273 }
5274
5275 //******************************************************************************
5276 // PM actions for graphics and audio.
5277 //******************************************************************************
5278
5279 void IOPMrootDomain::overridePowerChangeForUIService(
5280 IOService * service,
5281 IOPMActions * actions,
5282 IOPMPowerStateIndex * inOutPowerState,
5283 IOPMPowerChangeFlags * inOutChangeFlags )
5284 {
5285 uint32_t powerState = (uint32_t) *inOutPowerState;
5286 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
5287
5288 if (kSystemTransitionNone == _systemTransitionType)
5289 {
5290 // Not in midst of a system transition.
5291 // Do not modify power limit enable state.
5292 }
5293 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5294 {
5295 // Activate power limiter.
5296
5297 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5298 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5299 (changeFlags & kIOPMSynchronize))
5300 {
5301 actions->parameter |= kPMActionsFlagLimitPower;
5302 }
5303 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5304 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
5305 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
5306 (changeFlags & kIOPMSynchronize))
5307 {
5308 actions->parameter |= kPMActionsFlagLimitPower;
5309 }
5310 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
5311 (_systemTransitionType == kSystemTransitionSleep))
5312 {
5313 // For graphics devices, arm the limiter when entering
5314 // system sleep. Not when dropping to dark wake.
5315 actions->parameter |= kPMActionsFlagLimitPower;
5316 }
5317
5318 if (actions->parameter & kPMActionsFlagLimitPower)
5319 {
5320 DLOG("+ plimit %s %p\n",
5321 service->getName(), OBFUSCATE(service));
5322 }
5323 }
5324 else
5325 {
5326 // Remove power limit.
5327
5328 if ((actions->parameter & (
5329 kPMActionsFlagIsDisplayWrangler |
5330 kPMActionsFlagIsGraphicsDevice )) &&
5331 (_pendingCapability & kIOPMSystemCapabilityGraphics))
5332 {
5333 actions->parameter &= ~kPMActionsFlagLimitPower;
5334 }
5335 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5336 (_pendingCapability & kIOPMSystemCapabilityAudio))
5337 {
5338 actions->parameter &= ~kPMActionsFlagLimitPower;
5339 }
5340
5341 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5342 {
5343 DLOG("- plimit %s %p\n",
5344 service->getName(), OBFUSCATE(service));
5345 }
5346 }
5347
5348 if (actions->parameter & kPMActionsFlagLimitPower)
5349 {
5350 uint32_t maxPowerState = (uint32_t)(-1);
5351
5352 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
5353 {
5354 // Enforce limit for system power/cap transitions.
5355
5356 maxPowerState = 0;
5357 if ((service->getPowerState() > maxPowerState) &&
5358 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
5359 {
5360 maxPowerState++;
5361
5362 // Remove lingering effects of any tickle before entering
5363 // dark wake. It will take a new tickle to return to full
5364 // wake, so the existing tickle state is useless.
5365
5366 if (changeFlags & kIOPMDomainDidChange)
5367 *inOutChangeFlags |= kIOPMExpireIdleTimer;
5368 }
5369 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
5370 {
5371 maxPowerState++;
5372 }
5373 }
5374 else
5375 {
5376 // Deny all self-initiated changes when power is limited.
5377 // Wrangler tickle should never defeat the limiter.
5378
5379 maxPowerState = service->getPowerState();
5380 }
5381
5382 if (powerState > maxPowerState)
5383 {
5384 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5385 service->getName(), OBFUSCATE(service), powerState, maxPowerState,
5386 changeFlags);
5387 *inOutPowerState = maxPowerState;
5388
5389 if (darkWakePostTickle &&
5390 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5391 (changeFlags & kIOPMDomainWillChange) &&
5392 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5393 kDarkWakeFlagHIDTickleEarly))
5394 {
5395 darkWakePostTickle = false;
5396 reportUserInput();
5397 }
5398 }
5399
5400 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
5401 {
5402 if (logGraphicsClamp)
5403 {
5404 AbsoluteTime now;
5405 uint64_t nsec;
5406
5407 clock_get_uptime(&now);
5408 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
5409 absolutetime_to_nanoseconds(now, &nsec);
5410 if (kIOLogPMRootDomain & gIOKitDebug)
5411 MSG("Graphics suppressed %u ms\n",
5412 ((int)((nsec) / 1000000ULL)));
5413 }
5414 graphicsSuppressed = true;
5415 }
5416 }
5417 }
5418
5419 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5420 IOService * service,
5421 IOPMActions * actions )
5422 {
5423 #if !NO_KERNEL_HID
5424 // Warning: Not running in PM work loop context - don't modify state !!!
5425 // Trap tickle directed to IODisplayWrangler while running with graphics
5426 // capability suppressed.
5427
5428 assert(service == wrangler);
5429
5430 clock_get_uptime(&userActivityTime);
5431 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
5432 || (lastSleepReason == kIOPMSleepReasonMaintenance)
5433 || (lastSleepReason == kIOPMSleepReasonSoftware));
5434 if (aborting) {
5435 userActivityCount++;
5436 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5437 userActivityCount, lastSleepReason);
5438 }
5439
5440 if (!wranglerTickled &&
5441 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
5442 {
5443 DLOG("display wrangler tickled\n");
5444 if (kIOLogPMRootDomain & gIOKitDebug)
5445 OSReportWithBacktrace("Dark wake display tickle");
5446 if (pmPowerStateQueue)
5447 {
5448 pmPowerStateQueue->submitPowerEvent(
5449 kPowerEventPolicyStimulus,
5450 (void *) kStimulusDarkWakeActivityTickle,
5451 true /* set wake type */ );
5452 }
5453 }
5454 #endif
5455 }
5456
5457 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5458 IOService * service,
5459 IOPMActions * actions,
5460 const OSSymbol * powerClient,
5461 IOPMPowerStateIndex oldPowerState,
5462 IOPMPowerStateIndex newPowerState )
5463 {
5464 #if !NO_KERNEL_HID
5465 assert(service == wrangler);
5466
5467 // This function implements half of the user active detection
5468 // by monitoring changes to the display wrangler's device desire.
5469 //
5470 // User becomes active when either:
5471 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5472 // in max power state. This desire change in absence of a power state
5473 // change is detected within. This handles the case when user becomes
5474 // active while the display is already lit by setDisplayPowerOn().
5475 //
5476 // 2. Power state change to max, and DeviceDesire is also at max.
5477 // Handled by displayWranglerNotification().
5478 //
5479 // User becomes inactive when DeviceDesire drops to sleep state or below.
5480
5481 DLOG("wrangler %s (ps %u, %u->%u)\n",
5482 powerClient->getCStringNoCopy(),
5483 (uint32_t) service->getPowerState(),
5484 (uint32_t) oldPowerState, (uint32_t) newPowerState);
5485
5486 if (powerClient == gIOPMPowerClientDevice)
5487 {
5488 if ((newPowerState > oldPowerState) &&
5489 (newPowerState == kWranglerPowerStateMax) &&
5490 (service->getPowerState() == kWranglerPowerStateMax))
5491 {
5492 evaluatePolicy( kStimulusEnterUserActiveState );
5493 }
5494 else
5495 if ((newPowerState < oldPowerState) &&
5496 (newPowerState <= kWranglerPowerStateSleep))
5497 {
5498 evaluatePolicy( kStimulusLeaveUserActiveState );
5499 }
5500 }
5501
5502 if (newPowerState <= kWranglerPowerStateSleep) {
5503 evaluatePolicy( kStimulusDisplayWranglerSleep );
5504 }
5505 else if (newPowerState == kWranglerPowerStateMax) {
5506 evaluatePolicy( kStimulusDisplayWranglerWake );
5507 }
5508 #endif
5509 }
5510
5511 //******************************************************************************
5512 // User active state management
5513 //******************************************************************************
5514
5515 void IOPMrootDomain::preventTransitionToUserActive( bool prevent )
5516 {
5517 #if !NO_KERNEL_HID
5518 _preventUserActive = prevent;
5519 if (wrangler && !_preventUserActive)
5520 {
5521 // Allowing transition to user active, but the wrangler may have
5522 // already powered ON in case of sleep cancel/revert. Poll the
5523 // same conditions checked for in displayWranglerNotification()
5524 // to bring the user active state up to date.
5525
5526 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
5527 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
5528 kWranglerPowerStateMax))
5529 {
5530 evaluatePolicy( kStimulusEnterUserActiveState );
5531 }
5532 }
5533 #endif
5534 }
5535
5536 //******************************************************************************
5537 // Approve usage of delayed child notification by PM.
5538 //******************************************************************************
5539
5540 bool IOPMrootDomain::shouldDelayChildNotification(
5541 IOService * service )
5542 {
5543 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
5544 (kFullWakeReasonNone == fullWakeReason) &&
5545 (kSystemTransitionWake == _systemTransitionType))
5546 {
5547 DLOG("%s: delay child notify\n", service->getName());
5548 return true;
5549 }
5550 return false;
5551 }
5552
5553 //******************************************************************************
5554 // PM actions for PCI device.
5555 //******************************************************************************
5556
5557 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5558 IOService * service,
5559 IOPMActions * actions,
5560 IOPMPowerStateIndex powerState,
5561 IOPMPowerChangeFlags * inOutChangeFlags )
5562 {
5563 pmTracer->tracePCIPowerChange(
5564 PMTraceWorker::kPowerChangeStart,
5565 service, *inOutChangeFlags,
5566 (actions->parameter & kPMActionsPCIBitNumberMask));
5567 }
5568
5569 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5570 IOService * service,
5571 IOPMActions * actions,
5572 IOPMPowerStateIndex powerState,
5573 IOPMPowerChangeFlags changeFlags )
5574 {
5575 pmTracer->tracePCIPowerChange(
5576 PMTraceWorker::kPowerChangeCompleted,
5577 service, changeFlags,
5578 (actions->parameter & kPMActionsPCIBitNumberMask));
5579 }
5580
5581 //******************************************************************************
5582 // registerInterest
5583 //
5584 // Override IOService::registerInterest() to intercept special clients.
5585 //******************************************************************************
5586
5587 class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
5588 {
5589
5590 friend class IOPMrootDomain;
5591 OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
5592
5593 protected:
5594 uint32_t ackTimeoutCnt;
5595 uint32_t msgType; // Message pending ack
5596
5597 };
5598
5599 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
5600
5601 IONotifier * IOPMrootDomain::registerInterest(
5602 const OSSymbol * typeOfInterest,
5603 IOServiceInterestHandler handler,
5604 void * target, void * ref )
5605 {
5606 IOPMServiceInterestNotifier *notifier = 0;
5607 bool isSystemCapabilityClient;
5608 bool isKernelCapabilityClient;
5609 IOReturn rc = kIOReturnError;;
5610
5611 isSystemCapabilityClient =
5612 typeOfInterest &&
5613 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
5614
5615 isKernelCapabilityClient =
5616 typeOfInterest &&
5617 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
5618
5619 if (isSystemCapabilityClient)
5620 typeOfInterest = gIOAppPowerStateInterest;
5621
5622 notifier = new IOPMServiceInterestNotifier;
5623 if (!notifier) return NULL;
5624
5625 if (notifier->init()) {
5626 rc = super::registerInterestForNotifer(notifier, typeOfInterest, handler, target, ref);
5627 }
5628 if (rc != kIOReturnSuccess) {
5629 notifier->release();
5630 notifier = 0;
5631
5632 return NULL;
5633 }
5634 if (pmPowerStateQueue)
5635 {
5636 notifier->ackTimeoutCnt = 0;
5637 if (isSystemCapabilityClient)
5638 {
5639 notifier->retain();
5640 if (pmPowerStateQueue->submitPowerEvent(
5641 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
5642 notifier->release();
5643 }
5644
5645 if (isKernelCapabilityClient)
5646 {
5647 notifier->retain();
5648 if (pmPowerStateQueue->submitPowerEvent(
5649 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
5650 notifier->release();
5651 }
5652 }
5653
5654 return notifier;
5655 }
5656
5657 //******************************************************************************
5658 // systemMessageFilter
5659 //
5660 //******************************************************************************
5661
5662 bool IOPMrootDomain::systemMessageFilter(
5663 void * object, void * arg1, void * arg2, void * arg3 )
5664 {
5665 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
5666 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
5667 bool isCapClient = false;
5668 bool allow = false;
5669 IOPMServiceInterestNotifier *notifier;
5670
5671 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
5672 do {
5673 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
5674 (!isCapMsg || !_joinedCapabilityClients ||
5675 !_joinedCapabilityClients->containsObject((OSObject *) object)))
5676 break;
5677
5678 // Capability change message for app and kernel clients.
5679
5680 if (isCapMsg)
5681 {
5682 if ((context->notifyType == kNotifyPriority) ||
5683 (context->notifyType == kNotifyCapabilityChangePriority))
5684 isCapClient = true;
5685
5686 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5687 (object == (void *) systemCapabilityNotifier))
5688 isCapClient = true;
5689 }
5690
5691 if (isCapClient)
5692 {
5693 IOPMSystemCapabilityChangeParameters * capArgs =
5694 (IOPMSystemCapabilityChangeParameters *) arg2;
5695
5696 if (kSystemTransitionNewCapClient == _systemTransitionType)
5697 {
5698 capArgs->fromCapabilities = 0;
5699 capArgs->toCapabilities = _currentCapability;
5700 capArgs->changeFlags = 0;
5701 }
5702 else
5703 {
5704 capArgs->fromCapabilities = _currentCapability;
5705 capArgs->toCapabilities = _pendingCapability;
5706
5707 if (context->isPreChange)
5708 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
5709 else
5710 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
5711
5712 if ((object == (void *) systemCapabilityNotifier) &&
5713 context->isPreChange)
5714 {
5715 toldPowerdCapWillChange = true;
5716 }
5717 }
5718
5719 // Capability change messages only go to the PM configd plugin.
5720 // Wait for response post-change if capabilitiy is increasing.
5721 // Wait for response pre-change if capability is decreasing.
5722
5723 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5724 ( (capabilityLoss && context->isPreChange) ||
5725 (!capabilityLoss && !context->isPreChange) ) )
5726 {
5727 // app has not replied yet, wait for it
5728 *((OSObject **) arg3) = kOSBooleanFalse;
5729
5730 if (notifier) {
5731 notifier->msgType = context->messageType;
5732 }
5733 }
5734
5735 allow = true;
5736 break;
5737 }
5738
5739 // Capability client will always see kIOMessageCanSystemSleep,
5740 // even for demand sleep. It will also have a chance to veto
5741 // sleep one last time after all clients have responded to
5742 // kIOMessageSystemWillSleep
5743
5744 if ((kIOMessageCanSystemSleep == context->messageType) ||
5745 (kIOMessageSystemWillNotSleep == context->messageType))
5746 {
5747 if (object == (OSObject *) systemCapabilityNotifier)
5748 {
5749 allow = true;
5750 if (notifier) {
5751 notifier->msgType = context->messageType;
5752 }
5753 break;
5754 }
5755
5756 // Not idle sleep, don't ask apps.
5757 if (context->changeFlags & kIOPMSkipAskPowerDown)
5758 {
5759 break;
5760 }
5761 }
5762
5763 if (kIOPMMessageLastCallBeforeSleep == context->messageType)
5764 {
5765 if ((object == (OSObject *) systemCapabilityNotifier) &&
5766 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
5767 (fullToDarkReason == kIOPMSleepReasonIdle)) {
5768 if (notifier) {
5769 notifier->msgType = context->messageType;
5770 }
5771 allow = true;
5772 }
5773 break;
5774 }
5775
5776 // Reject capability change messages for legacy clients.
5777 // Reject legacy system sleep messages for capability client.
5778
5779 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
5780 {
5781 break;
5782 }
5783
5784 // Filter system sleep messages.
5785
5786 if ((context->notifyType == kNotifyApps) &&
5787 (_systemMessageClientMask & kSystemMessageClientLegacyApp))
5788 {
5789 allow = true;
5790
5791 if (notifier) {
5792 if (arg3) {
5793 if (notifier->ackTimeoutCnt >= 3)
5794 *((OSObject **) arg3) = kOSBooleanFalse;
5795 else
5796 *((OSObject **) arg3) = kOSBooleanTrue;
5797 }
5798
5799 notifier->msgType = context->messageType;
5800 }
5801 }
5802 else if ((context->notifyType == kNotifyPriority) &&
5803 (_systemMessageClientMask & kSystemMessageClientKernel))
5804 {
5805 allow = true;
5806 }
5807 }
5808 while (false);
5809
5810 if (allow && isCapMsg && _joinedCapabilityClients)
5811 {
5812 _joinedCapabilityClients->removeObject((OSObject *) object);
5813 if (_joinedCapabilityClients->getCount() == 0)
5814 {
5815 DLOG("destroyed capability client set %p\n",
5816 OBFUSCATE(_joinedCapabilityClients));
5817 _joinedCapabilityClients->release();
5818 _joinedCapabilityClients = 0;
5819 }
5820 }
5821
5822 return allow;
5823 }
5824
5825 //******************************************************************************
5826 // setMaintenanceWakeCalendar
5827 //
5828 //******************************************************************************
5829
5830 IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
5831 const IOPMCalendarStruct * calendar )
5832 {
5833 OSData * data;
5834 IOReturn ret = 0;
5835
5836 if (!calendar)
5837 return kIOReturnBadArgument;
5838
5839 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
5840 if (!data)
5841 return kIOReturnNoMemory;
5842
5843 if (kPMCalendarTypeMaintenance == calendar->selector) {
5844 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
5845 if (kIOReturnSuccess == ret)
5846 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
5847 } else
5848 if (kPMCalendarTypeSleepService == calendar->selector)
5849 {
5850 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
5851 if (kIOReturnSuccess == ret)
5852 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
5853 }
5854 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
5855
5856 data->release();
5857 return ret;
5858 }
5859
5860 // MARK: -
5861 // MARK: Display Wrangler
5862
5863 //******************************************************************************
5864 // displayWranglerNotification
5865 //
5866 // Handle the notification when the IODisplayWrangler changes power state.
5867 //******************************************************************************
5868
5869 IOReturn IOPMrootDomain::displayWranglerNotification(
5870 void * target, void * refCon,
5871 UInt32 messageType, IOService * service,
5872 void * messageArgument, vm_size_t argSize )
5873 {
5874 #if !NO_KERNEL_HID
5875 int displayPowerState;
5876 IOPowerStateChangeNotification * params =
5877 (IOPowerStateChangeNotification *) messageArgument;
5878
5879 if ((messageType != kIOMessageDeviceWillPowerOff) &&
5880 (messageType != kIOMessageDeviceHasPoweredOn))
5881 return kIOReturnUnsupported;
5882
5883 ASSERT_GATED();
5884 if (!gRootDomain)
5885 return kIOReturnUnsupported;
5886
5887 displayPowerState = params->stateNumber;
5888 DLOG("wrangler %s ps %d\n",
5889 getIOMessageString(messageType), displayPowerState);
5890
5891 switch (messageType) {
5892 case kIOMessageDeviceWillPowerOff:
5893 // Display wrangler has dropped power due to display idle
5894 // or force system sleep.
5895 //
5896 // 4 Display ON kWranglerPowerStateMax
5897 // 3 Display Dim kWranglerPowerStateDim
5898 // 2 Display Sleep kWranglerPowerStateSleep
5899 // 1 Not visible to user
5900 // 0 Not visible to user kWranglerPowerStateMin
5901
5902 if (displayPowerState <= kWranglerPowerStateSleep)
5903 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
5904 break;
5905
5906 case kIOMessageDeviceHasPoweredOn:
5907 // Display wrangler has powered on due to user activity
5908 // or wake from sleep.
5909
5910 if (kWranglerPowerStateMax == displayPowerState)
5911 {
5912 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
5913
5914 // See comment in handleUpdatePowerClientForDisplayWrangler
5915 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
5916 kWranglerPowerStateMax)
5917 {
5918 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
5919 }
5920 }
5921 break;
5922 }
5923 #endif
5924 return kIOReturnUnsupported;
5925 }
5926
5927 //******************************************************************************
5928 // displayWranglerMatchPublished
5929 //
5930 // Receives a notification when the IODisplayWrangler is published.
5931 // When it's published we install a power state change handler.
5932 //******************************************************************************
5933
5934 bool IOPMrootDomain::displayWranglerMatchPublished(
5935 void * target,
5936 void * refCon,
5937 IOService * newService,
5938 IONotifier * notifier __unused)
5939 {
5940 #if !NO_KERNEL_HID
5941 // found the display wrangler, now install a handler
5942 if( !newService->registerInterest( gIOGeneralInterest,
5943 &displayWranglerNotification, target, 0) )
5944 {
5945 return false;
5946 }
5947 #endif
5948 return true;
5949 }
5950
5951 #if defined(__i386__) || defined(__x86_64__)
5952
5953 bool IOPMrootDomain::IONVRAMMatchPublished(
5954 void * target,
5955 void * refCon,
5956 IOService * newService,
5957 IONotifier * notifier)
5958 {
5959 unsigned int len = 0;
5960 IOPMrootDomain *rd = (IOPMrootDomain *)target;
5961 OSNumber *statusCode = NULL;
5962
5963 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey, NULL, &len))
5964 {
5965 statusCode = OSDynamicCast(OSNumber, rd->getProperty(kIOPMSleepWakeFailureCodeKey));
5966 if (statusCode != NULL) {
5967 if (statusCode->unsigned64BitValue() != 0) {
5968 rd->swd_flags |= SWD_BOOT_BY_SW_WDOG;
5969 MSG("System was rebooted due to Sleep/Wake failure\n");
5970 }
5971 else {
5972 rd->swd_flags |= SWD_BOOT_BY_OSX_WDOG;
5973 MSG("System was non-responsive and was rebooted by watchdog\n");
5974 }
5975 }
5976
5977 rd->swd_logBufMap = rd->sleepWakeDebugRetrieve();
5978 }
5979 if (notifier) notifier->remove();
5980 return true;
5981 }
5982
5983 #else
5984 bool IOPMrootDomain::IONVRAMMatchPublished(
5985 void * target,
5986 void * refCon,
5987 IOService * newService,
5988 IONotifier * notifier __unused)
5989 {
5990 return false;
5991 }
5992
5993 #endif
5994
5995 //******************************************************************************
5996 // reportUserInput
5997 //
5998 //******************************************************************************
5999
6000 void IOPMrootDomain::reportUserInput( void )
6001 {
6002 #if !NO_KERNEL_HID
6003 OSIterator * iter;
6004 OSDictionary * matching;
6005
6006 if(!wrangler)
6007 {
6008 matching = serviceMatching("IODisplayWrangler");
6009 iter = getMatchingServices(matching);
6010 if (matching) matching->release();
6011 if(iter)
6012 {
6013 wrangler = OSDynamicCast(IOService, iter->getNextObject());
6014 iter->release();
6015 }
6016 }
6017
6018 if(wrangler)
6019 wrangler->activityTickle(0,0);
6020 #endif
6021 }
6022
6023 //******************************************************************************
6024 // latchDisplayWranglerTickle
6025 //******************************************************************************
6026
6027 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
6028 {
6029 #if !NO_KERNEL_HID
6030 if (latch)
6031 {
6032 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
6033 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
6034 !checkSystemCanSustainFullWake())
6035 {
6036 // Currently in dark wake, and not transitioning to full wake.
6037 // Full wake is unsustainable, so latch the tickle to prevent
6038 // the display from lighting up momentarily.
6039 wranglerTickleLatched = true;
6040 }
6041 else
6042 {
6043 wranglerTickleLatched = false;
6044 }
6045 }
6046 else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
6047 {
6048 wranglerTickleLatched = false;
6049
6050 pmPowerStateQueue->submitPowerEvent(
6051 kPowerEventPolicyStimulus,
6052 (void *) kStimulusDarkWakeActivityTickle );
6053 }
6054
6055 return wranglerTickleLatched;
6056 #else
6057 return false;
6058 #endif
6059 }
6060
6061 //******************************************************************************
6062 // setDisplayPowerOn
6063 //
6064 // For root domain user client
6065 //******************************************************************************
6066
6067 void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
6068 {
6069 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
6070 (void *) 0, options );
6071 }
6072
6073 // MARK: -
6074 // MARK: Battery
6075
6076 //******************************************************************************
6077 // batteryPublished
6078 //
6079 // Notification on battery class IOPowerSource appearance
6080 //******************************************************************************
6081
6082 bool IOPMrootDomain::batteryPublished(
6083 void * target,
6084 void * root_domain,
6085 IOService * resourceService,
6086 IONotifier * notifier __unused )
6087 {
6088 // rdar://2936060&4435589
6089 // All laptops have dimmable LCD displays
6090 // All laptops have batteries
6091 // So if this machine has a battery, publish the fact that the backlight
6092 // supports dimming.
6093 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
6094
6095 return (true);
6096 }
6097
6098 // MARK: -
6099 // MARK: System PM Policy
6100
6101 //******************************************************************************
6102 // checkSystemSleepAllowed
6103 //
6104 //******************************************************************************
6105
6106 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
6107 uint32_t sleepReason )
6108 {
6109 int err = 0;
6110
6111 // Conditions that prevent idle and demand system sleep.
6112
6113 do {
6114 if (userDisabledAllSleep)
6115 {
6116 err = 1; // 1. user-space sleep kill switch
6117 break;
6118 }
6119
6120 if (systemBooting || systemShutdown || gWillShutdown)
6121 {
6122 err = 2; // 2. restart or shutdown in progress
6123 break;
6124 }
6125
6126 if (options == 0)
6127 break;
6128
6129 // Conditions above pegs the system at full wake.
6130 // Conditions below prevent system sleep but does not prevent
6131 // dark wake, and must be called from gated context.
6132
6133 #if !CONFIG_SLEEP
6134 err = 3; // 3. config does not support sleep
6135 break;
6136 #endif
6137
6138 if (lowBatteryCondition || thermalWarningState)
6139 {
6140 break; // always sleep on low battery or when in thermal warning state
6141 }
6142
6143 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
6144 {
6145 break; // always sleep on dark wake thermal emergencies
6146 }
6147
6148 if (preventSystemSleepList->getCount() != 0)
6149 {
6150 err = 4; // 4. child prevent system sleep clamp
6151 break;
6152 }
6153
6154 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
6155 kIOPMDriverAssertionLevelOn)
6156 {
6157 err = 5; // 5. CPU assertion
6158 break;
6159 }
6160
6161 if (pciCantSleepValid)
6162 {
6163 if (pciCantSleepFlag)
6164 err = 6; // 6. PCI card does not support PM (cached)
6165 break;
6166 }
6167 else if (sleepSupportedPEFunction &&
6168 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6169 {
6170 IOReturn ret;
6171 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
6172 ret = getPlatform()->callPlatformFunction(
6173 sleepSupportedPEFunction, false,
6174 NULL, NULL, NULL, NULL);
6175 pciCantSleepValid = true;
6176 pciCantSleepFlag = false;
6177 if ((platformSleepSupport & kPCICantSleep) ||
6178 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
6179 {
6180 err = 6; // 6. PCI card does not support PM
6181 pciCantSleepFlag = true;
6182 break;
6183 }
6184 }
6185 }
6186 while (false);
6187
6188 if (err)
6189 {
6190 DLOG("System sleep prevented by %d\n", err);
6191 return false;
6192 }
6193 return true;
6194 }
6195
6196 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6197 {
6198 return checkSystemSleepAllowed(0, 0);
6199 }
6200
6201 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
6202 {
6203 ASSERT_GATED();
6204 return checkSystemSleepAllowed(1, sleepReason);
6205 }
6206
6207 //******************************************************************************
6208 // checkSystemCanSustainFullWake
6209 //******************************************************************************
6210
6211 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6212 {
6213 #if !NO_KERNEL_HID
6214 if (lowBatteryCondition || thermalWarningState)
6215 {
6216 // Low battery wake, or received a low battery notification
6217 // while system is awake. This condition will persist until
6218 // the following wake.
6219 return false;
6220 }
6221
6222 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
6223 {
6224 // Graphics state is unknown and external display might not be probed.
6225 // Do not incorporate state that requires graphics to be in max power
6226 // such as desktopMode or clamshellDisabled.
6227
6228 if (!acAdaptorConnected)
6229 {
6230 DLOG("full wake check: no AC\n");
6231 return false;
6232 }
6233 }
6234 #endif
6235 return true;
6236 }
6237
6238 //******************************************************************************
6239 // adjustPowerState
6240 //
6241 // Conditions that affect our wake/sleep decision has changed.
6242 // If conditions dictate that the system must remain awake, clamp power
6243 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6244 // is TRUE, then remove the power clamp and allow the power state to drop
6245 // to SLEEP_STATE.
6246 //******************************************************************************
6247
6248 void IOPMrootDomain::adjustPowerState( bool sleepASAP )
6249 {
6250 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6251 (uint32_t) getPowerState(), sleepASAP, idleSleepEnabled);
6252
6253 ASSERT_GATED();
6254
6255 if ((!idleSleepEnabled) || !checkSystemSleepEnabled())
6256 {
6257 changePowerStateToPriv(ON_STATE);
6258 }
6259 else if ( sleepASAP )
6260 {
6261 changePowerStateToPriv(SLEEP_STATE);
6262 }
6263 }
6264
6265 void IOPMrootDomain::handleDisplayPowerOn( )
6266 {
6267 if (!wrangler) return;
6268 if (displayPowerOnRequested)
6269 {
6270 if (!checkSystemCanSustainFullWake()) return;
6271
6272 // Force wrangler to max power state. If system is in dark wake
6273 // this alone won't raise the wrangler's power state.
6274
6275 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
6276
6277 // System in dark wake, always requesting full wake should
6278 // not have any bad side-effects, even if the request fails.
6279
6280 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6281 {
6282 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
6283 requestFullWake( kFullWakeReasonDisplayOn );
6284 }
6285 }
6286 else
6287 {
6288 // Relenquish desire to power up display.
6289 // Must first transition to state 1 since wrangler doesn't
6290 // power off the displays at state 0. At state 0 the root
6291 // domain is removed from the wrangler's power client list.
6292
6293 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
6294 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
6295
6296 }
6297
6298 }
6299
6300 //******************************************************************************
6301 // dispatchPowerEvent
6302 //
6303 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6304 //******************************************************************************
6305
6306 void IOPMrootDomain::dispatchPowerEvent(
6307 uint32_t event, void * arg0, uint64_t arg1 )
6308 {
6309 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6310 ASSERT_GATED();
6311
6312 switch (event)
6313 {
6314 case kPowerEventFeatureChanged:
6315 messageClients(kIOPMMessageFeatureChange, this);
6316 break;
6317
6318 case kPowerEventReceivedPowerNotification:
6319 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
6320 break;
6321
6322 case kPowerEventSystemBootCompleted:
6323 if (systemBooting)
6324 {
6325 systemBooting = false;
6326
6327 if (lowBatteryCondition)
6328 {
6329 privateSleepSystem (kIOPMSleepReasonLowPower);
6330
6331 // The rest is unnecessary since the system is expected
6332 // to sleep immediately. The following wake will update
6333 // everything.
6334 break;
6335 }
6336
6337 if (swd_flags & SWD_VALID_LOGS) {
6338 if (swd_flags & SWD_LOGS_IN_MEM) {
6339 sleepWakeDebugDumpFromMem(swd_logBufMap);
6340 swd_logBufMap->release();
6341 swd_logBufMap = 0;
6342 }
6343 else if (swd_flags & SWD_LOGS_IN_FILE)
6344 sleepWakeDebugDumpFromFile();
6345 }
6346 else if (swd_flags & (SWD_BOOT_BY_SW_WDOG|SWD_BOOT_BY_OSX_WDOG)) {
6347 // If logs are invalid, write the failure code
6348 sleepWakeDebugDumpFromMem(NULL);
6349 }
6350 // If lid is closed, re-send lid closed notification
6351 // now that booting is complete.
6352 if ( clamshellClosed )
6353 {
6354 handlePowerNotification(kLocalEvalClamshellCommand);
6355 }
6356 evaluatePolicy( kStimulusAllowSystemSleepChanged );
6357
6358 }
6359 break;
6360
6361 case kPowerEventSystemShutdown:
6362 if (kOSBooleanTrue == (OSBoolean *) arg0)
6363 {
6364 /* We set systemShutdown = true during shutdown
6365 to prevent sleep at unexpected times while loginwindow is trying
6366 to shutdown apps and while the OS is trying to transition to
6367 complete power of.
6368
6369 Set to true during shutdown, as soon as loginwindow shows
6370 the "shutdown countdown dialog", through individual app
6371 termination, and through black screen kernel shutdown.
6372 */
6373 systemShutdown = true;
6374 } else {
6375 /*
6376 A shutdown was initiated, but then the shutdown
6377 was cancelled, clearing systemShutdown to false here.
6378 */
6379 systemShutdown = false;
6380 }
6381 break;
6382
6383 case kPowerEventUserDisabledSleep:
6384 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
6385 break;
6386
6387 case kPowerEventRegisterSystemCapabilityClient:
6388 if (systemCapabilityNotifier)
6389 {
6390 systemCapabilityNotifier->release();
6391 systemCapabilityNotifier = 0;
6392 }
6393 if (arg0)
6394 {
6395 systemCapabilityNotifier = (IONotifier *) arg0;
6396 systemCapabilityNotifier->retain();
6397 }
6398 /* intentional fall-through */
6399 [[clang::fallthrough]];
6400
6401 case kPowerEventRegisterKernelCapabilityClient:
6402 if (!_joinedCapabilityClients)
6403 _joinedCapabilityClients = OSSet::withCapacity(8);
6404 if (arg0)
6405 {
6406 IONotifier * notify = (IONotifier *) arg0;
6407 if (_joinedCapabilityClients)
6408 {
6409 _joinedCapabilityClients->setObject(notify);
6410 synchronizePowerTree( kIOPMSyncNoChildNotify );
6411 }
6412 notify->release();
6413 }
6414 break;
6415
6416 case kPowerEventPolicyStimulus:
6417 if (arg0)
6418 {
6419 int stimulus = (uintptr_t) arg0;
6420 evaluatePolicy( stimulus, (uint32_t) arg1 );
6421 }
6422 break;
6423
6424 case kPowerEventAssertionCreate:
6425 if (pmAssertions) {
6426 pmAssertions->handleCreateAssertion((OSData *)arg0);
6427 }
6428 break;
6429
6430
6431 case kPowerEventAssertionRelease:
6432 if (pmAssertions) {
6433 pmAssertions->handleReleaseAssertion(arg1);
6434 }
6435 break;
6436
6437 case kPowerEventAssertionSetLevel:
6438 if (pmAssertions) {
6439 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
6440 }
6441 break;
6442
6443 case kPowerEventQueueSleepWakeUUID:
6444 handleQueueSleepWakeUUID((OSObject *)arg0);
6445 break;
6446 case kPowerEventPublishSleepWakeUUID:
6447 handlePublishSleepWakeUUID((bool)arg0);
6448 break;
6449
6450 case kPowerEventSetDisplayPowerOn:
6451 if (!wrangler) break;
6452 if (arg1 != 0)
6453 {
6454 displayPowerOnRequested = true;
6455 }
6456 else
6457 {
6458 displayPowerOnRequested = false;
6459 }
6460 handleDisplayPowerOn();
6461 break;
6462 }
6463 }
6464
6465 //******************************************************************************
6466 // systemPowerEventOccurred
6467 //
6468 // The power controller is notifying us of a hardware-related power management
6469 // event that we must handle.
6470 //
6471 // systemPowerEventOccurred covers the same functionality that
6472 // receivePowerNotification does; it simply provides a richer API for conveying
6473 // more information.
6474 //******************************************************************************
6475
6476 IOReturn IOPMrootDomain::systemPowerEventOccurred(
6477 const OSSymbol *event,
6478 uint32_t intValue)
6479 {
6480 IOReturn attempt = kIOReturnSuccess;
6481 OSNumber *newNumber = NULL;
6482
6483 if (!event)
6484 return kIOReturnBadArgument;
6485
6486 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
6487 if (!newNumber)
6488 return kIOReturnInternalError;
6489
6490 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
6491
6492 newNumber->release();
6493
6494 return attempt;
6495 }
6496
6497 void IOPMrootDomain::setThermalState(OSObject *value)
6498 {
6499 OSNumber * num;
6500
6501 if (gIOPMWorkLoop->inGate() == false) {
6502 gIOPMWorkLoop->runAction(
6503 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
6504 (OSObject *)this,
6505 (void *)value);
6506
6507 return;
6508 }
6509 if (value && (num = OSDynamicCast(OSNumber, value))) {
6510 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
6511 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
6512 }
6513 }
6514
6515 IOReturn IOPMrootDomain::systemPowerEventOccurred(
6516 const OSSymbol *event,
6517 OSObject *value)
6518 {
6519 OSDictionary *thermalsDict = NULL;
6520 bool shouldUpdate = true;
6521
6522 if (!event || !value)
6523 return kIOReturnBadArgument;
6524
6525 // LOCK
6526 // We reuse featuresDict Lock because it already exists and guards
6527 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6528 // of stepping on that lock.
6529 if (featuresDictLock) IOLockLock(featuresDictLock);
6530
6531 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
6532
6533 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
6534 thermalsDict = OSDictionary::withDictionary(thermalsDict);
6535 } else {
6536 thermalsDict = OSDictionary::withCapacity(1);
6537 }
6538
6539 if (!thermalsDict) {
6540 shouldUpdate = false;
6541 goto exit;
6542 }
6543
6544 thermalsDict->setObject (event, value);
6545
6546 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
6547
6548 thermalsDict->release();
6549
6550 exit:
6551 // UNLOCK
6552 if (featuresDictLock) IOLockUnlock(featuresDictLock);
6553
6554 if (shouldUpdate) {
6555 if (event &&
6556 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
6557 setThermalState(value);
6558 }
6559 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
6560 }
6561
6562 return kIOReturnSuccess;
6563 }
6564
6565 //******************************************************************************
6566 // receivePowerNotification
6567 //
6568 // The power controller is notifying us of a hardware-related power management
6569 // event that we must handle. This may be a result of an 'environment' interrupt
6570 // from the power mgt micro.
6571 //******************************************************************************
6572
6573 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
6574 {
6575 pmPowerStateQueue->submitPowerEvent(
6576 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6577 return kIOReturnSuccess;
6578 }
6579
6580 void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6581 {
6582 bool eval_clamshell = false;
6583
6584 ASSERT_GATED();
6585
6586 /*
6587 * Local (IOPMrootDomain only) eval clamshell command
6588 */
6589 if (msg & kLocalEvalClamshellCommand)
6590 {
6591 eval_clamshell = true;
6592 }
6593
6594 /*
6595 * Overtemp
6596 */
6597 if (msg & kIOPMOverTemp)
6598 {
6599 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6600 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
6601 }
6602
6603 /*
6604 * Forward DW thermal notification to client, if system is not going to sleep
6605 */
6606 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
6607 {
6608 DLOG("DarkWake thermal limits message received!\n");
6609
6610 messageClients(kIOPMMessageDarkWakeThermalEmergency);
6611 }
6612
6613 /*
6614 * Sleep Now!
6615 */
6616 if (msg & kIOPMSleepNow)
6617 {
6618 privateSleepSystem (kIOPMSleepReasonSoftware);
6619 }
6620
6621 /*
6622 * Power Emergency
6623 */
6624 if (msg & kIOPMPowerEmergency)
6625 {
6626 lowBatteryCondition = true;
6627 privateSleepSystem (kIOPMSleepReasonLowPower);
6628 }
6629
6630 /*
6631 * Clamshell OPEN
6632 */
6633 if (msg & kIOPMClamshellOpened)
6634 {
6635 // Received clamshel open message from clamshell controlling driver
6636 // Update our internal state and tell general interest clients
6637 clamshellClosed = false;
6638 clamshellExists = true;
6639
6640 // Don't issue a hid tickle when lid is open and polled on wake
6641 if (msg & kIOPMSetValue)
6642 {
6643 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6644 reportUserInput();
6645 }
6646
6647 // Tell PMCPU
6648 informCPUStateChange(kInformLid, 0);
6649
6650 // Tell general interest clients
6651 sendClientClamshellNotification();
6652
6653 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
6654 || (lastSleepReason == kIOPMSleepReasonIdle)
6655 || (lastSleepReason == kIOPMSleepReasonMaintenance));
6656 if (aborting) userActivityCount++;
6657 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
6658 }
6659
6660 /*
6661 * Clamshell CLOSED
6662 * Send the clamshell interest notification since the lid is closing.
6663 */
6664 if (msg & kIOPMClamshellClosed)
6665 {
6666 // Received clamshel open message from clamshell controlling driver
6667 // Update our internal state and tell general interest clients
6668 clamshellClosed = true;
6669 clamshellExists = true;
6670
6671 // Tell PMCPU
6672 informCPUStateChange(kInformLid, 1);
6673
6674 // Tell general interest clients
6675 sendClientClamshellNotification();
6676
6677 // And set eval_clamshell = so we can attempt
6678 eval_clamshell = true;
6679 }
6680
6681 /*
6682 * Set Desktop mode (sent from graphics)
6683 *
6684 * -> reevaluate lid state
6685 */
6686 if (msg & kIOPMSetDesktopMode)
6687 {
6688 desktopMode = (0 != (msg & kIOPMSetValue));
6689 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
6690
6691 sendClientClamshellNotification();
6692
6693 // Re-evaluate the lid state
6694 eval_clamshell = true;
6695 }
6696
6697 /*
6698 * AC Adaptor connected
6699 *
6700 * -> reevaluate lid state
6701 */
6702 if (msg & kIOPMSetACAdaptorConnected)
6703 {
6704 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6705 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
6706
6707 // Tell CPU PM
6708 informCPUStateChange(kInformAC, !acAdaptorConnected);
6709
6710 // Tell BSD if AC is connected
6711 // 0 == external power source; 1 == on battery
6712 post_sys_powersource(acAdaptorConnected ? 0:1);
6713
6714 sendClientClamshellNotification();
6715
6716 // Re-evaluate the lid state
6717 eval_clamshell = true;
6718
6719 // Lack of AC may have latched a display wrangler tickle.
6720 // This mirrors the hardware's USB wake event latch, where a latched
6721 // USB wake event followed by an AC attach will trigger a full wake.
6722 latchDisplayWranglerTickle( false );
6723
6724 #if HIBERNATION
6725 // AC presence will reset the standy timer delay adjustment.
6726 _standbyTimerResetSeconds = 0;
6727 #endif
6728 if (!userIsActive) {
6729 // Reset userActivityTime when power supply is changed(rdr 13789330)
6730 clock_get_uptime(&userActivityTime);
6731 }
6732 }
6733
6734 /*
6735 * Enable Clamshell (external display disappear)
6736 *
6737 * -> reevaluate lid state
6738 */
6739 if (msg & kIOPMEnableClamshell)
6740 {
6741 // Re-evaluate the lid state
6742 // System should sleep on external display disappearance
6743 // in lid closed operation.
6744 if (true == clamshellDisabled)
6745 {
6746 eval_clamshell = true;
6747 }
6748
6749 clamshellDisabled = false;
6750 sendClientClamshellNotification();
6751 }
6752
6753 /*
6754 * Disable Clamshell (external display appeared)
6755 * We don't bother re-evaluating clamshell state. If the system is awake,
6756 * the lid is probably open.
6757 */
6758 if (msg & kIOPMDisableClamshell)
6759 {
6760 clamshellDisabled = true;
6761 sendClientClamshellNotification();
6762 }
6763
6764 /*
6765 * Evaluate clamshell and SLEEP if appropiate
6766 */
6767 if (eval_clamshell && clamshellClosed)
6768 {
6769 if (shouldSleepOnClamshellClosed())
6770 privateSleepSystem (kIOPMSleepReasonClamshell);
6771 else
6772 evaluatePolicy( kStimulusDarkWakeEvaluate );
6773 }
6774
6775 /*
6776 * Power Button
6777 */
6778 if (msg & kIOPMPowerButton)
6779 {
6780 if (!wranglerAsleep)
6781 {
6782 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
6783 // Check that power button sleep is enabled
6784 if( pbs ) {
6785 if( kOSBooleanTrue != getProperty(pbs))
6786 privateSleepSystem (kIOPMSleepReasonPowerButton);
6787 }
6788 }
6789 else
6790 reportUserInput();
6791 }
6792 }
6793
6794 //******************************************************************************
6795 // evaluatePolicy
6796 //
6797 // Evaluate root-domain policy in response to external changes.
6798 //******************************************************************************
6799
6800 void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
6801 {
6802 union {
6803 struct {
6804 int idleSleepEnabled : 1;
6805 int idleSleepDisabled : 1;
6806 int displaySleep : 1;
6807 int sleepDelayChanged : 1;
6808 int evaluateDarkWake : 1;
6809 int adjustPowerState : 1;
6810 int userBecameInactive : 1;
6811 } bit;
6812 uint32_t u32;
6813 } flags;
6814
6815 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6816
6817 ASSERT_GATED();
6818 flags.u32 = 0;
6819
6820 switch (stimulus)
6821 {
6822 case kStimulusDisplayWranglerSleep:
6823 if (!wranglerAsleep)
6824 {
6825 // first transition to wrangler sleep or lower
6826 flags.bit.displaySleep = true;
6827 }
6828 break;
6829
6830 case kStimulusDisplayWranglerWake:
6831 displayIdleForDemandSleep = false;
6832 wranglerAsleep = false;
6833 break;
6834
6835 case kStimulusEnterUserActiveState:
6836 if (_preventUserActive)
6837 {
6838 DLOG("user active dropped\n");
6839 break;
6840 }
6841 if (!userIsActive)
6842 {
6843 userIsActive = true;
6844 userWasActive = true;
6845
6846 // Stay awake after dropping demand for display power on
6847 if (kFullWakeReasonDisplayOn == fullWakeReason) {
6848 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
6849 DLOG("User activity while in notification wake\n");
6850 changePowerStateWithOverrideTo( ON_STATE, 0);
6851 }
6852
6853 kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
6854 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
6855 messageClients(kIOPMMessageUserIsActiveChanged);
6856 }
6857 flags.bit.idleSleepDisabled = true;
6858 break;
6859
6860 case kStimulusLeaveUserActiveState:
6861 if (userIsActive)
6862 {
6863 userIsActive = false;
6864 clock_get_uptime(&userBecameInactiveTime);
6865 flags.bit.userBecameInactive = true;
6866
6867 kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
6868 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
6869 messageClients(kIOPMMessageUserIsActiveChanged);
6870 }
6871 break;
6872
6873 case kStimulusAggressivenessChanged:
6874 {
6875 unsigned long minutesToIdleSleep = 0;
6876 unsigned long minutesToDisplayDim = 0;
6877 unsigned long minutesDelta = 0;
6878
6879 // Fetch latest display and system sleep slider values.
6880 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
6881 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
6882 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6883 (uint32_t) sleepSlider,
6884 (uint32_t) minutesToIdleSleep,
6885 (uint32_t) minutesToDisplayDim);
6886
6887 DLOG("idle time -> %ld secs (ena %d)\n",
6888 idleSeconds, (minutesToIdleSleep != 0));
6889
6890
6891 // How long to wait before sleeping the system once
6892 // the displays turns off is indicated by 'extraSleepDelay'.
6893
6894 if ( minutesToIdleSleep > minutesToDisplayDim )
6895 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
6896 else if ( minutesToIdleSleep == minutesToDisplayDim )
6897 minutesDelta = 1;
6898
6899 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0))
6900 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
6901
6902 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
6903 flags.bit.idleSleepDisabled = true;
6904 idleSleepEnabled = false;
6905 }
6906 if (0x7fffffff == minutesToIdleSleep)
6907 minutesToIdleSleep = idleSeconds;
6908
6909 if (((minutesDelta != extraSleepDelay) ||
6910 (userActivityTime != userActivityTime_prev)) &&
6911 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
6912 flags.bit.sleepDelayChanged = true;
6913
6914 if (systemDarkWake && !darkWakeToSleepASAP &&
6915 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
6916 {
6917 // Reconsider decision to remain in dark wake
6918 flags.bit.evaluateDarkWake = true;
6919 }
6920
6921 sleepSlider = minutesToIdleSleep;
6922 extraSleepDelay = minutesDelta;
6923 userActivityTime_prev = userActivityTime;
6924 } break;
6925
6926 case kStimulusDemandSystemSleep:
6927 displayIdleForDemandSleep = true;
6928 if (wrangler && wranglerIdleSettings)
6929 {
6930 // Request wrangler idle only when demand sleep is triggered
6931 // from full wake.
6932 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6933 {
6934 wrangler->setProperties(wranglerIdleSettings);
6935 DLOG("Requested wrangler idle\n");
6936 }
6937 }
6938 // arg = sleepReason
6939 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
6940 break;
6941
6942 case kStimulusAllowSystemSleepChanged:
6943 flags.bit.adjustPowerState = true;
6944 break;
6945
6946 case kStimulusDarkWakeActivityTickle:
6947 // arg == true implies real and not self generated wrangler tickle.
6948 // Update wake type on PM work loop instead of the tickle thread to
6949 // eliminate the possibility of an early tickle clobbering the wake
6950 // type set by the platform driver.
6951 if (arg == true)
6952 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
6953
6954 if (false == wranglerTickled)
6955 {
6956 if (latchDisplayWranglerTickle(true))
6957 {
6958 DLOG("latched tickle\n");
6959 break;
6960 }
6961
6962 wranglerTickled = true;
6963 DLOG("Requesting full wake after dark wake activity tickle\n");
6964 requestFullWake( kFullWakeReasonLocalUser );
6965 }
6966 break;
6967
6968 case kStimulusDarkWakeEntry:
6969 case kStimulusDarkWakeReentry:
6970 // Any system transitions since the last dark wake transition
6971 // will invalid the stimulus.
6972
6973 if (arg == _systemStateGeneration)
6974 {
6975 DLOG("dark wake entry\n");
6976 systemDarkWake = true;
6977
6978 // Keep wranglerAsleep an invariant when wrangler is absent
6979 if (wrangler)
6980 wranglerAsleep = true;
6981
6982 if (kStimulusDarkWakeEntry == stimulus)
6983 {
6984 clock_get_uptime(&userBecameInactiveTime);
6985 flags.bit.evaluateDarkWake = true;
6986 }
6987
6988 // Always accelerate disk spindown while in dark wake,
6989 // even if system does not support/allow sleep.
6990
6991 cancelIdleSleepTimer();
6992 setQuickSpinDownTimeout();
6993 }
6994 break;
6995
6996 case kStimulusDarkWakeEvaluate:
6997 if (systemDarkWake)
6998 {
6999 flags.bit.evaluateDarkWake = true;
7000 }
7001 break;
7002
7003 case kStimulusNoIdleSleepPreventers:
7004 flags.bit.adjustPowerState = true;
7005 break;
7006
7007 } /* switch(stimulus) */
7008
7009 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
7010 {
7011 if (darkWakeToSleepASAP ||
7012 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
7013 {
7014 uint32_t newSleepReason;
7015
7016 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
7017 {
7018 // System was previously in full wake. Sleep reason from
7019 // full to dark already recorded in fullToDarkReason.
7020
7021 if (lowBatteryCondition)
7022 newSleepReason = kIOPMSleepReasonLowPower;
7023 else
7024 newSleepReason = fullToDarkReason;
7025 }
7026 else
7027 {
7028 // In dark wake from system sleep.
7029
7030 if (darkWakeSleepService)
7031 newSleepReason = kIOPMSleepReasonSleepServiceExit;
7032 else
7033 newSleepReason = kIOPMSleepReasonMaintenance;
7034 }
7035
7036 if (checkSystemCanSleep(newSleepReason))
7037 {
7038 privateSleepSystem(newSleepReason);
7039 }
7040 }
7041 else // non-maintenance (network) dark wake
7042 {
7043 if (checkSystemCanSleep(kIOPMSleepReasonIdle))
7044 {
7045 // Release power clamp, and wait for children idle.
7046 adjustPowerState(true);
7047 }
7048 else
7049 {
7050 changePowerStateToPriv(ON_STATE);
7051 }
7052 }
7053 }
7054
7055 if (systemDarkWake)
7056 {
7057 // The rest are irrelevant while system is in dark wake.
7058 flags.u32 = 0;
7059 }
7060
7061 if ((flags.bit.displaySleep) &&
7062 (kFullWakeReasonDisplayOn == fullWakeReason))
7063 {
7064 // kIOPMSleepReasonMaintenance?
7065 DLOG("Display sleep while in notification wake\n");
7066 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
7067 }
7068
7069 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
7070 {
7071 bool cancelQuickSpindown = false;
7072
7073 if (flags.bit.sleepDelayChanged)
7074 {
7075 // Cancel existing idle sleep timer and quick disk spindown.
7076 // New settings will be applied by the idleSleepEnabled flag
7077 // handler below if idle sleep is enabled.
7078
7079 DLOG("extra sleep timer changed\n");
7080 cancelIdleSleepTimer();
7081 cancelQuickSpindown = true;
7082 }
7083 else
7084 {
7085 DLOG("user inactive\n");
7086 }
7087
7088 if (!userIsActive && idleSleepEnabled)
7089 {
7090 startIdleSleepTimer(getTimeToIdleSleep());
7091 }
7092
7093 if (cancelQuickSpindown)
7094 restoreUserSpinDownTimeout();
7095 }
7096
7097 if (flags.bit.idleSleepEnabled)
7098 {
7099 DLOG("idle sleep timer enabled\n");
7100 if (!wrangler)
7101 {
7102 changePowerStateToPriv(ON_STATE);
7103 startIdleSleepTimer( idleSeconds );
7104 }
7105 else
7106 {
7107 // Start idle timer if prefs now allow system sleep
7108 // and user is already inactive. Disk spindown is
7109 // accelerated upon timer expiration.
7110
7111 if (!userIsActive)
7112 {
7113 startIdleSleepTimer(getTimeToIdleSleep());
7114 }
7115 }
7116 }
7117
7118 if (flags.bit.idleSleepDisabled)
7119 {
7120 DLOG("idle sleep timer disabled\n");
7121 cancelIdleSleepTimer();
7122 restoreUserSpinDownTimeout();
7123 adjustPowerState();
7124 }
7125
7126 if (flags.bit.adjustPowerState)
7127 {
7128 bool sleepASAP = false;
7129
7130 if (!systemBooting && (preventIdleSleepList->getCount() == 0))
7131 {
7132 if (!wrangler)
7133 {
7134 changePowerStateToPriv(ON_STATE);
7135 if (idleSleepEnabled)
7136 {
7137 // stay awake for at least idleSeconds
7138 startIdleSleepTimer(idleSeconds);
7139 }
7140 }
7141 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
7142 {
7143 sleepASAP = true;
7144 }
7145 }
7146
7147 adjustPowerState(sleepASAP);
7148 }
7149 }
7150
7151 //******************************************************************************
7152 // requestFullWake
7153 //
7154 // Request transition from dark wake to full wake
7155 //******************************************************************************
7156
7157 void IOPMrootDomain::requestFullWake( FullWakeReason reason )
7158 {
7159 uint32_t options = 0;
7160 IOService * pciRoot = 0;
7161 bool promotion = false;
7162
7163 // System must be in dark wake and a valid reason for entering full wake
7164 if ((kFullWakeReasonNone == reason) ||
7165 (kFullWakeReasonNone != fullWakeReason) ||
7166 (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
7167 {
7168 return;
7169 }
7170
7171 // Will clear reason upon exit from full wake
7172 fullWakeReason = reason;
7173
7174 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
7175 kIOPMSystemCapabilityAudio);
7176
7177 if ((kSystemTransitionWake == _systemTransitionType) &&
7178 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7179 !graphicsSuppressed)
7180 {
7181 // Promote to full wake while waking up to dark wake due to tickle.
7182 // PM will hold off notifying the graphics subsystem about system wake
7183 // as late as possible, so if a HID tickle does arrive, graphics can
7184 // power up on this same wake cycle. The latency to power up graphics
7185 // on the next cycle can be huge on some systems. However, once any
7186 // graphics suppression has taken effect, it is too late. All other
7187 // graphics devices must be similarly suppressed. But the delay till
7188 // the following cycle should be short.
7189
7190 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
7191 kIOPMSystemCapabilityAudio);
7192
7193 // Immediately bring up audio and graphics
7194 pciRoot = pciHostBridgeDriver;
7195 willEnterFullWake();
7196 promotion = true;
7197 }
7198
7199 // Unsafe to cancel once graphics was powered.
7200 // If system woke from dark wake, the return to sleep can
7201 // be cancelled. "awake -> dark -> sleep" transition
7202 // can be canceled also, during the "dark --> sleep" phase
7203 // *prior* to driver power down.
7204 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
7205 _pendingCapability == 0) {
7206 options |= kIOPMSyncCancelPowerDown;
7207 }
7208
7209 synchronizePowerTree(options, pciRoot);
7210 if (kFullWakeReasonLocalUser == fullWakeReason)
7211 {
7212 // IOGraphics doesn't light the display even though graphics is
7213 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7214 // So, do an explicit activity tickle
7215 if (wrangler)
7216 wrangler->activityTickle(0,0);
7217 }
7218
7219 // Log a timestamp for the initial full wake request.
7220 // System may not always honor this full wake request.
7221 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
7222 {
7223 AbsoluteTime now;
7224 uint64_t nsec;
7225
7226 clock_get_uptime(&now);
7227 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
7228 absolutetime_to_nanoseconds(now, &nsec);
7229 MSG("full wake %s (reason %u) %u ms\n",
7230 promotion ? "promotion" : "request",
7231 fullWakeReason, ((int)((nsec) / 1000000ULL)));
7232 }
7233 }
7234
7235 //******************************************************************************
7236 // willEnterFullWake
7237 //
7238 // System will enter full wake from sleep, from dark wake, or from dark
7239 // wake promotion. This function aggregate things that are in common to
7240 // all three full wake transitions.
7241 //
7242 // Assumptions: fullWakeReason was updated
7243 //******************************************************************************
7244
7245 void IOPMrootDomain::willEnterFullWake( void )
7246 {
7247 hibernateRetry = false;
7248 sleepToStandby = false;
7249 standbyNixed = false;
7250 resetTimers = false;
7251 sleepTimerMaintenance = false;
7252
7253 _systemMessageClientMask = kSystemMessageClientPowerd |
7254 kSystemMessageClientLegacyApp;
7255
7256 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
7257 {
7258 // Initial graphics full power
7259 _systemMessageClientMask |= kSystemMessageClientKernel;
7260
7261 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7262 setProperty(gIOPMUserTriggeredFullWakeKey,
7263 (kFullWakeReasonLocalUser == fullWakeReason) ?
7264 kOSBooleanTrue : kOSBooleanFalse);
7265 }
7266 #if HIBERNATION
7267 IOHibernateSetWakeCapabilities(_pendingCapability);
7268 #endif
7269
7270 IOService::setAdvisoryTickleEnable( true );
7271 tellClients(kIOMessageSystemWillPowerOn);
7272 preventTransitionToUserActive(false);
7273 }
7274
7275 //******************************************************************************
7276 // fullWakeDelayedWork
7277 //
7278 // System has already entered full wake. Invoked by a delayed thread call.
7279 //******************************************************************************
7280
7281 void IOPMrootDomain::fullWakeDelayedWork( void )
7282 {
7283 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7284 // Not gated, don't modify state
7285 if ((kSystemTransitionNone == _systemTransitionType) &&
7286 CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7287 {
7288 receivePowerNotification( kLocalEvalClamshellCommand );
7289 }
7290 #endif
7291 }
7292
7293 //******************************************************************************
7294 // evaluateAssertions
7295 //
7296 //******************************************************************************
7297 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
7298 {
7299 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
7300
7301 messageClients(kIOPMMessageDriverAssertionsChanged);
7302
7303 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
7304
7305 if (wrangler) {
7306 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
7307
7308 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
7309 wrangler->setIgnoreIdleTimer( value );
7310 }
7311 }
7312
7313 if (changedBits & kIOPMDriverAssertionCPUBit) {
7314 evaluatePolicy(kStimulusDarkWakeEvaluate);
7315 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
7316 AbsoluteTime now;
7317 clock_usec_t microsecs;
7318 clock_get_uptime(&now);
7319 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
7320 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
7321 if (assertOnWakeReport) {
7322 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
7323 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
7324 }
7325 }
7326 }
7327
7328 if (changedBits & kIOPMDriverAssertionReservedBit7) {
7329 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
7330 if (value) {
7331 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7332 updatePreventIdleSleepList(this, true);
7333 }
7334 else {
7335 DLOG("Driver assertion ReservedBit7 dropped\n");
7336 updatePreventIdleSleepList(this, false);
7337 }
7338 }
7339 }
7340
7341 // MARK: -
7342 // MARK: Statistics
7343
7344 //******************************************************************************
7345 // pmStats
7346 //
7347 //******************************************************************************
7348
7349 void IOPMrootDomain::pmStatsRecordEvent(
7350 int eventIndex,
7351 AbsoluteTime timestamp)
7352 {
7353 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
7354 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
7355 uint64_t delta;
7356 uint64_t nsec;
7357 OSData *publishPMStats = NULL;
7358
7359 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
7360
7361 absolutetime_to_nanoseconds(timestamp, &nsec);
7362
7363 switch (eventIndex) {
7364 case kIOPMStatsHibernateImageWrite:
7365 if (starting)
7366 gPMStats.hibWrite.start = nsec;
7367 else if (stopping)
7368 gPMStats.hibWrite.stop = nsec;
7369
7370 if (stopping) {
7371 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
7372 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
7373 }
7374 break;
7375 case kIOPMStatsHibernateImageRead:
7376 if (starting)
7377 gPMStats.hibRead.start = nsec;
7378 else if (stopping)
7379 gPMStats.hibRead.stop = nsec;
7380
7381 if (stopping) {
7382 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
7383 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
7384
7385 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
7386 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
7387 publishPMStats->release();
7388 bzero(&gPMStats, sizeof(gPMStats));
7389 }
7390 break;
7391 }
7392 }
7393
7394 /*
7395 * Appends a record of the application response to
7396 * IOPMrootDomain::pmStatsAppResponses
7397 */
7398 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7399 const OSSymbol *response,
7400 const char *name,
7401 int messageType,
7402 uint32_t delay_ms,
7403 uint64_t id,
7404 OSObject *object,
7405 IOPMPowerStateIndex powerState)
7406 {
7407 OSDictionary *responseDescription = NULL;
7408 OSNumber *delayNum = NULL;
7409 OSNumber *powerCaps = NULL;
7410 OSNumber *pidNum = NULL;
7411 OSNumber *msgNum = NULL;
7412 const OSSymbol *appname;
7413 const OSSymbol *sleep = NULL, *wake = NULL;
7414 IOPMServiceInterestNotifier *notify = 0;
7415
7416 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
7417 {
7418 if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut))
7419 notify->ackTimeoutCnt++;
7420 else
7421 notify->ackTimeoutCnt = 0;
7422
7423 }
7424
7425 if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) ||
7426 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
7427 return;
7428
7429
7430 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7431 kdebugTrace(kPMLogDrvResponseDelay, id, messageType, delay_ms);
7432 }
7433 else if (notify) {
7434 kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
7435 notify->msgType = 0;
7436 }
7437
7438 responseDescription = OSDictionary::withCapacity(5);
7439 if (responseDescription)
7440 {
7441 if (response) {
7442 responseDescription->setObject(_statsResponseTypeKey, response);
7443 }
7444
7445 msgNum = OSNumber::withNumber(messageType, 32);
7446 if (msgNum) {
7447 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7448 msgNum->release();
7449 }
7450
7451 if (name && (strlen(name) > 0))
7452 {
7453 appname = OSSymbol::withCString(name);
7454 if (appname) {
7455 responseDescription->setObject(_statsNameKey, appname);
7456 appname->release();
7457 }
7458 }
7459
7460 if (id != 0) {
7461 pidNum = OSNumber::withNumber(id, 32);
7462 if (pidNum) {
7463 responseDescription->setObject(_statsPIDKey, pidNum);
7464 pidNum->release();
7465 }
7466 }
7467
7468 delayNum = OSNumber::withNumber(delay_ms, 32);
7469 if (delayNum) {
7470 responseDescription->setObject(_statsTimeMSKey, delayNum);
7471 delayNum->release();
7472 }
7473
7474 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7475 powerCaps = OSNumber::withNumber(powerState, 32);
7476
7477 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7478 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7479 name, messageType,
7480 powerState, delay_ms);
7481 #endif
7482
7483 }
7484 else {
7485 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
7486 }
7487 if (powerCaps) {
7488 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7489 powerCaps->release();
7490 }
7491
7492 sleep = OSSymbol::withCString("Sleep");
7493 wake = OSSymbol::withCString("Wake");
7494 if (_systemTransitionType == kSystemTransitionSleep) {
7495 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7496 }
7497 else if (_systemTransitionType == kSystemTransitionWake) {
7498 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7499 }
7500 else if (_systemTransitionType == kSystemTransitionCapability) {
7501 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
7502 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7503 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
7504 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7505 }
7506 if (sleep) sleep->release();
7507 if (wake) wake->release();
7508
7509
7510
7511 IOLockLock(pmStatsLock);
7512 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
7513 pmStatsAppResponses->setObject(responseDescription);
7514 }
7515 IOLockUnlock(pmStatsLock);
7516
7517 responseDescription->release();
7518 }
7519
7520 return;
7521 }
7522
7523 // MARK: -
7524 // MARK: PMTraceWorker
7525
7526 //******************************************************************************
7527 // TracePoint support
7528 //
7529 //******************************************************************************
7530
7531 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7532 "IOPMRegisterNVRAMTracePointHandler"
7533
7534 IOReturn IOPMrootDomain::callPlatformFunction(
7535 const OSSymbol * functionName,
7536 bool waitForFunction,
7537 void * param1, void * param2,
7538 void * param3, void * param4 )
7539 {
7540 uint32_t bootFailureCode = 0xffffffff;
7541 unsigned int len = sizeof(bootFailureCode);
7542 if (pmTracer && functionName &&
7543 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7544 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7545 {
7546 uint32_t tracePointPhases, tracePointPCI;
7547 uint64_t statusCode;
7548
7549 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7550 pmTracer->tracePointTarget = (void *) param2;
7551 tracePointPCI = (uint32_t)(uintptr_t) param3;
7552 tracePointPhases = (uint32_t)(uintptr_t) param4;
7553 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
7554 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey, &bootFailureCode, &len)) {
7555 MSG("Failed to read failure code from NVRam\n");
7556 }
7557 // Failure code from EFI/BootRom is a four byte structure
7558 tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
7559 }
7560 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
7561 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
7562 MSG("Sleep failure code 0x%08x 0x%08x\n",
7563 tracePointPCI, tracePointPhases);
7564 }
7565 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
7566 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7567
7568 return kIOReturnSuccess;
7569 }
7570 #if HIBERNATION
7571 else if (functionName &&
7572 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
7573 {
7574 if (gSleepPolicyHandler)
7575 return kIOReturnExclusiveAccess;
7576 if (!param1)
7577 return kIOReturnBadArgument;
7578 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
7579 gSleepPolicyTarget = (void *) param2;
7580 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
7581 return kIOReturnSuccess;
7582 }
7583 #endif
7584
7585 return super::callPlatformFunction(
7586 functionName, waitForFunction, param1, param2, param3, param4);
7587 }
7588
7589 void IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
7590 uintptr_t param1, uintptr_t param2, uintptr_t param3)
7591 {
7592 uint32_t code = IODBG_POWER(event);
7593 uint64_t regId = id;
7594 if (regId == 0) {
7595 regId = getRegistryEntryID();
7596 }
7597 IOTimeStampConstant(code, (uintptr_t) regId, param1, param2, param3);
7598 }
7599
7600
7601 void IOPMrootDomain::tracePoint( uint8_t point )
7602 {
7603 if (systemBooting) return;
7604
7605 if (kIOPMTracePointWakeCapabilityClients == point)
7606 acceptSystemWakeEvents(false);
7607
7608 kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
7609 pmTracer->tracePoint(point);
7610 }
7611
7612 void IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uintptr_t handler)
7613 {
7614 if (!systemBooting) {
7615 uint32_t detail = ((msgIndex & 0xff) << 24) |
7616 ((msgType & 0xfff) << 12) |
7617 (handler & 0xfff);
7618 pmTracer->traceDetail( detail );
7619 kdebugTrace(kPMLogSleepWakeTracePoint, 0, pmTracer->getTracePhase(), msgType, handler & 0xfff);
7620 }
7621 }
7622
7623
7624 void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
7625 {
7626 size_t reportSize;
7627 void **report = NULL;
7628 uint32_t bktCnt;
7629 uint32_t bktSize;
7630 uint32_t *clientCnt;
7631
7632 ASSERT_GATED();
7633
7634 report = NULL;
7635 if (channel_id == kAssertDelayChID) {
7636 report = &assertOnWakeReport;
7637 bktCnt = kAssertDelayBcktCnt;
7638 bktSize = kAssertDelayBcktSize;
7639 clientCnt = &assertOnWakeClientCnt;
7640 }
7641 else if (channel_id == kSleepDelaysChID) {
7642 report = &sleepDelaysReport;
7643 bktCnt = kSleepDelaysBcktCnt;
7644 bktSize = kSleepDelaysBcktSize;
7645 clientCnt = &sleepDelaysClientCnt;
7646 }
7647
7648 switch (action)
7649 {
7650 case kIOReportEnable:
7651
7652 if (*report) {
7653 (*clientCnt)++;
7654 break;
7655 }
7656
7657 reportSize = HISTREPORT_BUFSIZE(bktCnt);
7658 *report = IOMalloc(reportSize);
7659 if (*report == NULL) {
7660 break;
7661 }
7662 bzero(*report, reportSize);
7663 HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
7664 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
7665
7666 if (channel_id == kAssertDelayChID)
7667 assertOnWakeSecs = 0;
7668
7669 break;
7670
7671 case kIOReportDisable:
7672 if (*clientCnt == 0) {
7673 break;
7674 }
7675 if (*clientCnt == 1)
7676 {
7677 IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
7678 *report = NULL;
7679 }
7680 (*clientCnt)--;
7681
7682 if (channel_id == kAssertDelayChID)
7683 assertOnWakeSecs = -1; // Invalid value to prevent updates
7684
7685 break;
7686
7687 case kIOReportGetDimensions:
7688 if (*report) {
7689 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
7690 }
7691 break;
7692 }
7693
7694 return;
7695 }
7696
7697 IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
7698 IOReportConfigureAction action,
7699 void *result,
7700 void *destination)
7701 {
7702 unsigned cnt;
7703 uint64_t configAction = (uint64_t)action;
7704
7705 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7706 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
7707 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
7708 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
7709 if (action != kIOReportGetDimensions) continue;
7710 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7711 }
7712 else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
7713 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
7714 gIOPMWorkLoop->runAction(
7715 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
7716 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
7717 (void *)configAction, (void *)result);
7718 }
7719 }
7720
7721 return super::configureReport(channelList, action, result, destination);
7722 }
7723
7724 IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
7725 {
7726
7727 uint32_t size2cpy;
7728 void *data2cpy;
7729 void **report;
7730
7731 ASSERT_GATED();
7732
7733 report = NULL;
7734 if (ch_id == kAssertDelayChID) {
7735 report = &assertOnWakeReport;
7736 }
7737 else if (ch_id == kSleepDelaysChID) {
7738 report = &sleepDelaysReport;
7739 }
7740
7741 if (*report == NULL) {
7742 return kIOReturnNotOpen;
7743 }
7744
7745 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
7746 if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
7747 return kIOReturnOverrun;
7748 }
7749
7750 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
7751 dest->appendBytes(data2cpy, size2cpy);
7752
7753 return kIOReturnSuccess;
7754 }
7755
7756 IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
7757 IOReportUpdateAction action,
7758 void *result,
7759 void *destination)
7760 {
7761 uint32_t size2cpy;
7762 void *data2cpy;
7763 uint8_t buf[SIMPLEREPORT_BUFSIZE];
7764 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7765 unsigned cnt;
7766 uint64_t ch_id;
7767
7768 if (action != kIOReportCopyChannelData) goto exit;
7769
7770 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7771 ch_id = channelList->channels[cnt].channel_id ;
7772
7773 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
7774 gIOPMWorkLoop->runAction(
7775 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
7776 (OSObject *)this, (void *)ch_id,
7777 (void *)result, (void *)dest);
7778 continue;
7779
7780 }
7781 else if ((ch_id == kSleepCntChID) ||
7782 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
7783 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
7784 }
7785 else continue;
7786
7787 if (ch_id == kSleepCntChID)
7788 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
7789 else if (ch_id == kDarkWkCntChID)
7790 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
7791 else if (ch_id == kUserWkCntChID)
7792 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
7793
7794 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7795 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7796 dest->appendBytes(data2cpy, size2cpy);
7797 }
7798
7799 exit:
7800 return super::updateReport(channelList, action, result, destination);
7801 }
7802
7803
7804 //******************************************************************************
7805 // PMTraceWorker Class
7806 //
7807 //******************************************************************************
7808
7809 #undef super
7810 #define super OSObject
7811 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
7812
7813 #define kPMBestGuessPCIDevicesCount 25
7814 #define kPMMaxRTCBitfieldSize 32
7815
7816 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
7817 {
7818 PMTraceWorker *me;
7819
7820 me = OSTypeAlloc( PMTraceWorker );
7821 if (!me || !me->init())
7822 {
7823 return NULL;
7824 }
7825
7826 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
7827
7828 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7829 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7830 // this dictionary lazily.
7831 me->owner = owner;
7832 me->pciDeviceBitMappings = NULL;
7833 me->pmTraceWorkerLock = IOLockAlloc();
7834 me->tracePhase = kIOPMTracePointSystemUp;
7835 me->traceData32 = 0;
7836 me->loginWindowData = 0;
7837 me->coreDisplayData = 0;
7838 me->coreGraphicsData = 0;
7839 return me;
7840 }
7841
7842 void PMTraceWorker::RTC_TRACE(void)
7843 {
7844 if (tracePointHandler && tracePointTarget)
7845 {
7846 uint32_t wordA;
7847
7848 IOLockLock(pmTraceWorkerLock);
7849 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
7850 (coreGraphicsData << 8) | tracePhase;
7851 IOLockUnlock(pmTraceWorkerLock);
7852
7853 tracePointHandler( tracePointTarget, traceData32, wordA );
7854 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
7855 }
7856 }
7857
7858 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
7859 {
7860 const OSSymbol * deviceName;
7861 int index = -1;
7862
7863 IOLockLock(pmTraceWorkerLock);
7864
7865 if (!pciDeviceBitMappings)
7866 {
7867 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
7868 if (!pciDeviceBitMappings)
7869 goto exit;
7870 }
7871
7872 // Check for bitmask overflow.
7873 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
7874 goto exit;
7875
7876 if ((deviceName = pciDevice->copyName()) &&
7877 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
7878 pciDeviceBitMappings->setObject(deviceName))
7879 {
7880 index = pciDeviceBitMappings->getCount() - 1;
7881 _LOG("PMTrace PCI array: set object %s => %d\n",
7882 deviceName->getCStringNoCopy(), index);
7883 }
7884 if (deviceName)
7885 deviceName->release();
7886 if (!addedToRegistry && (index >= 0))
7887 addedToRegistry = owner->setProperty("PCITopLevel", this);
7888
7889 exit:
7890 IOLockUnlock(pmTraceWorkerLock);
7891 return index;
7892 }
7893
7894 bool PMTraceWorker::serialize(OSSerialize *s) const
7895 {
7896 bool ok = false;
7897 if (pciDeviceBitMappings)
7898 {
7899 IOLockLock(pmTraceWorkerLock);
7900 ok = pciDeviceBitMappings->serialize(s);
7901 IOLockUnlock(pmTraceWorkerLock);
7902 }
7903 return ok;
7904 }
7905
7906 void PMTraceWorker::tracePoint(uint8_t phase)
7907 {
7908 // clear trace detail when phase begins
7909 if (tracePhase != phase)
7910 traceData32 = 0;
7911
7912 tracePhase = phase;
7913
7914 DLOG("trace point 0x%02x\n", tracePhase);
7915 RTC_TRACE();
7916 }
7917
7918 void PMTraceWorker::traceDetail(uint32_t detail)
7919 {
7920
7921 traceData32 = detail;
7922 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7923
7924 RTC_TRACE();
7925 }
7926
7927 void PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
7928 {
7929 switch (component) {
7930 case kIOPMLoginWindowProgress:
7931 loginWindowData = data & kIOPMLoginWindowProgressMask;
7932 break;
7933 case kIOPMCoreDisplayProgress:
7934 coreDisplayData = data & kIOPMCoreDisplayProgressMask;
7935 break;
7936 case kIOPMCoreGraphicsProgress:
7937 coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
7938 break;
7939 default:
7940 return;
7941 }
7942
7943 DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
7944 RTC_TRACE();
7945 }
7946
7947 void PMTraceWorker::tracePCIPowerChange(
7948 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
7949 {
7950 uint32_t bitMask;
7951 uint32_t expectedFlag;
7952
7953 // Ignore PCI changes outside of system sleep/wake.
7954 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
7955 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
7956 return;
7957
7958 // Only record the WillChange transition when going to sleep,
7959 // and the DidChange on the way up.
7960 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
7961 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
7962 kIOPMDomainWillChange : kIOPMDomainDidChange;
7963 if (changeFlags != expectedFlag)
7964 return;
7965
7966 // Mark this device off in our bitfield
7967 if (bitNum < kPMMaxRTCBitfieldSize)
7968 {
7969 bitMask = (1 << bitNum);
7970
7971 if (kPowerChangeStart == type)
7972 {
7973 traceData32 |= bitMask;
7974 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7975 service->getName(), bitNum, bitMask, traceData32);
7976 owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
7977 }
7978 else
7979 {
7980 traceData32 &= ~bitMask;
7981 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7982 service->getName(), bitNum, bitMask, traceData32);
7983 owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
7984 }
7985
7986 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7987 RTC_TRACE();
7988 }
7989 }
7990
7991 uint64_t PMTraceWorker::getPMStatusCode( )
7992 {
7993 return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase));
7994
7995 }
7996
7997 uint8_t PMTraceWorker::getTracePhase()
7998 {
7999 return tracePhase;
8000 }
8001
8002 uint32_t PMTraceWorker::getTraceData()
8003 {
8004 return traceData32;
8005 }
8006
8007 // MARK: -
8008 // MARK: PMHaltWorker
8009
8010 //******************************************************************************
8011 // PMHaltWorker Class
8012 //
8013 //******************************************************************************
8014
8015 PMHaltWorker * PMHaltWorker::worker( void )
8016 {
8017 PMHaltWorker * me;
8018 IOThread thread;
8019
8020 do {
8021 me = OSTypeAlloc( PMHaltWorker );
8022 if (!me || !me->init())
8023 break;
8024
8025 me->lock = IOLockAlloc();
8026 if (!me->lock)
8027 break;
8028
8029 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
8030 me->retain(); // thread holds extra retain
8031 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
8032 {
8033 me->release();
8034 break;
8035 }
8036 thread_deallocate(thread);
8037 return me;
8038
8039 } while (false);
8040
8041 if (me) me->release();
8042 return 0;
8043 }
8044
8045 void PMHaltWorker::free( void )
8046 {
8047 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8048 if (lock)
8049 {
8050 IOLockFree(lock);
8051 lock = 0;
8052 }
8053 return OSObject::free();
8054 }
8055
8056 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
8057 {
8058 PMHaltWorker * me = (PMHaltWorker *) arg;
8059
8060 IOLockLock( gPMHaltLock );
8061 gPMHaltBusyCount++;
8062 me->depth = gPMHaltDepth;
8063 IOLockUnlock( gPMHaltLock );
8064
8065 while (me->depth >= 0)
8066 {
8067 PMHaltWorker::work( me );
8068
8069 IOLockLock( gPMHaltLock );
8070 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
8071 {
8072 // This is the last thread to finish work on this level,
8073 // inform everyone to start working on next lower level.
8074 gPMHaltDepth--;
8075 me->depth = gPMHaltDepth;
8076 gPMHaltIdleCount = 0;
8077 thread_wakeup((event_t) &gPMHaltIdleCount);
8078 }
8079 else
8080 {
8081 // One or more threads are still working on this level,
8082 // this thread must wait.
8083 me->depth = gPMHaltDepth - 1;
8084 do {
8085 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
8086 } while (me->depth != gPMHaltDepth);
8087 }
8088 IOLockUnlock( gPMHaltLock );
8089 }
8090
8091 // No more work to do, terminate thread
8092 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
8093 thread_wakeup( &gPMHaltDepth );
8094 me->release();
8095 }
8096
8097 void PMHaltWorker::work( PMHaltWorker * me )
8098 {
8099 IOService * service;
8100 OSSet * inner;
8101 AbsoluteTime startTime;
8102 UInt32 deltaTime;
8103 bool timeout;
8104
8105 while (true)
8106 {
8107 service = 0;
8108 timeout = false;
8109
8110 // Claim an unit of work from the shared pool
8111 IOLockLock( gPMHaltLock );
8112 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
8113 if (inner)
8114 {
8115 service = OSDynamicCast(IOService, inner->getAnyObject());
8116 if (service)
8117 {
8118 service->retain();
8119 inner->removeObject(service);
8120 }
8121 }
8122 IOLockUnlock( gPMHaltLock );
8123 if (!service)
8124 break; // no more work at this depth
8125
8126 clock_get_uptime(&startTime);
8127
8128 if (!service->isInactive() &&
8129 service->setProperty(gPMHaltClientAcknowledgeKey, me))
8130 {
8131 IOLockLock(me->lock);
8132 me->startTime = startTime;
8133 me->service = service;
8134 me->timeout = false;
8135 IOLockUnlock(me->lock);
8136
8137 service->systemWillShutdown( gPMHaltMessageType );
8138
8139 // Wait for driver acknowledgement
8140 IOLockLock(me->lock);
8141 while (service->getProperty(gPMHaltClientAcknowledgeKey))
8142 {
8143 IOLockSleep(me->lock, me, THREAD_UNINT);
8144 }
8145 me->service = 0;
8146 timeout = me->timeout;
8147 IOLockUnlock(me->lock);
8148 }
8149
8150 deltaTime = computeDeltaTimeMS(&startTime);
8151 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
8152 (gIOKitDebug & kIOLogPMRootDomain))
8153 {
8154 LOG("%s driver %s (0x%llx) took %u ms\n",
8155 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
8156 "PowerOff" : "Restart",
8157 service->getName(), service->getRegistryEntryID(),
8158 (uint32_t) deltaTime );
8159 }
8160
8161 service->release();
8162 me->visits++;
8163 }
8164 }
8165
8166 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
8167 {
8168 UInt64 nano;
8169 AbsoluteTime startTime;
8170 AbsoluteTime endTime;
8171
8172 endTime = *now;
8173
8174 IOLockLock(me->lock);
8175 if (me->service && !me->timeout)
8176 {
8177 startTime = me->startTime;
8178 nano = 0;
8179 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
8180 {
8181 SUB_ABSOLUTETIME(&endTime, &startTime);
8182 absolutetime_to_nanoseconds(endTime, &nano);
8183 }
8184 if (nano > 3000000000ULL)
8185 {
8186 me->timeout = true;
8187 MSG("%s still waiting on %s\n",
8188 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
8189 "PowerOff" : "Restart",
8190 me->service->getName());
8191 }
8192 }
8193 IOLockUnlock(me->lock);
8194 }
8195
8196 //******************************************************************************
8197 // acknowledgeSystemWillShutdown
8198 //
8199 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8200 //******************************************************************************
8201
8202 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
8203 {
8204 PMHaltWorker * worker;
8205 OSObject * prop;
8206
8207 if (!from)
8208 return;
8209
8210 //DLOG("%s acknowledged\n", from->getName());
8211 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
8212 if (prop)
8213 {
8214 worker = (PMHaltWorker *) prop;
8215 IOLockLock(worker->lock);
8216 from->removeProperty( gPMHaltClientAcknowledgeKey );
8217 thread_wakeup((event_t) worker);
8218 IOLockUnlock(worker->lock);
8219 worker->release();
8220 }
8221 else
8222 {
8223 DLOG("%s acknowledged without worker property\n",
8224 from->getName());
8225 }
8226 }
8227
8228
8229 //******************************************************************************
8230 // notifySystemShutdown
8231 //
8232 // Notify all objects in PM tree that system will shutdown or restart
8233 //******************************************************************************
8234
8235 static void
8236 notifySystemShutdown( IOService * root, uint32_t messageType )
8237 {
8238 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8239 IORegistryIterator * iter;
8240 IORegistryEntry * entry;
8241 IOService * node;
8242 OSSet * inner;
8243 PMHaltWorker * workers[kPMHaltMaxWorkers];
8244 AbsoluteTime deadline;
8245 unsigned int totalNodes = 0;
8246 unsigned int depth;
8247 unsigned int rootDepth;
8248 unsigned int numWorkers;
8249 unsigned int count;
8250 int waitResult;
8251 void * baseFunc;
8252 bool ok;
8253
8254 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
8255
8256 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
8257
8258 // Iterate the entire PM tree starting from root
8259
8260 rootDepth = root->getDepth( gIOPowerPlane );
8261 if (!rootDepth) goto done;
8262
8263 // debug - for repeated test runs
8264 while (PMHaltWorker::metaClass->getInstanceCount())
8265 IOSleep(1);
8266
8267 if (!gPMHaltArray)
8268 {
8269 gPMHaltArray = OSArray::withCapacity(40);
8270 if (!gPMHaltArray) goto done;
8271 }
8272 else // debug
8273 gPMHaltArray->flushCollection();
8274
8275 if (!gPMHaltLock)
8276 {
8277 gPMHaltLock = IOLockAlloc();
8278 if (!gPMHaltLock) goto done;
8279 }
8280
8281 if (!gPMHaltClientAcknowledgeKey)
8282 {
8283 gPMHaltClientAcknowledgeKey =
8284 OSSymbol::withCStringNoCopy("PMShutdown");
8285 if (!gPMHaltClientAcknowledgeKey) goto done;
8286 }
8287
8288 gPMHaltMessageType = messageType;
8289
8290 // Depth-first walk of PM plane
8291
8292 iter = IORegistryIterator::iterateOver(
8293 root, gIOPowerPlane, kIORegistryIterateRecursively);
8294
8295 if (iter)
8296 {
8297 while ((entry = iter->getNextObject()))
8298 {
8299 node = OSDynamicCast(IOService, entry);
8300 if (!node)
8301 continue;
8302
8303 if (baseFunc ==
8304 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
8305 continue;
8306
8307 depth = node->getDepth( gIOPowerPlane );
8308 if (depth <= rootDepth)
8309 continue;
8310
8311 ok = false;
8312
8313 // adjust to zero based depth
8314 depth -= (rootDepth + 1);
8315
8316 // gPMHaltArray is an array of containers, each container
8317 // refers to nodes with the same depth.
8318
8319 count = gPMHaltArray->getCount();
8320 while (depth >= count)
8321 {
8322 // expand array and insert placeholders
8323 gPMHaltArray->setObject(PLACEHOLDER);
8324 count++;
8325 }
8326 count = gPMHaltArray->getCount();
8327 if (depth < count)
8328 {
8329 inner = (OSSet *)gPMHaltArray->getObject(depth);
8330 if (inner == PLACEHOLDER)
8331 {
8332 inner = OSSet::withCapacity(40);
8333 if (inner)
8334 {
8335 gPMHaltArray->replaceObject(depth, inner);
8336 inner->release();
8337 }
8338 }
8339
8340 // PM nodes that appear more than once in the tree will have
8341 // the same depth, OSSet will refuse to add the node twice.
8342 if (inner)
8343 ok = inner->setObject(node);
8344 }
8345 if (!ok)
8346 DLOG("Skipped PM node %s\n", node->getName());
8347 }
8348 iter->release();
8349 }
8350
8351 // debug only
8352 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
8353 {
8354 count = 0;
8355 if (inner != PLACEHOLDER)
8356 count = inner->getCount();
8357 DLOG("Nodes at depth %u = %u\n", i, count);
8358 }
8359
8360 // strip placeholders (not all depths are populated)
8361 numWorkers = 0;
8362 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
8363 {
8364 if (inner == PLACEHOLDER)
8365 {
8366 gPMHaltArray->removeObject(i);
8367 continue;
8368 }
8369 count = inner->getCount();
8370 if (count > numWorkers)
8371 numWorkers = count;
8372 totalNodes += count;
8373 i++;
8374 }
8375
8376 if (gPMHaltArray->getCount() == 0 || !numWorkers)
8377 goto done;
8378
8379 gPMHaltBusyCount = 0;
8380 gPMHaltIdleCount = 0;
8381 gPMHaltDepth = gPMHaltArray->getCount() - 1;
8382
8383 // Create multiple workers (and threads)
8384
8385 if (numWorkers > kPMHaltMaxWorkers)
8386 numWorkers = kPMHaltMaxWorkers;
8387
8388 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8389 totalNodes, gPMHaltArray->getCount(), numWorkers);
8390
8391 for (unsigned int i = 0; i < numWorkers; i++)
8392 workers[i] = PMHaltWorker::worker();
8393
8394 // Wait for workers to exhaust all available work
8395
8396 IOLockLock(gPMHaltLock);
8397 while (gPMHaltDepth >= 0)
8398 {
8399 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
8400
8401 waitResult = IOLockSleepDeadline(
8402 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
8403 if (THREAD_TIMED_OUT == waitResult)
8404 {
8405 AbsoluteTime now;
8406 clock_get_uptime(&now);
8407
8408 IOLockUnlock(gPMHaltLock);
8409 for (unsigned int i = 0 ; i < numWorkers; i++)
8410 {
8411 if (workers[i])
8412 PMHaltWorker::checkTimeout(workers[i], &now);
8413 }
8414 IOLockLock(gPMHaltLock);
8415 }
8416 }
8417 IOLockUnlock(gPMHaltLock);
8418
8419 // Release all workers
8420
8421 for (unsigned int i = 0; i < numWorkers; i++)
8422 {
8423 if (workers[i])
8424 workers[i]->release();
8425 // worker also retained by it's own thread
8426 }
8427
8428 done:
8429 DLOG("%s done\n", __FUNCTION__);
8430 return;
8431 }
8432
8433 // MARK: -
8434 // MARK: Kernel Assertion
8435
8436 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8437
8438 IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
8439 IOPMDriverAssertionType whichAssertionBits,
8440 IOPMDriverAssertionLevel assertionLevel,
8441 IOService *ownerService,
8442 const char *ownerDescription)
8443 {
8444 IOReturn ret;
8445 IOPMDriverAssertionID newAssertion;
8446
8447 if (!pmAssertions)
8448 return 0;
8449
8450 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
8451
8452 if (kIOReturnSuccess == ret)
8453 return newAssertion;
8454 else
8455 return 0;
8456 }
8457
8458 IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
8459 {
8460 if (!pmAssertions)
8461 return kIOReturnInternalError;
8462
8463 return pmAssertions->releaseAssertion(releaseAssertion);
8464 }
8465
8466
8467 IOReturn IOPMrootDomain::setPMAssertionLevel(
8468 IOPMDriverAssertionID assertionID,
8469 IOPMDriverAssertionLevel assertionLevel)
8470 {
8471 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8472 }
8473
8474 IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8475 {
8476 IOPMDriverAssertionType sysLevels;
8477
8478 if (!pmAssertions || whichAssertion == 0)
8479 return kIOPMDriverAssertionLevelOff;
8480
8481 sysLevels = pmAssertions->getActivatedAssertions();
8482
8483 // Check that every bit set in argument 'whichAssertion' is asserted
8484 // in the aggregate bits.
8485 if ((sysLevels & whichAssertion) == whichAssertion)
8486 return kIOPMDriverAssertionLevelOn;
8487 else
8488 return kIOPMDriverAssertionLevelOff;
8489 }
8490
8491 IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
8492 {
8493 if (!pmAssertions)
8494 return kIOReturnNotFound;
8495
8496 return pmAssertions->setUserAssertionLevels(inLevels);
8497 }
8498
8499 bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
8500 {
8501 if (pmAssertions)
8502 {
8503 pmAssertions->publishProperties();
8504 }
8505 return( IOService::serializeProperties(s) );
8506 }
8507
8508 OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8509 {
8510 OSObject *obj = NULL;
8511 obj = IOService::copyProperty(aKey);
8512
8513 if (obj) return obj;
8514
8515 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
8516 sizeof(kIOPMSleepWakeWdogRebootKey))) {
8517 if (swd_flags & SWD_BOOT_BY_SW_WDOG)
8518 return kOSBooleanTrue;
8519 else
8520 return kOSBooleanFalse;
8521
8522 }
8523
8524 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
8525 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
8526 if (swd_flags & SWD_VALID_LOGS)
8527 return kOSBooleanTrue;
8528 else
8529 return kOSBooleanFalse;
8530
8531 }
8532
8533 /*
8534 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8535 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8536 * issued by DisplayWrangler on darkwake.
8537 */
8538 if (!strcmp(aKey, "DesktopMode")) {
8539 if (desktopMode)
8540 return kOSBooleanTrue;
8541 else
8542 return kOSBooleanFalse;
8543 }
8544 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8545 if (displayIdleForDemandSleep) {
8546 return kOSBooleanTrue;
8547 }
8548 else {
8549 return kOSBooleanFalse;
8550 }
8551 }
8552
8553 if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
8554 {
8555 OSArray * array = 0;
8556 WAKEEVENT_LOCK();
8557 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
8558 OSCollection *collection = _systemWakeEventsArray->copyCollection();
8559 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8560 collection->release();
8561 }
8562 }
8563 WAKEEVENT_UNLOCK();
8564 return array;
8565 }
8566
8567 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
8568 {
8569 OSArray * array = 0;
8570 IOLockLock(pmStatsLock);
8571 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
8572 OSCollection *collection = pmStatsAppResponses->copyCollection();
8573 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8574 collection->release();
8575 }
8576 pmStatsAppResponses->flushCollection();
8577 }
8578 IOLockUnlock(pmStatsLock);
8579 return array;
8580 }
8581
8582 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
8583 {
8584 OSArray *idleSleepList = NULL;
8585 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
8586 return idleSleepList;
8587 }
8588
8589 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
8590 {
8591 OSArray *systemSleepList = NULL;
8592 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
8593 return systemSleepList;
8594 }
8595
8596 return NULL;
8597 }
8598
8599 // MARK: -
8600 // MARK: Wake Event Reporting
8601
8602 void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
8603 {
8604 WAKEEVENT_LOCK();
8605 strlcpy(outBuf, gWakeReasonString, bufSize);
8606 WAKEEVENT_UNLOCK();
8607 }
8608
8609 //******************************************************************************
8610 // acceptSystemWakeEvents
8611 //
8612 // Private control for the acceptance of driver wake event claims.
8613 //******************************************************************************
8614
8615 void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
8616 {
8617 bool logWakeReason = false;
8618
8619 WAKEEVENT_LOCK();
8620 if (accept)
8621 {
8622 gWakeReasonString[0] = '\0';
8623 if (!_systemWakeEventsArray)
8624 _systemWakeEventsArray = OSArray::withCapacity(4);
8625 if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
8626 _systemWakeEventsArray->flushCollection();
8627 }
8628 else
8629 {
8630 _acceptSystemWakeEvents = false;
8631 }
8632 WAKEEVENT_UNLOCK();
8633
8634 if (logWakeReason)
8635 MSG("system wake events:%s\n", gWakeReasonString);
8636 }
8637
8638 //******************************************************************************
8639 // claimSystemWakeEvent
8640 //
8641 // For a driver to claim a device is the source/conduit of a system wake event.
8642 //******************************************************************************
8643
8644 void IOPMrootDomain::claimSystemWakeEvent(
8645 IOService * device,
8646 IOOptionBits flags,
8647 const char * reason,
8648 OSObject * details )
8649 {
8650 const OSSymbol * deviceName = 0;
8651 OSNumber * deviceRegId = 0;
8652 OSNumber * claimTime = 0;
8653 OSData * flagsData = 0;
8654 OSString * reasonString = 0;
8655 OSDictionary * d = 0;
8656 uint64_t timestamp;
8657 bool ok = false;
8658
8659 pmEventTimeStamp(&timestamp);
8660
8661 if (!device || !reason) return;
8662
8663 deviceName = device->copyName(gIOServicePlane);
8664 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
8665 claimTime = OSNumber::withNumber(timestamp, 64);
8666 flagsData = OSData::withBytes(&flags, sizeof(flags));
8667 reasonString = OSString::withCString(reason);
8668 d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
8669 if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
8670 goto done;
8671
8672 d->setObject(gIONameKey, deviceName);
8673 d->setObject(gIORegistryEntryIDKey, deviceRegId);
8674 d->setObject(kIOPMWakeEventTimeKey, claimTime);
8675 d->setObject(kIOPMWakeEventFlagsKey, flagsData);
8676 d->setObject(kIOPMWakeEventReasonKey, reasonString);
8677 if (details)
8678 d->setObject(kIOPMWakeEventDetailsKey, details);
8679
8680 WAKEEVENT_LOCK();
8681 if (!gWakeReasonSysctlRegistered)
8682 {
8683 // Lazy registration until the platform driver stops registering
8684 // the same name.
8685 gWakeReasonSysctlRegistered = true;
8686 }
8687 if (_acceptSystemWakeEvents)
8688 {
8689 ok = _systemWakeEventsArray->setObject(d);
8690 if (gWakeReasonString[0] != '\0')
8691 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
8692 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
8693 }
8694 WAKEEVENT_UNLOCK();
8695
8696 done:
8697 if (deviceName) deviceName->release();
8698 if (deviceRegId) deviceRegId->release();
8699 if (claimTime) claimTime->release();
8700 if (flagsData) flagsData->release();
8701 if (reasonString) reasonString->release();
8702 if (d) d->release();
8703 }
8704
8705 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8706
8707 // MARK: -
8708 // MARK: PMSettingHandle
8709
8710 OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
8711
8712 void PMSettingHandle::free( void )
8713 {
8714 if (pmso)
8715 {
8716 pmso->clientHandleFreed();
8717 pmso->release();
8718 pmso = 0;
8719 }
8720
8721 OSObject::free();
8722 }
8723
8724 // MARK: -
8725 // MARK: PMSettingObject
8726
8727 #undef super
8728 #define super OSObject
8729 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
8730
8731 /*
8732 * Static constructor/initializer for PMSettingObject
8733 */
8734 PMSettingObject *PMSettingObject::pmSettingObject(
8735 IOPMrootDomain *parent_arg,
8736 IOPMSettingControllerCallback handler_arg,
8737 OSObject *target_arg,
8738 uintptr_t refcon_arg,
8739 uint32_t supportedPowerSources,
8740 const OSSymbol * settings[],
8741 OSObject **handle_obj)
8742 {
8743 uint32_t settingCount = 0;
8744 PMSettingObject *pmso = 0;
8745 PMSettingHandle *pmsh = 0;
8746
8747 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
8748 return NULL;
8749
8750 // count OSSymbol entries in NULL terminated settings array
8751 while (settings[settingCount]) {
8752 settingCount++;
8753 }
8754 if (0 == settingCount)
8755 return NULL;
8756
8757 pmso = new PMSettingObject;
8758 if (!pmso || !pmso->init())
8759 goto fail;
8760
8761 pmsh = new PMSettingHandle;
8762 if (!pmsh || !pmsh->init())
8763 goto fail;
8764
8765 queue_init(&pmso->calloutQueue);
8766 pmso->parent = parent_arg;
8767 pmso->func = handler_arg;
8768 pmso->target = target_arg;
8769 pmso->refcon = refcon_arg;
8770 pmso->settingCount = settingCount;
8771
8772 pmso->retain(); // handle holds a retain on pmso
8773 pmsh->pmso = pmso;
8774 pmso->pmsh = pmsh;
8775
8776 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
8777 if (pmso->publishedFeatureID) {
8778 for (unsigned int i=0; i<settingCount; i++) {
8779 // Since there is now at least one listener to this setting, publish
8780 // PM root domain support for it.
8781 parent_arg->publishPMSetting( settings[i],
8782 supportedPowerSources, &pmso->publishedFeatureID[i] );
8783 }
8784 }
8785
8786 *handle_obj = pmsh;
8787 return pmso;
8788
8789 fail:
8790 if (pmso) pmso->release();
8791 if (pmsh) pmsh->release();
8792 return NULL;
8793 }
8794
8795 void PMSettingObject::free( void )
8796 {
8797 if (publishedFeatureID) {
8798 for (uint32_t i=0; i<settingCount; i++) {
8799 if (publishedFeatureID[i]) {
8800 parent->removePublishedFeature( publishedFeatureID[i] );
8801 }
8802 }
8803
8804 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
8805 }
8806
8807 super::free();
8808 }
8809
8810 void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
8811 {
8812 (*func)(target, type, object, refcon);
8813 }
8814
8815 void PMSettingObject::clientHandleFreed( void )
8816 {
8817 parent->deregisterPMSettingObject(this);
8818 }
8819
8820 // MARK: -
8821 // MARK: PMAssertionsTracker
8822
8823 //*********************************************************************************
8824 //*********************************************************************************
8825 //*********************************************************************************
8826 // class PMAssertionsTracker Implementation
8827
8828 #define kAssertUniqueIDStart 500
8829
8830 PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
8831 {
8832 PMAssertionsTracker *myself;
8833
8834 myself = new PMAssertionsTracker;
8835
8836 if (myself) {
8837 myself->init();
8838 myself->owner = rootDomain;
8839 myself->issuingUniqueID = kAssertUniqueIDStart;
8840 myself->assertionsArray = OSArray::withCapacity(5);
8841 myself->assertionsKernel = 0;
8842 myself->assertionsUser = 0;
8843 myself->assertionsCombined = 0;
8844 myself->assertionsArrayLock = IOLockAlloc();
8845 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
8846
8847 if (!myself->assertionsArray || !myself->assertionsArrayLock)
8848 myself = NULL;
8849 }
8850
8851 return myself;
8852 }
8853
8854 /* tabulate
8855 * - Update assertionsKernel to reflect the state of all
8856 * assertions in the kernel.
8857 * - Update assertionsCombined to reflect both kernel & user space.
8858 */
8859 void PMAssertionsTracker::tabulate(void)
8860 {
8861 int i;
8862 int count;
8863 PMAssertStruct *_a = NULL;
8864 OSData *_d = NULL;
8865
8866 IOPMDriverAssertionType oldKernel = assertionsKernel;
8867 IOPMDriverAssertionType oldCombined = assertionsCombined;
8868
8869 ASSERT_GATED();
8870
8871 assertionsKernel = 0;
8872 assertionsCombined = 0;
8873
8874 if (!assertionsArray)
8875 return;
8876
8877 if ((count = assertionsArray->getCount()))
8878 {
8879 for (i=0; i<count; i++)
8880 {
8881 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8882 if (_d)
8883 {
8884 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8885 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
8886 assertionsKernel |= _a->assertionBits;
8887 }
8888 }
8889 }
8890
8891 tabulateProducerCount++;
8892 assertionsCombined = assertionsKernel | assertionsUser;
8893
8894 if ((assertionsKernel != oldKernel) ||
8895 (assertionsCombined != oldCombined))
8896 {
8897 owner->evaluateAssertions(assertionsCombined, oldCombined);
8898 }
8899 }
8900
8901 void PMAssertionsTracker::publishProperties( void )
8902 {
8903 OSArray *assertionsSummary = NULL;
8904
8905 if (tabulateConsumerCount != tabulateProducerCount)
8906 {
8907 IOLockLock(assertionsArrayLock);
8908
8909 tabulateConsumerCount = tabulateProducerCount;
8910
8911 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8912 */
8913 assertionsSummary = copyAssertionsArray();
8914 if (assertionsSummary)
8915 {
8916 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
8917 assertionsSummary->release();
8918 }
8919 else
8920 {
8921 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
8922 }
8923
8924 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8925 */
8926 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
8927
8928 IOLockUnlock(assertionsArrayLock);
8929 }
8930 }
8931
8932 PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
8933 {
8934 PMAssertStruct *_a = NULL;
8935 OSData *_d = NULL;
8936 int found = -1;
8937 int count = 0;
8938 int i = 0;
8939
8940 if (assertionsArray
8941 && (count = assertionsArray->getCount()))
8942 {
8943 for (i=0; i<count; i++)
8944 {
8945 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8946 if (_d)
8947 {
8948 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8949 if (_a && (_id == _a->id)) {
8950 found = i;
8951 break;
8952 }
8953 }
8954 }
8955 }
8956
8957 if (-1 == found) {
8958 return NULL;
8959 } else {
8960 if (index)
8961 *index = found;
8962 return _a;
8963 }
8964 }
8965
8966 /* PMAssertionsTracker::handleCreateAssertion
8967 * Perform assertion work on the PM workloop. Do not call directly.
8968 */
8969 IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
8970 {
8971 ASSERT_GATED();
8972
8973 if (newAssertion)
8974 {
8975 IOLockLock(assertionsArrayLock);
8976 assertionsArray->setObject(newAssertion);
8977 IOLockUnlock(assertionsArrayLock);
8978 newAssertion->release();
8979
8980 tabulate();
8981 }
8982 return kIOReturnSuccess;
8983 }
8984
8985 /* PMAssertionsTracker::createAssertion
8986 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8987 * appropiate.
8988 */
8989 IOReturn PMAssertionsTracker::createAssertion(
8990 IOPMDriverAssertionType which,
8991 IOPMDriverAssertionLevel level,
8992 IOService *serviceID,
8993 const char *whoItIs,
8994 IOPMDriverAssertionID *outID)
8995 {
8996 OSData *dataStore = NULL;
8997 PMAssertStruct track;
8998
8999 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9000 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
9001 track.level = level;
9002 track.assertionBits = which;
9003 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
9004 track.ownerService = serviceID;
9005 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
9006 track.modifiedTime = 0;
9007 pmEventTimeStamp(&track.createdTime);
9008
9009 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
9010 if (!dataStore)
9011 {
9012 if (track.ownerString)
9013 track.ownerString->release();
9014 return kIOReturnNoMemory;
9015 }
9016
9017 *outID = track.id;
9018
9019 if (owner && owner->pmPowerStateQueue) {
9020 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
9021 }
9022
9023 return kIOReturnSuccess;
9024 }
9025
9026 /* PMAssertionsTracker::handleReleaseAssertion
9027 * Runs in PM workloop. Do not call directly.
9028 */
9029 IOReturn PMAssertionsTracker::handleReleaseAssertion(
9030 IOPMDriverAssertionID _id)
9031 {
9032 ASSERT_GATED();
9033
9034 int index;
9035 PMAssertStruct *assertStruct = detailsForID(_id, &index);
9036
9037 if (!assertStruct)
9038 return kIOReturnNotFound;
9039
9040 IOLockLock(assertionsArrayLock);
9041 if (assertStruct->ownerString)
9042 assertStruct->ownerString->release();
9043
9044 assertionsArray->removeObject(index);
9045 IOLockUnlock(assertionsArrayLock);
9046
9047 tabulate();
9048 return kIOReturnSuccess;
9049 }
9050
9051 /* PMAssertionsTracker::releaseAssertion
9052 * Releases an assertion and affects system behavior if appropiate.
9053 * Actual work happens on PM workloop.
9054 */
9055 IOReturn PMAssertionsTracker::releaseAssertion(
9056 IOPMDriverAssertionID _id)
9057 {
9058 if (owner && owner->pmPowerStateQueue) {
9059 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
9060 }
9061 return kIOReturnSuccess;
9062 }
9063
9064 /* PMAssertionsTracker::handleSetAssertionLevel
9065 * Runs in PM workloop. Do not call directly.
9066 */
9067 IOReturn PMAssertionsTracker::handleSetAssertionLevel(
9068 IOPMDriverAssertionID _id,
9069 IOPMDriverAssertionLevel _level)
9070 {
9071 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
9072
9073 ASSERT_GATED();
9074
9075 if (!assertStruct) {
9076 return kIOReturnNotFound;
9077 }
9078
9079 IOLockLock(assertionsArrayLock);
9080 pmEventTimeStamp(&assertStruct->modifiedTime);
9081 assertStruct->level = _level;
9082 IOLockUnlock(assertionsArrayLock);
9083
9084 tabulate();
9085 return kIOReturnSuccess;
9086 }
9087
9088 /* PMAssertionsTracker::setAssertionLevel
9089 */
9090 IOReturn PMAssertionsTracker::setAssertionLevel(
9091 IOPMDriverAssertionID _id,
9092 IOPMDriverAssertionLevel _level)
9093 {
9094 if (owner && owner->pmPowerStateQueue) {
9095 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
9096 (void *)(uintptr_t)_level, _id);
9097 }
9098
9099 return kIOReturnSuccess;
9100 }
9101
9102 IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
9103 {
9104 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
9105
9106 ASSERT_GATED();
9107
9108 if (new_user_levels != assertionsUser)
9109 {
9110 assertionsUser = new_user_levels;
9111 DLOG("assertionsUser 0x%llx\n", assertionsUser);
9112 }
9113
9114 tabulate();
9115 return kIOReturnSuccess;
9116 }
9117
9118 IOReturn PMAssertionsTracker::setUserAssertionLevels(
9119 IOPMDriverAssertionType new_user_levels)
9120 {
9121 if (gIOPMWorkLoop) {
9122 gIOPMWorkLoop->runAction(
9123 OSMemberFunctionCast(
9124 IOWorkLoop::Action,
9125 this,
9126 &PMAssertionsTracker::handleSetUserAssertionLevels),
9127 this,
9128 (void *) &new_user_levels, 0, 0, 0);
9129 }
9130
9131 return kIOReturnSuccess;
9132 }
9133
9134
9135 OSArray *PMAssertionsTracker::copyAssertionsArray(void)
9136 {
9137 int count;
9138 int i;
9139 OSArray *outArray = NULL;
9140
9141 if (!assertionsArray ||
9142 (0 == (count = assertionsArray->getCount())) ||
9143 (NULL == (outArray = OSArray::withCapacity(count))))
9144 {
9145 goto exit;
9146 }
9147
9148 for (i=0; i<count; i++)
9149 {
9150 PMAssertStruct *_a = NULL;
9151 OSData *_d = NULL;
9152 OSDictionary *details = NULL;
9153
9154 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9155 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
9156 {
9157 OSNumber *_n = NULL;
9158
9159 details = OSDictionary::withCapacity(7);
9160 if (!details)
9161 continue;
9162
9163 outArray->setObject(details);
9164 details->release();
9165
9166 _n = OSNumber::withNumber(_a->id, 64);
9167 if (_n) {
9168 details->setObject(kIOPMDriverAssertionIDKey, _n);
9169 _n->release();
9170 }
9171 _n = OSNumber::withNumber(_a->createdTime, 64);
9172 if (_n) {
9173 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
9174 _n->release();
9175 }
9176 _n = OSNumber::withNumber(_a->modifiedTime, 64);
9177 if (_n) {
9178 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
9179 _n->release();
9180 }
9181 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
9182 if (_n) {
9183 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
9184 _n->release();
9185 }
9186 _n = OSNumber::withNumber(_a->level, 64);
9187 if (_n) {
9188 details->setObject(kIOPMDriverAssertionLevelKey, _n);
9189 _n->release();
9190 }
9191 _n = OSNumber::withNumber(_a->assertionBits, 64);
9192 if (_n) {
9193 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
9194 _n->release();
9195 }
9196
9197 if (_a->ownerString) {
9198 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
9199 }
9200 }
9201 }
9202
9203 exit:
9204 return outArray;
9205 }
9206
9207 IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
9208 {
9209 return assertionsCombined;
9210 }
9211
9212 IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
9213 IOPMDriverAssertionType type)
9214 {
9215 if (type && ((type & assertionsKernel) == assertionsKernel))
9216 {
9217 return kIOPMDriverAssertionLevelOn;
9218 } else {
9219 return kIOPMDriverAssertionLevelOff;
9220 }
9221 }
9222
9223 //*********************************************************************************
9224 //*********************************************************************************
9225 //*********************************************************************************
9226
9227
9228 static void pmEventTimeStamp(uint64_t *recordTS)
9229 {
9230 clock_sec_t tsec;
9231 clock_usec_t tusec;
9232
9233 if (!recordTS)
9234 return;
9235
9236 // We assume tsec fits into 32 bits; 32 bits holds enough
9237 // seconds for 136 years since the epoch in 1970.
9238 clock_get_calendar_microtime(&tsec, &tusec);
9239
9240
9241 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9242 *recordTS = 0;
9243 *recordTS |= (uint32_t)tusec;
9244 *recordTS |= ((uint64_t)tsec << 32);
9245
9246 return;
9247 }
9248
9249 // MARK: -
9250 // MARK: IORootParent
9251
9252 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9253
9254 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
9255
9256 // The reason that root domain needs a root parent is to facilitate demand
9257 // sleep, since a power change from the root parent cannot be vetoed.
9258 //
9259 // The above statement is no longer true since root domain now performs
9260 // demand sleep using overrides. But root parent remains to avoid changing
9261 // the power tree stacking. Root parent is parked at the max power state.
9262
9263
9264 static IOPMPowerState patriarchPowerStates[2] =
9265 {
9266 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9267 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9268 };
9269
9270 void IORootParent::initialize( void )
9271 {
9272 }
9273
9274 bool IORootParent::start( IOService * nub )
9275 {
9276 IOService::start(nub);
9277 attachToParent( getRegistryRoot(), gIOPowerPlane );
9278 PMinit();
9279 registerPowerDriver(this, patriarchPowerStates, 2);
9280 makeUsable();
9281 return true;
9282 }
9283
9284 void IORootParent::shutDownSystem( void )
9285 {
9286 }
9287
9288 void IORootParent::restartSystem( void )
9289 {
9290 }
9291
9292 void IORootParent::sleepSystem( void )
9293 {
9294 }
9295
9296 void IORootParent::dozeSystem( void )
9297 {
9298 }
9299
9300 void IORootParent::sleepToDoze( void )
9301 {
9302 }
9303
9304 void IORootParent::wakeSystem( void )
9305 {
9306 }
9307
9308 OSObject * IORootParent::copyProperty( const char * aKey) const
9309 {
9310 return (IOService::copyProperty(aKey));
9311 }
9312
9313
9314 #if defined(__i386__) || defined(__x86_64__)
9315 IOReturn IOPMrootDomain::restartWithStackshot()
9316 {
9317 if ((swd_flags & SWD_WDOG_ENABLED) == 0)
9318 return kIOReturnError;
9319
9320 takeStackshot(true, true, false);
9321
9322 return kIOReturnSuccess;
9323 }
9324
9325 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
9326 {
9327 takeStackshot(wdogTrigger, false, false);
9328 }
9329
9330 void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
9331 {
9332 swd_hdr * hdr = NULL;
9333 addr64_t data[3];
9334 int wdog_panic = -1;
9335 int cnt = 0;
9336 pid_t pid = 0;
9337 kern_return_t kr = KERN_SUCCESS;
9338 uint32_t flags;
9339
9340 char * dstAddr;
9341 uint32_t size;
9342 uint32_t bytesRemaining;
9343 unsigned bytesWritten = 0;
9344 unsigned totalBytes = 0;
9345 unsigned int len;
9346 OSString * UUIDstring = NULL;
9347 uint64_t code;
9348 IOMemoryMap * logBufMap = NULL;
9349
9350
9351 uint32_t bufSize;
9352 uint32_t initialStackSize;
9353
9354 if (isSpinDump) {
9355 if (_systemTransitionType != kSystemTransitionSleep &&
9356 _systemTransitionType != kSystemTransitionWake)
9357 return;
9358 } else {
9359 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9360 return;
9361 }
9362
9363 if (wdogTrigger) {
9364 PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic));
9365 if (wdog_panic == 1) {
9366 // If boot-arg specifies to panic then panic.
9367 panic("Sleep/Wake hang detected\n");
9368 return;
9369 }
9370 else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9371 // If current boot is due to this watch dog trigger restart in previous boot,
9372 // then don't trigger again until at least 1 successful sleep & wake.
9373 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
9374 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9375 PEHaltRestart(kPEHaltCPU);
9376 return;
9377 }
9378 }
9379
9380 }
9381
9382 if (isSpinDump) {
9383 if (gSpinDumpBufferFull)
9384 return;
9385 if (swd_spindump_buffer == NULL) {
9386 sleepWakeDebugSpinDumpMemAlloc();
9387 if (swd_spindump_buffer == NULL) return;
9388 }
9389
9390 bufSize = SWD_SPINDUMP_SIZE;
9391 initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
9392 } else {
9393 if (sleepWakeDebugIsWdogEnabled() == false)
9394 return;
9395
9396 if (swd_buffer == NULL) {
9397 sleepWakeDebugMemAlloc();
9398 if (swd_buffer == NULL) return;
9399 }
9400
9401 bufSize = SWD_BUF_SIZE;
9402 initialStackSize = SWD_INITIAL_STACK_SIZE;
9403 }
9404
9405 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9406 return;
9407
9408 if (isSpinDump) {
9409 hdr = (swd_hdr *)swd_spindump_buffer;
9410 }
9411 else {
9412 hdr = (swd_hdr *)swd_buffer;
9413 }
9414
9415 memset(hdr->UUID, 0x20, sizeof(hdr->UUID));
9416 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
9417
9418 if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) {
9419 const char *str = UUIDstring->getCStringNoCopy();
9420 snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s", str);
9421 }
9422 else {
9423 DLOG("Data for current UUID already exists\n");
9424 goto exit;
9425 }
9426 }
9427
9428 dstAddr = (char*)hdr + hdr->spindump_offset;
9429 bytesRemaining = bufSize - hdr->spindump_offset;
9430
9431 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9432 hdr->is_osx_watchdog = isOSXWatchdog;
9433
9434 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
9435
9436 flags = STACKSHOT_KCDATA_FORMAT|STACKSHOT_NO_IO_STATS|STACKSHOT_SAVE_KEXT_LOADINFO;
9437 while (kr == KERN_SUCCESS) {
9438
9439 if (cnt == 0) {
9440 /*
9441 * Take stackshot of all process on first sample. Size is restricted
9442 * to SWD_INITIAL_STACK_SIZE
9443 */
9444 pid = -1;
9445 size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
9446 flags |= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY;
9447 }
9448 else {
9449 /* Take sample of kernel threads only */
9450 pid = 0;
9451 size = bytesRemaining;
9452 }
9453
9454 kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, &bytesWritten);
9455 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9456 kr, pid, size, flags, bytesWritten);
9457 if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
9458 if (pid == -1) {
9459 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9460 // Continue to take stackshot of just kernel threads
9461 ++cnt;
9462 kr = KERN_SUCCESS;
9463 continue;
9464 }
9465 else if (totalBytes == 0) {
9466 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr, size, flags);
9467 }
9468 }
9469
9470 dstAddr += bytesWritten;
9471 totalBytes += bytesWritten;
9472 bytesRemaining -= bytesWritten;
9473
9474 if (++cnt == 10) {
9475 break;
9476 }
9477 IOSleep(10); // 10 ms
9478 }
9479
9480 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
9481
9482
9483 memset(hdr->spindump_status, 0x20, sizeof(hdr->spindump_status));
9484 code = pmTracer->getPMStatusCode();
9485 memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode));
9486 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x",
9487 (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
9488 memset(hdr->reason, 0x20, sizeof(hdr->reason));
9489 if (isSpinDump) {
9490 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: PSC Delay\n\n");
9491 gRootDomain->swd_lock = 0;
9492 gSpinDumpBufferFull = true;
9493 return;
9494 }
9495 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
9496
9497
9498 data[0] = round_page(sizeof(swd_hdr) + hdr->spindump_size);
9499 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9500 data[1] = hdr->crc = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size);
9501 data[2] = kvtophys((vm_offset_t)swd_buffer);
9502 len = sizeof(addr64_t)*3;
9503 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9504 data[0], data[1], data[2]);
9505
9506 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false)
9507 {
9508 DLOG("Failed to update nvram boot-args\n");
9509 goto exit;
9510 }
9511
9512 exit:
9513
9514 gRootDomain->swd_lock = 0;
9515
9516 if (wdogTrigger) {
9517 IOLog("Restarting to collect Sleep wake debug logs\n");
9518 PEHaltRestart(kPERestartCPU);
9519 }
9520 else {
9521 logBufMap = sleepWakeDebugRetrieve();
9522 if (logBufMap) {
9523 sleepWakeDebugDumpFromMem(logBufMap);
9524 logBufMap->release();
9525 logBufMap = 0;
9526 }
9527 }
9528 }
9529
9530 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9531 {
9532 vm_size_t size = SWD_BUF_SIZE;
9533
9534 swd_hdr *hdr = NULL;
9535
9536 IOBufferMemoryDescriptor *memDesc = NULL;
9537
9538
9539 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9540 return;
9541
9542 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9543 return;
9544
9545 // Try allocating above 4GB. If that fails, try at 2GB
9546 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9547 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9548 size, 0xFFFFFFFF00000000ULL);
9549 if (!memDesc) {
9550 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9551 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9552 size, 0xFFFFFFFF10000000ULL);
9553 }
9554
9555 if (memDesc == NULL)
9556 {
9557 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9558 goto exit;
9559 }
9560
9561
9562 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9563 memset(hdr, 0, sizeof(swd_hdr));
9564
9565 hdr->signature = SWD_HDR_SIGNATURE;
9566 hdr->alloc_size = size;
9567
9568 hdr->spindump_offset = sizeof(swd_hdr);
9569 swd_buffer = (void *)hdr;
9570 swd_memDesc = memDesc;
9571 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
9572
9573 exit:
9574 gRootDomain->swd_lock = 0;
9575 }
9576
9577 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9578 {
9579 vm_size_t size = SWD_SPINDUMP_SIZE;
9580
9581 swd_hdr *hdr = NULL;
9582
9583 IOBufferMemoryDescriptor *memDesc = NULL;
9584
9585 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9586 return;
9587
9588 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
9589 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
9590 SWD_SPINDUMP_SIZE);
9591
9592 if (memDesc == NULL)
9593 {
9594 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9595 goto exit;
9596 }
9597
9598
9599 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9600 memset(hdr, 0, sizeof(swd_hdr));
9601
9602 hdr->signature = SWD_HDR_SIGNATURE;
9603 hdr->alloc_size = size;
9604
9605 hdr->spindump_offset = sizeof(swd_hdr);
9606 swd_spindump_buffer = (void *)hdr;
9607
9608 exit:
9609 gRootDomain->swd_lock = 0;
9610 }
9611
9612 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9613 {
9614 swd_flags |= SWD_WDOG_ENABLED;
9615 if (!swd_buffer)
9616 sleepWakeDebugMemAlloc();
9617 }
9618
9619 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9620 {
9621 return ((swd_flags & SWD_WDOG_ENABLED) &&
9622 !systemBooting && !systemShutdown && !gWillShutdown);
9623 }
9624
9625 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9626 {
9627 swd_hdr *hdr = NULL;
9628 errno_t error = EIO;
9629
9630 if (swd_spindump_buffer && gSpinDumpBufferFull) {
9631 hdr = (swd_hdr *)swd_spindump_buffer;
9632
9633 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9634 (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
9635
9636 if (error) return;
9637
9638 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9639 (char*)hdr+offsetof(swd_hdr, UUID),
9640 sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
9641
9642 gSpinDumpBufferFull = false;
9643 }
9644 }
9645
9646 errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9647 {
9648 struct vnode *vp = NULL;
9649 vfs_context_t ctx = vfs_context_create(vfs_context_current());
9650 kauth_cred_t cred = vfs_context_ucred(ctx);
9651 struct vnode_attr va;
9652 errno_t error = EIO;
9653
9654 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
9655 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9656 {
9657 IOLog("Failed to open the file %s\n", name);
9658 swd_flags |= SWD_FILEOP_ERROR;
9659 goto exit;
9660 }
9661 VATTR_INIT(&va);
9662 VATTR_WANTED(&va, va_nlink);
9663 /* Don't dump to non-regular files or files with links. */
9664 if (vp->v_type != VREG ||
9665 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9666 IOLog("Bailing as this is not a regular file\n");
9667 swd_flags |= SWD_FILEOP_ERROR;
9668 goto exit;
9669 }
9670 VATTR_INIT(&va);
9671 VATTR_SET(&va, va_data_size, 0);
9672 vnode_setattr(vp, &va, ctx);
9673
9674
9675 if (buf != NULL) {
9676 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
9677 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx));
9678 if (error != 0) {
9679 IOLog("Failed to save sleep wake log. err 0x%x\n", error);
9680 swd_flags |= SWD_FILEOP_ERROR;
9681 }
9682 else {
9683 DLOG("Saved %d bytes to file %s\n",len, name);
9684 }
9685 }
9686
9687 exit:
9688 if (vp) vnode_close(vp, FWRITE, ctx);
9689 if (ctx) vfs_context_rele(ctx);
9690
9691 return error;
9692
9693 }
9694
9695 errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
9696 struct vnode *srcVp,
9697 vfs_context_t srcCtx,
9698 char *tmpBuf, uint64_t tmpBufSize,
9699 uint64_t srcOffset,
9700 const char *dstFname,
9701 uint64_t numBytes,
9702 uint32_t crc)
9703 {
9704 struct vnode *vp = NULL;
9705 vfs_context_t ctx = vfs_context_create(vfs_context_current());
9706 struct vnode_attr va;
9707 errno_t error = EIO;
9708 uint64_t bytesToRead, bytesToWrite;
9709 uint64_t readFileOffset, writeFileOffset, srcDataOffset;
9710 uint32_t newcrc = 0;
9711
9712 if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW),
9713 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9714 {
9715 IOLog("Failed to open the file %s\n", dstFname);
9716 swd_flags |= SWD_FILEOP_ERROR;
9717 goto exit;
9718 }
9719 VATTR_INIT(&va);
9720 VATTR_WANTED(&va, va_nlink);
9721 /* Don't dump to non-regular files or files with links. */
9722 if (vp->v_type != VREG ||
9723 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9724 IOLog("Bailing as this is not a regular file\n");
9725 swd_flags |= SWD_FILEOP_ERROR;
9726 goto exit;
9727 }
9728 VATTR_INIT(&va);
9729 VATTR_SET(&va, va_data_size, 0);
9730 vnode_setattr(vp, &va, ctx);
9731
9732 writeFileOffset = 0;
9733 while(numBytes) {
9734 bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
9735 readFileOffset = trunc_page(srcOffset);
9736
9737 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead, readFileOffset);
9738 error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
9739 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9740 vfs_context_ucred(srcCtx), (int *) 0,
9741 vfs_context_proc(srcCtx));
9742 if (error) {
9743 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
9744 swd_flags |= SWD_FILEOP_ERROR;
9745 break;
9746 }
9747
9748 srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset);
9749 bytesToWrite = bytesToRead - (srcOffset - readFileOffset);
9750 if (bytesToWrite > numBytes) bytesToWrite = numBytes;
9751
9752 if (crc) {
9753 newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
9754 }
9755 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite, writeFileOffset);
9756 error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
9757 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
9758 vfs_context_ucred(ctx), (int *) 0,
9759 vfs_context_proc(ctx));
9760 if (error) {
9761 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
9762 swd_flags |= SWD_FILEOP_ERROR;
9763 break;
9764 }
9765
9766 writeFileOffset += bytesToWrite;
9767 numBytes -= bytesToWrite;
9768 srcOffset += bytesToWrite;
9769
9770 }
9771 if (crc != newcrc) {
9772 /* Set stackshot size to 0 if crc doesn't match */
9773 VATTR_INIT(&va);
9774 VATTR_SET(&va, va_data_size, 0);
9775 vnode_setattr(vp, &va, ctx);
9776
9777 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
9778 swd_flags |= SWD_DATA_CRC_ERROR;
9779 error = EFAULT;
9780 }
9781 exit:
9782 if (vp) {
9783 error = vnode_close(vp, FWRITE, ctx);
9784 DLOG("vnode_close on file %s returned 0x%x\n",dstFname, error);
9785 }
9786 if (ctx) vfs_context_rele(ctx);
9787
9788 return error;
9789
9790
9791
9792 }
9793 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname, vfs_context_t *ctx,
9794 void *tmpBuf, struct vnode **vp)
9795 {
9796 int rc;
9797 uint64_t hdrOffset;
9798 uint32_t error = 0;
9799
9800 struct vnode_attr va;
9801 IOHibernateImageHeader *imageHdr;
9802
9803 *vp = NULL;
9804 if (vnode_open(fname, (FREAD | O_NOFOLLOW), 0,
9805 VNODE_LOOKUP_NOFOLLOW, vp, *ctx) != 0)
9806 {
9807 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname);
9808 goto err;
9809 }
9810 VATTR_INIT(&va);
9811 VATTR_WANTED(&va, va_nlink);
9812 VATTR_WANTED(&va, va_data_alloc);
9813 if ((*vp)->v_type != VREG ||
9814 vnode_getattr((*vp), &va, *ctx) || va.va_nlink != 1) {
9815 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname);
9816 error = SWD_FILEOP_ERROR;
9817 goto err;
9818 }
9819
9820 /* Read the sleepimage file header */
9821 rc = vn_rdwr(UIO_READ, *vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
9822 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9823 vfs_context_ucred(*ctx), (int *) 0,
9824 vfs_context_proc(*ctx));
9825 if (rc != 0) {
9826 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9827 round_page(sizeof(IOHibernateImageHeader)), rc, fname);
9828 error = SWD_FILEOP_ERROR;
9829 goto err;
9830 }
9831
9832 imageHdr = ((IOHibernateImageHeader *)tmpBuf);
9833 if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
9834 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9835 fname, imageHdr->signature);
9836 error = SWD_HDR_SIGNATURE_ERROR;
9837 goto err;
9838 }
9839
9840 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9841 hdrOffset = imageHdr->deviceBlockSize;
9842 if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
9843 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9844 va.va_data_alloc, fname);
9845 error = SWD_HDR_SIZE_ERROR;
9846 goto err;
9847 }
9848
9849 return 0;
9850
9851 err:
9852 if (*vp) vnode_close(*vp, FREAD, *ctx);
9853 *vp = NULL;
9854
9855 return error;
9856 }
9857
9858 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9859 {
9860 #if HIBERNATION
9861 int rc;
9862 char hibernateFilename[MAXPATHLEN+1];
9863 void *tmpBuf;
9864 swd_hdr *hdr = NULL;
9865 uint32_t stacksSize, logSize;
9866 uint64_t tmpBufSize;
9867 uint64_t hdrOffset, stacksOffset, logOffset;
9868 errno_t error = EIO;
9869 OSObject *obj = NULL;
9870 OSString *str = NULL;
9871 OSNumber *failStat = NULL;
9872 struct vnode *vp = NULL;
9873 vfs_context_t ctx = NULL;
9874 const char *stacksFname, *logFname;
9875
9876 IOBufferMemoryDescriptor *tmpBufDesc = NULL;
9877
9878 DLOG("sleepWakeDebugDumpFromFile\n");
9879 if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
9880 return;
9881
9882 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9883 return;
9884
9885
9886 /* Allocate a temp buffer to copy data between files */
9887 tmpBufSize = 2*4096;
9888 tmpBufDesc = IOBufferMemoryDescriptor::
9889 inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone,
9890 tmpBufSize, PAGE_SIZE);
9891
9892 if (!tmpBufDesc) {
9893 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9894 goto exit;
9895 }
9896
9897 tmpBuf = tmpBufDesc->getBytesNoCopy();
9898
9899 ctx = vfs_context_create(vfs_context_current());
9900
9901 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9902 swd_flags |= checkForValidDebugData(kSleepWakeStackBinFilename, &ctx, tmpBuf, &vp);
9903 if (vp == NULL) {
9904 /* Check if the debug data is saved to hibernation file */
9905 hibernateFilename[0] = 0;
9906 if ((obj = copyProperty(kIOHibernateFileKey)))
9907 {
9908 if ((str = OSDynamicCast(OSString, obj)))
9909 strlcpy(hibernateFilename, str->getCStringNoCopy(),
9910 sizeof(hibernateFilename));
9911 obj->release();
9912 }
9913 if (!hibernateFilename[0]) {
9914 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9915 goto exit;
9916 }
9917
9918 swd_flags |= checkForValidDebugData(hibernateFilename, &ctx, tmpBuf, &vp);
9919 if (vp == NULL) {
9920 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9921 goto exit;
9922 }
9923 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename);
9924 }
9925 else {
9926 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename);
9927 }
9928
9929 hdrOffset = ((IOHibernateImageHeader *)tmpBuf)->deviceBlockSize;
9930
9931 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
9932 /* Read the sleep/wake debug header(swd_hdr) */
9933 rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
9934 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9935 vfs_context_ucred(ctx), (int *) 0,
9936 vfs_context_proc(ctx));
9937 if (rc != 0) {
9938 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9939 round_page(sizeof(swd_hdr)), rc);
9940 swd_flags |= SWD_FILEOP_ERROR;
9941 goto exit;
9942 }
9943
9944 hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset)));
9945 if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) ||
9946 (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
9947 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9948 hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
9949 swd_flags |= SWD_BUF_SIZE_ERROR;
9950 goto exit;
9951 }
9952 stacksSize = hdr->spindump_size;
9953
9954 /* Get stacks & log offsets in the image file */
9955 stacksOffset = hdrOffset + hdr->spindump_offset;
9956 logOffset = hdrOffset + offsetof(swd_hdr, UUID);
9957 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9958 stacksFname = getDumpStackFilename(hdr);
9959 logFname = getDumpLogFilename(hdr);
9960
9961 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
9962 stacksFname, stacksSize, hdr->crc);
9963 if (error == EFAULT) {
9964 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9965 goto exit;
9966 }
9967 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset,
9968 logFname, logSize, 0);
9969 if (error) {
9970 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
9971 goto exit;
9972 }
9973 exit:
9974 if (error) {
9975 // Write just the SleepWakeLog.dump with failure code
9976 uint64_t fcode = 0;
9977 const char *fname;
9978 swd_hdr hdrCopy;
9979 char *offset = NULL;
9980 int size;
9981
9982 hdr = &hdrCopy;
9983 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9984 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
9985 fcode = failStat->unsigned64BitValue();
9986 fname = kSleepWakeLogFilename;
9987 }
9988 else {
9989 fname = kAppleOSXWatchdogLogFilename;
9990 }
9991
9992 offset = (char*)hdr+offsetof(swd_hdr, UUID);
9993 size = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9994 memset(offset, 0x20, size); // Fill with spaces
9995
9996
9997 snprintf(hdr->spindump_status, sizeof(hdr->spindump_status), "\nstatus: 0x%x", swd_flags);
9998 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: 0x%llx", fcode);
9999 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
10000 sleepWakeDebugSaveFile(fname, offset, size);
10001
10002 }
10003 gRootDomain->swd_lock = 0;
10004
10005 if (vp) vnode_close(vp, FREAD, ctx);
10006 if (ctx) vfs_context_rele(ctx);
10007 if (tmpBufDesc) tmpBufDesc->release();
10008 #endif /* HIBERNATION */
10009 }
10010
10011 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
10012 {
10013 IOVirtualAddress srcBuf = NULL;
10014 char *stackBuf = NULL, *logOffset = NULL;
10015 int logSize = 0;
10016
10017 errno_t error = EIO;
10018 uint64_t bufSize = 0;
10019 swd_hdr *hdr = NULL;
10020 OSNumber *failStat = NULL;
10021
10022 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10023 return;
10024
10025 if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) )
10026 {
10027 DLOG("Nothing saved to dump to file\n");
10028 goto exit;
10029 }
10030
10031 hdr = (swd_hdr *)srcBuf;
10032 bufSize = logBufMap->getLength();
10033 if (bufSize <= sizeof(swd_hdr))
10034 {
10035 IOLog("SleepWake log buffer size is invalid\n");
10036 swd_flags |= SWD_BUF_SIZE_ERROR;
10037 goto exit;
10038 }
10039
10040 stackBuf = (char*)hdr+hdr->spindump_offset;
10041
10042 error = sleepWakeDebugSaveFile(getDumpStackFilename(hdr), stackBuf, hdr->spindump_size);
10043 if (error) goto exit;
10044
10045 logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
10046 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
10047
10048 error = sleepWakeDebugSaveFile(getDumpLogFilename(hdr), logOffset, logSize);
10049 if (error) goto exit;
10050
10051 hdr->spindump_size = 0;
10052 error = 0;
10053
10054 exit:
10055 if (error) {
10056 // Write just the SleepWakeLog.dump with failure code
10057 uint64_t fcode = 0;
10058 const char *sname, *lname;
10059 swd_hdr hdrCopy;
10060
10061 /* Try writing an empty stacks file */
10062 hdr = &hdrCopy;
10063 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
10064 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
10065 fcode = failStat->unsigned64BitValue();
10066 lname = kSleepWakeLogFilename;
10067 sname = kSleepWakeStackFilename;
10068 }
10069 else {
10070 lname = kAppleOSXWatchdogLogFilename;
10071 sname= kAppleOSXWatchdogStackFilename;
10072 }
10073
10074 sleepWakeDebugSaveFile(sname, NULL, 0);
10075
10076 logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
10077 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
10078 memset(logOffset, 0x20, logSize); // Fill with spaces
10079
10080
10081 snprintf(hdr->spindump_status, sizeof(hdr->spindump_status), "\nstatus: 0x%x", swd_flags);
10082 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: 0x%llx", fcode);
10083 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
10084 sleepWakeDebugSaveFile(lname, logOffset, logSize);
10085 }
10086
10087 gRootDomain->swd_lock = 0;
10088 }
10089
10090 IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
10091 {
10092 IOVirtualAddress vaddr = NULL;
10093 IOMemoryDescriptor * desc = NULL;
10094 IOMemoryMap * logBufMap = NULL;
10095
10096 uint32_t len;
10097 addr64_t data[3];
10098 uint64_t bufSize = 0;
10099 uint64_t crc = 0;
10100 uint64_t newcrc = 0;
10101 uint64_t paddr = 0;
10102 swd_hdr *hdr = NULL;
10103 bool ret = false;
10104 char str[20];
10105
10106
10107 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10108 return NULL;
10109
10110 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, 0, &len)) {
10111 DLOG("No sleepWakeDebug note to read\n");
10112 goto exit;
10113 }
10114
10115 if (len == strlen("sleepimage")) {
10116 str[0] = 0;
10117 PEReadNVRAMProperty(kIOSleepWakeDebugKey, str, &len);
10118
10119 if (!strncmp((char*)str, "sleepimage", strlen("sleepimage"))) {
10120 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10121 swd_flags |= SWD_LOGS_IN_FILE|SWD_VALID_LOGS;
10122 goto exit;
10123 }
10124 }
10125 else if (len == sizeof(addr64_t)*3) {
10126 PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len);
10127 }
10128 else {
10129 DLOG("Invalid sleepWakeDebug note length(%d)\n", len);
10130 goto exit;
10131 }
10132
10133
10134
10135 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10136 data[0], data[1], data[2]);
10137 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10138 bufSize = data[0];
10139 crc = data[1];
10140 paddr = data[2];
10141 if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
10142 {
10143 IOLog("SleepWake log buffer size is invalid\n");
10144 swd_flags |= SWD_BUF_SIZE_ERROR;
10145 return NULL;
10146 }
10147
10148 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10149 bufSize, crc, paddr);
10150
10151
10152 desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize,
10153 kIODirectionOutIn | kIOMemoryMapperNone, NULL);
10154 if (desc == NULL)
10155 {
10156 IOLog("Fail to map SleepWake log buffer\n");
10157 swd_flags |= SWD_INTERNAL_FAILURE;
10158 goto exit;
10159 }
10160
10161 logBufMap = desc->map();
10162
10163 vaddr = logBufMap->getVirtualAddress();
10164
10165
10166 if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
10167 IOLog("Fail to map SleepWake log buffer\n");
10168 swd_flags |= SWD_INTERNAL_FAILURE;
10169 goto exit;
10170 }
10171
10172 hdr = (swd_hdr *)vaddr;
10173 if (hdr->spindump_offset+hdr->spindump_size > bufSize)
10174 {
10175 IOLog("SleepWake log header size is invalid\n");
10176 swd_flags |= SWD_HDR_SIZE_ERROR;
10177 goto exit;
10178 }
10179
10180 hdr->crc = crc;
10181 newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset),
10182 hdr->spindump_size);
10183 if (newcrc != crc) {
10184 IOLog("SleepWake log buffer contents are invalid\n");
10185 swd_flags |= SWD_DATA_CRC_ERROR;
10186 goto exit;
10187 }
10188
10189 ret = true;
10190 swd_flags |= SWD_LOGS_IN_MEM | SWD_VALID_LOGS;
10191
10192
10193 exit:
10194 PERemoveNVRAMProperty(kIOSleepWakeDebugKey);
10195 if (!ret) {
10196 if (logBufMap) logBufMap->release();
10197 logBufMap = 0;
10198 }
10199 if (desc) desc->release();
10200 gRootDomain->swd_lock = 0;
10201
10202 return logBufMap;
10203 }
10204
10205 #else
10206
10207 void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
10208 {
10209 uint32_t wdog_panic = 1;
10210
10211 if (restart) {
10212 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
10213 (wdog_panic == 0)) {
10214 return;
10215 }
10216 panic("Sleep/Wake hang detected\n");
10217 return;
10218 }
10219 }
10220
10221 void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
10222 {
10223 #pragma unused(restart)
10224 #pragma unused(isOSXWatchdog)
10225 }
10226
10227 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10228 {
10229 }
10230 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *map)
10231 {
10232 }
10233 errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
10234 struct vnode *srcVp,
10235 vfs_context_t srcCtx,
10236 char *tmpBuf, uint64_t tmpBufSize,
10237 uint64_t srcOffset,
10238 const char *dstFname,
10239 uint64_t numBytes,
10240 uint32_t crc)
10241 {
10242 return EIO;
10243 }
10244
10245 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10246 {
10247 }
10248
10249 IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
10250 {
10251 return NULL;
10252 }
10253
10254 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10255 {
10256 }
10257
10258 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10259 {
10260 return false;
10261 }
10262
10263 errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
10264 {
10265 return 0;
10266 }
10267
10268 #endif
10269