#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
#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)
#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"
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;
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
}
}
-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)
- {
- IOPMRootDomainWillShutdown();
+ startTime = mach_absolute_time();
+ IOPMRootDomainWillShutdown();
+ halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime);
#if HIBERNATION
- IOHibernateSystemPostWake();
+ startTime = mach_absolute_time();
+ IOHibernateSystemPostWake(true);
+ halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime);
+#endif
+ if (OSCompareAndSwap(0, 1, &gPagingOff))
+ {
+#if !CONFIG_EMBEDDED
+ gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
#endif
- if (OSCompareAndSwap(0, 1, &gPagingOff))
- {
- gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
- }
}
-
- 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
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
else
{
swdDebugTeardownCallout(p0, NULL);
- IOHibernateSystemPostWake();
+ IOHibernateSystemPostWake(false);
if (gRootDomain)
gRootDomain->sleepWakeDebugSaveSpinDumpFile();
}
//******************************************************************************
-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);
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 */
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(
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);
setProperty(key, b);
}
else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
+ key->isEqualTo(kIOPMDeepSleepTimerKey) ||
key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
key->isEqualTo(kIOPMAutoPowerOffTimerKey))
{
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",
((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,
clock_sec_t wakeSecs;
clock_usec_t wakeMicrosecs;
- clock_initialize_calendar();
+ clock_wakeup_calendar();
clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
gIOLastWakeTime.tv_sec = wakeSecs;
}
}
#else /* !__i386__ && !__x86_64__ */
- kdebugTrace(kPMLogSystemWake, 0, ml_get_wake_timebase() >> 32, ml_get_wake_timebase());
+ timeSinceReset = ml_get_time_since_reset();
+
+ kdebugTrace(kPMLogSystemWake, 0, timeSinceReset >> 32, timeSinceReset);
// stay awake for at least 30 seconds
wranglerTickled = true;
fullWakeReason = kFullWakeReasonLocalUser;
#if defined(__i386__) || defined(__x86_64__)
if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
{
+ DLOG("Cannot cancel idle sleep\n");
return false; // do not idle-cancel
}
#endif
- MSG("prevent idle sleep list: %s%c (%u)\n",
- service->getName(),
- (addNotRemove) ? '+' : '-', newCount);
return true;
}
+//******************************************************************************
+// startSpinDump
+//******************************************************************************
+
+void IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
+{
+ messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
+}
+
//******************************************************************************
// preventSystemSleepListUpdate
//
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 );
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
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 (standbyNixed || !standbyEnabled)
currentFactors |= kIOPMSleepFactorStandbyDisabled;
gSleepPolicyVars->sleepReason = lastSleepReason;
gSleepPolicyVars->sleepPhase = sleepPhase;
gSleepPolicyVars->standbyDelay = standbyDelay;
+ gSleepPolicyVars->standbyTimer = standbyTimer;
gSleepPolicyVars->poweroffDelay = powerOffDelay;
gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm;
gSleepPolicyVars->poweroffTimer = powerOffTimer;
wakeNow = false;
if (evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase2, &hibernateMode))
{
- if ((kIOPMSleepTypeStandby == params.sleepType) && gIOHibernateStandbyDisabled)
+ if ((kIOPMSleepTypeStandby == params.sleepType)
+ && gIOHibernateStandbyDisabled && gSleepPolicyVars
+ && (!(kIOPMSleepFactorStandbyForced & gSleepPolicyVars->sleepFactors)))
{
standbyNixed = true;
wakeNow = true;
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
{
IOPowerStateChangeNotification notify;
HaltRestartApplierContext * ctx;
- AbsoluteTime startTime;
+ 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))
{
LOG("%s handler %p took %u ms\n",
ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
+ halt_log_enter(ctx->LogString, (const void *) notifier->handler, elapsedTime);
}
}
void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
{
HaltRestartApplierContext ctx;
- AbsoluteTime startTime;
+ AbsoluteTime startTime, elapsedTime;
uint32_t deltaTime;
memset(&ctx, 0, sizeof(ctx));
}
}
IOLockUnlock(gPMHaltLock);
-
- deltaTime = computeDeltaTimeMS(&quiesceTime);
+ deltaTime = computeDeltaTimeMS(&quiesceTime, &elapsedTime);
DLOG("PM quiesce took %u ms\n", deltaTime);
+ halt_log_enter("Quiesce", NULL, elapsedTime);
}
- deltaTime = computeDeltaTimeMS(&startTime);
+ 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);
+ }
}
//******************************************************************************
clock_get_uptime(&ts_sleepStart);
DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
}
+
+ wranglerTickled = false;
}
}
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) {
darkWakePostTickle = false;
reportUserInput();
}
+ else if (wranglerTickled) {
+ requestFullWake( kFullWakeReasonLocalUser );
+ }
// Reset tracepoint at completion of capability change,
// completion of wake transition, and aborted sleep transition.
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();
}
}
+ 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;
}
// app has not replied yet, wait for it
*((OSObject **) arg3) = kOSBooleanFalse;
- if (notifier) {
- notifier->msgType = context->messageType;
- }
}
allow = true;
if (object == (OSObject *) systemCapabilityNotifier)
{
allow = true;
- if (notifier) {
- notifier->msgType = context->messageType;
- }
break;
}
if ((object == (OSObject *) systemCapabilityNotifier) &&
CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
(fullToDarkReason == kIOPMSleepReasonIdle)) {
- if (notifier) {
- notifier->msgType = context->messageType;
- }
allow = true;
}
break;
else
*((OSObject **) arg3) = kOSBooleanTrue;
}
-
- notifier->msgType = context->messageType;
}
}
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) )
{
return true;
}
+//******************************************************************************
+// mustHibernate
+//******************************************************************************
+
+#if HIBERNATION
+
+bool IOPMrootDomain::mustHibernate( void )
+{
+ return (lowBatteryCondition || thermalWarningState);
+}
+
+#endif /* HIBERNATION */
+
//******************************************************************************
// adjustPowerState
//
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();
[[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)
{
*/
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
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");
break;
case kStimulusLeaveUserActiveState:
+ DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
if (userIsActive)
{
userIsActive = false;
case kStimulusAggressivenessChanged:
{
+ DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
unsigned long minutesToIdleSleep = 0;
unsigned long minutesToDisplayDim = 0;
unsigned long minutesDelta = 0;
} 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;
}
}
+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
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;
if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
- kdebugTrace(kPMLogDrvResponseDelay, id, messageType, delay_ms);
+ kdebugTrace(kPMLogDrvPSChangeDelay, id, messageType, delay_ms);
}
else if (notify) {
- kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
+ // 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;
}
msgNum->release();
}
+ if (!name && notify && notify->identifier) {
+ name = notify->identifier->getCStringNoCopy();
+ }
+
if (name && (strlen(name) > 0))
{
appname = OSSymbol::withCString(name);
}
}
+ if (!id && notify) {
+ id = notify->uuid0;
+ }
if (id != 0) {
- pidNum = OSNumber::withNumber(id, 32);
+ pidNum = OSNumber::withNumber(id, 64);
if (pidNum) {
responseDescription->setObject(_statsPIDKey, pidNum);
pidNum->release();
pmTracer->tracePoint(point);
}
-void IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uintptr_t handler)
+void IOPMrootDomain::traceDetail(OSObject *object)
+{
+ 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);
+ }
+ }
+
+}
+
+
+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) {
- uint32_t detail = ((msgIndex & 0xff) << 24) |
- ((msgType & 0xfff) << 12) |
- (handler & 0xfff);
+ 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) {
+ uint32_t detail = ((msgType & 0xffff) << 16) | (delay & 0xffff);
pmTracer->traceDetail( detail );
- kdebugTrace(kPMLogSleepWakeTracePoint, 0, pmTracer->getTracePhase(), msgType, handler & 0xfff);
+ kdebugTrace(kPMLogSleepWakeTracePoint, pmTracer->getTracePhase(), msgType, delay);
+ DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
}
}
void PMTraceWorker::traceDetail(uint32_t detail)
{
-
+ if (detail == traceData32) {
+ return;
+ }
traceData32 = detail;
- DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
-
RTC_TRACE();
}
{
IOService * service;
OSSet * inner;
- AbsoluteTime startTime;
+ AbsoluteTime startTime, elapsedTime;
UInt32 deltaTime;
bool timeout;
IOLockUnlock(me->lock);
}
- deltaTime = computeDeltaTimeMS(&startTime);
+ deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
(gIOKitDebug & kIOLogPMRootDomain))
{
"PowerOff" : "Restart",
service->getName(), service->getRegistryEntryID(),
(uint32_t) deltaTime );
+ halt_log_enter(
+ (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
+ OSMemberFunctionCast(const void *, service, &IOService::systemWillShutdown),
+ elapsedTime);
}
service->release();
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)
{
swd_hdr * hdr = NULL;
addr64_t data[3];
int wdog_panic = -1;
+ int stress_rack = -1;
int cnt = 0;
pid_t pid = 0;
kern_return_t kr = KERN_SUCCESS;
if (wdogTrigger) {
PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic));
- if (wdog_panic == 1) {
+ 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\n");
+ panic("Sleep/Wake hang detected");
return;
}
else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
// then don't trigger again until at least 1 successful sleep & wake.
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;
}
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();
vfs_context_ucred(*ctx), (int *) 0,
vfs_context_proc(*ctx));
if (rc != 0) {
- IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
- round_page(sizeof(IOHibernateImageHeader)), rc, fname);
+ 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;
}
hdrOffset = ((IOHibernateImageHeader *)tmpBuf)->deviceBlockSize;
- DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
+ 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;
}
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;
(wdog_panic == 0)) {
return;
}
- panic("Sleep/Wake hang detected\n");
+ panic("Sleep/Wake hang detected");
return;
}
}