#include "IOPMPowerStateQueue.h"
#include <IOKit/IOCatalogue.h>
#include <IOKit/IOReportMacros.h>
+#include "IOKitKernelInternal.h"
#if HIBERNATION
#include <IOKit/IOHibernatePrivate.h>
#endif
#include <sys/vnode.h>
#include <sys/vnode_internal.h>
#include <sys/fcntl.h>
+#include <os/log.h>
+#include <pexpert/protos.h>
#include <sys/time.h>
#include "IOServicePrivate.h" // _IOServiceInterestNotifier
__BEGIN_DECLS
#include <mach/shared_region.h>
+#include <kern/clock.h>
__END_DECLS
#if defined(__i386__) || defined(__x86_64__)
#define LOG(x...) \
do { kprintf(LOG_PREFIX x); } while (false)
+#if DEVELOPMENT
#define DLOG(x...) do { \
if (kIOLogPMRootDomain & gIOKitDebug) \
kprintf(LOG_PREFIX x); \
+ else \
+ os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
} while (false)
+#else
+#define DLOG(x...) do { \
+ if (kIOLogPMRootDomain & gIOKitDebug) \
+ kprintf(LOG_PREFIX x); \
+} while (false)
+#endif
#define DMSG(x...) do { \
if (kIOLogPMRootDomain & gIOKitDebug) { \
- kprintf(LOG_PREFIX x); IOLog(x); \
+ kprintf(LOG_PREFIX x); \
} \
} while (false)
}
extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
extern "C" addr64_t kvtophys(vm_offset_t va);
-extern "C" int stack_snapshot_from_kernel(pid_t pid, void *buf, uint32_t size, uint32_t flags, unsigned *bytesTraced);
static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
-static void notifySystemShutdown( IOService * root, unsigned long event );
+static void notifySystemShutdown( IOService * root, uint32_t messageType );
static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
static void pmEventTimeStamp(uint64_t *recordTS);
#define kIOPMSystemCapabilitiesKey "System Capabilities"
#define kIORequestWranglerIdleKey "IORequestIdle"
-#define kDefaultWranglerIdlePeriod 25 // in milliseconds
+#define kDefaultWranglerIdlePeriod 1000 // in milliseconds
#define kIOSleepWakeDebugKey "Persistent-memory-note"
+#define kIOEFIBootRomFailureKey "wake-failure"
#define kRD_AllPowerSources (kIOPMSupportedOnAC \
| kIOPMSupportedOnBatt \
| kIOPMSupportedOnUPS)
-enum
-{
- // not idle around autowake time, secs
- kAutoWakePreWindow = 45,
- kAutoWakePostWindow = 15
-};
-
#define kLocalEvalClamshellCommand (1 << 15)
#define kIdleSleepRetryInterval (3 * 60)
static UInt32 gPagingOff = 0;
static UInt32 gSleepWakeUUIDIsSet = false;
static uint32_t gAggressivesState = 0;
+static uint32_t gHaltTimeMaxLog;
+static uint32_t gHaltTimeMaxPanic;
+IOLock * gHaltLogLock;
+static char * gHaltLog;
+enum { kHaltLogSize = 2048 };
+static size_t gHaltLogPos;
+static uint64_t gHaltStartTime;
+
uuid_string_t bootsessionuuid_string;
static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
+static uint32_t gNoIdleFlag = 0;
static PMStatsStruct gPMStats;
#if HIBERNATION
static char gWakeReasonString[128];
static bool gWakeReasonSysctlRegistered = false;
+static AbsoluteTime gIOLastWakeAbsTime;
+static AbsoluteTime gIOLastSleepAbsTime;
+
+#if defined(__i386__) || defined(__x86_64__)
+static bool gSpinDumpBufferFull = false;
+#endif
+
+static unsigned int gPMHaltBusyCount;
+static unsigned int gPMHaltIdleCount;
+static int gPMHaltDepth;
+static uint32_t gPMHaltMessageType;
+static IOLock * gPMHaltLock = 0;
+static OSArray * gPMHaltArray = 0;
+static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
+static bool gPMQuiesced;
// Constants used as arguments to IOPMrootDomain::informCPUStateChange
#define kCPUUnknownIndex 9999999
kInformableCount = 2
};
-const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
-const OSSymbol *gIOPMStatsApplicationResponseCancel;
-const OSSymbol *gIOPMStatsApplicationResponseSlow;
-const OSSymbol *gIOPMStatsApplicationResponsePrompt;
+const OSSymbol *gIOPMStatsResponseTimedOut;
+const OSSymbol *gIOPMStatsResponseCancel;
+const OSSymbol *gIOPMStatsResponseSlow;
+const OSSymbol *gIOPMStatsResponsePrompt;
const OSSymbol *gIOPMStatsDriverPSChangeSlow;
#define kBadPMFeatureID 0
private:
PMSettingObject *pmso;
- void free(void);
+ void free(void) APPLE_KEXT_OVERRIDE;
};
/*
uint32_t settingCount;
bool disabled;
- void free(void);
+ void free(void) APPLE_KEXT_OVERRIDE;
public:
static PMSettingObject *pmSettingObject(
static PMTraceWorker *tracer( IOPMrootDomain * );
void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
void tracePoint(uint8_t phase);
- void tracePoint(uint8_t phase, uint8_t data8);
void traceDetail(uint32_t detail);
- void traceLoginWindowPhase(uint8_t phase);
+ void traceComponentWakeProgress(uint32_t component, uint32_t data);
int recordTopLevelPCIDevice(IOService *);
void RTC_TRACE(void);
- virtual bool serialize(OSSerialize *s) const;
+ virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
IOPMTracePointHandler tracePointHandler;
void * tracePointTarget;
uint64_t getPMStatusCode();
+ uint8_t getTracePhase();
+ uint32_t getTraceData();
private:
IOPMrootDomain *owner;
- IOLock *pciMappingLock;
+ IOLock *pmTraceWorkerLock;
OSArray *pciDeviceBitMappings;
uint8_t addedToRegistry;
uint8_t tracePhase;
- uint8_t loginWindowPhase;
- uint8_t traceData8;
uint32_t traceData32;
+ uint8_t loginWindowData;
+ uint8_t coreDisplayData;
+ uint8_t coreGraphicsData;
};
/*
static void main( void * arg, wait_result_t waitResult );
static void work( PMHaltWorker * me );
static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
- virtual void free( void );
+ virtual void free( void ) APPLE_KEXT_OVERRIDE;
};
OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
}
}
-extern "C"
+extern "C" IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
{
- IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
- {
- return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
- }
+ return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
+}
- IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
- {
- return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
- }
+extern "C" IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
+{
+ return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
+}
- IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
- {
- return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
- }
+extern "C" IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
+{
+ return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
+}
- IOReturn vetoSleepWakeNotification(void * PMrefcon)
- {
- return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
- }
+extern "C" IOReturn vetoSleepWakeNotification(void * PMrefcon)
+{
+ return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
+}
- IOReturn rootDomainRestart ( void )
- {
- return gRootDomain->restartSystem();
+extern "C" IOReturn rootDomainRestart ( void )
+{
+ return gRootDomain->restartSystem();
+}
+
+extern "C" IOReturn rootDomainShutdown ( void )
+{
+ return gRootDomain->shutdownSystem();
+}
+
+static void halt_log_putc(char c)
+{
+ if (gHaltLogPos >= (kHaltLogSize - 1)) return;
+ gHaltLog[gHaltLogPos++] = c;
+}
+
+extern "C" void
+_doprnt_log(const char *fmt,
+ va_list *argp,
+ void (*putc)(char),
+ int radix);
+
+static int
+halt_log(const char *fmt, ...)
+{
+ va_list listp;
+
+ va_start(listp, fmt);
+ _doprnt_log(fmt, &listp, &halt_log_putc, 16);
+ va_end(listp);
+
+ return (0);
+}
+
+extern "C" void
+halt_log_enter(const char * what, const void * pc, uint64_t time)
+{
+ uint64_t nano, millis;
+
+ if (!gHaltLog) return;
+ absolutetime_to_nanoseconds(time, &nano);
+ millis = nano / 1000000ULL;
+ if (millis < 100) return;
+
+ IOLockLock(gHaltLogLock);
+ if (pc) {
+ halt_log("%s: %qd ms @ 0x%lx, ", what, millis, VM_KERNEL_UNSLIDE(pc));
+ OSKext::printKextsInBacktrace((vm_offset_t *) &pc, 1, &halt_log,
+ OSKext::kPrintKextsLock | OSKext::kPrintKextsUnslide | OSKext::kPrintKextsTerse);
+ } else {
+ halt_log("%s: %qd ms\n", what, millis, VM_KERNEL_UNSLIDE(pc));
}
+ IOLockUnlock(gHaltLogLock);
+}
+
+extern uint32_t gFSState;
+
+extern "C" void IOSystemShutdownNotification(void)
+{
+ uint64_t startTime;
- IOReturn rootDomainShutdown ( void )
+ IOLockLock(gHaltLogLock);
+ if (!gHaltLog)
{
- return gRootDomain->shutdownSystem();
+ gHaltLog = IONew(char, kHaltLogSize);
+ gHaltStartTime = mach_absolute_time();
+ if (gHaltLog) halt_log_putc('\n');
}
+ IOLockUnlock(gHaltLogLock);
- void IOSystemShutdownNotification(void)
+ startTime = mach_absolute_time();
+ IOPMRootDomainWillShutdown();
+ halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime);
+#if HIBERNATION
+ startTime = mach_absolute_time();
+ IOHibernateSystemPostWake(true);
+ halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime);
+#endif
+ if (OSCompareAndSwap(0, 1, &gPagingOff))
{
- IOPMRootDomainWillShutdown();
- if (OSCompareAndSwap(0, 1, &gPagingOff))
- {
- gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
- }
+#if !CONFIG_EMBEDDED
+ gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
+#endif
}
-
- int sync_internal(void);
}
+
+extern "C" int sync_internal(void);
+
/*
A device is always in the highest power state which satisfies its driver,
its policy-maker, and any power children it has, but within the constraint
}
//******************************************************************************
+// updateConsoleUsersCallout
+//
+//******************************************************************************
+
+static void updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
+{
+ IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
+ rootDomain->updateConsoleUsers();
+}
+
+void IOPMrootDomain::updateConsoleUsers(void)
+{
+ IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
+ if (tasksSuspended)
+ {
+ tasksSuspended = FALSE;
+ tasks_system_suspend(tasksSuspended);
+ }
+}
+
+//******************************************************************************
+
+static void swdDebugSetupCallout( thread_call_param_t p0, thread_call_param_t p1 )
+{
+ IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
+ uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
+
+ rootDomain->swdDebugSetup();
+
+ if (p1) {
+ rootDomain->allowPowerChange(notifyRef);
+ }
+ DLOG("swdDebugSetupCallout finish\n");
+}
+
+void IOPMrootDomain::swdDebugSetup( )
+{
+#if HIBERNATION
+ static int32_t mem_only = -1;
+ if ((mem_only == -1) &&
+ (PE_parse_boot_argn("swd_mem_only", &mem_only, sizeof(mem_only)) == false)) {
+ mem_only = 0;
+ }
+
+ if ((mem_only == 1) || (gRootDomain->sleepWakeDebugIsWdogEnabled() == false)) {
+ return;
+ }
+ DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup);
+ if (swd_DebugImageSetup == FALSE) {
+ swd_DebugImageSetup = TRUE;
+ if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
+ (CAP_LOSS(kIOPMSystemCapabilityGraphics))) {
+ IOHibernateSystemPostWake(true);
+ }
+ IOOpenDebugDataFile(kSleepWakeStackBinFilename, SWD_BUF_SIZE);
+ }
+#endif
+
+
+}
+
+static void swdDebugTeardownCallout( thread_call_param_t p0, thread_call_param_t p1 )
+{
+ IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
+ uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
+
+ rootDomain->swdDebugTeardown();
+ if (p1) {
+ rootDomain->allowPowerChange(notifyRef);
+ }
+ DLOG("swdDebugTeardownCallout finish\n");
+}
+
+void IOPMrootDomain::swdDebugTeardown( )
+{
+
+#if HIBERNATION
+ DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup);
+ if (swd_DebugImageSetup == TRUE) {
+ swd_DebugImageSetup = FALSE;
+ IOCloseDebugDataFile();
+ }
+#endif
+
+
+}
+//******************************************************************************
+
static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
{
if (ON_STATE == powerState)
{
sync_internal();
+ swdDebugSetupCallout(p0, NULL);
}
#if HIBERNATION
else
{
- IOHibernateSystemPostWake();
+ swdDebugTeardownCallout(p0, NULL);
+ IOHibernateSystemPostWake(false);
+
+ if (gRootDomain)
+ gRootDomain->sleepWakeDebugSaveSpinDumpFile();
}
#endif
}
//******************************************************************************
-
-static void hib_debugSetup_callout( thread_call_param_t p0, thread_call_param_t p1 )
-{
- IOService * rootDomain = (IOService *) p0;
- uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
-
-#if HIBERNATION
- IOHibernateOpenForDebugData();
-#endif
-
- rootDomain->allowPowerChange(notifyRef);
- DLOG("hib_debugSetup_callout finish\n");
-}
-//******************************************************************************
-
-static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
+static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime, AbsoluteTime * elapsedTime )
{
AbsoluteTime endTime;
UInt64 nano = 0;
clock_get_uptime(&endTime);
- if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
+ if (CMP_ABSOLUTETIME(&endTime, startTime) <= 0) *elapsedTime = 0;
+ else
{
SUB_ABSOLUTETIME(&endTime, startTime);
absolutetime_to_nanoseconds(endTime, &nano);
+ *elapsedTime = endTime;
}
return (UInt32)(nano / 1000000ULL);
if (p == kernproc) {
return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
} else if(proc_is64bit(p)) {
- struct user64_timeval t;
+ struct user64_timeval t = {};
t.tv_sec = swt->tv_sec;
t.tv_usec = swt->tv_usec;
return sysctl_io_opaque(req, &t, sizeof(t), NULL);
} else {
- struct user32_timeval t;
+ struct user32_timeval t = {};
t.tv_sec = swt->tv_sec;
t.tv_usec = swt->tv_usec;
return sysctl_io_opaque(req, &t, sizeof(t), NULL);
CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
&gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
+SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
+SYSCTL_QUAD(_kern, OID_AUTO, sleep_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastSleepAbsTime, "");
static int
sysctl_willshutdown
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
0, 0, sysctl_willshutdown, "I", "");
+extern struct sysctl_oid sysctl__kern_iokittest;
+extern struct sysctl_oid sysctl__debug_iokit;
+
+#if !CONFIG_EMBEDDED
static int
sysctl_progressmeterenable
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
0, 0, sysctl_progressmeter, "I", "");
+#endif /* !CONFIG_EMBEDDED */
+
+
+
+static int
+sysctl_consoleoptions
+(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
+{
+ int error, changed;
+ uint32_t new_value;
+
+ error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
+
+ if (changed) vc_user_options.options = new_value;
+
+ return (error);
+}
+
+static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+ 0, 0, sysctl_consoleoptions, "I", "");
+
+
+static int
+sysctl_progressoptions SYSCTL_HANDLER_ARGS
+{
+ return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
+}
+
+static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
+ CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
+ NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
+
static int
sysctl_wakereason SYSCTL_HANDLER_ARGS
CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
NULL, 0, sysctl_wakereason, "A", "wakereason");
+static int
+sysctl_targettype SYSCTL_HANDLER_ARGS
+{
+ IOService * root;
+ OSObject * obj;
+ OSData * data;
+ char tt[32];
+
+ tt[0] = '\0';
+ root = IOService::getServiceRoot();
+ if (root && (obj = root->copyProperty(gIODTTargetTypeKey)))
+ {
+ if ((data = OSDynamicCast(OSData, obj)))
+ {
+ strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
+ }
+ obj->release();
+ }
+ return sysctl_io_string(req, tt, 0, 0, NULL);
+}
+
+SYSCTL_PROC(_hw, OID_AUTO, targettype,
+ CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+ NULL, 0, sysctl_targettype, "A", "targettype");
+
static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
+static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
- gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
- gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
- gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
- gIOPMStatsApplicationResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
+ gIOPMStatsResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
+ gIOPMStatsResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
+ gIOPMStatsResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
+ gIOPMStatsResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
};
PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
+ PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
+ PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic, sizeof(gHaltTimeMaxPanic));
+ PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog, sizeof(gHaltTimeMaxLog));
queue_init(&aggressivesQueue);
aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
featuresDictLock = IOLockAlloc();
settingsCtrlLock = IOLockAlloc();
wakeEventLock = IOLockAlloc();
+ gHaltLogLock = IOLockAlloc();
setPMRootDomain(this);
extraSleepTimer = thread_call_allocate(
diskSyncCalloutEntry = thread_call_allocate(
&disk_sync_callout,
(thread_call_param_t) this);
- hibDebugSetupEntry = thread_call_allocate(
- &hib_debugSetup_callout,
+ swdDebugSetupEntry = thread_call_allocate(
+ &swdDebugSetupCallout,
+ (thread_call_param_t) this);
+ swdDebugTearDownEntry = thread_call_allocate(
+ &swdDebugTeardownCallout,
+ (thread_call_param_t) this);
+ updateConsoleUsersEntry = thread_call_allocate(
+ &updateConsoleUsersCallout,
(thread_call_param_t) this);
#if DARK_TO_FULL_EVALUATE_CLAMSHELL
userDisabledAllSleep = false;
systemBooting = true;
+ idleSleepEnabled = false;
sleepSlider = 0;
idleSleepTimerPending = false;
wrangler = NULL;
_statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
_statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
_statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
+ assertOnWakeSecs = -1; // Invalid value to prevent updates
pmStatsLock = IOLockAlloc();
idxPMCPUClamshell = kCPUUnknownIndex;
preventSystemSleepList = OSSet::withCapacity(2);
PMinit(); // creates gIOPMWorkLoop
+ gIOPMWorkLoop = getIOPMWorkloop();
// Create IOPMPowerStateQueue used to queue external power
// events, and to handle those events on the PM work loop.
pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
this, OSMemberFunctionCast(IOEventSource::Action, this,
&IOPMrootDomain::dispatchPowerEvent));
- getPMworkloop()->addEventSource(pmPowerStateQueue);
-#ifdef CHECK_THREAD_CONTEXT
- gIOPMWorkLoop = getPMworkloop();
-#endif
+ gIOPMWorkLoop->addEventSource(pmPowerStateQueue);
// create our power parent
patriarch = new IORootParent;
// IOBacklightDisplay can take a long time to load at boot, or it may
// not load at all if you're booting with clamshell closed. We publish
// 'DisplayDims' here redundantly to get it published early and at all.
- psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
+ OSDictionary * matching;
+ matching = serviceMatching("IOPMPowerSource");
+ psIterator = getMatchingServices( matching );
+ if (matching) matching->release();
if( psIterator && psIterator->getNextObject() )
{
// There's at least one battery on the system, so we publish
sysctl_register_oid(&sysctl__kern_sleeptime);
sysctl_register_oid(&sysctl__kern_waketime);
sysctl_register_oid(&sysctl__kern_willshutdown);
+ sysctl_register_oid(&sysctl__kern_iokittest);
+ sysctl_register_oid(&sysctl__debug_iokit);
+ sysctl_register_oid(&sysctl__hw_targettype);
+
+#if !CONFIG_EMBEDDED
sysctl_register_oid(&sysctl__kern_progressmeterenable);
sysctl_register_oid(&sysctl__kern_progressmeter);
sysctl_register_oid(&sysctl__kern_wakereason);
+#endif /* !CONFIG_EMBEDDED */
+ sysctl_register_oid(&sysctl__kern_consoleoptions);
+ sysctl_register_oid(&sysctl__kern_progressoptions);
#if HIBERNATION
IOHibernateSystemInit(this);
const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
- const OSSymbol *loginwindow_tracepoint_string = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
+ const OSSymbol *loginwindow_progress_string = OSSymbol::withCString(kIOPMLoginWindowProgressKey);
+ const OSSymbol *coredisplay_progress_string = OSSymbol::withCString(kIOPMCoreDisplayProgressKey);
+ const OSSymbol *coregraphics_progress_string = OSSymbol::withCString(kIOPMCoreGraphicsProgressKey);
#if HIBERNATION
const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
obj->retain();
pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
}
- else if (key->isEqualTo(loginwindow_tracepoint_string))
+ else if (key->isEqualTo(loginwindow_progress_string))
{
- if (pmTracer && (n = OSDynamicCast(OSNumber, obj)))
- pmTracer->traceLoginWindowPhase(n->unsigned8BitValue());
+ if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
+ uint32_t data = n->unsigned32BitValue();
+ pmTracer->traceComponentWakeProgress(kIOPMLoginWindowProgress, data);
+ kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMLoginWindowProgress, data);
+ }
+ }
+ else if (key->isEqualTo(coredisplay_progress_string))
+ {
+ if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
+ uint32_t data = n->unsigned32BitValue();
+ pmTracer->traceComponentWakeProgress(kIOPMCoreDisplayProgress, data);
+ kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreDisplayProgress, data);
+ }
+ }
+ else if (key->isEqualTo(coregraphics_progress_string))
+ {
+ if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
+ uint32_t data = n->unsigned32BitValue();
+ pmTracer->traceComponentWakeProgress(kIOPMCoreGraphicsProgress, data);
+ kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreGraphicsProgress, data);
+ }
}
else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
setProperty(key, b);
}
else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
+ key->isEqualTo(kIOPMDeepSleepTimerKey) ||
key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
key->isEqualTo(kIOPMAutoPowerOffTimerKey))
{
// Relay our allowed PM settings onto our registered PM clients
else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
{
- if ((gIOPMSettingAutoWakeSecondsKey == key) && ((n = OSDynamicCast(OSNumber, obj))))
- {
- UInt32 rsecs = n->unsigned32BitValue();
- if (!rsecs)
- autoWakeStart = autoWakeEnd = 0;
- else
- {
- AbsoluteTime deadline;
- clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
- autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
- if (rsecs > kAutoWakePreWindow)
- rsecs -= kAutoWakePreWindow;
- else
- rsecs = 0;
- clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
- autoWakeStart = AbsoluteTime_to_scalar(&deadline);
- }
- }
-
return_value = setPMSetting(key, obj);
if (kIOReturnSuccess != return_value)
break;
if(idle_seconds_string) idle_seconds_string->release();
if(sleepdisabled_string) sleepdisabled_string->release();
if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
- if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
+ if(loginwindow_progress_string) loginwindow_progress_string->release();
+ if(coredisplay_progress_string) coredisplay_progress_string->release();
+ if(coregraphics_progress_string) coregraphics_progress_string->release();
#if HIBERNATION
if(hibernatemode_string) hibernatemode_string->release();
if(hibernatefile_string) hibernatefile_string->release();
if (!connect || !connect->getReadyFlag())
continue;
- if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
+ if ((service = OSDynamicCast(IOService, connect->copyChildEntry(gIOPowerPlane))))
{
if (service->assertPMDriverCall(&callEntry))
{
AbsoluteTime deadline;
ASSERT_GATED();
+ if (gNoIdleFlag) {
+ DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
+ return;
+ }
if (inSeconds)
{
clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
DLOG("idle timer cancelled\n");
thread_call_cancel(extraSleepTimer);
idleSleepTimerPending = false;
+
+ if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
+ AbsoluteTime now;
+ clock_usec_t microsecs;
+ clock_get_uptime(&now);
+ SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
+ absolutetime_to_microtime(now, &assertOnWakeSecs, µsecs);
+ if (assertOnWakeReport) {
+ HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+ DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+ }
+ }
}
}
void IOPMrootDomain::handleSleepTimerExpiration( void )
{
- if (!getPMworkloop()->inGate())
+ if (!gIOPMWorkLoop->inGate())
{
- getPMworkloop()->runAction(
+ gIOPMWorkLoop->runAction(
OSMemberFunctionCast(IOWorkLoop::Action, this,
&IOPMrootDomain::handleSleepTimerExpiration),
this);
idleSleepTimerPending = false;
clock_get_uptime(&time);
- if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
- (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
- {
- thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
- return;
- }
-
setQuickSpinDownTimeout();
adjustPowerState(true);
}
uint32_t minutesSinceUserInactive = 0;
uint32_t sleepDelay = 0;
- if (sleepSlider == 0)
+ if (!idleSleepEnabled)
return 0xffffffff;
if (userActivityTime)
void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
{
+#if !__i386__ && !__x86_64__
+ uint64_t timeSinceReset = 0;
+#endif
+ uint64_t now;
ASSERT_GATED();
DLOG("PowerChangeDone: %u->%u\n",
(uint32_t) previousPowerState, (uint32_t) getPowerState());
clock_sec_t secs;
clock_usec_t microsecs;
- clock_get_calendar_microtime(&secs, µsecs);
+ clock_get_calendar_absolute_and_microtime(&secs, µsecs, &now);
logtime(secs);
gIOLastSleepTime.tv_sec = secs;
gIOLastSleepTime.tv_usec = microsecs;
gIOLastWakeTime.tv_sec = 0;
gIOLastWakeTime.tv_usec = 0;
+ gIOLastSleepAbsTime = now;
+ if (wake2DarkwakeDelay && sleepDelaysReport) {
+ clock_usec_t microsecs;
+ clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
+ // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
+
+ SUB_ABSOLUTETIME(&now, &ts_sleepStart);
+ absolutetime_to_microtime(now, &darkwake2SleepSecs, µsecs);
+ absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, µsecs);
+ HISTREPORT_TALLYVALUE(sleepDelaysReport,
+ (int64_t)(wake2DarkwakeSecs+darkwake2SleepSecs));
+
+ DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
+ wake2DarkwakeDelay = 0;
+ }
#if HIBERNATION
LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
#else
LOG("System Sleep\n");
#endif
-
+ if (thermalWarningState) {
+ const OSSymbol *event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
+ if (event) {
+ systemPowerEventOccurred(event, kIOPMThermalLevelUnknown);
+ event->release();
+ }
+ }
+ assertOnWakeSecs = 0;
((IOService *)this)->stop_watchdog_timer(); //14456299
+ lowBatteryCondition = false;
+
+#if DEVELOPMENT || DEBUG
+ extern int g_should_log_clock_adjustments;
+ if (g_should_log_clock_adjustments) {
+ clock_sec_t secs = 0;
+ clock_usec_t microsecs = 0;
+ uint64_t now_b = mach_absolute_time();
+
+ PEGetUTCTimeOfDay(&secs, µsecs);
+
+ uint64_t now_a = mach_absolute_time();
+ os_log(OS_LOG_DEFAULT, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
+ __func__, (unsigned long)secs, microsecs, now_b, now_a);
+ }
+#endif
+
getPlatform()->sleepKernel();
// The CPU(s) are off at this point,
// Code will resume execution here upon wake.
- clock_get_uptime(&systemWakeTime);
+ clock_get_uptime(&gIOLastWakeAbsTime);
+ IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
_highestCapability = 0;
((IOService *)this)->start_watchdog_timer(); //14456299
// sleep transition complete
gSleepOrShutdownPending = 0;
- // trip the reset of the calendar clock
- clock_wakeup_calendar();
+ // trip the reset of the calendar clock
+ {
+ clock_sec_t wakeSecs;
+ clock_usec_t wakeMicrosecs;
+
+ clock_wakeup_calendar();
+
+ clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
+ gIOLastWakeTime.tv_sec = wakeSecs;
+ gIOLastWakeTime.tv_usec = wakeMicrosecs;
+ }
#if HIBERNATION
LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
#endif
- // log system wake
- PMDebug(kPMLogSystemWake, 0, 0);
- lowBatteryCondition = false;
lastSleepReason = 0;
_lastDebugWakeSeconds = _debugWakeSeconds;
_debugWakeSeconds = 0;
_scheduledAlarms = 0;
-#ifndef __LP64__
- systemWake();
-#endif
-
#if defined(__i386__) || defined(__x86_64__)
+ kdebugTrace(kPMLogSystemWake, 0, 0, 0);
wranglerTickled = false;
graphicsSuppressed = false;
darkWakePostTickle = false;
}
else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
{
+#if HIBERNATION
OSNumber * hibOptions = OSDynamicCast(
OSNumber, getProperty(kIOHibernateOptionsKey));
-
if (hibernateAborted || ((hibOptions &&
!(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
{
hibOptions ? hibOptions->unsigned32BitValue() : 0);
}
else
+#endif
if (wakeType && (
wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
{
darkWakeMaintenance = true;
darkWakeSleepService = true;
+#if HIBERNATION
if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
sleepToStandby = true;
}
+#endif
}
else
if (wakeType &&
fullWakeReason = kFullWakeReasonLocalUser;
reportUserInput();
}
+ else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
+ {
+ handleDisplayPowerOn();
+ }
else if (!darkWakeMaintenance)
{
// Early/late tickle for non-maintenance wake.
}
}
#else /* !__i386__ && !__x86_64__ */
+ timeSinceReset = ml_get_time_since_reset();
+
+ kdebugTrace(kPMLogSystemWake, 0, timeSinceReset >> 32, timeSinceReset);
// stay awake for at least 30 seconds
wranglerTickled = true;
fullWakeReason = kFullWakeReasonLocalUser;
#endif
sleepCnt++;
+ thread_call_enter(updateConsoleUsersEntry);
+
changePowerStateToPriv(ON_STATE);
} break;
+#if !__i386__ && !__x86_64__
+ case ON_STATE: {
+ if (previousPowerState != ON_STATE)
+ {
+ DLOG("Force re-evaluating aggressiveness\n");
+ /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
+ pmPowerStateQueue->submitPowerEvent(
+ kPowerEventPolicyStimulus,
+ (void *) kStimulusNoIdleSleepPreventers );
+ }
+ break;
+ }
+
+#endif
}
}
return super::requestPowerDomainState(0, childConnection, specification);
}
+
//******************************************************************************
// updatePreventIdleSleepList
//
changePowerStateTo(SLEEP_STATE);
evaluatePolicy( kStimulusNoIdleSleepPreventers );
}
+ messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier,
+ &newCount, sizeof(newCount));
#if defined(__i386__) || defined(__x86_64__)
if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
{
+ DLOG("Cannot cancel idle sleep\n");
return false; // do not idle-cancel
}
#endif
return true;
}
+//******************************************************************************
+// startSpinDump
+//******************************************************************************
+
+void IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
+{
+ messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
+}
+
//******************************************************************************
// preventSystemSleepListUpdate
//
void IOPMrootDomain::updatePreventSystemSleepList(
IOService * service, bool addNotRemove )
{
- unsigned int oldCount;
+ unsigned int oldCount, newCount;
ASSERT_GATED();
if (this == service)
preventSystemSleepList->setObject(service);
DLOG("prevent system sleep list: %s+ (%u)\n",
service->getName(), preventSystemSleepList->getCount());
+ if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
+ AbsoluteTime now;
+ clock_usec_t microsecs;
+ clock_get_uptime(&now);
+ SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
+ absolutetime_to_microtime(now, &assertOnWakeSecs, µsecs);
+ if (assertOnWakeReport) {
+ HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+ DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+ }
+ }
}
else if (preventSystemSleepList->member(service))
{
evaluatePolicy( kStimulusDarkWakeEvaluate );
}
}
+ newCount = preventSystemSleepList->getCount();
+ messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier,
+ &newCount, sizeof(newCount));
}
-//******************************************************************************
-// tellChangeDown
-//
-// Override the superclass implementation to send a different message type.
-//******************************************************************************
-
-bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
+void IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
{
- DLOG("tellChangeDown %u->%u\n",
- (uint32_t) getPowerState(), (uint32_t) stateNum);
- if (SLEEP_STATE == stateNum)
+ OSCollectionIterator *iterator = NULL;
+ OSObject *object = NULL;
+ OSArray *array = NULL;
+
+ if (!gIOPMWorkLoop->inGate())
{
- // Legacy apps were already told in the full->dark transition
- if (!ignoreTellChangeDown)
- tracePoint( kIOPMTracePointSleepApplications );
+ gIOPMWorkLoop->runAction(
+ OSMemberFunctionCast(IOWorkLoop::Action, this,
+ &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
+ this, (void *)idleSleepList, (void *)systemSleepList);
+ return;
+ }
+
+ if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0))
+ {
+ iterator = OSCollectionIterator::withCollection(preventIdleSleepList);
+ array = OSArray::withCapacity(5);
+
+ while ((object = iterator->getNextObject()))
+ {
+ IOService *service = OSDynamicCast(IOService, object);
+ if (object)
+ {
+ array->setObject(OSSymbol::withCString(service->getName()));
+ }
+ }
+
+ iterator->release();
+ *idleSleepList = array;
+ }
+
+ if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0))
+ {
+ iterator = OSCollectionIterator::withCollection(preventSystemSleepList);
+ array = OSArray::withCapacity(5);
+
+ while ((object = iterator->getNextObject()))
+ {
+ IOService *service = OSDynamicCast(IOService, object);
+ if (object)
+ {
+ array->setObject(OSSymbol::withCString(service->getName()));
+ }
+ }
+
+ iterator->release();
+ *systemSleepList = array;
+ }
+}
+
+//******************************************************************************
+// tellChangeDown
+//
+// Override the superclass implementation to send a different message type.
+//******************************************************************************
+
+bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
+{
+ DLOG("tellChangeDown %u->%u\n",
+ (uint32_t) getPowerState(), (uint32_t) stateNum);
+
+ if (SLEEP_STATE == stateNum)
+ {
+ // Legacy apps were already told in the full->dark transition
+ if (!ignoreTellChangeDown)
+ tracePoint( kIOPMTracePointSleepApplications );
else
tracePoint( kIOPMTracePointSleepPriorityClients );
}
- if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
- {
+ if (!ignoreTellChangeDown) {
userActivityAtSleep = userActivityCount;
- hibernateAborted = false;
DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
- // Direct callout into OSKext so it can disable kext unloads
- // during sleep/wake to prevent deadlocks.
- OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
+ if (SLEEP_STATE == stateNum) {
+ hibernateAborted = false;
+
+ // Direct callout into OSKext so it can disable kext unloads
+ // during sleep/wake to prevent deadlocks.
+ OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
- IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
+ IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
- // Two change downs are sent by IOServicePM. Ignore the 2nd.
- // But tellClientsWithResponse() must be called for both.
- ignoreTellChangeDown = true;
+ // Two change downs are sent by IOServicePM. Ignore the 2nd.
+ // But tellClientsWithResponse() must be called for both.
+ ignoreTellChangeDown = true;
+ }
}
return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
void IOPMrootDomain::systemDidNotSleep( void )
{
+ // reset console lock state
+ thread_call_enter(updateConsoleUsersEntry);
+
if (!wrangler)
{
- if (idleSeconds)
+ if (idleSleepEnabled)
{
// stay awake for at least idleSeconds
startIdleSleepTimer(idleSeconds);
}
else
{
- if (sleepSlider && !userIsActive)
+ if (idleSleepEnabled && !userIsActive)
{
// Manually start the idle sleep timer besides waiting for
// the user to become inactive.
preventTransitionToUserActive(false);
IOService::setAdvisoryTickleEnable( true );
+
+ // After idle revert and cancel, send a did-change message to powerd
+ // to balance the previous will-change message. Kernel clients do not
+ // need this since sleep cannot be canceled once they are notified.
+
+ if (toldPowerdCapWillChange && systemCapabilityNotifier &&
+ (_pendingCapability != _currentCapability) &&
+ ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0))
+ {
+ // Differs from a real capability gain change where notifyRef != 0,
+ // but it is zero here since no response is expected.
+
+ IOPMSystemCapabilityChangeParameters params;
+
+ bzero(¶ms, sizeof(params));
+ params.fromCapabilities = _pendingCapability;
+ params.toCapabilities = _currentCapability;
+ params.changeFlags = kIOPMSystemCapabilityDidChange;
+
+ DLOG("MESG cap %x->%x did change\n",
+ params.fromCapabilities, params.toCapabilities);
+ messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier,
+ ¶ms, sizeof(params));
+ }
}
//******************************************************************************
void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
{
-
DLOG("tellChangeUp %u->%u\n",
(uint32_t) getPowerState(), (uint32_t) stateNum);
tellClients( kIOMessageSystemWillPowerOn );
}
-
tracePoint( kIOPMTracePointWakeApplications );
tellClients( kIOMessageSystemHasPoweredOn );
}
}
+#define CAP_WILL_CHANGE_TO_OFF(params, flag) \
+ (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
+ ((params)->fromCapabilities & (flag)) && \
+ (((params)->toCapabilities & (flag)) == 0))
+
+#define CAP_DID_CHANGE_TO_ON(params, flag) \
+ (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
+ ((params)->toCapabilities & (flag)) && \
+ (((params)->fromCapabilities & (flag)) == 0))
+
+#define CAP_DID_CHANGE_TO_OFF(params, flag) \
+ (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
+ ((params)->fromCapabilities & (flag)) && \
+ (((params)->toCapabilities & (flag)) == 0))
+
+#define CAP_WILL_CHANGE_TO_ON(params, flag) \
+ (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
+ ((params)->toCapabilities & (flag)) && \
+ (((params)->fromCapabilities & (flag)) == 0))
+
//******************************************************************************
// sysPowerDownHandler
//
if (messageType == kIOMessageSystemWillSleep)
{
#if HIBERNATION
- uint32_t mem_only = 0;
IOPowerStateChangeNotification *notify =
- (IOPowerStateChangeNotification *)messageArgs;
+ (IOPowerStateChangeNotification *)messageArgs;
- PE_parse_boot_argn("swd_mem_only", &mem_only, sizeof(mem_only));
- if ((mem_only != 1) && (gRootDomain->sleepWakeDebugIsWdogEnabled()))
- {
- notify->returnValue = 30 * 1000 * 1000;
- thread_call_enter1(
- gRootDomain->hibDebugSetupEntry,
- (thread_call_param_t)(uintptr_t) notify->powerRef);
- }
+ notify->returnValue = 30 * 1000 * 1000;
+ thread_call_enter1(
+ gRootDomain->swdDebugSetupEntry,
+ (thread_call_param_t)(uintptr_t) notify->powerRef);
#endif
}
else if (messageType == kIOMessageSystemCapabilityChange)
params->fromCapabilities, params->toCapabilities,
params->changeFlags);
- if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
- (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
- (params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)
+ if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU))
{
// We will ack within 20 seconds
params->maxWaitForReply = 20 * 1000 * 1000;
+
+ // Remove EFI/BootRom's previous wake's failure data
+ PERemoveNVRAMProperty(kIOEFIBootRomFailureKey);
+
#if HIBERNATION
gRootDomain->evaluateSystemSleepPolicyEarly();
gRootDomain->diskSyncCalloutEntry,
(thread_call_param_t)(uintptr_t) params->notifyRef);
}
- else
- if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
- (params->toCapabilities & kIOPMSystemCapabilityCPU) &&
- (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0)
- {
#if HIBERNATION
+ else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU))
+ {
// We will ack within 110 seconds
params->maxWaitForReply = 110 * 1000 * 1000;
thread_call_enter1(
gRootDomain->diskSyncCalloutEntry,
(thread_call_param_t)(uintptr_t) params->notifyRef);
-#endif
}
+ else if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityGraphics) ||
+ CAP_WILL_CHANGE_TO_ON(params, kIOPMSystemCapabilityGraphics))
+ {
+ // WillChange for Full wake -> Darkwake
+ params->maxWaitForReply = 30 * 1000 * 1000;
+ thread_call_enter1(
+ gRootDomain->swdDebugSetupEntry,
+ (thread_call_param_t)(uintptr_t) params->notifyRef);
+ }
+ else if (CAP_DID_CHANGE_TO_OFF(params, kIOPMSystemCapabilityGraphics) ||
+ CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityGraphics))
+ {
+ // DidChange for Full wake -> Darkwake
+ params->maxWaitForReply = 30 * 1000 * 1000;
+ thread_call_enter1(
+ gRootDomain->swdDebugTearDownEntry,
+ (thread_call_param_t)(uintptr_t) params->notifyRef);
+
+ }
+#endif
ret = kIOReturnSuccess;
}
void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
{
-#if HIBERNATION
+ OSDictionary *dict;
+ OSNumber *secs;
+
if (SLEEP_STATE == newPowerState)
{
+ if (!tasksSuspended)
+ {
+ AbsoluteTime deadline;
+ tasksSuspended = TRUE;
+ tasks_system_suspend(tasksSuspended);
+
+ clock_interval_to_deadline(10, kSecondScale, &deadline);
+#if !CONFIG_EMBEDDED
+ vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
+#endif /* !CONFIG_EMBEDDED */
+ }
+
+#if HIBERNATION
IOHibernateSystemSleep();
IOHibernateIOKitSleep();
- }
#endif
+ if (gRootDomain->activitySinceSleep()) {
+ dict = OSDictionary::withCapacity(1);
+ secs = OSNumber::withNumber(1, 32);
+
+ if (dict && secs) {
+ dict->setObject(gIOPMSettingDebugWakeRelativeKey, secs);
+ gRootDomain->setProperties(dict);
+ MSG("Reverting sleep with relative wake\n");
+ }
+ if (dict) dict->release();
+ if (secs) secs->release();
+ }
+
+ }
}
//******************************************************************************
fPMSettingsDict->setObject(type, object);
// Prep all PMSetting objects with the given 'type' for callout.
- array = (const OSArray *) settingsCallbacks->getObject(type);
+ array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
if (!array || ((capacity = array->getCount()) == 0))
goto unlock_exit;
PMSETTING_LOCK();
for (i=0; settings[i]; i++)
{
- list = (OSArray *) settingsCallbacks->getObject(settings[i]);
+ list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
if (!list) {
// New array of callbacks for this setting
list = OSArray::withCapacity(1);
{
while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
{
- array = (OSArray *) settingsCallbacks->getObject(sym);
+ array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
index = array->getNextIndexOfObject(pmso, 0);
if (-1 != index) {
array->removeObject(index);
varInfoStruct.varType = vBool;
varInfoStruct.varInitValue = value;
varInfoStruct.varCurValue = value;
- strncpy( (char *)varInfoStruct.varName,
+ strlcpy( (char *)varInfoStruct.varName,
(const char *)varNameStr,
- strlen(varNameStr) + 1 );
+ sizeof(varInfoStruct.varName));
// Set!
pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
uint32_t standbyDelay = 0;
uint32_t powerOffDelay = 0;
uint32_t powerOffTimer = 0;
+ uint32_t standbyTimer = 0;
uint32_t mismatch;
bool standbyEnabled;
bool powerOffEnabled;
&& (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
powerOffTimer = powerOffDelay;
+ if (!getSleepOption(kIOPMDeepSleepTimerKey, &standbyTimer))
+ standbyTimer = standbyDelay;
- DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
- sleepPhase, standbyEnabled, standbyDelay,
+ DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
+ sleepPhase, standbyEnabled, standbyDelay, standbyTimer,
powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
// pmset level overrides
currentFactors |= kIOPMSleepFactorACPower;
if (lowBatteryCondition)
currentFactors |= kIOPMSleepFactorBatteryLow;
- if (!standbyDelay)
+ if (!standbyDelay || !standbyTimer)
currentFactors |= kIOPMSleepFactorStandbyNoDelay;
- if (!standbyEnabled)
+ if (standbyNixed || !standbyEnabled)
currentFactors |= kIOPMSleepFactorStandbyDisabled;
+ if (resetTimers)
+ {
+ currentFactors |= kIOPMSleepFactorLocalUserActivity;
+ currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
+ }
if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
kIOPMDriverAssertionLevelOff)
currentFactors |= kIOPMSleepFactorUSBExternalDevice;
currentFactors |= kIOPMSleepFactorLocalUserActivity;
if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
currentFactors |= kIOPMSleepFactorHibernateFailed;
+ if (thermalWarningState)
+ currentFactors |= kIOPMSleepFactorThermalWarning;
DLOG("sleep factors 0x%llx\n", currentFactors);
gSleepPolicyVars->sleepReason = lastSleepReason;
gSleepPolicyVars->sleepPhase = sleepPhase;
gSleepPolicyVars->standbyDelay = standbyDelay;
+ gSleepPolicyVars->standbyTimer = standbyTimer;
gSleepPolicyVars->poweroffDelay = powerOffDelay;
gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm;
gSleepPolicyVars->poweroffTimer = powerOffTimer;
{
IOPMSystemSleepParameters params;
OSData * paramsData;
-
+ bool wakeNow;
// Evaluate sleep policy after sleeping drivers but before platform sleep.
DLOG("%s\n", __FUNCTION__);
bzero(¶ms, sizeof(params));
+ wakeNow = false;
if (evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase2, &hibernateMode))
{
- if ((hibernateDisabled || hibernateAborted) &&
+ if ((kIOPMSleepTypeStandby == params.sleepType)
+ && gIOHibernateStandbyDisabled && gSleepPolicyVars
+ && (!(kIOPMSleepFactorStandbyForced & gSleepPolicyVars->sleepFactors)))
+ {
+ standbyNixed = true;
+ wakeNow = true;
+ }
+ if (wakeNow
+ || ((hibernateDisabled || hibernateAborted) &&
(getSleepTypeAttributes(params.sleepType) &
- kIOPMSleepAttributeHibernateSetup))
+ kIOPMSleepAttributeHibernateSetup)))
{
// Final evaluation picked a state requiring hibernation,
- // but hibernate setup was skipped. Arm a short sleep using
+ // but hibernate isn't going to proceed. Arm a short sleep using
// the early non-hibernate sleep parameters.
- // Set hibernateRetry flag to force hibernate setup on the
- // next sleep.
-
bcopy(&gEarlySystemSleepParams, ¶ms, sizeof(params));
params.sleepType = kIOPMSleepTypeAbortedSleep;
params.ecWakeTimer = 1;
- hibernateRetry = true;
- DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
- params.ecWakeTimer, hibernateDisabled, hibernateAborted);
+ if (standbyNixed)
+ {
+ resetTimers = true;
+ }
+ else
+ {
+ // Set hibernateRetry flag to force hibernate setup on the
+ // next sleep.
+ hibernateRetry = true;
+ }
+ DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
+ params.ecWakeTimer, hibernateDisabled, hibernateAborted, standbyNixed);
}
else
{
hibernateRetry = false;
}
+ if (kIOPMSleepTypeAbortedSleep != params.sleepType)
+ {
+ resetTimers = false;
+ }
+
paramsData = OSData::withBytes(¶ms, sizeof(params));
if (paramsData)
{
{
obj = copyProperty(key);
}
- if (obj && (num = OSDynamicCast(OSNumber, obj)))
+ if (obj)
{
- *option = num->unsigned32BitValue();
- ok = true;
+ if ((num = OSDynamicCast(OSNumber, obj)))
+ {
+ *option = num->unsigned32BitValue();
+ ok = true;
+ }
+ else if (OSDynamicCast(OSBoolean, obj))
+ {
+ *option = (obj == kOSBooleanTrue) ? 1 : 0;
+ ok = true;
+ }
}
if (obj)
if (optionsProp)
optionsProp->release();
- return true;
+ return ok;
}
#endif /* HIBERNATION */
-IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
+IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType, uint32_t * standbyTimer )
{
#if HIBERNATION
IOPMSystemSleepParameters params;
OSMemberFunctionCast(IOWorkLoop::Action, this,
&IOPMrootDomain::getSystemSleepType),
(OSObject *) this,
- (void *) sleepType);
+ (void *) sleepType, (void *) standbyTimer);
return ret;
}
if (ok)
{
*sleepType = params.sleepType;
+ if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer) &&
+ !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
+ DLOG("Standby delay is not set\n");
+ *standbyTimer = 0;
+ }
return kIOReturnSuccess;
}
#endif
IOPMPowerFlags PowerFlags;
UInt32 MessageType;
UInt32 Counter;
+ const char * LogString;
};
static void
{
IOPowerStateChangeNotification notify;
HaltRestartApplierContext * ctx;
- AbsoluteTime startTime;
- UInt32 deltaTime;
+ AbsoluteTime startTime, elapsedTime;
+ uint32_t deltaTime;
ctx = (HaltRestartApplierContext *) context;
clock_get_uptime(&startTime);
ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)¬ify );
- deltaTime = computeDeltaTimeMS(&startTime);
+ deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
if ((deltaTime > kPMHaltTimeoutMS) ||
(gIOKitDebug & kIOLogPMRootDomain))
if (notifier)
{
LOG("%s handler %p took %u ms\n",
- (ctx->MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
- (ctx->MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
- OBFUSCATE(notifier->handler), (uint32_t) deltaTime );
+ ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
+ halt_log_enter(ctx->LogString, (const void *) notifier->handler, elapsedTime);
}
}
ctx->Counter++;
}
+static void quiescePowerTreeCallback( void * target, void * param )
+{
+ IOLockLock(gPMHaltLock);
+ gPMQuiesced = true;
+ thread_wakeup(param);
+ IOLockUnlock(gPMHaltLock);
+}
+
void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
{
HaltRestartApplierContext ctx;
- AbsoluteTime startTime;
- UInt32 deltaTime;
+ AbsoluteTime startTime, elapsedTime;
+ uint32_t deltaTime;
memset(&ctx, 0, sizeof(ctx));
ctx.RootDomain = this;
case kPEUPSDelayHaltCPU:
ctx.PowerState = OFF_STATE;
ctx.MessageType = kIOMessageSystemWillPowerOff;
+ ctx.LogString = "PowerOff";
break;
case kPERestartCPU:
ctx.PowerState = RESTART_STATE;
ctx.MessageType = kIOMessageSystemWillRestart;
+ ctx.LogString = "Restart";
break;
case kPEPagingOff:
ctx.PowerState = ON_STATE;
ctx.MessageType = kIOMessageSystemPagingOff;
+ ctx.LogString = "PagingOff";
IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
#if HIBERNATION
IOHibernateSystemRestart();
IOCPURunPlatformHaltRestartActions(pe_type);
- deltaTime = computeDeltaTimeMS(&startTime);
- LOG("%s all drivers took %u ms\n",
- (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
- (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
- (uint32_t) deltaTime );
+ // Wait for PM to quiesce
+ if ((kPEPagingOff != pe_type) && gPMHaltLock)
+ {
+ AbsoluteTime quiesceTime = mach_absolute_time();
+
+ IOLockLock(gPMHaltLock);
+ gPMQuiesced = false;
+ if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
+ kIOReturnSuccess)
+ {
+ while (!gPMQuiesced)
+ {
+ IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
+ }
+ }
+ IOLockUnlock(gPMHaltLock);
+ deltaTime = computeDeltaTimeMS(&quiesceTime, &elapsedTime);
+ DLOG("PM quiesce took %u ms\n", deltaTime);
+ halt_log_enter("Quiesce", NULL, elapsedTime);
+ }
+
+ deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
+ LOG("%s all drivers took %u ms\n", ctx.LogString, deltaTime);
+
+ halt_log_enter(ctx.LogString, NULL, elapsedTime);
+ if (gHaltLog) gHaltLog[gHaltLogPos] = 0;
+
+ deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
+ LOG("%s total %u ms\n", ctx.LogString, deltaTime);
+
+ if (gHaltLog && gHaltTimeMaxLog && (deltaTime >= gHaltTimeMaxLog))
+ {
+ printf("%s total %d ms:%s\n", ctx.LogString, deltaTime, gHaltLog);
+ }
+ if (gHaltLog && gHaltTimeMaxPanic && (deltaTime >= gHaltTimeMaxPanic))
+ {
+ panic("%s total %d ms:%s\n", ctx.LogString, deltaTime, gHaltLog);
+ }
}
//******************************************************************************
_systemTransitionType = kSystemTransitionNone;
_systemMessageClientMask = 0;
capabilityLoss = false;
+ toldPowerdCapWillChange = false;
if (lowBatteryCondition)
{
_pendingCapability = 0;
capabilityLoss = true;
- // Clear previous stats
- IOLockLock(pmStatsLock);
- if (pmStatsAppResponses)
- {
- pmStatsAppResponses->release();
- pmStatsAppResponses = OSArray::withCapacity(5);
- }
- IOLockUnlock(pmStatsLock);
-
}
else if (kSystemTransitionNewCapClient != _systemTransitionType)
{
// Full to Dark transition.
if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
{
+ // Clear previous stats
+ IOLockLock(pmStatsLock);
+ if (pmStatsAppResponses)
+ {
+ pmStatsAppResponses->release();
+ pmStatsAppResponses = OSArray::withCapacity(5);
+ }
+ IOLockUnlock(pmStatsLock);
+
+
tracePoint( kIOPMTracePointDarkWakeEntry );
*inOutChangeFlags |= kIOPMSyncTellPowerDown;
_systemMessageClientMask = kSystemMessageClientPowerd |
// Publish a UUID for the Sleep --> Wake cycle
handlePublishSleepWakeUUID(true);
+ if (sleepDelaysReport) {
+ clock_get_uptime(&ts_sleepStart);
+ DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
+ }
+
+ wranglerTickled = false;
}
}
{
// Beginning of a system sleep transition.
// Cancellation is still possible.
- tracePoint( kIOPMTracePointSleepStarted, sleepReason );
+ tracePoint( kIOPMTracePointSleepStarted );
_systemMessageClientMask = kSystemMessageClientAll;
if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
_systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
_systemMessageClientMask &= ~kSystemMessageClientKernel;
+#if HIBERNATION
+ gIOHibernateState = 0;
+#endif
// Record the reason for dark wake back to sleep
// System may not have ever achieved full wake
publishSleepReason = true;
lastSleepReason = sleepReason;
+ if (sleepDelaysReport) {
+ clock_get_uptime(&ts_sleepStart);
+ DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
+ }
}
// 3. System wake.
if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
CAP_CURRENT(kIOPMSystemCapabilityCPU))
{
+#if !CONFIG_EMBEDDED
pmPowerStateQueue->submitPowerEvent(
kPowerEventPolicyStimulus,
(void *) kStimulusDarkWakeReentry,
_systemStateGeneration );
+#else
+ // On embedded, there are no factors that can prolong a
+ // "darkWake" when a power down is vetoed. We need to
+ // promote to "fullWake" at least once so that factors
+ // that prevent idle sleep can assert themselves if required
+ pmPowerStateQueue->submitPowerEvent(
+ kPowerEventPolicyStimulus,
+ (void *) kStimulusDarkWakeActivityTickle);
+#endif
}
// Revert device desire to max.
{
// Going dark, reset full wake state
// userIsActive will be cleared by wrangler powering down
- wranglerTickled = false;
fullWakeReason = kFullWakeReasonNone;
+
+ if (ts_sleepStart) {
+ clock_get_uptime(&wake2DarkwakeDelay);
+ SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
+ DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
+ ts_sleepStart = 0;
+ }
}
}
darkWakePostTickle = false;
reportUserInput();
}
+ else if (wranglerTickled) {
+ requestFullWake( kFullWakeReasonLocalUser );
+ }
// Reset tracepoint at completion of capability change,
// completion of wake transition, and aborted sleep transition.
(changeFlags & kIOPMNotDone)))
{
setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
- tracePoint( kIOPMTracePointSystemUp, 0 );
+ tracePoint( kIOPMTracePointSystemUp );
}
_systemTransitionType = kSystemTransitionNone;
_systemMessageClientMask = 0;
+ toldPowerdCapWillChange = false;
logGraphicsClamp = false;
+
+ if (lowBatteryCondition) {
+ privateSleepSystem (kIOPMSleepReasonLowPower);
+ }
+ else if ((fullWakeReason == kFullWakeReasonDisplayOn) && (!displayPowerOnRequested)) {
+ // Request for full wake is removed while system is waking up to full wake
+ DLOG("DisplayOn fullwake request is removed\n");
+ handleDisplayPowerOn();
+ }
+
}
}
uint64_t nsec;
clock_get_uptime(&now);
- SUB_ABSOLUTETIME(&now, &systemWakeTime);
+ SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
absolutetime_to_nanoseconds(now, &nsec);
if (kIOLogPMRootDomain & gIOKitDebug)
MSG("Graphics suppressed %u ms\n",
clock_get_uptime(&userActivityTime);
bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
- || (lastSleepReason == kIOPMSleepReasonMaintenance));
+ || (lastSleepReason == kIOPMSleepReasonMaintenance)
+ || (lastSleepReason == kIOPMSleepReasonSoftware));
if (aborting) {
userActivityCount++;
DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
evaluatePolicy( kStimulusLeaveUserActiveState );
}
}
+
+ if (newPowerState <= kWranglerPowerStateSleep) {
+ evaluatePolicy( kStimulusDisplayWranglerSleep );
+ }
+ else if (newPowerState == kWranglerPowerStateMax) {
+ evaluatePolicy( kStimulusDisplayWranglerWake );
+ }
#endif
}
protected:
uint32_t ackTimeoutCnt;
+ uint32_t msgType; // Message pending ack
+ uint64_t uuid0;
+ uint64_t uuid1;
+ const OSSymbol *identifier;
};
OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
if (!notifier) return NULL;
if (notifier->init()) {
- rc = super::registerInterestForNotifer(notifier, typeOfInterest, handler, target, ref);
+ rc = super::registerInterestForNotifier(notifier, typeOfInterest, handler, target, ref);
}
if (rc != kIOReturnSuccess) {
notifier->release();
notifier = 0;
+
+ return NULL;
}
if (pmPowerStateQueue)
{
}
}
+ OSData *data = NULL;
+ uint8_t *uuid = NULL;
+ OSKext *kext = OSKext::lookupKextWithAddress((vm_address_t)handler);
+ if (kext) {
+ data = kext->copyUUID();
+ }
+ if (data && (data->getLength() == sizeof(uuid_t))) {
+ uuid = (uint8_t *)(data->getBytesNoCopy());
+
+ notifier->uuid0 = ((uint64_t)(uuid[0]) << 56) | ((uint64_t)(uuid[1]) << 48) | ((uint64_t)(uuid[2]) << 40)|
+ ((uint64_t)(uuid[3]) << 32) | ((uint64_t)(uuid[4]) << 24) | ((uint64_t)(uuid[5]) << 16) |
+ ((uint64_t)(uuid[6]) << 8) | (uuid[7]);
+ notifier->uuid1 = ((uint64_t)(uuid[8]) << 56) | ((uint64_t)(uuid[9]) << 48) | ((uint64_t)(uuid[10]) << 40)|
+ ((uint64_t)(uuid[11]) << 32) | ((uint64_t)(uuid[12]) << 24) | ((uint64_t)(uuid[13]) << 16) |
+ ((uint64_t)(uuid[14]) << 8) | (uuid[15]);
+
+ notifier->identifier = kext->getIdentifier();
+
+ }
+ if (kext) kext->release();
+ if (data) data->release();
+
return notifier;
}
bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
bool isCapClient = false;
bool allow = false;
+ IOPMServiceInterestNotifier *notifier;
+ notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
do {
if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
(!isCapMsg || !_joinedCapabilityClients ||
capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
else
capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
+
+ if ((object == (void *) systemCapabilityNotifier) &&
+ context->isPreChange)
+ {
+ toldPowerdCapWillChange = true;
+ }
}
// Capability change messages only go to the PM configd plugin.
{
// app has not replied yet, wait for it
*((OSObject **) arg3) = kOSBooleanFalse;
+
}
allow = true;
{
if ((object == (OSObject *) systemCapabilityNotifier) &&
CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
- (fullToDarkReason == kIOPMSleepReasonIdle))
+ (fullToDarkReason == kIOPMSleepReasonIdle)) {
allow = true;
+ }
break;
}
if ((context->notifyType == kNotifyApps) &&
(_systemMessageClientMask & kSystemMessageClientLegacyApp))
{
- IOPMServiceInterestNotifier *notify;
allow = true;
- if ((notify = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object))
- && arg3) {
-
- if (notify->ackTimeoutCnt >= 3)
- *((OSObject **) arg3) = kOSBooleanFalse;
- else
- *((OSObject **) arg3) = kOSBooleanTrue;
+ if (notifier) {
+ if (arg3) {
+ if (notifier->ackTimeoutCnt >= 3)
+ *((OSObject **) arg3) = kOSBooleanFalse;
+ else
+ *((OSObject **) arg3) = kOSBooleanTrue;
+ }
}
}
else if ((context->notifyType == kNotifyPriority) &&
_joinedCapabilityClients = 0;
}
}
+ if (notifier) {
+ notifier->msgType = context->messageType;
+ }
return allow;
}
IONotifier * notifier __unused)
{
#if !NO_KERNEL_HID
- // found the display wrangler, now install a handler
+ // found the display wrangler, check for any display assertions already created
+ gRootDomain->evaluateWranglerAssertions();
+ // install a handler
if( !newService->registerInterest( gIOGeneralInterest,
&displayWranglerNotification, target, 0) )
{
{
#if !NO_KERNEL_HID
OSIterator * iter;
+ OSDictionary * matching;
if(!wrangler)
{
- iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
+ matching = serviceMatching("IODisplayWrangler");
+ iter = getMatchingServices(matching);
+ if (matching) matching->release();
if(iter)
{
- wrangler = (IOService *) iter->getNextObject();
+ wrangler = OSDynamicCast(IOService, iter->getNextObject());
iter->release();
}
}
void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
{
- if (checkSystemCanSustainFullWake())
- {
- pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
- (void *) 0, options );
- }
+ pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
+ (void *) 0, options );
}
// MARK: -
break;
#endif
- if (lowBatteryCondition)
+ if (lowBatteryCondition || thermalWarningState)
{
- break; // always sleep on low battery
+ break; // always sleep on low battery or when in thermal warning state
}
if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
{
#if !NO_KERNEL_HID
- if (lowBatteryCondition)
+ if (lowBatteryCondition || thermalWarningState)
{
// Low battery wake, or received a low battery notification
// while system is awake. This condition will persist until
return true;
}
+//******************************************************************************
+// mustHibernate
+//******************************************************************************
+
+#if HIBERNATION
+
+bool IOPMrootDomain::mustHibernate( void )
+{
+ return (lowBatteryCondition || thermalWarningState);
+}
+
+#endif /* HIBERNATION */
+
//******************************************************************************
// adjustPowerState
//
void IOPMrootDomain::adjustPowerState( bool sleepASAP )
{
- DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
- (uint32_t) getPowerState(), sleepASAP, sleepSlider);
+ DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
+ (uint32_t) getPowerState(), sleepASAP, idleSleepEnabled);
ASSERT_GATED();
- if ((sleepSlider == 0) || !checkSystemSleepEnabled())
+ if ((!idleSleepEnabled) || !checkSystemSleepEnabled())
{
changePowerStateToPriv(ON_STATE);
}
}
}
+void IOPMrootDomain::handleDisplayPowerOn( )
+{
+ if (!wrangler) return;
+ if (displayPowerOnRequested)
+ {
+ if (!checkSystemCanSustainFullWake()) return;
+
+ // Force wrangler to max power state. If system is in dark wake
+ // this alone won't raise the wrangler's power state.
+
+ wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
+
+ // System in dark wake, always requesting full wake should
+ // not have any bad side-effects, even if the request fails.
+
+ if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
+ {
+ setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
+ requestFullWake( kFullWakeReasonDisplayOn );
+ }
+ }
+ else
+ {
+ // Relenquish desire to power up display.
+ // Must first transition to state 1 since wrangler doesn't
+ // power off the displays at state 0. At state 0 the root
+ // domain is removed from the wrangler's power client list.
+
+ wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
+ wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
+
+ }
+
+}
+
//******************************************************************************
// dispatchPowerEvent
//
void IOPMrootDomain::dispatchPowerEvent(
uint32_t event, void * arg0, uint64_t arg1 )
{
- DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
ASSERT_GATED();
switch (event)
{
case kPowerEventFeatureChanged:
+ DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
messageClients(kIOPMMessageFeatureChange, this);
break;
case kPowerEventReceivedPowerNotification:
+ DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
handlePowerNotification( (UInt32)(uintptr_t) arg0 );
break;
case kPowerEventSystemBootCompleted:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (systemBooting)
{
systemBooting = false;
break;
case kPowerEventSystemShutdown:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (kOSBooleanTrue == (OSBoolean *) arg0)
{
/* We set systemShutdown = true during shutdown
systemShutdown = true;
} else {
/*
- A shutdown was initiated, but then the shutdown
- was cancelled, clearing systemShutdown to false here.
- */
+ A shutdown was initiated, but then the shutdown
+ was cancelled, clearing systemShutdown to false here.
+ */
systemShutdown = false;
}
break;
case kPowerEventUserDisabledSleep:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
break;
case kPowerEventRegisterSystemCapabilityClient:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (systemCapabilityNotifier)
{
systemCapabilityNotifier->release();
systemCapabilityNotifier->retain();
}
/* intentional fall-through */
+ [[clang::fallthrough]];
case kPowerEventRegisterKernelCapabilityClient:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (!_joinedCapabilityClients)
_joinedCapabilityClients = OSSet::withCapacity(8);
if (arg0)
break;
case kPowerEventPolicyStimulus:
+ DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (arg0)
{
int stimulus = (uintptr_t) arg0;
break;
case kPowerEventAssertionCreate:
+ DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (pmAssertions) {
pmAssertions->handleCreateAssertion((OSData *)arg0);
}
case kPowerEventAssertionRelease:
+ DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (pmAssertions) {
pmAssertions->handleReleaseAssertion(arg1);
}
break;
case kPowerEventAssertionSetLevel:
+ DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (pmAssertions) {
pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
}
break;
case kPowerEventQueueSleepWakeUUID:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
handleQueueSleepWakeUUID((OSObject *)arg0);
break;
case kPowerEventPublishSleepWakeUUID:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
handlePublishSleepWakeUUID((bool)arg0);
break;
case kPowerEventSetDisplayPowerOn:
+ DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
if (!wrangler) break;
if (arg1 != 0)
{
- // Force wrangler to max power state. If system is in dark wake
- // this alone won't raise the wrangler's power state.
-
- wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
-
- // System in dark wake, always requesting full wake should
- // not have any bad side-effects, even if the request fails.
-
- if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
- {
- setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
- requestFullWake( kFullWakeReasonDisplayOn );
- }
+ displayPowerOnRequested = true;
}
else
{
- // Relenquish desire to power up display.
- // Must first transition to state 1 since wrangler doesn't
- // power off the displays at state 0. At state 0 the root
- // domain is removed from the wrangler's power client list.
-
- wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
- wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
+ displayPowerOnRequested = false;
}
+ handleDisplayPowerOn();
break;
}
}
return attempt;
}
+void IOPMrootDomain::setThermalState(OSObject *value)
+{
+ OSNumber * num;
+
+ if (gIOPMWorkLoop->inGate() == false) {
+ gIOPMWorkLoop->runAction(
+ OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
+ (OSObject *)this,
+ (void *)value);
+
+ return;
+ }
+ if (value && (num = OSDynamicCast(OSNumber, value))) {
+ thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
+ (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
+ }
+}
+
IOReturn IOPMrootDomain::systemPowerEventOccurred(
const OSSymbol *event,
OSObject *value)
// UNLOCK
if (featuresDictLock) IOLockUnlock(featuresDictLock);
- if (shouldUpdate)
+ if (shouldUpdate) {
+ if (event &&
+ event->isEqualTo(kIOPMThermalLevelWarningKey)) {
+ setThermalState(value);
+ }
messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
+ }
return kIOReturnSuccess;
}
}
/*
- * Sleep if system is in dark wake
+ * Forward DW thermal notification to client, if system is not going to sleep
*/
- if (msg & kIOPMDWOverTemp)
+ if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
{
DLOG("DarkWake thermal limits message received!\n");
- // Inform cap client that we're going to sleep
messageClients(kIOPMMessageDarkWakeThermalEmergency);
-
}
/*
*/
if (msg & kIOPMClamshellOpened)
{
+ DLOG("Clamshell opened\n");
// Received clamshel open message from clamshell controlling driver
// Update our internal state and tell general interest clients
clamshellClosed = false;
*/
if (msg & kIOPMClamshellClosed)
{
+ DLOG("Clamshell closed\n");
// Received clamshel open message from clamshell controlling driver
// Update our internal state and tell general interest clients
clamshellClosed = true;
*/
if (msg & kIOPMSetDesktopMode)
{
+ DLOG("Desktop mode\n");
desktopMode = (0 != (msg & kIOPMSetValue));
msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
*/
if (msg & kIOPMEnableClamshell)
{
+ DLOG("Clamshell enabled\n");
// Re-evaluate the lid state
// System should sleep on external display disappearance
// in lid closed operation.
*/
if (msg & kIOPMDisableClamshell)
{
+ DLOG("Clamshell disabled\n");
clamshellDisabled = true;
sendClientClamshellNotification();
}
*/
if (msg & kIOPMPowerButton)
{
+ DLOG("Powerbutton press\n");
if (!wranglerAsleep)
{
OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
uint32_t u32;
} flags;
- DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
ASSERT_GATED();
flags.u32 = 0;
switch (stimulus)
{
case kStimulusDisplayWranglerSleep:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
if (!wranglerAsleep)
{
// first transition to wrangler sleep or lower
- wranglerAsleep = true;
flags.bit.displaySleep = true;
}
break;
case kStimulusDisplayWranglerWake:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
displayIdleForDemandSleep = false;
wranglerAsleep = false;
break;
case kStimulusEnterUserActiveState:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
if (_preventUserActive)
{
DLOG("user active dropped\n");
userWasActive = true;
// Stay awake after dropping demand for display power on
- if (kFullWakeReasonDisplayOn == fullWakeReason)
+ if (kFullWakeReasonDisplayOn == fullWakeReason) {
fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
+ DLOG("User activity while in notification wake\n");
+ changePowerStateWithOverrideTo( ON_STATE, 0);
+ }
+ kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
messageClients(kIOPMMessageUserIsActiveChanged);
}
break;
case kStimulusLeaveUserActiveState:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
if (userIsActive)
{
userIsActive = false;
clock_get_uptime(&userBecameInactiveTime);
flags.bit.userBecameInactive = true;
+ kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
messageClients(kIOPMMessageUserIsActiveChanged);
}
case kStimulusAggressivenessChanged:
{
+ DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
unsigned long minutesToIdleSleep = 0;
unsigned long minutesToDisplayDim = 0;
unsigned long minutesDelta = 0;
DLOG("idle time -> %ld secs (ena %d)\n",
idleSeconds, (minutesToIdleSleep != 0));
- if (0x7fffffff == minutesToIdleSleep)
- minutesToIdleSleep = idleSeconds;
// How long to wait before sleeping the system once
// the displays turns off is indicated by 'extraSleepDelay'.
else if ( minutesToIdleSleep == minutesToDisplayDim )
minutesDelta = 1;
- if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
- flags.bit.idleSleepEnabled = true;
+ if ((!idleSleepEnabled) && (minutesToIdleSleep != 0))
+ idleSleepEnabled = flags.bit.idleSleepEnabled = true;
- if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
+ if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
flags.bit.idleSleepDisabled = true;
+ idleSleepEnabled = false;
+ }
+ if (0x7fffffff == minutesToIdleSleep)
+ minutesToIdleSleep = idleSeconds;
if (((minutesDelta != extraSleepDelay) ||
(userActivityTime != userActivityTime_prev)) &&
} break;
case kStimulusDemandSystemSleep:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
displayIdleForDemandSleep = true;
if (wrangler && wranglerIdleSettings)
{
break;
case kStimulusAllowSystemSleepChanged:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
flags.bit.adjustPowerState = true;
break;
case kStimulusDarkWakeActivityTickle:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
// arg == true implies real and not self generated wrangler tickle.
// Update wake type on PM work loop instead of the tickle thread to
// eliminate the possibility of an early tickle clobbering the wake
case kStimulusDarkWakeEntry:
case kStimulusDarkWakeReentry:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
// Any system transitions since the last dark wake transition
// will invalid the stimulus.
{
clock_get_uptime(&userBecameInactiveTime);
flags.bit.evaluateDarkWake = true;
+ if (activitySinceSleep()) {
+ DLOG("User activity recorded while going to darkwake\n");
+ reportUserInput();
+ }
}
// Always accelerate disk spindown while in dark wake,
break;
case kStimulusDarkWakeEvaluate:
+ DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
if (systemDarkWake)
{
flags.bit.evaluateDarkWake = true;
break;
case kStimulusNoIdleSleepPreventers:
+ DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
flags.bit.adjustPowerState = true;
break;
(kFullWakeReasonDisplayOn == fullWakeReason))
{
// kIOPMSleepReasonMaintenance?
+ DLOG("Display sleep while in notification wake\n");
changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
}
DLOG("user inactive\n");
}
- if (!userIsActive && sleepSlider)
+ if (!userIsActive && idleSleepEnabled)
{
startIdleSleepTimer(getTimeToIdleSleep());
}
if (!wrangler)
{
changePowerStateToPriv(ON_STATE);
- if (idleSeconds)
- {
- startIdleSleepTimer( idleSeconds );
- }
+ startIdleSleepTimer( idleSeconds );
}
else
{
if (!wrangler)
{
changePowerStateToPriv(ON_STATE);
- if (idleSeconds)
+ if (idleSleepEnabled)
{
// stay awake for at least idleSeconds
startIdleSleepTimer(idleSeconds);
uint64_t nsec;
clock_get_uptime(&now);
- SUB_ABSOLUTETIME(&now, &systemWakeTime);
+ SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
absolutetime_to_nanoseconds(now, &nsec);
MSG("full wake %s (reason %u) %u ms\n",
promotion ? "promotion" : "request",
{
hibernateRetry = false;
sleepToStandby = false;
+ standbyNixed = false;
+ resetTimers = false;
sleepTimerMaintenance = false;
_systemMessageClientMask = kSystemMessageClientPowerd |
}
}
- if (changedBits & kIOPMDriverAssertionCPUBit)
+ if (changedBits & kIOPMDriverAssertionCPUBit) {
evaluatePolicy(kStimulusDarkWakeEvaluate);
+ if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
+ AbsoluteTime now;
+ clock_usec_t microsecs;
+ clock_get_uptime(&now);
+ SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
+ absolutetime_to_microtime(now, &assertOnWakeSecs, µsecs);
+ if (assertOnWakeReport) {
+ HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+ DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+ }
+ }
+ }
if (changedBits & kIOPMDriverAssertionReservedBit7) {
bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
}
}
+void IOPMrootDomain::evaluateWranglerAssertions()
+{
+ if (gIOPMWorkLoop->inGate() == false) {
+ gIOPMWorkLoop->runAction(
+ OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::evaluateWranglerAssertions),
+ (OSObject *)this);
+
+ return;
+ }
+
+ if (pmAssertions->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit) {
+ DLOG("wrangler setIgnoreIdleTimer\(1) on matching\n");
+ wrangler->setIgnoreIdleTimer( true );
+ }
+}
+
// MARK: -
// MARK: Statistics
const char *name,
int messageType,
uint32_t delay_ms,
- int app_pid,
+ uint64_t id,
OSObject *object,
IOPMPowerStateIndex powerState)
{
if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
{
- if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut))
+ if (response->isEqualTo(gIOPMStatsResponseTimedOut))
notify->ackTimeoutCnt++;
else
notify->ackTimeoutCnt = 0;
}
- if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) ||
+ if (response->isEqualTo(gIOPMStatsResponsePrompt) ||
(_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
return;
- responseDescription = OSDictionary::withCapacity(5);
- if (responseDescription)
- {
- if (response) {
- responseDescription->setObject(_statsResponseTypeKey, response);
+ if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
+ kdebugTrace(kPMLogDrvPSChangeDelay, id, messageType, delay_ms);
+ }
+ else if (notify) {
+ // User space app or kernel capability client
+ if (id) {
+ kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
+ }
+ else {
+ kdebugTrace(kPMLogDrvResponseDelay, notify->uuid0, messageType, delay_ms);
+ }
+ notify->msgType = 0;
+ }
+
+ responseDescription = OSDictionary::withCapacity(5);
+ if (responseDescription)
+ {
+ if (response) {
+ responseDescription->setObject(_statsResponseTypeKey, response);
}
msgNum = OSNumber::withNumber(messageType, 32);
msgNum->release();
}
+ if (!name && notify && notify->identifier) {
+ name = notify->identifier->getCStringNoCopy();
+ }
+
if (name && (strlen(name) > 0))
{
appname = OSSymbol::withCString(name);
}
}
- if (app_pid != -1) {
- pidNum = OSNumber::withNumber(app_pid, 32);
+ if (!id && notify) {
+ id = notify->uuid0;
+ }
+ if (id != 0) {
+ pidNum = OSNumber::withNumber(id, 64);
if (pidNum) {
responseDescription->setObject(_statsPIDKey, pidNum);
pidNum->release();
if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
powerCaps = OSNumber::withNumber(powerState, 32);
-#if !defined(__i386__) && !defined(__x86_64__)
+#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
name, messageType,
powerState, delay_ms);
void * param1, void * param2,
void * param3, void * param4 )
{
+ uint32_t bootFailureCode = 0xffffffff;
+ unsigned int len = sizeof(bootFailureCode);
if (pmTracer && functionName &&
functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
!pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
pmTracer->tracePointTarget = (void *) param2;
tracePointPCI = (uint32_t)(uintptr_t) param3;
tracePointPhases = (uint32_t)(uintptr_t) param4;
+ if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
+ if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey, &bootFailureCode, &len)) {
+ MSG("Failed to read failure code from NVRam\n");
+ }
+ // Failure code from EFI/BootRom is a four byte structure
+ tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
+ }
statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
- if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
- {
+ if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
MSG("Sleep failure code 0x%08x 0x%08x\n",
tracePointPCI, tracePointPhases);
}
functionName, waitForFunction, param1, param2, param3, param4);
}
+void IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
+ uintptr_t param1, uintptr_t param2, uintptr_t param3)
+{
+ uint32_t code = IODBG_POWER(event);
+ uint64_t regId = id;
+ if (regId == 0) {
+ regId = getRegistryEntryID();
+ }
+ IOTimeStampConstant(code, (uintptr_t) regId, param1, param2, param3);
+}
+
+
void IOPMrootDomain::tracePoint( uint8_t point )
{
if (systemBooting) return;
if (kIOPMTracePointWakeCapabilityClients == point)
acceptSystemWakeEvents(false);
- PMDebug(kPMLogSleepWakeTracePoint, point, 0);
+ kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
pmTracer->tracePoint(point);
}
-void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
+void IOPMrootDomain::traceDetail(OSObject *object)
{
- if (systemBooting) return;
+ IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
+ if (!notifier) {
+ DLOG("Unknown notifier\n");
+ return;
+ }
+
+ if (!systemBooting) {
+ pmTracer->traceDetail( notifier->uuid0 >> 32 );
+ kdebugTrace(kPMLogSleepWakeMessage, pmTracer->getTracePhase(), notifier->msgType, notifier->uuid0, notifier->uuid1);
+ if (notifier->identifier) {
+ DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer->getTracePhase(), notifier->msgType,
+ notifier->identifier->getCStringNoCopy());
+ }
+ else {
+ DLOG("trace point 0x%02x msg 0x%x\n", pmTracer->getTracePhase(), notifier->msgType);
+ }
+ }
- PMDebug(kPMLogSleepWakeTracePoint, point, data);
- pmTracer->tracePoint(point, data);
}
-void IOPMrootDomain::traceDetail( uint32_t detail )
+
+void IOPMrootDomain::traceAckDelay(OSObject *object, uint32_t response, uint32_t delay_ms)
+{
+ IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
+ if (!notifier) {
+ DLOG("Unknown notifier\n");
+ return;
+ }
+
+ if (!systemBooting) {
+ kdebugTrace(kPMLogDrvResponseDelay, notifier->uuid0, notifier->uuid1, response, delay_ms);
+ if (notifier->identifier) {
+ DLOG("Response from %s took %d ms(response:%d)\n",
+ notifier->identifier->getCStringNoCopy(), delay_ms, response);
+ }
+ else {
+ DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
+ notifier->uuid0, notifier->uuid1, delay_ms, response);
+ }
+ }
+}
+
+void IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uint32_t delay)
{
- if (!systemBooting)
+ if (!systemBooting) {
+ uint32_t detail = ((msgType & 0xffff) << 16) | (delay & 0xffff);
pmTracer->traceDetail( detail );
+ kdebugTrace(kPMLogSleepWakeTracePoint, pmTracer->getTracePhase(), msgType, delay);
+ DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
+ }
}
+void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
+{
+ size_t reportSize;
+ void **report = NULL;
+ uint32_t bktCnt;
+ uint32_t bktSize;
+ uint32_t *clientCnt;
+
+ ASSERT_GATED();
+
+ report = NULL;
+ if (channel_id == kAssertDelayChID) {
+ report = &assertOnWakeReport;
+ bktCnt = kAssertDelayBcktCnt;
+ bktSize = kAssertDelayBcktSize;
+ clientCnt = &assertOnWakeClientCnt;
+ }
+ else if (channel_id == kSleepDelaysChID) {
+ report = &sleepDelaysReport;
+ bktCnt = kSleepDelaysBcktCnt;
+ bktSize = kSleepDelaysBcktSize;
+ clientCnt = &sleepDelaysClientCnt;
+ }
+
+ switch (action)
+ {
+ case kIOReportEnable:
+
+ if (*report) {
+ (*clientCnt)++;
+ break;
+ }
+
+ reportSize = HISTREPORT_BUFSIZE(bktCnt);
+ *report = IOMalloc(reportSize);
+ if (*report == NULL) {
+ break;
+ }
+ bzero(*report, reportSize);
+ HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
+ getRegistryEntryID(), channel_id, kIOReportCategoryPower);
+
+ if (channel_id == kAssertDelayChID)
+ assertOnWakeSecs = 0;
+
+ break;
+
+ case kIOReportDisable:
+ if (*clientCnt == 0) {
+ break;
+ }
+ if (*clientCnt == 1)
+ {
+ IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
+ *report = NULL;
+ }
+ (*clientCnt)--;
+
+ if (channel_id == kAssertDelayChID)
+ assertOnWakeSecs = -1; // Invalid value to prevent updates
+
+ break;
+
+ case kIOReportGetDimensions:
+ if (*report) {
+ HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
+ }
+ break;
+ }
+
+ return;
+}
+
IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
IOReportConfigureAction action,
void *result,
void *destination)
{
unsigned cnt;
- if (action != kIOReportGetDimensions) goto exit;
+ uint64_t configAction = (uint64_t)action;
for (cnt = 0; cnt < channelList->nchannels; cnt++) {
if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
(channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
(channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
+ if (action != kIOReportGetDimensions) continue;
SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
}
+ else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
+ (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
+ gIOPMWorkLoop->runAction(
+ OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
+ (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
+ (void *)configAction, (void *)result);
+ }
}
-exit:
return super::configureReport(channelList, action, result, destination);
}
+IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
+{
+
+ uint32_t size2cpy;
+ void *data2cpy;
+ void **report;
+
+ ASSERT_GATED();
+
+ report = NULL;
+ if (ch_id == kAssertDelayChID) {
+ report = &assertOnWakeReport;
+ }
+ else if (ch_id == kSleepDelaysChID) {
+ report = &sleepDelaysReport;
+ }
+
+ if (*report == NULL) {
+ return kIOReturnNotOpen;
+ }
+
+ HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
+ if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
+ return kIOReturnOverrun;
+ }
+
+ HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
+ dest->appendBytes(data2cpy, size2cpy);
+
+ return kIOReturnSuccess;
+}
IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
IOReportUpdateAction action,
for (cnt = 0; cnt < channelList->nchannels; cnt++) {
ch_id = channelList->channels[cnt].channel_id ;
- if ((ch_id == kSleepCntChID) ||
+ if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
+ gIOPMWorkLoop->runAction(
+ OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
+ (OSObject *)this, (void *)ch_id,
+ (void *)result, (void *)dest);
+ continue;
+
+ }
+ else if ((ch_id == kSleepCntChID) ||
(ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
}
// this dictionary lazily.
me->owner = owner;
me->pciDeviceBitMappings = NULL;
- me->pciMappingLock = IOLockAlloc();
+ me->pmTraceWorkerLock = IOLockAlloc();
me->tracePhase = kIOPMTracePointSystemUp;
- me->loginWindowPhase = 0;
me->traceData32 = 0;
+ me->loginWindowData = 0;
+ me->coreDisplayData = 0;
+ me->coreGraphicsData = 0;
return me;
}
{
uint32_t wordA;
- wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
- (traceData8 << 8);
+ IOLockLock(pmTraceWorkerLock);
+ wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
+ (coreGraphicsData << 8) | tracePhase;
+ IOLockUnlock(pmTraceWorkerLock);
tracePointHandler( tracePointTarget, traceData32, wordA );
_LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
const OSSymbol * deviceName;
int index = -1;
- IOLockLock(pciMappingLock);
+ IOLockLock(pmTraceWorkerLock);
if (!pciDeviceBitMappings)
{
addedToRegistry = owner->setProperty("PCITopLevel", this);
exit:
- IOLockUnlock(pciMappingLock);
+ IOLockUnlock(pmTraceWorkerLock);
return index;
}
bool ok = false;
if (pciDeviceBitMappings)
{
- IOLockLock(pciMappingLock);
+ IOLockLock(pmTraceWorkerLock);
ok = pciDeviceBitMappings->serialize(s);
- IOLockUnlock(pciMappingLock);
+ IOLockUnlock(pmTraceWorkerLock);
}
return ok;
}
RTC_TRACE();
}
-void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
-{
- // clear trace detail when phase begins
- if (tracePhase != phase)
- traceData32 = 0;
-
- tracePhase = phase;
- traceData8 = data8;
-
- DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
- RTC_TRACE();
-}
-
void PMTraceWorker::traceDetail(uint32_t detail)
{
- if (kIOPMTracePointSleepPriorityClients != tracePhase)
+ if (detail == traceData32) {
return;
-
+ }
traceData32 = detail;
- DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
-
RTC_TRACE();
}
-void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
+void PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
{
- loginWindowPhase = phase;
-
- DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
+ switch (component) {
+ case kIOPMLoginWindowProgress:
+ loginWindowData = data & kIOPMLoginWindowProgressMask;
+ break;
+ case kIOPMCoreDisplayProgress:
+ coreDisplayData = data & kIOPMCoreDisplayProgressMask;
+ break;
+ case kIOPMCoreGraphicsProgress:
+ coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
+ break;
+ default:
+ return;
+ }
+
+ DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
RTC_TRACE();
}
traceData32 |= bitMask;
_LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
service->getName(), bitNum, bitMask, traceData32);
+ owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
}
else
{
traceData32 &= ~bitMask;
_LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
service->getName(), bitNum, bitMask, traceData32);
+ owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
}
DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
uint64_t PMTraceWorker::getPMStatusCode( )
{
- return (((uint64_t)traceData32 << 32) | (tracePhase << 24) |
- (loginWindowPhase << 16) | (traceData8 << 8));
+ return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase));
}
+uint8_t PMTraceWorker::getTracePhase()
+{
+ return tracePhase;
+}
+
+uint32_t PMTraceWorker::getTraceData()
+{
+ return traceData32;
+}
+
// MARK: -
// MARK: PMHaltWorker
//
//******************************************************************************
-static unsigned int gPMHaltBusyCount;
-static unsigned int gPMHaltIdleCount;
-static int gPMHaltDepth;
-static unsigned long gPMHaltEvent;
-static IOLock * gPMHaltLock = 0;
-static OSArray * gPMHaltArray = 0;
-static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
-
PMHaltWorker * PMHaltWorker::worker( void )
{
PMHaltWorker * me;
{
IOService * service;
OSSet * inner;
- AbsoluteTime startTime;
+ AbsoluteTime startTime, elapsedTime;
UInt32 deltaTime;
bool timeout;
inner = (OSSet *)gPMHaltArray->getObject(me->depth);
if (inner)
{
- service = (IOService *)inner->getAnyObject();
+ service = OSDynamicCast(IOService, inner->getAnyObject());
if (service)
{
service->retain();
me->timeout = false;
IOLockUnlock(me->lock);
- service->systemWillShutdown( gPMHaltEvent );
+ service->systemWillShutdown( gPMHaltMessageType );
// Wait for driver acknowledgement
IOLockLock(me->lock);
IOLockUnlock(me->lock);
}
- deltaTime = computeDeltaTimeMS(&startTime);
+ deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
(gIOKitDebug & kIOLogPMRootDomain))
{
- LOG("%s driver %s (%p) took %u ms\n",
- (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
+ LOG("%s driver %s (0x%llx) took %u ms\n",
+ (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
"PowerOff" : "Restart",
- service->getName(), OBFUSCATE(service),
+ service->getName(), service->getRegistryEntryID(),
(uint32_t) deltaTime );
+ halt_log_enter(
+ (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
+ OSMemberFunctionCast(const void *, service, &IOService::systemWillShutdown),
+ elapsedTime);
}
service->release();
{
me->timeout = true;
MSG("%s still waiting on %s\n",
- (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
+ (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
"PowerOff" : "Restart",
me->service->getName());
}
IOLockUnlock(me->lock);
}
-
//******************************************************************************
// acknowledgeSystemWillShutdown
//
//******************************************************************************
static void
-notifySystemShutdown( IOService * root, unsigned long event )
+notifySystemShutdown( IOService * root, uint32_t messageType )
{
#define PLACEHOLDER ((OSSet *)gPMHaltArray)
IORegistryIterator * iter;
void * baseFunc;
bool ok;
- DLOG("%s event = %lx\n", __FUNCTION__, event);
+ DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
if (!gPMHaltClientAcknowledgeKey) goto done;
}
- gPMHaltEvent = event;
+ gPMHaltMessageType = messageType;
// Depth-first walk of PM plane
if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
sizeof(kIOPMSleepWakeWdogRebootKey))) {
if (swd_flags & SWD_BOOT_BY_SW_WDOG)
- return OSBoolean::withBoolean(true);
+ return kOSBooleanTrue;
else
- return OSBoolean::withBoolean(false);
+ return kOSBooleanFalse;
}
if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
if (swd_flags & SWD_VALID_LOGS)
- return OSBoolean::withBoolean(true);
+ return kOSBooleanTrue;
else
- return OSBoolean::withBoolean(false);
+ return kOSBooleanFalse;
}
*/
if (!strcmp(aKey, "DesktopMode")) {
if (desktopMode)
- return OSBoolean::withBoolean(true);
+ return kOSBooleanTrue;
else
- return OSBoolean::withBoolean(false);
+ return kOSBooleanFalse;
}
if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
if (displayIdleForDemandSleep) {
- return OSBoolean::withBoolean(true);
+ return kOSBooleanTrue;
}
else {
- return OSBoolean::withBoolean(false);
+ return kOSBooleanFalse;
}
}
{
OSArray * array = 0;
WAKEEVENT_LOCK();
- if (_systemWakeEventsArray && _systemWakeEventsArray->getCount())
- array = OSArray::withArray(_systemWakeEventsArray);
+ if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
+ OSCollection *collection = _systemWakeEventsArray->copyCollection();
+ if (collection && !(array = OSDynamicCast(OSArray, collection))) {
+ collection->release();
+ }
+ }
WAKEEVENT_UNLOCK();
return array;
}
OSArray * array = 0;
IOLockLock(pmStatsLock);
if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
- array = OSArray::withArray(pmStatsAppResponses);
+ OSCollection *collection = pmStatsAppResponses->copyCollection();
+ if (collection && !(array = OSDynamicCast(OSArray, collection))) {
+ collection->release();
+ }
pmStatsAppResponses->flushCollection();
}
IOLockUnlock(pmStatsLock);
return array;
}
+ if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
+ {
+ OSArray *idleSleepList = NULL;
+ gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
+ return idleSleepList;
+ }
+
+ if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
+ {
+ OSArray *systemSleepList = NULL;
+ gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
+ return systemSleepList;
+ }
+
return NULL;
}
else
{
_acceptSystemWakeEvents = false;
+#if CONFIG_EMBEDDED
+ logWakeReason = gWakeReasonSysctlRegistered;
+#if DEVELOPMENT
+ static int panic_allowed = -1;
+
+ if ((panic_allowed == -1) &&
+ (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed, sizeof(panic_allowed)) == false)) {
+ panic_allowed = 1;
+ }
+
+ if (panic_allowed) {
+ size_t i = 0;
+ // Panic if wake reason is null or empty
+ for (i = 0; (i < strlen(gWakeReasonString)); i++) {
+ if ((gWakeReasonString[i] != ' ') && (gWakeReasonString[i] != '\t'))
+ break;
+ }
+ if (i >= strlen(gWakeReasonString)) {
+ panic("Wake reason is empty\n");
+ }
+ }
+#endif
+#endif
}
WAKEEVENT_UNLOCK();
// Lazy registration until the platform driver stops registering
// the same name.
gWakeReasonSysctlRegistered = true;
+#if CONFIG_EMBEDDED
+ sysctl_register_oid(&sysctl__kern_wakereason);
+#endif
}
if (_acceptSystemWakeEvents)
{
if ((swd_flags & SWD_WDOG_ENABLED) == 0)
return kIOReturnError;
- takeStackshot(true, true);
+ takeStackshot(true, true, false);
return kIOReturnSuccess;
}
void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
{
- takeStackshot(wdogTrigger, false);
+ takeStackshot(wdogTrigger, false, false);
}
-void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog)
+void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
{
swd_hdr * hdr = NULL;
addr64_t data[3];
- uint32_t wdog_panic = 0;
+ int wdog_panic = -1;
+ int stress_rack = -1;
int cnt = 0;
pid_t pid = 0;
+ kern_return_t kr = KERN_SUCCESS;
uint32_t flags;
char * dstAddr;
uint32_t size;
uint32_t bytesRemaining;
+ unsigned bytesWritten = 0;
+ unsigned totalBytes = 0;
unsigned int len;
OSString * UUIDstring = NULL;
uint64_t code;
IOMemoryMap * logBufMap = NULL;
- swd_stackshot_hdr *stackshotHdr = NULL;
- if ( kIOSleepWakeWdogOff & gIOKitDebug )
- return;
+
+ uint32_t bufSize;
+ uint32_t initialStackSize;
+
+ if (isSpinDump) {
+ if (_systemTransitionType != kSystemTransitionSleep &&
+ _systemTransitionType != kSystemTransitionWake)
+ return;
+ } else {
+ if ( kIOSleepWakeWdogOff & gIOKitDebug )
+ return;
+ }
if (wdogTrigger) {
- if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
- (wdog_panic == 1)) {
- // If boot-arg is set to panic on sleep/wake hang, call panic
- panic("Sleep/Wake hang detected\n");
+ PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic));
+ PE_parse_boot_argn("stress-rack", &stress_rack, sizeof(stress_rack));
+ if ((wdog_panic == 1) || (stress_rack == 1)) {
+ // If boot-arg specifies to panic then panic.
+ panic("Sleep/Wake hang detected");
return;
}
else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
// If current boot is due to this watch dog trigger restart in previous boot,
// then don't trigger again until at least 1 successful sleep & wake.
- sleepCnt = displayWakeCnt = 1;
- if (!(sleepCnt && displayWakeCnt)) {
+ if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
IOLog("Shutting down due to repeated Sleep/Wake failures\n");
+ if (!tasksSuspended) {
+ tasksSuspended = TRUE;
+ tasks_system_suspend(true);
+ }
PEHaltRestart(kPEHaltCPU);
return;
}
}
- if (sleepWakeDebugIsWdogEnabled() == false)
- return;
+ if (isSpinDump) {
+ if (gSpinDumpBufferFull)
+ return;
+ if (swd_spindump_buffer == NULL) {
+ sleepWakeDebugSpinDumpMemAlloc();
+ if (swd_spindump_buffer == NULL) return;
+ }
+
+ bufSize = SWD_SPINDUMP_SIZE;
+ initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
+ } else {
+ if (sleepWakeDebugIsWdogEnabled() == false)
+ return;
+
+ if (swd_buffer == NULL) {
+ sleepWakeDebugMemAlloc();
+ if (swd_buffer == NULL) return;
+ }
- if (swd_buffer == NULL) {
- sleepWakeDebugMemAlloc();
- if (swd_buffer == NULL) return;
+ bufSize = SWD_BUF_SIZE;
+ initialStackSize = SWD_INITIAL_STACK_SIZE;
}
if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
return;
+ if (isSpinDump) {
+ hdr = (swd_hdr *)swd_spindump_buffer;
+ }
+ else {
+ hdr = (swd_hdr *)swd_buffer;
+ }
- hdr = (swd_hdr *)swd_buffer;
memset(hdr->UUID, 0x20, sizeof(hdr->UUID));
if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
}
dstAddr = (char*)hdr + hdr->spindump_offset;
- bytesRemaining = SWD_BUF_SIZE - hdr->spindump_offset;
+ bytesRemaining = bufSize - hdr->spindump_offset;
/* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
hdr->is_osx_watchdog = isOSXWatchdog;
DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
- while (bytesRemaining > sizeof(swd_stackshot_hdr)) {
-
- stackshotHdr = (swd_stackshot_hdr *)dstAddr;
- stackshotHdr->magic = SWD_STACKSHOTHDR_MAGIC;
- stackshotHdr->size = 0;
- bytesRemaining -= sizeof(swd_stackshot_hdr);
- dstAddr += sizeof(swd_stackshot_hdr);
+ flags = STACKSHOT_KCDATA_FORMAT|STACKSHOT_NO_IO_STATS|STACKSHOT_SAVE_KEXT_LOADINFO;
+ while (kr == KERN_SUCCESS) {
- if (isOSXWatchdog) {
- pid = -1;
- size = bytesRemaining;
- flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
- }
- else if (cnt == 0) {
- /*
+ if (cnt == 0) {
+ /*
* Take stackshot of all process on first sample. Size is restricted
* to SWD_INITIAL_STACK_SIZE
*/
pid = -1;
- size = (bytesRemaining > SWD_INITIAL_STACK_SIZE) ? SWD_INITIAL_STACK_SIZE : bytesRemaining;
- flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY;
+ size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
+ flags |= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY;
}
else {
/* Take sample of kernel threads only */
pid = 0;
size = bytesRemaining;
- flags = 0;
}
- stack_snapshot_from_kernel(pid, dstAddr, size, flags, &stackshotHdr->size);
+ kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, &bytesWritten);
+ DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
+ kr, pid, size, flags, bytesWritten);
+ if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
+ if (pid == -1) {
+ // Insufficient buffer when trying to take stackshot of user & kernel space threads.
+ // Continue to take stackshot of just kernel threads
+ ++cnt;
+ kr = KERN_SUCCESS;
+ continue;
+ }
+ else if (totalBytes == 0) {
+ MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr, size, flags);
+ }
+ }
- dstAddr += stackshotHdr->size;
- bytesRemaining -= stackshotHdr->size;
+ dstAddr += bytesWritten;
+ totalBytes += bytesWritten;
+ bytesRemaining -= bytesWritten;
- DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt, stackshotHdr->size, bytesRemaining);
- if ((stackshotHdr->size == 0) || (++cnt == 10))
+ if (++cnt == 10) {
break;
+ }
IOSleep(10); // 10 ms
}
- hdr->spindump_size = (SWD_BUF_SIZE - bytesRemaining - hdr->spindump_offset);
+ hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
- memset(hdr->cps, 0x20, sizeof(hdr->cps));
- snprintf(hdr->cps, sizeof(hdr->cps), "\ncps: %d", ((IOService*)this)->getPowerState());
+ memset(hdr->spindump_status, 0x20, sizeof(hdr->spindump_status));
code = pmTracer->getPMStatusCode();
memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode));
snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x",
(uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
memset(hdr->reason, 0x20, sizeof(hdr->reason));
+ if (isSpinDump) {
+ snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: PSC Delay\n\n");
+ gRootDomain->swd_lock = 0;
+ gSpinDumpBufferFull = true;
+ return;
+ }
snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
gRootDomain->swd_lock = 0;
if (wdogTrigger) {
- IOLog("Restarting to collect Sleep wake debug logs\n");
- PEHaltRestart(kPERestartCPU);
+ IOLog("Restarting to collect Sleep wake debug logs\n");
+ if (!tasksSuspended) {
+ tasksSuspended = TRUE;
+ tasks_system_suspend(true);
+ }
+
+ PEHaltRestart(kPERestartCPU);
}
else {
logBufMap = sleepWakeDebugRetrieve();
hdr->spindump_offset = sizeof(swd_hdr);
swd_buffer = (void *)hdr;
+ swd_memDesc = memDesc;
DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
exit:
gRootDomain->swd_lock = 0;
}
+void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
+{
+ vm_size_t size = SWD_SPINDUMP_SIZE;
+
+ swd_hdr *hdr = NULL;
+
+ IOBufferMemoryDescriptor *memDesc = NULL;
+
+ if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+ return;
+
+ memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
+ kernel_task, kIODirectionIn|kIOMemoryMapperNone,
+ SWD_SPINDUMP_SIZE);
+
+ if (memDesc == NULL)
+ {
+ DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
+ goto exit;
+ }
+
+
+ hdr = (swd_hdr *)memDesc->getBytesNoCopy();
+ memset(hdr, 0, sizeof(swd_hdr));
+
+ hdr->signature = SWD_HDR_SIGNATURE;
+ hdr->alloc_size = size;
+
+ hdr->spindump_offset = sizeof(swd_hdr);
+ swd_spindump_buffer = (void *)hdr;
+
+exit:
+ gRootDomain->swd_lock = 0;
+}
+
void IOPMrootDomain::sleepWakeDebugEnableWdog()
{
swd_flags |= SWD_WDOG_ENABLED;
bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
{
return ((swd_flags & SWD_WDOG_ENABLED) &&
- !systemBooting && !systemShutdown);
+ !systemBooting && !systemShutdown && !gWillShutdown);
+}
+
+void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
+{
+ swd_hdr *hdr = NULL;
+ errno_t error = EIO;
+
+ if (swd_spindump_buffer && gSpinDumpBufferFull) {
+ hdr = (swd_hdr *)swd_spindump_buffer;
+
+ error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
+ (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
+
+ if (error) return;
+
+ sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
+ (char*)hdr+offsetof(swd_hdr, UUID),
+ sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
+
+ gSpinDumpBufferFull = false;
+ }
}
errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
{
IOLog("Failed to open the file %s\n", name);
+ swd_flags |= SWD_FILEOP_ERROR;
goto exit;
}
VATTR_INIT(&va);
if (vp->v_type != VREG ||
vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
IOLog("Bailing as this is not a regular file\n");
+ swd_flags |= SWD_FILEOP_ERROR;
goto exit;
}
VATTR_INIT(&va);
vnode_setattr(vp, &va, ctx);
- error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
- UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx));
- if (error != 0)
- IOLog("Failed to save sleep wake log. err 0x%x\n", error);
- else
- DLOG("Saved %d bytes to file %s\n",len, name);
+ if (buf != NULL) {
+ error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
+ UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx));
+ if (error != 0) {
+ IOLog("Failed to save sleep wake log. err 0x%x\n", error);
+ swd_flags |= SWD_FILEOP_ERROR;
+ }
+ else {
+ DLOG("Saved %d bytes to file %s\n",len, name);
+ }
+ }
exit:
if (vp) vnode_close(vp, FWRITE, ctx);
if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW),
S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
{
- DLOG("Failed to open the file %s\n", dstFname);
+ IOLog("Failed to open the file %s\n", dstFname);
+ swd_flags |= SWD_FILEOP_ERROR;
goto exit;
}
VATTR_INIT(&va);
/* Don't dump to non-regular files or files with links. */
if (vp->v_type != VREG ||
vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
- DLOG("Bailing as this is not a regular file\n");
+ IOLog("Bailing as this is not a regular file\n");
+ swd_flags |= SWD_FILEOP_ERROR;
goto exit;
}
VATTR_INIT(&va);
bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
readFileOffset = trunc_page(srcOffset);
- DLOG("Read file (numBytes:0x%llx)\n", bytesToRead);
+ DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead, readFileOffset);
error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
vfs_context_ucred(srcCtx), (int *) 0,
vfs_context_proc(srcCtx));
if (error) {
- DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
+ IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
+ swd_flags |= SWD_FILEOP_ERROR;
break;
}
if (crc) {
newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
}
+ DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite, writeFileOffset);
error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
vfs_context_ucred(ctx), (int *) 0,
vfs_context_proc(ctx));
if (error) {
- DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
+ IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
+ swd_flags |= SWD_FILEOP_ERROR;
break;
}
}
if (crc != newcrc) {
- swd_stackshot_hdr *shdr = (swd_stackshot_hdr *)tmpBuf;;
-
- /* Set statckshot size to 0 if crc doesn't match */
- shdr->magic = SWD_STACKSHOTHDR_MAGIC;
- shdr->size = 0;
+ /* Set stackshot size to 0 if crc doesn't match */
+ VATTR_INIT(&va);
+ VATTR_SET(&va, va_data_size, 0);
+ vnode_setattr(vp, &va, ctx);
- assert(tmpBufSize > sizeof(swd_stackshot_hdr));
- bytesToWrite = round_page(sizeof(swd_stackshot_hdr));
- vn_rdwr(UIO_WRITE, vp, (char *)tmpBuf, bytesToWrite, 0,
- UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
- vfs_context_ucred(ctx), (int *) 0,
- vfs_context_proc(ctx));
-
- DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
+ IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
+ swd_flags |= SWD_DATA_CRC_ERROR;
error = EFAULT;
}
exit:
if (vp) {
error = vnode_close(vp, FWRITE, ctx);
- DLOG("vnode_close returned 0x%x\n", error);
+ DLOG("vnode_close on file %s returned 0x%x\n",dstFname, error);
}
if (ctx) vfs_context_rele(ctx);
+}
+uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname, vfs_context_t *ctx,
+ void *tmpBuf, struct vnode **vp)
+{
+ int rc;
+ uint64_t hdrOffset;
+ uint32_t error = 0;
+
+ struct vnode_attr va;
+ IOHibernateImageHeader *imageHdr;
+
+ *vp = NULL;
+ if (vnode_open(fname, (FREAD | O_NOFOLLOW), 0,
+ VNODE_LOOKUP_NOFOLLOW, vp, *ctx) != 0)
+ {
+ DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname);
+ goto err;
+ }
+ VATTR_INIT(&va);
+ VATTR_WANTED(&va, va_nlink);
+ VATTR_WANTED(&va, va_data_alloc);
+ if ((*vp)->v_type != VREG ||
+ vnode_getattr((*vp), &va, *ctx) || va.va_nlink != 1) {
+ IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname);
+ error = SWD_FILEOP_ERROR;
+ goto err;
+ }
+
+ /* Read the sleepimage file header */
+ rc = vn_rdwr(UIO_READ, *vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
+ UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
+ vfs_context_ucred(*ctx), (int *) 0,
+ vfs_context_proc(*ctx));
+ if (rc != 0) {
+ IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %llu(rc=%d) from %s\n",
+ mach_vm_round_page(sizeof(IOHibernateImageHeader)), rc, fname);
+ error = SWD_FILEOP_ERROR;
+ goto err;
+ }
+
+ imageHdr = ((IOHibernateImageHeader *)tmpBuf);
+ if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
+ IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
+ fname, imageHdr->signature);
+ error = SWD_HDR_SIGNATURE_ERROR;
+ goto err;
+ }
+
+ /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
+ hdrOffset = imageHdr->deviceBlockSize;
+ if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
+ IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
+ va.va_data_alloc, fname);
+ error = SWD_HDR_SIZE_ERROR;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ if (*vp) vnode_close(*vp, FREAD, *ctx);
+ *vp = NULL;
+
+ return error;
}
void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
{
-
+#if HIBERNATION
int rc;
char hibernateFilename[MAXPATHLEN+1];
- char PMStatusCode[100];
void *tmpBuf;
swd_hdr *hdr = NULL;
uint32_t stacksSize, logSize;
OSNumber *failStat = NULL;
struct vnode *vp = NULL;
vfs_context_t ctx = NULL;
+ const char *stacksFname, *logFname;
- struct vnode_attr va;
IOBufferMemoryDescriptor *tmpBufDesc = NULL;
- IOHibernateImageHeader *imageHdr;
DLOG("sleepWakeDebugDumpFromFile\n");
if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
return;
- hibernateFilename[0] = 0;
- if ((obj = copyProperty(kIOHibernateFileKey)))
- {
- if ((str = OSDynamicCast(OSString, obj)))
- strlcpy(hibernateFilename, str->getCStringNoCopy(),
- sizeof(hibernateFilename));
- obj->release();
- }
- if (!hibernateFilename[0]) {
- DMSG("sleepWakeDebugDumpFromFile: Failed to hib file name\n");
- goto exit;
- }
- DLOG("sleepWakeDebugDumpFromFile: Hib file name %s\n", hibernateFilename);
-
/* Allocate a temp buffer to copy data between files */
tmpBufSize = 2*4096;
tmpBufDesc = IOBufferMemoryDescriptor::
tmpBuf = tmpBufDesc->getBytesNoCopy();
ctx = vfs_context_create(vfs_context_current());
- if (vnode_open(hibernateFilename, (FREAD | O_NOFOLLOW), 0,
- VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
- {
- DMSG("sleepWakeDebugDumpFromFile: Failed to open the hibernate file %s\n", hibernateFilename);
- goto exit;
- }
- VATTR_INIT(&va);
- VATTR_WANTED(&va, va_nlink);
- VATTR_WANTED(&va, va_data_alloc);
- if (vp->v_type != VREG ||
- vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
- DMSG("sleepWakeDebugDumpFromFile: Bailing as this is not a regular file\n");
- goto exit;
- }
- /* Read the sleepimage file header */
- rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
- UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
- vfs_context_ucred(ctx), (int *) 0,
- vfs_context_proc(ctx));
- if (rc != 0) {
- DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d)\n", round_page(sizeof(IOHibernateImageHeader)), rc);
- goto exit;
- }
+ /* First check if 'kSleepWakeStackBinFilename' has valid data */
+ swd_flags |= checkForValidDebugData(kSleepWakeStackBinFilename, &ctx, tmpBuf, &vp);
+ if (vp == NULL) {
+ /* Check if the debug data is saved to hibernation file */
+ hibernateFilename[0] = 0;
+ if ((obj = copyProperty(kIOHibernateFileKey)))
+ {
+ if ((str = OSDynamicCast(OSString, obj)))
+ strlcpy(hibernateFilename, str->getCStringNoCopy(),
+ sizeof(hibernateFilename));
+ obj->release();
+ }
+ if (!hibernateFilename[0]) {
+ DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
+ goto exit;
+ }
- imageHdr = ((IOHibernateImageHeader *)tmpBuf);
- if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
- DMSG("sleepWakeDebugDumpFromFile: File header has unexpected value 0x%x\n", imageHdr->signature);
- goto exit;
+ swd_flags |= checkForValidDebugData(hibernateFilename, &ctx, tmpBuf, &vp);
+ if (vp == NULL) {
+ DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
+ goto exit;
+ }
+ DLOG("Getting SW Stacks image from file %s\n", hibernateFilename);
}
-
- /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
- hdrOffset = imageHdr->deviceBlockSize;
- if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
- DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx)\n", va.va_data_alloc);
- goto exit;
+ else {
+ DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename);
}
- DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
+ hdrOffset = ((IOHibernateImageHeader *)tmpBuf)->deviceBlockSize;
+
+ DLOG("Reading swd_hdr len 0x%llx offset 0x%lx\n", mach_vm_round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
/* Read the sleep/wake debug header(swd_hdr) */
rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
vfs_context_ucred(ctx), (int *) 0,
vfs_context_proc(ctx));
if (rc != 0) {
- DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
- round_page(sizeof(swd_hdr)), rc);
+ DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %llu. rc=%d\n",
+ mach_vm_round_page(sizeof(swd_hdr)), rc);
+ swd_flags |= SWD_FILEOP_ERROR;
goto exit;
}
(hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
+ swd_flags |= SWD_BUF_SIZE_ERROR;
goto exit;
}
stacksSize = hdr->spindump_size;
stacksOffset = hdrOffset + hdr->spindump_offset;
logOffset = hdrOffset + offsetof(swd_hdr, UUID);
logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
+ stacksFname = getDumpStackFilename(hdr);
+ logFname = getDumpLogFilename(hdr);
error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
- getDumpStackFilename(hdr), stacksSize, hdr->crc);
+ stacksFname, stacksSize, hdr->crc);
if (error == EFAULT) {
DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
goto exit;
}
error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset,
- getDumpLogFilename(hdr), logSize, 0);
+ logFname, logSize, 0);
if (error) {
DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
goto exit;
// Write just the SleepWakeLog.dump with failure code
uint64_t fcode = 0;
const char *fname;
+ swd_hdr hdrCopy;
+ char *offset = NULL;
+ int size;
+
+ hdr = &hdrCopy;
if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
fcode = failStat->unsigned64BitValue();
else {
fname = kAppleOSXWatchdogLogFilename;
}
- memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
- PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
- snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
- sleepWakeDebugSaveFile(fname, PMStatusCode, sizeof(PMStatusCode));
+
+ offset = (char*)hdr+offsetof(swd_hdr, UUID);
+ size = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
+ memset(offset, 0x20, size); // Fill with spaces
+
+
+ snprintf(hdr->spindump_status, sizeof(hdr->spindump_status), "\nstatus: 0x%x", swd_flags);
+ snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: 0x%llx", fcode);
+ snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
+ sleepWakeDebugSaveFile(fname, offset, size);
+
}
gRootDomain->swd_lock = 0;
if (vp) vnode_close(vp, FREAD, ctx);
if (ctx) vfs_context_rele(ctx);
if (tmpBufDesc) tmpBufDesc->release();
-
+#endif /* HIBERNATION */
}
void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
errno_t error = EIO;
uint64_t bufSize = 0;
swd_hdr *hdr = NULL;
- char PMStatusCode[100];
OSNumber *failStat = NULL;
if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
bufSize = logBufMap->getLength();
if (bufSize <= sizeof(swd_hdr))
{
- IOLog("SleepWake log buffer contents are invalid\n");
+ IOLog("SleepWake log buffer size is invalid\n");
+ swd_flags |= SWD_BUF_SIZE_ERROR;
goto exit;
}
// Write just the SleepWakeLog.dump with failure code
uint64_t fcode = 0;
const char *sname, *lname;
- swd_stackshot_hdr shdr;
-
- /* Try writing an empty stacks file */
- shdr.magic = SWD_STACKSHOTHDR_MAGIC;
- shdr.size = 0;
-
+ swd_hdr hdrCopy;
+ /* Try writing an empty stacks file */
+ hdr = &hdrCopy;
if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
fcode = failStat->unsigned64BitValue();
sname= kAppleOSXWatchdogStackFilename;
}
- sleepWakeDebugSaveFile(sname, (char*)(&shdr), sizeof(shdr));
- memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
- PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
- snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
- sleepWakeDebugSaveFile(lname, PMStatusCode, sizeof(PMStatusCode));
+ sleepWakeDebugSaveFile(sname, NULL, 0);
+
+ logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
+ logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
+ memset(logOffset, 0x20, logSize); // Fill with spaces
+
+
+ snprintf(hdr->spindump_status, sizeof(hdr->spindump_status), "\nstatus: 0x%x", swd_flags);
+ snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: 0x%llx", fcode);
+ snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
+ sleepWakeDebugSaveFile(lname, logOffset, logSize);
}
+
gRootDomain->swd_lock = 0;
}
IOMemoryDescriptor * desc = NULL;
IOMemoryMap * logBufMap = NULL;
- uint32_t len;
+ uint32_t len = INT_MAX;
addr64_t data[3];
uint64_t bufSize = 0;
uint64_t crc = 0;
goto exit;
}
}
- else if (len == sizeof(addr64_t)*3)
+ else if (len == sizeof(addr64_t)*3) {
PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len);
+ }
else {
DLOG("Invalid sleepWakeDebug note length(%d)\n", len);
goto exit;
paddr = data[2];
if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
{
- IOLog("SleepWake log buffer contents are invalid\n");
+ IOLog("SleepWake log buffer size is invalid\n");
+ swd_flags |= SWD_BUF_SIZE_ERROR;
return NULL;
}
if (desc == NULL)
{
IOLog("Fail to map SleepWake log buffer\n");
+ swd_flags |= SWD_INTERNAL_FAILURE;
goto exit;
}
if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
IOLog("Fail to map SleepWake log buffer\n");
+ swd_flags |= SWD_INTERNAL_FAILURE;
goto exit;
}
hdr = (swd_hdr *)vaddr;
if (hdr->spindump_offset+hdr->spindump_size > bufSize)
{
- IOLog("SleepWake log buffer contents are invalid\n");
+ IOLog("SleepWake log header size is invalid\n");
+ swd_flags |= SWD_HDR_SIZE_ERROR;
goto exit;
}
hdr->spindump_size);
if (newcrc != crc) {
IOLog("SleepWake log buffer contents are invalid\n");
+ swd_flags |= SWD_DATA_CRC_ERROR;
goto exit;
}
void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
{
+ uint32_t wdog_panic = 1;
+
+ if (restart) {
+ if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
+ (wdog_panic == 0)) {
+ return;
+ }
+ panic("Sleep/Wake hang detected");
+ return;
+ }
}
-void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog)
+void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
{
#pragma unused(restart)
#pragma unused(isOSXWatchdog)