Index: trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp
===================================================================
--- trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp	(revision 30395)
+++ trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp	(revision 30396)
@@ -822,10 +822,11 @@
             static const RTGETOPTDEF s_aTeleportOptions[] =
             {
-                { "--host",        'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
-                { "--hostname",    'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
-                { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
-                { "--port",        'p', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
-                { "--password",    'P', RTGETOPT_REQ_STRING },
-                { "--timeout",     't', RTGETOPT_REQ_UINT32 }
+                { "--host",              'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
+                { "--hostname",          'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
+                { "--maxdowntime",       'd', RTGETOPT_REQ_UINT32 },
+                { "--port",              'p', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
+                { "--password",          'P', RTGETOPT_REQ_STRING },
+                { "--timeout",           't', RTGETOPT_REQ_UINT32 },
+                { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
             };
             RTGETOPTSTATE GetOptState;
@@ -840,4 +841,5 @@
                     case 'h': bstrHostname  = Value.psz; break;
                     case 'd': uMaxDowntime  = Value.u32; break;
+                    case 'D': g_fDetailedProgress = true; break;
                     case 'p': uPort         = Value.u32; break;
                     case 'P': bstrPassword  = Value.psz; break;
Index: trunk/src/VBox/Main/ProgressImpl.cpp
===================================================================
--- trunk/src/VBox/Main/ProgressImpl.cpp	(revision 30395)
+++ trunk/src/VBox/Main/ProgressImpl.cpp	(revision 30396)
@@ -977,5 +977,5 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    AssertReturn(aPercent <= 100, E_INVALIDARG);
+    AssertMsgReturn(aPercent <= 100, ("%u\n", aPercent), E_INVALIDARG);
 
     checkForAutomaticTimeout();
Index: trunk/src/VBox/VMM/CPUM.cpp
===================================================================
--- trunk/src/VBox/VMM/CPUM.cpp	(revision 30395)
+++ trunk/src/VBox/VMM/CPUM.cpp	(revision 30396)
@@ -2085,7 +2085,7 @@
          */
         if (uVersion == CPUM_SAVED_STATE_VERSION_VER1_6)
-            SSMR3SetGCPtrSize(pSSM, sizeof(RTGCPTR32));
+            SSMR3HandleSetGCPtrSize(pSSM, sizeof(RTGCPTR32));
         else if (uVersion <= CPUM_SAVED_STATE_VERSION_VER3_0)
-            SSMR3SetGCPtrSize(pSSM, HC_ARCH_BITS == 32 ? sizeof(RTGCPTR32) : sizeof(RTGCPTR));
+            SSMR3HandleSetGCPtrSize(pSSM, HC_ARCH_BITS == 32 ? sizeof(RTGCPTR32) : sizeof(RTGCPTR));
 
         /*
Index: trunk/src/VBox/VMM/PGMSavedState.cpp
===================================================================
--- trunk/src/VBox/VMM/PGMSavedState.cpp	(revision 30395)
+++ trunk/src/VBox/VMM/PGMSavedState.cpp	(revision 30396)
@@ -1890,4 +1890,17 @@
         }
     }
+
+    /*
+     * Come up with a completion percentage.  Currently this is a simple
+     * dirty page (long term) vs. total pages ratio + some pass trickery.
+     */
+    unsigned uPctDirty = cDirtyPagesLong
+                       / (long double)(pVM->pgm.s.cAllPages - pVM->pgm.s.LiveSave.cIgnoredPages - pVM->pgm.s.cZeroPages);
+    if (uPctDirty <= 100)
+        SSMR3HandleReportLivePercent(pSSM, RT_MIN(100 - uPctDirty, uPass * 2));
+    else
+        AssertMsgFailed(("uPctDirty=%u cDirtyPagesLong=%#x cAllPages=%#x cIgnoredPages=%#x cZeroPages=%#x\n",
+                         uPctDirty, cDirtyPagesLong, pVM->pgm.s.cAllPages, pVM->pgm.s.LiveSave.cIgnoredPages, pVM->pgm.s.cZeroPages));
+
     return VINF_SSM_VOTE_FOR_ANOTHER_PASS;
 }
Index: trunk/src/VBox/VMM/SSM.cpp
===================================================================
--- trunk/src/VBox/VMM/SSM.cpp	(revision 30395)
+++ trunk/src/VBox/VMM/SSM.cpp	(revision 30396)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -485,8 +485,13 @@
     /** End of current unit in the estimated file. */
     uint64_t                offEstUnitEnd;
-    /** the amount of % we reserve for the 'prepare' phase */
+    /** The amount of % we reserve for the 'live' stage */
+    unsigned                uPercentLive;
+    /** The amount of % we reserve for the 'prepare' phase */
     unsigned                uPercentPrepare;
-    /** the amount of % we reserve for the 'done' stage */
+    /** The amount of % we reserve for the 'done' stage */
     unsigned                uPercentDone;
+    /** The lowest value reported via SSMR3HandleReportLivePercent during one
+     * vote run. */
+    unsigned                uReportedLivePercent;
     /** The filename, NULL if remote stream. */
     const char             *pszFilename;
@@ -872,5 +877,7 @@
 static DECLCALLBACK(int)    ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM);
 static DECLCALLBACK(int)    ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
+static DECLCALLBACK(int)    ssmR3LiveControlLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
 static int                  ssmR3Register(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit);
+static int                  ssmR3LiveControlEmit(PSSMHANDLE pSSM, long double lrdPct, uint32_t uPass);
 #endif
 
@@ -916,4 +923,9 @@
                                    NULL /*pfnSavePrep*/, ssmR3SelfSaveExec, NULL /*pfnSaveDone*/,
                                    NULL /*pfnSavePrep*/, ssmR3SelfLoadExec, NULL /*pfnSaveDone*/);
+    if (RT_SUCCESS(rc))
+        rc = SSMR3RegisterInternal(pVM, "SSMLiveControl", 0 /*uInstance*/, 1 /*uVersion*/, 1 /*cbGuess*/,
+                                   NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/,     NULL /*pfnLiveVote*/,
+                                   NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/,     NULL /*pfnSaveDone*/,
+                                   NULL /*pfnSavePrep*/, ssmR3LiveControlLoadExec, NULL /*pfnSaveDone*/);
 
     /*
@@ -1040,4 +1052,40 @@
     }
     return VINF_SUCCESS;
+}
+
+
+/**
+ * Load exec callback for the special live save state unit that tracks the
+ * progress of a live save.
+ *
+ * This is saved by ssmR3LiveControlEmit().
+ *
+ * @returns VBox status code.
+ * @param   pVM             Pointer to the shared VM structure.
+ * @param   pSSM            The SSM handle.
+ * @param   uVersion        The version (1).
+ * @param   uPass           The pass.
+ */
+static DECLCALLBACK(int) ssmR3LiveControlLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+    AssertLogRelMsgReturn(uVersion == 1, ("%d", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
+
+    uint16_t uPartsPerTenThousand;
+    int rc = SSMR3GetU16(pSSM, &uPartsPerTenThousand);
+    if (RT_SUCCESS(rc))
+    {
+        /* Scale it down to fit in our exec range. */
+        unsigned uPct = (unsigned)(  (long double)uPartsPerTenThousand / 100
+                                   * (100 - pSSM->uPercentPrepare - pSSM->uPercentDone) / 100)
+                      + pSSM->uPercentPrepare;
+        if (uPct != pSSM->uPercent)
+        {
+            AssertMsg(uPct < 100, ("uPct=%d uPartsPerTenThousand=%d uPercentPrepare=%d uPercentDone=%d\n", uPct, uPartsPerTenThousand, pSSM->uPercentPrepare, pSSM->uPercentDone));
+            pSSM->uPercent = uPct;
+            if (pSSM->pfnProgress)
+                pSSM->pfnProgress(pVM, RT_MIN(uPct, 100 - pSSM->uPercentDone), pSSM->pvUser);
+        }
+    }
+    return rc;
 }
 
@@ -2892,26 +2940,30 @@
 
 /**
- * Works the progress calculation.
+ * Works the progress calculation for non-live saves and restores.
  *
  * @param   pSSM        The SSM handle.
- * @param   cbAdvance   Number of bytes to advance
- */
-static void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance)
-{
-    /* Can't advance it beyond the estimated end of the unit. */
-    uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
-    if (cbAdvance > cbLeft)
-        cbAdvance = cbLeft;
-    pSSM->offEst += cbAdvance;
-
-    /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
-    while (   pSSM->offEst >= pSSM->offEstProgress
-           && pSSM->uPercent <= 100-pSSM->uPercentDone)
-    {
-        if (pSSM->pfnProgress)
-            pSSM->pfnProgress(pSSM->pVM, pSSM->uPercent, pSSM->pvUser);
-        pSSM->uPercent++;
-        pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare) * pSSM->cbEstTotal
-                             / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare);
+ * @param   cbAdvance   Number of bytes to advance (with in the current unit).
+ */
+static void ssmR3ProgressByByte(PSSMHANDLE pSSM, uint64_t cbAdvance)
+{
+    if (!pSSM->fLiveSave)
+    {
+        /* Can't advance it beyond the estimated end of the unit. */
+        uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
+        if (cbAdvance > cbLeft)
+            cbAdvance = cbLeft;
+        pSSM->offEst += cbAdvance;
+
+        /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc. This is not
+           quite right for live save, but the non-live stage there is very short. */
+        while (   pSSM->offEst >= pSSM->offEstProgress
+               && pSSM->uPercent <= 100 - pSSM->uPercentDone)
+        {
+            if (pSSM->pfnProgress)
+                pSSM->pfnProgress(pSSM->pVM, pSSM->uPercent, pSSM->pvUser);
+            pSSM->uPercent++;
+            pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare - pSSM->uPercentLive) * pSSM->cbEstTotal
+                                 / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare - pSSM->uPercentLive);
+        }
     }
 }
@@ -3151,5 +3203,5 @@
     if (RT_SUCCESS(rc))
         rc = ssmR3DataWriteRaw(pSSM, pSSM->u.Write.abDataBuffer, cb);
-    ssmR3Progress(pSSM, cb);
+    ssmR3ProgressByByte(pSSM, cb);
     return rc;
 }
@@ -3213,5 +3265,5 @@
 
                 pSSM->offUnit += cbRec;
-                ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
+                ssmR3ProgressByByte(pSSM, SSM_ZIP_BLOCK_SIZE);
 
                 /* advance */
@@ -3236,5 +3288,5 @@
 
                 /* advance */
-                ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
+                ssmR3ProgressByByte(pSSM, SSM_ZIP_BLOCK_SIZE);
                 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
                     return VINF_SUCCESS;
@@ -3250,5 +3302,5 @@
                 if (RT_SUCCESS(rc))
                     rc = ssmR3DataWriteRaw(pSSM, pvBuf, cbBuf);
-                ssmR3Progress(pSSM, cbBuf);
+                ssmR3ProgressByByte(pSSM, cbBuf);
                 break;
             }
@@ -4061,4 +4113,93 @@
 
 /**
+ * Emits a SSMLiveControl unit with a new progress report.
+ *
+ * @returns VBox status code.
+ * @param   pSSM                    The saved state handle.
+ * @param   lrdPct                  The progress of the the live save.
+ * @param   uPass                   The current pass.
+ */
+static int ssmR3LiveControlEmit(PSSMHANDLE pSSM, long double lrdPct, uint32_t uPass)
+{
+    AssertMsg(lrdPct <= 100.0, ("%u\n", lrdPct * 100));
+
+    /*
+     * Make sure we're in one of the two EXEC states or we may fail.
+     */
+    SSMSTATE enmSavedState = pSSM->enmOp;
+    if (enmSavedState == SSMSTATE_LIVE_VOTE)
+        pSSM->enmOp = SSMSTATE_LIVE_EXEC;
+    else if (enmSavedState == SSMSTATE_SAVE_DONE)
+        pSSM->enmOp = SSMSTATE_SAVE_EXEC;
+
+    /*
+     * Write the unit header.
+     */
+    SSMFILEUNITHDRV2 UnitHdr;
+    memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
+    UnitHdr.offStream       = ssmR3StrmTell(&pSSM->Strm);
+    UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
+    UnitHdr.u32CRC          = 0;
+    UnitHdr.u32Version      = 1;
+    UnitHdr.u32Instance     = 0;
+    UnitHdr.u32Pass         = uPass;
+    UnitHdr.fFlags          = 0;
+    UnitHdr.cbName          = sizeof("SSMLiveControl");
+    memcpy(&UnitHdr.szName[0], "SSMLiveControl", UnitHdr.cbName);
+    UnitHdr.u32CRC          = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
+    Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
+         UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
+    int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Write the payload.
+         */
+        ssmR3DataWriteBegin(pSSM);
+
+        uint16_t u16PartsPerTenThousand = (uint16_t)(lrdPct * (100 - pSSM->uPercentDone));
+        AssertMsg(u16PartsPerTenThousand <= 10000, ("%u\n", u16PartsPerTenThousand));
+        ssmR3DataWrite(pSSM, &u16PartsPerTenThousand, sizeof(u16PartsPerTenThousand));
+
+        rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
+        if (RT_SUCCESS(rc))
+        {
+            /*
+             * Write the termination record and flush the compression stream.
+             */
+            SSMRECTERM TermRec;
+            TermRec.u8TypeAndFlags   = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
+            TermRec.cbRec            = sizeof(TermRec) - 2;
+            if (pSSM->Strm.fChecksummed)
+            {
+                TermRec.fFlags       = SSMRECTERM_FLAGS_CRC32;
+                TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
+            }
+            else
+            {
+                TermRec.fFlags       = 0;
+                TermRec.u32StreamCRC = 0;
+            }
+            TermRec.cbUnit           = pSSM->offUnit + sizeof(TermRec);
+            rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
+            if (RT_SUCCESS(rc))
+                rc = ssmR3DataWriteFinish(pSSM);
+            if (RT_SUCCESS(rc))
+            {
+                pSSM->enmOp = enmSavedState;
+                return rc;
+            }
+        }
+    }
+
+    LogRel(("SSM: Failed to write live control unit. rc=%Rrc\n", rc));
+    if (RT_SUCCESS_NP(pSSM->rc))
+        pSSM->rc = rc;
+    pSSM->enmOp = enmSavedState;
+    return rc;
+}
+
+
+/**
  * Do the pfnSaveDone run.
  *
@@ -4338,4 +4479,28 @@
 
 /**
+ * Works the progress calculation during the exec part of a live save.
+ *
+ * @param   pSSM        The SSM handle.
+ * @param   iUnit       The current unit number.
+ */
+static void ssmR3ProgressByUnit(PSSMHANDLE pSSM, uint32_t iUnit)
+{
+    if (pSSM->fLiveSave)
+    {
+        unsigned    uPctExec = iUnit * 100 / pSSM->pVM->ssm.s.cUnits;
+        unsigned    cPctExec = 100 - pSSM->uPercentDone - pSSM->uPercentPrepare - pSSM->uPercentLive;
+        long double lrdPct   = (long double)uPctExec * cPctExec / 100 + pSSM->uPercentPrepare + pSSM->uPercentLive;
+        unsigned    uPct     = (unsigned)lrdPct;
+        if (uPct != pSSM->uPercent)
+        {
+            ssmR3LiveControlEmit(pSSM, lrdPct, SSM_PASS_FINAL);
+            pSSM->uPercent =  uPct;
+            pSSM->pfnProgress(pSSM->pVM, uPct, pSSM->pvUser);
+        }
+    }
+}
+
+
+/**
  * Do the pfnSaveExec run.
  *
@@ -4350,5 +4515,6 @@
     pSSM->rc = VINF_SUCCESS;
     pSSM->enmOp = SSMSTATE_SAVE_EXEC;
-    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
+    unsigned iUnit = 0;
+    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext, iUnit++)
     {
         /*
@@ -4356,4 +4522,5 @@
          * make sure to keep the progress indicator up to date.
          */
+        ssmR3ProgressByUnit(pSSM, iUnit);
         pSSM->offEstUnitEnd += pUnit->cbGuess;
         if (!pUnit->u.Common.pfnSaveExec)
@@ -4361,5 +4528,5 @@
             pUnit->fCalled = true;
             if (pUnit->cbGuess)
-                ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
+                ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
             continue;
         }
@@ -4463,11 +4630,12 @@
          * Advance the progress indicator to the end of the current unit.
          */
-        ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
+        ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
     } /* for each unit */
-
+    ssmR3ProgressByUnit(pSSM, pVM->ssm.s.cUnits);
 
     /* (progress should be pending 99% now) */
-    AssertMsg(   pSSM->uPercent == (101 - pSSM->uPercentDone)
-              || pSSM->fLiveSave, ("%d\n", pSSM->uPercent));
+    AssertMsg(   pSSM->uPercent == 101 - pSSM->uPercentDone
+              || pSSM->uPercent == 100 - pSSM->uPercentDone,
+              ("%d\n", pSSM->uPercent));
     return VINF_SUCCESS;
 }
@@ -4528,6 +4696,6 @@
      */
     if (pSSM->pfnProgress)
-        pSSM->pfnProgress(pVM, pSSM->uPercentPrepare-1, pSSM->pvUser);
-    pSSM->uPercent = pSSM->uPercentPrepare;
+        pSSM->pfnProgress(pVM, pSSM->uPercentPrepare + pSSM->uPercentLive - 1, pSSM->pvUser);
+    pSSM->uPercent = pSSM->uPercentPrepare + pSSM->uPercentLive;
 
     return VINF_SUCCESS;
@@ -4687,6 +4855,8 @@
     pSSM->offEst                    = 0;
     pSSM->offEstUnitEnd             = 0;
+    pSSM->uPercentLive              = 0;
     pSSM->uPercentPrepare           = 0;
     pSSM->uPercentDone              = 0;
+    pSSM->uReportedLivePercent      = 0;
     pSSM->pszFilename               = pszFilename;
     pSSM->u.Write.offDataBuffer     = 0;
@@ -4747,4 +4917,5 @@
     if (RT_FAILURE(rc))
         return rc;
+    pSSM->uPercentLive    = 0;
     pSSM->uPercentPrepare = 20;
     pSSM->uPercentDone    = 2;
@@ -4768,4 +4939,20 @@
 
 /**
+ * Used by PGM to report the completion percentage of the live stage during the
+ * vote run.
+ *
+ * @param   pSSM                The saved state handle.
+ * @param   uPercent            The completion percentage.
+ */
+VMMR3DECL(void) SSMR3HandleReportLivePercent(PSSMHANDLE pSSM, unsigned uPercent)
+{
+    AssertMsgReturnVoid(pSSM->enmOp == SSMSTATE_LIVE_VOTE, ("%d\n", pSSM->enmOp));
+    AssertReturnVoid(uPercent <= 100);
+    if (uPercent < pSSM->uReportedLivePercent)
+        pSSM->uReportedLivePercent = uPercent;
+}
+
+
+/**
  * Calls pfnLiveVote for all units.
  *
@@ -4784,4 +4971,8 @@
     pSSM->rc = VINF_SUCCESS;
     pSSM->enmOp = SSMSTATE_LIVE_VOTE;
+
+    unsigned uPrevPrecent = pSSM->uReportedLivePercent;
+    pSSM->uReportedLivePercent = 101;
+
     for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
     {
@@ -4837,5 +5028,29 @@
     }
     if (rcRet == VINF_SUCCESS)
+    {
         LogRel(("SSM: Step 1 completed after pass %u.\n", uPass));
+        pSSM->uReportedLivePercent = 100;
+    }
+    else
+    {
+        /*
+         * Work the progress callback.
+         */
+        if (pSSM->uReportedLivePercent > 100)
+            pSSM->uReportedLivePercent = 0;
+        if (   pSSM->uReportedLivePercent != uPrevPrecent
+            && pSSM->pfnProgress
+            && pSSM->uPercentLive)
+        {
+            long double lrdPct = (long double)pSSM->uReportedLivePercent * pSSM->uPercentLive / 100;
+            unsigned    uPct   = (unsigned)lrdPct;
+            if (uPct != pSSM->uPercent)
+            {
+                ssmR3LiveControlEmit(pSSM, lrdPct, uPass);
+                pSSM->uPercent = uPct;
+                pSSM->pfnProgress(pVM, uPct, pSSM->pvUser);
+            }
+        }
+    }
     return rcRet;
 }
@@ -5207,5 +5422,6 @@
     if (RT_FAILURE(rc))
         return rc;
-    pSSM->uPercentPrepare        = 20; /** @todo fix these. */
+    pSSM->uPercentLive           = 93;
+    pSSM->uPercentPrepare        = 2;
     pSSM->uPercentDone           = 2;
     pSSM->fLiveSave              = true;
@@ -5302,5 +5518,5 @@
             if (pcbRead)
                 *pcbRead = cbRead;
-            ssmR3Progress(pSSM, cbRead);
+            ssmR3ProgressByByte(pSSM, cbRead);
             return VINF_SUCCESS;
         }
@@ -5415,5 +5631,5 @@
     {
         pSSM->offUnit += cbToRead;
-        ssmR3Progress(pSSM, cbToRead);
+        ssmR3ProgressByByte(pSSM, cbToRead);
         return VINF_SUCCESS;
     }
@@ -5482,5 +5698,5 @@
     {
         pSSM->offUnit += cbCompr;
-        ssmR3Progress(pSSM, cbCompr);
+        ssmR3ProgressByByte(pSSM, cbCompr);
     }
     else
@@ -6670,5 +6886,5 @@
  *          format isn't 1.1 the call will be ignored.
  */
-VMMR3_INT_DECL(int) SSMR3SetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr)
+VMMR3_INT_DECL(int) SSMR3HandleSetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr)
 {
     Assert(cbGCPtr == sizeof(RTGCPTR32) || cbGCPtr == sizeof(RTGCPTR64));
@@ -7398,22 +7614,24 @@
      * Initialize the handle.
      */
-    pSSM->pVM               = pVM;
-    pSSM->enmOp             = SSMSTATE_INVALID;
-    pSSM->enmAfter          = SSMAFTER_INVALID;
-    pSSM->fCancelled        = SSMHANDLE_OK;
-    pSSM->rc                = VINF_SUCCESS;
-    pSSM->cbUnitLeftV1      = 0;
-    pSSM->offUnit           = UINT64_MAX;
-    pSSM->fLiveSave         = false;
-    pSSM->pfnProgress       = NULL;
-    pSSM->pvUser            = NULL;
-    pSSM->uPercent          = 0;
-    pSSM->offEstProgress    = 0;
-    pSSM->cbEstTotal        = 0;
-    pSSM->offEst            = 0;
-    pSSM->offEstUnitEnd     = 0;
-    pSSM->uPercentPrepare   = 5;
-    pSSM->uPercentDone      = 2;
-    pSSM->pszFilename       = pszFilename;
+    pSSM->pVM                   = pVM;
+    pSSM->enmOp                 = SSMSTATE_INVALID;
+    pSSM->enmAfter              = SSMAFTER_INVALID;
+    pSSM->fCancelled            = SSMHANDLE_OK;
+    pSSM->rc                    = VINF_SUCCESS;
+    pSSM->cbUnitLeftV1          = 0;
+    pSSM->offUnit               = UINT64_MAX;
+    pSSM->fLiveSave             = false;
+    pSSM->pfnProgress           = NULL;
+    pSSM->pvUser                = NULL;
+    pSSM->uPercent              = 0;
+    pSSM->offEstProgress        = 0;
+    pSSM->cbEstTotal            = 0;
+    pSSM->offEst                = 0;
+    pSSM->offEstUnitEnd         = 0;
+    pSSM->uPercentLive          = 0;
+    pSSM->uPercentPrepare       = 5;
+    pSSM->uPercentDone          = 2;
+    pSSM->uReportedLivePercent  = 0;
+    pSSM->pszFilename           = pszFilename;
 
     pSSM->u.Read.pZipDecompV1   = NULL;
@@ -7558,5 +7776,5 @@
                     Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
                     /* Complete the progress bar (pending 99% afterwards). */
-                    ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
+                    ssmR3ProgressByByte(pSSM, pSSM->cbEstTotal - pSSM->offEst);
                     break;
                 }
@@ -7652,5 +7870,5 @@
                                 Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
                                 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
-                                ssmR3Progress(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
+                                ssmR3ProgressByByte(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
                             }
                             else if (i64Diff > 0)
@@ -7849,6 +8067,5 @@
              */
             Log(("SSM: Unit at %#9llx: END UNIT\n", offUnit));
-            ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
-
+            ssmR3ProgressByByte(pSSM, pSSM->cbEstTotal - pSSM->offEst);
             return ssmR3LoadDirectoryAndFooter(pSSM);
         }
@@ -8003,7 +8220,10 @@
         ssmR3SetCancellable(pVM, &Handle, true);
 
-        Handle.enmAfter     = enmAfter;
-        Handle.pfnProgress  = pfnProgress;
-        Handle.pvUser       = pvProgressUser;
+        Handle.enmAfter         = enmAfter;
+        Handle.pfnProgress      = pfnProgress;
+        Handle.pvUser           = pvProgressUser;
+        Handle.uPercentLive     = 0;
+        Handle.uPercentPrepare  = 2;
+        Handle.uPercentDone     = 2;
 
         if (Handle.u.Read.u16VerMajor)
@@ -8069,7 +8289,7 @@
         }
 
-        /* pending 2% */
+        /* end of prepare % */
         if (pfnProgress)
-            pfnProgress(pVM, Handle.uPercentPrepare-1, pvProgressUser);
+            pfnProgress(pVM, Handle.uPercentPrepare - 1, pvProgressUser);
         Handle.uPercent      = Handle.uPercentPrepare;
         Handle.cbEstTotal    = Handle.u.Read.cbLoadFile;
@@ -8092,5 +8312,5 @@
             AssertMsg(   Handle.fLiveSave
                       || RT_FAILURE(rc)
-                      || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
+                      || Handle.uPercent == 101 - Handle.uPercentDone, ("%d\n", Handle.uPercent));
         }
 
