Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 100276)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 100277)
@@ -818,7 +818,8 @@
  *                              calling thread.
  * @param   pvDst               Where to return the bytes.
- * @param   cbDst               Number of bytes to read.
- *
- * @todo    Make cbDst = 0 a way of initializing pbInstrBuf?
+ * @param   cbDst               Number of bytes to read.  A value of zero is
+ *                              allowed for initializing pbInstrBuf (the
+ *                              recompiler does this).  In this case it is best
+ *                              to set pbInstrBuf to NULL prior to the call.
  */
 void iemOpcodeFetchBytesJmp(PVMCPUCC pVCpu, size_t cbDst, void *pvDst) IEM_NOEXCEPT_MAY_LONGJMP
@@ -1060,24 +1061,36 @@
             /* Do the reading. */
             uint32_t const cbToRead = RT_MIN((uint32_t)cbDst, cbMaxRead);
-            VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK),
-                                                pvDst, cbToRead, PGMACCESSORIGIN_IEM);
-            if (RT_LIKELY(rcStrict == VINF_SUCCESS))
-            { /* likely */ }
-            else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
+            if (cbToRead > 0)
             {
-                Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
-                     GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
-                rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
-                AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)));
+                VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK),
+                                                    pvDst, cbToRead, PGMACCESSORIGIN_IEM);
+                if (RT_LIKELY(rcStrict == VINF_SUCCESS))
+                { /* likely */ }
+                else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))
+                {
+                    Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status -  rcStrict=%Rrc\n",
+                         GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
+                    rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);
+                    AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)));
+                }
+                else
+                {
+                    Log((RT_SUCCESS(rcStrict)
+                         ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
+                         : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
+                         GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
+                    IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
+                }
             }
-            else
-            {
-                Log((RT_SUCCESS(rcStrict)
-                     ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n"
-                     : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n",
-                     GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead));
-                IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
-            }
-            pVCpu->iem.s.offInstrNextByte = offBuf + cbToRead;
+
+            /* Update the state and probably return. */
+            uint32_t const offPg = (GCPtrFirst & X86_PAGE_OFFSET_MASK);
+            pVCpu->iem.s.offCurInstrStart = (int16_t)(offPg - cbInstr);
+            pVCpu->iem.s.offInstrNextByte = offPg + cbInstr + cbToRead;
+            pVCpu->iem.s.cbInstrBuf       = offPg + RT_MIN(15, cbMaxRead + cbInstr) - cbToRead - cbInstr;
+            pVCpu->iem.s.cbInstrBufTotal  = X86_PAGE_SIZE;
+            pVCpu->iem.s.GCPhysInstrBuf   = pTlbe->GCPhys;
+            pVCpu->iem.s.uInstrBufPc      = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK;
+            pVCpu->iem.s.pbInstrBuf       = NULL;
             if (cbToRead == cbDst)
                 return;
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedFunctions.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedFunctions.cpp	(revision 100276)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedFunctions.cpp	(revision 100277)
@@ -610,4 +610,21 @@
 }
 
+
+/**
+ * Built-in function that checks the EIP/IP + uParam0 is within CS.LIM,
+ * raising a \#GP(0) if this isn't the case.
+ */
+static IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLim,
+                         (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
+{
+    uint32_t const cbInstr = (uint32_t)uParam0;
+    if (pVCpu->cpum.GstCtx.eip - pVCpu->cpum.GstCtx.cs.u32Limit >= cbInstr)
+        return VINF_SUCCESS;
+    Log(("EIP out of bounds at %04x:%08RX32 LB %u - CS.LIM=%#RX32\n",
+         pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, cbInstr, pVCpu->cpum.GstCtx.cs.u32Limit));
+    RT_NOREF(uParam1, uParam2);
+    return iemRaiseGeneralProtectionFault0(pVCpu);
+}
+
 /*
  * The threaded functions.
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py	(revision 100276)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py	(revision 100277)
@@ -879,5 +879,5 @@
 
         aoStmts = [
-            iai.McCppGeneric('IEM_MC2_PRE_EMIT_CALLS();', cchIndent = cchIndent), # Serves as a hook for various stuff.
+            iai.McCppGeneric('IEM_MC2_BEGIN_EMIT_CALLS();', cchIndent = cchIndent), # Scope and a hook for various stuff.
             iai.McCppGeneric(sCode, cchIndent = cchIndent),
         ];
@@ -889,4 +889,5 @@
                                             cchIndent = cchIndent));
 
+        aoStmts.append(iai.McCppGeneric('IEM_MC2_END_EMIT_CALLS();', cchIndent = cchIndent)); # For closing the scope.
         return aoStmts;
 
@@ -1247,4 +1248,5 @@
             '     */'
             '    kIemThreadedFunc_CheckMode,',
+            '    kIemThreadedFunc_CheckCsLim,',
         ];
         iThreadedFunction = 1;
@@ -1405,4 +1407,5 @@
                    + '     */'
                    + '    iemThreadedFunc_BltIn_CheckMode,\n'
+                   + '    iemThreadedFunc_BltIn_CheckCsLim,\n'
                    );
         iThreadedFunction = 1;
@@ -1437,4 +1440,5 @@
                    + '     */'
                    + '    "BltIn_CheckMode",\n'
+                   + '    "BltIn_CheckCsLim",\n'
                    );
         iThreadedFunction = 1;
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedRecompiler.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedRecompiler.cpp	(revision 100276)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllThreadedRecompiler.cpp	(revision 100277)
@@ -123,12 +123,9 @@
     uint16_t    uUnused0;
 
+    /** Offset into IEMTB::pabOpcodes. */
+    uint16_t    offOpcode;
     /** The opcode length. */
     uint8_t     cbOpcode;
-    /** The opcode chunk number.
-     * @note sketches for discontiguous opcode support  */
-    uint8_t     idxOpcodeChunk;
-    /** The offset into the opcode chunk of this function.
-     * @note sketches for discontiguous opcode support  */
-    uint16_t    offOpcodeChunk;
+    uint8_t     uUnused1;
 
     /** Generic parameters. */
@@ -188,4 +185,16 @@
     /** Pointer to the opcode bytes this block was recompiled from. */
     uint8_t            *pabOpcodes;
+
+#if 0
+    struct
+    {
+        uint16_t        offOpcodes;
+        uint16_t        cbOpcodes;
+    } aRanges;
+
+    /** Physical pages that the .    */
+    RTGCPHYS            aGCPhysPgs[2];
+#endif
+
 } IEMTB;
 
@@ -214,15 +223,30 @@
 #endif
 
-#define IEM_MC2_PRE_EMIT_CALLS() do { \
+#define IEM_MC2_BEGIN_EMIT_CALLS() \
+    { \
+        PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
         AssertMsg(pVCpu->iem.s.offOpcode == IEM_GET_INSTR_LEN(pVCpu), \
                   ("%u vs %u (%04x:%08RX64)\n", pVCpu->iem.s.offOpcode, IEM_GET_INSTR_LEN(pVCpu), \
                   pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip)); \
-    } while (0)
+        /** @todo check for cross page stuff */ \
+        if (!(pTb->fFlags & IEMTB_F_CS_LIM_CHECKS)) \
+        { /* likely */ } \
+        else \
+        { \
+            PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
+            pCall->enmFunction = kIemThreadedFunc_CheckCsLim; \
+            pCall->offOpcode   = pTb->cbOpcodes; \
+            pCall->auParams[0] = pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
+            pCall->auParams[1] = 0; \
+            pCall->auParams[2] = 0; \
+        } \
+        do { } while (0)
+
 #define IEM_MC2_EMIT_CALL_0(a_enmFunction) do { \
         IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
         \
-        PIEMTB              const pTb   = pVCpu->iem.s.pCurTbR3; \
         PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
         pCall->enmFunction = a_enmFunction; \
+        pCall->offOpcode   = pTb->cbOpcodes; \
         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
         pCall->auParams[0] = 0; \
@@ -234,7 +258,7 @@
         uint64_t         const uArg0Check       = (a_uArg0);     RT_NOREF(uArg0Check); \
         \
-        PIEMTB              const pTb   = pVCpu->iem.s.pCurTbR3; \
         PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
         pCall->enmFunction = a_enmFunction; \
+        pCall->offOpcode   = pTb->cbOpcodes; \
         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
         pCall->auParams[0] = a_uArg0; \
@@ -247,7 +271,7 @@
         uint64_t         const uArg1Check       = (a_uArg1);     RT_NOREF(uArg1Check); \
         \
-        PIEMTB              const pTb   = pVCpu->iem.s.pCurTbR3; \
         PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
         pCall->enmFunction = a_enmFunction; \
+        pCall->offOpcode   = pTb->cbOpcodes; \
         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
         pCall->auParams[0] = a_uArg0; \
@@ -261,11 +285,14 @@
         uint64_t         const uArg2Check       = (a_uArg2);     RT_NOREF(uArg2Check); \
         \
-        PIEMTB              const pTb   = pVCpu->iem.s.pCurTbR3; \
         PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
         pCall->enmFunction = a_enmFunction; \
+        pCall->offOpcode   = pTb->cbOpcodes; \
         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
         pCall->auParams[0] = a_uArg0; \
         pCall->auParams[1] = a_uArg1; \
         pCall->auParams[2] = a_uArg2; \
+    } while (0)
+
+#define IEM_MC2_END_EMIT_CALLS() \
     } while (0)
 
@@ -907,18 +934,10 @@
 DECL_FORCE_INLINE(void) iemThreadedCompileInitOpcodeFetching(PVMCPUCC pVCpu)
 {
-// // // // // // // // // // figure this out // // // //
-    pVCpu->iem.s.pbInstrBuf         = NULL;
-    pVCpu->iem.s.offInstrNextByte   = 0;
-    pVCpu->iem.s.offCurInstrStart   = 0;
+    /* Almost everything is done by iemGetPcWithPhysAndCode() already.  We just need to initialize the index into abOpcode. */
 #ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
     pVCpu->iem.s.offOpcode          = 0;
-#endif
-#ifdef VBOX_STRICT
-    pVCpu->iem.s.GCPhysInstrBuf     = NIL_RTGCPHYS;
-    pVCpu->iem.s.cbInstrBuf         = UINT16_MAX;
-    pVCpu->iem.s.cbInstrBufTotal    = UINT16_MAX;
-    pVCpu->iem.s.uInstrBufPc        = UINT64_C(0xc0ffc0ffcff0c0ff);
-#endif
-// // // // // // // // // // // // // // // // // // //
+#else
+    RT_NOREF(pVCpu);
+#endif
 }
 
@@ -994,15 +1013,5 @@
      * Allocate a new translation block.
      */
-    if (!(fExtraFlags & IEMTB_F_RIP_CHECKS))
-    { /* likely */  }
-    else if (  !IEM_IS_64BIT_CODE(pVCpu)
-             ? pVCpu->cpum.GstCtx.eip <= pVCpu->cpum.GstCtx.cs.u32Limit
-             : IEM_IS_CANONICAL(pVCpu->cpum.GstCtx.rip))
-    { /* likely */ }
-    else
-        return IEMExecOne(pVCpu);
-    fExtraFlags |= IEMTB_F_STATE_COMPILING;
-
-    PIEMTB pTb = iemThreadedTbAlloc(pVM, pVCpu, GCPhysPc, fExtraFlags);
+    PIEMTB pTb = iemThreadedTbAlloc(pVM, pVCpu, GCPhysPc, fExtraFlags | IEMTB_F_STATE_COMPILING);
     AssertReturn(pTb, VERR_IEM_TB_ALLOC_FAILED);
 
@@ -1144,34 +1153,16 @@
 /**
  * This is called when the PC doesn't match the current pbInstrBuf.
- */
-static RTGCPHYS iemGetPcWithPhysAndCodeMissed(PVMCPUCC pVCpu, uint64_t const uPc)
-{
-    /** @todo see iemOpcodeFetchBytesJmp */
-    pVCpu->iem.s.pbInstrBuf = NULL;
-
+ *
+ * Upon return, we're ready for opcode fetching.  But please note that
+ * pbInstrBuf can be NULL iff the memory doesn't have readable backing (i.e.
+ * MMIO or unassigned).
+ */
+static RTGCPHYS iemGetPcWithPhysAndCodeMissed(PVMCPUCC pVCpu)
+{
+    pVCpu->iem.s.pbInstrBuf       = NULL;
+    pVCpu->iem.s.offCurInstrStart = 0;
     pVCpu->iem.s.offInstrNextByte = 0;
-    pVCpu->iem.s.offCurInstrStart = 0;
-    pVCpu->iem.s.cbInstrBuf       = 0;
-    pVCpu->iem.s.cbInstrBufTotal  = 0;
-
-    uint8_t bIgn;
-    iemOpcodeFetchBytesJmp(pVCpu, 1, &bIgn);
-
-    uint64_t off = uPc - pVCpu->iem.s.uInstrBufPc;
-    if (off < pVCpu->iem.s.cbInstrBufTotal)
-    {
-        pVCpu->iem.s.offInstrNextByte = (uint32_t)off;
-        pVCpu->iem.s.offCurInstrStart = (uint16_t)off;
-        if ((uint16_t)off + 15 <= pVCpu->iem.s.cbInstrBufTotal)
-            pVCpu->iem.s.cbInstrBuf = (uint16_t)off + 15;
-        else
-            pVCpu->iem.s.cbInstrBuf = pVCpu->iem.s.cbInstrBufTotal;
-
-        return pVCpu->iem.s.GCPhysInstrBuf + off;
-    }
-
-    AssertFailed();
-    RT_NOREF(uPc);
-    return NIL_RTGCPHYS;
+    iemOpcodeFetchBytesJmp(pVCpu, 0, NULL);
+    return pVCpu->iem.s.GCPhysInstrBuf + pVCpu->iem.s.offCurInstrStart;
 }
 
@@ -1180,5 +1171,7 @@
 DECL_FORCE_INLINE_THROW(RTGCPHYS) iemGetPcWithPhysAndCode(PVMCPUCC pVCpu)
 {
-    /* Set uCurTbStartPc to RIP and calc the effective PC. */
+    /*
+     * Set uCurTbStartPc to RIP and calc the effective PC.
+     */
     uint64_t uPc = pVCpu->cpum.GstCtx.rip;
     pVCpu->iem.s.uCurTbStartPc = uPc;
@@ -1186,4 +1179,7 @@
     uPc += pVCpu->cpum.GstCtx.cs.u64Base;
 
+    /*
+     * Advance within the current buffer (PAGE) when possible.
+     */
     if (pVCpu->iem.s.pbInstrBuf)
     {
@@ -1201,5 +1197,5 @@
         }
     }
-    return iemGetPcWithPhysAndCodeMissed(pVCpu, uPc);
+    return iemGetPcWithPhysAndCodeMissed(pVCpu);
 }
 
@@ -1219,16 +1215,11 @@
      */
     if (IEM_IS_64BIT_CODE(pVCpu))
-    {
-        if (RT_LIKELY(   IEM_IS_CANONICAL(pVCpu->cpum.GstCtx.rip)
-                      && IEM_IS_CANONICAL(pVCpu->cpum.GstCtx.rip + 256)))
-            return IEMTB_F_TYPE_THREADED;
-    }
-    else
-    {
-        if (RT_LIKELY(   pVCpu->cpum.GstCtx.eip < pVCpu->cpum.GstCtx.cs.u32Limit
-                      && (uint64_t)256 + pVCpu->cpum.GstCtx.eip < pVCpu->cpum.GstCtx.cs.u32Limit))
-            return IEMTB_F_TYPE_THREADED;
-    }
-    return IEMTB_F_RIP_CHECKS | IEMTB_F_TYPE_THREADED;
+        return IEMTB_F_TYPE_THREADED;
+
+    if (RT_LIKELY(   pVCpu->cpum.GstCtx.eip < pVCpu->cpum.GstCtx.cs.u32Limit
+                  && pVCpu->cpum.GstCtx.eip - pVCpu->cpum.GstCtx.cs.u32Limit >= X86_PAGE_SIZE))
+        return IEMTB_F_TYPE_THREADED;
+
+    return IEMTB_F_TYPE_THREADED | IEMTB_F_CS_LIM_CHECKS;
 }
 
@@ -1265,7 +1256,5 @@
         PIEMTB       pTb = NULL;
         VBOXSTRICTRC rcStrict;
-#ifdef IEM_WITH_SETJMP
         IEM_TRY_SETJMP(pVCpu, rcStrict)
-#endif
         {
             for (;;)
@@ -1300,5 +1289,4 @@
             }
         }
-#ifdef IEM_WITH_SETJMP
         IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
         {
@@ -1306,11 +1294,22 @@
             if (pVCpu->iem.s.cActiveMappings > 0)
                 iemMemRollback(pVCpu);
-            if (pTb)
-                return rcStrict;
-            return iemThreadedCompileLongJumped(pVM, pVCpu, rcStrict);
+
+            /* If pTb isn't NULL we're in iemThreadedTbExec. */
+            if (!pTb)
+            {
+                /* If pCurTbR3 is NULL, we're in iemGetPcWithPhysAndCode.*/
+                pTb = pVCpu->iem.s.pCurTbR3;
+                if (pTb)
+                {
+                    /* If the pCurTbR3 block is in compiling state, we're in iemThreadedCompile,
+                       otherwise it's iemThreadedTbExec inside iemThreadedCompile (compile option). */
+                    if ((pTb->fFlags & IEMTB_F_STATE_MASK) == IEMTB_F_STATE_COMPILING)
+                        return iemThreadedCompileLongJumped(pVM, pVCpu, rcStrict);
+                }
+            }
+            return rcStrict;
         }
         IEM_CATCH_LONGJMP_END(pVCpu);
-#endif
-    }
-}
-
+    }
+}
+
Index: /trunk/src/VBox/VMM/include/IEMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 100276)
+++ /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 100277)
@@ -670,8 +670,8 @@
 #define IEMTB_F_STATE_OBSOLETE          UINT32_C(0x0c000000)
 
-/** Checks that EIP/IP is wihin CS.LIM and that RIP is canonical before each
- *  instruction.  Used when we're close the limit before starting a TB, as
- *  determined by iemGetTbFlagsForCurrentPc(). */
-#define IEMTB_F_RIP_CHECKS              UINT32_C(0x0c000000)
+/** Checks that EIP/IP is wihin CS.LIM before each instruction.  Used when
+ * we're close the limit before starting a TB, as determined by
+ * iemGetTbFlagsForCurrentPc(). */
+#define IEMTB_F_CS_LIM_CHECKS           UINT32_C(0x0c000000)
 
 /** Mask of the IEMTB_F_XXX flags that are part of the TB lookup key.
