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