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