Index: /trunk/include/VBox/types.h
===================================================================
--- /trunk/include/VBox/types.h	(revision 22914)
+++ /trunk/include/VBox/types.h	(revision 22915)
@@ -152,18 +152,36 @@
     /** The VM is created. */
     VMSTATE_CREATED,
+    /** The VM state is being loaded from file. */
+    VMSTATE_LOADING,
     /** The VM is runnning. */
     VMSTATE_RUNNING,
-    /** The VM state is being loaded from file. */
-    VMSTATE_LOADING,
+    /** Live save: The VM is running and the state is being saved. */
+    VMSTATE_LS_RUNNING,
+    /** The VM is being reset. */
+    VMSTATE_RESETTING,
+    /** Live save: The VM is being reset, suspended, and awaiting cancellation
+     * of the live save operation. */
+    VMSTATE_LS_RESETTING,
+    /** The VM is suspended. */
+    VMSTATE_SUSPENDED,
+    /** Live save: The VM has been suspended and is av
+     * the live save operation. */
+    VMSTATE_LS_SUSPENDING,
+    /** The VM is suspended and its state is being saved by EMT(0). */
+    VMSTATE_SAVING,
+    /** Live save: The VM is suspended and its state is being saved by EMT(0). */
+    VMSTATE_LS_SAVING,
+    /** Live save: The VM is being powered off and the save cancelled. */
+    VMSTATE_LS_POWERING_OFF,
+    /** The VM is suspended because of a fatal error. */
+    VMSTATE_FATAL_ERROR,
+    /** Live save: Waiting for cancellation and transition to FatalError. */
+    VMSTATE_LS_FATAL_ERROR,
+    /** The VM is in guru meditation over a fatal failure. */
+    VMSTATE_GURU_MEDITATION,
+    /** Live save: Waiting for cancellation and transition to GuruMeditation. */
+    VMSTATE_LS_GURU_MEDIATION,
     /** The VM is screwed because of a failed state loading. */
     VMSTATE_LOAD_FAILURE,
-    /** The VM state is being saved to file. */
-    VMSTATE_SAVING,
-    /** The VM is suspended. */
-    VMSTATE_SUSPENDED,
-    /** The VM is being reset. */
-    VMSTATE_RESETTING,
-    /** The VM is in guru meditation over a fatal failure. */
-    VMSTATE_GURU_MEDITATION,
     /** The VM is switched off, awaiting destruction. */
     VMSTATE_OFF,
Index: /trunk/include/VBox/vmapi.h
===================================================================
--- /trunk/include/VBox/vmapi.h	(revision 22914)
+++ /trunk/include/VBox/vmapi.h	(revision 22915)
@@ -352,5 +352,4 @@
 VMMR3DECL(int)  VMR3PowerOn(PVM pVM);
 VMMR3DECL(int)  VMR3Suspend(PVM pVM);
-VMMR3DECL(int)  VMR3SuspendNoSave(PVM pVM);
 VMMR3DECL(int)  VMR3Resume(PVM pVM);
 VMMR3DECL(int)  VMR3Reset(PVM pVM);
Index: /trunk/src/VBox/Main/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 22914)
+++ /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 22915)
@@ -5798,5 +5798,5 @@
         }
 
-        case VMSTATE_GURU_MEDITATION:
+        case VMSTATE_FATAL_ERROR:
         {
             AutoWriteLock alock(that);
@@ -5805,5 +5805,24 @@
                 break;
 
-            /* Guru respects only running VMs */
+            /* Fatal errors are only for running VMs. */
+            Assert(Global::IsOnline(that->mMachineState));
+
+            /* Note! 'Pause' is used here in want of something better.  There
+             *       are currently only two places where fatal errors might be
+             *       raised, so it is not worth adding a new externally
+             *       visible state for this yet.  */
+            that->setMachineState(MachineState_Paused);
+
+            break;
+        }
+
+        case VMSTATE_GURU_MEDITATION:
+        {
+            AutoWriteLock alock(that);
+
+            if (that->mVMStateChangeCallbackDisabled)
+                break;
+
+            /* Guru are only for running VMs */
             Assert (Global::IsOnline (that->mMachineState));
 
Index: /trunk/src/VBox/VMM/VM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VM.cpp	(revision 22914)
+++ /trunk/src/VBox/VMM/VM.cpp	(revision 22915)
@@ -133,7 +133,8 @@
 static DECLCALLBACK(size_t) vmR3LogPrefixCallback(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser);
 static DECLCALLBACK(int) vmR3PowerOn(PVM pVM);
-static DECLCALLBACK(int) vmR3Suspend(PVM pVM);
+static int               vmR3SuspendCommon(PVM pVM, bool fFatal);
+static DECLCALLBACK(int) vmR3Suspend(PVM pVM, bool fFatal);
 static DECLCALLBACK(int) vmR3Resume(PVM pVM);
-static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser);
+static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM);
 static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser);
 static DECLCALLBACK(int) vmR3PowerOff(PVM pVM);
@@ -1227,17 +1228,36 @@
 
     /*
-     * Validate input.
-     */
-    if (!pVM)
-    {
-        AssertMsgFailed(("Invalid VM pointer\n"));
-        return VERR_INVALID_PARAMETER;
-    }
-
+     * Validate input and pass it on to the internal worker.
+     */
+    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+    int rc = vmR3SuspendCommon(pVM, false /*fFatal*/);
+
+    LogFlow(("VMR3Suspend: returns %Rrc\n", rc));
+    return rc;
+}
+
+
+/**
+ * Common worker for VMR3Suspend and vmR3SetRuntimeErrorCommon.
+ *
+ * They both suspends the VM, but the latter ends up in the VMSTATE_FATAL_ERROR
+ * instead of VMSTATE_SUSPENDED.
+ *
+ * @returns VBox status code.
+ * @param   pVM                 The VM handle.
+ * @param   fFatal              Whether it's a fatal error or not.
+ *
+ * @thread      Any thread.
+ * @vmstate     Running
+ * @vmstateto   Suspended, FatalError
+ */
+static int vmR3SuspendCommon(PVM pVM, bool fFatal)
+{
     /*
      * Request the operation in EMT. (in reverse order as VCPU 0 does the actual work)
      */
     PVMREQ pReq = NULL;
-    int rc = VMR3ReqCall(pVM, VMCPUID_ALL_REVERSE, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Suspend, 1, pVM);
+    int rc = VMR3ReqCall(pVM, VMCPUID_ALL_REVERSE, &pReq, RT_INDEFINITE_WAIT,
+                         (PFNRT)vmR3Suspend, 2, pVM, fFatal);
     if (RT_SUCCESS(rc))
     {
@@ -1248,5 +1268,4 @@
         Assert(pReq == NULL);
 
-    LogFlow(("VMR3Suspend: returns %Rrc\n", rc));
     return rc;
 }
@@ -1254,29 +1273,13 @@
 
 /**
- * Suspends a running VM and prevent state saving until the VM is resumed or stopped.
+ * Suspends a running VM.
  *
  * @returns 0 on success.
  * @returns VBox error code on failure.
  * @param   pVM     VM to suspend.
- * @thread      Any thread.
- * @vmstate     Running
- * @vmstateto   Suspended
- */
-VMMR3DECL(int) VMR3SuspendNoSave(PVM pVM)
-{
-    pVM->vm.s.fPreventSaveState = true;
-    return VMR3Suspend(pVM);
-}
-
-
-/**
- * Suspends a running VM.
- *
- * @returns 0 on success.
- * @returns VBox error code on failure.
- * @param   pVM     VM to suspend.
+ * @param   fFatal  Whether it's a fatal error or normal suspend.
  * @thread  EMT
  */
-static DECLCALLBACK(int) vmR3Suspend(PVM pVM)
+static DECLCALLBACK(int) vmR3Suspend(PVM pVM, bool fFatal)
 {
     LogFlow(("vmR3Suspend: pVM=%p\n", pVM));
@@ -1299,5 +1302,5 @@
      * Change the state, notify the components and resume the execution.
      */
-    vmR3SetState(pVM, VMSTATE_SUSPENDED);
+    vmR3SetState(pVM, fFatal ? VMSTATE_FATAL_ERROR : VMSTATE_SUSPENDED);
     PDMR3Suspend(pVM);
 
@@ -1399,5 +1402,5 @@
  * @param   pVM                 VM which state should be saved.
  * @param   pszFilename         Name of the save state file.
- * @param   fContinueAftewards  Continue execution afterwards. When in doubt,
+ * @param   fContinueAfterwards Continue execution afterwards. When in doubt,
  *                              set this to true.
  * @param   pfnProgress         Progress callback. Optional.
@@ -1408,8 +1411,8 @@
  * @vmstateto   Suspended.
  */
-VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, bool fContinueAftewards, PFNVMPROGRESS pfnProgress, void *pvUser)
-{
-    LogFlow(("VMR3Save: pVM=%p pszFilename=%p:{%s} fContinueAftewards=%RTbool pfnProgress=%p pvUser=%p\n",
-             pVM, pszFilename, pszFilename, fContinueAftewards, pfnProgress, pvUser));
+VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser)
+{
+    LogFlow(("VMR3Save: pVM=%p pszFilename=%p:{%s} fContinueAfterwards=%RTbool pfnProgress=%p pvUser=%p\n",
+             pVM, pszFilename, pszFilename, fContinueAfterwards, pfnProgress, pvUser));
 
     /*
@@ -1424,12 +1427,35 @@
      * Request the operation in EMT(0).
      */
-    SSMAFTER enmAfter = fContinueAftewards ? SSMAFTER_CONTINUE : SSMAFTER_DESTROY;
-    PVMREQ pReq;
+    SSMAFTER    enmAfter = fContinueAfterwards ? SSMAFTER_CONTINUE : SSMAFTER_DESTROY;
+    PSSMHANDLE  pSSM;
+    PVMREQ      pReq;
     int rc = VMR3ReqCall(pVM, 0 /* VCPU 0 */, &pReq, RT_INDEFINITE_WAIT,
-                         (PFNRT)vmR3Save, 5, pVM, pszFilename, enmAfter, pfnProgress, pvUser);
+                         (PFNRT)vmR3Save, 6, pVM, pszFilename, enmAfter, pfnProgress, pvUser, &pSSM);
     if (RT_SUCCESS(rc))
     {
         rc = pReq->iStatus;
         VMR3ReqFree(pReq);
+    }
+    if (    RT_SUCCESS(rc)
+        &&  pSSM)
+    {
+#if 1
+        /**@todo*/ rc = VERR_NOT_IMPLEMENTED;
+#else
+        /*
+         * Live snapshot.
+         */
+        rc = SSMR3LiveDoStep1(pSSM);
+        if (RT_SUCCESS(rc))
+        {
+            rc = VMR3ReqCall(pVM, 0 /* VCPU 0 */, &pReq, RT_INDEFINITE_WAIT,
+                             (PFNRT)vmR3SaveLive, 2, pVM, pSSM);
+            if (RT_SUCCESS(rc))
+            {
+                rc = pReq->iStatus;
+                VMR3ReqFree(pReq);
+            }
+        }
+#endif
     }
 
@@ -1449,9 +1475,11 @@
  * @param   pfnProgress     Progress callback. Optional.
  * @param   pvUser          User argument for the progress callback.
+ * @param   ppSSM           Where to return the saved state handle in case of a
+ *                          live snapshot scenario.
  * @thread  EMT
  */
-static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
-{
-    LogFlow(("vmR3Save: pVM=%p pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
+static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM)
+{
+    LogFlow(("vmR3Save: pVM=%p pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p ppSSM=%p\n", pVM, pszFilename, pszFilename, enmAfter, pfnProgress, pvUser, ppSSM));
 
     /*
@@ -1459,4 +1487,5 @@
      */
     /** @todo SMP: Check that vmR3SetState always done by EMT(0). If not add a vmR3TrySetState(). */
+    *ppSSM = NULL;
     AssertMsgReturn(   pVM->enmVMState == VMSTATE_SUSPENDED
                     || pVM->enmVMState == VMSTATE_RUNNING,
@@ -1472,10 +1501,18 @@
 
     /*
-     * Change the state and perform the save.
-     */
-    bool fLive = pVM->enmVMState == VMSTATE_RUNNING;
-    vmR3SetState(pVM, VMSTATE_SAVING); /** @todo Should probably use a different state for live snapshots and/or live migration. Will fix the state machine later. */
-    int rc = SSMR3Save(pVM, pszFilename, enmAfter, pfnProgress, pvUser);
-    vmR3SetState(pVM, VMSTATE_SUSPENDED);
+     * Change the state and perform/start the saveing.
+     */
+    int rc;
+    if (pVM->enmVMState == VMSTATE_RUNNING)
+    {
+        /** @todo state mess. */
+        rc = SSMR3LiveToFile(pVM, pszFilename, enmAfter, pfnProgress, pvUser, ppSSM);
+    }
+    else
+    {
+        vmR3SetState(pVM, VMSTATE_SAVING); /** @todo Should probably use a different state for live snapshots and/or live migration. Will fix the state machine later. */
+        rc = SSMR3Save(pVM, pszFilename, enmAfter, pfnProgress, pvUser);
+        vmR3SetState(pVM, VMSTATE_SUSPENDED);
+    }
 
     return rc;
@@ -1642,4 +1679,5 @@
         &&  pVM->enmVMState != VMSTATE_SUSPENDED
         &&  pVM->enmVMState != VMSTATE_LOAD_FAILURE
+        &&  pVM->enmVMState != VMSTATE_FATAL_ERROR
         &&  pVM->enmVMState != VMSTATE_GURU_MEDITATION)
     {
@@ -2704,14 +2742,23 @@
         case VMSTATE_CREATING:          return "CREATING";
         case VMSTATE_CREATED:           return "CREATED";
+        case VMSTATE_LOADING:           return "LOADING";
         case VMSTATE_RUNNING:           return "RUNNING";
-        case VMSTATE_LOADING:           return "LOADING";
+        case VMSTATE_LS_RUNNING:        return "LS_RUNNING";
+        case VMSTATE_RESETTING:         return "RESETTING";
+        case VMSTATE_LS_RESETTING:      return "LS_RESETTING";
+        case VMSTATE_SUSPENDED:         return "SUSPENDED";
+        case VMSTATE_LS_SUSPENDING:     return "LS_SUSPENDING";
+        case VMSTATE_SAVING:            return "SAVING";
+        case VMSTATE_LS_SAVING:         return "LS_SAVING";
+        case VMSTATE_LS_POWERING_OFF:   return "LS_POWERING_OFF";
+        case VMSTATE_FATAL_ERROR:       return "FATAL_ERROR";
+        case VMSTATE_LS_FATAL_ERROR:    return "LS_FATAL_ERROR";
+        case VMSTATE_GURU_MEDITATION:   return "GURU_MEDITATION";
+        case VMSTATE_LS_GURU_MEDIATION: return "LS_GURU_MEDIATION";
         case VMSTATE_LOAD_FAILURE:      return "LOAD_FAILURE";
-        case VMSTATE_SAVING:            return "SAVING";
-        case VMSTATE_SUSPENDED:         return "SUSPENDED";
-        case VMSTATE_RESETTING:         return "RESETTING";
-        case VMSTATE_GURU_MEDITATION:   return "GURU_MEDITATION";
         case VMSTATE_OFF:               return "OFF";
         case VMSTATE_DESTROYING:        return "DESTROYING";
         case VMSTATE_TERMINATED:        return "TERMINATED";
+
         default:
             AssertMsgFailed(("Unknown state %d\n", enmState));
@@ -2730,4 +2777,8 @@
 void vmR3SetState(PVM pVM, VMSTATE enmStateNew)
 {
+#ifdef DEBUG_bird /** @todo remove when sorted out. */
+    VM_ASSERT_EMT0(pVM);
+#endif
+
     /*
      * Validate state machine transitions before doing the actual change.
@@ -3411,7 +3462,5 @@
     int rc = VINF_SUCCESS;
     if (fFlags & VMSETRTERR_FLAGS_FATAL)
-        /** @todo Add some special VM state for the FATAL variant that isn't resumable.
-         *        It's too risky for 2.2.0, do after branching. */
-        rc = VMR3SuspendNoSave(pVM);
+        rc = vmR3SuspendCommon(pVM, true /*fFatal*/);
     else if (fFlags & VMSETRTERR_FLAGS_SUSPEND)
         rc = VMR3Suspend(pVM);
@@ -3492,11 +3541,11 @@
  * @param   fFlags          The error flags.
  * @param   pszErrorId      Error ID string.
- * @param   pszFormat       Format string.
- * @param   pVa             Pointer to the format arguments.
+ * @param   pszMessage      The error message residing the MM heap.
  *
  * @thread  EMT
  */
-DECLCALLBACK(int) vmR3SetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa)
-{
+DECLCALLBACK(int) vmR3SetRuntimeError(PVM pVM, uint32_t fFlags, const char *pszErrorId, char *pszMessage)
+{
+#if 0 /** @todo make copy of the error msg. */
     /*
      * Make a copy of the message.
@@ -3506,4 +3555,37 @@
     vmSetRuntimeErrorCopy(pVM, fFlags, pszErrorId, pszFormat, va2);
     va_end(va2);
+#endif
+
+    /*
+     * Join paths with VMR3SetRuntimeErrorWorker.
+     */
+    int rc = vmR3SetRuntimeErrorCommonF(pVM, fFlags, pszErrorId, "%s", pszMessage);
+    MMR3HeapFree(pszMessage);
+    return rc;
+}
+
+
+/**
+ * Worker for VMSetRuntimeErrorV for doing the job on EMT in ring-3.
+ *
+ * @returns VBox status code with modifications, see VMSetRuntimeErrorV.
+ *
+ * @param   pVM             The VM handle.
+ * @param   fFlags          The error flags.
+ * @param   pszErrorId      Error ID string.
+ * @param   pszFormat       Format string.
+ * @param   pVa             Pointer to the format arguments.
+ *
+ * @thread  EMT
+ */
+DECLCALLBACK(int) vmR3SetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa)
+{
+    /*
+     * Make a copy of the message.
+     */
+    va_list va2;
+    va_copy(va2, *pVa);
+    vmSetRuntimeErrorCopy(pVM, fFlags, pszErrorId, pszFormat, va2);
+    va_end(va2);
 
     /*
Index: /trunk/src/VBox/VMM/VMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/VMInternal.h	(revision 22914)
+++ /trunk/src/VBox/VMM/VMInternal.h	(revision 22915)
@@ -461,4 +461,5 @@
 DECLCALLBACK(void)  vmR3SetErrorUV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *args);
 void                vmSetErrorCopy(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args);
+DECLCALLBACK(int)   vmR3SetRuntimeError(PVM pVM, uint32_t fFlags, const char *pszErrorId, char *pszMessage);
 DECLCALLBACK(int)   vmR3SetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa);
 void                vmSetRuntimeErrorCopy(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va);
Index: /trunk/src/VBox/VMM/VMMAll/VMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/VMAll.cpp	(revision 22914)
+++ /trunk/src/VBox/VMM/VMMAll/VMAll.cpp	(revision 22915)
@@ -255,7 +255,9 @@
     /*
      * Switch to EMT.
-     */
-    va_list va2;
-    va_copy(va2, va); /* Have to make a copy here or GCC will break. */
+     *
+     * If it's a no-wait request, we have to format the message into a buffer
+     * here since the variable arguments list will become invalid once we call
+     * va_end and return.
+     */
     int rc;
     PVMREQ pReq;
@@ -263,14 +265,24 @@
         ||  VM_IS_EMT(pVM))
     {
+        fFlags &= ~VMSETRTERR_FLAGS_NO_WAIT;
+
+        va_list va2;
+        va_copy(va2, va); /* Have to make a copy here or GCC will break. */
         rc = VMR3ReqCallU(pVM->pUVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, VMREQFLAGS_VBOX_STATUS,
                           (PFNRT)vmR3SetRuntimeErrorV, 5, pVM, fFlags, pszErrorId, pszFormat, &va2);
+        va_end(va2);
         if (RT_SUCCESS(rc))
             rc = pReq->iStatus;
     }
     else
+    {
+        char *pszMessage = MMR3HeapAPrintfV(pVM, MM_TAG_VM, pszFormat, va);
+
         rc = VMR3ReqCallU(pVM->pUVM, VMCPUID_ANY, &pReq, 0, VMREQFLAGS_VBOX_STATUS | VMREQFLAGS_NO_WAIT,
-                          (PFNRT)vmR3SetRuntimeErrorV, 5, pVM, fFlags, pszErrorId, pszFormat, &va2);
+                          (PFNRT)vmR3SetRuntimeError, 4, pVM, fFlags, pszErrorId, pszMessage);
+        if (RT_FAILURE(rc))
+            MMR3HeapFree(pszMessage);
+    }
     VMR3ReqFree(pReq);
-    va_end(va2);
 
 #else
