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