Index: /trunk/include/VBox/types.h
===================================================================
--- /trunk/include/VBox/types.h	(revision 60403)
+++ /trunk/include/VBox/types.h	(revision 60404)
@@ -163,4 +163,8 @@
     /** Live save: The VM is being reset and immediately suspended. */
     VMSTATE_RESETTING_LS,
+    /** The VM is being soft/warm reset. */
+    VMSTATE_SOFT_RESETTING,
+    /** Live save: The VM is being soft/warm reset (not suspended afterwards). */
+    VMSTATE_SOFT_RESETTING_LS,
     /** The VM is being suspended. */
     VMSTATE_SUSPENDING,
Index: /trunk/include/VBox/vmm/pdmapi.h
===================================================================
--- /trunk/include/VBox/vmm/pdmapi.h	(revision 60403)
+++ /trunk/include/VBox/vmm/pdmapi.h	(revision 60404)
@@ -85,7 +85,9 @@
 VMMR3_INT_DECL(int)     PDMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
 VMMR3DECL(void)         PDMR3PowerOn(PVM pVM);
+VMMR3_INT_DECL(bool)    PDMR3GetResetInfo(PVM pVM, uint32_t fOverride, uint32_t *pfResetFlags);
 VMMR3_INT_DECL(void)    PDMR3ResetCpu(PVMCPU pVCpu);
 VMMR3_INT_DECL(void)    PDMR3Reset(PVM pVM);
 VMMR3_INT_DECL(void)    PDMR3MemSetup(PVM pVM, bool fAtReset);
+VMMR3_INT_DECL(void)    PDMR3SoftReset(PVM pVM, uint32_t fResetFlags);
 VMMR3_INT_DECL(void)    PDMR3Suspend(PVM pVM);
 VMMR3_INT_DECL(void)    PDMR3Resume(PVM pVM);
Index: /trunk/include/VBox/vmm/pdmdev.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdev.h	(revision 60403)
+++ /trunk/include/VBox/vmm/pdmdev.h	(revision 60404)
@@ -132,4 +132,42 @@
 /** Pointer to a FNPDMDEVRESET() function. */
 typedef FNPDMDEVRESET *PFNPDMDEVRESET;
+
+/**
+ * Soft reset notification.
+ *
+ * This is mainly for emulating the 286 style protected mode exits, in which
+ * most devices should remain in their current state.
+ *
+ * @returns VBox status.
+ * @param   pDevIns     The device instance data.
+ * @param   fFlags      PDMVMRESET_F_XXX (only bits relevant to soft resets).
+ *
+ * @remarks Caller enters the device critical section.
+ */
+typedef DECLCALLBACK(void)  FNPDMDEVSOFTRESET(PPDMDEVINS pDevIns, uint32_t fFlags);
+/** Pointer to a FNPDMDEVSOFTRESET() function. */
+typedef FNPDMDEVSOFTRESET *PFNPDMDEVSOFTRESET;
+
+/** @name PDMVMRESET_F_XXX - VM reset flags.
+ * These flags are used both for FNPDMDEVSOFTRESET and for hardware signalling
+ * reset via PDMDevHlpVMReset.
+ * @{ */
+/** Unknown reason. */
+#define PDMVMRESET_F_UNKNOWN            UINT32_C(0x00000000)
+/** GIM triggered reset. */
+#define PDMVMRESET_F_GIM                UINT32_C(0x00000001)
+/** The last source always causing hard resets. */
+#define PDMVMRESET_F_LAST_ALWAYS_HARD   PDMVMRESET_F_GIM
+/** ACPI triggered reset. */
+#define PDMVMRESET_F_ACPI               UINT32_C(0x0000000c)
+/** PS/2 system port A (92h) reset. */
+#define PDMVMRESET_F_PORT_A             UINT32_C(0x0000000d)
+/** Keyboard reset. */
+#define PDMVMRESET_F_KBD                UINT32_C(0x0000000e)
+/** Tripple fault. */
+#define PDMVMRESET_F_TRIPLE_FAULT       UINT32_C(0x0000000f)
+/** Reset source mask. */
+#define PDMVMRESET_F_SRC_MASK           UINT32_C(0x0000000f)
+/** @} */
 
 /**
@@ -334,6 +372,7 @@
      * Critical section is entered. */
     PFNPDMDEVPOWEROFF   pfnPowerOff;
-    /** @todo */
-    PFNRT               pfnSoftReset;
+    /** Software system reset notification - optional.
+     * Critical section is entered. */
+    PFNPDMDEVSOFTRESET  pfnSoftReset;
     /** Initialization safty marker. */
     uint32_t            u32VersionEnd;
@@ -345,5 +384,5 @@
 
 /** Current DEVREG version number. */
-#define PDM_DEVREG_VERSION                      PDM_VERSION_MAKE(0xffff, 2, 0)
+#define PDM_DEVREG_VERSION                      PDM_VERSION_MAKE(0xffff, 2, 1)
 
 /** PDM Device Flags.
@@ -1053,4 +1092,56 @@
 
 /**
+ * Firmware registration structure.
+ */
+typedef struct PDMFWREG
+{
+    /** Struct version+magic number (PDM_FWREG_VERSION). */
+    uint32_t                u32Version;
+
+    /**
+     * Checks whether this is a hard or soft reset.
+     *
+     * The current definition of soft reset is what the PC BIOS does when CMOS[0xF]
+     * is 5, 9 or 0xA.
+     *
+     * @returns true if hard reset, false if soft.
+     * @param   pDevIns         Device instance of the firmware.
+     * @param   fFlags          PDMRESET_F_XXX passed to the PDMDevHlpVMReset API.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsHardReset,(PPDMDEVINS pDevIns, uint32_t fFlags));
+
+    /** Just a safety precaution. */
+    uint32_t                u32TheEnd;
+} PDMFWREG;
+/** Pointer to a FW registration structure. */
+typedef PDMFWREG *PPDMFWREG;
+/** Pointer to a const FW registration structure. */
+typedef PDMFWREG const *PCPDMFWREG;
+
+/** Current PDMFWREG version number. */
+#define PDM_FWREG_VERSION                       PDM_VERSION_MAKE(0xffdd, 1, 0)
+
+/**
+ * Firmware R3 helpers.
+ */
+typedef struct PDMFWHLPR3
+{
+    /** Structure version. PDM_FWHLP_VERSION defines the current version. */
+    uint32_t                u32Version;
+
+    /** Just a safety precaution. */
+    uint32_t                u32TheEnd;
+} PDMFWHLPR3;
+
+/** Pointer to FW R3 helpers. */
+typedef R3PTRTYPE(PDMFWHLPR3 *) PPDMFWHLPR3;
+/** Pointer to const FW R3 helpers. */
+typedef R3PTRTYPE(const PDMFWHLPR3 *) PCPDMFWHLPR3;
+
+/** Current PDMFWHLPR3 version number. */
+#define PDM_FWHLPR3_VERSION                     PDM_VERSION_MAKE(0xffdb, 1, 0)
+
+
+/**
  * Advanced Programmable Interrupt Controller registration structure.
  */
@@ -3574,17 +3665,17 @@
 
     /**
-     * Unregisters the VMM device heap - OBSOLETE.
-     *
-     * This entry can be reused.
-     * This entry can be reused.
-     * This entry can be reused.
+     * Registers the firmware (BIOS, EFI) device with PDM.
+     *
+     * The firmware provides a callback table and gets a special PDM helper table.
+     * There can only be one firmware device for a VM.
      *
      * @returns VBox status code.
      * @param   pDevIns             The device instance.
-     * @param   GCPhys              The physical address.
-     * @thread  EMT.
-     * @obsolete
-     */
-    DECLR3CALLBACKMEMBER(int, pfnUnregisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys));
+     * @param   pFwReg              Firmware registration structure.
+     * @param   ppFwHlp             Where to return the firmware helper structure.
+     * @remarks Only valid during device construction.
+     * @thread  EMT(0)
+     */
+    DECLR3CALLBACKMEMBER(int, pfnFirmwareRegister,(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlpR3));
 
     /**
@@ -3593,7 +3684,8 @@
      * @returns The appropriate VBox status code to pass around on reset.
      * @param   pDevIns             The device instance.
+     * @param   fFlags              PDMVMRESET_F_XXX flags.
      * @thread  The emulation thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnVMReset,(PPDMDEVINS pDevIns));
+    DECLR3CALLBACKMEMBER(int, pfnVMReset,(PPDMDEVINS pDevIns, uint32_t fFlags));
 
     /**
@@ -3705,5 +3797,5 @@
 
 /** Current PDMDEVHLPR3 version number. */
-#define PDM_DEVHLPR3_VERSION                    PDM_VERSION_MAKE(0xffe7, 15, 1)
+#define PDM_DEVHLPR3_VERSION                    PDM_VERSION_MAKE(0xffe7, 16, 0)
 
 
@@ -5298,9 +5390,17 @@
 
 /**
+ * @copydoc PDMDEVHLPR3::pfnFirmwareRegister
+ */
+DECLINLINE(int) PDMDevHlpFirmwareRegister(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlpR3)
+{
+    return pDevIns->pHlpR3->pfnFirmwareRegister(pDevIns, pFwReg, ppFwHlpR3);
+}
+
+/**
  * @copydoc PDMDEVHLPR3::pfnVMReset
  */
-DECLINLINE(int) PDMDevHlpVMReset(PPDMDEVINS pDevIns)
-{
-    return pDevIns->pHlpR3->pfnVMReset(pDevIns);
+DECLINLINE(int) PDMDevHlpVMReset(PPDMDEVINS pDevIns, uint32_t fFlags)
+{
+    return pDevIns->pHlpR3->pfnVMReset(pDevIns, fFlags);
 }
 
Index: /trunk/include/VBox/vmm/vmapi.h
===================================================================
--- /trunk/include/VBox/vmm/vmapi.h	(revision 60403)
+++ /trunk/include/VBox/vmm/vmapi.h	(revision 60404)
@@ -412,4 +412,6 @@
 VMMR3DECL(VMRESUMEREASON) VMR3GetResumeReason(PUVM);
 VMMR3DECL(int)          VMR3Reset(PUVM pUVM);
+VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetFF(PVM pVM);
+VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetTripleFault(PVM pVM);
 VMMR3DECL(int)          VMR3Save(PUVM pUVM, const char *pszFilename, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended);
 VMMR3_INT_DECL(int)     VMR3SaveFT(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, bool *pfSuspended, bool fSkipStateChanges);
Index: /trunk/src/VBox/Devices/Input/DevPS2.cpp
===================================================================
--- /trunk/src/VBox/Devices/Input/DevPS2.cpp	(revision 60403)
+++ /trunk/src/VBox/Devices/Input/DevPS2.cpp	(revision 60404)
@@ -548,5 +548,5 @@
 #else /* IN_RING3 */
         LogRel(("Reset initiated by keyboard controller\n"));
-        rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns));
+        rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns), PDMVMRESET_F_KBD);
 #endif /* !IN_RING3 */
         break;
@@ -556,5 +556,5 @@
     /* Make OS/2 happy. */
     /* The 8042 RAM is readable using commands 0x20 thru 0x3f, and writable
-       by 0x60 thru 0x7f. Now days only the firs byte, the mode, is used.
+       by 0x60 thru 0x7f. Now days only the first byte, the mode, is used.
        We'll ignore the writes (0x61..7f) and return 0 for all the reads
        just to make some OS/2 debug stuff a bit happier. */
@@ -1016,5 +1016,5 @@
             rc = VINF_IOM_R3_IOPORT_WRITE;
 # else
-            rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns));
+            rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns), PDMVMRESET_F_KBD);
 # endif
         }
Index: /trunk/src/VBox/Devices/PC/DevACPI.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevACPI.cpp	(revision 60403)
+++ /trunk/src/VBox/Devices/PC/DevACPI.cpp	(revision 60404)
@@ -1753,5 +1753,5 @@
     {
         LogRel(("ACPI: Reset initiated by ACPI\n"));
-        rc = PDMDevHlpVMReset(pDevIns);
+        rc = PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_ACPI);
     }
     else
Index: /trunk/src/VBox/Devices/PC/DevPcArch.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevPcArch.cpp	(revision 60403)
+++ /trunk/src/VBox/Devices/PC/DevPcArch.cpp	(revision 60404)
@@ -171,5 +171,5 @@
         {
             LogRel(("Reset initiated by system port A\n"));
-            return PDMDevHlpVMReset(pDevIns);
+            return PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_PORT_A);
         }
 
Index: /trunk/src/VBox/Devices/PC/DevPcBios.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevPcBios.cpp	(revision 60403)
+++ /trunk/src/VBox/Devices/PC/DevPcBios.cpp	(revision 60404)
@@ -199,4 +199,16 @@
     uint32_t        u32McfgBase;
     uint32_t        cbMcfgLength;
+
+    /** Firmware registration structure.   */
+    PDMFWREG        FwReg;
+    /** Dummy. */
+    PCPDMFWHLPR3    pFwHlpR3;
+    /** Whether to consult the shutdown status (CMOS[0xf]) for deciding upon soft
+     * or hard reset. */
+    bool            fCheckShutdownStatusForSoftReset;
+    /** Whether to clear the shutdown status on hard reset. */
+    bool            fClearShutdownStatusOnHardReset;
+    /** Number of soft resets we've logged. */
+    uint32_t        cLoggedSoftResets;
 } DEVPCBIOS;
 /** Pointer to the BIOS device state. */
@@ -281,4 +293,83 @@
     /* not in use. */
     return VINF_SUCCESS;
+}
+
+
+/**
+ * Write to CMOS memory.
+ * This is used by the init complete code.
+ */
+static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
+{
+    Assert(off < 256);
+    Assert(u32Val < 256);
+
+    int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
+    AssertRC(rc);
+}
+
+
+/**
+ * Read from CMOS memory.
+ * This is used by the init complete code.
+ */
+static uint8_t pcbiosCmosRead(PPDMDEVINS pDevIns, unsigned off)
+{
+    Assert(off < 256);
+
+    uint8_t u8val;
+    int rc = PDMDevHlpCMOSRead(pDevIns, off, &u8val);
+    AssertRC(rc);
+
+    return u8val;
+}
+
+
+/**
+ * @interface_method_impl{PDMFWREG,pfnIsHardReset}
+ */
+static DECLCALLBACK(bool) pcbiosFw_IsHardReset(PPDMDEVINS pDevIns, uint32_t fFlags)
+{
+    PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
+    if (pThis->fCheckShutdownStatusForSoftReset)
+    {
+        uint8_t bShutdownStatus = pcbiosCmosRead(pDevIns, 0xf);
+        if (   bShutdownStatus == 0x5
+            || bShutdownStatus == 0x9
+            || bShutdownStatus == 0xa)
+        {
+            const uint32_t cMaxLogged = 10;
+            if (pThis->cLoggedSoftResets < cMaxLogged)
+            {
+                RTFAR16 Far16 = { 0xfeed, 0xface };
+                PDMDevHlpPhysRead(pDevIns, 0x467, &Far16, sizeof(Far16));
+                pThis->cLoggedSoftResets++;
+                LogRel(("PcBios: Soft reset #%u - shutdown status %#x, warm reset vector (0040:0067) is %04x:%04x%s\n",
+                        pThis->cLoggedSoftResets, bShutdownStatus, Far16.sel, Far16.sel,
+                        pThis->cLoggedSoftResets < cMaxLogged ? "." : " - won't log any more!"));
+            }
+            return false;
+        }
+    }
+    return true;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnReset}
+ */
+static DECLCALLBACK(void) pcbiosReset(PPDMDEVINS pDevIns)
+{
+    PDEVPCBIOS pThis = PDMINS_2_DATA(pDevIns, PDEVPCBIOS);
+
+    if (pThis->fClearShutdownStatusOnHardReset)
+    {
+        uint8_t bShutdownStatus = pcbiosCmosRead(pDevIns, 0xf);
+        if (bShutdownStatus != 0)
+        {
+            LogRel(("PcBios: Clearing shutdown status code %02x.\n", bShutdownStatus));
+            pcbiosCmosWrite(pDevIns, 0xf, 0);
+        }
+    }
 }
 
@@ -329,35 +420,4 @@
     }
     return VERR_INVALID_PARAMETER;
-}
-
-
-/**
- * Write to CMOS memory.
- * This is used by the init complete code.
- */
-static void pcbiosCmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
-{
-    Assert(off < 256);
-    Assert(u32Val < 256);
-
-    int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
-    AssertRC(rc);
-}
-
-
-/**
- * Read from CMOS memory.
- * This is used by the init complete code.
- */
-static uint8_t pcbiosCmosRead(PPDMDEVINS pDevIns, int off)
-{
-    uint8_t     u8val;
-
-    Assert(off < 256);
-
-    int rc = PDMDevHlpCMOSRead(pDevIns, off, &u8val);
-    AssertRC(rc);
-
-    return u8val;
 }
 
@@ -1075,4 +1135,6 @@
                               "DmiExposeMemoryTable\0"
                               "DmiExposeProcInf\0"
+                              "CheckShutdownStatusForSoftReset\0"
+                              "ClearShutdownStatusOnHardReset\0"
                               ))
         return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
@@ -1529,4 +1591,5 @@
     /*
      * Map the Network Boot ROM into memory.
+     *
      * Currently there is a fixed mapping: 0x000e2000 to 0x000effff contains
      * the (up to) 56 kb ROM image.  The mapping size is fixed to trouble with
@@ -1550,4 +1613,28 @@
     if (pThis->uBootDelay > 15)
         pThis->uBootDelay = 15;
+
+
+    /*
+     * Read shutdown status code config and register ourselves as the firmware device.
+     */
+
+    /** @cfgm{CheckShutdownStatusForSoftReset, boolean, true}
+     * Whether to consult the shutdown status code (CMOS register 0Fh) to
+     * determine whether the guest intended a soft or hard reset.  Currently only
+     * shutdown status codes 05h, 09h and 0Ah are considered soft reset. */
+    rc = CFGMR3QueryBoolDef(pCfg, "CheckShutdownStatusForSoftReset", &pThis->fCheckShutdownStatusForSoftReset, true);
+    AssertLogRelRCReturn(rc, rc);
+
+    /** @cfgm{ClearShutdownStatusOnHardReset, boolean, true}
+     * Whether to clear the shutdown status code (CMOS register 0Fh) on hard reset. */
+    rc = CFGMR3QueryBoolDef(pCfg, "ClearShutdownStatusOnHardReset", &pThis->fClearShutdownStatusOnHardReset, true);
+    AssertLogRelRCReturn(rc, rc);
+
+    LogRel(("PcBios: fCheckShutdownStatusForSoftReset=%RTbool  fClearShutdownStatusOnHardReset=%RTbool\n",
+            pThis->fCheckShutdownStatusForSoftReset, pThis->fClearShutdownStatusOnHardReset));
+
+    static PDMFWREG const s_FwReg = { PDM_FWREG_VERSION, pcbiosFw_IsHardReset, PDM_FWREG_VERSION };
+    rc = PDMDevHlpFirmwareRegister(pDevIns, &s_FwReg, &pThis->pFwHlpR3);
+    AssertLogRelRCReturn(rc, rc);
 
     return VINF_SUCCESS;
@@ -1589,5 +1676,5 @@
     NULL,
     /* pfnReset */
-    NULL,
+    pcbiosReset,
     /* pfnSuspend */
     NULL,
Index: /trunk/src/VBox/Devices/PC/DevRTC.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevRTC.cpp	(revision 60403)
+++ /trunk/src/VBox/Devices/PC/DevRTC.cpp	(revision 60404)
@@ -1054,23 +1054,7 @@
     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
 
-    /* If shutdown status is non-zero, log its value. */
-    if (pThis->cmos_data[0xF])
-    {
-        LogRel(("CMOS shutdown status byte is %02X\n", pThis->cmos_data[0xF]));
-
-#if 0   /* It would be nice to log the warm reboot vector but alas, we already trashed it. */
-        uint32_t u32WarmVector;
-        int rc;
-        rc = PDMDevHlpPhysRead(pDevIns, 0x467, &u32WarmVector, sizeof(u32WarmVector));
-        AssertRC(rc);
-        LogRel((", 40:67 contains %04X:%04X\n", u32WarmVector >> 16, u32WarmVector & 0xFFFF));
-#endif
-        /* If we're going to trash the VM's memory, we also have to clear this. */
-        pThis->cmos_data[0xF] = 0;
-    }
-
     /* Reset index values (important for second bank). */
-    pThis->cmos_index[0]        = 0;
-    pThis->cmos_index[1]        = CMOS_BANK_SIZE;   /* Point to start of second bank. */
+    pThis->cmos_index[0] = 0;
+    pThis->cmos_index[1] = CMOS_BANK_SIZE;   /* Point to start of second bank. */
 }
 
@@ -1092,5 +1076,5 @@
                               "Base\0"
                               "UseUTC\0"
-                              "GCEnabled\0"
+                              "RCEnabled\0"
                               "R0Enabled\0"))
         return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
@@ -1116,6 +1100,6 @@
                                 N_("Configuration error: Querying \"UseUTC\" as a bool failed"));
 
-    bool fGCEnabled;
-    rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
+    bool fRCEnabled;
+    rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &fRCEnabled, true);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
@@ -1128,6 +1112,6 @@
                                 N_("Configuration error: failed to read R0Enabled as boolean"));
 
-    Log(("RTC: Irq=%#x Base=%#x fGCEnabled=%RTbool fR0Enabled=%RTbool\n",
-         u8Irq, pThis->IOPortBase, fGCEnabled, fR0Enabled));
+    Log(("RTC: Irq=%#x Base=%#x fRCEnabled=%RTbool fR0Enabled=%RTbool\n",
+         u8Irq, pThis->IOPortBase, fRCEnabled, fR0Enabled));
 
 
@@ -1199,5 +1183,5 @@
     if (RT_FAILURE(rc))
         return rc;
-    if (fGCEnabled)
+    if (fRCEnabled)
     {
         rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOPortBase, 4, NIL_RTRCPTR,
Index: /trunk/src/VBox/Devices/Storage/DrvVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 60403)
+++ /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 60404)
@@ -3140,4 +3140,6 @@
         || enmVmState == VMSTATE_RESETTING
         || enmVmState == VMSTATE_RESETTING_LS
+        || enmVmState == VMSTATE_SOFT_RESETTING
+        || enmVmState == VMSTATE_SOFT_RESETTING_LS
         || enmVmState == VMSTATE_SUSPENDING
         || enmVmState == VMSTATE_SUSPENDING_LS
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 60403)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 60404)
@@ -3303,6 +3303,7 @@
     switch (enmVMState)
     {
+        case VMSTATE_RUNNING:
         case VMSTATE_RESETTING:
-        case VMSTATE_RUNNING:
+        case VMSTATE_SOFT_RESETTING:
         {
             LogFlowFunc(("Suspending the VM...\n"));
@@ -6555,4 +6556,6 @@
         case VMSTATE_RESETTING:
         case VMSTATE_RESETTING_LS:
+        case VMSTATE_SOFT_RESETTING:
+        case VMSTATE_SOFT_RESETTING_LS:
         case VMSTATE_DEBUGGING:
         case VMSTATE_DEBUGGING_LS:
@@ -8346,4 +8349,5 @@
 
         case VMSTATE_RESETTING:
+        /** @todo shouldn't VMSTATE_RESETTING_LS be here?   */
         {
 #ifdef VBOX_WITH_GUEST_PROPS
@@ -8353,4 +8357,9 @@
             break;
         }
+
+        case VMSTATE_SOFT_RESETTING:
+        case VMSTATE_SOFT_RESETTING_LS:
+            /* Shouldn't do anything here! */
+            break;
 
         case VMSTATE_SUSPENDED:
Index: /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp	(revision 60403)
+++ /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp	(revision 60404)
@@ -863,4 +863,6 @@
                 case VMSTATE_RESETTING:
                 case VMSTATE_RESETTING_LS:
+                case VMSTATE_SOFT_RESETTING:
+                case VMSTATE_SOFT_RESETTING_LS:
                     Assert(!pState->mfSuspendedByUs);
                     Assert(!pState->mfUnlockedMedia);
Index: /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 60403)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 60404)
@@ -695,6 +695,6 @@
             {
                 LogRel(("GIM: HyperV: Reset initiated through MSR\n"));
-                int rc = PDMDevHlpVMReset(pVM->gim.s.pDevInsR3);
-                AssertRC(rc);
+                int rc = PDMDevHlpVMReset(pVM->gim.s.pDevInsR3, PDMVMRESET_F_GIM);
+                AssertRC(rc); /* Note! Not allowed to return VINF_EM_RESET / VINF_EM_HALT here, so ignore them. */
             }
             /* else: Ignore writes to other bits. */
Index: /trunk/src/VBox/VMM/VMMR3/EM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/EM.cpp	(revision 60403)
+++ /trunk/src/VBox/VMM/VMMR3/EM.cpp	(revision 60404)
@@ -477,5 +477,5 @@
     pVCpu->em.s.fForceRAW = false;
 
-    /* VMR3Reset may return VINF_EM_RESET or VINF_EM_SUSPEND, so transition
+    /* VMR3ResetFF may return VINF_EM_RESET or VINF_EM_SUSPEND, so transition
        out of the HALTED state here so that enmPrevState doesn't end up as
        HALTED when EMR3Execute returns. */
@@ -1701,5 +1701,5 @@
         if (VM_FF_TEST_AND_CLEAR(pVM, VM_FF_RESET))
         {
-            rc2 = VMR3Reset(pVM->pUVM);
+            rc2 = VBOXSTRICTRC_TODO(VMR3ResetFF(pVM));
             UPDATE_RC();
         }
@@ -2404,16 +2404,7 @@
                     {
                         Log(("EMR3ExecuteVM: VINF_EM_TRIPLE_FAULT: CPU reset...\n"));
-                        Assert(pVM->cCpus == 1);
-#ifdef VBOX_WITH_REM
-                        REMR3Reset(pVM);
-#endif
-                        PGMR3ResetCpu(pVM, pVCpu);
-                        TRPMR3ResetCpu(pVCpu);
-                        CPUMR3ResetCpu(pVM, pVCpu);
-                        EMR3ResetCpu(pVCpu);
-                        HMR3ResetCpu(pVCpu);
-                        pVCpu->em.s.enmState = emR3Reschedule(pVM, pVCpu, pVCpu->em.s.pCtx);
-                        Log2(("EMR3ExecuteVM: VINF_EM_TRIPLE_FAULT: %d -> %d\n", enmOldState, pVCpu->em.s.enmState));
-                        break;
+                        rc = VBOXSTRICTRC_TODO(VMR3ResetTripleFault(pVM));
+                        Log2(("EMR3ExecuteVM: VINF_EM_TRIPLE_FAULT: %d -> %d (rc=%Rrc)\n", enmOldState, pVCpu->em.s.enmState, rc));
+                        continue;
                     }
                     /* Else fall through and trigger a guru. */
Index: /trunk/src/VBox/VMM/VMMR3/PDM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDM.cpp	(revision 60403)
+++ /trunk/src/VBox/VMM/VMMR3/PDM.cpp	(revision 60404)
@@ -256,4 +256,5 @@
 #include "PDMInternal.h"
 #include <VBox/vmm/pdm.h>
+#include <VBox/vmm/em.h>
 #include <VBox/vmm/mm.h>
 #include <VBox/vmm/pgm.h>
@@ -1620,4 +1621,82 @@
 
     LogFlow(("PDMR3MemSetup: returns void\n"));
+}
+
+
+/**
+ * Retrieves and resets the info left behind by PDMDevHlpVMReset.
+ *
+ * @returns True if hard reset, false if soft reset.
+ * @param   pVM             The cross context VM structure.
+ * @param   fOverride       If non-zero, the override flags will be used instead
+ *                          of the reset flags kept by PDM. (For triple faults.)
+ * @param   pfResetFlags    Where to return the reset flags (PDMVMRESET_F_XXX).
+ * @thread  EMT
+ */
+VMMR3_INT_DECL(bool) PDMR3GetResetInfo(PVM pVM, uint32_t fOverride, uint32_t *pfResetFlags)
+{
+    VM_ASSERT_EMT(pVM);
+
+    /*
+     * Get the reset flags.
+     */
+    uint32_t fResetFlags;
+    fResetFlags = ASMAtomicXchgU32(&pVM->pdm.s.fResetFlags, 0);
+    if (fOverride)
+        fResetFlags = fOverride;
+    *pfResetFlags = fResetFlags;
+
+    /*
+     * To try avoid trouble, we never ever do soft/warm resets on SMP systems
+     * with more than CPU #0 active.  However, if only one CPU is active we
+     * will ask the firmware what it wants us to do (because the firmware may
+     * depend on the VMM doing a lot of what is normally its responsibility,
+     * like clearing memory).
+     */
+    bool     fOtherCpusActive = false;
+    VMCPUID  iCpu             = pVM->cCpus;
+    while (iCpu-- > 1)
+    {
+        EMSTATE enmState = EMGetState(&pVM->aCpus[iCpu]);
+        if (   enmState != EMSTATE_WAIT_SIPI
+            && enmState != EMSTATE_NONE)
+        {
+            fOtherCpusActive = true;
+            break;
+        }
+    }
+
+    bool fHardReset = fOtherCpusActive
+                   || (fResetFlags & PDMVMRESET_F_SRC_MASK) < PDMVMRESET_F_LAST_ALWAYS_HARD
+                   || !pVM->pdm.s.pFirmware
+                   || pVM->pdm.s.pFirmware->Reg.pfnIsHardReset(pVM->pdm.s.pFirmware->pDevIns, fResetFlags);
+
+    Log(("PDMR3GetResetInfo: returns fHardReset=%RTbool fResetFlags=%#x\n", fHardReset, fResetFlags));
+    return fHardReset;
+}
+
+
+/**
+ * Performs a soft reset of devices.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   fResetFlags     PDMVMRESET_F_XXX.
+ */
+VMMR3_INT_DECL(void) PDMR3SoftReset(PVM pVM, uint32_t fResetFlags)
+{
+    LogFlow(("PDMR3SoftReset: fResetFlags=%#x\n", fResetFlags));
+
+    /*
+     * Iterate thru the device instances and work the callback.
+     */
+    for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
+        if (pDevIns->pReg->pfnSoftReset)
+        {
+            PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
+            pDevIns->pReg->pfnSoftReset(pDevIns, fResetFlags);
+            PDMCritSectLeave(pDevIns->pCritSectRoR3);
+        }
+
+    LogFlow(("PDMR3SoftReset: returns void\n"));
 }
 
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 60403)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 60404)
@@ -3307,21 +3307,84 @@
 
 /**
- * @copydoc PDMDEVHLPR3::pfnUnregisterVMMDevHeap
+ * @interface_method_impl{PDMDEVHLPR3,pfnFirmwareRegister}
  */
-static DECLCALLBACK(int) pdmR3DevHlp_UnregisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
-{
-    /* Free to replace this interface. */
-    AssertFailedReturn(VERR_NOT_IMPLEMENTED);
+static DECLCALLBACK(int) pdmR3DevHlp_FirmwareRegister(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
+    LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: pFWReg=%p:{.u32Version=%#x, .pfnIsHardReset=%p, .u32TheEnd=%#x} ppFwHlp=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pFwReg, pFwReg->u32Version, pFwReg->pfnIsHardReset, pFwReg->u32TheEnd, ppFwHlp));
+
+    /*
+     * Validate input.
+     */
+    if (pFwReg->u32Version != PDM_FWREG_VERSION)
+    {
+        AssertMsgFailed(("u32Version=%#x expected %#x\n", pFwReg->u32Version, PDM_FWREG_VERSION));
+        LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: returns %Rrc (version)\n",
+                 pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
+        return VERR_INVALID_PARAMETER;
+    }
+    if (!pFwReg->pfnIsHardReset)
+    {
+        Assert(pFwReg->pfnIsHardReset);
+        LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: returns %Rrc (callbacks)\n",
+                 pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (!ppFwHlp)
+    {
+        Assert(ppFwHlp);
+        LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: returns %Rrc (ppFwHlp)\n",
+                 pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Only one DMA device.
+     */
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    if (pVM->pdm.s.pFirmware)
+    {
+        AssertMsgFailed(("Only one firmware device is supported!\n"));
+        LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: returns %Rrc\n",
+                 pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Allocate and initialize pci bus structure.
+     */
+    int rc = VINF_SUCCESS;
+    PPDMFW pFirmware = (PPDMFW)MMR3HeapAlloc(pDevIns->Internal.s.pVMR3, MM_TAG_PDM_DEVICE, sizeof(*pFirmware));
+    if (pFirmware)
+    {
+        pFirmware->pDevIns   = pDevIns;
+        pFirmware->Reg       = *pFwReg;
+        pVM->pdm.s.pFirmware = pFirmware;
+
+        /* set the helper pointer. */
+        *ppFwHlp = &g_pdmR3DevFirmwareHlp;
+        Log(("PDM: Registered firmware device '%s'/%d pDevIns=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pDevIns));
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
 }
 
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnVMReset} */
-static DECLCALLBACK(int) pdmR3DevHlp_VMReset(PPDMDEVINS pDevIns)
-{
-    PDMDEV_ASSERT_DEVINS(pDevIns);
-    PVM pVM = pDevIns->Internal.s.pVMR3;
-    VM_ASSERT_EMT(pVM);
-    LogFlow(("pdmR3DevHlp_VMReset: caller='%s'/%d: VM_FF_RESET %d -> 1\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, VM_FF_IS_SET(pVM, VM_FF_RESET)));
+static DECLCALLBACK(int) pdmR3DevHlp_VMReset(PPDMDEVINS pDevIns, uint32_t fFlags)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    VM_ASSERT_EMT(pVM);
+    LogFlow(("pdmR3DevHlp_VMReset: caller='%s'/%d: fFlags=%#x VM_FF_RESET %d -> 1\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, fFlags, VM_FF_IS_SET(pVM, VM_FF_RESET)));
 
     /*
@@ -3339,4 +3402,5 @@
     else
     {
+        pVM->pdm.s.fResetFlags = fFlags;
         VM_FF_SET(pVM, VM_FF_RESET);
         rc = VINF_EM_RESET;
@@ -3615,5 +3679,5 @@
     pdmR3DevHlp_GetCurrentCpuId,
     pdmR3DevHlp_RegisterVMMDevHeap,
-    pdmR3DevHlp_UnregisterVMMDevHeap,
+    pdmR3DevHlp_FirmwareRegister,
     pdmR3DevHlp_VMReset,
     pdmR3DevHlp_VMSuspend,
@@ -3679,9 +3743,9 @@
 
 
-/** @interface_method_impl{PDMDEVHLPR3,pfnUnregisterVMMDevHeap} */
-static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_UnregisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
-{
-    PDMDEV_ASSERT_DEVINS(pDevIns);
-    NOREF(GCPhys);
+/** @interface_method_impl{PDMDEVHLPR3,pfnFirmwareRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_FirmwareRegister(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlpR3)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    NOREF(pFwReg); NOREF(ppFwHlpR3);
     AssertReleaseMsgFailed(("Untrusted device called trusted helper! '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
     return VERR_ACCESS_DENIED;
@@ -3690,7 +3754,7 @@
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnVMReset} */
-static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_VMReset(PPDMDEVINS pDevIns)
-{
-    PDMDEV_ASSERT_DEVINS(pDevIns);
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_VMReset(PPDMDEVINS pDevIns, uint32_t fFlags)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns); NOREF(fFlags);
     AssertReleaseMsgFailed(("Untrusted device called trusted helper! '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
     return VERR_ACCESS_DENIED;
@@ -3867,5 +3931,5 @@
     pdmR3DevHlp_Untrusted_GetCurrentCpuId,
     pdmR3DevHlp_Untrusted_RegisterVMMDevHeap,
-    pdmR3DevHlp_Untrusted_UnregisterVMMDevHeap,
+    pdmR3DevHlp_Untrusted_FirmwareRegister,
     pdmR3DevHlp_Untrusted_VMReset,
     pdmR3DevHlp_Untrusted_VMSuspend,
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 60403)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 60404)
@@ -823,4 +823,13 @@
 
 /**
+ * Firmware Device Helpers.
+ */
+const PDMFWHLPR3 g_pdmR3DevFirmwareHlp =
+{
+    PDM_FWHLPR3_VERSION,
+    PDM_FWHLPR3_VERSION
+};
+
+/**
  * DMAC Device Helpers.
  */
@@ -842,2 +851,3 @@
     PDM_RTCHLP_VERSION
 };
+
Index: /trunk/src/VBox/VMM/VMMR3/VM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/VM.cpp	(revision 60403)
+++ /trunk/src/VBox/VMM/VMMR3/VM.cpp	(revision 60404)
@@ -54,4 +54,5 @@
 #include <VBox/vmm/pgm.h>
 #include <VBox/vmm/pdmapi.h>
+#include <VBox/vmm/pdmdev.h>
 #include <VBox/vmm/pdmcritsect.h>
 #include <VBox/vmm/em.h>
@@ -2740,5 +2741,92 @@
 
 /**
- * EMT rendezvous worker for VMR3Reset.
+ * EMT rendezvous worker for VMR3ResetFF for doing soft/warm reset.
+ *
+ * @returns VERR_VM_INVALID_VM_STATE, VINF_EM_RESCHEDULE.
+ *          (This is a strict return code, see FNVMMEMTRENDEZVOUS.)
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   pVCpu           The cross context virtual CPU structure of the calling EMT.
+ * @param   pvUser          The reset flags.
+ */
+static DECLCALLBACK(VBOXSTRICTRC) vmR3SoftReset(PVM pVM, PVMCPU pVCpu, void *pvUser)
+{
+    uint32_t fResetFlags = *(uint32_t *)pvUser;
+
+
+    /*
+     * The first EMT will try change the state to resetting.  If this fails,
+     * we won't get called for the other EMTs.
+     */
+    if (pVCpu->idCpu == pVM->cCpus - 1)
+    {
+        int rc = vmR3TrySetState(pVM, "vmR3ResetSoft", 3,
+                                 VMSTATE_SOFT_RESETTING,     VMSTATE_RUNNING,
+                                 VMSTATE_SOFT_RESETTING,     VMSTATE_SUSPENDED,
+                                 VMSTATE_SOFT_RESETTING_LS,  VMSTATE_RUNNING_LS);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    /*
+     * Check the state.
+     */
+    VMSTATE enmVMState = VMR3GetState(pVM);
+    AssertLogRelMsgReturn(   enmVMState == VMSTATE_SOFT_RESETTING
+                          || enmVMState == VMSTATE_SOFT_RESETTING_LS,
+                          ("%s\n", VMR3GetStateName(enmVMState)),
+                          VERR_VM_UNEXPECTED_UNSTABLE_STATE);
+
+    /*
+     * EMT(0) does the full cleanup *after* all the other EMTs has been
+     * thru here and been told to enter the EMSTATE_WAIT_SIPI state.
+     *
+     * Because there are per-cpu reset routines and order may/is important,
+     * the following sequence looks a bit ugly...
+     */
+
+    /* Reset the VCpu state. */
+    VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED);
+
+    /*
+     * Soft reset the VM components.
+     */
+    if (pVCpu->idCpu == 0)
+    {
+#ifdef VBOX_WITH_REM
+        REMR3Reset(pVM);
+#endif
+        PDMR3SoftReset(pVM, fResetFlags);
+        TRPMR3Reset(pVM);
+        CPUMR3Reset(pVM);               /* This must come *after* PDM (due to APIC base MSR caching). */
+        EMR3Reset(pVM);
+        HMR3Reset(pVM);                 /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */
+
+        /*
+         * Since EMT(0) is the last to go thru here, it will advance the state.
+         * (Unlike vmR3HardReset we won't be doing any suspending of live
+         * migration VMs here since memory is unchanged.)
+         */
+        PUVM pUVM = pVM->pUVM;
+        RTCritSectEnter(&pUVM->vm.s.AtStateCritSect);
+        enmVMState = pVM->enmVMState;
+        if (enmVMState == VMSTATE_SOFT_RESETTING)
+        {
+            if (pUVM->vm.s.enmPrevVMState == VMSTATE_SUSPENDED)
+                vmR3SetStateLocked(pVM, pUVM, VMSTATE_SUSPENDED, VMSTATE_SOFT_RESETTING);
+            else
+                vmR3SetStateLocked(pVM, pUVM, VMSTATE_RUNNING,   VMSTATE_SOFT_RESETTING);
+        }
+        else
+            vmR3SetStateLocked(pVM, pUVM, VMSTATE_RUNNING_LS, VMSTATE_SOFT_RESETTING_LS);
+        RTCritSectLeave(&pUVM->vm.s.AtStateCritSect);
+    }
+
+    return VINF_EM_RESCHEDULE;
+}
+
+
+/**
+ * EMT rendezvous worker for VMR3Reset and VMR3ResetFF.
  *
  * This is called by the emulation threads as a response to the reset request
@@ -2752,5 +2840,5 @@
  * @param   pvUser          Ignored.
  */
-static DECLCALLBACK(VBOXSTRICTRC) vmR3Reset(PVM pVM, PVMCPU pVCpu, void *pvUser)
+static DECLCALLBACK(VBOXSTRICTRC) vmR3HardReset(PVM pVM, PVMCPU pVCpu, void *pvUser)
 {
     Assert(!pvUser); NOREF(pvUser);
@@ -2762,5 +2850,5 @@
     if (pVCpu->idCpu == pVM->cCpus - 1)
     {
-        int rc = vmR3TrySetState(pVM, "VMR3Reset", 3,
+        int rc = vmR3TrySetState(pVM, "vmR3HardReset", 3,
                                  VMSTATE_RESETTING,     VMSTATE_RUNNING,
                                  VMSTATE_RESETTING,     VMSTATE_SUSPENDED,
@@ -2871,4 +2959,53 @@
 
 /**
+ * Internal worker for VMR3Reset, VMR3ResetFF, VMR3TripleFault.
+ *
+ * @returns VBox status code.
+ * @param   pVM             The cross context VM structure.
+ * @param   fHardReset      Whether it's a hard reset or not.
+ * @param   fResetFlags     The reset flags (PDMVMRESET_F_XXX).
+ */
+static VBOXSTRICTRC vmR3ResetCommon(PVM pVM, bool fHardReset, uint32_t fResetFlags)
+{
+    LogFlow(("vmR3ResetCommon: fHardReset=%RTbool fResetFlags=%#x\n", fHardReset, fResetFlags));
+    int rc;
+    if (fHardReset)
+    {
+        /*
+         * Hard reset.
+         */
+        /* Check whether we're supposed to power off instead of resetting. */
+        if (pVM->vm.s.fPowerOffInsteadOfReset)
+        {
+            PUVM pUVM = pVM->pUVM;
+            if (   pUVM->pVmm2UserMethods
+                && pUVM->pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff)
+                pUVM->pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff(pUVM->pVmm2UserMethods, pUVM);
+            return VMR3PowerOff(pUVM);
+        }
+
+        /* Gather all the EMTs to make sure there are no races before changing
+           the VM state. */
+        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
+                                vmR3HardReset, NULL);
+    }
+    else
+    {
+        /*
+         * Soft reset. Since we only support this with a single CPU active,
+         * we must be on EMT #0 here.
+         */
+        VM_ASSERT_EMT0(pVM);
+        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
+                                vmR3SoftReset, &fResetFlags);
+    }
+
+    LogFlow(("vmR3ResetCommon: returns %Rrc\n", rc));
+    return rc;
+}
+
+
+
+/**
  * Reset the current VM.
  *
@@ -2883,20 +3020,53 @@
     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
 
-    if (pVM->vm.s.fPowerOffInsteadOfReset)
-    {
-        if (   pUVM->pVmm2UserMethods
-            && pUVM->pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff)
-            pUVM->pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff(pUVM->pVmm2UserMethods, pUVM);
-        return VMR3PowerOff(pUVM);
-    }
-
-    /*
-     * Gather all the EMTs to make sure there are no races before
-     * changing the VM state.
-     */
-    int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
-                                vmR3Reset, NULL);
-    LogFlow(("VMR3Reset: returns %Rrc\n", rc));
-    return rc;
+    return VBOXSTRICTRC_VAL(vmR3ResetCommon(pVM, true, 0));
+}
+
+
+/**
+ * Handle the reset force flag or triple fault.
+ *
+ * This handles both soft and hard resets (see PDMVMRESET_F_XXX).
+ *
+ * @returns VBox status code.
+ * @param   pUVM    The VM to reset.
+ * @thread  EMT
+ *
+ * @remarks Caller is expected to clear the reset FF.
+ */
+VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetFF(PVM pVM)
+{
+    LogFlow(("VMR3ResetFF:\n"));
+
+    /*
+     * First consult the firmware on whether this is a hard or soft reset.
+     */
+    uint32_t fResetFlags;
+    bool fHardReset = PDMR3GetResetInfo(pVM, 0 /*fOverride*/, &fResetFlags);
+    return vmR3ResetCommon(pVM, fHardReset, fResetFlags);
+}
+
+
+/**
+ * For handling a CPU reset on triple fault.
+ *
+ * According to one mainboard manual, a CPU triple fault causes the 286 CPU to
+ * send a SHUTDOWN signal to the chipset.  The chipset responds by sending a
+ * RESET signal to the CPU.  So, it should be very similar to a soft/warm reset.
+ *
+ * @returns VBox status code.
+ * @param   pUVM    The VM to reset.
+ * @thread  EMT
+ */
+VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetTripleFault(PVM pVM)
+{
+    LogFlow(("VMR3ResetTripleFault:\n"));
+
+    /*
+     * First consult the firmware on whether this is a hard or soft reset.
+     */
+    uint32_t fResetFlags;
+    bool fHardReset = PDMR3GetResetInfo(pVM, PDMVMRESET_F_TRIPLE_FAULT, &fResetFlags);
+    return vmR3ResetCommon(pVM, fHardReset, fResetFlags);
 }
 
@@ -3078,4 +3248,6 @@
         case VMSTATE_RESETTING:         return "RESETTING";
         case VMSTATE_RESETTING_LS:      return "RESETTING_LS";
+        case VMSTATE_SOFT_RESETTING:    return "SOFT_RESETTING";
+        case VMSTATE_SOFT_RESETTING_LS: return "SOFT_RESETTING_LS";
         case VMSTATE_SUSPENDED:         return "SUSPENDED";
         case VMSTATE_SUSPENDED_LS:      return "SUSPENDED_LS";
@@ -3155,4 +3327,5 @@
                             || enmStateNew == VMSTATE_SUSPENDING
                             || enmStateNew == VMSTATE_RESETTING
+                            || enmStateNew == VMSTATE_SOFT_RESETTING
                             || enmStateNew == VMSTATE_RUNNING_LS
                             || enmStateNew == VMSTATE_RUNNING_FT
@@ -3168,4 +3341,5 @@
                             || enmStateNew == VMSTATE_SUSPENDING_EXT_LS
                             || enmStateNew == VMSTATE_RESETTING_LS
+                            || enmStateNew == VMSTATE_SOFT_RESETTING_LS
                             || enmStateNew == VMSTATE_RUNNING
                             || enmStateNew == VMSTATE_DEBUGGING_LS
@@ -3186,6 +3360,15 @@
             break;
 
+        case VMSTATE_SOFT_RESETTING:
+            AssertMsgReturn(enmStateNew == VMSTATE_RUNNING, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
+            break;
+
         case VMSTATE_RESETTING_LS:
             AssertMsgReturn(   enmStateNew == VMSTATE_SUSPENDING_LS
+                            , ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
+            break;
+
+        case VMSTATE_SOFT_RESETTING_LS:
+            AssertMsgReturn(   enmStateNew == VMSTATE_RUNNING_LS
                             , ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
             break;
@@ -3211,4 +3394,5 @@
                             || enmStateNew == VMSTATE_SAVING
                             || enmStateNew == VMSTATE_RESETTING
+                            || enmStateNew == VMSTATE_SOFT_RESETTING
                             || enmStateNew == VMSTATE_RESUMING
                             || enmStateNew == VMSTATE_LOADING
Index: /trunk/src/VBox/VMM/VMMR3/VMEmt.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/VMEmt.cpp	(revision 60403)
+++ /trunk/src/VBox/VMM/VMMR3/VMEmt.cpp	(revision 60404)
@@ -195,5 +195,5 @@
                  * Service a delayed reset request.
                  */
-                rc = VMR3Reset(pVM->pUVM);
+                rc = VBOXSTRICTRC_VAL(VMR3ResetFF(pVM));
                 VM_FF_CLEAR(pVM, VM_FF_RESET);
                 Log(("vmR3EmulationThread: Reset rc=%Rrc, VM state %s -> %s\n", rc, VMR3GetStateName(enmBefore), VMR3GetStateName(pVM->enmVMState)));
Index: /trunk/src/VBox/VMM/include/PDMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 60403)
+++ /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 60404)
@@ -676,4 +676,21 @@
 /** Maximum number of PCI busses for a VM. */
 #define PDM_PCI_BUSSES_MAX 8
+
+
+#ifdef IN_RING3
+/**
+ * PDM registered firmware device.
+ */
+typedef struct PDMFW
+{
+    /** Pointer to the firmware device instance. */
+    PPDMDEVINSR3                    pDevIns;
+    /** Copy of the registration structure. */
+    PDMFWREG                        Reg;
+} PDMFW;
+/** Pointer to a firmware instance. */
+typedef PDMFW *PPDMFW;
+#endif
+
 
 /**
@@ -1085,7 +1102,6 @@
     /** List of registered drivers. (FIFO) */
     R3PTRTYPE(PPDMDRV)              pDrvs;
-#if HC_ARCH_BITS == 32
-    RTR3PTR                         uPadding0; /**< Alignment padding. */
-#endif
+    /** The registered firmware device (can be NULL). */
+    R3PTRTYPE(PPDMFW)               pFirmware;
     /** PCI Buses. */
     PDMPCIBUS                       aPciBuses[PDM_PCI_BUSSES_MAX];
@@ -1122,4 +1138,9 @@
     uint32_t volatile               uIrqTag;
 
+    /** Pending reset flags (PDMVMRESET_F_XXX). */
+    uint32_t volatile               fResetFlags;
+    /** Alignment padding. */
+    uint32_t volatile               u32Padding;
+
     /** The tracing ID of the next device instance.
      *
@@ -1217,4 +1238,5 @@
 extern const PDMAPICHLPR3   g_pdmR3DevApicHlp;
 extern const PDMIOAPICHLPR3 g_pdmR3DevIoApicHlp;
+extern const PDMFWHLPR3     g_pdmR3DevFirmwareHlp;
 extern const PDMPCIHLPR3    g_pdmR3DevPciHlp;
 extern const PDMDMACHLP     g_pdmR3DevDmacHlp;
