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