Index: trunk/include/VBox/vmm/dbgf.h
===================================================================
--- trunk/include/VBox/vmm/dbgf.h	(revision 64769)
+++ trunk/include/VBox/vmm/dbgf.h	(revision 64770)
@@ -124,5 +124,5 @@
 VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromPhys(PUVM pUVM, PDBGFADDRESS pAddress, RTGCPHYS PhysAddr);
 VMMR3DECL(bool)         DBGFR3AddrIsValid(PUVM pUVM, PCDBGFADDRESS pAddress);
-VMMR3DECL(int)          DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTGCPHYS pGCPhys);
+VMMR3DECL(int)          DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys);
 VMMR3DECL(int)          DBGFR3AddrToHostPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys);
 VMMR3DECL(int)          DBGFR3AddrToVolatileR3Ptr(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr);
@@ -791,9 +791,12 @@
             uint8_t         cb;
         } Reg;
-        /** Recompiler breakpoint data. */
+
+        /** INT3 breakpoint data. */
         struct DBGFBPINT3
         {
             /** The flat GC address of the breakpoint. */
             RTGCUINTPTR     GCPtr;
+            /** The physical address of the breakpoint. */
+            RTGCPHYS        PhysAddr;
             /** The byte value we replaced by the INT 3 instruction. */
             uint8_t         bOrg;
@@ -831,5 +834,5 @@
 
         /** Paddind to ensure that the size is identical on win32 and linux. */
-        uint64_t    u64Padding[2];
+        uint64_t    u64Padding[3];
     } u;
 } DBGFBP;
@@ -844,5 +847,5 @@
 
 #ifdef IN_RING3 /* The breakpoint management API is only available in ring-3. */
-VMMR3DECL(int)  DBGFR3BpSet(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp);
+VMMR3DECL(int)  DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp);
 VMMR3DECL(int)  DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
                                uint8_t fType, uint8_t cb, uint32_t *piBp);
@@ -879,4 +882,5 @@
 VMM_INT_DECL(bool)          DBGFBpIsHwArmed(PVM pVM);
 VMM_INT_DECL(bool)          DBGFBpIsHwIoArmed(PVM pVM);
+VMM_INT_DECL(bool)          DBGFBpIsInt3Armed(PVM pVM);
 VMM_INT_DECL(bool)          DBGFIsStepping(PVMCPU pVCpu);
 VMM_INT_DECL(VBOXSTRICTRC)  DBGFBpCheckIo(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTIOPORT uIoPort, uint8_t cbValue);
Index: trunk/include/VBox/vmm/vm.h
===================================================================
--- trunk/include/VBox/vmm/vm.h	(revision 64769)
+++ trunk/include/VBox/vmm/vm.h	(revision 64770)
@@ -1207,6 +1207,13 @@
             /** Enabled software interrupt breakpoints. */
             uint32_t                    cSoftIntBreakpoints;
-            /** Number of selected events. */
+            /** The number of selected events. */
             uint32_t                    cSelectedEvents;
+            /** The number of enabled hardware breakpoints. */
+            uint8_t                     cEnabledHwBreakpoints;
+            /** The number of enabled hardware I/O breakpoints. */
+            uint8_t                     cEnabledHwIoBreakpoints;
+            /** The number of enabled INT3 breakpoints. */
+            uint8_t                     cEnabledInt3Breakpoints;
+            uint8_t                     abPadding[1]; /**< Unused padding space up for grabs. */
         } const     ro;
 #endif
Index: trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp
===================================================================
--- trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp	(revision 64769)
+++ trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp	(revision 64770)
@@ -1085,8 +1085,8 @@
      */
     uint32_t iBp;
-    rc = DBGFR3BpSet(pUVM, &Address, iHitTrigger, iHitDisable, &iBp);
+    PDBGC    pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+    rc = DBGFR3BpSetInt3(pUVM, pDbgc->idCpu, &Address, iHitTrigger, iHitDisable, &iBp);
     if (RT_SUCCESS(rc))
     {
-        PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
         rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
         if (RT_SUCCESS(rc))
Index: trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp
===================================================================
--- trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 64769)
+++ trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 64770)
@@ -42,5 +42,5 @@
 }
 
-VMMR3DECL(int)  DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
+VMMR3DECL(int)  DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
 {
     return VERR_INTERNAL_ERROR;
@@ -68,5 +68,5 @@
     return VERR_INTERNAL_ERROR;
 }
-VMMR3DECL(int) DBGFR3BpSet(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, PRTUINT piBp)
+VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, PRTUINT piBp)
 {
     return VERR_INTERNAL_ERROR;
Index: trunk/src/VBox/VMM/VMMAll/DBGFAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/DBGFAll.cpp	(revision 64769)
+++ trunk/src/VBox/VMM/VMMAll/DBGFAll.cpp	(revision 64770)
@@ -150,4 +150,17 @@
 {
     return pVM->dbgf.s.cEnabledHwIoBreakpoints > 0;
+}
+
+
+/**
+ * Checks if any INT3 breakpoints are armed.
+ *
+ * @returns true if armed, false if not.
+ * @param   pVM        The cross context VM structure.
+ * @remarks Don't call this from CPUMRecalcHyperDRx!
+ */
+VMM_INT_DECL(bool) DBGFBpIsInt3Armed(PVM pVM)
+{
+    return pVM->dbgf.s.cEnabledInt3Breakpoints > 0;
 }
 
Index: trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 64769)
+++ trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 64770)
@@ -1670,16 +1670,22 @@
 static int hmR0SvmLoadGuestXcptIntercepts(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
 {
-    int rc = VINF_SUCCESS;
-    NOREF(pCtx);
     if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
     {
-        /* The remaining intercepts are handled elsewhere, e.g. in hmR0SvmLoadSharedCR0(). */
+        /* Trap #UD for GIM provider (e.g. for hypercalls). */
         if (pVCpu->hm.s.fGIMTrapXcptUD)
             hmR0SvmAddXcptIntercept(pVmcb, X86_XCPT_UD);
         else
             hmR0SvmRemoveXcptIntercept(pVmcb, X86_XCPT_UD);
+
+        /* Trap #BP for INT3 debug breakpoints set by the VM debugger. */
+        if (pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
+            hmR0SvmAddXcptIntercept(pVmcb, X86_XCPT_BP);
+        else
+            hmR0SvmRemoveXcptIntercept(pVmcb, X86_XCPT_BP);
+
+        /* The remaining intercepts are handled elsewhere, e.g. in hmR0SvmLoadSharedCR0(). */
         HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
     }
-    return rc;
+    return VINF_SUCCESS;
 }
 
Index: trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 64769)
+++ trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 64770)
@@ -2650,4 +2650,6 @@
     LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
 
+    /** @todo r=ramshankar: Shouldn't setting up \#UD intercepts be handled by
+     *        hmR0VmxLoadGuestXcptIntercepts()? Why do we check it here? */
     uint32_t u32XcptBitmap = pVCpu->hm.s.fGIMTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
 
@@ -9107,5 +9109,5 @@
     /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
     uint32_t    fCpe2Extra;
-    /** Extra stuff we need in    */
+    /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
     uint32_t    bmXcptExtra;
     /** The sequence number of the Dtrace provider settings the state was
@@ -9305,4 +9307,10 @@
         ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
     }
+
+    /*
+     * INT3 breakpoints - triggered by #BP exceptions.
+     */
+    if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
+        pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
 
     /*
@@ -10406,5 +10414,6 @@
     if (   !pVCpu->hm.s.fUseDebugLoop
         && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
-        && !DBGFIsStepping(pVCpu) )
+        && !DBGFIsStepping(pVCpu)
+        && !pVM->dbgf.ro.cEnabledInt3Breakpoints)
         rcStrict = hmR0VmxRunGuestCodeNormal(pVM, pVCpu, pCtx);
     else
Index: trunk/src/VBox/VMM/VMMR3/DBGFAddr.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/DBGFAddr.cpp	(revision 64769)
+++ trunk/src/VBox/VMM/VMMR3/DBGFAddr.cpp	(revision 64770)
@@ -237,5 +237,5 @@
  * @param   pGCPhys         Where to return the physical address.
  */
-static DECLCALLBACK(int) dbgfR3AddrToPhysOnVCpu(PVMCPU pVCpu, PDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
+static DECLCALLBACK(int) dbgfR3AddrToPhysOnVCpu(PVMCPU pVCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
 {
     VMCPU_ASSERT_EMT(pVCpu);
@@ -265,5 +265,5 @@
  * @param   pGCPhys         Where to return the physical address.
  */
-VMMR3DECL(int)  DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
+VMMR3DECL(int)  DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
 {
     /*
Index: trunk/src/VBox/VMM/VMMR3/DBGFBp.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/DBGFBp.cpp	(revision 64769)
+++ trunk/src/VBox/VMM/VMMR3/DBGFBp.cpp	(revision 64770)
@@ -42,9 +42,32 @@
 
 /*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/**
+ * DBGF INT3-breakpoint set callback arguments.
+ */
+typedef struct DBGFBPINT3ARGS
+{
+    /** The source virtual CPU ID (used for breakpoint address resolution). */
+    VMCPUID         idSrcCpu;
+    /** The breakpoint address. */
+    PCDBGFADDRESS   pAddress;
+    /** The hit count at which the breakpoint starts triggering. */
+    uint64_t        iHitTrigger;
+    /** The hit count at which disables the breakpoint. */
+    uint64_t        iHitDisable;
+    /** Where to store the breakpoint Id (optional). */
+    uint32_t       *piBp;
+} DBGFBPINT3ARGS;
+/** Pointer to a DBGF INT3 breakpoint set callback argument. */
+typedef DBGFBPINT3ARGS *PDBGFBPINT3ARGS;
+
+
+/*********************************************************************************************************************************
 *   Internal Functions                                                                                                           *
 *********************************************************************************************************************************/
 RT_C_DECLS_BEGIN
 static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);
-static int dbgfR3BpInt3Arm(PUVM pUVM, PDBGFBP pBp);
+static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);
 RT_C_DECLS_END
 
@@ -166,7 +189,8 @@
 
 /**
- * Updates IOM on whether we've got any armed I/O port or MMIO breakpoints.
- *
- * @returns VINF_SUCCESS
+ * Updates the search optimization structure for enabled breakpoints of the
+ * specified type.
+ *
+ * @returns VINF_SUCCESS.
  * @param   pVM         The cross context VM structure.
  * @param   enmType     The breakpoint type.
@@ -317,76 +341,118 @@
 
 /**
- * Sets a breakpoint (int 3 based).
- *
- * @returns VBox status code.
- * @param   pUVM            The user mode VM handle.
- * @param   pAddress        The address of the breakpoint.
- * @param   piHitTrigger    The hit count at which the breakpoint start triggering.
- *                          Use 0 (or 1) if it's gonna trigger at once.
- * @param   piHitDisable    The hit count which disables the breakpoint.
- *                          Use ~(uint64_t) if it's never gonna be disabled.
- * @param   piBp            Where to store the breakpoint id. (optional)
- * @thread  Any thread.
- */
-static DECLCALLBACK(int) dbgfR3BpSetInt3(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger,
-                                         uint64_t *piHitDisable, uint32_t *piBp)
+ * @callback_method_impl{FNVMMEMTRENDEZVOUS}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpEnableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
 {
     /*
      * Validate input.
      */
-    PVM pVM = pUVM->pVM;
+    PDBGFBP pBp = (PDBGFBP)pvUser;
+    AssertReturn(pBp, VERR_INVALID_PARAMETER);
+    Assert(pBp->enmType == DBGFBPTYPE_INT3);
+    VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
-    if (!DBGFR3AddrIsValid(pUVM, pAddress))
+
+    /*
+     * Arm the breakpoint.
+     */
+    return dbgfR3BpInt3Arm(pVM, pBp);
+}
+
+
+/**
+ * @callback_method_impl{FNVMMEMTRENDEZVOUS}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpSetInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
+{
+    /*
+     * Validate input.
+     */
+    PDBGFBPINT3ARGS pBpArgs = (PDBGFBPINT3ARGS)pvUser;
+    AssertReturn(pBpArgs, VERR_INVALID_PARAMETER);
+    VMCPU_ASSERT_EMT(pVCpu);
+    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+
+    AssertMsgReturn(!pBpArgs->piBp || VALID_PTR(pBpArgs->piBp), ("piBp=%p\n", pBpArgs->piBp), VERR_INVALID_POINTER);
+    PCDBGFADDRESS pAddress = pBpArgs->pAddress;
+    if (!DBGFR3AddrIsValid(pVM->pUVM, pAddress))
         return VERR_INVALID_PARAMETER;
-    if (*piHitTrigger > *piHitDisable)
+
+    if (pBpArgs->iHitTrigger > pBpArgs->iHitDisable)
         return VERR_INVALID_PARAMETER;
-    AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER);
-    if (piBp)
-        *piBp = UINT32_MAX;
-
-    /*
-     * Check if the breakpoint already exists.
-     */
-    PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
-    if (pBp)
-    {
-        int rc = VINF_SUCCESS;
-        if (!pBp->fEnabled)
-            rc = dbgfR3BpInt3Arm(pUVM, pBp);
+
+    /*
+     * Check if we're on the source CPU where we can resolve the breakpoint address.
+     */
+    if (pVCpu->idCpu == pBpArgs->idSrcCpu)
+    {
+        if (pBpArgs->piBp)
+            *pBpArgs->piBp = UINT32_MAX;
+
+        /*
+         * Check if the breakpoint already exists.
+         */
+        PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr);
+        if (pBp)
+        {
+            int rc = VINF_SUCCESS;
+            if (!pBp->fEnabled)
+                rc = dbgfR3BpInt3Arm(pVM, pBp);
+            if (RT_SUCCESS(rc))
+            {
+                if (pBpArgs->piBp)
+                    *pBpArgs->piBp = pBp->iBp;
+
+                /*
+                 * Returning VINF_DBGF_BP_ALREADY_EXIST here causes a VBOXSTRICTRC out-of-range assertion
+                 * in VMMR3EmtRendezvous(). Re-setting of an existing breakpoint shouldn't cause an assertion
+                 * killing the VM (and debugging session), so for now we'll pretend success.
+                 */
+#if 0
+                rc = VINF_DBGF_BP_ALREADY_EXIST;
+#endif
+            }
+            else
+                dbgfR3BpFree(pVM, pBp);
+            return rc;
+        }
+
+        /*
+         * Allocate the breakpoint.
+         */
+        pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
+        if (!pBp)
+            return VERR_DBGF_NO_MORE_BP_SLOTS;
+
+        /*
+         * Translate & save the breakpoint address into a guest-physical address.
+         */
+        int rc = DBGFR3AddrToPhys(pVM->pUVM, pBpArgs->idSrcCpu, pAddress, &pBp->u.Int3.PhysAddr);
         if (RT_SUCCESS(rc))
         {
-            rc = VINF_DBGF_BP_ALREADY_EXIST;
-            if (piBp)
-                *piBp = pBp->iBp;
+            /* The physical address from DBGFR3AddrToPhys() is the start of the page,
+               we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm(). */
+            pBp->u.Int3.PhysAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK);
+            pBp->u.Int3.GCPtr = pAddress->FlatPtr;
+            pBp->iHitTrigger  = pBpArgs->iHitTrigger;
+            pBp->iHitDisable  = pBpArgs->iHitDisable;
+
+            /*
+             * Now set the breakpoint in guest memory.
+             */
+            rc = dbgfR3BpInt3Arm(pVM, pBp);
+            if (RT_SUCCESS(rc))
+            {
+                if (pBpArgs->piBp)
+                    *pBpArgs->piBp = pBp->iBp;
+                return VINF_SUCCESS;
+            }
         }
+
+        dbgfR3BpFree(pVM, pBp);
         return rc;
     }
 
-    /*
-     * Allocate and initialize the bp.
-     */
-    pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3);
-    if (!pBp)
-        return VERR_DBGF_NO_MORE_BP_SLOTS;
-    pBp->u.Int3.GCPtr   = pAddress->FlatPtr;
-    pBp->iHitTrigger    = *piHitTrigger;
-    pBp->iHitDisable    = *piHitDisable;
-    ASMCompilerBarrier();
-    pBp->fEnabled       = true;
-    dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
-
-    /*
-     * Now ask REM to set the breakpoint.
-     */
-    int rc = dbgfR3BpInt3Arm(pUVM, pBp);
-    if (RT_SUCCESS(rc))
-    {
-        if (piBp)
-            *piBp = pBp->iBp;
-    }
-    else
-        dbgfR3BpFree(pVM, pBp);
-
-    return rc;
+    return VINF_SUCCESS;
 }
 
@@ -397,4 +463,6 @@
  * @returns VBox status code.
  * @param   pUVM        The user mode VM handle.
+ * @param   idSrcCpu    The ID of the virtual CPU used for the
+ *                      breakpoint address resolution.
  * @param   pAddress    The address of the breakpoint.
  * @param   iHitTrigger The hit count at which the breakpoint start triggering.
@@ -405,11 +473,18 @@
  * @thread  Any thread.
  */
-VMMR3DECL(int) DBGFR3BpSet(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp)
-{
-    /*
-     * This must be done on EMT.
-     */
-    int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetInt3, 5,
-                              pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp);
+VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable,
+                               uint32_t *piBp)
+{
+    AssertReturn(idSrcCpu <= pUVM->cCpus, VERR_INVALID_CPU_ID);
+
+    DBGFBPINT3ARGS BpArgs;
+    RT_ZERO(BpArgs);
+    BpArgs.idSrcCpu    = idSrcCpu;
+    BpArgs.iHitTrigger = iHitTrigger;
+    BpArgs.iHitDisable = iHitDisable;
+    BpArgs.pAddress    = pAddress;
+    BpArgs.piBp        = piBp;
+
+    int rc = VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpSetInt3OnCpu, &BpArgs);
     LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc));
     return rc;
@@ -419,27 +494,32 @@
 /**
  * Arms an int 3 breakpoint.
- * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable().
- *
- * @returns VBox status code.
- * @param   pUVM        The user mode VM handle.
+ *
+ * This is used to implement both DBGFR3BpSetInt3() and
+ * DBGFR3BpEnable().
+ *
+ * @returns VBox status code.
+ * @param   pVM         The cross context VM structure.
  * @param   pBp         The breakpoint.
  */
-static int dbgfR3BpInt3Arm(PUVM pUVM, PDBGFBP pBp)
-{
-    /** @todo should actually use physical address here! */
-
-    /** @todo SMP support! */
-    VMCPUID idCpu = 0;
-
-    /*
-     * Save current byte and write int3 instruction.
-     */
-    DBGFADDRESS Addr;
-    DBGFR3AddrFromFlat(pUVM, &Addr, pBp->u.Int3.GCPtr);
-    int rc = DBGFR3MemRead(pUVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
+static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp)
+{
+    VM_ASSERT_EMT(pVM);
+
+    /*
+     * Save current byte and write the int3 instruction byte.
+     */
+    int rc = PGMPhysSimpleReadGCPhys(pVM, &pBp->u.Int3.bOrg, pBp->u.Int3.PhysAddr, sizeof(pBp->u.Int3.bOrg));
     if (RT_SUCCESS(rc))
     {
         static const uint8_t s_bInt3 = 0xcc;
-        rc = DBGFR3MemWrite(pUVM, idCpu, &Addr, &s_bInt3, 1);
+        rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &s_bInt3, sizeof(s_bInt3));
+        if (RT_SUCCESS(rc))
+        {
+            pBp->fEnabled = true;
+            dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
+            pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
+            Log(("DBGF: Set breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
+                 pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
+        }
     }
     return rc;
@@ -449,14 +529,14 @@
 /**
  * Disarms an int 3 breakpoint.
+ *
  * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable().
  *
  * @returns VBox status code.
- * @param   pUVM        The user mode VM handle.
+ * @param   pVM         The cross context VM structure.
  * @param   pBp         The breakpoint.
  */
-static int dbgfR3BpInt3Disarm(PUVM pUVM, PDBGFBP pBp)
-{
-    /** @todo SMP support! */
-    VMCPUID idCpu = 0;
+static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp)
+{
+    VM_ASSERT_EMT(pVM);
 
     /*
@@ -464,11 +544,41 @@
      * We currently ignore invalid bytes.
      */
-    DBGFADDRESS     Addr;
-    DBGFR3AddrFromFlat(pUVM, &Addr, pBp->u.Int3.GCPtr);
-    uint8_t         bCurrent;
-    int rc = DBGFR3MemRead(pUVM, idCpu, &Addr, &bCurrent, 1);
-    if (bCurrent == 0xcc)
-        rc = DBGFR3MemWrite(pUVM, idCpu, &Addr, &pBp->u.Int3.bOrg, 1);
+    uint8_t bCurrent = 0;
+    int rc = PGMPhysSimpleReadGCPhys(pVM, &bCurrent, pBp->u.Int3.PhysAddr, sizeof(bCurrent));
+    if (   RT_SUCCESS(rc)
+        && bCurrent == 0xcc)
+    {
+        rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &pBp->u.Int3.bOrg, sizeof(pBp->u.Int3.bOrg));
+        if (RT_SUCCESS(rc))
+        {
+            pBp->fEnabled = false;
+            dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
+            pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch;
+            Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr,
+                 pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints));
+        }
+    }
     return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNVMMEMTRENDEZVOUS}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpDisableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser)
+{
+    /*
+     * Validate input.
+     */
+    PDBGFBP pBp = (PDBGFBP)pvUser;
+    AssertReturn(pBp, VERR_INVALID_PARAMETER);
+    Assert(pBp->enmType == DBGFBPTYPE_INT3);
+    VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
+    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+
+    /*
+     * Disarm the breakpoint.
+     */
+    return dbgfR3BpInt3Disarm(pVM, pBp);
 }
 
@@ -966,5 +1076,5 @@
      * Allocate and initialize the breakpoint.
      */
-    PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_PORT_IO);
+    PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_MMIO);
     if (!pBp)
         return VERR_DBGF_NO_MORE_BP_SLOTS;
@@ -1041,4 +1151,5 @@
      */
     PVM pVM = pUVM->pVM;
+    VM_ASSERT_EMT(pVM);
     VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
     PDBGFBP pBp = dbgfR3BpGet(pVM, iBp);
@@ -1060,6 +1171,5 @@
 
             case DBGFBPTYPE_INT3:
-                rc = dbgfR3BpInt3Disarm(pUVM, pBp);
-                dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
+                rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
                 break;
 
@@ -1137,5 +1247,5 @@
 
     /*
-     * Remove the breakpoint.
+     * Arm the breakpoint.
      */
     int rc;
@@ -1148,6 +1258,5 @@
 
         case DBGFBPTYPE_INT3:
-            dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
-            rc = dbgfR3BpInt3Arm(pUVM, pBp);
+            rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpEnableInt3OnCpu, pBp);
             break;
 
@@ -1232,6 +1341,5 @@
 
         case DBGFBPTYPE_INT3:
-            rc = dbgfR3BpInt3Disarm(pUVM, pBp);
-            dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3);
+            rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp);
             break;
 
@@ -1337,5 +1445,5 @@
      */
     int rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnum, 3, pUVM, pfnCallback, pvUser);
-    LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc));
+    LogFlow(("DBGFR3BpEnum: returns %Rrc\n", rc));
     return rc;
 }
Index: trunk/src/VBox/VMM/VMMR3/DBGFMem.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/DBGFMem.cpp	(revision 64769)
+++ trunk/src/VBox/VMM/VMMR3/DBGFMem.cpp	(revision 64770)
@@ -161,5 +161,5 @@
 
     /*
-     * HMA is special
+     * HMA is special.
      */
     int rc;
@@ -174,5 +174,5 @@
     {
         /*
-         * Select DBGF worker by addressing mode.
+         * Select PGM worker by addressing mode.
          */
         PVMCPU  pVCpu   = VMMGetCpuById(pVM, idCpu);
Index: trunk/src/VBox/VMM/include/DBGFInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/DBGFInternal.h	(revision 64769)
+++ trunk/src/VBox/VMM/include/DBGFInternal.h	(revision 64770)
@@ -209,6 +209,15 @@
     uint32_t                    cSoftIntBreakpoints;
 
-    /** Number of selected events. */
+    /** The number of selected events. */
     uint32_t                    cSelectedEvents;
+
+    /** The number of enabled hardware breakpoints. */
+    uint8_t                     cEnabledHwBreakpoints;
+    /** The number of enabled hardware I/O breakpoints. */
+    uint8_t                     cEnabledHwIoBreakpoints;
+    /** The number of enabled INT3 breakpoints. */
+    uint8_t                     cEnabledInt3Breakpoints;
+    uint8_t                     abPadding; /**< Unused padding space up for grabs. */
+    uint32_t                    uPadding;
 
     /** Debugger Attached flag.
@@ -276,11 +285,5 @@
     } SteppingFilter;
 
-    uint32_t                    u32Padding; /**< Alignment padding. */
-
-    /** The number of enabled hardware breakpoints. */
-    uint8_t                     cEnabledHwBreakpoints;
-    /** The number of enabled hardware I/O breakpoints. */
-    uint8_t                     cEnabledHwIoBreakpoints;
-    uint8_t                     abPadding[2]; /**< Unused padding space up for grabs. */
+    uint32_t                    u32Padding[2]; /**< Alignment padding. */
 
     /** Array of hardware breakpoints. (0..3)
