Index: trunk/src/VBox/Debugger/DBGCCmdHlp.cpp
===================================================================
--- trunk/src/VBox/Debugger/DBGCCmdHlp.cpp	(revision 86097)
+++ trunk/src/VBox/Debugger/DBGCCmdHlp.cpp	(revision 86098)
@@ -1347,4 +1347,97 @@
 
 /**
+ * @interface_method_impl{DBGCCMDHLP,pfnRegPrintf}
+ */
+static DECLCALLBACK(int) dbgcHlpRegPrintf(PDBGCCMDHLP pCmdHlp, VMCPUID idCpu, int f64BitMode, bool fTerse)
+{
+    PDBGC pDbgc   = DBGC_CMDHLP2DBGC(pCmdHlp);
+    char  szDisAndRegs[8192];
+    int   rc;
+
+    if (f64BitMode < 0)
+        f64BitMode = DBGFR3CpuIsIn64BitCode(pDbgc->pUVM, idCpu);
+
+    if (fTerse)
+    {
+        if (f64BitMode)
+            rc = DBGFR3RegPrintf(pDbgc->pUVM, idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs),
+                                 "u %016VR{rip} L 0\n"
+                                 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
+                                 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
+                                 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
+                                 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
+                                 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
+                                 "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss}                     rflags=%08VR{rflags}\n");
+        else
+            rc = DBGFR3RegPrintf(pDbgc->pUVM, idCpu, szDisAndRegs, sizeof(szDisAndRegs),
+                                 "u %04VR{cs}:%08VR{eip} L 0\n"
+                                 "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n"
+                                 "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n"
+                                 "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss}               eflags=%08VR{eflags}\n");
+    }
+    else
+    {
+        if (f64BitMode)
+            rc = DBGFR3RegPrintf(pDbgc->pUVM, idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs),
+                                 "u %016VR{rip} L 0\n"
+                                 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
+                                 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
+                                 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
+                                 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
+                                 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
+                                 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n"
+                                 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n"
+                                 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n"
+                                 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n"
+                                 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n"
+                                 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n"
+                                 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n"
+                                 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n"
+                                 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim}  idtr=%016VR{idtr_base}:%04VR{idtr_lim}  rflags=%08VR{rflags}\n"
+                                 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n"
+                                 "tr  ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n"
+                                 "    sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
+                                 "        efer=%016VR{efer}\n"
+                                 "         pat=%016VR{pat}\n"
+                                 "     sf_mask=%016VR{sf_mask}\n"
+                                 "krnl_gs_base=%016VR{krnl_gs_base}\n"
+                                 "       lstar=%016VR{lstar}\n"
+                                 "        star=%016VR{star} cstar=%016VR{cstar}\n"
+                                 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
+                                 );
+        else
+            rc = DBGFR3RegPrintf(pDbgc->pUVM, idCpu, szDisAndRegs, sizeof(szDisAndRegs),
+                                 "u %04VR{cs}:%08VR{eip} L 0\n"
+                                 "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n"
+                                 "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n"
+                                 "cs={%04VR{cs} base=%08VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} dr0=%08VR{dr0} dr1=%08VR{dr1}\n"
+                                 "ds={%04VR{ds} base=%08VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} dr2=%08VR{dr2} dr3=%08VR{dr3}\n"
+                                 "es={%04VR{es} base=%08VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} dr6=%08VR{dr6} dr7=%08VR{dr7}\n"
+                                 "fs={%04VR{fs} base=%08VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr0=%08VR{cr0} cr2=%08VR{cr2}\n"
+                                 "gs={%04VR{gs} base=%08VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr3=%08VR{cr3} cr4=%08VR{cr4}\n"
+                                 "ss={%04VR{ss} base=%08VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}} cr8=%08VR{cr8}\n"
+                                 "gdtr=%08VR{gdtr_base}:%04VR{gdtr_lim}  idtr=%08VR{idtr_base}:%04VR{idtr_lim}  eflags=%08VR{eflags}\n"
+                                 "ldtr={%04VR{ldtr} base=%08VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%04VR{ldtr_attr}}\n"
+                                 "tr  ={%04VR{tr} base=%08VR{tr_base} limit=%08VR{tr_lim} flags=%04VR{tr_attr}}\n"
+                                 "sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
+                                 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
+                                 );
+    }
+    if (RT_FAILURE(rc))
+        return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegPrintf failed");
+    char *pszRegs = strchr(szDisAndRegs, '\n');
+    *pszRegs++ = '\0';
+    rc = DBGCCmdHlpPrintf(pCmdHlp, "%s", pszRegs);
+
+    /*
+     * Disassemble one instruction at cs:[r|e]ip.
+     */
+    if (!f64BitMode && strstr(pszRegs, " vm ")) /* a bit ugly... */
+        return pCmdHlp->pfnExec(pCmdHlp, "uv86 %s", szDisAndRegs + 2);
+    return pCmdHlp->pfnExec(pCmdHlp, "%s", szDisAndRegs);
+}
+
+
+/**
  * Initializes the Command Helpers for a DBGC instance.
  *
@@ -1376,4 +1469,5 @@
     pDbgc->CmdHlp.pfnGetCurrentCpu      = dbgcHlpGetCurrentCpu;
     pDbgc->CmdHlp.pfnGetCpuMode         = dbgcHlpGetCpuMode;
+    pDbgc->CmdHlp.pfnRegPrintf          = dbgcHlpRegPrintf;
     pDbgc->CmdHlp.u32EndMarker          = DBGCCMDHLP_MAGIC;
 }
Index: trunk/src/VBox/Debugger/DBGCCommands.cpp
===================================================================
--- trunk/src/VBox/Debugger/DBGCCommands.cpp	(revision 86097)
+++ trunk/src/VBox/Debugger/DBGCCommands.cpp	(revision 86098)
@@ -233,4 +233,11 @@
     {  1,           1,          DBGCVAR_CAT_SYMBOL,     0,                              "var",          "Variable name." },
     {  1,           1,          DBGCVAR_CAT_ANY,        0,                              "value",        "Value to assign to the variable." },
+};
+
+/** 'stop' arguments */
+static const DBGCVARDESC    g_aArgStop[] =
+{
+    /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
+    {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "idCpu",        "CPU ID." },
 };
 
@@ -298,5 +305,5 @@
     { "set",        2,        2,        &g_aArgSet[0],       RT_ELEMENTS(g_aArgSet),       0, dbgcCmdSet,       "<var> <value>",        "Sets a global variable." },
     { "showvars",   0,        0,        NULL,                0,                            0, dbgcCmdShowVars,  "",                     "List all the defined variables." },
-    { "stop",       0,        0,        NULL,                0,                            0, dbgcCmdStop,      "",                     "Stop execution." },
+    { "stop",       0,        1,        &g_aArgStop[0],      RT_ELEMENTS(g_aArgStop),      0, dbgcCmdStop,      "[idCpu]",              "Stop execution either of all or the specified CPU. (The latter is not recommended unless you know exactly what you're doing.)" },
     { "unload",     1,       ~0U,       &g_aArgUnload[0],    RT_ELEMENTS(g_aArgUnload),    0, dbgcCmdUnload,    "<modname1> [modname2..N]", "Unloads one or more modules in the current address space." },
     { "unloadplugin", 1,     ~0U,       &g_aArgPlugIn[0],    RT_ELEMENTS(g_aArgPlugIn),    0, dbgcCmdUnloadPlugIn, "<plugin1> [plugin2..N]", "Unloads one or more plugins." },
@@ -938,20 +945,38 @@
 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
 {
-    /*
-     * Check if the VM is halted or not before trying to halt it.
-     */
-    int rc;
-    if (DBGFR3IsHalted(pUVM))
-        rc = DBGCCmdHlpPrintf(pCmdHlp, "warning: The VM is already halted...\n");
+    DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
+
+    /*
+     * Parse arguments.
+     */
+    VMCPUID idCpu = VMCPUID_ALL;
+    if (cArgs == 1)
+    {
+        VMCPUID cCpus = DBGFR3CpuGetCount(pUVM);
+        if (paArgs[0].u.u64Number >= cCpus)
+            return DBGCCmdHlpFail(pCmdHlp, pCmd, "idCpu %RU64 is out of range! Highest valid ID is %u.\n",
+                                  paArgs[0].u.u64Number, cCpus - 1);
+        idCpu = (VMCPUID)paArgs[0].u.u64Number;
+    }
     else
-    {
-        rc = DBGFR3Halt(pUVM);
-        if (RT_SUCCESS(rc))
+        Assert(cArgs == 0);
+
+    /*
+     * Try halt the VM or VCpu.
+     */
+    int rc = DBGFR3Halt(pUVM, idCpu);
+    if (RT_SUCCESS(rc))
+    {
+        Assert(rc == VINF_SUCCESS || rc == VWRN_DBGF_ALREADY_HALTED);
+        if (rc != VWRN_DBGF_ALREADY_HALTED)
             rc = VWRN_DBGC_CMD_PENDING;
+        else if (idCpu == VMCPUID_ALL)
+            rc = DBGCCmdHlpPrintf(pCmdHlp, "warning: The VM is already halted...\n");
         else
-            rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
-    }
-
-    NOREF(pCmd); NOREF(paArgs); NOREF(cArgs);
+            rc = DBGCCmdHlpPrintf(pCmdHlp, "warning: CPU %u is already halted...\n", idCpu);
+    }
+    else
+        rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
+
     return rc;
 }
Index: trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp
===================================================================
--- trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp	(revision 86097)
+++ trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp	(revision 86098)
@@ -237,4 +237,12 @@
     {  1,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address where to write." },
     {  1,           ~0U,        DBGCVAR_CAT_NUMBER,     0,                              "value",        "Value to write." },
+};
+
+
+/** 'g' arguments. */
+static const DBGCVARDESC    g_aArgGo[] =
+{
+    /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
+    {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "idCpu",        "CPU ID." },
 };
 
@@ -425,5 +433,5 @@
     { "ed",         2,        2,        &g_aArgEditMem[0],  RT_ELEMENTS(g_aArgEditMem),     0,       dbgcCmdEditMem,     "<addr> <value>",       "Write a 4-byte value to memory." },
     { "eq",         2,        2,        &g_aArgEditMem[0],  RT_ELEMENTS(g_aArgEditMem),     0,       dbgcCmdEditMem,     "<addr> <value>",       "Write a 8-byte value to memory." },
-    { "g",          0,        0,        NULL,               0,                              0,       dbgcCmdGo,          "",                     "Continue execution." },
+    { "g",          0,        1,        &g_aArgGo[0],       RT_ELEMENTS(g_aArgGo),          0,       dbgcCmdGo,          "[idCpu]",              "Continue execution of all or the specified CPU. (The latter is not recommended unless you know exactly what you're doing.)" },
     { "gu",         0,        0,        NULL,               0,                              0,       dbgcCmdGoUp,        "",                     "Go up - continue execution till after return." },
     { "k",          0,        0,        NULL,               0,                              0,       dbgcCmdStack,       "",                     "Callstack." },
@@ -651,15 +659,32 @@
 
     /*
-     * Check if the VM is halted or not before trying to resume it.
-     */
-    if (!DBGFR3IsHalted(pUVM))
-        return DBGCCmdHlpFail(pCmdHlp, pCmd, "The VM is already running");
-
-    int rc = DBGFR3Resume(pUVM);
-    if (RT_FAILURE(rc))
-        return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3Resume");
-
-    NOREF(paArgs); NOREF(cArgs);
-    return VINF_SUCCESS;
+     * Parse arguments.
+     */
+    VMCPUID idCpu = VMCPUID_ALL;
+    if (cArgs == 1)
+    {
+        VMCPUID cCpus = DBGFR3CpuGetCount(pUVM);
+        if (paArgs[0].u.u64Number >= cCpus)
+            return DBGCCmdHlpFail(pCmdHlp, pCmd, "idCpu %RU64 is out of range! Highest valid ID is %u.\n",
+                                  paArgs[0].u.u64Number, cCpus - 1);
+        idCpu = (VMCPUID)paArgs[0].u.u64Number;
+    }
+    else
+        Assert(cArgs == 0);
+
+    /*
+     * Try resume the VM or CPU.
+     */
+    int rc = DBGFR3Resume(pUVM, idCpu);
+    if (RT_SUCCESS(rc))
+    {
+        Assert(rc == VINF_SUCCESS || rc == VWRN_DBGF_ALREADY_RUNNING);
+        if (rc != VWRN_DBGF_ALREADY_RUNNING)
+            return VINF_SUCCESS;
+        if (idCpu == VMCPUID_ALL)
+            return DBGCCmdHlpFail(pCmdHlp, pCmd, "The VM is already running");
+        return DBGCCmdHlpFail(pCmdHlp, pCmd, "CPU %u is already running", idCpu);
+    }
+    return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3Resume");
 }
 
@@ -2466,85 +2491,5 @@
                               || (   strcmp(pCmd->pszCmd, "rg32") != 0
                                   && DBGFR3CpuIsIn64BitCode(pUVM, pDbgc->idCpu));
-        char        szDisAndRegs[8192];
-        int         rc;
-
-        if (pDbgc->fRegTerse)
-        {
-            if (f64BitMode)
-                rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs),
-                                     "u %016VR{rip} L 0\n"
-                                     "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
-                                     "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
-                                     "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
-                                     "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
-                                     "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
-                                     "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss}                     rflags=%08VR{rflags}\n");
-            else
-                rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, szDisAndRegs, sizeof(szDisAndRegs),
-                                     "u %04VR{cs}:%08VR{eip} L 0\n"
-                                     "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n"
-                                     "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n"
-                                     "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss}               eflags=%08VR{eflags}\n");
-        }
-        else
-        {
-            if (f64BitMode)
-                rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs),
-                                     "u %016VR{rip} L 0\n"
-                                     "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
-                                     "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
-                                     "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
-                                     "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
-                                     "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
-                                     "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n"
-                                     "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n"
-                                     "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n"
-                                     "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n"
-                                     "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n"
-                                     "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n"
-                                     "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n"
-                                     "dr6=%016VR{dr6} dr7=%016VR{dr7}\n"
-                                     "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim}  idtr=%016VR{idtr_base}:%04VR{idtr_lim}  rflags=%08VR{rflags}\n"
-                                     "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n"
-                                     "tr  ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n"
-                                     "    sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
-                                     "        efer=%016VR{efer}\n"
-                                     "         pat=%016VR{pat}\n"
-                                     "     sf_mask=%016VR{sf_mask}\n"
-                                     "krnl_gs_base=%016VR{krnl_gs_base}\n"
-                                     "       lstar=%016VR{lstar}\n"
-                                     "        star=%016VR{star} cstar=%016VR{cstar}\n"
-                                     "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
-                                     );
-            else
-                rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, szDisAndRegs, sizeof(szDisAndRegs),
-                                     "u %04VR{cs}:%08VR{eip} L 0\n"
-                                     "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n"
-                                     "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n"
-                                     "cs={%04VR{cs} base=%08VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} dr0=%08VR{dr0} dr1=%08VR{dr1}\n"
-                                     "ds={%04VR{ds} base=%08VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} dr2=%08VR{dr2} dr3=%08VR{dr3}\n"
-                                     "es={%04VR{es} base=%08VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} dr6=%08VR{dr6} dr7=%08VR{dr7}\n"
-                                     "fs={%04VR{fs} base=%08VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr0=%08VR{cr0} cr2=%08VR{cr2}\n"
-                                     "gs={%04VR{gs} base=%08VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr3=%08VR{cr3} cr4=%08VR{cr4}\n"
-                                     "ss={%04VR{ss} base=%08VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}} cr8=%08VR{cr8}\n"
-                                     "gdtr=%08VR{gdtr_base}:%04VR{gdtr_lim}  idtr=%08VR{idtr_base}:%04VR{idtr_lim}  eflags=%08VR{eflags}\n"
-                                     "ldtr={%04VR{ldtr} base=%08VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%04VR{ldtr_attr}}\n"
-                                     "tr  ={%04VR{tr} base=%08VR{tr_base} limit=%08VR{tr_lim} flags=%04VR{tr_attr}}\n"
-                                     "sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
-                                     "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
-                                     );
-        }
-        if (RT_FAILURE(rc))
-            return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegPrintf failed");
-        char *pszRegs = strchr(szDisAndRegs, '\n');
-        *pszRegs++ = '\0';
-        rc = DBGCCmdHlpPrintf(pCmdHlp, "%s", pszRegs);
-
-        /*
-         * Disassemble one instruction at cs:[r|e]ip.
-         */
-        if (!f64BitMode && strstr(pszRegs, " vm ")) /* a bit ugly... */
-            return pCmdHlp->pfnExec(pCmdHlp, "uv86 %s", szDisAndRegs + 2);
-        return pCmdHlp->pfnExec(pCmdHlp, "%s", szDisAndRegs);
+        return DBGCCmdHlpRegPrintf(pCmdHlp, pDbgc->idCpu, f64BitMode, pDbgc->fRegTerse);
     }
     return dbgcCmdRegCommon(pCmd, pCmdHlp, pUVM, paArgs, cArgs, "");
Index: trunk/src/VBox/Debugger/DBGCGdbRemoteStub.cpp
===================================================================
--- trunk/src/VBox/Debugger/DBGCGdbRemoteStub.cpp	(revision 86097)
+++ trunk/src/VBox/Debugger/DBGCGdbRemoteStub.cpp	(revision 86098)
@@ -1565,6 +1565,6 @@
         case 'c':
         {
-            if (DBGFR3IsHalted(pThis->Dbgc.pUVM))
-                DBGFR3Resume(pThis->Dbgc.pUVM);
+            if (DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
+                DBGFR3Resume(pThis->Dbgc.pUVM, VMCPUID_ALL);
             break;
         }
@@ -1581,6 +1581,6 @@
         case 't':
         {
-            if (!DBGFR3IsHalted(pThis->Dbgc.pUVM))
-                rc = DBGFR3Halt(pThis->Dbgc.pUVM);
+            if (!DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
+                rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
             /* The reply will be send in the event loop. */
             break;
@@ -1732,6 +1732,6 @@
             case 'c': /* Continue, no response */
             {
-                if (DBGFR3IsHalted(pThis->Dbgc.pUVM))
-                    DBGFR3Resume(pThis->Dbgc.pUVM);
+                if (DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
+                    DBGFR3Resume(pThis->Dbgc.pUVM, VMCPUID_ALL);
                 break;
             }
@@ -2174,6 +2174,6 @@
         {
             /* Stop target and send packet to indicate the target has stopped. */
-            if (!DBGFR3IsHalted(pThis->Dbgc.pUVM))
-                rc = DBGFR3Halt(pThis->Dbgc.pUVM);
+            if (!DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
+                rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
             /* The reply will be send in the event loop. */
         }
@@ -2403,5 +2403,5 @@
                     break;
             }
-            if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pUVM))
+            if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pUVM, VMCPUID_ALL))
             {
                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
@@ -2589,9 +2589,9 @@
              * Wait for a debug event.
              */
-            PCDBGFEVENT pEvent;
-            rc = DBGFR3EventWait(pThis->Dbgc.pUVM, 32, &pEvent);
+            DBGFEVENT Event;
+            rc = DBGFR3EventWait(pThis->Dbgc.pUVM, 32, &Event);
             if (RT_SUCCESS(rc))
             {
-                rc = dbgcGdbStubCtxProcessEvent(pThis, pEvent);
+                rc = dbgcGdbStubCtxProcessEvent(pThis, &Event);
                 if (RT_FAILURE(rc))
                     break;
@@ -2840,6 +2840,6 @@
         //dbgcRunInitScripts(pDbgc); Not yet
 
-        if (!DBGFR3IsHalted(pThis->Dbgc.pUVM))
-            rc = DBGFR3Halt(pThis->Dbgc.pUVM);
+        if (!DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
+            rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
 
         /*
Index: trunk/src/VBox/Debugger/DBGConsole.cpp
===================================================================
--- trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 86097)
+++ trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 86098)
@@ -648,4 +648,5 @@
     bool fPrintPrompt = true;
     int rc = VINF_SUCCESS;
+    VMCPUID const idCpuSaved = pDbgc->idCpu;
     switch (pEvent->enmType)
     {
@@ -655,8 +656,10 @@
         case DBGFEVENT_HALT_DONE:
         {
-            rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
-                                         pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
+            /** @todo add option to suppress this on CPUs that aren't selected (like
+             *        fRegTerse). */
+            rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: CPU %u has halted! (%s)\n",
+                                         pEvent->idCpu, pEvent->idCpu, dbgcGetEventCtx(pEvent->enmCtx));
             if (RT_SUCCESS(rc))
-                rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
+                rc = DBGCCmdHlpRegPrintf(&pDbgc->CmdHlp, pEvent->idCpu, -1, pDbgc->fRegTerse);
             break;
         }
@@ -668,8 +671,9 @@
         case DBGFEVENT_FATAL_ERROR:
         {
-            rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
-                                         dbgcGetEventCtx(pEvent->enmCtx));
+            pDbgc->idCpu = pEvent->idCpu;
+            rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event/%u: Fatal error! (%s)\n",
+                                         pEvent->idCpu, dbgcGetEventCtx(pEvent->enmCtx));
             if (RT_SUCCESS(rc))
-                rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
+                rc = DBGCCmdHlpRegPrintf(&pDbgc->CmdHlp, pEvent->idCpu, -1, pDbgc->fRegTerse);
             break;
         }
@@ -680,20 +684,21 @@
         case DBGFEVENT_BREAKPOINT_HYPER:
         {
+            pDbgc->idCpu = pEvent->idCpu;
             rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
             switch (rc)
             {
                 case VERR_DBGC_BP_NOT_FOUND:
-                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
-                                                 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
+                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: Unknown breakpoint %u! (%s)\n",
+                                                 pEvent->idCpu, pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
                     break;
 
                 case VINF_DBGC_BP_NO_COMMAND:
-                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
-                                                 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
+                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: Breakpoint %u! (%s)\n",
+                                                 pEvent->idCpu, pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
                     break;
 
                 case VINF_BUFFER_OVERFLOW:
-                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
-                                                 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
+                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: Breakpoint %u! Command too long to execute! (%s)\n",
+                                                 pEvent->idCpu, pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
                     break;
 
@@ -701,7 +706,7 @@
                     break;
             }
-            if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pUVM))
+            if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pUVM, pEvent->idCpu))
             {
-                rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
+                rc = DBGCCmdHlpRegPrintf(&pDbgc->CmdHlp, pEvent->idCpu, -1, pDbgc->fRegTerse);
 
                 /* Set the resume flag to ignore the breakpoint when resuming execution. */
@@ -710,4 +715,6 @@
                     rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r eflags.rf = 1");
             }
+            else
+                pDbgc->idCpu = idCpuSaved;
             break;
         }
@@ -716,6 +723,7 @@
         case DBGFEVENT_STEPPED_HYPER:
         {
-            if (!pDbgc->cMultiStepsLeft)
-                rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
+            if (!pDbgc->cMultiStepsLeft || pEvent->idCpu != idCpuSaved)
+                rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: Single step! (%s)\n",
+                                             pEvent->idCpu, dbgcGetEventCtx(pEvent->enmCtx));
             else
                 pDbgc->cMultiStepsLeft -= 1;
@@ -723,5 +731,5 @@
             {
                 if (pDbgc->fStepTraceRegs)
-                    rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
+                    rc = DBGCCmdHlpRegPrintf(&pDbgc->CmdHlp, pEvent->idCpu, -1, pDbgc->fRegTerse);
                 else
                 {
@@ -739,5 +747,5 @@
 
             /* If multi-stepping, take the next step: */
-            if (pDbgc->cMultiStepsLeft > 0)
+            if (pDbgc->cMultiStepsLeft > 0 && pEvent->idCpu != idCpuSaved)
             {
                 int rc2 = DBGFR3StepEx(pDbgc->pUVM, pDbgc->idCpu, DBGF_STEP_F_INTO, NULL, NULL, 0, pDbgc->uMultiStepStrideLength);
@@ -747,4 +755,6 @@
                     DBGCCmdHlpFailRc(&pDbgc->CmdHlp, pDbgc->pMultiStepCmd, rc2, "DBGFR3StepEx(,,DBGF_STEP_F_INTO,) failed");
             }
+            else
+                pDbgc->idCpu = pEvent->idCpu;
             break;
         }
@@ -752,14 +762,16 @@
         case DBGFEVENT_ASSERTION_HYPER:
         {
+            pDbgc->idCpu = pEvent->idCpu;
             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
-                                         "\ndbgf event: Hypervisor Assertion! (%s)\n"
+                                         "\ndbgf event/%u: Hypervisor Assertion! (%s)\n"
                                          "%s"
                                          "%s"
                                          "\n",
+                                         pEvent->idCpu,
                                          dbgcGetEventCtx(pEvent->enmCtx),
                                          pEvent->u.Assert.pszMsg1,
                                          pEvent->u.Assert.pszMsg2);
             if (RT_SUCCESS(rc))
-                rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
+                rc = DBGCCmdHlpRegPrintf(&pDbgc->CmdHlp, pEvent->idCpu, -1, pDbgc->fRegTerse);
             break;
         }
@@ -767,10 +779,12 @@
         case DBGFEVENT_DEV_STOP:
         {
+            pDbgc->idCpu = pEvent->idCpu;
             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
                                          "\n"
-                                         "dbgf event: DBGFSTOP (%s)\n"
+                                         "dbgf event/%u: DBGFSTOP (%s)\n"
                                          "File:     %s\n"
                                          "Line:     %d\n"
                                          "Function: %s\n",
+                                         pEvent->idCpu,
                                          dbgcGetEventCtx(pEvent->enmCtx),
                                          pEvent->u.Src.pszFile,
@@ -782,5 +796,5 @@
                                              pEvent->u.Src.pszMessage);
             if (RT_SUCCESS(rc))
-                rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
+                rc = DBGCCmdHlpRegPrintf(&pDbgc->CmdHlp, pEvent->idCpu, -1, pDbgc->fRegTerse);
             break;
         }
@@ -816,6 +830,6 @@
                     Assert(pEvtDesc->pszDesc);
                     Assert(pEvent->u.Generic.cArgs == 1);
-                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s no %#llx! (%s)\n",
-                                                 pEvtDesc->pszDesc, pEvent->u.Generic.auArgs[0], pEvtDesc->pszName);
+                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: %s no %#llx! (%s)\n",
+                                                 pEvent->idCpu, pEvtDesc->pszDesc, pEvent->u.Generic.auArgs[0], pEvtDesc->pszName);
                 }
                 else if (pEvtDesc->fFlags & DBGCSXEVT_F_BUGCHECK)
@@ -826,7 +840,7 @@
                                          pEvent->u.Generic.auArgs[1], pEvent->u.Generic.auArgs[2],
                                          pEvent->u.Generic.auArgs[3], pEvent->u.Generic.auArgs[4]);
-                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s %s%s!\n%s", pEvtDesc->pszName,
-                                                 pEvtDesc->pszDesc ? "- " : "", pEvtDesc->pszDesc ? pEvtDesc->pszDesc : "",
-                                                 szDetails);
+                    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: %s %s%s!\n%s", pEvent->idCpu,
+                                                 pEvtDesc->pszName, pEvtDesc->pszDesc ? "- " : "",
+                                                 pEvtDesc->pszDesc ? pEvtDesc->pszDesc : "", szDetails);
                 }
                 else if (   (pEvtDesc->fFlags & DBGCSXEVT_F_TAKE_ARG)
@@ -836,8 +850,9 @@
                 {
                     if (pEvtDesc->pszDesc)
-                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!",
-                                                     pEvtDesc->pszName, pEvtDesc->pszDesc);
+                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: %s - %s!",
+                                                     pEvent->idCpu, pEvtDesc->pszName, pEvtDesc->pszDesc);
                     else
-                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!", pEvtDesc->pszName);
+                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: %s!",
+                                                     pEvent->idCpu, pEvtDesc->pszName);
                     if (pEvent->u.Generic.cArgs <= 1)
                         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " arg=%#llx\n", pEvent->u.Generic.auArgs[0]);
@@ -852,12 +867,14 @@
                 {
                     if (pEvtDesc->pszDesc)
-                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!\n",
-                                                     pEvtDesc->pszName, pEvtDesc->pszDesc);
+                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: %s - %s!\n",
+                                                     pEvent->idCpu, pEvtDesc->pszName, pEvtDesc->pszDesc);
                     else
-                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!\n", pEvtDesc->pszName);
+                        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event/%u: %s!\n",
+                                                     pEvent->idCpu, pEvtDesc->pszName);
                 }
             }
             else
-                rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
+                rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d on CPU %u!\n",
+                                             pEvent->enmType, pEvent->idCpu);
             break;
         }
@@ -869,4 +886,5 @@
     if (fPrintPrompt && RT_SUCCESS(rc))
     {
+        /** @todo add CPU indicator to the prompt if an SMP VM? */
         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
         pDbgc->fReady = true;
@@ -938,9 +956,9 @@
              * Wait for a debug event.
              */
-            PCDBGFEVENT pEvent;
-            rc = DBGFR3EventWait(pDbgc->pUVM, pDbgc->fLog ? 1 : 32, &pEvent);
+            DBGFEVENT Event;
+            rc = DBGFR3EventWait(pDbgc->pUVM, pDbgc->fLog ? 1 : 32, &Event);
             if (RT_SUCCESS(rc))
             {
-                rc = dbgcProcessEvent(pDbgc, pEvent);
+                rc = dbgcProcessEvent(pDbgc, &Event);
                 if (RT_FAILURE(rc))
                     break;
Index: trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp
===================================================================
--- trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 86097)
+++ trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 86098)
@@ -94,5 +94,5 @@
     return VERR_INTERNAL_ERROR;
 }
-VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PCDBGFEVENT *ppEvent)
+VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PDBGFEVENT pEvent)
 {
     return VERR_INTERNAL_ERROR;
@@ -107,5 +107,5 @@
 }
 
-VMMR3DECL(int) DBGFR3Halt(PUVM pUVM)
+VMMR3DECL(int) DBGFR3Halt(PUVM pUVM, VMCPUID idCpu)
 {
     return VERR_INTERNAL_ERROR;
@@ -122,5 +122,5 @@
 {
 }
-VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM)
+VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM, VMCPUID idCpu)
 {
     return true;
@@ -164,5 +164,5 @@
     return VERR_DBG_LINE_NOT_FOUND;
 }
-VMMR3DECL(int) DBGFR3Resume(PUVM pUVM)
+VMMR3DECL(int) DBGFR3Resume(PUVM pUVM, VMCPUID idCpu)
 {
     return VERR_INTERNAL_ERROR;
Index: trunk/src/VBox/VMM/VMMR3/DBGF.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/DBGF.cpp	(revision 86097)
+++ trunk/src/VBox/VMM/VMMR3/DBGF.cpp	(revision 86098)
@@ -75,4 +75,5 @@
 #include <VBox/vmm/em.h>
 #include <VBox/vmm/hm.h>
+#include <VBox/vmm/mm.h>
 #include "DBGFInternal.h"
 #include <VBox/vmm/vm.h>
@@ -110,37 +111,11 @@
 *   Internal Functions                                                                                                           *
 *********************************************************************************************************************************/
-static int dbgfR3VMMWait(PVM pVM);
-static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution);
-static DECLCALLBACK(int) dbgfR3Attach(PVM pVM);
+DECLINLINE(int) dbgfR3SendEventWait(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx);
+DECLINLINE(DBGFCMD) dbgfR3CpuGetCmd(PUVMCPU pUVCpu);
+static int dbgfR3CpuWait(PVMCPU pVCpu);
+static int dbgfR3CpuCmd(PVMCPU pVCpu, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution);
 static DBGFSTEPINSTRTYPE dbgfStepGetCurInstrType(PVM pVM, PVMCPU pVCpu);
-static bool dbgfStepAreWeThereYet(PVM pVM,  PVMCPU pVCpu);
-
-
-/**
- * Sets the VMM Debug Command variable.
- *
- * @returns Previous command.
- * @param   pVM     The cross context VM structure.
- * @param   enmCmd  The command.
- */
-DECLINLINE(DBGFCMD) dbgfR3SetCmd(PVM pVM, DBGFCMD enmCmd)
-{
-    DBGFCMD rc;
-    if (enmCmd == DBGFCMD_NO_COMMAND)
-    {
-        Log2(("DBGF: Setting command to %d (DBGFCMD_NO_COMMAND)\n", enmCmd));
-        rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
-        VM_FF_CLEAR(pVM, VM_FF_DBGF);
-    }
-    else
-    {
-        Log2(("DBGF: Setting command to %d\n", enmCmd));
-        AssertMsg(pVM->dbgf.s.enmVMMCmd == DBGFCMD_NO_COMMAND, ("enmCmd=%d enmVMMCmd=%d\n", enmCmd, pVM->dbgf.s.enmVMMCmd));
-        rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
-        VM_FF_SET(pVM, VM_FF_DBGF);
-        VMR3NotifyGlobalFFU(pVM->pUVM, 0 /* didn't notify REM */);
-    }
-    return rc;
-}
+static bool dbgfStepAreWeThereYet(PVM pVM, PVMCPU pVCpu);
+
 
 
@@ -244,97 +219,17 @@
 VMMR3_INT_DECL(void) DBGFR3PowerOff(PVM pVM)
 {
-
     /*
      * Send a termination event to any attached debugger.
      */
-    /* wait to become the speaker (we should already be that). */
-    if (    pVM->dbgf.s.fAttached
-        &&  RTSemPingShouldWait(&pVM->dbgf.s.PingPong))
-        RTSemPingWait(&pVM->dbgf.s.PingPong, 5000);
-
     if (pVM->dbgf.s.fAttached)
     {
-        /* Just mark it as detached if we're not in a position to send a power
-           off event.  It should fail later on. */
-        if (!RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
-        {
-            ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
-            if (RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
-                ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, true);
-        }
-
-        if (RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
-        {
-            /* Try send the power off event. */
-            int rc;
-            DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
-            if (enmCmd == DBGFCMD_DETACH_DEBUGGER)
-                /* the debugger beat us to initiating the detaching. */
-                rc = VINF_SUCCESS;
-            else
-            {
-                /* ignore the command (if any). */
-                enmCmd = DBGFCMD_NO_COMMAND;
-                pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_POWERING_OFF;
-                pVM->dbgf.s.DbgEvent.enmCtx  = DBGFEVENTCTX_OTHER;
-                rc = RTSemPing(&pVM->dbgf.s.PingPong);
-            }
-
-            /*
-             * Process commands and priority requests until we get a command
-             * indicating that the debugger has detached.
-             */
-            uint32_t cPollHack = 1;
-            PVMCPU   pVCpu     = VMMGetCpu(pVM);
-            while (RT_SUCCESS(rc))
-            {
-                if (enmCmd != DBGFCMD_NO_COMMAND)
-                {
-                    /* process command */
-                    bool fResumeExecution;
-                    DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
-                    rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
-                    if (enmCmd == DBGFCMD_DETACHED_DEBUGGER)
-                        break;
-                    enmCmd = DBGFCMD_NO_COMMAND;
-                }
-                else
-                {
-                    /* Wait for new command, processing pending priority requests
-                       first.  The request processing is a bit crazy, but
-                       unfortunately required by plugin unloading. */
-                    if (   VM_FF_IS_SET(pVM, VM_FF_REQUEST)
-                        || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
-                    {
-                        LogFlow(("DBGFR3PowerOff: Processes priority requests...\n"));
-                        rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
-                        if (rc == VINF_SUCCESS)
-                            rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, true /*fPriorityOnly*/);
-                        LogFlow(("DBGFR3PowerOff: VMR3ReqProcess -> %Rrc\n", rc));
-                        cPollHack = 1;
-                    }
-                    /* Need to handle rendezvous too, for generic debug event management. */
-                    else if (VM_FF_IS_SET(pVM, VM_FF_EMT_RENDEZVOUS))
-                    {
-                        rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
-                        AssertLogRel(rc == VINF_SUCCESS);
-                        cPollHack = 1;
-                    }
-                    else if (cPollHack < 120)
-                        cPollHack++;
-
-                    rc = RTSemPingWait(&pVM->dbgf.s.PingPong, cPollHack);
-                    if (RT_SUCCESS(rc))
-                        enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
-                    else if (rc == VERR_TIMEOUT)
-                        rc = VINF_SUCCESS;
-                }
-            }
-
-            /*
-             * Clear the FF so we won't get confused later on.
-             */
-            VM_FF_CLEAR(pVM, VM_FF_DBGF);
-        }
+        PVMCPU pVCpu = VMMGetCpu(pVM);
+        int rc = dbgfR3SendEventWait(pVM, pVCpu, DBGFEVENT_POWERING_OFF, DBGFEVENTCTX_OTHER);
+        AssertLogRelRC(rc);
+
+        /*
+         * Clear the FF so we won't get confused later on.
+         */
+        VM_FF_CLEAR(pVM, VM_FF_DBGF);
     }
 }
@@ -371,9 +266,7 @@
      * First a message.
      */
-#ifndef RT_OS_L4
-
-# if !defined(DEBUG) || defined(DEBUG_sandervl) || defined(DEBUG_frank)
+#if !defined(DEBUG)
     int cWait = 10;
-# else
+#else
     int cWait = !VM_IS_RAW_MODE_ENABLED(pVM)
              && (   enmEvent == DBGFEVENT_ASSERTION_HYPER
@@ -382,5 +275,5 @@
               ? 10
               : 150;
-# endif
+#endif
     RTStrmPrintf(g_pStdErr, "DBGF: No debugger attached, waiting %d second%s for one to attach (event=%d)\n",
                  cWait / 10, cWait != 10 ? "s" : "", enmEvent);
@@ -394,4 +287,16 @@
             RTStrmFlush(g_pStdErr);
             return true;
+        }
+
+        /* Process rendezvous (debugger attaching involves such). */
+        if (VM_FF_IS_SET(pVM, VM_FF_EMT_RENDEZVOUS))
+        {
+            int rc = VMMR3EmtRendezvousFF(pVM, pVCpu); AssertRC(rc);
+            if (rc != VINF_SUCCESS)
+            {
+                /** @todo Ignoring these could be bad. */
+                RTStrmPrintf(g_pStdErr, "[rcRendezvous=%Rrc, ignored!]", rc);
+                RTStrmFlush(g_pStdErr);
+            }
         }
 
@@ -405,4 +310,5 @@
             if (rc != VINF_SUCCESS)
             {
+                /** @todo Ignoring these could be bad. */
                 RTStrmPrintf(g_pStdErr, "[rcReq=%Rrc, ignored!]", rc);
                 RTStrmFlush(g_pStdErr);
@@ -418,5 +324,4 @@
         cWait--;
     }
-#endif
 
     RTStrmPrintf(g_pStdErr, "Stopping the VM!\n");
@@ -444,29 +349,28 @@
     VBOXSTRICTRC rcStrict = VINF_SUCCESS;
 
-    if (VM_FF_TEST_AND_CLEAR(pVM, VM_FF_DBGF))
-    {
+    /*
+     * Dispatch pending events.
+     */
+    if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_DBGF))
+    {
+        if (   pVCpu->dbgf.s.cEvents > 0
+            && pVCpu->dbgf.s.aEvents[pVCpu->dbgf.s.cEvents - 1].enmState == DBGFEVENTSTATE_CURRENT)
+        {
+            rcStrict = DBGFR3EventHandlePending(pVM, pVCpu);
+            /** @todo may end up with VERR_DBGF_NOT_ATTACHED here, which will prove fatal... */
+        }
+
         /*
          * Command pending? Process it.
          */
-        if (pVM->dbgf.s.enmVMMCmd != DBGFCMD_NO_COMMAND)
+        PUVMCPU pUVCpu = pVCpu->pUVCpu;
+        if (pUVCpu->dbgf.s.enmDbgfCmd != DBGFCMD_NO_COMMAND)
         {
             bool            fResumeExecution;
-            DBGFCMDDATA     CmdData = pVM->dbgf.s.VMMCmdData;
-            DBGFCMD         enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
-            rcStrict = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
+            DBGFCMDDATA     CmdData = pUVCpu->dbgf.s.DbgfCmdData;
+            DBGFCMD         enmCmd = dbgfR3CpuGetCmd(pUVCpu);
+            VBOXSTRICTRC rcStrict2 = dbgfR3CpuCmd(pVCpu, enmCmd, &CmdData, &fResumeExecution);
             if (!fResumeExecution)
-                rcStrict = dbgfR3VMMWait(pVM);
-        }
-    }
-
-    /*
-     * Dispatch pending events.
-     */
-    if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_DBGF))
-    {
-        if (   pVCpu->dbgf.s.cEvents > 0
-            && pVCpu->dbgf.s.aEvents[pVCpu->dbgf.s.cEvents - 1].enmState == DBGFEVENTSTATE_CURRENT)
-        {
-            VBOXSTRICTRC rcStrict2 = DBGFR3EventHandlePending(pVM, pVCpu);
+                rcStrict2 = dbgfR3CpuWait(pVCpu);
             if (   rcStrict2 != VINF_SUCCESS
                 && (   rcStrict == VINF_SUCCESS
@@ -482,42 +386,26 @@
 
 /**
- * Flag whether the event implies that we're stopped in the hypervisor code
- * and have to block certain operations.
- *
- * @param   pVM         The cross context VM structure.
- * @param   enmEvent    The event.
- */
-static void dbgfR3EventSetStoppedInHyperFlag(PVM pVM, DBGFEVENTTYPE enmEvent)
-{
-    switch (enmEvent)
-    {
-        case DBGFEVENT_STEPPED_HYPER:
-        case DBGFEVENT_ASSERTION_HYPER:
-        case DBGFEVENT_BREAKPOINT_HYPER:
-            pVM->dbgf.s.fStoppedInHyper = true;
-            break;
-        default:
-            pVM->dbgf.s.fStoppedInHyper = false;
-            break;
-    }
-}
-
-
-/**
  * Try to determine the event context.
  *
  * @returns debug event context.
- * @param   pVM         The cross context VM structure.
- */
-static DBGFEVENTCTX dbgfR3FigureEventCtx(PVM pVM)
-{
-    /** @todo SMP support! */
-    PVMCPU pVCpu = pVM->apCpusR3[0];
-
+ * @param   pVCpu       The cross context vCPU structure.
+ */
+static DBGFEVENTCTX dbgfR3FigureEventCtx(PVMCPU pVCpu)
+{
     switch (EMGetState(pVCpu))
     {
+        case EMSTATE_HM:
+        case EMSTATE_NEM:
+        case EMSTATE_DEBUG_GUEST_HM:
+        case EMSTATE_DEBUG_GUEST_NEM:
+            return DBGFEVENTCTX_HM;
+
+        case EMSTATE_IEM:
         case EMSTATE_RAW:
+        case EMSTATE_IEM_THEN_REM:
+        case EMSTATE_DEBUG_GUEST_IEM:
         case EMSTATE_DEBUG_GUEST_RAW:
             return DBGFEVENTCTX_RAW;
+
 
         case EMSTATE_REM:
@@ -534,18 +422,130 @@
 }
 
+
+/**
+ * Sends the event to the debugger (i.e. adds it to the event ring buffer).
+ *
+ * @returns VBox status code.
+ * @param   pVM         The cross context VM structure.
+ * @param   pVCpu       The CPU sending the event.
+ * @param   enmType     The event type to send.
+ * @param   enmCtx      The event context, DBGFEVENTCTX_INVALID will be resolved.
+ * @param   pvPayload   Event payload (DBGFEVENT::u data), optional.
+ * @param   cbPayload   The size of the event payload, optional.
+ */
+static int dbgfR3SendEventWorker(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx,
+                                 void const *pvPayload, size_t cbPayload)
+{
+    PUVM pUVM = pVM->pUVM;
+    pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID; /** @todo per vCPU stepping filter. */
+
+    /*
+     * Massage the input a little.
+     */
+    AssertStmt(cbPayload <= RT_SIZEOFMEMB(DBGFEVENT, u), cbPayload = RT_SIZEOFMEMB(DBGFEVENT, u));
+    if (enmCtx == DBGFEVENTCTX_INVALID)
+        enmCtx = dbgfR3FigureEventCtx(pVCpu);
+
+    /*
+     * Put the event into the ring buffer.
+     */
+    RTSemFastMutexRequest(pUVM->dbgf.s.hMtxDbgEvtWr);
+
+    uint32_t const cDbgEvtMax     = RT_MAX(1, pUVM->dbgf.s.cDbgEvtMax);
+    uint32_t const idxDbgEvtWrite = ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite);
+    uint32_t const idxDbgEvtRead  = ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtRead);
+    /** @todo Handle full buffer. */ RT_NOREF(idxDbgEvtRead);
+
+    PDBGFEVENT pEvent = &pUVM->dbgf.s.paDbgEvts[idxDbgEvtWrite % cDbgEvtMax];
+
+#ifdef DEBUG
+    ASMMemFill32(pEvent, sizeof(*pEvent), UINT32_C(0xdeadbeef));
+#endif
+    pEvent->enmType   = enmType;
+    pEvent->enmCtx    = enmCtx;
+    pEvent->idCpu     = pVCpu->idCpu;
+    pEvent->uReserved = 0;
+    if (cbPayload)
+        memcpy(&pEvent->u, pvPayload, cbPayload);
+
+    ASMAtomicWriteU32(&pUVM->dbgf.s.idxDbgEvtWrite, (idxDbgEvtWrite + 1) % cDbgEvtMax);
+
+    RTSemFastMutexRelease(pUVM->dbgf.s.hMtxDbgEvtWr);
+
+    /*
+     * Signal the debugger.
+     */
+    return RTSemEventSignal(pUVM->dbgf.s.hEvtWait);
+}
+
+
+/**
+ * Send event and wait for the debugger to respond.
+ *
+ * @returns Strict VBox status code.
+ * @param   pVM         The cross context VM structure.
+ * @param   pVCpu       The CPU sending the event.
+ * @param   enmType     The event type to send.
+ * @param   enmCtx      The event context, DBGFEVENTCTX_INVALID will be resolved.
+ */
+DECLINLINE(int) dbgfR3SendEventWait(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx)
+{
+    int rc = dbgfR3SendEventWorker(pVM, pVCpu, enmType, enmCtx, NULL, 0);
+    if (RT_SUCCESS(rc))
+        rc = dbgfR3CpuWait(pVCpu);
+    return rc;
+}
+
+
+/**
+ * Send event and wait for the debugger to respond, extended version.
+ *
+ * @returns Strict VBox status code.
+ * @param   pVM         The cross context VM structure.
+ * @param   pVCpu       The CPU sending the event.
+ * @param   enmType     The event type to send.
+ * @param   enmCtx      The event context, DBGFEVENTCTX_INVALID will be resolved.
+ * @param   pvPayload   Event payload (DBGFEVENT::u data), optional.
+ * @param   cbPayload   The size of the event payload, optional.
+ */
+DECLINLINE(int) dbgfR3SendEventWaitEx(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx,
+                                      void const *pvPayload, size_t cbPayload)
+{
+    int rc = dbgfR3SendEventWorker(pVM, pVCpu, enmType, enmCtx, pvPayload, cbPayload);
+    if (RT_SUCCESS(rc))
+        rc = dbgfR3CpuWait(pVCpu);
+    return rc;
+}
+
+
+/**
+ * Send event but do NOT wait for the debugger.
+ *
+ * Currently only used by dbgfR3CpuCmd().
+ *
+ * @param   pVM         The cross context VM structure.
+ * @param   pVCpu       The CPU sending the event.
+ * @param   enmType     The event type to send.
+ * @param   enmCtx      The event context, DBGFEVENTCTX_INVALID will be resolved.
+ */
+DECLINLINE(int) dbgfR3SendEventNoWait(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx)
+{
+    return dbgfR3SendEventWorker(pVM, pVCpu, enmType, enmCtx, NULL, 0);
+}
+
+
 /**
  * The common event prologue code.
- * It will set the 'stopped-in-hyper' flag, make sure someone is attached,
- * and perhaps process any high priority pending actions (none yet).
+ *
+ * It will make sure someone is attached, and perhaps process any high priority
+ * pending actions (none yet).
  *
  * @returns VBox status code.
  * @param   pVM         The cross context VM structure.
+ * @param   pVCpu       The vCPU cross context structure.
  * @param   enmEvent    The event to be sent.
  */
-static int dbgfR3EventPrologue(PVM pVM, DBGFEVENTTYPE enmEvent)
-{
-    /** @todo SMP */
-    PVMCPU pVCpu = VMMGetCpu(pVM);
-
+static int dbgfR3EventPrologue(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent)
+{
     /*
      * Check if a debugger is attached.
@@ -554,12 +554,7 @@
         &&  !dbgfR3WaitForAttach(pVM, pVCpu, enmEvent))
     {
-        Log(("DBGFR3VMMEventSrc: enmEvent=%d - debugger not attached\n", enmEvent));
+        Log(("dbgfR3EventPrologue: enmEvent=%d - debugger not attached\n", enmEvent));
         return VERR_DBGF_NOT_ATTACHED;
     }
-
-    /*
-     * Set flag.
-     */
-    dbgfR3EventSetStoppedInHyperFlag(pVM, enmEvent);
 
     /*
@@ -573,24 +568,4 @@
 
 /**
- * Sends the event in the event buffer.
- *
- * @returns VBox status code.
- * @param   pVM     The cross context VM structure.
- */
-static int dbgfR3SendEvent(PVM pVM)
-{
-    pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID;
-
-    int rc = RTSemPing(&pVM->dbgf.s.PingPong);
-    if (RT_SUCCESS(rc))
-        rc = dbgfR3VMMWait(pVM);
-
-    pVM->dbgf.s.fStoppedInHyper = false;
-    /** @todo sync VMM -> REM after exitting the debugger. everything may change while in the debugger! */
-    return rc;
-}
-
-
-/**
  * Processes a pending event on the current CPU.
  *
@@ -618,18 +593,18 @@
      * Make sure we've got a debugger and is allowed to speak to it.
      */
-    int rc = dbgfR3EventPrologue(pVM, pEvent->enmType);
+    int rc = dbgfR3EventPrologue(pVM, pVCpu, pEvent->enmType);
     if (RT_FAILURE(rc))
     {
         /** @todo drop them events?   */
-        return rc;
-    }
-
-/** @todo SMP + debugger speaker logic  */
-    /*
-     * Copy the event over and mark it as ignore.
-     */
-    pVM->dbgf.s.DbgEvent = *pEvent;
+        return rc; /** @todo this will cause trouble if we're here via an FF! */
+    }
+
+    /*
+     * Send the event and mark it as ignore.
+     * ASSUMES no new events get generate while dbgfR3CpuWait is executing!
+     */
+    VBOXSTRICTRC rcStrict = dbgfR3SendEventWaitEx(pVM, pVCpu, pEvent->enmType, pEvent->enmCtx, &pEvent->u, sizeof(pEvent->u));
     pVCpu->dbgf.s.aEvents[pVCpu->dbgf.s.cEvents - 1].enmState = DBGFEVENTSTATE_IGNORE;
-    return dbgfR3SendEvent(pVM);
+    return rcStrict;
 }
 
@@ -645,4 +620,7 @@
 VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent)
 {
+    PVMCPU pVCpu = VMMGetCpu(pVM);
+    AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
+
     /*
      * Do stepping filtering.
@@ -653,9 +631,9 @@
         || enmEvent == DBGFEVENT_STEPPED_HYPER)
     {
-        if (!dbgfStepAreWeThereYet(pVM, VMMGetCpu(pVM)))
+        if (!dbgfStepAreWeThereYet(pVM, pVCpu))
             return VINF_EM_DBG_STEP;
     }
 
-    int rc = dbgfR3EventPrologue(pVM, enmEvent);
+    int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
     if (RT_FAILURE(rc))
         return rc;
@@ -664,7 +642,5 @@
      * Send the event and process the reply communication.
      */
-    pVM->dbgf.s.DbgEvent.enmType = enmEvent;
-    pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
-    return dbgfR3SendEvent(pVM);
+    return dbgfR3SendEventWait(pVM, pVCpu, enmEvent, DBGFEVENTCTX_INVALID);
 }
 
@@ -708,5 +684,8 @@
 VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args)
 {
-    int rc = dbgfR3EventPrologue(pVM, enmEvent);
+    PVMCPU pVCpu = VMMGetCpu(pVM);
+    AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
+
+    int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
     if (RT_FAILURE(rc))
         return rc;
@@ -726,11 +705,10 @@
      * Send the event and process the reply communication.
      */
-    pVM->dbgf.s.DbgEvent.enmType = enmEvent;
-    pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
-    pVM->dbgf.s.DbgEvent.u.Src.pszFile      = pszFile;
-    pVM->dbgf.s.DbgEvent.u.Src.uLine        = uLine;
-    pVM->dbgf.s.DbgEvent.u.Src.pszFunction  = pszFunction;
-    pVM->dbgf.s.DbgEvent.u.Src.pszMessage   = pszMessage;
-    return dbgfR3SendEvent(pVM);
+    DBGFEVENT DbgEvent;  /** @todo split up DBGFEVENT so we can skip the dead wait on the stack? */
+    DbgEvent.u.Src.pszFile      = pszFile;
+    DbgEvent.u.Src.uLine        = uLine;
+    DbgEvent.u.Src.pszFunction  = pszFunction;
+    DbgEvent.u.Src.pszMessage   = pszMessage;
+    return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_INVALID, &DbgEvent.u, sizeof(DbgEvent.u.Src));
 }
 
@@ -747,5 +725,8 @@
 VMMR3_INT_DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2)
 {
-    int rc = dbgfR3EventPrologue(pVM, enmEvent);
+    PVMCPU pVCpu = VMMGetCpu(pVM);
+    AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
+
+    int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
     if (RT_FAILURE(rc))
         return rc;
@@ -754,9 +735,8 @@
      * Send the event and process the reply communication.
      */
-    pVM->dbgf.s.DbgEvent.enmType = enmEvent;
-    pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
-    pVM->dbgf.s.DbgEvent.u.Assert.pszMsg1 = pszMsg1;
-    pVM->dbgf.s.DbgEvent.u.Assert.pszMsg2 = pszMsg2;
-    return dbgfR3SendEvent(pVM);
+    DBGFEVENT DbgEvent;
+    DbgEvent.u.Assert.pszMsg1 = pszMsg1;
+    DbgEvent.u.Assert.pszMsg2 = pszMsg2;
+    return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_INVALID, &DbgEvent.u, sizeof(DbgEvent.u.Assert));
 }
 
@@ -772,5 +752,8 @@
 VMMR3_INT_DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent)
 {
-    int rc = dbgfR3EventPrologue(pVM, enmEvent);
+    PVMCPU pVCpu = VMMGetCpu(pVM);
+    AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
+
+    int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
     if (RT_FAILURE(rc))
         return rc;
@@ -779,33 +762,103 @@
      * Send the event and process the reply communication.
      */
-    /** @todo SMP */
-    PVMCPU pVCpu = VMMGetCpu0(pVM);
-
-    pVM->dbgf.s.DbgEvent.enmType = enmEvent;
-    RTUINT iBp = pVM->dbgf.s.DbgEvent.u.Bp.iBp = pVCpu->dbgf.s.iActiveBp;
+    DBGFEVENT DbgEvent;
+    RTUINT iBp = DbgEvent.u.Bp.iBp = pVCpu->dbgf.s.iActiveBp;
     pVCpu->dbgf.s.iActiveBp = ~0U;
     if (iBp != ~0U)
-        pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_RAW;
-    else
-    {
-        /* REM breakpoints has be been searched for. */
+    {
+        DbgEvent.enmCtx = DBGFEVENTCTX_RAW;
+        return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_RAW, &DbgEvent.u, sizeof(DbgEvent.u.Bp));
+    }
+
+    AssertFailed(); /** @todo this should be obsolete now...   */
+
+    /* REM breakpoints has be been searched for. */
 #if 0   /** @todo get flat PC api! */
-        uint32_t eip = CPUMGetGuestEIP(pVM);
+    uint32_t eip = CPUMGetGuestEIP(pVM);
 #else
-        /** @todo SMP support!! */
-        PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu(pVM));
-        RTGCPTR  eip = pCtx->rip + pCtx->cs.u64Base;
+    PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+    RTGCPTR  eip = pCtx->rip + pCtx->cs.u64Base;
 #endif
-        for (size_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
-            if (    pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_REM
-                &&  pVM->dbgf.s.aBreakpoints[i].u.Rem.GCPtr == eip)
-            {
-                pVM->dbgf.s.DbgEvent.u.Bp.iBp = pVM->dbgf.s.aBreakpoints[i].iBp;
-                break;
-            }
-        AssertMsg(pVM->dbgf.s.DbgEvent.u.Bp.iBp != ~0U, ("eip=%08x\n", eip));
-        pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_REM;
-    }
-    return dbgfR3SendEvent(pVM);
+    for (size_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
+        if (    pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_REM
+            &&  pVM->dbgf.s.aBreakpoints[i].u.Rem.GCPtr == eip)
+        {
+            DbgEvent.u.Bp.iBp = pVM->dbgf.s.aBreakpoints[i].iBp;
+            break;
+        }
+    AssertMsg(DbgEvent.u.Bp.iBp != ~0U, ("eip=%08x\n", eip));
+    return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_REM, &DbgEvent.u, sizeof(DbgEvent.u.Bp));
+}
+
+
+/**
+ * Returns whether the given vCPU is waiting for the debugger.
+ *
+ * @returns Flags whether the vCPU is currently waiting for the debugger.
+ * @param   pUVCpu              The user mode vCPU structure.
+ */
+DECLINLINE(bool) dbgfR3CpuIsHalted(PUVMCPU pUVCpu)
+{
+    return ASMAtomicReadBool(&pUVCpu->dbgf.s.fStopped);
+}
+
+
+/**
+ * Checks whether the given vCPU is waiting in the debugger.
+ *
+ * @returns Flag whether the indicated vCPU is halted, when VMCPUID_ALL
+ *          is given true is returned when at least one vCPU is halted.
+ * @param   pUVM        The user mode VM structure.
+ * @param   idCpu       The CPU ID to check, VMCPUID_ALL to check all vCPUs.
+ */
+DECLINLINE(bool) dbgfR3CpuAreAnyHaltedByCpuId(PUVM pUVM, VMCPUID idCpu)
+{
+    AssertReturn(idCpu < pUVM->cCpus || idCpu == VMCPUID_ALL, false);
+
+    /* Check that either the given vCPU or all are actually halted. */
+    if (idCpu != VMCPUID_ALL)
+        return dbgfR3CpuIsHalted(&pUVM->aCpus[idCpu]);
+
+    for (VMCPUID i = 0; i < pUVM->cCpus; i++)
+        if (dbgfR3CpuIsHalted(&pUVM->aCpus[i]))
+            return true;
+    return false;
+}
+
+
+/**
+ * Gets the pending debug command for this EMT/CPU, replacing it with
+ * DBGFCMD_NO_COMMAND.
+ *
+ * @returns Pending command.
+ * @param   pUVCpu          The user mode virtual CPU structure.
+ * @thread  EMT(pUVCpu)
+ */
+DECLINLINE(DBGFCMD) dbgfR3CpuGetCmd(PUVMCPU pUVCpu)
+{
+    DBGFCMD enmCmd = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pUVCpu->dbgf.s.enmDbgfCmd, DBGFCMD_NO_COMMAND);
+    Log2(("DBGF: Getting command: %d\n", enmCmd));
+    return enmCmd;
+}
+
+
+/**
+ * Send a debug command to a CPU, making sure to notify it.
+ *
+ * @returns VBox status code.
+ * @param   pUVCpu      The user mode virtual CPU structure.
+ * @param   enmCmd      The command to submit to the CPU.
+ */
+DECLINLINE(int) dbgfR3CpuSetCmdAndNotify(PUVMCPU pUVCpu, DBGFCMD enmCmd)
+{
+    Log2(("DBGF: Setting command to %d\n", enmCmd));
+    Assert(enmCmd != DBGFCMD_NO_COMMAND);
+    AssertMsg(pUVCpu->dbgf.s.enmDbgfCmd == DBGFCMD_NO_COMMAND, ("enmCmd=%d enmDbgfCmd=%d\n", enmCmd, pUVCpu->dbgf.s.enmDbgfCmd));
+
+    ASMAtomicWriteU32((uint32_t volatile *)(void *)&pUVCpu->dbgf.s.enmDbgfCmd, enmCmd);
+    VMCPU_FF_SET(pUVCpu->pVCpu, VMCPU_FF_DBGF);
+
+    VMR3NotifyCpuFFU(pUVCpu, 0 /*fFlags*/);
+    return VINF_SUCCESS;
 }
 
@@ -815,12 +868,15 @@
  *
  * @returns VBox status code. (clearify)
- * @param   pVM     The cross context VM structure.
- */
-static int dbgfR3VMMWait(PVM pVM)
-{
-    PVMCPU pVCpu = VMMGetCpu(pVM);
-
-    LogFlow(("dbgfR3VMMWait:\n"));
+ * @param   pVCpu               The cross context vCPU structure.
+ */
+static int dbgfR3CpuWait(PVMCPU pVCpu)
+{
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    PUVMCPU pUVCpu = pVCpu->pUVCpu;
+
+    LogFlow(("dbgfR3CpuWait:\n"));
     int rcRet = VINF_SUCCESS;
+
+    ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, true);
 
     /*
@@ -832,81 +888,104 @@
          * Wait.
          */
-        uint32_t cPollHack = 1; /** @todo this interface is horrible now that we're using lots of VMR3ReqCall stuff all over DBGF. */
         for (;;)
         {
-            int rc;
-            if (    !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_REQUEST)
-                &&  !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
+            /*
+             * Process forced flags before we go sleep.
+             */
+            if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_DBGF | VMCPU_FF_REQUEST)
+                || VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VMCPU_FF_REQUEST | VM_FF_CHECK_VM_STATE))
             {
-                rc = RTSemPingWait(&pVM->dbgf.s.PingPong, cPollHack);
-                if (RT_SUCCESS(rc))
+                if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_DBGF))
                     break;
-                if (rc != VERR_TIMEOUT)
+
+                int rc;
+                if (VM_FF_IS_SET(pVM, VM_FF_EMT_RENDEZVOUS))
+                    rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
+                else if (   VM_FF_IS_SET(pVM, VM_FF_REQUEST)
+                         || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
                 {
-                    LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
+                    LogFlow(("dbgfR3CpuWait: Processes requests...\n"));
+                    rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, false /*fPriorityOnly*/);
+                    if (rc == VINF_SUCCESS)
+                        rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, false /*fPriorityOnly*/);
+                    LogFlow(("dbgfR3CpuWait: VMR3ReqProcess -> %Rrc rcRet=%Rrc\n", rc, rcRet));
+                }
+                else if (VM_FF_IS_SET(pVM, VM_FF_CHECK_VM_STATE))
+                {
+                    VMSTATE enmState = VMR3GetState(pVM);
+                    switch (enmState)
+                    {
+                        case VMSTATE_FATAL_ERROR:
+                        case VMSTATE_FATAL_ERROR_LS:
+                        case VMSTATE_GURU_MEDITATION:
+                        case VMSTATE_GURU_MEDITATION_LS:
+                            rc = VINF_EM_SUSPEND;
+                            break;
+                        case VMSTATE_DESTROYING:
+                            rc = VINF_EM_TERMINATE;
+                            break;
+                        default:
+                            AssertMsgFailed(("%s\n", VMGetStateName(enmState)));
+                    }
+                }
+                else
+                    rc = VINF_SUCCESS;
+                if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
+                {
+                    switch (rc)
+                    {
+                        case VINF_EM_DBG_BREAKPOINT:
+                        case VINF_EM_DBG_STEPPED:
+                        case VINF_EM_DBG_STEP:
+                        case VINF_EM_DBG_STOP:
+                        case VINF_EM_DBG_EVENT:
+                            AssertMsgFailed(("rc=%Rrc\n", rc));
+                            break;
+
+                        /* return straight away */
+                        case VINF_EM_TERMINATE:
+                        case VINF_EM_OFF:
+                            LogFlow(("dbgfR3CpuWait: returns %Rrc\n", rc));
+                            ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
+                            return rc;
+
+                        /* remember return code. */
+                        default:
+                            AssertReleaseMsgFailed(("rc=%Rrc is not in the switch!\n", rc));
+                            RT_FALL_THRU();
+                        case VINF_EM_RESET:
+                        case VINF_EM_SUSPEND:
+                        case VINF_EM_HALT:
+                        case VINF_EM_RESUME:
+                        case VINF_EM_RESCHEDULE:
+                        case VINF_EM_RESCHEDULE_REM:
+                        case VINF_EM_RESCHEDULE_RAW:
+                            if (rc < rcRet || rcRet == VINF_SUCCESS)
+                                rcRet = rc;
+                            break;
+                    }
+                }
+                else if (RT_FAILURE(rc))
+                {
+                    LogFlow(("dbgfR3CpuWait: returns %Rrc\n", rc));
+                    ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
                     return rc;
                 }
             }
-
-            if (VM_FF_IS_SET(pVM, VM_FF_EMT_RENDEZVOUS))
+            else if (pVM->dbgf.s.fAttached)
             {
-                rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
-                cPollHack = 1;
-            }
-            else if (   VM_FF_IS_SET(pVM, VM_FF_REQUEST)
-                     || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
-            {
-                LogFlow(("dbgfR3VMMWait: Processes requests...\n"));
-                rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, false /*fPriorityOnly*/);
-                if (rc == VINF_SUCCESS)
-                    rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, false /*fPriorityOnly*/);
-                LogFlow(("dbgfR3VMMWait: VMR3ReqProcess -> %Rrc rcRet=%Rrc\n", rc, rcRet));
-                cPollHack = 1;
+                int rc = VMR3WaitU(pUVCpu);
+                if (RT_FAILURE(rc))
+                {
+                    LogFlow(("dbgfR3CpuWait: returns %Rrc (VMR3WaitU)\n", rc));
+                    ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
+                    return rc;
+                }
             }
             else
             {
-                rc = VINF_SUCCESS;
-                if (cPollHack < 120)
-                    cPollHack++;
-            }
-
-            if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
-            {
-                switch (rc)
-                {
-                    case VINF_EM_DBG_BREAKPOINT:
-                    case VINF_EM_DBG_STEPPED:
-                    case VINF_EM_DBG_STEP:
-                    case VINF_EM_DBG_STOP:
-                    case VINF_EM_DBG_EVENT:
-                        AssertMsgFailed(("rc=%Rrc\n", rc));
-                        break;
-
-                    /* return straight away */
-                    case VINF_EM_TERMINATE:
-                    case VINF_EM_OFF:
-                        LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
-                        return rc;
-
-                    /* remember return code. */
-                    default:
-                        AssertReleaseMsgFailed(("rc=%Rrc is not in the switch!\n", rc));
-                        RT_FALL_THRU();
-                    case VINF_EM_RESET:
-                    case VINF_EM_SUSPEND:
-                    case VINF_EM_HALT:
-                    case VINF_EM_RESUME:
-                    case VINF_EM_RESCHEDULE:
-                    case VINF_EM_RESCHEDULE_REM:
-                    case VINF_EM_RESCHEDULE_RAW:
-                        if (rc < rcRet || rcRet == VINF_SUCCESS)
-                            rcRet = rc;
-                        break;
-                }
-            }
-            else if (RT_FAILURE(rc))
-            {
-                LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
-                return rc;
+                LogFlow(("dbgfR3CpuWait: Debugger detached, continuing normal execution (%Rrc)\n", rcRet));
+                ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
+                return rcRet;
             }
         }
@@ -915,8 +994,9 @@
          * Process the command.
          */
+        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_DBGF);
         bool            fResumeExecution;
-        DBGFCMDDATA     CmdData = pVM->dbgf.s.VMMCmdData;
-        DBGFCMD         enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
-        int rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
+        DBGFCMDDATA     CmdData = pUVCpu->dbgf.s.DbgfCmdData;
+        DBGFCMD         enmCmd = dbgfR3CpuGetCmd(pUVCpu);
+        int rc = dbgfR3CpuCmd(pVCpu, enmCmd, &CmdData, &fResumeExecution);
         if (fResumeExecution)
         {
@@ -927,5 +1007,6 @@
                      &&  (rc < rcRet || rcRet == VINF_SUCCESS))
                 rcRet = rc;
-            LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rcRet));
+            LogFlow(("dbgfR3CpuWait: returns %Rrc\n", rcRet));
+            ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
             return rcRet;
         }
@@ -941,17 +1022,18 @@
  *
  * @returns VBox status code. (clearify!)
- * @param   pVM                 The cross context VM structure.
+ * @param   pVCpu               The cross context vCPU structure.
  * @param   enmCmd              The command in question.
  * @param   pCmdData            Pointer to the command data.
  * @param   pfResumeExecution   Where to store the resume execution / continue waiting indicator.
  */
-static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution)
-{
-    bool    fSendEvent;
-    bool    fResume;
-    int     rc = VINF_SUCCESS;
-
-    NOREF(pCmdData); /* for later */
-
+static int dbgfR3CpuCmd(PVMCPU pVCpu, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution)
+{
+    RT_NOREF(pCmdData); /* for later */
+
+    /*
+     * The cases in this switch returns directly if no event to send.
+     */
+    DBGFEVENTTYPE enmEvent;
+    DBGFEVENTCTX  enmCtx = DBGFEVENTCTX_INVALID;
     switch (enmCmd)
     {
@@ -961,8 +1043,6 @@
         case DBGFCMD_HALT:
         {
-            pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_HALT_DONE;
-            pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
-            fSendEvent = true;
-            fResume = false;
+            *pfResumeExecution = false;
+            enmEvent = DBGFEVENT_HALT_DONE;
             break;
         }
@@ -970,43 +1050,14 @@
 
         /*
-         * Resume is not answered we'll just resume execution.
+         * Resume is not answered, we just resume execution.
          */
         case DBGFCMD_GO:
         {
-            /** @todo SMP */
-            PVMCPU pVCpu = VMMGetCpu0(pVM);
             pVCpu->dbgf.s.fSingleSteppingRaw = false;
-            fSendEvent = false;
-            fResume = true;
-            break;
+            *pfResumeExecution = true;
+            return VINF_SUCCESS;
         }
 
         /** @todo implement (and define) the rest of the commands. */
-
-        /*
-         * Disable breakpoints and stuff.
-         * Send an everythings cool event to the debugger thread and resume execution.
-         */
-        case DBGFCMD_DETACH_DEBUGGER:
-        {
-            ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
-            pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE;
-            pVM->dbgf.s.DbgEvent.enmCtx  = DBGFEVENTCTX_OTHER;
-            pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID;
-            fSendEvent = true;
-            fResume = true;
-            break;
-        }
-
-        /*
-         * The debugger has detached successfully.
-         * There is no reply to this event.
-         */
-        case DBGFCMD_DETACHED_DEBUGGER:
-        {
-            fSendEvent = false;
-            fResume = true;
-            break;
-        }
 
         /*
@@ -1016,6 +1067,5 @@
         {
             Log2(("Single step\n"));
-            /** @todo SMP */
-            PVMCPU pVCpu = VMMGetCpu0(pVM);
+            PVM pVM = pVCpu->CTX_SUFF(pVM);
             if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_OVER)
             {
@@ -1026,18 +1076,12 @@
             {
                 pVCpu->dbgf.s.fSingleSteppingRaw = true;
-                fSendEvent = false;
-                fResume = true;
-                rc = VINF_EM_DBG_STEP;
+                *pfResumeExecution = true;
+                return VINF_EM_DBG_STEP;
             }
-            else
-            {
-                /* Stop after zero steps. Nonsense, but whatever. */
-                pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID;
-                pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
-                pVM->dbgf.s.DbgEvent.enmType = pVM->dbgf.s.DbgEvent.enmCtx != DBGFEVENTCTX_HYPER
-                                             ? DBGFEVENT_STEPPED : DBGFEVENT_STEPPED_HYPER;
-                fSendEvent = false;
-                fResume = false;
-            }
+            /* Stop after zero steps. Nonsense, but whatever. */
+            pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID;
+            *pfResumeExecution = false;
+            enmCtx   = dbgfR3FigureEventCtx(pVCpu);
+            enmEvent = enmCtx != DBGFEVENTCTX_HYPER ? DBGFEVENT_STEPPED : DBGFEVENT_STEPPED_HYPER;
             break;
         }
@@ -1048,8 +1092,6 @@
         default:
         {
-            pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_INVALID_COMMAND;
-            pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
-            fSendEvent = true;
-            fResume = false;
+            *pfResumeExecution = false;
+            enmEvent = DBGFEVENT_INVALID_COMMAND;
             break;
         }
@@ -1057,23 +1099,83 @@
 
     /*
-     * Send pending event.
-     */
-    if (fSendEvent)
-    {
-        Log2(("DBGF: Emulation thread: sending event %d\n", pVM->dbgf.s.DbgEvent.enmType));
-        int rc2 = RTSemPing(&pVM->dbgf.s.PingPong);
-        if (RT_FAILURE(rc2))
-        {
-            AssertRC(rc2);
-            *pfResumeExecution = true;
-            return rc2;
-        }
-    }
-
-    /*
-     * Return.
-     */
-    *pfResumeExecution = fResume;
+     * Send the pending event.
+     */
+    Log2(("DBGF: Emulation thread: sending event %d\n", enmEvent));
+    int rc = dbgfR3SendEventNoWait(pVCpu->CTX_SUFF(pVM), pVCpu, enmEvent, enmCtx);
+    AssertRCStmt(rc, *pfResumeExecution = true);
     return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNVMMEMTRENDEZVOUS,
+ * EMT rendezvous worker for DBGFR3Attach - only called on one EMT.}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) dbgfR3Attach(PVM pVM, PVMCPU pVCpu, void *pvUser)
+{
+    PUVM pUVM = pVM->pUVM;
+    int *prcAttach = (int *)pvUser;
+    RT_NOREF(pVCpu);
+
+    if (pVM->dbgf.s.fAttached)
+    {
+        Log(("dbgfR3Attach: Debugger already attached\n"));
+        *prcAttach = VERR_DBGF_ALREADY_ATTACHED;
+        return VINF_SUCCESS;
+    }
+
+    /*
+     * The per-CPU bits.
+     */
+    for (uint32_t i = 0; i < pUVM->cCpus; i++)
+    {
+        PUVMCPU pUVCpu = &pUVM->aCpus[i];
+
+        pUVCpu->dbgf.s.enmDbgfCmd = DBGFCMD_NO_COMMAND;
+        RT_ZERO(pUVCpu->dbgf.s.DbgfCmdData);
+    }
+
+    /*
+     * Init of the VM -> Debugger communication part living in the global VM structure.
+     */
+    pUVM->dbgf.s.cDbgEvtMax      = pVM->cCpus * 5 + 10; /* Initial size of event ring, increased when being full. */
+    pUVM->dbgf.s.idxDbgEvtWrite  = 0;
+    pUVM->dbgf.s.idxDbgEvtRead   = 0;
+    pUVM->dbgf.s.hEvtWait        = NIL_RTSEMEVENT;
+    pUVM->dbgf.s.hEvtRingBufFull = NIL_RTSEMEVENTMULTI;
+    pUVM->dbgf.s.hMtxDbgEvtWr    = NIL_RTSEMFASTMUTEX;
+    int rc;
+    pUVM->dbgf.s.paDbgEvts       = (PDBGFEVENT)MMR3HeapAllocU(pUVM, MM_TAG_DBGF, pUVM->dbgf.s.cDbgEvtMax * sizeof(DBGFEVENT));
+    if (pUVM->dbgf.s.paDbgEvts)
+    {
+        rc = RTSemEventCreate(&pUVM->dbgf.s.hEvtWait);
+        if (RT_SUCCESS(rc))
+        {
+            rc = RTSemFastMutexCreate(&pUVM->dbgf.s.hMtxDbgEvtWr);
+            if (RT_SUCCESS(rc))
+            {
+                rc = RTSemEventMultiCreate(&pUVM->dbgf.s.hEvtRingBufFull);
+                if (RT_SUCCESS(rc))
+                {
+                    /*
+                     * At last, set the attached flag.
+                     */
+                    ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, true);
+                    *prcAttach = VINF_SUCCESS;
+                    return VINF_SUCCESS;
+                }
+
+                RTSemFastMutexDestroy(pUVM->dbgf.s.hMtxDbgEvtWr);
+                pUVM->dbgf.s.hMtxDbgEvtWr = NIL_RTSEMFASTMUTEX;
+            }
+            RTSemEventDestroy(pUVM->dbgf.s.hEvtWait);
+            pUVM->dbgf.s.hEvtWait = NIL_RTSEMEVENT;
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    *prcAttach = rc;
+    return VINF_SUCCESS;
 }
 
@@ -1094,38 +1196,73 @@
 
     /*
-     * Call the VM, use EMT for serialization.
-     *
-     * Using a priority call here so we can actually attach a debugger during
-     * the countdown in dbgfR3WaitForAttach.
-     */
-    /** @todo SMP */
-    return VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3Attach, 1, pVM);
-}
-
-
-/**
- * EMT worker for DBGFR3Attach.
- *
- * @returns VBox status code.
- * @param   pVM     The cross context VM structure.
- */
-static DECLCALLBACK(int) dbgfR3Attach(PVM pVM)
-{
-    if (pVM->dbgf.s.fAttached)
-    {
-        Log(("dbgR3Attach: Debugger already attached\n"));
-        return VERR_DBGF_ALREADY_ATTACHED;
-    }
-
-    /*
-     * Create the Ping-Pong structure.
-     */
-    int rc = RTSemPingPongInit(&pVM->dbgf.s.PingPong);
-    AssertRCReturn(rc, rc);
-
-    /*
-     * Set the attached flag.
-     */
-    ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, true);
+     * Call the VM, use EMT rendezvous for serialization.
+     */
+    int rcAttach = VERR_IPE_UNINITIALIZED_STATUS;
+    int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE | VMMEMTRENDEZVOUS_FLAGS_PRIORITY, dbgfR3Attach, &rcAttach);
+    if (RT_SUCCESS(rc))
+        rc = rcAttach;
+
+    return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNVMMEMTRENDEZVOUS,
+ * EMT rendezvous worker for DBGFR3Detach - called on all EMTs (why?).}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) dbgfR3Detach(PVM pVM, PVMCPU pVCpu, void *pvUser)
+{
+    if (pVCpu->idCpu == 0)
+    {
+        PUVM pUVM = (PUVM)pvUser;
+
+        /*
+         * Per-CPU cleanup.
+         */
+        for (VMCPUID i = 0; i < pUVM->cCpus; i++)
+        {
+            PUVMCPU pUVCpu = &pUVM->aCpus[i];
+
+            pUVCpu->dbgf.s.enmDbgfCmd = DBGFCMD_NO_COMMAND;
+            RT_ZERO(pUVCpu->dbgf.s.DbgfCmdData);
+        }
+
+        /*
+         * De-init of the VM -> Debugger communication part living in the global VM structure.
+         */
+        if (pUVM->dbgf.s.paDbgEvts)
+        {
+            MMR3HeapFree(pUVM->dbgf.s.paDbgEvts);
+            pUVM->dbgf.s.paDbgEvts = NULL;
+        }
+
+        if (pUVM->dbgf.s.hEvtWait != NIL_RTSEMEVENT)
+        {
+            RTSemEventDestroy(pUVM->dbgf.s.hEvtWait);
+            pUVM->dbgf.s.hEvtWait = NIL_RTSEMEVENT;
+        }
+
+        if (pUVM->dbgf.s.hMtxDbgEvtWr != NIL_RTSEMFASTMUTEX)
+        {
+            RTSemFastMutexDestroy(pUVM->dbgf.s.hMtxDbgEvtWr);
+            pUVM->dbgf.s.hMtxDbgEvtWr = NIL_RTSEMFASTMUTEX;
+        }
+
+        if (pUVM->dbgf.s.hEvtRingBufFull != NIL_RTSEMEVENTMULTI)
+        {
+            RTSemEventMultiDestroy(pUVM->dbgf.s.hEvtRingBufFull);
+            pUVM->dbgf.s.hEvtRingBufFull = NIL_RTSEMEVENTMULTI;
+        }
+
+        pUVM->dbgf.s.cDbgEvtMax      = 0;
+        pUVM->dbgf.s.idxDbgEvtWrite  = 0;
+        pUVM->dbgf.s.idxDbgEvtRead   = 0;
+        pUVM->dbgf.s.hEvtWait        = NIL_RTSEMEVENT;
+        pUVM->dbgf.s.hEvtRingBufFull = NIL_RTSEMEVENTMULTI;
+        pUVM->dbgf.s.hMtxDbgEvtWr    = NIL_RTSEMFASTMUTEX;
+
+        ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
+    }
+
     return VINF_SUCCESS;
 }
@@ -1143,5 +1280,4 @@
 {
     LogFlow(("DBGFR3Detach:\n"));
-    int rc;
 
     /*
@@ -1160,31 +1296,5 @@
         return VERR_DBGF_NOT_ATTACHED;
 
-    /*
-     * Try send the detach command.
-     * Keep in mind that we might be racing EMT, so, be extra careful.
-     */
-    DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACH_DEBUGGER);
-    if (RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong))
-    {
-        rc = RTSemPong(&pVM->dbgf.s.PingPong);
-        AssertMsgRCReturn(rc, ("Failed to signal emulation thread. rc=%Rrc\n", rc), rc);
-        LogRel(("DBGFR3Detach: enmCmd=%d (pong -> ping)\n", enmCmd));
-    }
-
-    /*
-     * Wait for the OK event.
-     */
-    rc = RTSemPongWait(&pVM->dbgf.s.PingPong, RT_INDEFINITE_WAIT);
-    AssertLogRelMsgRCReturn(rc, ("Wait on detach command failed, rc=%Rrc\n", rc), rc);
-
-    /*
-     * Send the notification command indicating that we're really done.
-     */
-    enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACHED_DEBUGGER);
-    rc = RTSemPong(&pVM->dbgf.s.PingPong);
-    AssertMsgRCReturn(rc, ("Failed to signal emulation thread. rc=%Rrc\n", rc), rc);
-
-    LogFlowFunc(("returns VINF_SUCCESS\n"));
-    return VINF_SUCCESS;
+    return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE | VMMEMTRENDEZVOUS_FLAGS_PRIORITY, dbgfR3Detach, pUVM);
 }
 
@@ -1196,7 +1306,7 @@
  * @param   pUVM        The user mode VM handle.
  * @param   cMillies    Number of millis to wait.
- * @param   ppEvent     Where to store the event pointer.
- */
-VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PCDBGFEVENT *ppEvent)
+ * @param   pEvent      Where to store the event data.
+ */
+VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PDBGFEVENT pEvent)
 {
     /*
@@ -1207,17 +1317,31 @@
     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
     AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
-    *ppEvent = NULL;
-
-    /*
-     * Wait.
-     */
-    int rc = RTSemPongWait(&pVM->dbgf.s.PingPong, cMillies);
+
+    RT_BZERO(pEvent, sizeof(*pEvent));
+
+    /*
+     * Wait for an event to arrive if there are none.
+     */
+    int rc = VINF_SUCCESS;
+    uint32_t idxDbgEvtRead = ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtRead);
+    if (idxDbgEvtRead == ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite))
+    {
+        do
+        {
+            rc = RTSemEventWait(pUVM->dbgf.s.hEvtWait, cMillies);
+        } while (   RT_SUCCESS(rc)
+                 && idxDbgEvtRead == ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite));
+    }
+
     if (RT_SUCCESS(rc))
     {
-        *ppEvent = &pVM->dbgf.s.DbgEvent;
-        Log2(("DBGF: Debugger thread: receiving event %d\n", (*ppEvent)->enmType));
-        return VINF_SUCCESS;
-    }
-
+        Assert(idxDbgEvtRead != ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite));
+
+        uint32_t const cDbgEvtMax = RT_MAX(1, pUVM->dbgf.s.cDbgEvtMax);
+        memcpy(pEvent, &pUVM->dbgf.s.paDbgEvts[idxDbgEvtRead % cDbgEvtMax], sizeof(*pEvent));
+        ASMAtomicWriteU32(&pUVM->dbgf.s.idxDbgEvtRead, (idxDbgEvtRead + 1) % cDbgEvtMax);
+    }
+
+    Log2(("DBGFR3EventWait: rc=%Rrc (event type %d)\n", rc, pEvent->enmType));
     return rc;
 }
@@ -1231,7 +1355,10 @@
  *
  * @returns VBox status code.
+ * @retval  VWRN_DBGF_ALREADY_HALTED if @a idCpu is VMCPUID_ALL and all vCPUs
+ *          are halted.
  * @param   pUVM        The user mode VM handle.
- */
-VMMR3DECL(int) DBGFR3Halt(PUVM pUVM)
+ * @param   idCpu       The vCPU to halt, VMCPUID_ALL halts all still running vCPUs.
+ */
+VMMR3DECL(int) DBGFR3Halt(PUVM pUVM, VMCPUID idCpu)
 {
     /*
@@ -1242,26 +1369,49 @@
     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
     AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
-    RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
-    if (   enmSpeaker == RTPINGPONGSPEAKER_PONG
-        || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED)
-        return VWRN_DBGF_ALREADY_HALTED;
-
-    /*
-     * Send command.
-     */
-    dbgfR3SetCmd(pVM, DBGFCMD_HALT);
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Checks if the VM is halted by the debugger.
- *
- * @returns True if halted.
- * @returns False if not halted.
+    AssertReturn(idCpu == VMCPUID_ALL || idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
+
+    /*
+     * Halt the requested CPUs as needed.
+     */
+    int rc;
+    if (idCpu != VMCPUID_ALL)
+    {
+        PUVMCPU pUVCpu = &pUVM->aCpus[idCpu];
+        if (!dbgfR3CpuIsHalted(pUVCpu))
+        {
+            dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_HALT);
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VWRN_DBGF_ALREADY_HALTED;
+    }
+    else
+    {
+        rc = VWRN_DBGF_ALREADY_HALTED;
+        for (VMCPUID i = 0; i < pUVM->cCpus; i++)
+        {
+            PUVMCPU pUVCpu = &pUVM->aCpus[i];
+            if (!dbgfR3CpuIsHalted(pUVCpu))
+            {
+                dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_HALT);
+                rc = VINF_SUCCESS;
+            }
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * Checks if any of the specified vCPUs have been halted by the debugger.
+ *
+ * @returns True if at least one halted vCPUs.
+ * @returns False if no halted vCPUs.
  * @param   pUVM        The user mode VM handle.
- */
-VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM)
+ * @param   idCpu       The CPU id to check for, VMCPUID_ALL will return true if
+ *                      at least a single vCPU is halted in the debugger.
+ */
+VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM, VMCPUID idCpu)
 {
     UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
@@ -1270,7 +1420,5 @@
     AssertReturn(pVM->dbgf.s.fAttached, false);
 
-    RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
-    return enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED
-        || enmSpeaker == RTPINGPONGSPEAKER_PONG;
+    return dbgfR3CpuAreAnyHaltedByCpuId(pUVM, idCpu);
 }
 
@@ -1303,7 +1451,5 @@
         return VERR_DBGF_NOT_ATTACHED;
 
-    if (!RTSemPongShouldWait(&pVM->dbgf.s.PingPong))
-        return VERR_SEM_OUT_OF_TURN;
-
+    /** @todo was: if (!RTSemPongShouldWait(...)) return VERR_SEM_OUT_OF_TURN; */
     return VINF_SUCCESS;
 }
@@ -1316,10 +1462,12 @@
  *
  * @returns VBox status code.
+ * @retval  VWRN_DBGF_ALREADY_RUNNING if the specified vCPUs are all running.
  * @param   pUVM        The user mode VM handle.
- */
-VMMR3DECL(int) DBGFR3Resume(PUVM pUVM)
-{
-    /*
-     * Check state.
+ * @param   idCpu       The vCPU to resume, VMCPUID_ALL resumes all still halted vCPUs.
+ */
+VMMR3DECL(int) DBGFR3Resume(PUVM pUVM, VMCPUID idCpu)
+{
+    /*
+     * Validate input and attachment state.
      */
     UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
@@ -1327,15 +1475,32 @@
     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
     AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
-    if (RT_LIKELY(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong)))
-    { /* likely */ }
+
+    /*
+     * Ping the halted emulation threads, telling them to run.
+     */
+    int rc = VWRN_DBGF_ALREADY_RUNNING;
+    if (idCpu != VMCPUID_ALL)
+    {
+        PUVMCPU pUVCpu = &pUVM->aCpus[idCpu];
+        if (dbgfR3CpuIsHalted(pUVCpu))
+        {
+            rc = dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_GO);
+            AssertRC(rc);
+        }
+    }
     else
-        return VERR_SEM_OUT_OF_TURN;
-
-    /*
-     * Send the ping back to the emulation thread telling it to run.
-     */
-    dbgfR3SetCmd(pVM, DBGFCMD_GO);
-    int rc = RTSemPong(&pVM->dbgf.s.PingPong);
-    AssertRC(rc);
+    {
+        for (VMCPUID i = 0; i < pUVM->cCpus; i++)
+        {
+            PUVMCPU pUVCpu = &pUVM->aCpus[i];
+            if (dbgfR3CpuIsHalted(pUVCpu))
+            {
+                int rc2 = dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_GO);
+                AssertRC(rc2);
+                if (rc == VWRN_DBGF_ALREADY_RUNNING || RT_FAILURE(rc2))
+                    rc = rc2;
+            }
+        }
+    }
 
     return rc;
@@ -1621,5 +1786,6 @@
 
     AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
-    if (RT_LIKELY(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong)))
+    PUVMCPU pUVCpu = &pUVM->aCpus[idCpu];
+    if (RT_LIKELY(dbgfR3CpuIsHalted(pUVCpu)))
     { /* likely */ }
     else
@@ -1628,5 +1794,5 @@
 
     /*
-     * Send the ping back to the emulation thread telling it to run.
+     * Send the emulation thread a single-step command.
      */
     if (fFlags == DBGF_STEP_F_INTO)
@@ -1654,9 +1820,6 @@
     pVM->dbgf.s.SteppingFilter.uCallDepth   = 0;
 
-/** @todo SMP (idCpu) */
-    dbgfR3SetCmd(pVM, DBGFCMD_SINGLE_STEP);
-    int rc = RTSemPong(&pVM->dbgf.s.PingPong);
-    AssertRC(rc);
-    return rc;
+    Assert(dbgfR3CpuIsHalted(pUVCpu));
+    return dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_SINGLE_STEP);
 }
 
Index: trunk/src/VBox/VMM/include/DBGFInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/DBGFInternal.h	(revision 86097)
+++ trunk/src/VBox/VMM/include/DBGFInternal.h	(revision 86098)
@@ -578,12 +578,5 @@
     DBGFCMD_GO,
     /** Single step execution - stepping into calls. */
-    DBGFCMD_SINGLE_STEP,
-    /** Detaches the debugger.
-     * Disabling all breakpoints, watch points and the like. */
-    DBGFCMD_DETACH_DEBUGGER,
-    /** Detached the debugger.
-     * The isn't a command as such, it's just that it's necessary for the
-     * detaching protocol to be racefree. */
-    DBGFCMD_DETACHED_DEBUGGER
+    DBGFCMD_SINGLE_STEP
 } DBGFCMD;
 
@@ -806,35 +799,4 @@
      */
     bool volatile               fAttached;
-
-    /** Stopped in the Hypervisor.
-     * Set if we're stopped on a trace, breakpoint or assertion inside
-     * the hypervisor and have to restrict the available operations.
-     */
-    bool volatile               fStoppedInHyper;
-
-    /**
-     * Ping-Pong construct where the Ping side is the VMM and the Pong side
-     * the Debugger.
-     */
-    RTPINGPONG                  PingPong;
-    RTHCUINTPTR                 uPtrPadding; /**< Alignment padding. */
-
-    /** The Event to the debugger.
-     * The VMM will ping the debugger when the event is ready. The event is
-     * either a response to a command or to a break/watch point issued
-     * previously.
-     */
-    DBGFEVENT                   DbgEvent;
-
-    /** The Command to the VMM.
-     * Operated in an atomic fashion since the VMM will poll on this.
-     * This means that a the command data must be written before this member
-     * is set. The VMM will reset this member to the no-command state
-     * when it have processed it.
-     */
-    DBGFCMD volatile            enmVMMCmd;
-    /** The Command data.
-     * Not all commands take data. */
-    DBGFCMDDATA                 VMMCmdData;
 
     /** Stepping filtering. */
@@ -906,5 +868,4 @@
     } BugCheck;
 } DBGF;
-AssertCompileMemberAlignment(DBGF, DbgEvent, 8);
 AssertCompileMemberAlignment(DBGF, aHwBreakpoints, 8);
 AssertCompileMemberAlignment(DBGF, bmHardIntBreakpoints, 8);
@@ -1065,4 +1026,24 @@
     PDBGFTRACERINSR3            pTracerR3;
 
+    /** @name VM -> Debugger event communication.
+     * @{ */
+    /** The event semaphore the debugger waits on for new events to arrive. */
+    RTSEMEVENT                  hEvtWait;
+    /** Multi event semaphore the vCPUs wait on in case the debug event ringbuffer is
+     * full and require growing (done from the thread waiting for events). */
+    RTSEMEVENTMULTI             hEvtRingBufFull;
+    /** Fast mutex protecting the event ring from concurrent write accesses by multiple vCPUs. */
+    RTSEMFASTMUTEX              hMtxDbgEvtWr;
+    /** Ringbuffer of events, dynamically allocated based on the number of available vCPUs
+     * (+ some safety entries). */
+    PDBGFEVENT                  paDbgEvts;
+    /** Number of entries in the event ring buffer. */
+    uint32_t                    cDbgEvtMax;
+    /** Next free entry to write to (vCPU thread). */
+    volatile uint32_t           idxDbgEvtWrite;
+    /** Next event entry to from (debugger thread). */
+    volatile uint32_t           idxDbgEvtRead;
+    /** @} */
+
     /** The type database lock. */
     RTSEMRW                     hTypeDbLock;
@@ -1084,7 +1065,24 @@
 {
     /** The guest register set for this CPU.  Can be NULL. */
-    R3PTRTYPE(struct DBGFREGSET *) pGuestRegSet;
+    R3PTRTYPE(struct DBGFREGSET *)  pGuestRegSet;
     /** The hypervisor register set for this CPU.  Can be NULL. */
-    R3PTRTYPE(struct DBGFREGSET *) pHyperRegSet;
+    R3PTRTYPE(struct DBGFREGSET *)  pHyperRegSet;
+
+    /** @name Debugger -> vCPU command communication.
+     * @{ */
+    /** Flag whether this vCPU is currently stopped waiting in the debugger. */
+    bool volatile                   fStopped;
+    /** The Command to the vCPU.
+     * Operated in an atomic fashion since the vCPU will poll on this.
+     * This means that a the command data must be written before this member
+     * is set. The VMM will reset this member to the no-command state
+     * when it have processed it.
+     */
+    DBGFCMD volatile                enmDbgfCmd;
+    /** The Command data.
+     * Not all commands take data. */
+    DBGFCMDDATA                     DbgfCmdData;
+    /** @} */
+
 } DBGFUSERPERVMCPU;
 
Index: trunk/src/VBox/VMM/testcase/tstVMStruct.h
===================================================================
--- trunk/src/VBox/VMM/testcase/tstVMStruct.h	(revision 86097)
+++ trunk/src/VBox/VMM/testcase/tstVMStruct.h	(revision 86098)
@@ -275,9 +275,4 @@
     GEN_CHECK_OFF(DBGF, cSelectedEvents);
     GEN_CHECK_OFF(DBGF, fAttached);
-    GEN_CHECK_OFF(DBGF, fStoppedInHyper);
-    GEN_CHECK_OFF(DBGF, PingPong);
-    GEN_CHECK_OFF(DBGF, DbgEvent);
-    GEN_CHECK_OFF(DBGF, enmVMMCmd);
-    GEN_CHECK_OFF(DBGF, VMMCmdData);
     //GEN_CHECK_OFF(DBGF, pInfoFirst);
     //GEN_CHECK_OFF(DBGF, InfoCritSect);
