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