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