]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
9a5ccd20bc70603c99d5d5892f873b2582dc82ef
[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 return NULL;
5476 }
5477 if (pmPowerStateQueue)
5478 {
5479 notifier->ackTimeoutCnt = 0;
5480 if (isSystemCapabilityClient)
5481 {
5482 notifier->retain();
5483 if (pmPowerStateQueue->submitPowerEvent(
5484 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
5485 notifier->release();
5486 }
5487
5488 if (isKernelCapabilityClient)
5489 {
5490 notifier->retain();
5491 if (pmPowerStateQueue->submitPowerEvent(
5492 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
5493 notifier->release();
5494 }
5495 }
5496
5497 return notifier;
5498 }
5499
5500 //******************************************************************************
5501 // systemMessageFilter
5502 //
5503 //******************************************************************************
5504
5505 bool IOPMrootDomain::systemMessageFilter(
5506 void * object, void * arg1, void * arg2, void * arg3 )
5507 {
5508 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
5509 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
5510 bool isCapClient = false;
5511 bool allow = false;
5512
5513 do {
5514 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
5515 (!isCapMsg || !_joinedCapabilityClients ||
5516 !_joinedCapabilityClients->containsObject((OSObject *) object)))
5517 break;
5518
5519 // Capability change message for app and kernel clients.
5520
5521 if (isCapMsg)
5522 {
5523 if ((context->notifyType == kNotifyPriority) ||
5524 (context->notifyType == kNotifyCapabilityChangePriority))
5525 isCapClient = true;
5526
5527 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5528 (object == (void *) systemCapabilityNotifier))
5529 isCapClient = true;
5530 }
5531
5532 if (isCapClient)
5533 {
5534 IOPMSystemCapabilityChangeParameters * capArgs =
5535 (IOPMSystemCapabilityChangeParameters *) arg2;
5536
5537 if (kSystemTransitionNewCapClient == _systemTransitionType)
5538 {
5539 capArgs->fromCapabilities = 0;
5540 capArgs->toCapabilities = _currentCapability;
5541 capArgs->changeFlags = 0;
5542 }
5543 else
5544 {
5545 capArgs->fromCapabilities = _currentCapability;
5546 capArgs->toCapabilities = _pendingCapability;
5547
5548 if (context->isPreChange)
5549 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
5550 else
5551 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
5552
5553 if ((object == (void *) systemCapabilityNotifier) &&
5554 context->isPreChange)
5555 {
5556 toldPowerdCapWillChange = true;
5557 }
5558 }
5559
5560 // Capability change messages only go to the PM configd plugin.
5561 // Wait for response post-change if capabilitiy is increasing.
5562 // Wait for response pre-change if capability is decreasing.
5563
5564 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5565 ( (capabilityLoss && context->isPreChange) ||
5566 (!capabilityLoss && !context->isPreChange) ) )
5567 {
5568 // app has not replied yet, wait for it
5569 *((OSObject **) arg3) = kOSBooleanFalse;
5570 }
5571
5572 allow = true;
5573 break;
5574 }
5575
5576 // Capability client will always see kIOMessageCanSystemSleep,
5577 // even for demand sleep. It will also have a chance to veto
5578 // sleep one last time after all clients have responded to
5579 // kIOMessageSystemWillSleep
5580
5581 if ((kIOMessageCanSystemSleep == context->messageType) ||
5582 (kIOMessageSystemWillNotSleep == context->messageType))
5583 {
5584 if (object == (OSObject *) systemCapabilityNotifier)
5585 {
5586 allow = true;
5587 break;
5588 }
5589
5590 // Not idle sleep, don't ask apps.
5591 if (context->changeFlags & kIOPMSkipAskPowerDown)
5592 {
5593 break;
5594 }
5595 }
5596
5597 if (kIOPMMessageLastCallBeforeSleep == context->messageType)
5598 {
5599 if ((object == (OSObject *) systemCapabilityNotifier) &&
5600 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
5601 (fullToDarkReason == kIOPMSleepReasonIdle))
5602 allow = true;
5603 break;
5604 }
5605
5606 // Reject capability change messages for legacy clients.
5607 // Reject legacy system sleep messages for capability client.
5608
5609 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
5610 {
5611 break;
5612 }
5613
5614 // Filter system sleep messages.
5615
5616 if ((context->notifyType == kNotifyApps) &&
5617 (_systemMessageClientMask & kSystemMessageClientLegacyApp))
5618 {
5619 IOPMServiceInterestNotifier *notify;
5620 allow = true;
5621
5622 if ((notify = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object))
5623 && arg3) {
5624
5625 if (notify->ackTimeoutCnt >= 3)
5626 *((OSObject **) arg3) = kOSBooleanFalse;
5627 else
5628 *((OSObject **) arg3) = kOSBooleanTrue;
5629 }
5630 }
5631 else if ((context->notifyType == kNotifyPriority) &&
5632 (_systemMessageClientMask & kSystemMessageClientKernel))
5633 {
5634 allow = true;
5635 }
5636 }
5637 while (false);
5638
5639 if (allow && isCapMsg && _joinedCapabilityClients)
5640 {
5641 _joinedCapabilityClients->removeObject((OSObject *) object);
5642 if (_joinedCapabilityClients->getCount() == 0)
5643 {
5644 DLOG("destroyed capability client set %p\n",
5645 OBFUSCATE(_joinedCapabilityClients));
5646 _joinedCapabilityClients->release();
5647 _joinedCapabilityClients = 0;
5648 }
5649 }
5650
5651 return allow;
5652 }
5653
5654 //******************************************************************************
5655 // setMaintenanceWakeCalendar
5656 //
5657 //******************************************************************************
5658
5659 IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
5660 const IOPMCalendarStruct * calendar )
5661 {
5662 OSData * data;
5663 IOReturn ret = 0;
5664
5665 if (!calendar)
5666 return kIOReturnBadArgument;
5667
5668 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
5669 if (!data)
5670 return kIOReturnNoMemory;
5671
5672 if (kPMCalendarTypeMaintenance == calendar->selector) {
5673 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
5674 if (kIOReturnSuccess == ret)
5675 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
5676 } else
5677 if (kPMCalendarTypeSleepService == calendar->selector)
5678 {
5679 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
5680 if (kIOReturnSuccess == ret)
5681 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
5682 }
5683 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
5684
5685 data->release();
5686 return ret;
5687 }
5688
5689 // MARK: -
5690 // MARK: Display Wrangler
5691
5692 //******************************************************************************
5693 // displayWranglerNotification
5694 //
5695 // Handle the notification when the IODisplayWrangler changes power state.
5696 //******************************************************************************
5697
5698 IOReturn IOPMrootDomain::displayWranglerNotification(
5699 void * target, void * refCon,
5700 UInt32 messageType, IOService * service,
5701 void * messageArgument, vm_size_t argSize )
5702 {
5703 #if !NO_KERNEL_HID
5704 int displayPowerState;
5705 IOPowerStateChangeNotification * params =
5706 (IOPowerStateChangeNotification *) messageArgument;
5707
5708 if ((messageType != kIOMessageDeviceWillPowerOff) &&
5709 (messageType != kIOMessageDeviceHasPoweredOn))
5710 return kIOReturnUnsupported;
5711
5712 ASSERT_GATED();
5713 if (!gRootDomain)
5714 return kIOReturnUnsupported;
5715
5716 displayPowerState = params->stateNumber;
5717 DLOG("wrangler %s ps %d\n",
5718 getIOMessageString(messageType), displayPowerState);
5719
5720 switch (messageType) {
5721 case kIOMessageDeviceWillPowerOff:
5722 // Display wrangler has dropped power due to display idle
5723 // or force system sleep.
5724 //
5725 // 4 Display ON kWranglerPowerStateMax
5726 // 3 Display Dim kWranglerPowerStateDim
5727 // 2 Display Sleep kWranglerPowerStateSleep
5728 // 1 Not visible to user
5729 // 0 Not visible to user kWranglerPowerStateMin
5730
5731 if (displayPowerState <= kWranglerPowerStateSleep)
5732 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
5733 break;
5734
5735 case kIOMessageDeviceHasPoweredOn:
5736 // Display wrangler has powered on due to user activity
5737 // or wake from sleep.
5738
5739 if (kWranglerPowerStateMax == displayPowerState)
5740 {
5741 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
5742
5743 // See comment in handleUpdatePowerClientForDisplayWrangler
5744 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
5745 kWranglerPowerStateMax)
5746 {
5747 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
5748 }
5749 }
5750 break;
5751 }
5752 #endif
5753 return kIOReturnUnsupported;
5754 }
5755
5756 //******************************************************************************
5757 // displayWranglerMatchPublished
5758 //
5759 // Receives a notification when the IODisplayWrangler is published.
5760 // When it's published we install a power state change handler.
5761 //******************************************************************************
5762
5763 bool IOPMrootDomain::displayWranglerMatchPublished(
5764 void * target,
5765 void * refCon,
5766 IOService * newService,
5767 IONotifier * notifier __unused)
5768 {
5769 #if !NO_KERNEL_HID
5770 // found the display wrangler, now install a handler
5771 if( !newService->registerInterest( gIOGeneralInterest,
5772 &displayWranglerNotification, target, 0) )
5773 {
5774 return false;
5775 }
5776 #endif
5777 return true;
5778 }
5779
5780 #if defined(__i386__) || defined(__x86_64__)
5781
5782 bool IOPMrootDomain::IONVRAMMatchPublished(
5783 void * target,
5784 void * refCon,
5785 IOService * newService,
5786 IONotifier * notifier)
5787 {
5788 unsigned int len = 0;
5789 IOPMrootDomain *rd = (IOPMrootDomain *)target;
5790 OSNumber *statusCode = NULL;
5791
5792 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey, NULL, &len))
5793 {
5794 statusCode = OSDynamicCast(OSNumber, rd->getProperty(kIOPMSleepWakeFailureCodeKey));
5795 if (statusCode != NULL) {
5796 if (statusCode->unsigned64BitValue() != 0) {
5797 rd->swd_flags |= SWD_BOOT_BY_SW_WDOG;
5798 MSG("System was rebooted due to Sleep/Wake failure\n");
5799 }
5800 else {
5801 rd->swd_flags |= SWD_BOOT_BY_OSX_WDOG;
5802 MSG("System was non-responsive and was rebooted by watchdog\n");
5803 }
5804 }
5805
5806 rd->swd_logBufMap = rd->sleepWakeDebugRetrieve();
5807 }
5808 if (notifier) notifier->remove();
5809 return true;
5810 }
5811
5812 #else
5813 bool IOPMrootDomain::IONVRAMMatchPublished(
5814 void * target,
5815 void * refCon,
5816 IOService * newService,
5817 IONotifier * notifier __unused)
5818 {
5819 return false;
5820 }
5821
5822 #endif
5823
5824 //******************************************************************************
5825 // reportUserInput
5826 //
5827 //******************************************************************************
5828
5829 void IOPMrootDomain::reportUserInput( void )
5830 {
5831 #if !NO_KERNEL_HID
5832 OSIterator * iter;
5833 OSDictionary * matching;
5834
5835 if(!wrangler)
5836 {
5837 matching = serviceMatching("IODisplayWrangler");
5838 iter = getMatchingServices(matching);
5839 if (matching) matching->release();
5840 if(iter)
5841 {
5842 wrangler = (IOService *) iter->getNextObject();
5843 iter->release();
5844 }
5845 }
5846
5847 if(wrangler)
5848 wrangler->activityTickle(0,0);
5849 #endif
5850 }
5851
5852 //******************************************************************************
5853 // latchDisplayWranglerTickle
5854 //******************************************************************************
5855
5856 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
5857 {
5858 #if !NO_KERNEL_HID
5859 if (latch)
5860 {
5861 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
5862 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
5863 !checkSystemCanSustainFullWake())
5864 {
5865 // Currently in dark wake, and not transitioning to full wake.
5866 // Full wake is unsustainable, so latch the tickle to prevent
5867 // the display from lighting up momentarily.
5868 wranglerTickleLatched = true;
5869 }
5870 else
5871 {
5872 wranglerTickleLatched = false;
5873 }
5874 }
5875 else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
5876 {
5877 wranglerTickleLatched = false;
5878
5879 pmPowerStateQueue->submitPowerEvent(
5880 kPowerEventPolicyStimulus,
5881 (void *) kStimulusDarkWakeActivityTickle );
5882 }
5883
5884 return wranglerTickleLatched;
5885 #else
5886 return false;
5887 #endif
5888 }
5889
5890 //******************************************************************************
5891 // setDisplayPowerOn
5892 //
5893 // For root domain user client
5894 //******************************************************************************
5895
5896 void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
5897 {
5898 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
5899 (void *) 0, options );
5900 }
5901
5902 // MARK: -
5903 // MARK: Battery
5904
5905 //******************************************************************************
5906 // batteryPublished
5907 //
5908 // Notification on battery class IOPowerSource appearance
5909 //******************************************************************************
5910
5911 bool IOPMrootDomain::batteryPublished(
5912 void * target,
5913 void * root_domain,
5914 IOService * resourceService,
5915 IONotifier * notifier __unused )
5916 {
5917 // rdar://2936060&4435589
5918 // All laptops have dimmable LCD displays
5919 // All laptops have batteries
5920 // So if this machine has a battery, publish the fact that the backlight
5921 // supports dimming.
5922 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
5923
5924 return (true);
5925 }
5926
5927 // MARK: -
5928 // MARK: System PM Policy
5929
5930 //******************************************************************************
5931 // checkSystemSleepAllowed
5932 //
5933 //******************************************************************************
5934
5935 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
5936 uint32_t sleepReason )
5937 {
5938 int err = 0;
5939
5940 // Conditions that prevent idle and demand system sleep.
5941
5942 do {
5943 if (userDisabledAllSleep)
5944 {
5945 err = 1; // 1. user-space sleep kill switch
5946 break;
5947 }
5948
5949 if (systemBooting || systemShutdown || gWillShutdown)
5950 {
5951 err = 2; // 2. restart or shutdown in progress
5952 break;
5953 }
5954
5955 if (options == 0)
5956 break;
5957
5958 // Conditions above pegs the system at full wake.
5959 // Conditions below prevent system sleep but does not prevent
5960 // dark wake, and must be called from gated context.
5961
5962 #if !CONFIG_SLEEP
5963 err = 3; // 3. config does not support sleep
5964 break;
5965 #endif
5966
5967 if (lowBatteryCondition || thermalWarningState)
5968 {
5969 break; // always sleep on low battery or when in thermal warning state
5970 }
5971
5972 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
5973 {
5974 break; // always sleep on dark wake thermal emergencies
5975 }
5976
5977 if (preventSystemSleepList->getCount() != 0)
5978 {
5979 err = 4; // 4. child prevent system sleep clamp
5980 break;
5981 }
5982
5983 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
5984 kIOPMDriverAssertionLevelOn)
5985 {
5986 err = 5; // 5. CPU assertion
5987 break;
5988 }
5989
5990 if (pciCantSleepValid)
5991 {
5992 if (pciCantSleepFlag)
5993 err = 6; // 6. PCI card does not support PM (cached)
5994 break;
5995 }
5996 else if (sleepSupportedPEFunction &&
5997 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5998 {
5999 IOReturn ret;
6000 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
6001 ret = getPlatform()->callPlatformFunction(
6002 sleepSupportedPEFunction, false,
6003 NULL, NULL, NULL, NULL);
6004 pciCantSleepValid = true;
6005 pciCantSleepFlag = false;
6006 if ((platformSleepSupport & kPCICantSleep) ||
6007 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
6008 {
6009 err = 6; // 6. PCI card does not support PM
6010 pciCantSleepFlag = true;
6011 break;
6012 }
6013 }
6014 }
6015 while (false);
6016
6017 if (err)
6018 {
6019 DLOG("System sleep prevented by %d\n", err);
6020 return false;
6021 }
6022 return true;
6023 }
6024
6025 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6026 {
6027 return checkSystemSleepAllowed(0, 0);
6028 }
6029
6030 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
6031 {
6032 ASSERT_GATED();
6033 return checkSystemSleepAllowed(1, sleepReason);
6034 }
6035
6036 //******************************************************************************
6037 // checkSystemCanSustainFullWake
6038 //******************************************************************************
6039
6040 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6041 {
6042 #if !NO_KERNEL_HID
6043 if (lowBatteryCondition || thermalWarningState)
6044 {
6045 // Low battery wake, or received a low battery notification
6046 // while system is awake. This condition will persist until
6047 // the following wake.
6048 return false;
6049 }
6050
6051 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
6052 {
6053 // Graphics state is unknown and external display might not be probed.
6054 // Do not incorporate state that requires graphics to be in max power
6055 // such as desktopMode or clamshellDisabled.
6056
6057 if (!acAdaptorConnected)
6058 {
6059 DLOG("full wake check: no AC\n");
6060 return false;
6061 }
6062 }
6063 #endif
6064 return true;
6065 }
6066
6067 //******************************************************************************
6068 // adjustPowerState
6069 //
6070 // Conditions that affect our wake/sleep decision has changed.
6071 // If conditions dictate that the system must remain awake, clamp power
6072 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6073 // is TRUE, then remove the power clamp and allow the power state to drop
6074 // to SLEEP_STATE.
6075 //******************************************************************************
6076
6077 void IOPMrootDomain::adjustPowerState( bool sleepASAP )
6078 {
6079 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
6080 (uint32_t) getPowerState(), sleepASAP, sleepSlider);
6081
6082 ASSERT_GATED();
6083
6084 if ((sleepSlider == 0) || !checkSystemSleepEnabled())
6085 {
6086 changePowerStateToPriv(ON_STATE);
6087 }
6088 else if ( sleepASAP )
6089 {
6090 changePowerStateToPriv(SLEEP_STATE);
6091 }
6092 }
6093
6094 void IOPMrootDomain::handleDisplayPowerOn( )
6095 {
6096 if (!wrangler) return;
6097 if (displayPowerOnRequested)
6098 {
6099 if (!checkSystemCanSustainFullWake()) return;
6100
6101 // Force wrangler to max power state. If system is in dark wake
6102 // this alone won't raise the wrangler's power state.
6103
6104 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
6105
6106 // System in dark wake, always requesting full wake should
6107 // not have any bad side-effects, even if the request fails.
6108
6109 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6110 {
6111 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
6112 requestFullWake( kFullWakeReasonDisplayOn );
6113 }
6114 }
6115 else
6116 {
6117 // Relenquish desire to power up display.
6118 // Must first transition to state 1 since wrangler doesn't
6119 // power off the displays at state 0. At state 0 the root
6120 // domain is removed from the wrangler's power client list.
6121
6122 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
6123 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
6124
6125 }
6126
6127 }
6128
6129 //******************************************************************************
6130 // dispatchPowerEvent
6131 //
6132 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6133 //******************************************************************************
6134
6135 void IOPMrootDomain::dispatchPowerEvent(
6136 uint32_t event, void * arg0, uint64_t arg1 )
6137 {
6138 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6139 ASSERT_GATED();
6140
6141 switch (event)
6142 {
6143 case kPowerEventFeatureChanged:
6144 messageClients(kIOPMMessageFeatureChange, this);
6145 break;
6146
6147 case kPowerEventReceivedPowerNotification:
6148 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
6149 break;
6150
6151 case kPowerEventSystemBootCompleted:
6152 if (systemBooting)
6153 {
6154 systemBooting = false;
6155
6156 if (lowBatteryCondition)
6157 {
6158 privateSleepSystem (kIOPMSleepReasonLowPower);
6159
6160 // The rest is unnecessary since the system is expected
6161 // to sleep immediately. The following wake will update
6162 // everything.
6163 break;
6164 }
6165
6166 if (swd_flags & SWD_VALID_LOGS) {
6167 if (swd_flags & SWD_LOGS_IN_MEM) {
6168 sleepWakeDebugDumpFromMem(swd_logBufMap);
6169 swd_logBufMap->release();
6170 swd_logBufMap = 0;
6171 }
6172 else if (swd_flags & SWD_LOGS_IN_FILE)
6173 sleepWakeDebugDumpFromFile();
6174 }
6175 else if (swd_flags & (SWD_BOOT_BY_SW_WDOG|SWD_BOOT_BY_OSX_WDOG)) {
6176 // If logs are invalid, write the failure code
6177 sleepWakeDebugDumpFromMem(NULL);
6178 }
6179 // If lid is closed, re-send lid closed notification
6180 // now that booting is complete.
6181 if ( clamshellClosed )
6182 {
6183 handlePowerNotification(kLocalEvalClamshellCommand);
6184 }
6185 evaluatePolicy( kStimulusAllowSystemSleepChanged );
6186
6187 }
6188 break;
6189
6190 case kPowerEventSystemShutdown:
6191 if (kOSBooleanTrue == (OSBoolean *) arg0)
6192 {
6193 /* We set systemShutdown = true during shutdown
6194 to prevent sleep at unexpected times while loginwindow is trying
6195 to shutdown apps and while the OS is trying to transition to
6196 complete power of.
6197
6198 Set to true during shutdown, as soon as loginwindow shows
6199 the "shutdown countdown dialog", through individual app
6200 termination, and through black screen kernel shutdown.
6201 */
6202 systemShutdown = true;
6203 } else {
6204 /*
6205 A shutdown was initiated, but then the shutdown
6206 was cancelled, clearing systemShutdown to false here.
6207 */
6208 systemShutdown = false;
6209 }
6210 break;
6211
6212 case kPowerEventUserDisabledSleep:
6213 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
6214 break;
6215
6216 case kPowerEventRegisterSystemCapabilityClient:
6217 if (systemCapabilityNotifier)
6218 {
6219 systemCapabilityNotifier->release();
6220 systemCapabilityNotifier = 0;
6221 }
6222 if (arg0)
6223 {
6224 systemCapabilityNotifier = (IONotifier *) arg0;
6225 systemCapabilityNotifier->retain();
6226 }
6227 /* intentional fall-through */
6228
6229 case kPowerEventRegisterKernelCapabilityClient:
6230 if (!_joinedCapabilityClients)
6231 _joinedCapabilityClients = OSSet::withCapacity(8);
6232 if (arg0)
6233 {
6234 IONotifier * notify = (IONotifier *) arg0;
6235 if (_joinedCapabilityClients)
6236 {
6237 _joinedCapabilityClients->setObject(notify);
6238 synchronizePowerTree( kIOPMSyncNoChildNotify );
6239 }
6240 notify->release();
6241 }
6242 break;
6243
6244 case kPowerEventPolicyStimulus:
6245 if (arg0)
6246 {
6247 int stimulus = (uintptr_t) arg0;
6248 evaluatePolicy( stimulus, (uint32_t) arg1 );
6249 }
6250 break;
6251
6252 case kPowerEventAssertionCreate:
6253 if (pmAssertions) {
6254 pmAssertions->handleCreateAssertion((OSData *)arg0);
6255 }
6256 break;
6257
6258
6259 case kPowerEventAssertionRelease:
6260 if (pmAssertions) {
6261 pmAssertions->handleReleaseAssertion(arg1);
6262 }
6263 break;
6264
6265 case kPowerEventAssertionSetLevel:
6266 if (pmAssertions) {
6267 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
6268 }
6269 break;
6270
6271 case kPowerEventQueueSleepWakeUUID:
6272 handleQueueSleepWakeUUID((OSObject *)arg0);
6273 break;
6274 case kPowerEventPublishSleepWakeUUID:
6275 handlePublishSleepWakeUUID((bool)arg0);
6276 break;
6277
6278 case kPowerEventSetDisplayPowerOn:
6279 if (!wrangler) break;
6280 if (arg1 != 0)
6281 {
6282 displayPowerOnRequested = true;
6283 }
6284 else
6285 {
6286 displayPowerOnRequested = false;
6287 }
6288 handleDisplayPowerOn();
6289 break;
6290 }
6291 }
6292
6293 //******************************************************************************
6294 // systemPowerEventOccurred
6295 //
6296 // The power controller is notifying us of a hardware-related power management
6297 // event that we must handle.
6298 //
6299 // systemPowerEventOccurred covers the same functionality that
6300 // receivePowerNotification does; it simply provides a richer API for conveying
6301 // more information.
6302 //******************************************************************************
6303
6304 IOReturn IOPMrootDomain::systemPowerEventOccurred(
6305 const OSSymbol *event,
6306 uint32_t intValue)
6307 {
6308 IOReturn attempt = kIOReturnSuccess;
6309 OSNumber *newNumber = NULL;
6310
6311 if (!event)
6312 return kIOReturnBadArgument;
6313
6314 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
6315 if (!newNumber)
6316 return kIOReturnInternalError;
6317
6318 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
6319
6320 newNumber->release();
6321
6322 return attempt;
6323 }
6324
6325 void IOPMrootDomain::setThermalState(OSObject *value)
6326 {
6327 OSNumber * num;
6328
6329 if (gIOPMWorkLoop->inGate() == false) {
6330 gIOPMWorkLoop->runAction(
6331 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
6332 (OSObject *)this,
6333 (void *)value);
6334
6335 return;
6336 }
6337 if (value && (num = OSDynamicCast(OSNumber, value))) {
6338 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
6339 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
6340 }
6341 }
6342
6343 IOReturn IOPMrootDomain::systemPowerEventOccurred(
6344 const OSSymbol *event,
6345 OSObject *value)
6346 {
6347 OSDictionary *thermalsDict = NULL;
6348 bool shouldUpdate = true;
6349
6350 if (!event || !value)
6351 return kIOReturnBadArgument;
6352
6353 // LOCK
6354 // We reuse featuresDict Lock because it already exists and guards
6355 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6356 // of stepping on that lock.
6357 if (featuresDictLock) IOLockLock(featuresDictLock);
6358
6359 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
6360
6361 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
6362 thermalsDict = OSDictionary::withDictionary(thermalsDict);
6363 } else {
6364 thermalsDict = OSDictionary::withCapacity(1);
6365 }
6366
6367 if (!thermalsDict) {
6368 shouldUpdate = false;
6369 goto exit;
6370 }
6371
6372 thermalsDict->setObject (event, value);
6373
6374 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
6375
6376 thermalsDict->release();
6377
6378 exit:
6379 // UNLOCK
6380 if (featuresDictLock) IOLockUnlock(featuresDictLock);
6381
6382 if (shouldUpdate) {
6383 if (event &&
6384 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
6385 setThermalState(value);
6386 }
6387 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
6388 }
6389
6390 return kIOReturnSuccess;
6391 }
6392
6393 //******************************************************************************
6394 // receivePowerNotification
6395 //
6396 // The power controller is notifying us of a hardware-related power management
6397 // event that we must handle. This may be a result of an 'environment' interrupt
6398 // from the power mgt micro.
6399 //******************************************************************************
6400
6401 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
6402 {
6403 pmPowerStateQueue->submitPowerEvent(
6404 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6405 return kIOReturnSuccess;
6406 }
6407
6408 void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6409 {
6410 bool eval_clamshell = false;
6411
6412 ASSERT_GATED();
6413
6414 /*
6415 * Local (IOPMrootDomain only) eval clamshell command
6416 */
6417 if (msg & kLocalEvalClamshellCommand)
6418 {
6419 eval_clamshell = true;
6420 }
6421
6422 /*
6423 * Overtemp
6424 */
6425 if (msg & kIOPMOverTemp)
6426 {
6427 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6428 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
6429 }
6430
6431 /*
6432 * Forward DW thermal notification to client, if system is not going to sleep
6433 */
6434 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
6435 {
6436 DLOG("DarkWake thermal limits message received!\n");
6437
6438 messageClients(kIOPMMessageDarkWakeThermalEmergency);
6439 }
6440
6441 /*
6442 * Sleep Now!
6443 */
6444 if (msg & kIOPMSleepNow)
6445 {
6446 privateSleepSystem (kIOPMSleepReasonSoftware);
6447 }
6448
6449 /*
6450 * Power Emergency
6451 */
6452 if (msg & kIOPMPowerEmergency)
6453 {
6454 lowBatteryCondition = true;
6455 privateSleepSystem (kIOPMSleepReasonLowPower);
6456 }
6457
6458 /*
6459 * Clamshell OPEN
6460 */
6461 if (msg & kIOPMClamshellOpened)
6462 {
6463 // Received clamshel open message from clamshell controlling driver
6464 // Update our internal state and tell general interest clients
6465 clamshellClosed = false;
6466 clamshellExists = true;
6467
6468 // Don't issue a hid tickle when lid is open and polled on wake
6469 if (msg & kIOPMSetValue)
6470 {
6471 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6472 reportUserInput();
6473 }
6474
6475 // Tell PMCPU
6476 informCPUStateChange(kInformLid, 0);
6477
6478 // Tell general interest clients
6479 sendClientClamshellNotification();
6480
6481 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
6482 || (lastSleepReason == kIOPMSleepReasonIdle)
6483 || (lastSleepReason == kIOPMSleepReasonMaintenance));
6484 if (aborting) userActivityCount++;
6485 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
6486 }
6487
6488 /*
6489 * Clamshell CLOSED
6490 * Send the clamshell interest notification since the lid is closing.
6491 */
6492 if (msg & kIOPMClamshellClosed)
6493 {
6494 // Received clamshel open message from clamshell controlling driver
6495 // Update our internal state and tell general interest clients
6496 clamshellClosed = true;
6497 clamshellExists = true;
6498
6499 // Tell PMCPU
6500 informCPUStateChange(kInformLid, 1);
6501
6502 // Tell general interest clients
6503 sendClientClamshellNotification();
6504
6505 // And set eval_clamshell = so we can attempt
6506 eval_clamshell = true;
6507 }
6508
6509 /*
6510 * Set Desktop mode (sent from graphics)
6511 *
6512 * -> reevaluate lid state
6513 */
6514 if (msg & kIOPMSetDesktopMode)
6515 {
6516 desktopMode = (0 != (msg & kIOPMSetValue));
6517 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
6518
6519 sendClientClamshellNotification();
6520
6521 // Re-evaluate the lid state
6522 eval_clamshell = true;
6523 }
6524
6525 /*
6526 * AC Adaptor connected
6527 *
6528 * -> reevaluate lid state
6529 */
6530 if (msg & kIOPMSetACAdaptorConnected)
6531 {
6532 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6533 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
6534
6535 // Tell CPU PM
6536 informCPUStateChange(kInformAC, !acAdaptorConnected);
6537
6538 // Tell BSD if AC is connected
6539 // 0 == external power source; 1 == on battery
6540 post_sys_powersource(acAdaptorConnected ? 0:1);
6541
6542 sendClientClamshellNotification();
6543
6544 // Re-evaluate the lid state
6545 eval_clamshell = true;
6546
6547 // Lack of AC may have latched a display wrangler tickle.
6548 // This mirrors the hardware's USB wake event latch, where a latched
6549 // USB wake event followed by an AC attach will trigger a full wake.
6550 latchDisplayWranglerTickle( false );
6551
6552 #if HIBERNATION
6553 // AC presence will reset the standy timer delay adjustment.
6554 _standbyTimerResetSeconds = 0;
6555 #endif
6556 if (!userIsActive) {
6557 // Reset userActivityTime when power supply is changed(rdr 13789330)
6558 clock_get_uptime(&userActivityTime);
6559 }
6560 }
6561
6562 /*
6563 * Enable Clamshell (external display disappear)
6564 *
6565 * -> reevaluate lid state
6566 */
6567 if (msg & kIOPMEnableClamshell)
6568 {
6569 // Re-evaluate the lid state
6570 // System should sleep on external display disappearance
6571 // in lid closed operation.
6572 if (true == clamshellDisabled)
6573 {
6574 eval_clamshell = true;
6575 }
6576
6577 clamshellDisabled = false;
6578 sendClientClamshellNotification();
6579 }
6580
6581 /*
6582 * Disable Clamshell (external display appeared)
6583 * We don't bother re-evaluating clamshell state. If the system is awake,
6584 * the lid is probably open.
6585 */
6586 if (msg & kIOPMDisableClamshell)
6587 {
6588 clamshellDisabled = true;
6589 sendClientClamshellNotification();
6590 }
6591
6592 /*
6593 * Evaluate clamshell and SLEEP if appropiate
6594 */
6595 if (eval_clamshell && clamshellClosed)
6596 {
6597 if (shouldSleepOnClamshellClosed())
6598 privateSleepSystem (kIOPMSleepReasonClamshell);
6599 else
6600 evaluatePolicy( kStimulusDarkWakeEvaluate );
6601 }
6602
6603 /*
6604 * Power Button
6605 */
6606 if (msg & kIOPMPowerButton)
6607 {
6608 if (!wranglerAsleep)
6609 {
6610 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
6611 // Check that power button sleep is enabled
6612 if( pbs ) {
6613 if( kOSBooleanTrue != getProperty(pbs))
6614 privateSleepSystem (kIOPMSleepReasonPowerButton);
6615 }
6616 }
6617 else
6618 reportUserInput();
6619 }
6620 }
6621
6622 //******************************************************************************
6623 // evaluatePolicy
6624 //
6625 // Evaluate root-domain policy in response to external changes.
6626 //******************************************************************************
6627
6628 void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
6629 {
6630 union {
6631 struct {
6632 int idleSleepEnabled : 1;
6633 int idleSleepDisabled : 1;
6634 int displaySleep : 1;
6635 int sleepDelayChanged : 1;
6636 int evaluateDarkWake : 1;
6637 int adjustPowerState : 1;
6638 int userBecameInactive : 1;
6639 } bit;
6640 uint32_t u32;
6641 } flags;
6642
6643 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6644
6645 ASSERT_GATED();
6646 flags.u32 = 0;
6647
6648 switch (stimulus)
6649 {
6650 case kStimulusDisplayWranglerSleep:
6651 if (!wranglerAsleep)
6652 {
6653 // first transition to wrangler sleep or lower
6654 wranglerAsleep = true;
6655 flags.bit.displaySleep = true;
6656 }
6657 break;
6658
6659 case kStimulusDisplayWranglerWake:
6660 displayIdleForDemandSleep = false;
6661 wranglerAsleep = false;
6662 break;
6663
6664 case kStimulusEnterUserActiveState:
6665 if (_preventUserActive)
6666 {
6667 DLOG("user active dropped\n");
6668 break;
6669 }
6670 if (!userIsActive)
6671 {
6672 userIsActive = true;
6673 userWasActive = true;
6674
6675 // Stay awake after dropping demand for display power on
6676 if (kFullWakeReasonDisplayOn == fullWakeReason)
6677 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
6678
6679 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
6680 messageClients(kIOPMMessageUserIsActiveChanged);
6681 }
6682 flags.bit.idleSleepDisabled = true;
6683 break;
6684
6685 case kStimulusLeaveUserActiveState:
6686 if (userIsActive)
6687 {
6688 userIsActive = false;
6689 clock_get_uptime(&userBecameInactiveTime);
6690 flags.bit.userBecameInactive = true;
6691
6692 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
6693 messageClients(kIOPMMessageUserIsActiveChanged);
6694 }
6695 break;
6696
6697 case kStimulusAggressivenessChanged:
6698 {
6699 unsigned long minutesToIdleSleep = 0;
6700 unsigned long minutesToDisplayDim = 0;
6701 unsigned long minutesDelta = 0;
6702
6703 // Fetch latest display and system sleep slider values.
6704 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
6705 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
6706 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6707 (uint32_t) sleepSlider,
6708 (uint32_t) minutesToIdleSleep,
6709 (uint32_t) minutesToDisplayDim);
6710
6711 DLOG("idle time -> %ld secs (ena %d)\n",
6712 idleSeconds, (minutesToIdleSleep != 0));
6713
6714 if (0x7fffffff == minutesToIdleSleep)
6715 minutesToIdleSleep = idleSeconds;
6716
6717 // How long to wait before sleeping the system once
6718 // the displays turns off is indicated by 'extraSleepDelay'.
6719
6720 if ( minutesToIdleSleep > minutesToDisplayDim )
6721 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
6722 else if ( minutesToIdleSleep == minutesToDisplayDim )
6723 minutesDelta = 1;
6724
6725 if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
6726 flags.bit.idleSleepEnabled = true;
6727
6728 if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
6729 flags.bit.idleSleepDisabled = true;
6730
6731 if (((minutesDelta != extraSleepDelay) ||
6732 (userActivityTime != userActivityTime_prev)) &&
6733 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
6734 flags.bit.sleepDelayChanged = true;
6735
6736 if (systemDarkWake && !darkWakeToSleepASAP &&
6737 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
6738 {
6739 // Reconsider decision to remain in dark wake
6740 flags.bit.evaluateDarkWake = true;
6741 }
6742
6743 sleepSlider = minutesToIdleSleep;
6744 extraSleepDelay = minutesDelta;
6745 userActivityTime_prev = userActivityTime;
6746 } break;
6747
6748 case kStimulusDemandSystemSleep:
6749 displayIdleForDemandSleep = true;
6750 if (wrangler && wranglerIdleSettings)
6751 {
6752 // Request wrangler idle only when demand sleep is triggered
6753 // from full wake.
6754 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6755 {
6756 wrangler->setProperties(wranglerIdleSettings);
6757 DLOG("Requested wrangler idle\n");
6758 }
6759 }
6760 // arg = sleepReason
6761 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
6762 break;
6763
6764 case kStimulusAllowSystemSleepChanged:
6765 flags.bit.adjustPowerState = true;
6766 break;
6767
6768 case kStimulusDarkWakeActivityTickle:
6769 // arg == true implies real and not self generated wrangler tickle.
6770 // Update wake type on PM work loop instead of the tickle thread to
6771 // eliminate the possibility of an early tickle clobbering the wake
6772 // type set by the platform driver.
6773 if (arg == true)
6774 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
6775
6776 if (false == wranglerTickled)
6777 {
6778 if (latchDisplayWranglerTickle(true))
6779 {
6780 DLOG("latched tickle\n");
6781 break;
6782 }
6783
6784 wranglerTickled = true;
6785 DLOG("Requesting full wake after dark wake activity tickle\n");
6786 requestFullWake( kFullWakeReasonLocalUser );
6787 }
6788 break;
6789
6790 case kStimulusDarkWakeEntry:
6791 case kStimulusDarkWakeReentry:
6792 // Any system transitions since the last dark wake transition
6793 // will invalid the stimulus.
6794
6795 if (arg == _systemStateGeneration)
6796 {
6797 DLOG("dark wake entry\n");
6798 systemDarkWake = true;
6799
6800 // Keep wranglerAsleep an invariant when wrangler is absent
6801 if (wrangler)
6802 wranglerAsleep = true;
6803
6804 if (kStimulusDarkWakeEntry == stimulus)
6805 {
6806 clock_get_uptime(&userBecameInactiveTime);
6807 flags.bit.evaluateDarkWake = true;
6808 }
6809
6810 // Always accelerate disk spindown while in dark wake,
6811 // even if system does not support/allow sleep.
6812
6813 cancelIdleSleepTimer();
6814 setQuickSpinDownTimeout();
6815 }
6816 break;
6817
6818 case kStimulusDarkWakeEvaluate:
6819 if (systemDarkWake)
6820 {
6821 flags.bit.evaluateDarkWake = true;
6822 }
6823 break;
6824
6825 case kStimulusNoIdleSleepPreventers:
6826 flags.bit.adjustPowerState = true;
6827 break;
6828
6829 } /* switch(stimulus) */
6830
6831 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
6832 {
6833 if (darkWakeToSleepASAP ||
6834 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
6835 {
6836 uint32_t newSleepReason;
6837
6838 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6839 {
6840 // System was previously in full wake. Sleep reason from
6841 // full to dark already recorded in fullToDarkReason.
6842
6843 if (lowBatteryCondition)
6844 newSleepReason = kIOPMSleepReasonLowPower;
6845 else
6846 newSleepReason = fullToDarkReason;
6847 }
6848 else
6849 {
6850 // In dark wake from system sleep.
6851
6852 if (darkWakeSleepService)
6853 newSleepReason = kIOPMSleepReasonSleepServiceExit;
6854 else
6855 newSleepReason = kIOPMSleepReasonMaintenance;
6856 }
6857
6858 if (checkSystemCanSleep(newSleepReason))
6859 {
6860 privateSleepSystem(newSleepReason);
6861 }
6862 }
6863 else // non-maintenance (network) dark wake
6864 {
6865 if (checkSystemCanSleep(kIOPMSleepReasonIdle))
6866 {
6867 // Release power clamp, and wait for children idle.
6868 adjustPowerState(true);
6869 }
6870 else
6871 {
6872 changePowerStateToPriv(ON_STATE);
6873 }
6874 }
6875 }
6876
6877 if (systemDarkWake)
6878 {
6879 // The rest are irrelevant while system is in dark wake.
6880 flags.u32 = 0;
6881 }
6882
6883 if ((flags.bit.displaySleep) &&
6884 (kFullWakeReasonDisplayOn == fullWakeReason))
6885 {
6886 // kIOPMSleepReasonMaintenance?
6887 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
6888 }
6889
6890 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
6891 {
6892 bool cancelQuickSpindown = false;
6893
6894 if (flags.bit.sleepDelayChanged)
6895 {
6896 // Cancel existing idle sleep timer and quick disk spindown.
6897 // New settings will be applied by the idleSleepEnabled flag
6898 // handler below if idle sleep is enabled.
6899
6900 DLOG("extra sleep timer changed\n");
6901 cancelIdleSleepTimer();
6902 cancelQuickSpindown = true;
6903 }
6904 else
6905 {
6906 DLOG("user inactive\n");
6907 }
6908
6909 if (!userIsActive && sleepSlider)
6910 {
6911 startIdleSleepTimer(getTimeToIdleSleep());
6912 }
6913
6914 if (cancelQuickSpindown)
6915 restoreUserSpinDownTimeout();
6916 }
6917
6918 if (flags.bit.idleSleepEnabled)
6919 {
6920 DLOG("idle sleep timer enabled\n");
6921 if (!wrangler)
6922 {
6923 changePowerStateToPriv(ON_STATE);
6924 if (idleSeconds)
6925 {
6926 startIdleSleepTimer( idleSeconds );
6927 }
6928 }
6929 else
6930 {
6931 // Start idle timer if prefs now allow system sleep
6932 // and user is already inactive. Disk spindown is
6933 // accelerated upon timer expiration.
6934
6935 if (!userIsActive)
6936 {
6937 startIdleSleepTimer(getTimeToIdleSleep());
6938 }
6939 }
6940 }
6941
6942 if (flags.bit.idleSleepDisabled)
6943 {
6944 DLOG("idle sleep timer disabled\n");
6945 cancelIdleSleepTimer();
6946 restoreUserSpinDownTimeout();
6947 adjustPowerState();
6948 }
6949
6950 if (flags.bit.adjustPowerState)
6951 {
6952 bool sleepASAP = false;
6953
6954 if (!systemBooting && (preventIdleSleepList->getCount() == 0))
6955 {
6956 if (!wrangler)
6957 {
6958 changePowerStateToPriv(ON_STATE);
6959 if (idleSeconds)
6960 {
6961 // stay awake for at least idleSeconds
6962 startIdleSleepTimer(idleSeconds);
6963 }
6964 }
6965 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
6966 {
6967 sleepASAP = true;
6968 }
6969 }
6970
6971 adjustPowerState(sleepASAP);
6972 }
6973 }
6974
6975 //******************************************************************************
6976 // requestFullWake
6977 //
6978 // Request transition from dark wake to full wake
6979 //******************************************************************************
6980
6981 void IOPMrootDomain::requestFullWake( FullWakeReason reason )
6982 {
6983 uint32_t options = 0;
6984 IOService * pciRoot = 0;
6985 bool promotion = false;
6986
6987 // System must be in dark wake and a valid reason for entering full wake
6988 if ((kFullWakeReasonNone == reason) ||
6989 (kFullWakeReasonNone != fullWakeReason) ||
6990 (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
6991 {
6992 return;
6993 }
6994
6995 // Will clear reason upon exit from full wake
6996 fullWakeReason = reason;
6997
6998 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
6999 kIOPMSystemCapabilityAudio);
7000
7001 if ((kSystemTransitionWake == _systemTransitionType) &&
7002 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7003 !graphicsSuppressed)
7004 {
7005 // Promote to full wake while waking up to dark wake due to tickle.
7006 // PM will hold off notifying the graphics subsystem about system wake
7007 // as late as possible, so if a HID tickle does arrive, graphics can
7008 // power up on this same wake cycle. The latency to power up graphics
7009 // on the next cycle can be huge on some systems. However, once any
7010 // graphics suppression has taken effect, it is too late. All other
7011 // graphics devices must be similarly suppressed. But the delay till
7012 // the following cycle should be short.
7013
7014 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
7015 kIOPMSystemCapabilityAudio);
7016
7017 // Immediately bring up audio and graphics
7018 pciRoot = pciHostBridgeDriver;
7019 willEnterFullWake();
7020 promotion = true;
7021 }
7022
7023 // Unsafe to cancel once graphics was powered.
7024 // If system woke from dark wake, the return to sleep can
7025 // be cancelled. "awake -> dark -> sleep" transition
7026 // can be canceled also, during the "dark --> sleep" phase
7027 // *prior* to driver power down.
7028 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
7029 _pendingCapability == 0) {
7030 options |= kIOPMSyncCancelPowerDown;
7031 }
7032
7033 synchronizePowerTree(options, pciRoot);
7034 if (kFullWakeReasonLocalUser == fullWakeReason)
7035 {
7036 // IOGraphics doesn't light the display even though graphics is
7037 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7038 // So, do an explicit activity tickle
7039 if (wrangler)
7040 wrangler->activityTickle(0,0);
7041 }
7042
7043 // Log a timestamp for the initial full wake request.
7044 // System may not always honor this full wake request.
7045 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
7046 {
7047 AbsoluteTime now;
7048 uint64_t nsec;
7049
7050 clock_get_uptime(&now);
7051 SUB_ABSOLUTETIME(&now, &systemWakeTime);
7052 absolutetime_to_nanoseconds(now, &nsec);
7053 MSG("full wake %s (reason %u) %u ms\n",
7054 promotion ? "promotion" : "request",
7055 fullWakeReason, ((int)((nsec) / 1000000ULL)));
7056 }
7057 }
7058
7059 //******************************************************************************
7060 // willEnterFullWake
7061 //
7062 // System will enter full wake from sleep, from dark wake, or from dark
7063 // wake promotion. This function aggregate things that are in common to
7064 // all three full wake transitions.
7065 //
7066 // Assumptions: fullWakeReason was updated
7067 //******************************************************************************
7068
7069 void IOPMrootDomain::willEnterFullWake( void )
7070 {
7071 hibernateRetry = false;
7072 sleepToStandby = false;
7073 sleepTimerMaintenance = false;
7074
7075 _systemMessageClientMask = kSystemMessageClientPowerd |
7076 kSystemMessageClientLegacyApp;
7077
7078 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
7079 {
7080 // Initial graphics full power
7081 _systemMessageClientMask |= kSystemMessageClientKernel;
7082
7083 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7084 setProperty(gIOPMUserTriggeredFullWakeKey,
7085 (kFullWakeReasonLocalUser == fullWakeReason) ?
7086 kOSBooleanTrue : kOSBooleanFalse);
7087 }
7088 #if HIBERNATION
7089 IOHibernateSetWakeCapabilities(_pendingCapability);
7090 #endif
7091
7092 IOService::setAdvisoryTickleEnable( true );
7093 tellClients(kIOMessageSystemWillPowerOn);
7094 preventTransitionToUserActive(false);
7095 }
7096
7097 //******************************************************************************
7098 // fullWakeDelayedWork
7099 //
7100 // System has already entered full wake. Invoked by a delayed thread call.
7101 //******************************************************************************
7102
7103 void IOPMrootDomain::fullWakeDelayedWork( void )
7104 {
7105 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7106 // Not gated, don't modify state
7107 if ((kSystemTransitionNone == _systemTransitionType) &&
7108 CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7109 {
7110 receivePowerNotification( kLocalEvalClamshellCommand );
7111 }
7112 #endif
7113 }
7114
7115 //******************************************************************************
7116 // evaluateAssertions
7117 //
7118 //******************************************************************************
7119 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
7120 {
7121 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
7122
7123 messageClients(kIOPMMessageDriverAssertionsChanged);
7124
7125 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
7126
7127 if (wrangler) {
7128 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
7129
7130 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
7131 wrangler->setIgnoreIdleTimer( value );
7132 }
7133 }
7134
7135 if (changedBits & kIOPMDriverAssertionCPUBit) {
7136 evaluatePolicy(kStimulusDarkWakeEvaluate);
7137 if (!assertOnWakeSecs && systemWakeTime) {
7138 AbsoluteTime now;
7139 clock_usec_t microsecs;
7140 clock_get_uptime(&now);
7141 SUB_ABSOLUTETIME(&now, &systemWakeTime);
7142 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
7143 if (assertOnWakeReport) {
7144 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
7145 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
7146 }
7147 }
7148 }
7149
7150 if (changedBits & kIOPMDriverAssertionReservedBit7) {
7151 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
7152 if (value) {
7153 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7154 updatePreventIdleSleepList(this, true);
7155 }
7156 else {
7157 DLOG("Driver assertion ReservedBit7 dropped\n");
7158 updatePreventIdleSleepList(this, false);
7159 }
7160 }
7161 }
7162
7163 // MARK: -
7164 // MARK: Statistics
7165
7166 //******************************************************************************
7167 // pmStats
7168 //
7169 //******************************************************************************
7170
7171 void IOPMrootDomain::pmStatsRecordEvent(
7172 int eventIndex,
7173 AbsoluteTime timestamp)
7174 {
7175 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
7176 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
7177 uint64_t delta;
7178 uint64_t nsec;
7179 OSData *publishPMStats = NULL;
7180
7181 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
7182
7183 absolutetime_to_nanoseconds(timestamp, &nsec);
7184
7185 switch (eventIndex) {
7186 case kIOPMStatsHibernateImageWrite:
7187 if (starting)
7188 gPMStats.hibWrite.start = nsec;
7189 else if (stopping)
7190 gPMStats.hibWrite.stop = nsec;
7191
7192 if (stopping) {
7193 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
7194 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
7195 }
7196 break;
7197 case kIOPMStatsHibernateImageRead:
7198 if (starting)
7199 gPMStats.hibRead.start = nsec;
7200 else if (stopping)
7201 gPMStats.hibRead.stop = nsec;
7202
7203 if (stopping) {
7204 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
7205 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
7206
7207 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
7208 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
7209 publishPMStats->release();
7210 bzero(&gPMStats, sizeof(gPMStats));
7211 }
7212 break;
7213 }
7214 }
7215
7216 /*
7217 * Appends a record of the application response to
7218 * IOPMrootDomain::pmStatsAppResponses
7219 */
7220 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7221 const OSSymbol *response,
7222 const char *name,
7223 int messageType,
7224 uint32_t delay_ms,
7225 int app_pid,
7226 OSObject *object,
7227 IOPMPowerStateIndex powerState)
7228 {
7229 OSDictionary *responseDescription = NULL;
7230 OSNumber *delayNum = NULL;
7231 OSNumber *powerCaps = NULL;
7232 OSNumber *pidNum = NULL;
7233 OSNumber *msgNum = NULL;
7234 const OSSymbol *appname;
7235 const OSSymbol *sleep = NULL, *wake = NULL;
7236 IOPMServiceInterestNotifier *notify = 0;
7237
7238 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
7239 {
7240 if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut))
7241 notify->ackTimeoutCnt++;
7242 else
7243 notify->ackTimeoutCnt = 0;
7244
7245 }
7246
7247 if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) ||
7248 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
7249 return;
7250
7251
7252 responseDescription = OSDictionary::withCapacity(5);
7253 if (responseDescription)
7254 {
7255 if (response) {
7256 responseDescription->setObject(_statsResponseTypeKey, response);
7257 }
7258
7259 msgNum = OSNumber::withNumber(messageType, 32);
7260 if (msgNum) {
7261 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7262 msgNum->release();
7263 }
7264
7265 if (name && (strlen(name) > 0))
7266 {
7267 appname = OSSymbol::withCString(name);
7268 if (appname) {
7269 responseDescription->setObject(_statsNameKey, appname);
7270 appname->release();
7271 }
7272 }
7273
7274 if (app_pid != -1) {
7275 pidNum = OSNumber::withNumber(app_pid, 32);
7276 if (pidNum) {
7277 responseDescription->setObject(_statsPIDKey, pidNum);
7278 pidNum->release();
7279 }
7280 }
7281
7282 delayNum = OSNumber::withNumber(delay_ms, 32);
7283 if (delayNum) {
7284 responseDescription->setObject(_statsTimeMSKey, delayNum);
7285 delayNum->release();
7286 }
7287
7288 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7289 powerCaps = OSNumber::withNumber(powerState, 32);
7290
7291 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7292 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7293 name, messageType,
7294 powerState, delay_ms);
7295 #endif
7296
7297 }
7298 else {
7299 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
7300 }
7301 if (powerCaps) {
7302 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7303 powerCaps->release();
7304 }
7305
7306 sleep = OSSymbol::withCString("Sleep");
7307 wake = OSSymbol::withCString("Wake");
7308 if (_systemTransitionType == kSystemTransitionSleep) {
7309 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7310 }
7311 else if (_systemTransitionType == kSystemTransitionWake) {
7312 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7313 }
7314 else if (_systemTransitionType == kSystemTransitionCapability) {
7315 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
7316 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7317 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
7318 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7319 }
7320 if (sleep) sleep->release();
7321 if (wake) wake->release();
7322
7323
7324
7325 IOLockLock(pmStatsLock);
7326 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
7327 pmStatsAppResponses->setObject(responseDescription);
7328 }
7329 IOLockUnlock(pmStatsLock);
7330
7331 responseDescription->release();
7332 }
7333
7334 return;
7335 }
7336
7337 // MARK: -
7338 // MARK: PMTraceWorker
7339
7340 //******************************************************************************
7341 // TracePoint support
7342 //
7343 //******************************************************************************
7344
7345 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7346 "IOPMRegisterNVRAMTracePointHandler"
7347
7348 IOReturn IOPMrootDomain::callPlatformFunction(
7349 const OSSymbol * functionName,
7350 bool waitForFunction,
7351 void * param1, void * param2,
7352 void * param3, void * param4 )
7353 {
7354 if (pmTracer && functionName &&
7355 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7356 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7357 {
7358 uint32_t tracePointPhases, tracePointPCI;
7359 uint64_t statusCode;
7360
7361 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7362 pmTracer->tracePointTarget = (void *) param2;
7363 tracePointPCI = (uint32_t)(uintptr_t) param3;
7364 tracePointPhases = (uint32_t)(uintptr_t) param4;
7365 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
7366 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
7367 {
7368 MSG("Sleep failure code 0x%08x 0x%08x\n",
7369 tracePointPCI, tracePointPhases);
7370 }
7371 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
7372 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7373
7374 return kIOReturnSuccess;
7375 }
7376 #if HIBERNATION
7377 else if (functionName &&
7378 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
7379 {
7380 if (gSleepPolicyHandler)
7381 return kIOReturnExclusiveAccess;
7382 if (!param1)
7383 return kIOReturnBadArgument;
7384 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
7385 gSleepPolicyTarget = (void *) param2;
7386 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
7387 return kIOReturnSuccess;
7388 }
7389 #endif
7390
7391 return super::callPlatformFunction(
7392 functionName, waitForFunction, param1, param2, param3, param4);
7393 }
7394
7395 void IOPMrootDomain::tracePoint( uint8_t point )
7396 {
7397 if (systemBooting) return;
7398
7399 if (kIOPMTracePointWakeCapabilityClients == point)
7400 acceptSystemWakeEvents(false);
7401
7402 PMDebug(kPMLogSleepWakeTracePoint, point, 0);
7403 pmTracer->tracePoint(point);
7404 }
7405
7406 void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
7407 {
7408 if (systemBooting) return;
7409
7410 PMDebug(kPMLogSleepWakeTracePoint, point, data);
7411 pmTracer->tracePoint(point, data);
7412 }
7413
7414 void IOPMrootDomain::traceDetail( uint32_t detail )
7415 {
7416 if (!systemBooting)
7417 pmTracer->traceDetail( detail );
7418 }
7419
7420
7421 void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
7422 {
7423 size_t reportSize;
7424 void **report = NULL;
7425 uint32_t bktCnt;
7426 uint32_t bktSize;
7427 uint32_t *clientCnt;
7428
7429 ASSERT_GATED();
7430
7431 report = NULL;
7432 if (channel_id == kAssertDelayChID) {
7433 report = &assertOnWakeReport;
7434 bktCnt = kAssertDelayBcktCnt;
7435 bktSize = kAssertDelayBcktSize;
7436 clientCnt = &assertOnWakeClientCnt;
7437 }
7438 else if (channel_id == kSleepDelaysChID) {
7439 report = &sleepDelaysReport;
7440 bktCnt = kSleepDelaysBcktCnt;
7441 bktSize = kSleepDelaysBcktSize;
7442 clientCnt = &sleepDelaysClientCnt;
7443 }
7444
7445 switch (action)
7446 {
7447 case kIOReportEnable:
7448
7449 if (*report) {
7450 (*clientCnt)++;
7451 break;
7452 }
7453
7454 reportSize = HISTREPORT_BUFSIZE(bktCnt);
7455 *report = IOMalloc(reportSize);
7456 if (*report == NULL) {
7457 break;
7458 }
7459 bzero(*report, reportSize);
7460 HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
7461 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
7462
7463 if (channel_id == kAssertDelayChID)
7464 assertOnWakeSecs = 0;
7465
7466 break;
7467
7468 case kIOReportDisable:
7469 if (*clientCnt == 0) {
7470 break;
7471 }
7472 if (*clientCnt == 1)
7473 {
7474 IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
7475 *report = NULL;
7476 }
7477 (*clientCnt)--;
7478
7479 if (channel_id == kAssertDelayChID)
7480 assertOnWakeSecs = -1; // Invalid value to prevent updates
7481
7482 break;
7483
7484 case kIOReportGetDimensions:
7485 if (*report) {
7486 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
7487 }
7488 break;
7489 }
7490
7491 return;
7492 }
7493
7494 IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
7495 IOReportConfigureAction action,
7496 void *result,
7497 void *destination)
7498 {
7499 unsigned cnt;
7500 uint64_t configAction = (uint64_t)action;
7501
7502 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7503 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
7504 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
7505 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
7506 if (action != kIOReportGetDimensions) continue;
7507 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7508 }
7509 else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
7510 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
7511 gIOPMWorkLoop->runAction(
7512 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
7513 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
7514 (void *)configAction, (void *)result);
7515 }
7516 }
7517
7518 return super::configureReport(channelList, action, result, destination);
7519 }
7520
7521 IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
7522 {
7523
7524 uint32_t size2cpy;
7525 void *data2cpy;
7526 void **report;
7527
7528 ASSERT_GATED();
7529
7530 report = NULL;
7531 if (ch_id == kAssertDelayChID) {
7532 report = &assertOnWakeReport;
7533 }
7534 else if (ch_id == kSleepDelaysChID) {
7535 report = &sleepDelaysReport;
7536 }
7537
7538 if (*report == NULL) {
7539 return kIOReturnNotOpen;
7540 }
7541
7542 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
7543 if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
7544 return kIOReturnOverrun;
7545 }
7546
7547 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
7548 dest->appendBytes(data2cpy, size2cpy);
7549
7550 return kIOReturnSuccess;
7551 }
7552
7553 IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
7554 IOReportUpdateAction action,
7555 void *result,
7556 void *destination)
7557 {
7558 uint32_t size2cpy;
7559 void *data2cpy;
7560 uint8_t buf[SIMPLEREPORT_BUFSIZE];
7561 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7562 unsigned cnt;
7563 uint64_t ch_id;
7564
7565 if (action != kIOReportCopyChannelData) goto exit;
7566
7567 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7568 ch_id = channelList->channels[cnt].channel_id ;
7569
7570 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
7571 gIOPMWorkLoop->runAction(
7572 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
7573 (OSObject *)this, (void *)ch_id,
7574 (void *)result, (void *)dest);
7575 continue;
7576
7577 }
7578 else if ((ch_id == kSleepCntChID) ||
7579 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
7580 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
7581 }
7582 else continue;
7583
7584 if (ch_id == kSleepCntChID)
7585 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
7586 else if (ch_id == kDarkWkCntChID)
7587 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
7588 else if (ch_id == kUserWkCntChID)
7589 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
7590
7591 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7592 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7593 dest->appendBytes(data2cpy, size2cpy);
7594 }
7595
7596 exit:
7597 return super::updateReport(channelList, action, result, destination);
7598 }
7599
7600
7601 //******************************************************************************
7602 // PMTraceWorker Class
7603 //
7604 //******************************************************************************
7605
7606 #undef super
7607 #define super OSObject
7608 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
7609
7610 #define kPMBestGuessPCIDevicesCount 25
7611 #define kPMMaxRTCBitfieldSize 32
7612
7613 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
7614 {
7615 PMTraceWorker *me;
7616
7617 me = OSTypeAlloc( PMTraceWorker );
7618 if (!me || !me->init())
7619 {
7620 return NULL;
7621 }
7622
7623 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
7624
7625 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7626 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7627 // this dictionary lazily.
7628 me->owner = owner;
7629 me->pciDeviceBitMappings = NULL;
7630 me->pciMappingLock = IOLockAlloc();
7631 me->tracePhase = kIOPMTracePointSystemUp;
7632 me->loginWindowPhase = 0;
7633 me->traceData32 = 0;
7634 return me;
7635 }
7636
7637 void PMTraceWorker::RTC_TRACE(void)
7638 {
7639 if (tracePointHandler && tracePointTarget)
7640 {
7641 uint32_t wordA;
7642
7643 wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
7644 (traceData8 << 8);
7645
7646 tracePointHandler( tracePointTarget, traceData32, wordA );
7647 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
7648 }
7649 }
7650
7651 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
7652 {
7653 const OSSymbol * deviceName;
7654 int index = -1;
7655
7656 IOLockLock(pciMappingLock);
7657
7658 if (!pciDeviceBitMappings)
7659 {
7660 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
7661 if (!pciDeviceBitMappings)
7662 goto exit;
7663 }
7664
7665 // Check for bitmask overflow.
7666 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
7667 goto exit;
7668
7669 if ((deviceName = pciDevice->copyName()) &&
7670 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
7671 pciDeviceBitMappings->setObject(deviceName))
7672 {
7673 index = pciDeviceBitMappings->getCount() - 1;
7674 _LOG("PMTrace PCI array: set object %s => %d\n",
7675 deviceName->getCStringNoCopy(), index);
7676 }
7677 if (deviceName)
7678 deviceName->release();
7679 if (!addedToRegistry && (index >= 0))
7680 addedToRegistry = owner->setProperty("PCITopLevel", this);
7681
7682 exit:
7683 IOLockUnlock(pciMappingLock);
7684 return index;
7685 }
7686
7687 bool PMTraceWorker::serialize(OSSerialize *s) const
7688 {
7689 bool ok = false;
7690 if (pciDeviceBitMappings)
7691 {
7692 IOLockLock(pciMappingLock);
7693 ok = pciDeviceBitMappings->serialize(s);
7694 IOLockUnlock(pciMappingLock);
7695 }
7696 return ok;
7697 }
7698
7699 void PMTraceWorker::tracePoint(uint8_t phase)
7700 {
7701 // clear trace detail when phase begins
7702 if (tracePhase != phase)
7703 traceData32 = 0;
7704
7705 tracePhase = phase;
7706
7707 DLOG("trace point 0x%02x\n", tracePhase);
7708 RTC_TRACE();
7709 }
7710
7711 void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
7712 {
7713 // clear trace detail when phase begins
7714 if (tracePhase != phase)
7715 traceData32 = 0;
7716
7717 tracePhase = phase;
7718 traceData8 = data8;
7719
7720 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
7721 RTC_TRACE();
7722 }
7723
7724 void PMTraceWorker::traceDetail(uint32_t detail)
7725 {
7726 if (kIOPMTracePointSleepPriorityClients != tracePhase)
7727 return;
7728
7729 traceData32 = detail;
7730 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7731
7732 RTC_TRACE();
7733 }
7734
7735 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
7736 {
7737 loginWindowPhase = phase;
7738
7739 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
7740 RTC_TRACE();
7741 }
7742
7743 void PMTraceWorker::tracePCIPowerChange(
7744 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
7745 {
7746 uint32_t bitMask;
7747 uint32_t expectedFlag;
7748
7749 // Ignore PCI changes outside of system sleep/wake.
7750 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
7751 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
7752 return;
7753
7754 // Only record the WillChange transition when going to sleep,
7755 // and the DidChange on the way up.
7756 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
7757 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
7758 kIOPMDomainWillChange : kIOPMDomainDidChange;
7759 if (changeFlags != expectedFlag)
7760 return;
7761
7762 // Mark this device off in our bitfield
7763 if (bitNum < kPMMaxRTCBitfieldSize)
7764 {
7765 bitMask = (1 << bitNum);
7766
7767 if (kPowerChangeStart == type)
7768 {
7769 traceData32 |= bitMask;
7770 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7771 service->getName(), bitNum, bitMask, traceData32);
7772 }
7773 else
7774 {
7775 traceData32 &= ~bitMask;
7776 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7777 service->getName(), bitNum, bitMask, traceData32);
7778 }
7779
7780 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7781 RTC_TRACE();
7782 }
7783 }
7784
7785 uint64_t PMTraceWorker::getPMStatusCode( )
7786 {
7787 return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase << 24) |
7788 (loginWindowPhase << 16) | (traceData8 << 8));
7789
7790 }
7791
7792 // MARK: -
7793 // MARK: PMHaltWorker
7794
7795 //******************************************************************************
7796 // PMHaltWorker Class
7797 //
7798 //******************************************************************************
7799
7800 PMHaltWorker * PMHaltWorker::worker( void )
7801 {
7802 PMHaltWorker * me;
7803 IOThread thread;
7804
7805 do {
7806 me = OSTypeAlloc( PMHaltWorker );
7807 if (!me || !me->init())
7808 break;
7809
7810 me->lock = IOLockAlloc();
7811 if (!me->lock)
7812 break;
7813
7814 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
7815 me->retain(); // thread holds extra retain
7816 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
7817 {
7818 me->release();
7819 break;
7820 }
7821 thread_deallocate(thread);
7822 return me;
7823
7824 } while (false);
7825
7826 if (me) me->release();
7827 return 0;
7828 }
7829
7830 void PMHaltWorker::free( void )
7831 {
7832 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7833 if (lock)
7834 {
7835 IOLockFree(lock);
7836 lock = 0;
7837 }
7838 return OSObject::free();
7839 }
7840
7841 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
7842 {
7843 PMHaltWorker * me = (PMHaltWorker *) arg;
7844
7845 IOLockLock( gPMHaltLock );
7846 gPMHaltBusyCount++;
7847 me->depth = gPMHaltDepth;
7848 IOLockUnlock( gPMHaltLock );
7849
7850 while (me->depth >= 0)
7851 {
7852 PMHaltWorker::work( me );
7853
7854 IOLockLock( gPMHaltLock );
7855 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
7856 {
7857 // This is the last thread to finish work on this level,
7858 // inform everyone to start working on next lower level.
7859 gPMHaltDepth--;
7860 me->depth = gPMHaltDepth;
7861 gPMHaltIdleCount = 0;
7862 thread_wakeup((event_t) &gPMHaltIdleCount);
7863 }
7864 else
7865 {
7866 // One or more threads are still working on this level,
7867 // this thread must wait.
7868 me->depth = gPMHaltDepth - 1;
7869 do {
7870 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
7871 } while (me->depth != gPMHaltDepth);
7872 }
7873 IOLockUnlock( gPMHaltLock );
7874 }
7875
7876 // No more work to do, terminate thread
7877 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
7878 thread_wakeup( &gPMHaltDepth );
7879 me->release();
7880 }
7881
7882 void PMHaltWorker::work( PMHaltWorker * me )
7883 {
7884 IOService * service;
7885 OSSet * inner;
7886 AbsoluteTime startTime;
7887 UInt32 deltaTime;
7888 bool timeout;
7889
7890 while (true)
7891 {
7892 service = 0;
7893 timeout = false;
7894
7895 // Claim an unit of work from the shared pool
7896 IOLockLock( gPMHaltLock );
7897 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
7898 if (inner)
7899 {
7900 service = (IOService *)inner->getAnyObject();
7901 if (service)
7902 {
7903 service->retain();
7904 inner->removeObject(service);
7905 }
7906 }
7907 IOLockUnlock( gPMHaltLock );
7908 if (!service)
7909 break; // no more work at this depth
7910
7911 clock_get_uptime(&startTime);
7912
7913 if (!service->isInactive() &&
7914 service->setProperty(gPMHaltClientAcknowledgeKey, me))
7915 {
7916 IOLockLock(me->lock);
7917 me->startTime = startTime;
7918 me->service = service;
7919 me->timeout = false;
7920 IOLockUnlock(me->lock);
7921
7922 service->systemWillShutdown( gPMHaltMessageType );
7923
7924 // Wait for driver acknowledgement
7925 IOLockLock(me->lock);
7926 while (service->getProperty(gPMHaltClientAcknowledgeKey))
7927 {
7928 IOLockSleep(me->lock, me, THREAD_UNINT);
7929 }
7930 me->service = 0;
7931 timeout = me->timeout;
7932 IOLockUnlock(me->lock);
7933 }
7934
7935 deltaTime = computeDeltaTimeMS(&startTime);
7936 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
7937 (gIOKitDebug & kIOLogPMRootDomain))
7938 {
7939 LOG("%s driver %s (0x%llx) took %u ms\n",
7940 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
7941 "PowerOff" : "Restart",
7942 service->getName(), service->getRegistryEntryID(),
7943 (uint32_t) deltaTime );
7944 }
7945
7946 service->release();
7947 me->visits++;
7948 }
7949 }
7950
7951 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
7952 {
7953 UInt64 nano;
7954 AbsoluteTime startTime;
7955 AbsoluteTime endTime;
7956
7957 endTime = *now;
7958
7959 IOLockLock(me->lock);
7960 if (me->service && !me->timeout)
7961 {
7962 startTime = me->startTime;
7963 nano = 0;
7964 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
7965 {
7966 SUB_ABSOLUTETIME(&endTime, &startTime);
7967 absolutetime_to_nanoseconds(endTime, &nano);
7968 }
7969 if (nano > 3000000000ULL)
7970 {
7971 me->timeout = true;
7972 MSG("%s still waiting on %s\n",
7973 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
7974 "PowerOff" : "Restart",
7975 me->service->getName());
7976 }
7977 }
7978 IOLockUnlock(me->lock);
7979 }
7980
7981 //******************************************************************************
7982 // acknowledgeSystemWillShutdown
7983 //
7984 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7985 //******************************************************************************
7986
7987 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
7988 {
7989 PMHaltWorker * worker;
7990 OSObject * prop;
7991
7992 if (!from)
7993 return;
7994
7995 //DLOG("%s acknowledged\n", from->getName());
7996 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
7997 if (prop)
7998 {
7999 worker = (PMHaltWorker *) prop;
8000 IOLockLock(worker->lock);
8001 from->removeProperty( gPMHaltClientAcknowledgeKey );
8002 thread_wakeup((event_t) worker);
8003 IOLockUnlock(worker->lock);
8004 worker->release();
8005 }
8006 else
8007 {
8008 DLOG("%s acknowledged without worker property\n",
8009 from->getName());
8010 }
8011 }
8012
8013
8014 //******************************************************************************
8015 // notifySystemShutdown
8016 //
8017 // Notify all objects in PM tree that system will shutdown or restart
8018 //******************************************************************************
8019
8020 static void
8021 notifySystemShutdown( IOService * root, uint32_t messageType )
8022 {
8023 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8024 IORegistryIterator * iter;
8025 IORegistryEntry * entry;
8026 IOService * node;
8027 OSSet * inner;
8028 PMHaltWorker * workers[kPMHaltMaxWorkers];
8029 AbsoluteTime deadline;
8030 unsigned int totalNodes = 0;
8031 unsigned int depth;
8032 unsigned int rootDepth;
8033 unsigned int numWorkers;
8034 unsigned int count;
8035 int waitResult;
8036 void * baseFunc;
8037 bool ok;
8038
8039 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
8040
8041 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
8042
8043 // Iterate the entire PM tree starting from root
8044
8045 rootDepth = root->getDepth( gIOPowerPlane );
8046 if (!rootDepth) goto done;
8047
8048 // debug - for repeated test runs
8049 while (PMHaltWorker::metaClass->getInstanceCount())
8050 IOSleep(1);
8051
8052 if (!gPMHaltArray)
8053 {
8054 gPMHaltArray = OSArray::withCapacity(40);
8055 if (!gPMHaltArray) goto done;
8056 }
8057 else // debug
8058 gPMHaltArray->flushCollection();
8059
8060 if (!gPMHaltLock)
8061 {
8062 gPMHaltLock = IOLockAlloc();
8063 if (!gPMHaltLock) goto done;
8064 }
8065
8066 if (!gPMHaltClientAcknowledgeKey)
8067 {
8068 gPMHaltClientAcknowledgeKey =
8069 OSSymbol::withCStringNoCopy("PMShutdown");
8070 if (!gPMHaltClientAcknowledgeKey) goto done;
8071 }
8072
8073 gPMHaltMessageType = messageType;
8074
8075 // Depth-first walk of PM plane
8076
8077 iter = IORegistryIterator::iterateOver(
8078 root, gIOPowerPlane, kIORegistryIterateRecursively);
8079
8080 if (iter)
8081 {
8082 while ((entry = iter->getNextObject()))
8083 {
8084 node = OSDynamicCast(IOService, entry);
8085 if (!node)
8086 continue;
8087
8088 if (baseFunc ==
8089 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
8090 continue;
8091
8092 depth = node->getDepth( gIOPowerPlane );
8093 if (depth <= rootDepth)
8094 continue;
8095
8096 ok = false;
8097
8098 // adjust to zero based depth
8099 depth -= (rootDepth + 1);
8100
8101 // gPMHaltArray is an array of containers, each container
8102 // refers to nodes with the same depth.
8103
8104 count = gPMHaltArray->getCount();
8105 while (depth >= count)
8106 {
8107 // expand array and insert placeholders
8108 gPMHaltArray->setObject(PLACEHOLDER);
8109 count++;
8110 }
8111 count = gPMHaltArray->getCount();
8112 if (depth < count)
8113 {
8114 inner = (OSSet *)gPMHaltArray->getObject(depth);
8115 if (inner == PLACEHOLDER)
8116 {
8117 inner = OSSet::withCapacity(40);
8118 if (inner)
8119 {
8120 gPMHaltArray->replaceObject(depth, inner);
8121 inner->release();
8122 }
8123 }
8124
8125 // PM nodes that appear more than once in the tree will have
8126 // the same depth, OSSet will refuse to add the node twice.
8127 if (inner)
8128 ok = inner->setObject(node);
8129 }
8130 if (!ok)
8131 DLOG("Skipped PM node %s\n", node->getName());
8132 }
8133 iter->release();
8134 }
8135
8136 // debug only
8137 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
8138 {
8139 count = 0;
8140 if (inner != PLACEHOLDER)
8141 count = inner->getCount();
8142 DLOG("Nodes at depth %u = %u\n", i, count);
8143 }
8144
8145 // strip placeholders (not all depths are populated)
8146 numWorkers = 0;
8147 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
8148 {
8149 if (inner == PLACEHOLDER)
8150 {
8151 gPMHaltArray->removeObject(i);
8152 continue;
8153 }
8154 count = inner->getCount();
8155 if (count > numWorkers)
8156 numWorkers = count;
8157 totalNodes += count;
8158 i++;
8159 }
8160
8161 if (gPMHaltArray->getCount() == 0 || !numWorkers)
8162 goto done;
8163
8164 gPMHaltBusyCount = 0;
8165 gPMHaltIdleCount = 0;
8166 gPMHaltDepth = gPMHaltArray->getCount() - 1;
8167
8168 // Create multiple workers (and threads)
8169
8170 if (numWorkers > kPMHaltMaxWorkers)
8171 numWorkers = kPMHaltMaxWorkers;
8172
8173 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8174 totalNodes, gPMHaltArray->getCount(), numWorkers);
8175
8176 for (unsigned int i = 0; i < numWorkers; i++)
8177 workers[i] = PMHaltWorker::worker();
8178
8179 // Wait for workers to exhaust all available work
8180
8181 IOLockLock(gPMHaltLock);
8182 while (gPMHaltDepth >= 0)
8183 {
8184 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
8185
8186 waitResult = IOLockSleepDeadline(
8187 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
8188 if (THREAD_TIMED_OUT == waitResult)
8189 {
8190 AbsoluteTime now;
8191 clock_get_uptime(&now);
8192
8193 IOLockUnlock(gPMHaltLock);
8194 for (unsigned int i = 0 ; i < numWorkers; i++)
8195 {
8196 if (workers[i])
8197 PMHaltWorker::checkTimeout(workers[i], &now);
8198 }
8199 IOLockLock(gPMHaltLock);
8200 }
8201 }
8202 IOLockUnlock(gPMHaltLock);
8203
8204 // Release all workers
8205
8206 for (unsigned int i = 0; i < numWorkers; i++)
8207 {
8208 if (workers[i])
8209 workers[i]->release();
8210 // worker also retained by it's own thread
8211 }
8212
8213 done:
8214 DLOG("%s done\n", __FUNCTION__);
8215 return;
8216 }
8217
8218 // MARK: -
8219 // MARK: Kernel Assertion
8220
8221 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8222
8223 IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
8224 IOPMDriverAssertionType whichAssertionBits,
8225 IOPMDriverAssertionLevel assertionLevel,
8226 IOService *ownerService,
8227 const char *ownerDescription)
8228 {
8229 IOReturn ret;
8230 IOPMDriverAssertionID newAssertion;
8231
8232 if (!pmAssertions)
8233 return 0;
8234
8235 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
8236
8237 if (kIOReturnSuccess == ret)
8238 return newAssertion;
8239 else
8240 return 0;
8241 }
8242
8243 IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
8244 {
8245 if (!pmAssertions)
8246 return kIOReturnInternalError;
8247
8248 return pmAssertions->releaseAssertion(releaseAssertion);
8249 }
8250
8251
8252 IOReturn IOPMrootDomain::setPMAssertionLevel(
8253 IOPMDriverAssertionID assertionID,
8254 IOPMDriverAssertionLevel assertionLevel)
8255 {
8256 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8257 }
8258
8259 IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8260 {
8261 IOPMDriverAssertionType sysLevels;
8262
8263 if (!pmAssertions || whichAssertion == 0)
8264 return kIOPMDriverAssertionLevelOff;
8265
8266 sysLevels = pmAssertions->getActivatedAssertions();
8267
8268 // Check that every bit set in argument 'whichAssertion' is asserted
8269 // in the aggregate bits.
8270 if ((sysLevels & whichAssertion) == whichAssertion)
8271 return kIOPMDriverAssertionLevelOn;
8272 else
8273 return kIOPMDriverAssertionLevelOff;
8274 }
8275
8276 IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
8277 {
8278 if (!pmAssertions)
8279 return kIOReturnNotFound;
8280
8281 return pmAssertions->setUserAssertionLevels(inLevels);
8282 }
8283
8284 bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
8285 {
8286 if (pmAssertions)
8287 {
8288 pmAssertions->publishProperties();
8289 }
8290 return( IOService::serializeProperties(s) );
8291 }
8292
8293 OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8294 {
8295 OSObject *obj = NULL;
8296 obj = IOService::copyProperty(aKey);
8297
8298 if (obj) return obj;
8299
8300 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
8301 sizeof(kIOPMSleepWakeWdogRebootKey))) {
8302 if (swd_flags & SWD_BOOT_BY_SW_WDOG)
8303 return kOSBooleanTrue;
8304 else
8305 return kOSBooleanFalse;
8306
8307 }
8308
8309 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
8310 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
8311 if (swd_flags & SWD_VALID_LOGS)
8312 return kOSBooleanTrue;
8313 else
8314 return kOSBooleanFalse;
8315
8316 }
8317
8318 /*
8319 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8320 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8321 * issued by DisplayWrangler on darkwake.
8322 */
8323 if (!strcmp(aKey, "DesktopMode")) {
8324 if (desktopMode)
8325 return kOSBooleanTrue;
8326 else
8327 return kOSBooleanFalse;
8328 }
8329 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8330 if (displayIdleForDemandSleep) {
8331 return kOSBooleanTrue;
8332 }
8333 else {
8334 return kOSBooleanFalse;
8335 }
8336 }
8337
8338 if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
8339 {
8340 OSArray * array = 0;
8341 WAKEEVENT_LOCK();
8342 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
8343 OSCollection *collection = _systemWakeEventsArray->copyCollection();
8344 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8345 collection->release();
8346 }
8347 }
8348 WAKEEVENT_UNLOCK();
8349 return array;
8350 }
8351
8352 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
8353 {
8354 OSArray * array = 0;
8355 IOLockLock(pmStatsLock);
8356 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
8357 OSCollection *collection = pmStatsAppResponses->copyCollection();
8358 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8359 collection->release();
8360 }
8361 pmStatsAppResponses->flushCollection();
8362 }
8363 IOLockUnlock(pmStatsLock);
8364 return array;
8365 }
8366
8367 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
8368 {
8369 OSArray *idleSleepList = NULL;
8370 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
8371 return idleSleepList;
8372 }
8373
8374 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
8375 {
8376 OSArray *systemSleepList = NULL;
8377 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
8378 return systemSleepList;
8379 }
8380
8381 return NULL;
8382 }
8383
8384 // MARK: -
8385 // MARK: Wake Event Reporting
8386
8387 void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
8388 {
8389 WAKEEVENT_LOCK();
8390 strlcpy(outBuf, gWakeReasonString, bufSize);
8391 WAKEEVENT_UNLOCK();
8392 }
8393
8394 //******************************************************************************
8395 // acceptSystemWakeEvents
8396 //
8397 // Private control for the acceptance of driver wake event claims.
8398 //******************************************************************************
8399
8400 void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
8401 {
8402 bool logWakeReason = false;
8403
8404 WAKEEVENT_LOCK();
8405 if (accept)
8406 {
8407 gWakeReasonString[0] = '\0';
8408 if (!_systemWakeEventsArray)
8409 _systemWakeEventsArray = OSArray::withCapacity(4);
8410 if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
8411 _systemWakeEventsArray->flushCollection();
8412 }
8413 else
8414 {
8415 _acceptSystemWakeEvents = false;
8416 }
8417 WAKEEVENT_UNLOCK();
8418
8419 if (logWakeReason)
8420 MSG("system wake events:%s\n", gWakeReasonString);
8421 }
8422
8423 //******************************************************************************
8424 // claimSystemWakeEvent
8425 //
8426 // For a driver to claim a device is the source/conduit of a system wake event.
8427 //******************************************************************************
8428
8429 void IOPMrootDomain::claimSystemWakeEvent(
8430 IOService * device,
8431 IOOptionBits flags,
8432 const char * reason,
8433 OSObject * details )
8434 {
8435 const OSSymbol * deviceName = 0;
8436 OSNumber * deviceRegId = 0;
8437 OSNumber * claimTime = 0;
8438 OSData * flagsData = 0;
8439 OSString * reasonString = 0;
8440 OSDictionary * d = 0;
8441 uint64_t timestamp;
8442 bool ok = false;
8443
8444 pmEventTimeStamp(&timestamp);
8445
8446 if (!device || !reason) return;
8447
8448 deviceName = device->copyName(gIOServicePlane);
8449 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
8450 claimTime = OSNumber::withNumber(timestamp, 64);
8451 flagsData = OSData::withBytes(&flags, sizeof(flags));
8452 reasonString = OSString::withCString(reason);
8453 d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
8454 if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
8455 goto done;
8456
8457 d->setObject(gIONameKey, deviceName);
8458 d->setObject(gIORegistryEntryIDKey, deviceRegId);
8459 d->setObject(kIOPMWakeEventTimeKey, claimTime);
8460 d->setObject(kIOPMWakeEventFlagsKey, flagsData);
8461 d->setObject(kIOPMWakeEventReasonKey, reasonString);
8462 if (details)
8463 d->setObject(kIOPMWakeEventDetailsKey, details);
8464
8465 WAKEEVENT_LOCK();
8466 if (!gWakeReasonSysctlRegistered)
8467 {
8468 // Lazy registration until the platform driver stops registering
8469 // the same name.
8470 gWakeReasonSysctlRegistered = true;
8471 }
8472 if (_acceptSystemWakeEvents)
8473 {
8474 ok = _systemWakeEventsArray->setObject(d);
8475 if (gWakeReasonString[0] != '\0')
8476 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
8477 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
8478 }
8479 WAKEEVENT_UNLOCK();
8480
8481 done:
8482 if (deviceName) deviceName->release();
8483 if (deviceRegId) deviceRegId->release();
8484 if (claimTime) claimTime->release();
8485 if (flagsData) flagsData->release();
8486 if (reasonString) reasonString->release();
8487 if (d) d->release();
8488 }
8489
8490 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8491
8492 // MARK: -
8493 // MARK: PMSettingHandle
8494
8495 OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
8496
8497 void PMSettingHandle::free( void )
8498 {
8499 if (pmso)
8500 {
8501 pmso->clientHandleFreed();
8502 pmso->release();
8503 pmso = 0;
8504 }
8505
8506 OSObject::free();
8507 }
8508
8509 // MARK: -
8510 // MARK: PMSettingObject
8511
8512 #undef super
8513 #define super OSObject
8514 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
8515
8516 /*
8517 * Static constructor/initializer for PMSettingObject
8518 */
8519 PMSettingObject *PMSettingObject::pmSettingObject(
8520 IOPMrootDomain *parent_arg,
8521 IOPMSettingControllerCallback handler_arg,
8522 OSObject *target_arg,
8523 uintptr_t refcon_arg,
8524 uint32_t supportedPowerSources,
8525 const OSSymbol * settings[],
8526 OSObject **handle_obj)
8527 {
8528 uint32_t settingCount = 0;
8529 PMSettingObject *pmso = 0;
8530 PMSettingHandle *pmsh = 0;
8531
8532 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
8533 return NULL;
8534
8535 // count OSSymbol entries in NULL terminated settings array
8536 while (settings[settingCount]) {
8537 settingCount++;
8538 }
8539 if (0 == settingCount)
8540 return NULL;
8541
8542 pmso = new PMSettingObject;
8543 if (!pmso || !pmso->init())
8544 goto fail;
8545
8546 pmsh = new PMSettingHandle;
8547 if (!pmsh || !pmsh->init())
8548 goto fail;
8549
8550 queue_init(&pmso->calloutQueue);
8551 pmso->parent = parent_arg;
8552 pmso->func = handler_arg;
8553 pmso->target = target_arg;
8554 pmso->refcon = refcon_arg;
8555 pmso->settingCount = settingCount;
8556
8557 pmso->retain(); // handle holds a retain on pmso
8558 pmsh->pmso = pmso;
8559 pmso->pmsh = pmsh;
8560
8561 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
8562 if (pmso->publishedFeatureID) {
8563 for (unsigned int i=0; i<settingCount; i++) {
8564 // Since there is now at least one listener to this setting, publish
8565 // PM root domain support for it.
8566 parent_arg->publishPMSetting( settings[i],
8567 supportedPowerSources, &pmso->publishedFeatureID[i] );
8568 }
8569 }
8570
8571 *handle_obj = pmsh;
8572 return pmso;
8573
8574 fail:
8575 if (pmso) pmso->release();
8576 if (pmsh) pmsh->release();
8577 return NULL;
8578 }
8579
8580 void PMSettingObject::free( void )
8581 {
8582 if (publishedFeatureID) {
8583 for (uint32_t i=0; i<settingCount; i++) {
8584 if (publishedFeatureID[i]) {
8585 parent->removePublishedFeature( publishedFeatureID[i] );
8586 }
8587 }
8588
8589 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
8590 }
8591
8592 super::free();
8593 }
8594
8595 void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
8596 {
8597 (*func)(target, type, object, refcon);
8598 }
8599
8600 void PMSettingObject::clientHandleFreed( void )
8601 {
8602 parent->deregisterPMSettingObject(this);
8603 }
8604
8605 // MARK: -
8606 // MARK: PMAssertionsTracker
8607
8608 //*********************************************************************************
8609 //*********************************************************************************
8610 //*********************************************************************************
8611 // class PMAssertionsTracker Implementation
8612
8613 #define kAssertUniqueIDStart 500
8614
8615 PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
8616 {
8617 PMAssertionsTracker *myself;
8618
8619 myself = new PMAssertionsTracker;
8620
8621 if (myself) {
8622 myself->init();
8623 myself->owner = rootDomain;
8624 myself->issuingUniqueID = kAssertUniqueIDStart;
8625 myself->assertionsArray = OSArray::withCapacity(5);
8626 myself->assertionsKernel = 0;
8627 myself->assertionsUser = 0;
8628 myself->assertionsCombined = 0;
8629 myself->assertionsArrayLock = IOLockAlloc();
8630 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
8631
8632 if (!myself->assertionsArray || !myself->assertionsArrayLock)
8633 myself = NULL;
8634 }
8635
8636 return myself;
8637 }
8638
8639 /* tabulate
8640 * - Update assertionsKernel to reflect the state of all
8641 * assertions in the kernel.
8642 * - Update assertionsCombined to reflect both kernel & user space.
8643 */
8644 void PMAssertionsTracker::tabulate(void)
8645 {
8646 int i;
8647 int count;
8648 PMAssertStruct *_a = NULL;
8649 OSData *_d = NULL;
8650
8651 IOPMDriverAssertionType oldKernel = assertionsKernel;
8652 IOPMDriverAssertionType oldCombined = assertionsCombined;
8653
8654 ASSERT_GATED();
8655
8656 assertionsKernel = 0;
8657 assertionsCombined = 0;
8658
8659 if (!assertionsArray)
8660 return;
8661
8662 if ((count = assertionsArray->getCount()))
8663 {
8664 for (i=0; i<count; i++)
8665 {
8666 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8667 if (_d)
8668 {
8669 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8670 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
8671 assertionsKernel |= _a->assertionBits;
8672 }
8673 }
8674 }
8675
8676 tabulateProducerCount++;
8677 assertionsCombined = assertionsKernel | assertionsUser;
8678
8679 if ((assertionsKernel != oldKernel) ||
8680 (assertionsCombined != oldCombined))
8681 {
8682 owner->evaluateAssertions(assertionsCombined, oldCombined);
8683 }
8684 }
8685
8686 void PMAssertionsTracker::publishProperties( void )
8687 {
8688 OSArray *assertionsSummary = NULL;
8689
8690 if (tabulateConsumerCount != tabulateProducerCount)
8691 {
8692 IOLockLock(assertionsArrayLock);
8693
8694 tabulateConsumerCount = tabulateProducerCount;
8695
8696 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8697 */
8698 assertionsSummary = copyAssertionsArray();
8699 if (assertionsSummary)
8700 {
8701 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
8702 assertionsSummary->release();
8703 }
8704 else
8705 {
8706 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
8707 }
8708
8709 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8710 */
8711 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
8712
8713 IOLockUnlock(assertionsArrayLock);
8714 }
8715 }
8716
8717 PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
8718 {
8719 PMAssertStruct *_a = NULL;
8720 OSData *_d = NULL;
8721 int found = -1;
8722 int count = 0;
8723 int i = 0;
8724
8725 if (assertionsArray
8726 && (count = assertionsArray->getCount()))
8727 {
8728 for (i=0; i<count; i++)
8729 {
8730 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8731 if (_d)
8732 {
8733 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8734 if (_a && (_id == _a->id)) {
8735 found = i;
8736 break;
8737 }
8738 }
8739 }
8740 }
8741
8742 if (-1 == found) {
8743 return NULL;
8744 } else {
8745 if (index)
8746 *index = found;
8747 return _a;
8748 }
8749 }
8750
8751 /* PMAssertionsTracker::handleCreateAssertion
8752 * Perform assertion work on the PM workloop. Do not call directly.
8753 */
8754 IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
8755 {
8756 ASSERT_GATED();
8757
8758 if (newAssertion)
8759 {
8760 IOLockLock(assertionsArrayLock);
8761 assertionsArray->setObject(newAssertion);
8762 IOLockUnlock(assertionsArrayLock);
8763 newAssertion->release();
8764
8765 tabulate();
8766 }
8767 return kIOReturnSuccess;
8768 }
8769
8770 /* PMAssertionsTracker::createAssertion
8771 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8772 * appropiate.
8773 */
8774 IOReturn PMAssertionsTracker::createAssertion(
8775 IOPMDriverAssertionType which,
8776 IOPMDriverAssertionLevel level,
8777 IOService *serviceID,
8778 const char *whoItIs,
8779 IOPMDriverAssertionID *outID)
8780 {
8781 OSData *dataStore = NULL;
8782 PMAssertStruct track;
8783
8784 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8785 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
8786 track.level = level;
8787 track.assertionBits = which;
8788 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
8789 track.ownerService = serviceID;
8790 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
8791 track.modifiedTime = 0;
8792 pmEventTimeStamp(&track.createdTime);
8793
8794 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
8795 if (!dataStore)
8796 {
8797 if (track.ownerString)
8798 track.ownerString->release();
8799 return kIOReturnNoMemory;
8800 }
8801
8802 *outID = track.id;
8803
8804 if (owner && owner->pmPowerStateQueue) {
8805 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
8806 }
8807
8808 return kIOReturnSuccess;
8809 }
8810
8811 /* PMAssertionsTracker::handleReleaseAssertion
8812 * Runs in PM workloop. Do not call directly.
8813 */
8814 IOReturn PMAssertionsTracker::handleReleaseAssertion(
8815 IOPMDriverAssertionID _id)
8816 {
8817 ASSERT_GATED();
8818
8819 int index;
8820 PMAssertStruct *assertStruct = detailsForID(_id, &index);
8821
8822 if (!assertStruct)
8823 return kIOReturnNotFound;
8824
8825 IOLockLock(assertionsArrayLock);
8826 if (assertStruct->ownerString)
8827 assertStruct->ownerString->release();
8828
8829 assertionsArray->removeObject(index);
8830 IOLockUnlock(assertionsArrayLock);
8831
8832 tabulate();
8833 return kIOReturnSuccess;
8834 }
8835
8836 /* PMAssertionsTracker::releaseAssertion
8837 * Releases an assertion and affects system behavior if appropiate.
8838 * Actual work happens on PM workloop.
8839 */
8840 IOReturn PMAssertionsTracker::releaseAssertion(
8841 IOPMDriverAssertionID _id)
8842 {
8843 if (owner && owner->pmPowerStateQueue) {
8844 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
8845 }
8846 return kIOReturnSuccess;
8847 }
8848
8849 /* PMAssertionsTracker::handleSetAssertionLevel
8850 * Runs in PM workloop. Do not call directly.
8851 */
8852 IOReturn PMAssertionsTracker::handleSetAssertionLevel(
8853 IOPMDriverAssertionID _id,
8854 IOPMDriverAssertionLevel _level)
8855 {
8856 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
8857
8858 ASSERT_GATED();
8859
8860 if (!assertStruct) {
8861 return kIOReturnNotFound;
8862 }
8863
8864 IOLockLock(assertionsArrayLock);
8865 pmEventTimeStamp(&assertStruct->modifiedTime);
8866 assertStruct->level = _level;
8867 IOLockUnlock(assertionsArrayLock);
8868
8869 tabulate();
8870 return kIOReturnSuccess;
8871 }
8872
8873 /* PMAssertionsTracker::setAssertionLevel
8874 */
8875 IOReturn PMAssertionsTracker::setAssertionLevel(
8876 IOPMDriverAssertionID _id,
8877 IOPMDriverAssertionLevel _level)
8878 {
8879 if (owner && owner->pmPowerStateQueue) {
8880 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
8881 (void *)(uintptr_t)_level, _id);
8882 }
8883
8884 return kIOReturnSuccess;
8885 }
8886
8887 IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
8888 {
8889 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
8890
8891 ASSERT_GATED();
8892
8893 if (new_user_levels != assertionsUser)
8894 {
8895 assertionsUser = new_user_levels;
8896 DLOG("assertionsUser 0x%llx\n", assertionsUser);
8897 }
8898
8899 tabulate();
8900 return kIOReturnSuccess;
8901 }
8902
8903 IOReturn PMAssertionsTracker::setUserAssertionLevels(
8904 IOPMDriverAssertionType new_user_levels)
8905 {
8906 if (gIOPMWorkLoop) {
8907 gIOPMWorkLoop->runAction(
8908 OSMemberFunctionCast(
8909 IOWorkLoop::Action,
8910 this,
8911 &PMAssertionsTracker::handleSetUserAssertionLevels),
8912 this,
8913 (void *) &new_user_levels, 0, 0, 0);
8914 }
8915
8916 return kIOReturnSuccess;
8917 }
8918
8919
8920 OSArray *PMAssertionsTracker::copyAssertionsArray(void)
8921 {
8922 int count;
8923 int i;
8924 OSArray *outArray = NULL;
8925
8926 if (!assertionsArray ||
8927 (0 == (count = assertionsArray->getCount())) ||
8928 (NULL == (outArray = OSArray::withCapacity(count))))
8929 {
8930 goto exit;
8931 }
8932
8933 for (i=0; i<count; i++)
8934 {
8935 PMAssertStruct *_a = NULL;
8936 OSData *_d = NULL;
8937 OSDictionary *details = NULL;
8938
8939 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8940 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
8941 {
8942 OSNumber *_n = NULL;
8943
8944 details = OSDictionary::withCapacity(7);
8945 if (!details)
8946 continue;
8947
8948 outArray->setObject(details);
8949 details->release();
8950
8951 _n = OSNumber::withNumber(_a->id, 64);
8952 if (_n) {
8953 details->setObject(kIOPMDriverAssertionIDKey, _n);
8954 _n->release();
8955 }
8956 _n = OSNumber::withNumber(_a->createdTime, 64);
8957 if (_n) {
8958 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
8959 _n->release();
8960 }
8961 _n = OSNumber::withNumber(_a->modifiedTime, 64);
8962 if (_n) {
8963 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
8964 _n->release();
8965 }
8966 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
8967 if (_n) {
8968 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
8969 _n->release();
8970 }
8971 _n = OSNumber::withNumber(_a->level, 64);
8972 if (_n) {
8973 details->setObject(kIOPMDriverAssertionLevelKey, _n);
8974 _n->release();
8975 }
8976 _n = OSNumber::withNumber(_a->assertionBits, 64);
8977 if (_n) {
8978 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
8979 _n->release();
8980 }
8981
8982 if (_a->ownerString) {
8983 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
8984 }
8985 }
8986 }
8987
8988 exit:
8989 return outArray;
8990 }
8991
8992 IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
8993 {
8994 return assertionsCombined;
8995 }
8996
8997 IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
8998 IOPMDriverAssertionType type)
8999 {
9000 if (type && ((type & assertionsKernel) == assertionsKernel))
9001 {
9002 return kIOPMDriverAssertionLevelOn;
9003 } else {
9004 return kIOPMDriverAssertionLevelOff;
9005 }
9006 }
9007
9008 //*********************************************************************************
9009 //*********************************************************************************
9010 //*********************************************************************************
9011
9012
9013 static void pmEventTimeStamp(uint64_t *recordTS)
9014 {
9015 clock_sec_t tsec;
9016 clock_usec_t tusec;
9017
9018 if (!recordTS)
9019 return;
9020
9021 // We assume tsec fits into 32 bits; 32 bits holds enough
9022 // seconds for 136 years since the epoch in 1970.
9023 clock_get_calendar_microtime(&tsec, &tusec);
9024
9025
9026 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9027 *recordTS = 0;
9028 *recordTS |= (uint32_t)tusec;
9029 *recordTS |= ((uint64_t)tsec << 32);
9030
9031 return;
9032 }
9033
9034 // MARK: -
9035 // MARK: IORootParent
9036
9037 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9038
9039 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
9040
9041 // The reason that root domain needs a root parent is to facilitate demand
9042 // sleep, since a power change from the root parent cannot be vetoed.
9043 //
9044 // The above statement is no longer true since root domain now performs
9045 // demand sleep using overrides. But root parent remains to avoid changing
9046 // the power tree stacking. Root parent is parked at the max power state.
9047
9048
9049 static IOPMPowerState patriarchPowerStates[2] =
9050 {
9051 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9052 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9053 };
9054
9055 void IORootParent::initialize( void )
9056 {
9057 }
9058
9059 bool IORootParent::start( IOService * nub )
9060 {
9061 IOService::start(nub);
9062 attachToParent( getRegistryRoot(), gIOPowerPlane );
9063 PMinit();
9064 registerPowerDriver(this, patriarchPowerStates, 2);
9065 makeUsable();
9066 return true;
9067 }
9068
9069 void IORootParent::shutDownSystem( void )
9070 {
9071 }
9072
9073 void IORootParent::restartSystem( void )
9074 {
9075 }
9076
9077 void IORootParent::sleepSystem( void )
9078 {
9079 }
9080
9081 void IORootParent::dozeSystem( void )
9082 {
9083 }
9084
9085 void IORootParent::sleepToDoze( void )
9086 {
9087 }
9088
9089 void IORootParent::wakeSystem( void )
9090 {
9091 }
9092
9093 OSObject * IORootParent::copyProperty( const char * aKey) const
9094 {
9095 return (IOService::copyProperty(aKey));
9096 }
9097
9098
9099 #if defined(__i386__) || defined(__x86_64__)
9100 IOReturn IOPMrootDomain::restartWithStackshot()
9101 {
9102 if ((swd_flags & SWD_WDOG_ENABLED) == 0)
9103 return kIOReturnError;
9104
9105 takeStackshot(true, true, false);
9106
9107 return kIOReturnSuccess;
9108 }
9109
9110 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
9111 {
9112 takeStackshot(wdogTrigger, false, false);
9113 }
9114
9115 void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
9116 {
9117 swd_hdr * hdr = NULL;
9118 addr64_t data[3];
9119 uint32_t wdog_panic = 0;
9120 int cnt = 0;
9121 pid_t pid = 0;
9122 uint32_t flags;
9123
9124 char * dstAddr;
9125 uint32_t size;
9126 uint32_t bytesRemaining;
9127 unsigned int len;
9128 OSString * UUIDstring = NULL;
9129 uint64_t code;
9130 IOMemoryMap * logBufMap = NULL;
9131
9132 swd_stackshot_hdr *stackshotHdr = NULL;
9133
9134 uint32_t bufSize;
9135 uint32_t initialStackSize;
9136
9137 if (isSpinDump) {
9138 if (_systemTransitionType != kSystemTransitionSleep &&
9139 _systemTransitionType != kSystemTransitionWake)
9140 return;
9141 } else {
9142 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9143 return;
9144 }
9145
9146 if (wdogTrigger) {
9147 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
9148 (wdog_panic == 1)) {
9149 // If boot-arg is set to panic on sleep/wake hang, call panic
9150 panic("Sleep/Wake hang detected\n");
9151 return;
9152 }
9153 else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9154 // If current boot is due to this watch dog trigger restart in previous boot,
9155 // then don't trigger again until at least 1 successful sleep & wake.
9156 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
9157 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9158 PEHaltRestart(kPEHaltCPU);
9159 return;
9160 }
9161 }
9162
9163 }
9164
9165 if (isSpinDump) {
9166 if (gSpinDumpBufferFull)
9167 return;
9168 if (swd_spindump_buffer == NULL) {
9169 sleepWakeDebugSpinDumpMemAlloc();
9170 if (swd_spindump_buffer == NULL) return;
9171 }
9172
9173 bufSize = SWD_SPINDUMP_SIZE;
9174 initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
9175 } else {
9176 if (sleepWakeDebugIsWdogEnabled() == false)
9177 return;
9178
9179 if (swd_buffer == NULL) {
9180 sleepWakeDebugMemAlloc();
9181 if (swd_buffer == NULL) return;
9182 }
9183
9184 bufSize = SWD_BUF_SIZE;
9185 initialStackSize = SWD_INITIAL_STACK_SIZE;
9186 }
9187
9188 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9189 return;
9190
9191 if (isSpinDump)
9192 hdr = (swd_hdr *)swd_spindump_buffer;
9193 else
9194 hdr = (swd_hdr *)swd_buffer;
9195 memset(hdr->UUID, 0x20, sizeof(hdr->UUID));
9196 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
9197
9198 if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) {
9199 const char *str = UUIDstring->getCStringNoCopy();
9200 snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s", str);
9201 }
9202 else {
9203 DLOG("Data for current UUID already exists\n");
9204 goto exit;
9205 }
9206 }
9207
9208 dstAddr = (char*)hdr + hdr->spindump_offset;
9209 bytesRemaining = bufSize - hdr->spindump_offset;
9210
9211 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9212 hdr->is_osx_watchdog = isOSXWatchdog;
9213
9214 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
9215
9216 while (bytesRemaining > sizeof(swd_stackshot_hdr)) {
9217
9218 stackshotHdr = (swd_stackshot_hdr *)dstAddr;
9219 stackshotHdr->magic = SWD_STACKSHOTHDR_MAGIC;
9220 stackshotHdr->size = 0;
9221 bytesRemaining -= sizeof(swd_stackshot_hdr);
9222 dstAddr += sizeof(swd_stackshot_hdr);
9223
9224 if (isOSXWatchdog) {
9225 pid = -1;
9226 size = bytesRemaining;
9227 flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
9228 }
9229 else if (cnt == 0) {
9230 /*
9231 * Take stackshot of all process on first sample. Size is restricted
9232 * to SWD_INITIAL_STACK_SIZE
9233 */
9234 pid = -1;
9235 size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
9236 flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY;
9237 }
9238 else {
9239 /* Take sample of kernel threads only */
9240 pid = 0;
9241 size = bytesRemaining;
9242 flags = 0;
9243 }
9244
9245 stack_snapshot_from_kernel(pid, dstAddr, size, flags, &stackshotHdr->size);
9246
9247 dstAddr += stackshotHdr->size;
9248 bytesRemaining -= stackshotHdr->size;
9249
9250 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt, stackshotHdr->size, bytesRemaining);
9251 if ((stackshotHdr->size == 0) || (++cnt == 10))
9252 break;
9253 IOSleep(10); // 10 ms
9254 }
9255
9256 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
9257
9258
9259 memset(hdr->cps, 0x20, sizeof(hdr->cps));
9260 snprintf(hdr->cps, sizeof(hdr->cps), "\ncps: %d", ((IOService*)this)->getPowerState());
9261 code = pmTracer->getPMStatusCode();
9262 memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode));
9263 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x",
9264 (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
9265 memset(hdr->reason, 0x20, sizeof(hdr->reason));
9266 if (isSpinDump) {
9267 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: PSC Delay\n\n");
9268 gRootDomain->swd_lock = 0;
9269 gSpinDumpBufferFull = true;
9270 return;
9271 }
9272 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
9273
9274
9275 data[0] = round_page(sizeof(swd_hdr) + hdr->spindump_size);
9276 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9277 data[1] = hdr->crc = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size);
9278 data[2] = kvtophys((vm_offset_t)swd_buffer);
9279 len = sizeof(addr64_t)*3;
9280 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9281 data[0], data[1], data[2]);
9282
9283 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false)
9284 {
9285 DLOG("Failed to update nvram boot-args\n");
9286 goto exit;
9287 }
9288
9289 exit:
9290
9291 gRootDomain->swd_lock = 0;
9292
9293 if (wdogTrigger) {
9294 IOLog("Restarting to collect Sleep wake debug logs\n");
9295 PEHaltRestart(kPERestartCPU);
9296 }
9297 else {
9298 logBufMap = sleepWakeDebugRetrieve();
9299 if (logBufMap) {
9300 sleepWakeDebugDumpFromMem(logBufMap);
9301 logBufMap->release();
9302 logBufMap = 0;
9303 }
9304 }
9305 }
9306
9307 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9308 {
9309 vm_size_t size = SWD_BUF_SIZE;
9310
9311 swd_hdr *hdr = NULL;
9312
9313 IOBufferMemoryDescriptor *memDesc = NULL;
9314
9315
9316 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9317 return;
9318
9319 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9320 return;
9321
9322 // Try allocating above 4GB. If that fails, try at 2GB
9323 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9324 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9325 size, 0xFFFFFFFF00000000ULL);
9326 if (!memDesc) {
9327 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9328 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9329 size, 0xFFFFFFFF10000000ULL);
9330 }
9331
9332 if (memDesc == NULL)
9333 {
9334 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9335 goto exit;
9336 }
9337
9338
9339 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9340 memset(hdr, 0, sizeof(swd_hdr));
9341
9342 hdr->signature = SWD_HDR_SIGNATURE;
9343 hdr->alloc_size = size;
9344
9345 hdr->spindump_offset = sizeof(swd_hdr);
9346 swd_buffer = (void *)hdr;
9347 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
9348
9349 exit:
9350 gRootDomain->swd_lock = 0;
9351 }
9352
9353 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9354 {
9355 vm_size_t size = SWD_SPINDUMP_SIZE;
9356
9357 swd_hdr *hdr = NULL;
9358
9359 IOBufferMemoryDescriptor *memDesc = NULL;
9360
9361 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9362 return;
9363
9364 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
9365 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
9366 SWD_SPINDUMP_SIZE);
9367
9368 if (memDesc == NULL)
9369 {
9370 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9371 goto exit;
9372 }
9373
9374
9375 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9376 memset(hdr, 0, sizeof(swd_hdr));
9377
9378 hdr->signature = SWD_HDR_SIGNATURE;
9379 hdr->alloc_size = size;
9380
9381 hdr->spindump_offset = sizeof(swd_hdr);
9382 swd_spindump_buffer = (void *)hdr;
9383
9384 exit:
9385 gRootDomain->swd_lock = 0;
9386 }
9387
9388 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9389 {
9390 swd_flags |= SWD_WDOG_ENABLED;
9391 if (!swd_buffer)
9392 sleepWakeDebugMemAlloc();
9393 }
9394
9395 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9396 {
9397 return ((swd_flags & SWD_WDOG_ENABLED) &&
9398 !systemBooting && !systemShutdown && !gWillShutdown);
9399 }
9400
9401 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9402 {
9403 swd_hdr *hdr = NULL;
9404 errno_t error = EIO;
9405
9406 if (swd_spindump_buffer && gSpinDumpBufferFull) {
9407 hdr = (swd_hdr *)swd_spindump_buffer;
9408
9409 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9410 (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
9411
9412 if (error) return;
9413
9414 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9415 (char*)hdr+offsetof(swd_hdr, UUID),
9416 sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
9417
9418 gSpinDumpBufferFull = false;
9419 }
9420 }
9421
9422 errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9423 {
9424 struct vnode *vp = NULL;
9425 vfs_context_t ctx = vfs_context_create(vfs_context_current());
9426 kauth_cred_t cred = vfs_context_ucred(ctx);
9427 struct vnode_attr va;
9428 errno_t error = EIO;
9429
9430 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
9431 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9432 {
9433 IOLog("Failed to open the file %s\n", name);
9434 goto exit;
9435 }
9436 VATTR_INIT(&va);
9437 VATTR_WANTED(&va, va_nlink);
9438 /* Don't dump to non-regular files or files with links. */
9439 if (vp->v_type != VREG ||
9440 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9441 IOLog("Bailing as this is not a regular file\n");
9442 goto exit;
9443 }
9444 VATTR_INIT(&va);
9445 VATTR_SET(&va, va_data_size, 0);
9446 vnode_setattr(vp, &va, ctx);
9447
9448
9449 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
9450 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx));
9451 if (error != 0)
9452 IOLog("Failed to save sleep wake log. err 0x%x\n", error);
9453 else
9454 DLOG("Saved %d bytes to file %s\n",len, name);
9455
9456 exit:
9457 if (vp) vnode_close(vp, FWRITE, ctx);
9458 if (ctx) vfs_context_rele(ctx);
9459
9460 return error;
9461
9462 }
9463
9464 errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
9465 struct vnode *srcVp,
9466 vfs_context_t srcCtx,
9467 char *tmpBuf, uint64_t tmpBufSize,
9468 uint64_t srcOffset,
9469 const char *dstFname,
9470 uint64_t numBytes,
9471 uint32_t crc)
9472 {
9473 struct vnode *vp = NULL;
9474 vfs_context_t ctx = vfs_context_create(vfs_context_current());
9475 struct vnode_attr va;
9476 errno_t error = EIO;
9477 uint64_t bytesToRead, bytesToWrite;
9478 uint64_t readFileOffset, writeFileOffset, srcDataOffset;
9479 uint32_t newcrc = 0;
9480
9481 if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW),
9482 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9483 {
9484 DLOG("Failed to open the file %s\n", dstFname);
9485 goto exit;
9486 }
9487 VATTR_INIT(&va);
9488 VATTR_WANTED(&va, va_nlink);
9489 /* Don't dump to non-regular files or files with links. */
9490 if (vp->v_type != VREG ||
9491 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9492 DLOG("Bailing as this is not a regular file\n");
9493 goto exit;
9494 }
9495 VATTR_INIT(&va);
9496 VATTR_SET(&va, va_data_size, 0);
9497 vnode_setattr(vp, &va, ctx);
9498
9499 writeFileOffset = 0;
9500 while(numBytes) {
9501 bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
9502 readFileOffset = trunc_page(srcOffset);
9503
9504 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead, readFileOffset);
9505 error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
9506 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9507 vfs_context_ucred(srcCtx), (int *) 0,
9508 vfs_context_proc(srcCtx));
9509 if (error) {
9510 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
9511 break;
9512 }
9513
9514 srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset);
9515 bytesToWrite = bytesToRead - (srcOffset - readFileOffset);
9516 if (bytesToWrite > numBytes) bytesToWrite = numBytes;
9517
9518 if (crc) {
9519 newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
9520 }
9521 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite, writeFileOffset);
9522 error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
9523 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
9524 vfs_context_ucred(ctx), (int *) 0,
9525 vfs_context_proc(ctx));
9526 if (error) {
9527 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
9528 break;
9529 }
9530
9531 writeFileOffset += bytesToWrite;
9532 numBytes -= bytesToWrite;
9533 srcOffset += bytesToWrite;
9534
9535 }
9536 if (crc != newcrc) {
9537 swd_stackshot_hdr *shdr = (swd_stackshot_hdr *)tmpBuf;;
9538
9539 /* Set statckshot size to 0 if crc doesn't match */
9540 shdr->magic = SWD_STACKSHOTHDR_MAGIC;
9541 shdr->size = 0;
9542
9543 assert(tmpBufSize > sizeof(swd_stackshot_hdr));
9544 bytesToWrite = round_page(sizeof(swd_stackshot_hdr));
9545 vn_rdwr(UIO_WRITE, vp, (char *)tmpBuf, bytesToWrite, 0,
9546 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
9547 vfs_context_ucred(ctx), (int *) 0,
9548 vfs_context_proc(ctx));
9549
9550 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
9551 error = EFAULT;
9552 }
9553 exit:
9554 if (vp) {
9555 error = vnode_close(vp, FWRITE, ctx);
9556 DLOG("vnode_close returned 0x%x\n", error);
9557 }
9558 if (ctx) vfs_context_rele(ctx);
9559
9560 return error;
9561
9562
9563
9564 }
9565 void IOPMrootDomain::checkForValidDebugData(const char *fname, vfs_context_t *ctx,
9566 void *tmpBuf, struct vnode **vp)
9567 {
9568 int rc;
9569 uint64_t hdrOffset;
9570
9571 struct vnode_attr va;
9572 IOHibernateImageHeader *imageHdr;
9573
9574 *vp = NULL;
9575 if (vnode_open(fname, (FREAD | O_NOFOLLOW), 0,
9576 VNODE_LOOKUP_NOFOLLOW, vp, *ctx) != 0)
9577 {
9578 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname);
9579 goto err;
9580 }
9581 VATTR_INIT(&va);
9582 VATTR_WANTED(&va, va_nlink);
9583 VATTR_WANTED(&va, va_data_alloc);
9584 if ((*vp)->v_type != VREG ||
9585 vnode_getattr((*vp), &va, *ctx) || va.va_nlink != 1) {
9586 DMSG("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname);
9587 goto err;
9588 }
9589
9590 /* Read the sleepimage file header */
9591 rc = vn_rdwr(UIO_READ, *vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
9592 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9593 vfs_context_ucred(*ctx), (int *) 0,
9594 vfs_context_proc(*ctx));
9595 if (rc != 0) {
9596 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9597 round_page(sizeof(IOHibernateImageHeader)), rc, fname);
9598 goto err;
9599 }
9600
9601 imageHdr = ((IOHibernateImageHeader *)tmpBuf);
9602 if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
9603 DMSG("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9604 fname, imageHdr->signature);
9605 goto err;
9606 }
9607
9608 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9609 hdrOffset = imageHdr->deviceBlockSize;
9610 if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
9611 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9612 va.va_data_alloc, fname);
9613 goto err;
9614 }
9615
9616 return;
9617
9618 err:
9619 if (*vp) vnode_close(*vp, FREAD, *ctx);
9620 *vp = NULL;
9621
9622 return;
9623 }
9624
9625 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9626 {
9627 #if HIBERNATION
9628 int rc;
9629 char hibernateFilename[MAXPATHLEN+1];
9630 char PMStatusCode[100];
9631 void *tmpBuf;
9632 swd_hdr *hdr = NULL;
9633 uint32_t stacksSize, logSize;
9634 uint64_t tmpBufSize;
9635 uint64_t hdrOffset, stacksOffset, logOffset;
9636 errno_t error = EIO;
9637 OSObject *obj = NULL;
9638 OSString *str = NULL;
9639 OSNumber *failStat = NULL;
9640 struct vnode *vp = NULL;
9641 vfs_context_t ctx = NULL;
9642
9643 IOBufferMemoryDescriptor *tmpBufDesc = NULL;
9644
9645 DLOG("sleepWakeDebugDumpFromFile\n");
9646 if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
9647 return;
9648
9649 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9650 return;
9651
9652
9653 /* Allocate a temp buffer to copy data between files */
9654 tmpBufSize = 2*4096;
9655 tmpBufDesc = IOBufferMemoryDescriptor::
9656 inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone,
9657 tmpBufSize, PAGE_SIZE);
9658
9659 if (!tmpBufDesc) {
9660 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9661 goto exit;
9662 }
9663
9664 tmpBuf = tmpBufDesc->getBytesNoCopy();
9665
9666 ctx = vfs_context_create(vfs_context_current());
9667
9668 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9669 checkForValidDebugData(kSleepWakeStackBinFilename, &ctx, tmpBuf, &vp);
9670 if (vp == NULL) {
9671 /* Check if the debug data is saved to hibernation file */
9672 hibernateFilename[0] = 0;
9673 if ((obj = copyProperty(kIOHibernateFileKey)))
9674 {
9675 if ((str = OSDynamicCast(OSString, obj)))
9676 strlcpy(hibernateFilename, str->getCStringNoCopy(),
9677 sizeof(hibernateFilename));
9678 obj->release();
9679 }
9680 if (!hibernateFilename[0]) {
9681 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9682 goto exit;
9683 }
9684
9685 checkForValidDebugData(hibernateFilename, &ctx, tmpBuf, &vp);
9686 if (vp == NULL) {
9687 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9688 goto exit;
9689 }
9690 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename);
9691 }
9692 else {
9693 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename);
9694 }
9695
9696 hdrOffset = ((IOHibernateImageHeader *)tmpBuf)->deviceBlockSize;
9697
9698 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
9699 /* Read the sleep/wake debug header(swd_hdr) */
9700 rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
9701 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9702 vfs_context_ucred(ctx), (int *) 0,
9703 vfs_context_proc(ctx));
9704 if (rc != 0) {
9705 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9706 round_page(sizeof(swd_hdr)), rc);
9707 goto exit;
9708 }
9709
9710 hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset)));
9711 if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) ||
9712 (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
9713 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9714 hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
9715 goto exit;
9716 }
9717 stacksSize = hdr->spindump_size;
9718
9719 /* Get stacks & log offsets in the image file */
9720 stacksOffset = hdrOffset + hdr->spindump_offset;
9721 logOffset = hdrOffset + offsetof(swd_hdr, UUID);
9722 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9723
9724 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
9725 getDumpStackFilename(hdr), stacksSize, hdr->crc);
9726 if (error == EFAULT) {
9727 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9728 goto exit;
9729 }
9730 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset,
9731 getDumpLogFilename(hdr), logSize, 0);
9732 if (error) {
9733 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
9734 goto exit;
9735 }
9736 exit:
9737 if (error) {
9738 // Write just the SleepWakeLog.dump with failure code
9739 uint64_t fcode = 0;
9740 const char *fname;
9741 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9742 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
9743 fcode = failStat->unsigned64BitValue();
9744 fname = kSleepWakeLogFilename;
9745 }
9746 else {
9747 fname = kAppleOSXWatchdogLogFilename;
9748 }
9749 memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
9750 PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
9751 snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
9752 sleepWakeDebugSaveFile(fname, PMStatusCode, sizeof(PMStatusCode));
9753 }
9754 gRootDomain->swd_lock = 0;
9755
9756 if (vp) vnode_close(vp, FREAD, ctx);
9757 if (ctx) vfs_context_rele(ctx);
9758 if (tmpBufDesc) tmpBufDesc->release();
9759 #endif /* HIBERNATION */
9760 }
9761
9762 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
9763 {
9764 IOVirtualAddress srcBuf = NULL;
9765 char *stackBuf = NULL, *logOffset = NULL;
9766 int logSize = 0;
9767
9768 errno_t error = EIO;
9769 uint64_t bufSize = 0;
9770 swd_hdr *hdr = NULL;
9771 char PMStatusCode[100];
9772 OSNumber *failStat = NULL;
9773
9774 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9775 return;
9776
9777 if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) )
9778 {
9779 DLOG("Nothing saved to dump to file\n");
9780 goto exit;
9781 }
9782
9783 hdr = (swd_hdr *)srcBuf;
9784 bufSize = logBufMap->getLength();
9785 if (bufSize <= sizeof(swd_hdr))
9786 {
9787 IOLog("SleepWake log buffer contents are invalid\n");
9788 goto exit;
9789 }
9790
9791 stackBuf = (char*)hdr+hdr->spindump_offset;
9792
9793 error = sleepWakeDebugSaveFile(getDumpStackFilename(hdr), stackBuf, hdr->spindump_size);
9794 if (error) goto exit;
9795
9796 logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
9797 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9798
9799 error = sleepWakeDebugSaveFile(getDumpLogFilename(hdr), logOffset, logSize);
9800 if (error) goto exit;
9801
9802 hdr->spindump_size = 0;
9803 error = 0;
9804
9805 exit:
9806 if (error) {
9807 // Write just the SleepWakeLog.dump with failure code
9808 uint64_t fcode = 0;
9809 const char *sname, *lname;
9810 swd_stackshot_hdr shdr;
9811
9812 /* Try writing an empty stacks file */
9813 shdr.magic = SWD_STACKSHOTHDR_MAGIC;
9814 shdr.size = 0;
9815
9816
9817 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9818 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
9819 fcode = failStat->unsigned64BitValue();
9820 lname = kSleepWakeLogFilename;
9821 sname = kSleepWakeStackFilename;
9822 }
9823 else {
9824 lname = kAppleOSXWatchdogLogFilename;
9825 sname= kAppleOSXWatchdogStackFilename;
9826 }
9827
9828 sleepWakeDebugSaveFile(sname, (char*)(&shdr), sizeof(shdr));
9829 memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
9830 PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
9831 snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
9832 sleepWakeDebugSaveFile(lname, PMStatusCode, sizeof(PMStatusCode));
9833 }
9834 gRootDomain->swd_lock = 0;
9835 }
9836
9837 IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9838 {
9839 IOVirtualAddress vaddr = NULL;
9840 IOMemoryDescriptor * desc = NULL;
9841 IOMemoryMap * logBufMap = NULL;
9842
9843 uint32_t len;
9844 addr64_t data[3];
9845 uint64_t bufSize = 0;
9846 uint64_t crc = 0;
9847 uint64_t newcrc = 0;
9848 uint64_t paddr = 0;
9849 swd_hdr *hdr = NULL;
9850 bool ret = false;
9851 char str[20];
9852
9853
9854 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9855 return NULL;
9856
9857 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, 0, &len)) {
9858 DLOG("No sleepWakeDebug note to read\n");
9859 goto exit;
9860 }
9861
9862 if (len == strlen("sleepimage")) {
9863 str[0] = 0;
9864 PEReadNVRAMProperty(kIOSleepWakeDebugKey, str, &len);
9865
9866 if (!strncmp((char*)str, "sleepimage", strlen("sleepimage"))) {
9867 DLOG("sleepWakeDebugRetrieve: in file logs\n");
9868 swd_flags |= SWD_LOGS_IN_FILE|SWD_VALID_LOGS;
9869 goto exit;
9870 }
9871 }
9872 else if (len == sizeof(addr64_t)*3)
9873 PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len);
9874 else {
9875 DLOG("Invalid sleepWakeDebug note length(%d)\n", len);
9876 goto exit;
9877 }
9878
9879
9880
9881 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9882 data[0], data[1], data[2]);
9883 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
9884 bufSize = data[0];
9885 crc = data[1];
9886 paddr = data[2];
9887 if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
9888 {
9889 IOLog("SleepWake log buffer contents are invalid\n");
9890 return NULL;
9891 }
9892
9893 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9894 bufSize, crc, paddr);
9895
9896
9897 desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize,
9898 kIODirectionOutIn | kIOMemoryMapperNone, NULL);
9899 if (desc == NULL)
9900 {
9901 IOLog("Fail to map SleepWake log buffer\n");
9902 goto exit;
9903 }
9904
9905 logBufMap = desc->map();
9906
9907 vaddr = logBufMap->getVirtualAddress();
9908
9909
9910 if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
9911 IOLog("Fail to map SleepWake log buffer\n");
9912 goto exit;
9913 }
9914
9915 hdr = (swd_hdr *)vaddr;
9916 if (hdr->spindump_offset+hdr->spindump_size > bufSize)
9917 {
9918 IOLog("SleepWake log buffer contents are invalid\n");
9919 goto exit;
9920 }
9921
9922 hdr->crc = crc;
9923 newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset),
9924 hdr->spindump_size);
9925 if (newcrc != crc) {
9926 IOLog("SleepWake log buffer contents are invalid\n");
9927 goto exit;
9928 }
9929
9930 ret = true;
9931 swd_flags |= SWD_LOGS_IN_MEM | SWD_VALID_LOGS;
9932
9933
9934 exit:
9935 PERemoveNVRAMProperty(kIOSleepWakeDebugKey);
9936 if (!ret) {
9937 if (logBufMap) logBufMap->release();
9938 logBufMap = 0;
9939 }
9940 if (desc) desc->release();
9941 gRootDomain->swd_lock = 0;
9942
9943 return logBufMap;
9944 }
9945
9946 #else
9947
9948 void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
9949 {
9950 }
9951
9952 void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
9953 {
9954 #pragma unused(restart)
9955 #pragma unused(isOSXWatchdog)
9956 }
9957
9958 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9959 {
9960 }
9961 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *map)
9962 {
9963 }
9964 errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
9965 struct vnode *srcVp,
9966 vfs_context_t srcCtx,
9967 char *tmpBuf, uint64_t tmpBufSize,
9968 uint64_t srcOffset,
9969 const char *dstFname,
9970 uint64_t numBytes,
9971 uint32_t crc)
9972 {
9973 return EIO;
9974 }
9975
9976 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
9977 {
9978 }
9979
9980 IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9981 {
9982 return NULL;
9983 }
9984
9985 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9986 {
9987 }
9988
9989 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9990 {
9991 return false;
9992 }
9993
9994 errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9995 {
9996 return 0;
9997 }
9998
9999 #endif
10000