Index: trunk/src/VBox/VMM/Makefile.kmk
===================================================================
--- trunk/src/VBox/VMM/Makefile.kmk	(revision 47425)
+++ trunk/src/VBox/VMM/Makefile.kmk	(revision 47427)
@@ -36,7 +36,7 @@
  VMM_COMMON_DEFS += VBOX_WITH_FIRST_IEM_STEP
 endif
-ifdef VBOX_WITH_IEM
- VMM_COMMON_DEFS += VBOX_WITH_IEM
-endif
+#ifdef VBOX_WITH_IEM
+# VMM_COMMON_DEFS += VBOX_WITH_IEM
+#endif
 ifdef VBOX_WITH_REM
  VMM_COMMON_DEFS += VBOX_WITH_REM
Index: trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 47425)
+++ trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 47427)
@@ -824,5 +824,5 @@
     pIemCpu->rcPassUp           = VINF_SUCCESS;
     pIemCpu->fBypassHandlers    = fBypassHandlers;
-#ifdef IN_RC
+#ifdef VBOX_WITH_RAW_MODE_NOT_R0
     pIemCpu->fInPatchCode       = pIemCpu->uCpl == 0
                                && pCtx->cs.u64Base == 0
@@ -872,22 +872,24 @@
             return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
         cbToTryRead = pCtx->cs.u32Limit - GCPtrPC32 + 1;
+        if (!cbToTryRead) /* overflowed */
+        {
+            Assert(GCPtrPC32 == 0); Assert(pCtx->cs.u32Limit == UINT32_MAX);
+            cbToTryRead = UINT32_MAX;
+        }
         GCPtrPC = pCtx->cs.u64Base + GCPtrPC32;
     }
 
-#if defined(IN_RC) && defined(VBOX_WITH_RAW_MODE)
+#ifdef VBOX_WITH_RAW_MODE_NOT_R0
     /* Allow interpretation of patch manager code blocks since they can for
        instance throw #PFs for perfectly good reasons. */
     if (pIemCpu->fInPatchCode)
     {
-        uint32_t cbLeftOnPage = PAGE_SIZE - (GCPtrPC & PAGE_OFFSET_MASK);
-        if (cbToTryRead > cbLeftOnPage)
-            cbToTryRead = cbLeftOnPage;
-        if (cbToTryRead > sizeof(pIemCpu->abOpcode))
-            cbToTryRead = sizeof(pIemCpu->abOpcode);
-        memcpy(pIemCpu->abOpcode, (void const *)(uintptr_t)GCPtrPC, cbToTryRead);
-        pIemCpu->cbOpcode = cbToTryRead;
+        size_t cbRead = 0;
+        int rc = PATMReadPatchCode(IEMCPU_TO_VM(pIemCpu), GCPtrPC, pIemCpu->abOpcode, sizeof(pIemCpu->abOpcode), &cbRead);
+        AssertRCReturn(rc, rc);
+        pIemCpu->cbOpcode = (uint8_t)cbRead; Assert(pIemCpu->cbOpcode == cbRead); Assert(cbRead > 0);
         return VINF_SUCCESS;
     }
-#endif
+#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
 
     RTGCPHYS    GCPhys;
@@ -965,5 +967,6 @@
  * @returns Strict VBox status code.
  * @param   pIemCpu             The IEM state.
- * @param   cbMin               Where to return the opcode byte.
+ * @param   cbMin               The minimum number of bytes relative offOpcode
+ *                              that must be read.
  */
 static VBOXSTRICTRC iemOpcodeFetchMoreBytes(PIEMCPU pIemCpu, size_t cbMin)
@@ -984,6 +987,4 @@
         if (!IEM_IS_CANONICAL(GCPtrNext))
             return iemRaiseGeneralProtectionFault0(pIemCpu);
-        cbToTryRead = PAGE_SIZE - (GCPtrNext & PAGE_OFFSET_MASK);
-        Assert(cbToTryRead >= cbMin - cbLeft); /* ASSUMPTION based on iemInitDecoderAndPrefetchOpcodes. */
     }
     else
@@ -995,8 +996,36 @@
             return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
         cbToTryRead = pCtx->cs.u32Limit - GCPtrNext32 + 1;
+        if (!cbToTryRead) /* overflowed */
+        {
+            Assert(GCPtrNext32 == 0); Assert(pCtx->cs.u32Limit == UINT32_MAX);
+            cbToTryRead = UINT32_MAX;
+            /** @todo check out wrapping around the code segment.  */
+        }
         if (cbToTryRead < cbMin - cbLeft)
             return iemRaiseSelectorBounds(pIemCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
         GCPtrNext = pCtx->cs.u64Base + GCPtrNext32;
     }
+
+    /* Only read up to the end of the page, and make sure we don't read more
+       than the opcode buffer can hold. */
+    uint32_t cbLeftOnPage = PAGE_SIZE - (GCPtrNext & PAGE_OFFSET_MASK);
+    if (cbToTryRead > cbLeftOnPage)
+        cbToTryRead = cbLeftOnPage;
+    if (cbToTryRead > sizeof(pIemCpu->abOpcode) - pIemCpu->cbOpcode)
+        cbToTryRead = sizeof(pIemCpu->abOpcode) - pIemCpu->cbOpcode;
+    Assert(cbToTryRead >= cbMin - cbLeft); /* ASSUMPTION based on iemInitDecoderAndPrefetchOpcodes. */
+
+#ifdef VBOX_WITH_RAW_MODE_NOT_R0
+    /* Allow interpretation of patch manager code blocks since they can for
+       instance throw #PFs for perfectly good reasons. */
+    if (pIemCpu->fInPatchCode)
+    {
+        size_t cbRead = 0;
+        int rc = PATMReadPatchCode(IEMCPU_TO_VM(pIemCpu), GCPtrNext, pIemCpu->abOpcode, cbToTryRead, &cbRead);
+        AssertRCReturn(rc, rc);
+        pIemCpu->cbOpcode = (uint8_t)cbRead; Assert(pIemCpu->cbOpcode == cbRead); Assert(cbRead > 0);
+        return VINF_SUCCESS;
+    }
+#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
 
     RTGCPHYS    GCPhys;
@@ -1027,10 +1056,4 @@
      * Read the bytes at this address.
      */
-    uint32_t cbLeftOnPage = PAGE_SIZE - (GCPtrNext & PAGE_OFFSET_MASK);
-    if (cbToTryRead > cbLeftOnPage)
-        cbToTryRead = cbLeftOnPage;
-    if (cbToTryRead > sizeof(pIemCpu->abOpcode) - pIemCpu->cbOpcode)
-        cbToTryRead = sizeof(pIemCpu->abOpcode) - pIemCpu->cbOpcode;
-    Assert(cbToTryRead >= cbMin - cbLeft);
     if (!pIemCpu->fBypassHandlers)
         rc = PGMPhysRead(IEMCPU_TO_VM(pIemCpu), GCPhys, &pIemCpu->abOpcode[pIemCpu->cbOpcode], cbToTryRead);
Index: trunk/src/VBox/VMM/VMMAll/PATMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/PATMAll.cpp	(revision 47425)
+++ trunk/src/VBox/VMM/VMMAll/PATMAll.cpp	(revision 47427)
@@ -36,4 +36,5 @@
 #include <VBox/log.h>
 #include <iprt/assert.h>
+#include <iprt/string.h>
 
 
@@ -282,4 +283,44 @@
 {
     return (PATMIsEnabled(pVM) && pAddrGC - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem) ? true : false;
+}
+
+/**
+ * Reads patch code.
+ *
+ * @returns
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_PATCH_NOT_FOUND if the request is entirely outside the patch
+ *          code.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   GCPtrPatchCode  The patch address to start reading at.
+ * @param   pvDst           Where to return the patch code.
+ * @param   cbToRead        Number of bytes to read.
+ * @param   pcbRead         Where to return the actual number of bytes we've
+ *                          read. Optional.
+ */
+VMM_INT_DECL(int) PATMReadPatchCode(PVM pVM, RTGCPTR GCPtrPatchCode, void *pvDst, size_t cbToRead, size_t *pcbRead)
+{
+    /* Shortcut. */
+    if (!PATMIsEnabled(pVM))
+        return VERR_PATCH_NOT_FOUND;
+    Assert(!HMIsEnabled(pVM));
+
+    RTGCPTR offPatchedInstr = GCPtrPatchCode - (RTGCPTR32)pVM->patm.s.pPatchMemGC;
+    if (offPatchedInstr >= pVM->patm.s.cbPatchMem)
+        return VERR_PATCH_NOT_FOUND;
+
+    uint32_t cbMaxRead = pVM->patm.s.cbPatchMem - (uint32_t)offPatchedInstr;
+    if (cbToRead > cbMaxRead)
+        cbToRead = cbMaxRead;
+
+#ifdef IN_RC
+    memcpy(pvDst, pVM->patm.s.pPatchMemGC + (uint32_t)offPatchedInstr, cbToRead);
+#else
+    memcpy(pvDst, pVM->patm.s.pPatchMemHC + (uint32_t)offPatchedInstr, cbToRead);
+#endif
+    if (pcbRead)
+        *pcbRead = cbToRead;
+    return VINF_SUCCESS;
 }
 
