]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOPMrootDomain.cpp
xnu-4570.20.62.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
index ddce488072142902f1eb28fe8608eabd1fd64edb..3b778df403ad1329ed7fe1c9fdab5f65ee8c07e1 100644 (file)
@@ -47,6 +47,7 @@
 #include "IOPMPowerStateQueue.h"
 #include <IOKit/IOCatalogue.h>
 #include <IOKit/IOReportMacros.h>
+#include "IOKitKernelInternal.h"
 #if HIBERNATION
 #include <IOKit/IOHibernatePrivate.h>
 #endif
@@ -56,6 +57,8 @@
 #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
@@ -63,6 +66,7 @@
 
 __BEGIN_DECLS
 #include <mach/shared_region.h>
+#include <kern/clock.h>
 __END_DECLS
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -81,14 +85,23 @@ __END_DECLS
 #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)
 
@@ -169,10 +182,9 @@ IOReturn OSKextSystemSleepOrWake( UInt32 );
 }
 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);
 
@@ -184,21 +196,15 @@ static const OSSymbol *sleepMessagePEFunction   = NULL;
 #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)
 
@@ -312,10 +318,19 @@ 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;
+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
@@ -329,6 +344,21 @@ struct timeval gIOLastWakeTime;
 
 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
@@ -338,10 +368,10 @@ enum {
     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
@@ -357,7 +387,7 @@ class PMSettingHandle : public OSObject
 
 private:
     PMSettingObject *pmso;
-    void free(void);
+    void free(void) APPLE_KEXT_OVERRIDE;
 };
 
 /*
@@ -381,7 +411,7 @@ private:
     uint32_t                        settingCount;
     bool                            disabled;
 
-    void free(void);
+    void free(void) APPLE_KEXT_OVERRIDE;
 
 public:
     static PMSettingObject *pmSettingObject(
@@ -426,26 +456,28 @@ public:
     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;
 };
 
 /*
@@ -525,7 +557,7 @@ public:
     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 )
@@ -547,50 +579,115 @@ static void IOPMRootDomainWillShutdown(void)
     }
 }
 
-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
@@ -647,6 +744,94 @@ IOPMrootDomain * IOPMrootDomain::construct( void )
 }
 
 //******************************************************************************
+// 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 )
 {
@@ -659,11 +844,16 @@ 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
 
@@ -672,31 +862,18 @@ static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
 }
 
 //******************************************************************************
-
-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);
@@ -713,12 +890,12 @@ sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
   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);
@@ -733,6 +910,8 @@ static SYSCTL_PROC(_kern, OID_AUTO, waketime,
         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
@@ -753,6 +932,10 @@ static SYSCTL_PROC(_kern, OID_AUTO, 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
@@ -790,6 +973,39 @@ static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
         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
@@ -807,7 +1023,33 @@ SYSCTL_PROC(_kern, OID_AUTO, wakereason,
     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;
@@ -846,10 +1088,10 @@ bool IOPMrootDomain::start( IOService * nub )
     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");
@@ -877,6 +1119,9 @@ bool IOPMrootDomain::start( IOService * nub )
         };
 
     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);
@@ -886,6 +1131,7 @@ bool IOPMrootDomain::start( IOService * nub )
     featuresDictLock = IOLockAlloc();
     settingsCtrlLock = IOLockAlloc();
     wakeEventLock = IOLockAlloc();
+    gHaltLogLock = IOLockAlloc();
     setPMRootDomain(this);
 
     extraSleepTimer = thread_call_allocate(
@@ -895,8 +1141,14 @@ bool IOPMrootDomain::start( IOService * nub )
     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
@@ -916,6 +1168,7 @@ bool IOPMrootDomain::start( IOService * nub )
 
     userDisabledAllSleep = false;
     systemBooting = true;
+    idleSleepEnabled = false;
     sleepSlider = 0;
     idleSleepTimerPending = false;
     wrangler = NULL;
@@ -952,6 +1205,7 @@ bool IOPMrootDomain::start( IOService * nub )
     _statsResponseTypeKey   = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
     _statsMessageTypeKey    = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
     _statsPowerCapsKey      = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
+    assertOnWakeSecs        = -1;  // Invalid value to prevent updates
 
     pmStatsLock = IOLockAlloc();
     idxPMCPUClamshell = kCPUUnknownIndex;
@@ -980,16 +1234,14 @@ bool IOPMrootDomain::start( IOService * nub )
     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;
@@ -1047,7 +1299,10 @@ bool IOPMrootDomain::start( IOService * nub )
     // 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
@@ -1061,9 +1316,17 @@ bool IOPMrootDomain::start( IOService * nub )
     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);
@@ -1099,7 +1362,9 @@ IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
     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);
@@ -1180,10 +1445,29 @@ IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
             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)  ||
@@ -1194,6 +1478,7 @@ IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
                 setProperty(key, b);
         }
         else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
+                 key->isEqualTo(kIOPMDeepSleepTimerKey) ||
                  key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
                  key->isEqualTo(kIOPMAutoPowerOffTimerKey))
         {
@@ -1212,25 +1497,6 @@ IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
         // 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;
@@ -1281,7 +1547,9 @@ exit:
     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();
@@ -1753,7 +2021,7 @@ void IOPMrootDomain::broadcastAggressives(
                 if (!connect || !connect->getReadyFlag())
                     continue;
 
-                if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
+                if ((service = OSDynamicCast(IOService, connect->copyChildEntry(gIOPowerPlane))))
                 {
                     if (service->assertPMDriverCall(&callEntry))
                     {
@@ -1793,6 +2061,10 @@ void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
     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);
@@ -1819,6 +2091,18 @@ void IOPMrootDomain::cancelIdleSleepTimer( void )
         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, &microsecs);
+                if (assertOnWakeReport)  {
+                    HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+                    DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+                }
+        }
     }
 }
 
@@ -1842,9 +2126,9 @@ static void idleSleepTimerExpired(
 
 void IOPMrootDomain::handleSleepTimerExpiration( void )
 {
-    if (!getPMworkloop()->inGate())
+    if (!gIOPMWorkLoop->inGate())
     {
-        getPMworkloop()->runAction(
+        gIOPMWorkLoop->runAction(
             OSMemberFunctionCast(IOWorkLoop::Action, this,
                 &IOPMrootDomain::handleSleepTimerExpiration),
             this);
@@ -1859,13 +2143,6 @@ void IOPMrootDomain::handleSleepTimerExpiration( void )
     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);
 }
@@ -1886,7 +2163,7 @@ uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
     uint32_t        minutesSinceUserInactive = 0;
     uint32_t         sleepDelay = 0;
 
-    if (sleepSlider == 0)
+    if (!idleSleepEnabled)
         return 0xffffffff;
 
     if (userActivityTime)
@@ -2007,6 +2284,10 @@ IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
 
 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());
@@ -2024,13 +2305,28 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
 
             clock_sec_t     secs;
             clock_usec_t    microsecs;
-            clock_get_calendar_microtime(&secs, &microsecs);
+            clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &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, &microsecs);
+                absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, &microsecs);
+                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" : "");
 
@@ -2040,14 +2336,39 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
 #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, &microsecs);
+
+                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
@@ -2058,27 +2379,30 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
             // 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;
@@ -2111,9 +2435,9 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
             }
             else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
             {
+#if HIBERNATION
                 OSNumber * hibOptions = OSDynamicCast(
                     OSNumber, getProperty(kIOHibernateOptionsKey));
-
                 if (hibernateAborted || ((hibOptions &&
                     !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
                 {
@@ -2124,6 +2448,7 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
                         hibOptions ? hibOptions->unsigned32BitValue() : 0);
                 }
                 else
+#endif
                 if (wakeType && (
                     wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
                     wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
@@ -2158,9 +2483,11 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
                 {
                     darkWakeMaintenance = true;
                     darkWakeSleepService = true;
+#if HIBERNATION
                     if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
                         sleepToStandby = true;
                     }
+#endif
                 }
                 else
                 if (wakeType &&
@@ -2206,6 +2533,10 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
                 fullWakeReason = kFullWakeReasonLocalUser;
                 reportUserInput();
             }
+            else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
+            {
+                handleDisplayPowerOn();
+            }
             else if (!darkWakeMaintenance)
             {
                 // Early/late tickle for non-maintenance wake.
@@ -2218,6 +2549,9 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
                 }
             }
 #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;
@@ -2225,8 +2559,24 @@ void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
 #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
 
     }
 }
@@ -2248,6 +2598,7 @@ IOReturn IOPMrootDomain::requestPowerDomainState (
     return super::requestPowerDomainState(0, childConnection, specification);
 }
 
+
 //******************************************************************************
 // updatePreventIdleSleepList
 //
@@ -2303,10 +2654,13 @@ bool IOPMrootDomain::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
@@ -2314,6 +2668,15 @@ bool IOPMrootDomain::updatePreventIdleSleepList(
     return true;
 }
 
+//******************************************************************************
+// startSpinDump
+//******************************************************************************
+
+void IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
+{
+    messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
+}
+
 //******************************************************************************
 // preventSystemSleepListUpdate
 //
@@ -2323,7 +2686,7 @@ bool IOPMrootDomain::updatePreventIdleSleepList(
 void IOPMrootDomain::updatePreventSystemSleepList(
         IOService * service, bool addNotRemove )
 {
-    unsigned int oldCount;
+    unsigned int oldCount, newCount;
 
     ASSERT_GATED();
     if (this == service)
@@ -2335,6 +2698,17 @@ void IOPMrootDomain::updatePreventSystemSleepList(
         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, &microsecs);
+                if (assertOnWakeReport)  {
+                    HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
+                    DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
+                }
+        }
     }
     else if (preventSystemSleepList->member(service))
     {
@@ -2349,43 +2723,101 @@ void IOPMrootDomain::updatePreventSystemSleepList(
             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 );
@@ -2467,9 +2899,12 @@ void IOPMrootDomain::askChangeDownDone(
 
 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);
@@ -2477,7 +2912,7 @@ void IOPMrootDomain::systemDidNotSleep( void )
     }
     else
     {
-        if (sleepSlider && !userIsActive)
+        if (idleSleepEnabled && !userIsActive)
         {
             // Manually start the idle sleep timer besides waiting for
             // the user to become inactive.
@@ -2487,6 +2922,30 @@ void IOPMrootDomain::systemDidNotSleep( void )
 
     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(&params, 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,
+            &params, sizeof(params));
+    }
 }
 
 //******************************************************************************
@@ -2524,7 +2983,6 @@ void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
 
 void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
 {
-
     DLOG("tellChangeUp %u->%u\n",
         (uint32_t) getPowerState(), (uint32_t) stateNum);
 
@@ -2549,12 +3007,31 @@ void IOPMrootDomain::tellChangeUp( unsigned long 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
 //
@@ -2576,18 +3053,13 @@ IOReturn IOPMrootDomain::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)
@@ -2606,12 +3078,14 @@ IOReturn IOPMrootDomain::sysPowerDownHandler(
             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();
 
@@ -2648,20 +3122,36 @@ IOReturn IOPMrootDomain::sysPowerDownHandler(
                     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;
     }
 
@@ -2844,13 +3334,41 @@ hibernate_should_abort(void)
 
 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();
+        }
+
+    }
 }
 
 //******************************************************************************
@@ -3252,7 +3770,7 @@ IOReturn IOPMrootDomain::setPMSetting(
     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;
 
@@ -3405,7 +3923,7 @@ IOReturn IOPMrootDomain::registerPMSettingController(
     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);
@@ -3470,7 +3988,7 @@ void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
     {
         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);
@@ -3522,9 +4040,9 @@ void IOPMrootDomain::informCPUStateChange(
     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 );
@@ -3618,6 +4136,7 @@ bool IOPMrootDomain::evaluateSystemSleepPolicy(
     uint32_t    standbyDelay   = 0;
     uint32_t    powerOffDelay  = 0;
     uint32_t    powerOffTimer  = 0;
+    uint32_t    standbyTimer  = 0;
     uint32_t    mismatch;
     bool        standbyEnabled;
     bool        powerOffEnabled;
@@ -3637,9 +4156,11 @@ bool IOPMrootDomain::evaluateSystemSleepPolicy(
         && (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
@@ -3675,10 +4196,15 @@ bool IOPMrootDomain::evaluateSystemSleepPolicy(
         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;
@@ -3710,6 +4236,8 @@ bool IOPMrootDomain::evaluateSystemSleepPolicy(
         currentFactors |= kIOPMSleepFactorLocalUserActivity;
     if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
         currentFactors |= kIOPMSleepFactorHibernateFailed;
+    if (thermalWarningState)
+        currentFactors |= kIOPMSleepFactorThermalWarning;
 
     DLOG("sleep factors 0x%llx\n", currentFactors);
 
@@ -3733,6 +4261,7 @@ bool IOPMrootDomain::evaluateSystemSleepPolicy(
         gSleepPolicyVars->sleepReason       = lastSleepReason;
         gSleepPolicyVars->sleepPhase        = sleepPhase;
         gSleepPolicyVars->standbyDelay      = standbyDelay;
+        gSleepPolicyVars->standbyTimer      = standbyTimer;
         gSleepPolicyVars->poweroffDelay     = powerOffDelay;
         gSleepPolicyVars->scheduledAlarms   = _scheduledAlarms | _userScheduledAlarm;
         gSleepPolicyVars->poweroffTimer     = powerOffTimer;
@@ -3921,36 +4450,56 @@ void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
 {
     IOPMSystemSleepParameters   params;
     OSData *                    paramsData;
-
+    bool                        wakeNow;
     // Evaluate sleep policy after sleeping drivers but before platform sleep.
 
     DLOG("%s\n", __FUNCTION__);
 
     bzero(&params, sizeof(params));
+    wakeNow = false;
     if (evaluateSystemSleepPolicy(&params, 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, &params, 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(&params, sizeof(params));
         if (paramsData)
         {
@@ -4006,10 +4555,18 @@ bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
     {
         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)
@@ -4017,11 +4574,11 @@ bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
     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;
@@ -4034,7 +4591,7 @@ IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
                         OSMemberFunctionCast(IOWorkLoop::Action, this,
                             &IOPMrootDomain::getSystemSleepType),
                         (OSObject *) this,
-                        (void *) sleepType);
+                        (void *) sleepType, (void *) standbyTimer);
         return ret;
     }
 
@@ -4045,6 +4602,11 @@ IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
     if (ok)
     {
         *sleepType = params.sleepType;
+        if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer)  &&
+                !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
+            DLOG("Standby delay is not set\n");
+            *standbyTimer = 0;
+        }
         return kIOReturnSuccess;
     }
 #endif
@@ -4066,6 +4628,7 @@ struct HaltRestartApplierContext {
     IOPMPowerFlags      PowerFlags;
     UInt32              MessageType;
     UInt32              Counter;
+    const char *        LogString;
 };
 
 static void
@@ -4073,8 +4636,8 @@ platformHaltRestartApplier( OSObject * object, void * context )
 {
     IOPowerStateChangeNotification  notify;
     HaltRestartApplierContext *     ctx;
-    AbsoluteTime                    startTime;
-    UInt32                          deltaTime;
+    AbsoluteTime                    startTime, elapsedTime;
+    uint32_t                        deltaTime;
 
     ctx = (HaltRestartApplierContext *) context;
 
@@ -4086,7 +4649,7 @@ platformHaltRestartApplier( OSObject * object, void * context )
 
     clock_get_uptime(&startTime);
     ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
-    deltaTime = computeDeltaTimeMS(&startTime);
+    deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
 
     if ((deltaTime > kPMHaltTimeoutMS) ||
         (gIOKitDebug & kIOLogPMRootDomain))
@@ -4100,20 +4663,27 @@ platformHaltRestartApplier( OSObject * object, void * context )
         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;
@@ -4125,16 +4695,19 @@ void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
         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();
@@ -4169,11 +4742,44 @@ void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
 
     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);
+    }
 }
 
 //******************************************************************************
@@ -4425,6 +5031,7 @@ void IOPMrootDomain::handleOurPowerChangeStart(
     _systemTransitionType    = kSystemTransitionNone;
     _systemMessageClientMask = 0;
     capabilityLoss           = false;
+    toldPowerdCapWillChange  = false;
 
     if (lowBatteryCondition)
     {
@@ -4483,15 +5090,6 @@ void IOPMrootDomain::handleOurPowerChangeStart(
         _pendingCapability = 0;
         capabilityLoss = true;
 
-        // Clear previous stats
-        IOLockLock(pmStatsLock);
-        if (pmStatsAppResponses)
-        {
-            pmStatsAppResponses->release();
-            pmStatsAppResponses = OSArray::withCapacity(5);
-        }
-        IOLockUnlock(pmStatsLock);
-
     }
     else if (kSystemTransitionNewCapClient != _systemTransitionType)
     {
@@ -4529,6 +5127,16 @@ void IOPMrootDomain::handleOurPowerChangeStart(
         // 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 |
@@ -4548,6 +5156,12 @@ void IOPMrootDomain::handleOurPowerChangeStart(
 
             // 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;
         }
     }
 
@@ -4557,19 +5171,26 @@ void IOPMrootDomain::handleOurPowerChangeStart(
     {
         // 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.
@@ -4660,10 +5281,20 @@ void IOPMrootDomain::handleOurPowerChangeDone(
             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.
@@ -4685,8 +5316,14 @@ void IOPMrootDomain::handleOurPowerChangeDone(
                 {
                     // 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;
+                    }
                 }
             }
 
@@ -4770,6 +5407,9 @@ void IOPMrootDomain::handleOurPowerChangeDone(
             darkWakePostTickle = false;
             reportUserInput();
         }
+        else if (wranglerTickled) {
+            requestFullWake( kFullWakeReasonLocalUser );
+        }
 
         // Reset tracepoint at completion of capability change,
         // completion of wake transition, and aborted sleep transition.
@@ -4780,13 +5420,24 @@ void IOPMrootDomain::handleOurPowerChangeDone(
              (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();
+        }
+
     }
 }
 
@@ -4923,7 +5574,7 @@ void IOPMrootDomain::overridePowerChangeForUIService(
                 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",
@@ -4947,7 +5598,8 @@ void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
 
     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",
@@ -5015,6 +5667,13 @@ void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
             evaluatePolicy( kStimulusLeaveUserActiveState );
         }
     }
+
+    if (newPowerState <= kWranglerPowerStateSleep) {
+        evaluatePolicy( kStimulusDisplayWranglerSleep );
+    }
+    else if (newPowerState == kWranglerPowerStateMax) {
+        evaluatePolicy( kStimulusDisplayWranglerWake );
+    }
 #endif
 }
 
@@ -5102,7 +5761,11 @@ class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
 
 protected:
     uint32_t    ackTimeoutCnt;
+    uint32_t    msgType;  // Message pending ack
 
+    uint64_t    uuid0;
+    uint64_t    uuid1;
+    const OSSymbol    *identifier;
 };
 
 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
@@ -5132,11 +5795,13 @@ IONotifier * IOPMrootDomain::registerInterest(
     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)
     {
@@ -5158,6 +5823,28 @@ IONotifier * IOPMrootDomain::registerInterest(
         }
     }
 
+    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;
 }
 
@@ -5173,7 +5860,9 @@ bool IOPMrootDomain::systemMessageFilter(
     bool  isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
     bool  isCapClient = false;
     bool  allow = false;
+    IOPMServiceInterestNotifier *notifier;
 
+    notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
     do {
         if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
             (!isCapMsg || !_joinedCapabilityClients ||
@@ -5213,6 +5902,12 @@ bool IOPMrootDomain::systemMessageFilter(
                     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.
@@ -5225,6 +5920,7 @@ bool IOPMrootDomain::systemMessageFilter(
             {
                 // app has not replied yet, wait for it
                 *((OSObject **) arg3) = kOSBooleanFalse;
+
             }
 
             allow = true;
@@ -5256,8 +5952,9 @@ bool IOPMrootDomain::systemMessageFilter(
         {
             if ((object == (OSObject *) systemCapabilityNotifier) &&
                 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
-                (fullToDarkReason == kIOPMSleepReasonIdle))
+                (fullToDarkReason == kIOPMSleepReasonIdle)) {
                 allow = true;
+            }
             break;
         }
 
@@ -5274,16 +5971,15 @@ bool IOPMrootDomain::systemMessageFilter(
         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) &&
@@ -5305,6 +6001,9 @@ bool IOPMrootDomain::systemMessageFilter(
             _joinedCapabilityClients = 0;
         }
     }
+    if (notifier) {
+        notifier->msgType = context->messageType;
+    }
 
     return allow;
 }
@@ -5425,7 +6124,9 @@ bool IOPMrootDomain::displayWranglerMatchPublished(
     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) )
     {
@@ -5488,13 +6189,16 @@ void IOPMrootDomain::reportUserInput( void )
 {
 #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();
         }
     }
@@ -5550,11 +6254,8 @@ bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
 
 void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
 {
-    if (checkSystemCanSustainFullWake())
-    {
-        pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
-                                             (void *) 0, options );
-    }
+    pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
+                                         (void *) 0, options );
 }
 
 // MARK: -
@@ -5622,9 +6323,9 @@ bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
         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)
@@ -5698,7 +6399,7 @@ bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
 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
@@ -5722,6 +6423,19 @@ bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
     return true;
 }
 
+//******************************************************************************
+// mustHibernate
+//******************************************************************************
+
+#if HIBERNATION
+
+bool IOPMrootDomain::mustHibernate( void )
+{
+    return (lowBatteryCondition || thermalWarningState);
+}
+
+#endif /* HIBERNATION */
+
 //******************************************************************************
 // adjustPowerState
 //
@@ -5734,12 +6448,12 @@ bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
 
 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);
     }
@@ -5749,6 +6463,41 @@ void IOPMrootDomain::adjustPowerState( bool sleepASAP )
     }
 }
 
+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
 //
@@ -5758,20 +6507,22 @@ void IOPMrootDomain::adjustPowerState( bool sleepASAP )
 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;
@@ -5811,6 +6562,7 @@ void IOPMrootDomain::dispatchPowerEvent(
             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
@@ -5825,18 +6577,20 @@ void IOPMrootDomain::dispatchPowerEvent(
                 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();
@@ -5848,8 +6602,10 @@ void IOPMrootDomain::dispatchPowerEvent(
                 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)
@@ -5865,6 +6621,7 @@ void IOPMrootDomain::dispatchPowerEvent(
             break;
 
         case kPowerEventPolicyStimulus:
+            DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
             if (arg0)
             {
                 int stimulus = (uintptr_t) arg0;
@@ -5873,6 +6630,7 @@ void IOPMrootDomain::dispatchPowerEvent(
             break;
 
         case kPowerEventAssertionCreate:
+            DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
             if (pmAssertions) {
                 pmAssertions->handleCreateAssertion((OSData *)arg0);
             }
@@ -5880,52 +6638,40 @@ void IOPMrootDomain::dispatchPowerEvent(
 
 
         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;
     }
 }
@@ -5962,6 +6708,24 @@ IOReturn IOPMrootDomain::systemPowerEventOccurred(
     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)
@@ -6001,8 +6765,13 @@ exit:
     // UNLOCK
     if (featuresDictLock) IOLockUnlock(featuresDictLock);
 
-    if (shouldUpdate)
+    if (shouldUpdate) {
+        if (event && 
+             event->isEqualTo(kIOPMThermalLevelWarningKey)) {
+             setThermalState(value);
+        }
         messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
+    }
 
     return kIOReturnSuccess;
 }
@@ -6046,15 +6815,13 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
     }
 
     /*
-     * 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);
-
     }
 
     /*
@@ -6079,6 +6846,7 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
      */
     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;
@@ -6110,6 +6878,7 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
      */
     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;
@@ -6132,6 +6901,7 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
      */
     if (msg & kIOPMSetDesktopMode)
     {
+        DLOG("Desktop mode\n");
         desktopMode = (0 != (msg & kIOPMSetValue));
         msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
 
@@ -6185,6 +6955,7 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
      */
     if (msg & kIOPMEnableClamshell)
     {
+        DLOG("Clamshell enabled\n");
         // Re-evaluate the lid state
         // System should sleep on external display disappearance
         // in lid closed operation.
@@ -6204,6 +6975,7 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
      */
     if (msg & kIOPMDisableClamshell)
     {
+        DLOG("Clamshell disabled\n");
         clamshellDisabled = true;
         sendClientClamshellNotification();
     }
@@ -6224,6 +6996,7 @@ void IOPMrootDomain::handlePowerNotification( UInt32 msg )
      */
     if (msg & kIOPMPowerButton)
     {
+        DLOG("Powerbutton press\n");
         if (!wranglerAsleep)
         {
             OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
@@ -6259,7 +7032,6 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         uint32_t u32;
     } flags;
 
-    DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
 
     ASSERT_GATED();
     flags.u32 = 0;
@@ -6267,20 +7039,22 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
     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");
@@ -6292,9 +7066,13 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
                 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);
             }
@@ -6302,12 +7080,14 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             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);
             }
@@ -6315,6 +7095,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
 
         case kStimulusAggressivenessChanged:
         {
+            DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
             unsigned long   minutesToIdleSleep  = 0;
             unsigned long   minutesToDisplayDim = 0;
             unsigned long   minutesDelta        = 0;
@@ -6330,8 +7111,6 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             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'.
@@ -6341,11 +7120,15 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             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)) &&
@@ -6365,6 +7148,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         }   break;
 
         case kStimulusDemandSystemSleep:
+            DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
             displayIdleForDemandSleep = true;
             if (wrangler && wranglerIdleSettings)
             {
@@ -6381,10 +7165,12 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             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
@@ -6408,6 +7194,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
 
         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.
 
@@ -6424,6 +7211,10 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
                 {
                     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,
@@ -6435,6 +7226,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             break;
 
         case kStimulusDarkWakeEvaluate:
+            DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
             if (systemDarkWake)
             {
                 flags.bit.evaluateDarkWake = true;
@@ -6442,6 +7234,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             break;
 
         case kStimulusNoIdleSleepPreventers:
+            DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
             flags.bit.adjustPowerState = true;
             break;
 
@@ -6503,6 +7296,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         (kFullWakeReasonDisplayOn == fullWakeReason))
     {
         // kIOPMSleepReasonMaintenance?
+        DLOG("Display sleep while in notification wake\n");
         changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
     }
 
@@ -6525,7 +7319,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             DLOG("user inactive\n");
         }
 
-        if (!userIsActive && sleepSlider)
+        if (!userIsActive && idleSleepEnabled)
         {
             startIdleSleepTimer(getTimeToIdleSleep());
         }
@@ -6540,10 +7334,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
         if (!wrangler)
         {
             changePowerStateToPriv(ON_STATE);
-            if (idleSeconds)
-            {
-                startIdleSleepTimer( idleSeconds );
-            }
+            startIdleSleepTimer( idleSeconds );
         }
         else
         {
@@ -6575,7 +7366,7 @@ void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
             if (!wrangler)
             {
                 changePowerStateToPriv(ON_STATE);
-                if (idleSeconds)
+                if (idleSleepEnabled)
                 {
                     // stay awake for at least idleSeconds
                     startIdleSleepTimer(idleSeconds);
@@ -6667,7 +7458,7 @@ void IOPMrootDomain::requestFullWake( FullWakeReason reason )
         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",
@@ -6689,6 +7480,8 @@ void IOPMrootDomain::willEnterFullWake( void )
 {
     hibernateRetry = false;
     sleepToStandby = false;
+    standbyNixed   = false;
+    resetTimers    = false;
     sleepTimerMaintenance = false;
 
     _systemMessageClientMask = kSystemMessageClientPowerd |
@@ -6751,8 +7544,20 @@ void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, I
         }
     }
 
-    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, &microsecs);
+                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;
@@ -6767,6 +7572,22 @@ void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, I
     }
 }
 
+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
 
@@ -6829,7 +7650,7 @@ void IOPMrootDomain::pmStatsRecordApplicationResponse(
     const char          *name,
     int                 messageType,
     uint32_t            delay_ms,
-    int                 app_pid,
+    uint64_t            id,
     OSObject            *object,
     IOPMPowerStateIndex powerState)
 {
@@ -6844,23 +7665,37 @@ void IOPMrootDomain::pmStatsRecordApplicationResponse(
 
     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);
@@ -6869,6 +7704,10 @@ void IOPMrootDomain::pmStatsRecordApplicationResponse(
             msgNum->release();
         }
 
+        if (!name && notify && notify->identifier) {
+            name = notify->identifier->getCStringNoCopy();
+        }
+
         if (name && (strlen(name) > 0))
         {
             appname = OSSymbol::withCString(name);
@@ -6878,8 +7717,11 @@ void IOPMrootDomain::pmStatsRecordApplicationResponse(
             }
         }
 
-        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();
@@ -6895,7 +7737,7 @@ void IOPMrootDomain::pmStatsRecordApplicationResponse(
         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);
@@ -6958,6 +7800,8 @@ IOReturn IOPMrootDomain::callPlatformFunction(
     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)
@@ -6969,9 +7813,15 @@ IOReturn IOPMrootDomain::callPlatformFunction(
         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);
         }
@@ -6999,6 +7849,18 @@ IOReturn IOPMrootDomain::callPlatformFunction(
         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;
@@ -7006,45 +7868,196 @@ void IOPMrootDomain::tracePoint( uint8_t point )
     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,
@@ -7063,7 +8076,15 @@ IOReturn IOPMrootDomain::updateReport(IOReportChannelList      *channelList,
     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);
         }
@@ -7115,10 +8136,12 @@ PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
     // 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;
 }
 
@@ -7128,8 +8151,10 @@ void PMTraceWorker::RTC_TRACE(void)
     {
         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);
@@ -7141,7 +8166,7 @@ int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
     const OSSymbol *    deviceName;
     int                 index = -1;
 
-    IOLockLock(pciMappingLock);
+    IOLockLock(pmTraceWorkerLock);
 
     if (!pciDeviceBitMappings)
     {
@@ -7168,7 +8193,7 @@ int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
         addedToRegistry = owner->setProperty("PCITopLevel", this);
 
 exit:
-    IOLockUnlock(pciMappingLock);
+    IOLockUnlock(pmTraceWorkerLock);
     return index;
 }
 
@@ -7177,9 +8202,9 @@ bool PMTraceWorker::serialize(OSSerialize *s) const
     bool ok = false;
     if (pciDeviceBitMappings)
     {
-        IOLockLock(pciMappingLock);
+        IOLockLock(pmTraceWorkerLock);
         ok = pciDeviceBitMappings->serialize(s);
-        IOLockUnlock(pciMappingLock);
+        IOLockUnlock(pmTraceWorkerLock);
     }
     return ok;
 }
@@ -7196,35 +8221,32 @@ void PMTraceWorker::tracePoint(uint8_t phase)
     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();
 }
 
@@ -7257,12 +8279,14 @@ void PMTraceWorker::tracePCIPowerChange(
             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);
@@ -7272,11 +8296,20 @@ void PMTraceWorker::tracePCIPowerChange(
 
 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
 
@@ -7285,14 +8318,6 @@ uint64_t  PMTraceWorker::getPMStatusCode( )
 //
 //******************************************************************************
 
-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;
@@ -7379,7 +8404,7 @@ void PMHaltWorker::work( PMHaltWorker * me )
 {
     IOService *     service;
     OSSet *         inner;
-    AbsoluteTime    startTime;
+    AbsoluteTime    startTime, elapsedTime;
     UInt32          deltaTime;
     bool            timeout;
 
@@ -7393,7 +8418,7 @@ void PMHaltWorker::work( PMHaltWorker * me )
         inner = (OSSet *)gPMHaltArray->getObject(me->depth);
         if (inner)
         {
-            service = (IOService *)inner->getAnyObject();
+            service = OSDynamicCast(IOService, inner->getAnyObject());
             if (service)
             {
                 service->retain();
@@ -7415,7 +8440,7 @@ void PMHaltWorker::work( PMHaltWorker * me )
             me->timeout   = false;
             IOLockUnlock(me->lock);
 
-            service->systemWillShutdown( gPMHaltEvent );
+            service->systemWillShutdown( gPMHaltMessageType );
 
             // Wait for driver acknowledgement
             IOLockLock(me->lock);
@@ -7428,15 +8453,19 @@ void PMHaltWorker::work( PMHaltWorker * me )
             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();
@@ -7466,7 +8495,7 @@ void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
         {
             me->timeout = true;
             MSG("%s still waiting on %s\n",
-                (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
+                (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
                     "PowerOff" : "Restart",
                 me->service->getName());
         }
@@ -7474,7 +8503,6 @@ void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
     IOLockUnlock(me->lock);
 }
 
-
 //******************************************************************************
 // acknowledgeSystemWillShutdown
 //
@@ -7515,7 +8543,7 @@ void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
 //******************************************************************************
 
 static void
-notifySystemShutdown( IOService * root, unsigned long event )
+notifySystemShutdown( IOService * root, uint32_t messageType )
 {
 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
     IORegistryIterator *    iter;
@@ -7533,7 +8561,7 @@ notifySystemShutdown( IOService * root, unsigned long event )
     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);
 
@@ -7567,7 +8595,7 @@ notifySystemShutdown( IOService * root, unsigned long event )
         if (!gPMHaltClientAcknowledgeKey) goto done;
     }
 
-    gPMHaltEvent = event;
+    gPMHaltMessageType = messageType;
 
     // Depth-first walk of PM plane
 
@@ -7797,18 +8825,18 @@ OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
     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;
 
     }
 
@@ -7819,16 +8847,16 @@ OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
      */
     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;
         }
     }
 
@@ -7836,8 +8864,12 @@ OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
     {
         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;
     }
@@ -7847,13 +8879,30 @@ OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
         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;
 }
 
@@ -7889,6 +8938,29 @@ void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
     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();
 
@@ -7944,6 +9016,9 @@ void IOPMrootDomain::claimSystemWakeEvent(
         // 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)
     {
@@ -8578,50 +9653,67 @@ IOReturn IOPMrootDomain::restartWithStackshot()
     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;
            }
@@ -8629,19 +9721,39 @@ void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog)
 
    }
 
-   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 ) {
 
@@ -8656,63 +9768,72 @@ void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog)
    }
 
    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");
 
 
@@ -8735,8 +9856,13 @@ exit:
    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();
@@ -8788,12 +9914,48 @@ void IOPMrootDomain::sleepWakeDebugMemAlloc( )
 
     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;
@@ -8804,7 +9966,28 @@ void IOPMrootDomain::sleepWakeDebugEnableWdog()
 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)
@@ -8819,6 +10002,7 @@ errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int
                         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);
@@ -8827,6 +10011,7 @@ errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int
    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);
@@ -8834,12 +10019,17 @@ errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int
     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);
@@ -8869,7 +10059,8 @@ errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
    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);
@@ -8877,7 +10068,8 @@ errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
    /* 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);   
@@ -8889,13 +10081,14 @@ errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
         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;
        }
 
@@ -8906,12 +10099,14 @@ errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
        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;
        }
 
@@ -8921,26 +10116,19 @@ errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
 
     }
     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);
 
@@ -8948,14 +10136,77 @@ exit:
 
 
 
+}
+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;
@@ -8967,10 +10218,9 @@ void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
     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)
@@ -8980,20 +10230,6 @@ void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
        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::
@@ -9008,53 +10244,47 @@ void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
     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;
     }
 
@@ -9063,6 +10293,7 @@ void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
         (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;
@@ -9071,15 +10302,17 @@ void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
     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;
@@ -9089,6 +10322,11 @@ 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();
@@ -9097,17 +10335,24 @@ exit:
       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)
@@ -9119,7 +10364,6 @@ 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))
@@ -9135,7 +10379,8 @@ void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
    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;
    }
 
@@ -9158,13 +10403,10 @@ 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();
@@ -9176,12 +10418,19 @@ exit:
           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;
 }
 
@@ -9191,7 +10440,7 @@ IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
    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;
@@ -9220,8 +10469,9 @@ IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
            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;
@@ -9237,7 +10487,8 @@ IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
    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;
    }
 
@@ -9250,6 +10501,7 @@ IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
    if (desc == NULL)
    {
       IOLog("Fail to map SleepWake log buffer\n");
+      swd_flags |= SWD_INTERNAL_FAILURE;
       goto exit;
    }
 
@@ -9260,13 +10512,15 @@ IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
 
    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;
    }
 
@@ -9275,6 +10529,7 @@ IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
             hdr->spindump_size);
    if (newcrc != crc) {
       IOLog("SleepWake log buffer contents are invalid\n");
+      swd_flags |= SWD_DATA_CRC_ERROR;
       goto exit;
    }
 
@@ -9298,9 +10553,19 @@ 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)