Index: trunk/src/VBox/VMM/PDMDevHlp.cpp
===================================================================
--- trunk/src/VBox/VMM/PDMDevHlp.cpp	(revision 17509)
+++ trunk/src/VBox/VMM/PDMDevHlp.cpp	(revision 17510)
@@ -47,10 +47,4 @@
 *   Defined Constants And Macros                                               *
 *******************************************************************************/
-/** Allow physical read and writes from any thread.
- * (pdmR3DevHlp_PhysRead and pdmR3DevHlp_PhysWrite.)
- */
-#define PDM_PHYS_READWRITE_FROM_ANY_THREAD
-
-
 /** @name R3 DevHlp
  * @{
@@ -2033,30 +2027,17 @@
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    PVM pVM = pDevIns->Internal.s.pVMR3;
     LogFlow(("pdmR3DevHlp_PhysRead: caller='%s'/%d: GCPhys=%RGp pvBuf=%p cbRead=%#x\n",
              pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, GCPhys, pvBuf, cbRead));
 
-    /*
-     * For the convenience of the device we put no thread restriction on this interface.
-     * That means we'll have to check which thread we're in and choose our path.
-     */
-#ifdef PDM_PHYS_READWRITE_FROM_ANY_THREAD
-    PGMPhysRead(pDevIns->Internal.s.pVMR3, GCPhys, pvBuf, cbRead);
-#else
-    if (VM_IS_EMT(pDevIns->Internal.s.pVMR3) || VMMR3LockIsOwner(pDevIns->Internal.s.pVMR3))
-        PGMPhysRead(pDevIns->Internal.s.pVMR3, GCPhys, pvBuf, cbRead);
+    int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_NEW_PHYS_CODE
+    if (!VM_IS_EMT(pVM))
+        rc = PGMR3PhysReadExternal(pVM, GCPhys, pvBuf, cbRead);
     else
-    {
-        Log(("pdmR3DevHlp_PhysRead: caller='%s'/%d: Requesting call in EMT...\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
-        PVMREQ pReq;
-        AssertCompileSize(RTGCPHYS, 4);
-        int rc = VMR3ReqCallVoid(pDevIns->Internal.s.pVMR3, &pReq, RT_INDEFINITE_WAIT,
-                                 (PFNRT)PGMPhysRead, 4, pDevIns->Internal.s.pVMR3, GCPhys, pvBuf, cbRead);
-        while (rc == VERR_TIMEOUT)
-            rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
-        AssertReleaseRC(rc);
-        VMR3ReqFree(pReq);
-    }
 #endif
-    Log(("pdmR3DevHlp_PhysRead: caller='%s'/%d: returns void\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
+        PGMPhysRead(pVM, GCPhys, pvBuf, cbRead);
+    Log(("pdmR3DevHlp_PhysRead: caller='%s'/%d: returns %Rrc\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
+    /** @todo return rc; */ NOREF(rc);
 }
 
@@ -2066,30 +2047,17 @@
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    PVM pVM = pDevIns->Internal.s.pVMR3;
     LogFlow(("pdmR3DevHlp_PhysWrite: caller='%s'/%d: GCPhys=%RGp pvBuf=%p cbWrite=%#x\n",
              pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, GCPhys, pvBuf, cbWrite));
 
-    /*
-     * For the convenience of the device we put no thread restriction on this interface.
-     * That means we'll have to check which thread we're in and choose our path.
-     */
-#ifdef PDM_PHYS_READWRITE_FROM_ANY_THREAD
-    PGMPhysWrite(pDevIns->Internal.s.pVMR3, GCPhys, pvBuf, cbWrite);
-#else
-    if (VM_IS_EMT(pDevIns->Internal.s.pVMR3) || VMMR3LockIsOwner(pDevIns->Internal.s.pVMR3))
-        PGMPhysWrite(pDevIns->Internal.s.pVMR3, GCPhys, pvBuf, cbWrite);
+    int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_NEW_PHYS_CODE
+    if (!VM_IS_EMT(pVM))
+        rc = PGMR3PhysWriteExternal(pVM, GCPhys, pvBuf, cbWrite);
     else
-    {
-        Log(("pdmR3DevHlp_PhysWrite: caller='%s'/%d: Requesting call in EMT...\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
-        PVMREQ pReq;
-        AssertCompileSize(RTGCPHYS, 4);
-        int rc = VMR3ReqCallVoid(pDevIns->Internal.s.pVMR3, &pReq, RT_INDEFINITE_WAIT,
-                                 (PFNRT)PGMPhysWrite, 4, pDevIns->Internal.s.pVMR3, GCPhys, pvBuf, cbWrite);
-        while (rc == VERR_TIMEOUT)
-            rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
-        AssertReleaseRC(rc);
-        VMR3ReqFree(pReq);
-    }
 #endif
-    Log(("pdmR3DevHlp_PhysWrite: caller='%s'/%d: returns void\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
+        PGMPhysWrite(pVM, GCPhys, pvBuf, cbWrite);
+    Log(("pdmR3DevHlp_PhysWrite: caller='%s'/%d: returns %Rrc\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
+    /** @todo return rc; */ NOREF(rc);
 }
 
Index: trunk/src/VBox/VMM/PGMPhys.cpp
===================================================================
--- trunk/src/VBox/VMM/PGMPhys.cpp	(revision 17509)
+++ trunk/src/VBox/VMM/PGMPhys.cpp	(revision 17510)
@@ -87,4 +87,261 @@
 #define PGMPHYS_DATATYPE    uint64_t
 #include "PGMPhysRWTmpl.h"
+
+
+/**
+ * EMT worker for PGMR3PhysReadExternal.
+ */
+static DECLCALLBACK(int) pgmR3PhysReadExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, void *pvBuf, size_t cbRead)
+{
+    PGMPhysRead(pVM, *pGCPhys, pvBuf, cbRead);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Write to physical memory, external users.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS.
+ *
+ * @param   pVM             VM Handle.
+ * @param   GCPhys          Physical address to write to.
+ * @param   pvBuf           What to write.
+ * @param   cbWrite         How many bytes to write.
+ *
+ * @thread  Any but EMTs.
+ */
+VMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+{
+    VM_ASSERT_OTHER_THREAD(pVM);
+
+    AssertMsgReturn(cbRead > 0, ("don't even think about reading zero bytes!\n"), VINF_SUCCESS);
+    LogFlow(("PGMR3PhysReadExternal: %RGp %d\n", GCPhys, cbRead));
+
+    pgmLock(pVM);
+
+    /*
+     * Copy loop on ram ranges.
+     */
+    PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
+    for (;;)
+    {
+        /* Find range. */
+        while (pRam && GCPhys > pRam->GCPhysLast)
+            pRam = pRam->CTX_SUFF(pNext);
+        /* Inside range or not? */
+        if (pRam && GCPhys >= pRam->GCPhys)
+        {
+            /*
+             * Must work our way thru this page by page.
+             */
+            RTGCPHYS off = GCPhys - pRam->GCPhys;
+            while (off < pRam->cb)
+            {
+                unsigned iPage = off >> PAGE_SHIFT;
+                PPGMPAGE pPage = &pRam->aPages[iPage];
+
+                /*
+                 * If the page has an ALL access handler, we'll have to
+                 * delegate the job to EMT.
+                 */
+                if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
+                {
+                    pgmUnlock(pVM);
+
+                    PVMREQ pReq = NULL;
+                    int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
+                                         (PFNRT)pgmR3PhysReadExternalEMT, 4, pVM, &GCPhys, pvBuf, cbRead);
+                    if (RT_SUCCESS(rc))
+                    {
+                        rc = pReq->iStatus;
+                        VMR3ReqFree(pReq);
+                    }
+                    return rc;
+                }
+                Assert(!PGM_PAGE_IS_MMIO(pPage));
+
+                /*
+                 * Simple stuff, go ahead.
+                 */
+                size_t   cb    = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
+                if (cb > cbRead)
+                    cb = cbRead;
+                const void *pvSrc;
+                int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, pRam->GCPhys + off, &pvSrc);
+                if (RT_SUCCESS(rc))
+                    memcpy(pvBuf, pvSrc, cb);
+                else
+                {
+                    AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
+                                           pRam->GCPhys + off, pPage, rc));
+                    memset(pvBuf, 0xff, cb);
+                }
+
+                /* next page */
+                if (cb >= cbRead)
+                {
+                    pgmUnlock(pVM);
+                    return VINF_SUCCESS;
+                }
+                cbRead -= cb;
+                off    += cb;
+                GCPhys += cb;
+                pvBuf   = (char *)pvBuf + cb;
+            } /* walk pages in ram range. */
+        }
+        else
+        {
+            LogFlow(("PGMPhysRead: Unassigned %RGp size=%u\n", GCPhys, cbRead));
+
+            /*
+             * Unassigned address space.
+             */
+            if (!pRam)
+                break;
+            size_t cb = pRam->GCPhys - GCPhys;
+            if (cb >= cbRead)
+            {
+                memset(pvBuf, 0xff, cbRead);
+                break;
+            }
+            memset(pvBuf, 0xff, cb);
+
+            cbRead -= cb;
+            pvBuf   = (char *)pvBuf + cb;
+            GCPhys += cb;
+        }
+    } /* Ram range walk */
+
+    pgmUnlock(pVM);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * EMT worker for PGMR3PhysWriteExternal.
+ */
+static DECLCALLBACK(int) pgmR3PhysWriteExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, const void *pvBuf, size_t cbWrite)
+{
+    /** @todo VERR_EM_NO_MEMORY */
+    PGMPhysWrite(pVM, *pGCPhys, pvBuf, cbWrite);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Write to physical memory, external users.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS.
+ * @retval  VERR_EM_NO_MEMORY.
+ *
+ * @param   pVM             VM Handle.
+ * @param   GCPhys          Physical address to write to.
+ * @param   pvBuf           What to write.
+ * @param   cbWrite         How many bytes to write.
+ *
+ * @thread  Any but EMTs.
+ */
+VMMDECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+{
+    VM_ASSERT_OTHER_THREAD(pVM);
+
+    AssertMsg(!pVM->pgm.s.fNoMorePhysWrites, ("Calling PGMR3PhysWriteExternal after pgmR3Save()!\n"));
+    AssertMsgReturn(cbWrite > 0, ("don't even think about writing zero bytes!\n"), VINF_SUCCESS);
+    LogFlow(("PGMR3PhysWriteExternal: %RGp %d\n", GCPhys, cbWrite));
+
+    pgmLock(pVM);
+
+    /*
+     * Copy loop on ram ranges, stop when we hit something difficult.
+     */
+    PPGMRAMRANGE    pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
+    for (;;)
+    {
+        /* Find range. */
+        while (pRam && GCPhys > pRam->GCPhysLast)
+            pRam = pRam->CTX_SUFF(pNext);
+        /* Inside range or not? */
+        if (pRam && GCPhys >= pRam->GCPhys)
+        {
+            /*
+             * Must work our way thru this page by page.
+             */
+            RTGCPTR off = GCPhys - pRam->GCPhys;
+            while (off < pRam->cb)
+            {
+                RTGCPTR     iPage = off >> PAGE_SHIFT;
+                PPGMPAGE    pPage = &pRam->aPages[iPage];
+
+                /*
+                 * It the page is in any way problematic, we have to
+                 * do the work on the EMT. Anything that needs to be made
+                 * writable or involves access handlers is problematic.
+                 */
+                if (    PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
+                    ||  PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
+                {
+                    pgmUnlock(pVM);
+
+                    PVMREQ pReq = NULL;
+                    int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
+                                         (PFNRT)pgmR3PhysWriteExternalEMT, 4, pVM, &GCPhys, pvBuf, cbWrite);
+                    if (RT_SUCCESS(rc))
+                    {
+                        rc = pReq->iStatus;
+                        VMR3ReqFree(pReq);
+                    }
+                    return rc;
+                }
+                Assert(!PGM_PAGE_IS_MMIO(pPage));
+
+                /*
+                 * Simple stuff, go ahead.
+                 */
+                size_t      cb    = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
+                if (cb > cbWrite)
+                    cb = cbWrite;
+                void *pvDst;
+                int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pRam->GCPhys + off, &pvDst);
+                if (RT_SUCCESS(rc))
+                    memcpy(pvDst, pvBuf, cb);
+                else
+                    AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
+                                           pRam->GCPhys + off, pPage, rc));
+
+                /* next page */
+                if (cb >= cbWrite)
+                {
+                    pgmUnlock(pVM);
+                    return VINF_SUCCESS;
+                }
+
+                cbWrite -= cb;
+                off     += cb;
+                GCPhys  += cb;
+                pvBuf    = (const char *)pvBuf + cb;
+            } /* walk pages in ram range */
+        }
+        else
+        {
+            /*
+             * Unassigned address space, skip it.
+             */
+            if (!pRam)
+                break;
+            size_t cb = pRam->GCPhys - GCPhys;
+            if (cb >= cbWrite)
+                break;
+            cbWrite -= cb;
+            pvBuf   = (const char *)pvBuf + cb;
+            GCPhys += cb;
+        }
+    } /* Ram range walk */
+
+    pgmUnlock(pVM);
+    return VINF_SUCCESS;
+}
 
 
Index: trunk/src/VBox/VMM/VMMAll/EMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/EMAll.cpp	(revision 17509)
+++ trunk/src/VBox/VMM/VMMAll/EMAll.cpp	(revision 17510)
@@ -299,8 +299,8 @@
 
 
-DECLINLINE(int) emRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
-{
-#ifdef IN_RC
-    int rc = MMGCRamRead(pVM, pDest, (void *)GCSrc, cb);
+DECLINLINE(int) emRamRead(PVM pVM, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCPTR GCPtrSrc, uint32_t cb)
+{
+#ifdef IN_RC
+    int rc = MMGCRamRead(pVM, pvDst, (void *)GCPtrSrc, cb);
     if (RT_LIKELY(rc != VERR_ACCESS_DENIED))
         return rc;
@@ -310,19 +310,26 @@
      * instruction and it either flushed the TLB or the CPU reused it.
      */
+#endif
+#ifdef VBOX_WITH_NEW_PHYS_CODE
+    return PGMPhysInterpretedReadNoHandlers(pVM, pCtxCore, pvDst, GCPtrSrc, cb, /*fMayTrap*/ false);
+#else
+    NOREF(pCtxCore);
+# ifdef IN_RC
     RTGCPHYS GCPhys;
-    rc = PGMPhysGCPtr2GCPhys(pVM, GCSrc, &GCPhys);
+    rc = PGMPhysGCPtr2GCPhys(pVM, GCPtrSrc, &GCPhys);
     AssertRCReturn(rc, rc);
-    PGMPhysRead(pVM, GCPhys, pDest, cb);
+    PGMPhysRead(pVM, GCPhys, pvDst, cb);
     return VINF_SUCCESS;
-#else
-    return PGMPhysReadGCPtr(pVM, pDest, GCSrc, cb);
-#endif
-}
-
-
-DECLINLINE(int) emRamWrite(PVM pVM, RTGCPTR GCDest, void *pSrc, uint32_t cb)
-{
-#ifdef IN_RC
-    int rc = MMGCRamWrite(pVM, (void *)GCDest, pSrc, cb);
+# else
+    return PGMPhysReadGCPtr(pVM, pvDst, GCPtrSrc, cb);
+# endif
+#endif
+}
+
+
+DECLINLINE(int) emRamWrite(PVM pVM, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, const void *pvSrc, uint32_t cb)
+{
+#ifdef IN_RC
+    int rc = MMGCRamWrite(pVM, (void *)(uintptr_t)GCPtrDst, (void *)pvSrc, cb);
     if (RT_LIKELY(rc != VERR_ACCESS_DENIED))
         return rc;
@@ -334,7 +341,13 @@
      * access doesn't cost us much (see PGMPhysGCPtr2GCPhys()).
      */
+#endif
+#ifdef VBOX_WITH_NEW_PHYS_CODE
+    return PGMPhysInterpretedWriteNoHandlers(pVM, pCtxCore, GCPtrDst, pvSrc, cb, /*fMayTrap*/ false);
+#else
+    NOREF(pCtxCore);
+# ifdef IN_RC
     uint64_t fFlags;
     RTGCPHYS GCPhys;
-    rc = PGMGstGetPage(pVM, GCDest, &fFlags, &GCPhys);
+    rc = PGMGstGetPage(pVM, GCPtrDst, &fFlags, &GCPhys);
     if (RT_FAILURE(rc))
         return rc;
@@ -345,7 +358,7 @@
     PGMPhysWrite(pVM, GCPhys + ((RTGCUINTPTR)GCDest & PAGE_OFFSET_MASK), pSrc, cb);
     return VINF_SUCCESS;
-
-#else
-    return PGMPhysWriteGCPtr(pVM, GCDest, pSrc, cb);
+# else
+    return PGMPhysWriteGCPtr(pVM, GCPtrDst, pvSrc, cb);
+# endif
 #endif
 }
@@ -455,5 +468,5 @@
                 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
                 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault, VERR_EM_INTERPRETER);
-                rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
+                rc = emRamRead(pVM, pRegFrame, &valpar1, pParam1, param1.size);
                 if (RT_FAILURE(rc))
                 {
@@ -474,5 +487,5 @@
                 pParam2 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param2, pParam2);
                 EM_ASSERT_FAULT_RETURN(pParam2 == pvFault, VERR_EM_INTERPRETER);
-                rc = emRamRead(pVM,  &valpar2, pParam2, param2.size);
+                rc = emRamRead(pVM, pRegFrame, &valpar2, pParam2, param2.size);
                 if (RT_FAILURE(rc))
                 {
@@ -508,5 +521,5 @@
             else
             {
-                rc = emRamWrite(pVM, pParam1, &valpar2, param1.size);
+                rc = emRamWrite(pVM, pRegFrame, pParam1, &valpar2, param1.size);
                 if (RT_FAILURE(rc))
                 {
@@ -534,5 +547,5 @@
             else
             {
-                rc = emRamWrite(pVM, pParam2, &valpar1, param2.size);
+                rc = emRamWrite(pVM, pRegFrame, pParam2, &valpar1, param2.size);
                 if (RT_FAILURE(rc))
                 {
@@ -581,5 +594,5 @@
                 AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
 #endif
-                rc = emRamRead(pVM,  &valpar1, pParam1, param1.size);
+                rc = emRamRead(pVM, pRegFrame,  &valpar1, pParam1, param1.size);
                 if (RT_FAILURE(rc))
                 {
@@ -599,5 +612,5 @@
 
             /* Write result back */
-            rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
+            rc = emRamWrite(pVM, pRegFrame, pParam1, &valpar1, param1.size);
             if (RT_FAILURE(rc))
             {
@@ -651,5 +664,5 @@
                 return VERR_EM_INTERPRETER;
 
-            rc = emRamRead(pVM,  &valpar1, pStackVal, param1.size);
+            rc = emRamRead(pVM, pRegFrame, &valpar1, pStackVal, param1.size);
             if (RT_FAILURE(rc))
             {
@@ -672,5 +685,5 @@
                 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
                 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault || (RTGCPTR)pRegFrame->esp == pvFault, VERR_EM_INTERPRETER);
-                rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
+                rc = emRamWrite(pVM, pRegFrame, pParam1, &valpar1, param1.size);
                 if (RT_FAILURE(rc))
                 {
@@ -744,5 +757,5 @@
                 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
                 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault, VERR_EM_INTERPRETER);
-                rc = emRamRead(pVM,  &valpar1, pParam1, param1.size);
+                rc = emRamRead(pVM, pRegFrame, &valpar1, pParam1, param1.size);
                 if (RT_FAILURE(rc))
                 {
@@ -781,5 +794,5 @@
 
             /* And write it back */
-            rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
+            rc = emRamWrite(pVM, pRegFrame, pParam1, &valpar1, param1.size);
             if (RT_SUCCESS(rc))
             {
@@ -922,5 +935,5 @@
                 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
                 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault, VERR_EM_INTERPRETER);
-                rc = emRamRead(pVM,  &valpar1, pParam1, param1.size);
+                rc = emRamRead(pVM, pRegFrame, &valpar1, pParam1, param1.size);
                 if (RT_FAILURE(rc))
                 {
@@ -957,5 +970,5 @@
 
             /* And write it back */
-            rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
+            rc = emRamWrite(pVM, pRegFrame, pParam1, &valpar1, param1.size);
             if (RT_SUCCESS(rc))
             {
@@ -1031,5 +1044,5 @@
             pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + valpar2/8);
             EM_ASSERT_FAULT_RETURN((RTGCPTR)((RTGCUINTPTR)pParam1 & ~3) == pvFault, VERR_EM_INTERPRETER);
-            rc = emRamRead(pVM, &valpar1, pParam1, 1);
+            rc = emRamRead(pVM, pRegFrame, &valpar1, pParam1, 1);
             if (RT_FAILURE(rc))
             {
@@ -1049,5 +1062,5 @@
 
             /* And write it back */
-            rc = emRamWrite(pVM, pParam1, &valpar1, 1);
+            rc = emRamWrite(pVM, pRegFrame, pParam1, &valpar1, 1);
             if (RT_SUCCESS(rc))
             {
@@ -1202,5 +1215,5 @@
             Assert(param2.size <= 8 && param2.size > 0);
             EM_ASSERT_FAULT_RETURN(pDest == pvFault, VERR_EM_INTERPRETER);
-            rc = emRamWrite(pVM, pDest, &val64, param2.size);
+            rc = emRamWrite(pVM, pRegFrame, pDest, &val64, param2.size);
             if (RT_FAILURE(rc))
                 return VERR_EM_INTERPRETER;
@@ -1232,5 +1245,5 @@
             Assert(param1.size <= 8 && param1.size > 0);
             EM_ASSERT_FAULT_RETURN(pSrc == pvFault, VERR_EM_INTERPRETER);
-            rc = emRamRead(pVM, &val64, pSrc, param1.size);
+            rc = emRamRead(pVM, pRegFrame, &val64, pSrc, param1.size);
             if (RT_FAILURE(rc))
                 return VERR_EM_INTERPRETER;
@@ -1773,16 +1786,16 @@
     Assert(!CPUMIsGuestIn64BitCode(pVM, pRegFrame));
 
-    rc  = emRamRead(pVM, &eip,      (RTGCPTR)pIretStack      , 4);
-    rc |= emRamRead(pVM, &cs,       (RTGCPTR)(pIretStack + 4), 4);
-    rc |= emRamRead(pVM, &eflags,   (RTGCPTR)(pIretStack + 8), 4);
+    rc  = emRamRead(pVM, pRegFrame, &eip,      (RTGCPTR)pIretStack      , 4);
+    rc |= emRamRead(pVM, pRegFrame, &cs,       (RTGCPTR)(pIretStack + 4), 4);
+    rc |= emRamRead(pVM, pRegFrame, &eflags,   (RTGCPTR)(pIretStack + 8), 4);
     AssertRCReturn(rc, VERR_EM_INTERPRETER);
     AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER);
 
-    rc |= emRamRead(pVM, &esp,      (RTGCPTR)(pIretStack + 12), 4);
-    rc |= emRamRead(pVM, &ss,       (RTGCPTR)(pIretStack + 16), 4);
-    rc |= emRamRead(pVM, &es,       (RTGCPTR)(pIretStack + 20), 4);
-    rc |= emRamRead(pVM, &ds,       (RTGCPTR)(pIretStack + 24), 4);
-    rc |= emRamRead(pVM, &fs,       (RTGCPTR)(pIretStack + 28), 4);
-    rc |= emRamRead(pVM, &gs,       (RTGCPTR)(pIretStack + 32), 4);
+    rc |= emRamRead(pVM, pRegFrame, &esp,      (RTGCPTR)(pIretStack + 12), 4);
+    rc |= emRamRead(pVM, pRegFrame, &ss,       (RTGCPTR)(pIretStack + 16), 4);
+    rc |= emRamRead(pVM, pRegFrame, &es,       (RTGCPTR)(pIretStack + 20), 4);
+    rc |= emRamRead(pVM, pRegFrame, &ds,       (RTGCPTR)(pIretStack + 24), 4);
+    rc |= emRamRead(pVM, pRegFrame, &fs,       (RTGCPTR)(pIretStack + 28), 4);
+    rc |= emRamRead(pVM, pRegFrame, &gs,       (RTGCPTR)(pIretStack + 32), 4);
     AssertRCReturn(rc, VERR_EM_INTERPRETER);
 
@@ -2257,5 +2270,5 @@
         LogFlow(("emInterpretSmsw %VGv <- cr0 (%x)\n", pParam1, cr0));
 
-        rc = emRamWrite(pVM, pParam1, &cr0, sizeof(uint16_t));
+        rc = emRamWrite(pVM, pRegFrame, pParam1, &cr0, sizeof(uint16_t));
         if (RT_FAILURE(rc))
         {
@@ -2451,5 +2464,5 @@
     }
 
-    rc = emRamRead(pVM, &dtr32, pParam1, sizeof(dtr32));
+    rc = emRamRead(pVM, pRegFrame, &dtr32, pParam1, sizeof(dtr32));
     AssertRCReturn(rc, VERR_EM_INTERPRETER);
 
Index: trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 17509)
+++ trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 17510)
@@ -1538,17 +1538,9 @@
             if (cb >= cbRead)
             {
-#if 0 /** @todo enable this later. */
                 memset(pvBuf, 0xff, cbRead);
-#else
-                memset(pvBuf, 0, cbRead);
-#endif
                 break;
             }
 
-#if 0 /** @todo enable this later. */
             memset(pvBuf, 0xff, cb);
-#else
-            memset(pvBuf, 0, cb);
-#endif
             cbRead -= cb;
             pvBuf   = (char *)pvBuf + cb;
@@ -2583,4 +2575,5 @@
 #endif /* Old PGMPhysWrite */
 
+
 /**
  * Read from guest physical memory by GC physical address, bypassing
@@ -3257,5 +3250,399 @@
 }
 
-/// @todo VMMDECL(int) PGMPhysInterpretedWrite(PVM pVM, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
-
-
+
+/**
+ * Performs a read of guest virtual memory for instruction emulation.
+ *
+ * This will check permissions, raise exceptions and update the access bits.
+ *
+ * The current implementation will bypass all access handlers. It may later be
+ * changed to at least respect MMIO.
+ *
+ *
+ * @returns VBox status code suitable to scheduling.
+ * @retval  VINF_SUCCESS if the read was performed successfully.
+ * @retval  VINF_EM_RAW_GUEST_TRAP if an exception was raised but not dispatched yet.
+ * @retval  VINF_TRPM_XCPT_DISPATCHED if an exception was raised and dispatched.
+ *
+ * @param   pVM         The VM handle.
+ * @param   pCtxCore    The context core.
+ * @param   pvDst       Where to put the bytes we've read.
+ * @param   GCPtrSrc    The source address.
+ * @param   cb          The number of bytes to read. Not more than a page.
+ * @param   fRaiseTrap  If set the trap will be raised on as per spec, if clear
+ *                      an appropriate error status will be returned (no
+ *                      informational at all).
+ *
+ *
+ * @remarks Takes the PGM lock.
+ * @remarks A page fault on the 2nd page of the access will be raised without
+ *          writing the bits on the first page since we're ASSUMING that the
+ *          caller is emulating an instruction access.
+ * @remarks This function will dynamically map physical pages in GC. This may
+ *          unmap mappings done by the caller. Be careful!
+ */
+VMMDECL(int) PGMPhysInterpretedReadNoHandlers(PVM pVM, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCUINTPTR GCPtrSrc, size_t cb, bool fRaiseTrap)
+{
+    Assert(cb <= PAGE_SIZE);
+
+    /*
+     * 1. Translate virtual to physical. This may fault.
+     * 2. Map the physical address.
+     * 3. Do the read operation.
+     * 4. Set access bits if required.
+     */
+    int rc;
+    unsigned cb1 = PAGE_SIZE - (GCPtrSrc & PAGE_OFFSET_MASK);
+    if (cb <= cb1)
+    {
+        /*
+         * Not crossing pages.
+         */
+        RTGCPHYS    GCPhys;
+        uint64_t    fFlags;
+        rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrSrc, &fFlags, &GCPhys);
+        if (RT_SUCCESS(rc))
+        {
+            if (1) /** @todo we should check reserved bits ... */
+            {
+                const void *pvSrc;
+                PGMPAGEMAPLOCK Lock;
+                rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvSrc, &Lock);
+                switch (rc)
+                {
+                    case VINF_SUCCESS:
+                        Log(("PGMPhysInterpretedReadNoHandlers: pvDst=%p pvSrc=%p (%RGv) cb=%d\n",
+                               pvDst, (const uint8_t *)pvSrc + (GCPtrSrc & PAGE_OFFSET_MASK), GCPtrSrc, cb));
+                        memcpy(pvDst, (const uint8_t *)pvSrc + (GCPtrSrc & PAGE_OFFSET_MASK), cb);
+                        break;
+                    case VERR_PGM_PHYS_PAGE_RESERVED:
+                    case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
+                        memset(pvDst, 0xff, cb);
+                        break;
+                    default:
+                        AssertMsgFailed(("%Rrc\n", rc));
+                        AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+                        return rc;
+                }
+                PGMPhysReleasePageMappingLock(pVM, &Lock);
+
+                if (!(fFlags & X86_PTE_A))
+                {
+                    /** @todo access bit emulation isn't 100% correct. */
+                    rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)X86_PTE_A);
+                    AssertRC(rc);
+                }
+                return VINF_SUCCESS;
+            }
+        }
+    }
+    else
+    {
+        /*
+         * Crosses pages.
+         */
+        size_t      cb2 = cb - cb1;
+        uint64_t    fFlags1;
+        RTGCPHYS    GCPhys1;
+        uint64_t    fFlags2;
+        RTGCPHYS    GCPhys2;
+        rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrSrc, &fFlags1, &GCPhys1);
+        if (RT_SUCCESS(rc))
+        {
+            rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrSrc + cb1, &fFlags2, &GCPhys2);
+            if (RT_SUCCESS(rc))
+            {
+                if (1) /** @todo we should check reserved bits ... */
+                {
+                    const void *pvSrc;
+                    PGMPAGEMAPLOCK Lock;
+                    rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys1, &pvSrc, &Lock);
+                    switch (rc)
+                    {
+                        case VINF_SUCCESS:
+                            Log(("PGMPhysInterpretedReadNoHandlers: pvDst=%p pvSrc=%p (%RGv) cb=%d [2]\n",
+                                   pvDst, (const uint8_t *)pvSrc + (GCPtrSrc & PAGE_OFFSET_MASK), GCPtrSrc, cb1));
+                            memcpy(pvDst, (const uint8_t *)pvSrc + (GCPtrSrc & PAGE_OFFSET_MASK), cb1);
+                            PGMPhysReleasePageMappingLock(pVM, &Lock);
+                            break;
+                        case VERR_PGM_PHYS_PAGE_RESERVED:
+                        case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
+                            memset(pvDst, 0xff, cb1);
+                            break;
+                        default:
+                            AssertMsgFailed(("%Rrc\n", rc));
+                            AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+                            return rc;
+                    }
+
+                    rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys2, &pvSrc, &Lock);
+                    switch (rc)
+                    {
+                        case VINF_SUCCESS:
+                            memcpy((uint8_t *)pvDst + cb1, pvSrc, cb2);
+                            PGMPhysReleasePageMappingLock(pVM, &Lock);
+                            break;
+                        case VERR_PGM_PHYS_PAGE_RESERVED:
+                        case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
+                            memset((uint8_t *)pvDst + cb1, 0xff, cb2);
+                            break;
+                        default:
+                            AssertMsgFailed(("%Rrc\n", rc));
+                            AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+                            return rc;
+                    }
+
+                    if (!(fFlags1 & X86_PTE_A))
+                    {
+                        rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)X86_PTE_A);
+                        AssertRC(rc);
+                    }
+                    if (!(fFlags2 & X86_PTE_A))
+                    {
+                        rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrSrc + cb1, 1, X86_PTE_A, ~(uint64_t)X86_PTE_A);
+                        AssertRC(rc);
+                    }
+                    return VINF_SUCCESS;
+                }
+                /* sort out which page */
+            }
+            else
+                GCPtrSrc += cb1; /* fault on 2nd page */
+        }
+    }
+
+    /*
+     * Raise a #PF if we're allowed to do that.
+     */
+    /* Calc the error bits. */
+    uint32_t cpl = CPUMGetGuestCPL(pVM, pCtxCore);
+    uint32_t uErr;
+    switch (rc)
+    {
+        case VINF_SUCCESS:
+            uErr = (cpl >= 2) ? X86_TRAP_PF_RSVD | X86_TRAP_PF_US : X86_TRAP_PF_RSVD;
+            rc = VERR_ACCESS_DENIED;
+            break;
+
+        case VERR_PAGE_NOT_PRESENT:
+        case VERR_PAGE_TABLE_NOT_PRESENT:
+            uErr = (cpl >= 2) ? X86_TRAP_PF_US : 0;
+            break;
+
+        default:
+            AssertMsgFailed(("rc=%Rrc GCPtrSrc=%RGv cb=%#x\n", rc, GCPtrSrc, cb));
+            AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+            return rc;
+    }
+    if (fRaiseTrap)
+    {
+        Log(("PGMPhysInterpretedReadNoHandlers: GCPtrSrc=%RGv cb=%#x -> Raised #PF(%#x)\n", GCPtrSrc, cb, uErr));
+        return TRPMRaiseXcptErrCR2(pVM, pCtxCore, X86_XCPT_PF, uErr, GCPtrSrc);
+    }
+    Log(("PGMPhysInterpretedReadNoHandlers: GCPtrSrc=%RGv cb=%#x -> #PF(%#x) [!raised]\n", GCPtrSrc, cb, uErr));
+    return rc;
+}
+
+
+/**
+ * Performs a write to guest virtual memory for instruction emulation.
+ *
+ * This will check permissions, raise exceptions and update the dirty and access
+ * bits.
+ *
+ * @returns VBox status code suitable to scheduling.
+ * @retval  VINF_SUCCESS if the read was performed successfully.
+ * @retval  VINF_EM_RAW_GUEST_TRAP if an exception was raised but not dispatched yet.
+ * @retval  VINF_TRPM_XCPT_DISPATCHED if an exception was raised and dispatched.
+ *
+ * @param   pVM         The VM handle.
+ * @param   pCtxCore    The context core.
+ * @param   GCPtrDst    The destination address.
+ * @param   pvSrc       What to write.
+ * @param   cb          The number of bytes to write. Not more than a page.
+ * @param   fRaiseTrap  If set the trap will be raised on as per spec, if clear
+ *                      an appropriate error status will be returned (no
+ *                      informational at all).
+ *
+ * @remarks Takes the PGM lock.
+ * @remarks A page fault on the 2nd page of the access will be raised without
+ *          writing the bits on the first page since we're ASSUMING that the
+ *          caller is emulating an instruction access.
+ * @remarks This function will dynamically map physical pages in GC. This may
+ *          unmap mappings done by the caller. Be careful!
+ */
+VMMDECL(int) PGMPhysInterpretedWriteNoHandlers(PVM pVM, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb, bool fRaiseTrap)
+{
+    Assert(cb <= PAGE_SIZE);
+
+    /*
+     * 1. Translate virtual to physical. This may fault.
+     * 2. Map the physical address.
+     * 3. Do the write operation.
+     * 4. Set access bits if required.
+     */
+    int rc;
+    unsigned cb1 = PAGE_SIZE - (GCPtrDst & PAGE_OFFSET_MASK);
+    if (cb <= cb1)
+    {
+        /*
+         * Not crossing pages.
+         */
+        RTGCPHYS    GCPhys;
+        uint64_t    fFlags;
+        rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrDst, &fFlags, &GCPhys);
+        if (RT_SUCCESS(rc))
+        {
+            if (    (fFlags & X86_PTE_RW)                   /** @todo Also check reserved bits. */
+                ||  (   !(CPUMGetGuestCR0(pVM) & X86_CR0_WP)
+                     &&   CPUMGetGuestCPL(pVM, pCtxCore) <= 2) ) /** @todo it's 2, right? Check cpl check below as well. */
+            {
+                void *pvDst;
+                PGMPAGEMAPLOCK Lock;
+                rc = PGMPhysGCPhys2CCPtr(pVM, GCPhys, &pvDst, &Lock);
+                switch (rc)
+                {
+                    case VINF_SUCCESS:
+                        Log(("PGMPhysInterpretedWriteNoHandlers: pvDst=%p (%RGv) pvSrc=%p cb=%d\n",
+                               (uint8_t *)pvDst + (GCPtrDst & PAGE_OFFSET_MASK), GCPtrDst, pvSrc,  cb));
+                        memcpy((uint8_t *)pvDst + (GCPtrDst & PAGE_OFFSET_MASK), pvSrc, cb);
+                        PGMPhysReleasePageMappingLock(pVM, &Lock);
+                        break;
+                    case VERR_PGM_PHYS_PAGE_RESERVED:
+                    case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
+                        /* bit bucket */
+                        break;
+                    default:
+                        AssertMsgFailed(("%Rrc\n", rc));
+                        AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+                        return rc;
+                }
+
+                if (!(fFlags & (X86_PTE_A | X86_PTE_D)))
+                {
+                    /** @todo dirty & access bit emulation isn't 100% correct. */
+                    rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
+                    AssertRC(rc);
+                }
+                return VINF_SUCCESS;
+            }
+            rc = VERR_ACCESS_DENIED;
+        }
+    }
+    else
+    {
+        /*
+         * Crosses pages.
+         */
+        size_t      cb2 = cb - cb1;
+        uint64_t    fFlags1;
+        RTGCPHYS    GCPhys1;
+        uint64_t    fFlags2;
+        RTGCPHYS    GCPhys2;
+        rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrDst, &fFlags1, &GCPhys1);
+        if (RT_SUCCESS(rc))
+        {
+            rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrDst + cb1, &fFlags2, &GCPhys2);
+            if (RT_SUCCESS(rc))
+            {
+                if (    (   (fFlags1 & X86_PTE_RW)  /** @todo Also check reserved bits. */
+                         && (fFlags2 & X86_PTE_RW))
+                    ||  (   !(CPUMGetGuestCR0(pVM) & X86_CR0_WP)
+                         &&   CPUMGetGuestCPL(pVM, pCtxCore) <= 2) )
+                {
+                    void *pvDst;
+                    PGMPAGEMAPLOCK Lock;
+                    rc = PGMPhysGCPhys2CCPtr(pVM, GCPhys1, &pvDst, &Lock);
+                    switch (rc)
+                    {
+                        case VINF_SUCCESS:
+                            Log(("PGMPhysInterpretedWriteNoHandlers: pvDst=%p (%RGv) pvSrc=%p cb=%d\n",
+                                   (uint8_t *)pvDst + (GCPtrDst & PAGE_OFFSET_MASK), GCPtrDst, pvSrc, cb1));
+                            memcpy((uint8_t *)pvDst + (GCPtrDst & PAGE_OFFSET_MASK), pvSrc, cb1);
+                            PGMPhysReleasePageMappingLock(pVM, &Lock);
+                            break;
+                        case VERR_PGM_PHYS_PAGE_RESERVED:
+                        case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
+                            /* bit bucket */
+                            break;
+                        default:
+                            AssertMsgFailed(("%Rrc\n", rc));
+                            AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+                            return rc;
+                    }
+
+                    rc = PGMPhysGCPhys2CCPtr(pVM, GCPhys2, &pvDst, &Lock);
+                    switch (rc)
+                    {
+                        case VINF_SUCCESS:
+                            memcpy(pvDst, (const uint8_t *)pvSrc + cb1, cb2);
+                            PGMPhysReleasePageMappingLock(pVM, &Lock);
+                            break;
+                        case VERR_PGM_PHYS_PAGE_RESERVED:
+                        case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
+                            /* bit bucket */
+                            break;
+                        default:
+                            AssertMsgFailed(("%Rrc\n", rc));
+                            AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+                            return rc;
+                    }
+
+                    if (!(fFlags1 & (X86_PTE_A | X86_PTE_RW)))
+                    {
+                        rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrDst, 1, (X86_PTE_A | X86_PTE_RW), ~(uint64_t)(X86_PTE_A | X86_PTE_RW));
+                        AssertRC(rc);
+                    }
+                    if (!(fFlags2 & (X86_PTE_A | X86_PTE_RW)))
+                    {
+                        rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrDst + cb1, 1, (X86_PTE_A | X86_PTE_RW), ~(uint64_t)(X86_PTE_A | X86_PTE_RW));
+                        AssertRC(rc);
+                    }
+                    return VINF_SUCCESS;
+                }
+                if ((fFlags1 & (X86_PTE_RW)) == X86_PTE_RW)
+                    GCPtrDst += cb1; /* fault on the 2nd page. */
+                rc = VERR_ACCESS_DENIED;
+            }
+            else
+                GCPtrDst += cb1; /* fault on the 2nd page. */
+        }
+    }
+
+    /*
+     * Raise a #PF if we're allowed to do that.
+     */
+    /* Calc the error bits. */
+    uint32_t uErr;
+    uint32_t cpl = CPUMGetGuestCPL(pVM, pCtxCore);
+    switch (rc)
+    {
+        case VINF_SUCCESS:
+            uErr = (cpl >= 2) ? X86_TRAP_PF_RSVD | X86_TRAP_PF_US : X86_TRAP_PF_RSVD;
+            rc = VERR_ACCESS_DENIED;
+            break;
+
+        case VERR_ACCESS_DENIED:
+            uErr = (cpl >= 2) ? X86_TRAP_PF_RW | X86_TRAP_PF_US : X86_TRAP_PF_RW;
+            break;
+
+        case VERR_PAGE_NOT_PRESENT:
+        case VERR_PAGE_TABLE_NOT_PRESENT:
+            uErr = (cpl >= 2) ? X86_TRAP_PF_US : 0;
+            break;
+
+        default:
+            AssertMsgFailed(("rc=%Rrc GCPtrDst=%RGv cb=%#x\n", rc, GCPtrDst, cb));
+            AssertReturn(RT_FAILURE(rc), VERR_INTERNAL_ERROR);
+            return rc;
+    }
+    if (fRaiseTrap)
+    {
+        Log(("PGMPhysInterpretedWriteNoHandlers: GCPtrDst=%RGv cb=%#x -> Raised #PF(%#x)\n", GCPtrDst, cb, uErr));
+        return TRPMRaiseXcptErrCR2(pVM, pCtxCore, X86_XCPT_PF, uErr, GCPtrDst);
+    }
+    Log(("PGMPhysInterpretedWriteNoHandlers: GCPtrDst=%RGv cb=%#x -> #PF(%#x) [!raised]\n", GCPtrDst, cb, uErr));
+    return rc;
+}
+
+
