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