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