]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOPMrootDomain.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
index b4faa6330b2c054aec5742b99e1d7b7bb1c72296..4231fad39c5a9c75c5efba53b91c105ca4897cd4 100644 (file)
 #include <IOKit/IOReportMacros.h>
 #include <IOKit/IOLib.h>
 #include <IOKit/IOKitKeys.h>
+#include <IOKit/IOUserServer.h>
 #include "IOKitKernelInternal.h"
 #if HIBERNATION
 #include <IOKit/IOHibernatePrivate.h>
-#if __arm64__
-#include <arm64/ppl/ppl_hib.h>
-#endif /* __arm64__ */
 #endif /* HIBERNATION */
 #include <console/video_console.h>
 #include <sys/syslog.h>
@@ -522,8 +520,8 @@ static UInt32           gWillShutdown = 0;
 static UInt32           gPagingOff = 0;
 static UInt32           gSleepWakeUUIDIsSet = false;
 static uint32_t         gAggressivesState = 0;
-static uint32_t         gHaltTimeMaxLog;
-static uint32_t         gHaltTimeMaxPanic;
+uint32_t                gHaltTimeMaxLog;
+uint32_t                gHaltTimeMaxPanic;
 IOLock *                gHaltLogLock;
 static char *           gHaltLog;
 enum                  { kHaltLogSize = 2048 };
@@ -578,7 +576,6 @@ defaultSleepPolicyHandler(void *ctx, const IOPMSystemSleepPolicyVariables *vars,
 
        // Hibernation enabled and either user forced hibernate or low battery sleep
        if ((vars->hibernateMode & kIOHibernateModeOn) &&
-           ppl_hib_hibernation_supported() &&
            (((vars->hibernateMode & kIOHibernateModeSleep) == 0) ||
            (vars->sleepFactors & kIOPMSleepFactorBatteryLow))) {
                sleepType = kIOPMSleepTypeHibernate;
@@ -609,6 +606,7 @@ static char gShutdownReasonString[80];
 static bool gWakeReasonSysctlRegistered = false;
 static bool gBootReasonSysctlRegistered = false;
 static bool gShutdownReasonSysctlRegistered = false;
+static bool gWillShutdownSysctlRegistered = false;
 static AbsoluteTime gUserActiveAbsTime;
 static AbsoluteTime gUserInactiveAbsTime;
 
@@ -981,6 +979,18 @@ IOSystemShutdownNotification(int stage)
                return;
        }
 
+       if (kIOSystemShutdownNotificationTerminateDEXTs == stage) {
+               uint64_t nano, millis;
+               startTime = mach_absolute_time();
+               IOServicePH::systemHalt();
+               absolutetime_to_nanoseconds(mach_absolute_time() - startTime, &nano);
+               millis = nano / NSEC_PER_MSEC;
+               if (true || (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog))) {
+                       printf("IOServicePH::systemHalt took %qd ms\n", millis);
+               }
+               return;
+       }
+
        assert(kIOSystemShutdownNotificationStageProcessExit == stage);
 
        IOLockLock(gHaltLogLock);
@@ -1006,7 +1016,6 @@ IOSystemShutdownNotification(int stage)
        }
 }
 
-
 extern "C" int sync_internal(void);
 
 /*
@@ -1175,11 +1184,11 @@ sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
-    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
     &gIOLastUserSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
 
 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
-    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
     &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
 
 SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
@@ -1188,11 +1197,15 @@ SYSCTL_QUAD(_kern, OID_AUTO, useractive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &
 SYSCTL_QUAD(_kern, OID_AUTO, userinactive_abs_time, CTLFLAG_RD | CTLFLAG_LOCKED, &gUserInactiveAbsTime, "");
 
 static int
-sysctl_willshutdown
-(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
+sysctl_willshutdown SYSCTL_HANDLER_ARGS
 {
-       int new_value, changed;
-       int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
+       int new_value, changed, error;
+
+       if (!gWillShutdownSysctlRegistered) {
+               return ENOENT;
+       }
+
+       error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
        if (changed) {
                if (!gWillShutdown && (new_value == 1)) {
                        IOPMRootDomainWillShutdown();
@@ -1204,12 +1217,9 @@ sysctl_willshutdown
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_willshutdown, "I", "");
 
-extern struct sysctl_oid sysctl__kern_iokittest;
-extern struct sysctl_oid sysctl__debug_iokit;
-
 #if defined(XNU_TARGET_OS_OSX)
 
 static int
@@ -1245,11 +1255,11 @@ sysctl_progressmeter
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_progressmeterenable, "I", "");
 
 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_progressmeter, "I", "");
 
 #endif /* defined(XNU_TARGET_OS_OSX) */
@@ -1273,7 +1283,7 @@ sysctl_consoleoptions
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_consoleoptions, "I", "");
 
 
@@ -1284,7 +1294,7 @@ sysctl_progressoptions SYSCTL_HANDLER_ARGS
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
-    CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
+    CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
     NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
 
 
@@ -1294,20 +1304,32 @@ sysctl_wakereason SYSCTL_HANDLER_ARGS
        char wr[sizeof(gWakeReasonString)];
 
        wr[0] = '\0';
-       if (gRootDomain) {
+       if (gRootDomain && gWakeReasonSysctlRegistered) {
                gRootDomain->copyWakeReasonString(wr, sizeof(wr));
+       } else {
+               return ENOENT;
        }
 
        return sysctl_io_string(req, wr, 0, 0, NULL);
 }
 
 SYSCTL_PROC(_kern, OID_AUTO, wakereason,
-    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_wakereason, "A", "wakereason");
 
-SYSCTL_STRING(_kern, OID_AUTO, bootreason,
-    CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
-    gBootReasonString, sizeof(gBootReasonString), "");
+static int
+sysctl_bootreason SYSCTL_HANDLER_ARGS
+{
+       if (!os_atomic_load(&gBootReasonSysctlRegistered, acquire)) {
+               return ENOENT;
+       }
+
+       return sysctl_io_string(req, gBootReasonString, 0, 0, NULL);
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, bootreason,
+    CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    NULL, 0, sysctl_bootreason, "A", "");
 
 static int
 sysctl_shutdownreason SYSCTL_HANDLER_ARGS
@@ -1315,15 +1337,17 @@ sysctl_shutdownreason SYSCTL_HANDLER_ARGS
        char sr[sizeof(gShutdownReasonString)];
 
        sr[0] = '\0';
-       if (gRootDomain) {
+       if (gRootDomain && gShutdownReasonSysctlRegistered) {
                gRootDomain->copyShutdownReasonString(sr, sizeof(sr));
+       } else {
+               return ENOENT;
        }
 
        return sysctl_io_string(req, sr, 0, 0, NULL);
 }
 
 SYSCTL_PROC(_kern, OID_AUTO, shutdownreason,
-    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_shutdownreason, "A", "shutdownreason");
 
 static int
@@ -1345,7 +1369,7 @@ sysctl_targettype SYSCTL_HANDLER_ARGS
 }
 
 SYSCTL_PROC(_hw, OID_AUTO, targettype,
-    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_targettype, "A", "targettype");
 
 static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
@@ -1377,7 +1401,7 @@ sysctl_aotmetrics SYSCTL_HANDLER_ARGS
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, aotmetrics,
-    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
+    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
     NULL, 0, sysctl_aotmetrics, "S,IOPMAOTMetrics", "");
 
 
@@ -1426,7 +1450,7 @@ sysctl_aotmodebits
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, aotmodebits,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
     NULL, 0, sysctl_aotmodebits, "I", "");
 
 static int
@@ -1451,7 +1475,7 @@ sysctl_aotmode
 }
 
 static SYSCTL_PROC(_kern, OID_AUTO, aotmode,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
     NULL, 0, sysctl_aotmode, "I", "");
 
 //******************************************************************************
@@ -1752,30 +1776,10 @@ IOPMrootDomain::start( IOService * nub )
 
        // read swd_panic boot-arg
        PE_parse_boot_argn("swd_panic", &gSwdPanic, sizeof(gSwdPanic));
-       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 defined(XNU_TARGET_OS_OSX)
-       sysctl_register_oid(&sysctl__kern_progressmeterenable);
-       sysctl_register_oid(&sysctl__kern_progressmeter);
-       sysctl_register_oid(&sysctl__kern_wakereason);
-#endif /* defined(XNU_TARGET_OS_OSX) */
-       sysctl_register_oid(&sysctl__kern_consoleoptions);
-       sysctl_register_oid(&sysctl__kern_progressoptions);
-
-       sysctl_register_oid(&sysctl__kern_aotmode);
-       sysctl_register_oid(&sysctl__kern_aotmodebits);
-       sysctl_register_oid(&sysctl__kern_aotmetrics);
+       gWillShutdownSysctlRegistered = true;
 
 #if HIBERNATION
 #if defined(__arm64__)
-       if (ppl_hib_hibernation_supported()) {
-               publishFeature(kIOHibernateFeatureKey);
-       }
 #endif /* defined(__arm64__) */
        IOHibernateSystemInit(this);
 #endif
@@ -2978,6 +2982,9 @@ IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
                        // Until the platform driver can claim its wake reasons
                        strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
                            sizeof(gWakeReasonString));
+                       if (!gWakeReasonSysctlRegistered) {
+                               gWakeReasonSysctlRegistered = true;
+                       }
                        WAKEEVENT_UNLOCK();
                }
 
@@ -3067,6 +3074,15 @@ IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
                        isRTCAlarmWake = true;
                        fullWakeReason = kFullWakeReasonLocalUser;
                        requestUserActive(this, "RTC debug alarm");
+               } else {
+#if HIBERNATION
+                       OSSharedPtr<OSObject> hibOptionsProp = copyProperty(kIOHibernateOptionsKey);
+                       OSNumber * hibOptions = OSDynamicCast(OSNumber, hibOptionsProp.get());
+                       if (hibOptions && !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)) {
+                               fullWakeReason = kFullWakeReasonLocalUser;
+                               requestUserActive(this, "hibernate user wake");
+                       }
+#endif
                }
 
                // stay awake for at least 30 seconds
@@ -6000,6 +6016,27 @@ IOPMrootDomain::overrideOurPowerChange(
            _currentCapability, changeFlags,
            request->getTag());
 
+
+#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
+       /*
+        * ASBM send lowBattery notifications every 1 second until the device
+        * enters hibernation. This queues up multiple sleep requests.
+        * After the device wakes from hibernation, none of these previously
+        * queued sleep requests are valid.
+        * lowBattteryCondition variable is set when ASBM notifies rootDomain
+        * and is cleared at the very last point in sleep.
+        * Any attempt to sleep with reason kIOPMSleepReasonLowPower without
+        * lowBatteryCondition is invalid
+        */
+       if (REQUEST_TAG_TO_REASON(request->getTag()) == kIOPMSleepReasonLowPower) {
+               if (!lowBatteryCondition) {
+                       DLOG("Duplicate lowBattery sleep");
+                       *inOutChangeFlags |= kIOPMNotDone;
+                       return;
+               }
+       }
+#endif
+
        if ((AOT_STATE == desiredPowerState) && (ON_STATE == currentPowerState)) {
                // Assertion may have been taken in AOT leading to changePowerStateTo(AOT)
                *inOutChangeFlags |= kIOPMNotDone;
@@ -6013,15 +6050,6 @@ IOPMrootDomain::overrideOurPowerChange(
                return;
        }
 
-#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
-       if (lowBatteryCondition && (desiredPowerState < currentPowerState)) {
-               // Reject sleep requests when lowBatteryCondition is TRUE to
-               // avoid racing with the impending system shutdown.
-               *inOutChangeFlags |= kIOPMNotDone;
-               return;
-       }
-#endif
-
        if (desiredPowerState < currentPowerState) {
                if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) {
                        // Root domain is dropping power state from ON->SLEEP.
@@ -8154,23 +8182,9 @@ IOPMrootDomain::handlePowerNotification( UInt32 msg )
         * Power Emergency
         */
        if (msg & kIOPMPowerEmergency) {
-               DLOG("Low battery notification received\n");
-#if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
-               // Wait for the next low battery notification if the system state is
-               // in transition.
-               if ((_systemTransitionType == kSystemTransitionNone) &&
-                   CAP_CURRENT(kIOPMSystemCapabilityCPU) &&
-                   !systemBooting && !systemShutdown && !gWillShutdown) {
-                       // Setting lowBatteryCondition will prevent system sleep
-                       lowBatteryCondition = true;
-
-                       // Notify userspace to initiate system shutdown
-                       messageClients(kIOPMMessageRequestSystemShutdown);
-               }
-#else
+               DLOG("Received kIOPMPowerEmergency");
                lowBatteryCondition = true;
                privateSleepSystem(kIOPMSleepReasonLowPower);
-#endif
        }
 
        /*
@@ -10690,9 +10704,6 @@ IOPMrootDomain::claimSystemWakeEvent(
                // Lazy registration until the platform driver stops registering
                // the same name.
                gWakeReasonSysctlRegistered = true;
-#if !defined(XNU_TARGET_OS_OSX)
-               sysctl_register_oid(&sysctl__kern_wakereason);
-#endif /* !defined(XNU_TARGET_OS_OSX) */
        }
        if (addWakeReason) {
                _systemWakeEventsArray->setObject(dict.get());
@@ -10735,8 +10746,7 @@ IOPMrootDomain::claimSystemBootEvent(
        if (!gBootReasonSysctlRegistered) {
                // Lazy sysctl registration after setting gBootReasonString
                strlcat(gBootReasonString, reason, sizeof(gBootReasonString));
-               sysctl_register_oid(&sysctl__kern_bootreason);
-               gBootReasonSysctlRegistered = true;
+               os_atomic_store(&gBootReasonSysctlRegistered, true, release);
        }
        WAKEEVENT_UNLOCK();
 }
@@ -10765,10 +10775,7 @@ IOPMrootDomain::claimSystemShutdownEvent(
        }
        strlcat(gShutdownReasonString, reason, sizeof(gShutdownReasonString));
 
-       if (!gShutdownReasonSysctlRegistered) {
-               sysctl_register_oid(&sysctl__kern_shutdownreason);
-               gShutdownReasonSysctlRegistered = true;
-       }
+       gShutdownReasonSysctlRegistered = true;
        WAKEEVENT_UNLOCK();
 }