VirtualBox

Changeset 100694 in vbox


Ignore:
Timestamp:
Jul 25, 2023 10:34:22 AM (20 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
158538
Message:

IEM/VMM: Deal with opcode checking cross page boundraries and tentativiely for branches. bugref:10369

Location:
trunk
Files:
7 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/err.h

    r100566 r100694  
    25032503/** Recompiled execution: Stop execution TB - Mode (fExec) changed. */
    25042504#define VINF_IEM_REEXEC_MODE_CHANGED                (5310)
     2505/** Recompilation: End translation block. */
     2506#define VINF_IEM_RECOMPILE_END_TB                   (5311)
     2507
    25052508/** Restart the current instruction. For testing only. */
    25062509#define VERR_IEM_RESTART_INSTRUCTION                (-5389)
  • trunk/src/VBox/VMM/Makefile.kmk

    r100672 r100694  
    249249 VBoxVMM_SOURCES += \
    250250        VMMAll/IEMAllThreadedRecompiler.cpp \
    251         VMMAll/IEMAllThreadedFunctions.cpp
     251        VMMAll/IEMAllThreadedFunctions.cpp \
     252        VMMAll/IEMAllThreadedFunctionsBltIn.cpp
    252253endif
    253254
  • trunk/src/VBox/VMM/VMMAll/IEMAll.cpp

    r100672 r100694  
    997997                {
    998998                    Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n",
    999                          pVCpu->cpum.GstCtx.cs, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
     999                         pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
    10001000                    iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    10011001                }
     
    10071007                pVCpu->iem.s.GCPhysInstrBuf   = pTlbe->GCPhys;
    10081008                pVCpu->iem.s.pbInstrBuf       = pTlbe->pbMappingR3;
     1009                pVCpu->iem.s.fTbCrossedPage  |= offPg == 0;
    10091010                memcpy(pvDst, &pTlbe->pbMappingR3[offPg], cbDst);
    10101011                return;
     
    10601061            {
    10611062                Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0) [slow]\n",
    1062                      pVCpu->cpum.GstCtx.cs, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
     1063                     pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst));
    10631064                iemRaiseGeneralProtectionFault0Jmp(pVCpu);
    10641065            }
     
    10981099            pVCpu->iem.s.uInstrBufPc      = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK;
    10991100            pVCpu->iem.s.pbInstrBuf       = NULL;
     1101            pVCpu->iem.s.fTbCrossedPage  |= offPg == 0;
    11001102            if (cbToRead == cbDst)
    11011103                return;
     
    11851187    {
    11861188        Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n",
    1187              pVCpu->cpum.GstCtx.cs, pVCpu->cpum.GstCtx.rip, offOpcode, cbMin));
     1189             pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, offOpcode, cbMin));
    11881190        return iemRaiseGeneralProtectionFault0(pVCpu);
    11891191    }
  • trunk/src/VBox/VMM/VMMAll/IEMAllThreadedFunctions.cpp

    r100326 r100694  
    610610
    611611
    612 
    613 /**
    614  * Built-in function that compares the fExec mask against uParam0.
    615  */
    616 static IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckMode,
    617                          (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
    618 {
    619     uint32_t const fExpectedExec = (uint32_t)uParam0;
    620     if (pVCpu->iem.s.fExec == fExpectedExec)
    621         return VINF_SUCCESS;
    622     Log12(("Mode changed at %04x:%08RX64: %#x -> %#x (xor: %#x)\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
    623            fExpectedExec, pVCpu->iem.s.fExec, fExpectedExec ^ pVCpu->iem.s.fExec));
    624     RT_NOREF(uParam1, uParam2);
    625     return VINF_IEM_REEXEC_MODE_CHANGED;
    626 }
    627 
    628 
    629 /**
    630  * Built-in function that checks the EIP/IP + uParam0 is within CS.LIM,
    631  * raising a \#GP(0) if this isn't the case.
    632  */
    633 static IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLim,
    634                          (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
    635 {
    636     uint32_t const cbInstr = (uint32_t)uParam0;
    637     if (pVCpu->cpum.GstCtx.eip - pVCpu->cpum.GstCtx.cs.u32Limit >= cbInstr)
    638         return VINF_SUCCESS;
    639     Log(("EIP out of bounds at %04x:%08RX32 LB %u - CS.LIM=%#RX32\n",
    640          pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, cbInstr, pVCpu->cpum.GstCtx.cs.u32Limit));
    641     RT_NOREF(uParam1, uParam2);
    642     return iemRaiseGeneralProtectionFault0(pVCpu);
    643 }
    644 
    645612/*
    646613 * The threaded functions.
  • trunk/src/VBox/VMM/VMMAll/IEMAllThreadedFunctionsBltIn.cpp

    r100670 r100694  
    11/* $Id$ */
    22/** @file
    3  * IEM - Instruction Decoding and Emulation, Threaded Functions.
     3 * IEM - Instruction Decoding and Emulation, Built-in Threaded Functions.
     4 *
     5 * This is separate from IEMThreadedFunctions.cpp because it doesn't work
     6 * with IEM_WITH_OPAQUE_DECODER_STATE defined.
    47 */
    58
     
    3033*   Header Files                                                                                                                 *
    3134*********************************************************************************************************************************/
    32 #ifndef LOG_GROUP /* defined when included by tstIEMCheckMc.cpp */
    33 # define LOG_GROUP LOG_GROUP_IEM
    34 #endif
     35#define LOG_GROUP LOG_GROUP_IEM_RE_THREADED
    3536#define VMCPU_INCL_CPUM_GST_CTX
    36 #define IEM_WITH_OPAQUE_DECODER_STATE
    3737#include <VBox/vmm/iem.h>
    3838#include <VBox/vmm/cpum.h>
     
    6868
    6969#include "IEMInline.h"
    70 #include "IEMMc.h"
    71 
    72 #include "IEMThreadedFunctions.h"
    73 
    74 
    75 /*********************************************************************************************************************************
    76 *   Defined Constants And Macros                                                                                                 *
    77 *********************************************************************************************************************************/
    78 
    79 /** Variant of IEM_MC_ADVANCE_RIP_AND_FINISH with instruction length as param
    80  *  and only used when we're in 16-bit code on a pre-386 CPU. */
    81 #define IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC16(a_cbInstr) \
    82     return iemRegAddToIp16AndFinishingClearingRF(pVCpu, a_cbInstr)
    83 
    84 /** Variant of IEM_MC_ADVANCE_RIP_AND_FINISH with instruction length as param
    85  *  and used for 16-bit and 32-bit code on 386 and later CPUs. */
    86 #define IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32(a_cbInstr) \
    87     return iemRegAddToEip32AndFinishingClearingRF(pVCpu, a_cbInstr)
    88 
    89 /** Variant of IEM_MC_ADVANCE_RIP_AND_FINISH with instruction length as param
    90  *  and only used when we're in 64-bit code. */
    91 #define IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC64(a_cbInstr) \
    92     return iemRegAddToRip64AndFinishingClearingRF(pVCpu, a_cbInstr)
    93 
    94 #undef  IEM_MC_ADVANCE_RIP_AND_FINISH
    95 
    96 
    97 /** Variant of IEM_MC_REL_JMP_S8_AND_FINISH with instruction length as extra
    98  *  parameter, for use in 16-bit code on a pre-386 CPU. */
    99 #define IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC16(a_i8, a_cbInstr) \
    100     return iemRegIp16RelativeJumpS8AndFinishClearingRF(pVCpu, a_cbInstr, (a_i8))
    101 
    102 /** Variant of IEM_MC_REL_JMP_S8_AND_FINISH with instruction length and operand
    103  * size as extra parameters, for use in 16-bit and 32-bit code on 386 and
    104  * later CPUs. */
    105 #define IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC32(a_i8, a_cbInstr, a_enmEffOpSize) \
    106     return iemRegEip32RelativeJumpS8AndFinishClearingRF(pVCpu, a_cbInstr, (a_i8), a_enmEffOpSize)
    107 
    108 /** Variant of IEM_MC_REL_JMP_S8_AND_FINISH with instruction length and operand
    109  * size as extra parameters, for use in 64-bit code. */
    110 #define IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC64(a_i8, a_cbInstr, a_enmEffOpSize) \
    111     return iemRegRip64RelativeJumpS8AndFinishClearingRF(pVCpu, a_cbInstr, (a_i8), a_enmEffOpSize)
    112 
    113 #undef  IEM_MC_REL_JMP_S8_AND_FINISH
    114 
    115 
    116 /** Variant of IEM_MC_REL_JMP_S16_AND_FINISH with instruction length as
    117  *  param, for use in 16-bit code on a pre-386 CPU. */
    118 #define IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC16(a_i16, a_cbInstr) \
    119     return iemRegEip32RelativeJumpS16AndFinishClearingRF(pVCpu, a_cbInstr, (a_i16))
    120 
    121 /** Variant of IEM_MC_REL_JMP_S16_AND_FINISH with instruction length as
    122  *  param, for use in 16-bit and 32-bit code on 386 and later CPUs. */
    123 #define IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC32(a_i16, a_cbInstr) \
    124     return iemRegEip32RelativeJumpS16AndFinishClearingRF(pVCpu, a_cbInstr, (a_i16))
    125 
    126 /** Variant of IEM_MC_REL_JMP_S16_AND_FINISH with instruction length as
    127  *  param, for use in 64-bit code. */
    128 #define IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC64(a_i16, a_cbInstr) \
    129     return iemRegRip64RelativeJumpS16AndFinishClearingRF(pVCpu, a_cbInstr, (a_i16))
    130 
    131 #undef  IEM_MC_REL_JMP_S16_AND_FINISH
    132 
    133 
    134 /** Variant of IEM_MC_REL_JMP_S32_AND_FINISH with instruction length as
    135  *  an extra parameter - dummy for pre-386 variations not eliminated by the
    136  *  python script. */
    137 #define IEM_MC_REL_JMP_S32_AND_FINISH_THREADED_PC16(a_i32, a_cbInstr) \
    138     do { RT_NOREF(pVCpu, a_i32, a_cbInstr); AssertFailedReturn(VERR_IEM_IPE_9); } while (0)
    139 
    140 /** Variant of IEM_MC_REL_JMP_S32_AND_FINISH with instruction length as
    141  *  an extra parameter, for use in 16-bit and 32-bit code on 386+. */
    142 #define IEM_MC_REL_JMP_S32_AND_FINISH_THREADED_PC32(a_i32, a_cbInstr) \
    143     return iemRegEip32RelativeJumpS32AndFinishClearingRF(pVCpu, a_cbInstr, (a_i32))
    144 
    145 /** Variant of IEM_MC_REL_JMP_S32_AND_FINISH with instruction length as
    146  *  an extra parameter, for use in 64-bit code. */
    147 #define IEM_MC_REL_JMP_S32_AND_FINISH_THREADED_PC64(a_i32, a_cbInstr) \
    148     return iemRegRip64RelativeJumpS32AndFinishClearingRF(pVCpu, a_cbInstr, (a_i32))
    149 
    150 #undef  IEM_MC_REL_JMP_S32_AND_FINISH
    151 
    152 
    153 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters, 16-bit. */
    154 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_16(a_GCPtrEff, a_bRm, a_u16Disp) \
    155     (a_GCPtrEff) = iemOpHlpCalcRmEffAddrThreadedAddr16(pVCpu, a_bRm, a_u16Disp)
    156 
    157 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters, pre-386 16-bit. */
    158 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_16_PRE386(a_GCPtrEff, a_bRm, a_u16Disp) \
    159     IEM_MC_CALC_RM_EFF_ADDR_THREADED_16(a_GCPtrEff, a_bRm, a_u16Disp)
    160 
    161 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters, 32-bit with address prefix. */
    162 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_32_ADDR16(a_GCPtrEff, a_bRm, a_u16Disp) \
    163     IEM_MC_CALC_RM_EFF_ADDR_THREADED_16(a_GCPtrEff, a_bRm, a_u16Disp)
    164 
    165 
    166 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters, 32-bit. */
    167 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_32(a_GCPtrEff, a_bRm, a_uSibAndRspOffset, a_u32Disp) \
    168     (a_GCPtrEff) = iemOpHlpCalcRmEffAddrThreadedAddr32(pVCpu, a_bRm, a_uSibAndRspOffset, a_u32Disp)
    169 
    170 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters, 32-bit flat. */
    171 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_32_FLAT(a_GCPtrEff, a_bRm, a_uSibAndRspOffset, a_u32Disp) \
    172     (a_GCPtrEff) = iemOpHlpCalcRmEffAddrThreadedAddr32(pVCpu, a_bRm, a_uSibAndRspOffset, a_u32Disp)
    173 
    174 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters, 16-bit with address prefix. */
    175 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_16_ADDR32(a_GCPtrEff, a_bRm, a_uSibAndRspOffset, a_u32Disp) \
    176     (a_GCPtrEff) = iemOpHlpCalcRmEffAddrThreadedAddr32(pVCpu, a_bRm, a_uSibAndRspOffset, a_u32Disp)
    177 
    178 
    179 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters. */
    180 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_64(a_GCPtrEff, a_bRmEx, a_uSibAndRspOffset, a_u32Disp, a_cbImm) \
    181     (a_GCPtrEff) = iemOpHlpCalcRmEffAddrThreadedAddr64(pVCpu, a_bRmEx, a_uSibAndRspOffset, a_u32Disp, a_cbImm)
    182 
    183 /** Variant of IEM_MC_CALC_RM_EFF_ADDR with additional parameters.
    184  * @todo How did that address prefix thing work for 64-bit code again? */
    185 #define IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_ADDR32(a_GCPtrEff, a_bRmEx, a_uSibAndRspOffset, a_u32Disp, a_cbImm) \
    186     (a_GCPtrEff) = (uint32_t)iemOpHlpCalcRmEffAddrThreadedAddr64(pVCpu, a_bRmEx, a_uSibAndRspOffset, a_u32Disp, a_cbImm)
    187 
    188 #undef  IEM_MC_CALC_RM_EFF_ADDR
    189 
    190 
    191 /** Variant of IEM_MC_CALL_CIMPL_1 with explicit instruction length parameter. */
    192 #define IEM_MC_CALL_CIMPL_1_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0) \
    193     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0)
    194 #undef  IEM_MC_CALL_CIMPL_1
    195 
    196 /** Variant of IEM_MC_CALL_CIMPL_2 with explicit instruction length parameter. */
    197 #define IEM_MC_CALL_CIMPL_2_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1) \
    198     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1)
    199 #undef  IEM_MC_CALL_CIMPL_2
    200 
    201 /** Variant of IEM_MC_CALL_CIMPL_3 with explicit instruction length parameter. */
    202 #define IEM_MC_CALL_CIMPL_3_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1, a2) \
    203     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1, a2)
    204 #undef  IEM_MC_CALL_CIMPL_3
    205 
    206 /** Variant of IEM_MC_CALL_CIMPL_4 with explicit instruction length parameter. */
    207 #define IEM_MC_CALL_CIMPL_4_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1, a2, a3) \
    208     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1, a2, a3)
    209 #undef  IEM_MC_CALL_CIMPL_4
    210 
    211 /** Variant of IEM_MC_CALL_CIMPL_5 with explicit instruction length parameter. */
    212 #define IEM_MC_CALL_CIMPL_5_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1, a2, a3, a4) \
    213     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1, a2, a3, a4)
    214 #undef  IEM_MC_CALL_CIMPL_5
    215 
    216 
    217 /** Variant of IEM_MC_DEFER_TO_CIMPL_0_RET with explicit instruction
    218  * length parameter. */
    219 #define IEM_MC_DEFER_TO_CIMPL_0_RET_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl) \
    220     return (a_pfnCImpl)(pVCpu, (a_cbInstr))
    221 #undef  IEM_MC_DEFER_TO_CIMPL_0_RET
    222 
    223 /** Variant of IEM_MC_DEFER_TO_CIMPL_1_RET with explicit instruction
    224  * length parameter. */
    225 #define IEM_MC_DEFER_TO_CIMPL_1_RET_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0) \
    226     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0)
    227 #undef  IEM_MC_DEFER_TO_CIMPL_1_RET
    228 
    229 /** Variant of IEM_MC_CALL_CIMPL_2 with explicit instruction length parameter. */
    230 #define IEM_MC_DEFER_TO_CIMPL_2_RET_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1) \
    231     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1)
    232 #undef  IEM_MC_DEFER_TO_CIMPL_2_RET
    233 
    234 /** Variant of IEM_MC_DEFER_TO_CIMPL_3 with explicit instruction length
    235  *  parameter. */
    236 #define IEM_MC_DEFER_TO_CIMPL_3_RET_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1, a2) \
    237     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1, a2)
    238 #undef  IEM_MC_DEFER_TO_CIMPL_3_RET
    239 
    240 /** Variant of IEM_MC_DEFER_TO_CIMPL_4 with explicit instruction length
    241  *  parameter. */
    242 #define IEM_MC_DEFER_TO_CIMPL_4_RET_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1, a2, a3) \
    243     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1, a2, a3)
    244 #undef  IEM_MC_DEFER_TO_CIMPL_4_RET
    245 
    246 /** Variant of IEM_MC_DEFER_TO_CIMPL_5 with explicit instruction length
    247  *  parameter. */
    248 #define IEM_MC_DEFER_TO_CIMPL_5_RET_THREADED(a_cbInstr, a_fFlags, a_pfnCImpl, a0, a1, a2, a3, a4) \
    249     return (a_pfnCImpl)(pVCpu, (a_cbInstr), a0, a1, a2, a3, a4)
    250 #undef  IEM_MC_DEFER_TO_CIMPL_5_RET
    251 
    252 
    253 /** Variant of IEM_MC_FETCH_GREG_U8 with extended (20) register index. */
    254 #define IEM_MC_FETCH_GREG_U8_THREADED(a_u8Dst, a_iGRegEx) \
    255     (a_u8Dst) = iemGRegFetchU8Ex(pVCpu, (a_iGRegEx))
    256 
    257 /** Variant of IEM_MC_FETCH_GREG_U8_ZX_U16 with extended (20) register index. */
    258 #define IEM_MC_FETCH_GREG_U8_ZX_U16_THREADED(a_u16Dst, a_iGRegEx) \
    259     (a_u16Dst) = iemGRegFetchU8Ex(pVCpu, (a_iGRegEx))
    260 
    261 /** Variant of IEM_MC_FETCH_GREG_U8_ZX_U32 with extended (20) register index. */
    262 #define IEM_MC_FETCH_GREG_U8_ZX_U32_THREADED(a_u32Dst, a_iGRegEx) \
    263     (a_u32Dst) = iemGRegFetchU8Ex(pVCpu, (a_iGRegEx))
    264 
    265 /** Variant of IEM_MC_FETCH_GREG_U8_ZX_U64 with extended (20) register index. */
    266 #define IEM_MC_FETCH_GREG_U8_ZX_U64_THREADED(a_u64Dst, a_iGRegEx) \
    267     (a_u64Dst) = iemGRegFetchU8Ex(pVCpu, (a_iGRegEx))
    268 
    269 /** Variant of IEM_MC_FETCH_GREG_U8_SX_U16 with extended (20) register index. */
    270 #define IEM_MC_FETCH_GREG_U8_SX_U16_THREADED(a_u16Dst, a_iGRegEx) \
    271     (a_u16Dst) = (int8_t)iemGRegFetchU8Ex(pVCpu, (a_iGRegEx))
    272 
    273 /** Variant of IEM_MC_FETCH_GREG_U8_SX_U32 with extended (20) register index. */
    274 #define IEM_MC_FETCH_GREG_U8_SX_U32_THREADED(a_u32Dst, a_iGRegEx) \
    275     (a_u32Dst) = (int8_t)iemGRegFetchU8Ex(pVCpu, (a_iGRegEx))
    276 #undef IEM_MC_FETCH_GREG_U8_SX_U32
    277 
    278 /** Variant of IEM_MC_FETCH_GREG_U8_SX_U64 with extended (20) register index. */
    279 #define IEM_MC_FETCH_GREG_U8_SX_U64_THREADED(a_u64Dst, a_iGRegEx) \
    280     (a_u64Dst) = (int8_t)iemGRegFetchU8Ex(pVCpu, (a_iGRegEx))
    281 #undef IEM_MC_FETCH_GREG_U8_SX_U64
    282 
    283 /** Variant of IEM_MC_STORE_GREG_U8 with extended (20) register index. */
    284 #define IEM_MC_STORE_GREG_U8_THREADED(a_iGRegEx, a_u8Value) \
    285     *iemGRegRefU8Ex(pVCpu, (a_iGRegEx)) = (a_u8Value)
    286 #undef IEM_MC_STORE_GREG_U8
    287 
    288 /** Variant of IEM_MC_STORE_GREG_U8 with extended (20) register index. */
    289 #define IEM_MC_STORE_GREG_U8_CONST_THREADED(a_iGRegEx, a_u8Value) \
    290     *iemGRegRefU8Ex(pVCpu, (a_iGRegEx)) = (a_u8Value)
    291 #undef IEM_MC_STORE_GREG_U8
    292 
    293 /** Variant of IEM_MC_REF_GREG_U8 with extended (20) register index. */
    294 #define IEM_MC_REF_GREG_U8_THREADED(a_pu8Dst, a_iGRegEx) \
    295     (a_pu8Dst) = iemGRegRefU8Ex(pVCpu, (a_iGRegEx))
    296 #undef IEM_MC_REF_GREG_U8
    297 
    298 /** Variant of IEM_MC_ADD_GREG_U8 with extended (20) register index. */
    299 #define IEM_MC_ADD_GREG_U8_THREADED(a_iGRegEx, a_u8Value) \
    300     *iemGRegRefU8Ex(pVCpu, (a_iGRegEx)) += (a_u8Value)
    301 #undef IEM_MC_ADD_GREG_U8
    302 
    303 /** Variant of IEM_MC_SUB_GREG_U8 with extended (20) register index. */
    304 #define IEM_MC_SUB_GREG_U8_THREADED(a_iGRegEx,  a_u8Value) \
    305     *iemGRegRefU8Ex(pVCpu, (a_iGRegEx)) -= (a_u8Value)
    306 #undef IEM_MC_SUB_GREG_U8
    307 
    308 /** Variant of IEM_MC_ADD_GREG_U8_TO_LOCAL with extended (20) register index. */
    309 #define IEM_MC_ADD_GREG_U8_TO_LOCAL_THREADED(a_u8Value, a_iGRegEx) \
    310     do { (a_u8Value) += iemGRegFetchU8Ex(pVCpu, (a_iGRegEx)); } while (0)
    311 #undef IEM_MC_ADD_GREG_U8_TO_LOCAL
    312 
    313 /** Variant of IEM_MC_AND_GREG_U8 with extended (20) register index. */
    314 #define IEM_MC_AND_GREG_U8_THREADED(a_iGRegEx, a_u8Value) \
    315     *iemGRegRefU8Ex(pVCpu, (a_iGRegEx)) &= (a_u8Value)
    316 #undef IEM_MC_AND_GREG_U8
    317 
    318 /** Variant of IEM_MC_OR_GREG_U8 with extended (20) register index. */
    319 #define IEM_MC_OR_GREG_U8_THREADED(a_iGRegEx, a_u8Value) \
    320     *iemGRegRefU8Ex(pVCpu, (a_iGRegEx)) |= (a_u8Value)
    321 #undef IEM_MC_OR_GREG_U8
    322 
    323 /**
    324  * Calculates the effective address of a ModR/M memory operand, 16-bit
    325  * addressing variant.
    326  *
    327  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR_THREADED_ADDR16.
    328  *
    329  * @returns The effective address.
    330  * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
    331  * @param   bRm                 The ModRM byte.
    332  * @param   u16Disp             The displacement byte/word, if any.
    333  *                              RIP relative addressing.
    334  */
    335 static RTGCPTR iemOpHlpCalcRmEffAddrThreadedAddr16(PVMCPUCC pVCpu, uint8_t bRm, uint16_t u16Disp) RT_NOEXCEPT
    336 {
    337     Log5(("iemOpHlpCalcRmEffAddrThreadedAddr16: bRm=%#x u16Disp=%#x\n", bRm, u16Disp));
    338     Assert(!IEM_IS_64BIT_CODE(pVCpu));
    339 
    340     /* Handle the disp16 form with no registers first. */
    341     if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
    342     {
    343         Log5(("iemOpHlpCalcRmEffAddrThreadedAddr16: EffAddr=%#010RGv\n", (RTGCPTR)u16Disp));
    344         return u16Disp;
    345     }
    346 
    347     /* Get the displacment. */
    348     /** @todo we can eliminate this step by making u16Disp have this value
    349      *        already! */
    350     uint16_t u16EffAddr;
    351     switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    352     {
    353         case 0:  u16EffAddr = 0;                        break;
    354         case 1:  u16EffAddr = (int16_t)(int8_t)u16Disp; break;
    355         case 2:  u16EffAddr = u16Disp;                  break;
    356         default: AssertFailedStmt(u16EffAddr = 0);
    357     }
    358 
    359     /* Add the base and index registers to the disp. */
    360     switch (bRm & X86_MODRM_RM_MASK)
    361     {
    362         case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
    363         case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
    364         case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; break;
    365         case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; break;
    366         case 4: u16EffAddr += pVCpu->cpum.GstCtx.si; break;
    367         case 5: u16EffAddr += pVCpu->cpum.GstCtx.di; break;
    368         case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp; break;
    369         case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx; break;
    370     }
    371 
    372     Log5(("iemOpHlpCalcRmEffAddrThreadedAddr16: EffAddr=%#010RGv\n", (RTGCPTR)u16EffAddr));
    373     return u16EffAddr;
    374 }
    375 
    376 
    377 /**
    378  * Calculates the effective address of a ModR/M memory operand, 32-bit
    379  * addressing variant.
    380  *
    381  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR_THREADED_ADDR32 and
    382  * IEM_MC_CALC_RM_EFF_ADDR_THREADED_ADDR32FLAT.
    383  *
    384  * @returns The effective address.
    385  * @param   pVCpu               The cross context virtual CPU structure of the
    386  *                              calling thread.
    387  * @param   bRm                 The ModRM byte.
    388  * @param   uSibAndRspOffset    Two parts:
    389  *                                - The first 8 bits make up the SIB byte.
    390  *                                - The next 8 bits are the fixed RSP/ESP offse
    391  *                                  in case of a pop [xSP].
    392  * @param   u32Disp             The displacement byte/dword, if any.
    393  */
    394 static RTGCPTR iemOpHlpCalcRmEffAddrThreadedAddr32(PVMCPUCC pVCpu, uint8_t bRm, uint32_t uSibAndRspOffset,
    395                                                    uint32_t u32Disp) RT_NOEXCEPT
    396 {
    397     Log5(("iemOpHlpCalcRmEffAddrThreadedAddr32: bRm=%#x uSibAndRspOffset=%#x u32Disp=%#x\n", bRm, uSibAndRspOffset, u32Disp));
    398 
    399     /* Handle the disp32 form with no registers first. */
    400     if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    401     {
    402         Log5(("iemOpHlpCalcRmEffAddrThreadedAddr32: EffAddr=%#010RGv\n", (RTGCPTR)u32Disp));
    403         return u32Disp;
    404     }
    405 
    406     /* Get the register (or SIB) value. */
    407     uint32_t u32EffAddr;
    408 #ifdef _MSC_VER
    409     u32EffAddr = 0;/* MSC uninitialized variable analysis is too simple, it seems. */
    410 #endif
    411     switch (bRm & X86_MODRM_RM_MASK)
    412     {
    413         case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    414         case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    415         case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    416         case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    417         case 4: /* SIB */
    418         {
    419             /* Get the index and scale it. */
    420             switch ((uSibAndRspOffset >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    421             {
    422                 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
    423                 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
    424                 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
    425                 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
    426                 case 4: u32EffAddr = 0; /*none */ break;
    427                 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    428                 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    429                 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    430             }
    431             u32EffAddr <<= (uSibAndRspOffset >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    432 
    433             /* add base */
    434             switch (uSibAndRspOffset & X86_SIB_BASE_MASK)
    435             {
    436                 case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
    437                 case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
    438                 case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
    439                 case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
    440                 case 4:
    441                     u32EffAddr += pVCpu->cpum.GstCtx.esp;
    442                     u32EffAddr += uSibAndRspOffset >> 8;
    443                     break;
    444                 case 5:
    445                     if ((bRm & X86_MODRM_MOD_MASK) != 0)
    446                         u32EffAddr += pVCpu->cpum.GstCtx.ebp;
    447                     else
    448                         u32EffAddr += u32Disp;
    449                     break;
    450                 case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
    451                 case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
    452             }
    453             break;
    454         }
    455         case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
    456         case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
    457         case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
    458     }
    459 
    460     /* Get and add the displacement. */
    461     switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    462     {
    463         case 0: break;
    464         case 1: u32EffAddr += (int8_t)u32Disp; break;
    465         case 2: u32EffAddr += u32Disp; break;
    466         default: AssertFailed();
    467     }
    468 
    469     Log5(("iemOpHlpCalcRmEffAddrThreadedAddr32: EffAddr=%#010RGv\n", (RTGCPTR)u32EffAddr));
    470     return u32EffAddr;
    471 }
    472 
    473 
    474 /**
    475  * Calculates the effective address of a ModR/M memory operand.
    476  *
    477  * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR_THREADED_ADDR64.
    478  *
    479  * @returns The effective address.
    480  * @param   pVCpu               The cross context virtual CPU structure of the
    481  *                              calling thread.
    482  * @param   bRmEx               The ModRM byte but with bit 3 set to REX.B and
    483  *                              bit 4 to REX.X.  The two bits are part of the
    484  *                              REG sub-field, which isn't needed in this
    485  *                              function.
    486  * @param   uSibAndRspOffset    Two parts:
    487  *                                - The first 8 bits make up the SIB byte.
    488  *                                - The next 8 bits are the fixed RSP/ESP offse
    489  *                                  in case of a pop [xSP].
    490  * @param   u32Disp             The displacement byte/word/dword, if any.
    491  * @param   cbInstr             The size of the fully decoded instruction. Used
    492  *                              for RIP relative addressing.
    493  * @todo combine cbInstr and cbImm!
    494  */
    495 static RTGCPTR iemOpHlpCalcRmEffAddrThreadedAddr64(PVMCPUCC pVCpu, uint8_t bRmEx, uint32_t uSibAndRspOffset,
    496                                                    uint32_t u32Disp, uint8_t cbInstr) RT_NOEXCEPT
    497 {
    498     Log5(("iemOpHlpCalcRmEffAddrThreadedAddr64: bRmEx=%#x\n", bRmEx));
    499     Assert(IEM_IS_64BIT_CODE(pVCpu));
    500 
    501     uint64_t u64EffAddr;
    502 
    503     /* Handle the rip+disp32 form with no registers first. */
    504     if ((bRmEx & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
    505     {
    506         u64EffAddr = (int32_t)u32Disp;
    507         u64EffAddr += pVCpu->cpum.GstCtx.rip + cbInstr;
    508     }
    509     else
    510     {
    511         /* Get the register (or SIB) value. */
    512 #ifdef _MSC_VER
    513         u64EffAddr = 0; /* MSC uninitialized variable analysis is too simple, it seems. */
    514 #endif
    515         switch (bRmEx & (X86_MODRM_RM_MASK | 0x8)) /* bRmEx[bit 3] = REX.B */
    516         {
    517             default:
    518             case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    519             case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    520             case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    521             case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    522             case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    523             case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    524             case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    525             case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    526             case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    527             case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    528             case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    529             case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    530             case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    531             case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    532             /* SIB */
    533             case 4:
    534             case 12:
    535             {
    536                 /* Get the index and scale it. */
    537                 switch (  ((uSibAndRspOffset >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
    538                         | ((bRmEx & 0x10) >> 1)) /* bRmEx[bit 4] = REX.X */
    539                 {
    540                     case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
    541                     case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
    542                     case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
    543                     case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
    544                     case  4: u64EffAddr = 0; /*none */ break;
    545                     case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
    546                     case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
    547                     case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
    548                     case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
    549                     case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
    550                     case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
    551                     case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
    552                     case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
    553                     case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
    554                     case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
    555                     case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
    556                 }
    557                 u64EffAddr <<= (uSibAndRspOffset >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
    558 
    559                 /* add base */
    560                 switch ((uSibAndRspOffset & X86_SIB_BASE_MASK) | (bRmEx & 0x8)) /* bRmEx[bit 3] = REX.B */
    561                 {
    562                     case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
    563                     case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
    564                     case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
    565                     case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
    566                     case  4:
    567                         u64EffAddr += pVCpu->cpum.GstCtx.rsp;
    568                         u64EffAddr += uSibAndRspOffset >> 8;
    569                         break;
    570                     case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
    571                     case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
    572                     case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
    573                     case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
    574                     case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
    575                     case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
    576                     case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
    577                     case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
    578                     case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
    579                     /* complicated encodings */
    580                     case 5:
    581                         if ((bRmEx & X86_MODRM_MOD_MASK) != 0)
    582                             u64EffAddr += pVCpu->cpum.GstCtx.rbp;
    583                         else
    584                             u64EffAddr += (int32_t)u32Disp;
    585                         break;
    586                     case 13:
    587                         if ((bRmEx & X86_MODRM_MOD_MASK) != 0)
    588                             u64EffAddr += pVCpu->cpum.GstCtx.r13;
    589                         else
    590                             u64EffAddr += (int32_t)u32Disp;
    591                         break;
    592                 }
    593                 break;
    594             }
    595         }
    596 
    597         /* Get and add the displacement. */
    598         switch ((bRmEx >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
    599         {
    600             case 0: break;
    601             case 1: u64EffAddr += (int8_t)u32Disp; break;
    602             case 2: u64EffAddr += (int32_t)u32Disp; break;
    603             default: AssertFailed();
    604         }
    605     }
    606 
    607     Log5(("iemOpHlpCalcRmEffAddrThreadedAddr64: EffAddr=%#010RGv\n", u64EffAddr));
    608     return u64EffAddr;
     70
     71
     72
     73static VBOXSTRICTRC iemThreadeFuncWorkerObsoleteTb(PVMCPUCC pVCpu)
     74{
     75    iemThreadedTbObsolete(pVCpu, pVCpu->iem.s.pCurTbR3);
     76    return VINF_IEM_REEXEC_MODE_CHANGED; /** @todo different status code... */
    60977}
    61078
     
    61482 * Built-in function that compares the fExec mask against uParam0.
    61583 */
    616 static IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckMode,
    617                          (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     84IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckMode,
     85                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
    61886{
    61987    uint32_t const fExpectedExec = (uint32_t)uParam0;
    62088    if (pVCpu->iem.s.fExec == fExpectedExec)
    62189        return VINF_SUCCESS;
    622     Log12(("Mode changed at %04x:%08RX64: %#x -> %#x (xor: %#x)\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
    623            fExpectedExec, pVCpu->iem.s.fExec, fExpectedExec ^ pVCpu->iem.s.fExec));
     90    LogFlow(("Mode changed at %04x:%08RX64: %#x -> %#x (xor: %#x)\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
     91             fExpectedExec, pVCpu->iem.s.fExec, fExpectedExec ^ pVCpu->iem.s.fExec));
    62492    RT_NOREF(uParam1, uParam2);
    62593    return VINF_IEM_REEXEC_MODE_CHANGED;
     
    62795
    62896
     97DECL_FORCE_INLINE(RTGCPHYS) iemTbGetRangePhysPageAddr(PCIEMTB pTb, uint8_t idxRange)
     98{
     99    Assert(idxRange < RT_MIN(pTb->cRanges, RT_ELEMENTS(pTb->aRanges)));
     100    uint8_t const idxPage = pTb->aRanges[idxRange].idxPhysPage;
     101    Assert(idxPage <= RT_ELEMENTS(pTb->aGCPhysPages));
     102    if (idxPage == 0)
     103        return pTb->GCPhysPc & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
     104    Assert(!(pTb->aGCPhysPages[idxPage - 1] & GUEST_PAGE_OFFSET_MASK));
     105    return pTb->aGCPhysPages[idxPage - 1];
     106}
     107
     108
     109/**
     110 * Macro that implements the 16/32-bit CS.LIM check, as this is done by a
     111 * number of functions.
     112 */
     113#define BODY_CHECK_CS_LIM(a_cbInstr) do { \
     114        if (RT_LIKELY(pVCpu->cpum.GstCtx.eip - pVCpu->cpum.GstCtx.cs.u32Limit >= cbInstr)) \
     115        { /* likely */ } \
     116        else \
     117        { \
     118            Log7(("EIP out of bounds at %04x:%08RX32 LB %u - CS.LIM=%#RX32\n", \
     119                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, (a_cbInstr), pVCpu->cpum.GstCtx.cs.u32Limit)); \
     120            return iemRaiseGeneralProtectionFault0(pVCpu); \
     121        } \
     122    } while(0)
     123
     124/**
     125 * Macro that implements opcode (re-)checking.
     126 */
     127#define BODY_CHECK_OPCODES(a_pTb, a_idxRange, a_offRange, a_cbInstr) do { \
     128        Assert((a_idxRange) < (a_pTb)->cRanges && (a_pTb)->cRanges < RT_ELEMENTS((a_pTb)->aRanges)); \
     129        Assert((a_offRange) < (a_pTb)->aRanges[(a_idxRange)].cbOpcodes); \
     130        /* We can use pbInstrBuf here as it will be updated when branching (and prior to executing a TB). */ \
     131        if (RT_LIKELY(memcmp(&pVCpu->iem.s.pbInstrBuf[(a_pTb)->aRanges[(a_idxRange)].offPhysPage + (a_offRange)], \
     132                             &(a_pTb)->pabOpcodes[    (a_pTb)->aRanges[(a_idxRange)].offOpcodes  + (a_offRange)], \
     133                                                      (a_pTb)->aRanges[(a_idxRange)].cbOpcodes   - (a_offRange)) == 0)) \
     134        { /* likely */ } \
     135        else \
     136        { \
     137            Log7(("TB obsolete: %p at %04x:%08RX64 LB %u; range %u, off %#x LB %#x + %#x; #%u\n", (a_pTb), \
     138                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, (a_cbInstr), (a_idxRange), \
     139                  (a_pTb)->aRanges[(a_idxRange)].offOpcodes, (a_pTb)->aRanges[(a_idxRange)].cbOpcodes, (a_offRange), __LINE__)); \
     140            RT_NOREF(a_cbInstr); \
     141            return iemThreadeFuncWorkerObsoleteTb(pVCpu); \
     142        } \
     143    } while(0)
     144
     145/**
     146 * Macro that implements TLB loading and updating pbInstrBuf updating for an
     147 * instruction crossing into a new page.
     148 *
     149 * This may long jump if we're raising a \#PF, \#GP or similar trouble.
     150 */
     151#define BODY_LOAD_TLB_FOR_NEW_PAGE(a_pTb, a_offInstr, a_idxRange, a_cbInstr) do { \
     152        pVCpu->iem.s.pbInstrBuf       = NULL; \
     153        pVCpu->iem.s.offCurInstrStart = GUEST_PAGE_SIZE - (a_offInstr); \
     154        pVCpu->iem.s.offInstrNextByte = GUEST_PAGE_SIZE; \
     155        iemOpcodeFetchBytesJmp(pVCpu, 0, NULL); \
     156        \
     157        RTGCPHYS const GCPhysNewPage = iemTbGetRangePhysPageAddr(a_pTb, a_idxRange); \
     158        if (RT_LIKELY(   pVCpu->iem.s.GCPhysInstrBuf == GCPhysNewPage \
     159                      && pVCpu->iem.s.pbInstrBuf)) \
     160        { /* likely */ } \
     161        else \
     162        { \
     163            Log7(("TB obsolete: %p at %04x:%08RX64 LB %u; crossing at %#x; GCPhys=%RGp expected %RGp, pbInstrBuf=%p - #%u\n", \
     164                  (a_pTb), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, (a_cbInstr), (a_offInstr), \
     165                  pVCpu->iem.s.GCPhysInstrBuf, GCPhysNewPage, pVCpu->iem.s.pbInstrBuf, __LINE__)); \
     166            RT_NOREF(a_cbInstr); \
     167            return iemThreadeFuncWorkerObsoleteTb(pVCpu); \
     168        } \
     169    } while(0)
     170
     171/**
     172 * Macro that implements TLB loading and updating pbInstrBuf updating when
     173 * branching or when crossing a page on an instruction boundrary.
     174 *
     175 * This differs from BODY_LOAD_TLB_FOR_NEW_PAGE in that it will first check if
     176 * it is an inter-page branch.
     177 *
     178 * This may long jump if we're raising a \#PF, \#GP or similar trouble.
     179 */
     180#define BODY_LOAD_TLB_FOR_BRANCH(a_pTb, a_idxRange, a_cbInstr) do { \
     181        /* Is RIP within the current code page? */ \
     182        Assert(pVCpu->cpum.GstCtx.cs.u64Base == 0 || !IEM_IS_64BIT_CODE(pVCpu)); \
     183        uint64_t const uPc = pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base; \
     184        uint64_t const off = uPc - pVCpu->iem.s.uInstrBufPc; \
     185        if (off < pVCpu->iem.s.cbInstrBufTotal) \
     186            Assert(!(pVCpu->iem.s.GCPhysInstrBuf & GUEST_PAGE_OFFSET_MASK)); \
     187        else \
     188        { \
     189            /* Must translate new RIP. */ \
     190            pVCpu->iem.s.pbInstrBuf       = NULL; \
     191            pVCpu->iem.s.offCurInstrStart = 0; \
     192            pVCpu->iem.s.offInstrNextByte = 0; \
     193            iemOpcodeFetchBytesJmp(pVCpu, 0, NULL); \
     194            \
     195            RTGCPHYS const GCPhysNewPage = iemTbGetRangePhysPageAddr(a_pTb, a_idxRange); \
     196            if (RT_LIKELY(   pVCpu->iem.s.GCPhysInstrBuf == GCPhysNewPage \
     197                          && pVCpu->iem.s.pbInstrBuf)) \
     198            { /* likely */ } \
     199            else \
     200            { \
     201                Log7(("TB obsolete: %p at %04x:%08RX64 LB %u; branching; GCPhys=%RGp expected %RGp, pbInstrBuf=%p - #%u\n", \
     202                      (a_pTb), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, (a_cbInstr), \
     203                      pVCpu->iem.s.GCPhysInstrBuf, GCPhysNewPage, pVCpu->iem.s.pbInstrBuf, __LINE__)); \
     204                RT_NOREF(a_cbInstr); \
     205                return iemThreadeFuncWorkerObsoleteTb(pVCpu); \
     206            } \
     207        } \
     208    } while(0)
     209
     210
    629211/**
    630212 * Built-in function that checks the EIP/IP + uParam0 is within CS.LIM,
    631213 * raising a \#GP(0) if this isn't the case.
    632214 */
    633 static IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLim,
    634                          (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     215IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLim,
     216                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
    635217{
    636218    uint32_t const cbInstr = (uint32_t)uParam0;
    637     if (pVCpu->cpum.GstCtx.eip - pVCpu->cpum.GstCtx.cs.u32Limit >= cbInstr)
    638         return VINF_SUCCESS;
    639     Log(("EIP out of bounds at %04x:%08RX32 LB %u - CS.LIM=%#RX32\n",
    640          pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, cbInstr, pVCpu->cpum.GstCtx.cs.u32Limit));
    641219    RT_NOREF(uParam1, uParam2);
    642     return iemRaiseGeneralProtectionFault0(pVCpu);
    643 }
    644 
    645 /*
    646  * The threaded functions.
    647  */
    648 #include "IEMThreadedFunctions.cpp.h"
    649 
     220    BODY_CHECK_CS_LIM(cbInstr);
     221    return VINF_SUCCESS;
     222}
     223
     224
     225/**
     226 * Built-in function for re-checking opcodes and CS.LIM after an instruction
     227 * that may have modified them.
     228 */
     229IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodes,
     230                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     231{
     232    PCIEMTB const  pTb      = pVCpu->iem.s.pCurTbR3;
     233    uint32_t const cbInstr  = (uint32_t)uParam0;
     234    uint32_t const idxRange = (uint32_t)uParam1;
     235    uint32_t const offRange = (uint32_t)uParam2;
     236    BODY_CHECK_CS_LIM(cbInstr);
     237    BODY_CHECK_OPCODES(pTb, idxRange, offRange, cbInstr);
     238    return VINF_SUCCESS;
     239}
     240
     241
     242/**
     243 * Built-in function for re-checking opcodes after an instruction that may have
     244 * modified them.
     245 */
     246IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodes,
     247                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     248{
     249    PCIEMTB const  pTb      = pVCpu->iem.s.pCurTbR3;
     250    uint32_t const cbInstr  = (uint32_t)uParam0;
     251    uint32_t const idxRange = (uint32_t)uParam1;
     252    uint32_t const offRange = (uint32_t)uParam2;
     253    BODY_CHECK_OPCODES(pTb, idxRange, offRange, cbInstr);
     254    return VINF_SUCCESS;
     255}
     256
     257
     258/**
     259 * Built-in function for checking CS.LIM, loading TLB and checking opcodes on
     260 * both pages when transitioning to a different code page.
     261 *
     262 * This is used when the previous instruction requires revalidation of opcodes
     263 * bytes and the current instruction stries a page boundrary with opcode bytes
     264 * in both the old and new page.
     265 *
     266 * @see iemThreadedFunc_BltIn_CheckOpcodesAcrossPageLoadingTlb
     267 */
     268IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodesAcrossPageLoadingTlb,
     269                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     270{
     271    PCIEMTB const  pTb         = pVCpu->iem.s.pCurTbR3;
     272    uint32_t const cbInstr     = (uint32_t)uParam0;
     273    uint32_t const cbStartPage = (uint32_t)(uParam0 >> 32);
     274    uint32_t const idxRange1   = (uint32_t)uParam1;
     275    uint32_t const offRange1   = (uint32_t)uParam2;
     276    uint32_t const idxRange2   = idxRange1 + 1;
     277    BODY_CHECK_CS_LIM(cbInstr);
     278    BODY_CHECK_OPCODES(pTb, idxRange1, offRange1, cbInstr);
     279    BODY_LOAD_TLB_FOR_NEW_PAGE(pTb, cbStartPage, idxRange2, cbInstr);
     280    BODY_CHECK_OPCODES(pTb, idxRange2, 0, cbInstr);
     281    return VINF_SUCCESS;
     282}
     283
     284
     285/**
     286 * Built-in function for loading TLB and checking opcodes on both pages when
     287 * transitioning to a different code page.
     288 *
     289 * This is used when the previous instruction requires revalidation of opcodes
     290 * bytes and the current instruction stries a page boundrary with opcode bytes
     291 * in both the old and new page.
     292 *
     293 * @see iemThreadedFunc_BltIn_CheckCsLimAndOpcodesAcrossPageLoadingTlb
     294 */
     295IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodesAcrossPageLoadingTlb,
     296                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     297{
     298    PCIEMTB const  pTb         = pVCpu->iem.s.pCurTbR3;
     299    uint32_t const cbInstr     = (uint32_t)uParam0;
     300    uint32_t const cbStartPage = (uint32_t)(uParam0 >> 32);
     301    uint32_t const idxRange1   = (uint32_t)uParam1;
     302    uint32_t const offRange1   = (uint32_t)uParam2;
     303    uint32_t const idxRange2   = idxRange1 + 1;
     304    BODY_CHECK_OPCODES(pTb, idxRange1, offRange1, cbInstr);
     305    BODY_LOAD_TLB_FOR_NEW_PAGE(pTb, cbStartPage, idxRange2, cbInstr);
     306    BODY_CHECK_OPCODES(pTb, idxRange2, 0, cbInstr);
     307    return VINF_SUCCESS;
     308}
     309
     310
     311/**
     312 * Built-in function for checking CS.LIM, loading TLB and checking opcodes when
     313 * transitioning to a different code page.
     314 *
     315 * The code page transition can either be natural over onto the next page (with
     316 * the instruction starting at page offset zero) or by means of branching.
     317 *
     318 * @see iemThreadedFunc_BltIn_CheckOpcodesLoadingTlb
     319 */
     320IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodesLoadingTlb,
     321                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     322{
     323    PCIEMTB const  pTb      = pVCpu->iem.s.pCurTbR3;
     324    uint32_t const cbInstr  = (uint32_t)uParam0;
     325    uint32_t const idxRange = (uint32_t)uParam1;
     326    uint32_t const offRange = (uint32_t)uParam2;
     327    BODY_CHECK_CS_LIM(cbInstr);
     328    BODY_LOAD_TLB_FOR_BRANCH(pTb, idxRange, cbInstr);
     329    BODY_CHECK_OPCODES(pTb, idxRange, offRange, cbInstr);
     330    return VINF_SUCCESS;
     331}
     332
     333
     334/**
     335 * Built-in function for loading TLB and checking opcodes when transitioning to
     336 * a different code page.
     337 *
     338 * The code page transition can either be natural over onto the next page (with
     339 * the instruction starting at page offset zero) or by means of branching.
     340 *
     341 * @see iemThreadedFunc_BltIn_CheckCsLimAndOpcodesLoadingTlb
     342 */
     343IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodesLoadingTlb,
     344                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     345{
     346    PCIEMTB const  pTb      = pVCpu->iem.s.pCurTbR3;
     347    uint32_t const cbInstr  = (uint32_t)uParam0;
     348    uint32_t const idxRange = (uint32_t)uParam1;
     349    uint32_t const offRange = (uint32_t)uParam2;
     350    BODY_LOAD_TLB_FOR_BRANCH(pTb, idxRange, cbInstr);
     351    BODY_CHECK_OPCODES(pTb, idxRange, offRange, cbInstr);
     352    return VINF_SUCCESS;
     353}
     354
     355
     356/**
     357 * Built-in function for checking CS.LIM, loading TLB and checking opcodes when
     358 * advancing naturally to a different code page.
     359 *
     360 * Only opcodes on the new page is checked.
     361 *
     362 * @see iemThreadedFunc_BltIn_CheckOpcodesOnNextPageLoadingTlb
     363 */
     364IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodesOnNextPageLoadingTlb,
     365                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     366{
     367    PCIEMTB const  pTb         = pVCpu->iem.s.pCurTbR3;
     368    uint32_t const cbInstr     = (uint32_t)uParam0;
     369    uint32_t const cbStartPage = (uint32_t)(uParam0 >> 32);
     370    uint32_t const idxRange1   = (uint32_t)uParam1;
     371    //uint32_t const offRange1   = (uint32_t)uParam2;
     372    uint32_t const idxRange2   = idxRange1 + 1;
     373    BODY_CHECK_CS_LIM(cbInstr);
     374    BODY_LOAD_TLB_FOR_NEW_PAGE(pTb, cbStartPage, idxRange2, cbInstr);
     375    BODY_CHECK_OPCODES(pTb, idxRange2, 0, cbInstr);
     376    RT_NOREF(uParam2);
     377    return VINF_SUCCESS;
     378}
     379
     380
     381/**
     382 * Built-in function for loading TLB and checking opcodes when advancing
     383 * naturally to a different code page.
     384 *
     385 * Only opcodes on the new page is checked.
     386 *
     387 * @see iemThreadedFunc_BltIn_CheckCsLimAndOpcodesOnNextPageLoadingTlb
     388 */
     389IEM_DECL_IMPL_DEF(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodesOnNextPageLoadingTlb,
     390                  (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2))
     391{
     392    PCIEMTB const  pTb         = pVCpu->iem.s.pCurTbR3;
     393    uint32_t const cbInstr     = (uint32_t)uParam0;
     394    uint32_t const cbStartPage = (uint32_t)(uParam0 >> 32);
     395    uint32_t const idxRange1   = (uint32_t)uParam1;
     396    //uint32_t const offRange1   = (uint32_t)uParam2;
     397    uint32_t const idxRange2   = idxRange1 + 1;
     398    BODY_LOAD_TLB_FOR_NEW_PAGE(pTb, cbStartPage, idxRange2, cbInstr);
     399    BODY_CHECK_OPCODES(pTb, idxRange2, 0, cbInstr);
     400    RT_NOREF(uParam2);
     401    return VINF_SUCCESS;
     402}
     403
  • trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py

    r100633 r100694  
    12561256            '    kIemThreadedFunc_Invalid = 0,',
    12571257            '',
    1258             '    /*'
    1259             '     * Predefined'
    1260             '     */'
     1258            '    /*',
     1259            '     * Predefined',
     1260            '     */',
    12611261            '    kIemThreadedFunc_CheckMode,',
    12621262            '    kIemThreadedFunc_CheckCsLim,',
     1263            '    kIemThreadedFunc_CheckCsLimAndOpcodes,',
     1264            '    kIemThreadedFunc_CheckCsLimAndOpcodesAcrossPageLoadingTlb,',
     1265            '    kIemThreadedFunc_CheckCsLimAndOpcodesLoadingTlb,',
     1266            '    kIemThreadedFunc_CheckCsLimAndOpcodesOnNextPageLoadingTlb,',
     1267            '    kIemThreadedFunc_CheckOpcodes,',
     1268            '    kIemThreadedFunc_CheckOpcodesAcrossPageLoadingTlb,',
     1269            '    kIemThreadedFunc_CheckOpcodesLoadingTlb,',
     1270            '    kIemThreadedFunc_CheckOpcodesOnNextPageLoadingTlb,',
    12631271        ];
    12641272        iThreadedFunction = 1;
     
    14201428                   + '    iemThreadedFunc_BltIn_CheckMode,\n'
    14211429                   + '    iemThreadedFunc_BltIn_CheckCsLim,\n'
     1430                   + '    iemThreadedFunc_BltIn_CheckCsLimAndOpcodes,\n'
     1431                   + '    iemThreadedFunc_BltIn_CheckCsLimAndOpcodesAcrossPageLoadingTlb,\n'
     1432                   + '    iemThreadedFunc_BltIn_CheckCsLimAndOpcodesLoadingTlb,\n'
     1433                   + '    iemThreadedFunc_BltIn_CheckCsLimAndOpcodesOnNextPageLoadingTlb,\n'
     1434                   + '    iemThreadedFunc_BltIn_CheckOpcodes,\n'
     1435                   + '    iemThreadedFunc_BltIn_CheckOpcodesAcrossPageLoadingTlb,\n'
     1436                   + '    iemThreadedFunc_BltIn_CheckOpcodesLoadingTlb,\n'
     1437                   + '    iemThreadedFunc_BltIn_CheckOpcodesOnNextPageLoadingTlb,\n'
    14221438                   );
    14231439        iThreadedFunction = 1;
     
    14531469                   + '    "BltIn_CheckMode",\n'
    14541470                   + '    "BltIn_CheckCsLim",\n'
     1471                   + '    "BltIn_CheckCsLimAndOpcodes",\n'
     1472                   + '    "BltIn_CheckCsLimAndOpcodesAcrossPageLoadingTlb",\n'
     1473                   + '    "BltIn_CheckCsLimAndOpcodesLoadingTlb",\n'
     1474                   + '    "BltIn_CheckCsLimAndOpcodesOnNextPageLoadingTlb",\n'
     1475                   + '    "BltIn_CheckOpcodes",\n'
     1476                   + '    "BltIn_CheckOpcodesAcrossPageLoadingTlb",\n'
     1477                   + '    "BltIn_CheckOpcodesLoadingTlb",\n'
     1478                   + '    "BltIn_CheckOpcodesOnNextPageLoadingTlb",\n'
    14551479                   );
    14561480        iThreadedFunction = 1;
  • trunk/src/VBox/VMM/VMMAll/IEMAllThreadedRecompiler.cpp

    r100671 r100694  
    1111 *      - Level 5  (Log5) : Decoding details. [same as IEM]
    1212 *      - Level 6  (Log6) :
    13  *      - Level 7  (Log7) :
     13 *      - Level 7  (Log7) : TB obsoletion.
    1414 *      - Level 8  (Log8) : TB compilation.
    1515 *      - Level 9  (Log9) : TB exec.
    1616 *      - Level 10 (Log10): TB block lookup.
    17  *      - Level 11 (Log11): TB block lookup.
     17 *      - Level 11 (Log11): TB block lookup details.
    1818 *      - Level 12 (Log12): TB insertion.
    1919 */
     
    114114*   Structures and Typedefs                                                                                                      *
    115115*********************************************************************************************************************************/
    116 /**
    117  * A call for the threaded call table.
    118  */
    119 typedef struct IEMTHRDEDCALLENTRY
    120 {
    121     /** The function to call (IEMTHREADEDFUNCS). */
    122     uint16_t    enmFunction;
    123     uint16_t    uUnused0;
    124 
    125     /** Offset into IEMTB::pabOpcodes. */
    126     uint16_t    offOpcode;
    127     /** The opcode length. */
    128     uint8_t     cbOpcode;
    129     uint8_t     uUnused1;
    130 
    131     /** Generic parameters. */
    132     uint64_t    auParams[3];
    133 } IEMTHRDEDCALLENTRY;
    134 AssertCompileSize(IEMTHRDEDCALLENTRY, sizeof(uint64_t) * 4);
    135 /** Pointer to a threaded call entry. */
    136 typedef IEMTHRDEDCALLENTRY       *PIEMTHRDEDCALLENTRY;
    137 /** Pointer to a const threaded call entry. */
    138 typedef IEMTHRDEDCALLENTRY const *PCIEMTHRDEDCALLENTRY;
    139 
    140 
    141 
    142 /**
    143  * Translation block.
    144  */
    145 typedef struct IEMTB
    146 {
    147     /** Next block with the same hash table entry. */
    148     PIEMTB volatile     pNext;
    149     /** List on the local VCPU for blocks. */
    150     RTLISTNODE          LocalList;
    151 
    152     /** @name What uniquely identifies the block.
    153      * @{ */
    154     RTGCPHYS            GCPhysPc;
    155     /** IEMTB_F_XXX (i.e. IEM_F_XXX ++). */
    156     uint32_t            fFlags;
    157     union
    158     {
    159         struct
    160         {
    161             /**< Relevant CS X86DESCATTR_XXX bits. */
    162             uint16_t    fAttr;
    163         } x86;
    164     };
    165     /** @} */
    166 
    167     union
    168     {
    169         struct
    170         {
    171             /** The call sequence table. */
    172             PIEMTHRDEDCALLENTRY paCalls;
    173             /** Number of calls in paCalls. */
    174             uint16_t            cCalls;
    175             /** Number of calls allocated. */
    176             uint16_t            cAllocated;
    177         } Thrd;
    178     };
    179 
    180 
    181     /** Number of bytes of opcodes stored in pabOpcodes. */
    182     uint16_t            cbOpcodes;
    183     /** The max storage available in the pabOpcodes block. */
    184     uint16_t            cbOpcodesAllocated;
    185     /** Pointer to the opcode bytes this block was recompiled from. */
    186     uint8_t            *pabOpcodes;
    187 
    188 #if 0
    189     struct
    190     {
    191         uint16_t        offOpcodes;
    192         uint16_t        cbOpcodes;
    193     } aRanges;
    194 
    195     /** Physical pages that the .    */
    196     RTGCPHYS            aGCPhysPgs[2];
    197 #endif
    198 
    199 } IEMTB;
     116
    200117
    201118
     
    203120*   Internal Functions                                                                                                           *
    204121*********************************************************************************************************************************/
     122static bool         iemThreadedCompileBeginEmitCallsComplications(PVMCPUCC pVCpu, PIEMTB pTb);
    205123static VBOXSTRICTRC iemThreadedTbExec(PVMCPUCC pVCpu, PIEMTB pTb);
    206124
     
    225143#define IEM_MC2_BEGIN_EMIT_CALLS() \
    226144    { \
    227         PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
    228         AssertMsg(pVCpu->iem.s.offOpcode == IEM_GET_INSTR_LEN(pVCpu), \
    229                   ("%u vs %u (%04x:%08RX64)\n", pVCpu->iem.s.offOpcode, IEM_GET_INSTR_LEN(pVCpu), \
     145        PIEMTB const  pTb = pVCpu->iem.s.pCurTbR3; \
     146        uint8_t const cbInstrMc2 = IEM_GET_INSTR_LEN(pVCpu); \
     147        AssertMsg(pVCpu->iem.s.offOpcode == cbInstrMc2, \
     148                  ("%u vs %u (%04x:%08RX64)\n", pVCpu->iem.s.offOpcode, cbInstrMc2, \
    230149                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip)); \
    231         /** @todo check for cross page stuff */ \
    232         if (!(pTb->fFlags & IEMTB_F_CS_LIM_CHECKS)) \
     150        \
     151        /* No page crossing, right? */ \
     152        uint16_t const offOpcodeMc2 = pTb->cbOpcodes; \
     153        uint8_t const  idxRangeMc2  = pTb->cRanges - 1; \
     154        if (   !pVCpu->iem.s.fTbCrossedPage \
     155            && !pVCpu->iem.s.fTbCheckOpcodes \
     156            && !pVCpu->iem.s.fTbBranched \
     157            && !(pTb->fFlags & IEMTB_F_CS_LIM_CHECKS)) \
     158        { \
     159            /** @todo Custom copy function, given range is 1 thru 15 bytes. */ \
     160            memcpy(&pTb->pabOpcodes[offOpcodeMc2], pVCpu->iem.s.abOpcode, pVCpu->iem.s.offOpcode); \
     161            pTb->cbOpcodes                       = offOpcodeMc2 + pVCpu->iem.s.offOpcode; \
     162            pTb->aRanges[idxRangeMc2].cbOpcodes += cbInstrMc2; \
     163            Assert(pTb->cbOpcodes <= pTb->cbOpcodesAllocated); \
     164        } \
     165        else if (iemThreadedCompileBeginEmitCallsComplications(pVCpu, pTb)) \
    233166        { /* likely */ } \
    234167        else \
    235         { \
    236             PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
    237             pCall->enmFunction = kIemThreadedFunc_CheckCsLim; \
    238             pCall->offOpcode   = pTb->cbOpcodes; \
    239             pCall->auParams[0] = pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
    240             pCall->auParams[1] = 0; \
    241             pCall->auParams[2] = 0; \
    242         } \
     168            return VINF_IEM_RECOMPILE_END_TB; \
     169        \
    243170        do { } while (0)
    244171
     
    248175        PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
    249176        pCall->enmFunction = a_enmFunction; \
    250         pCall->offOpcode   = pTb->cbOpcodes; \
    251         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
     177        pCall->offOpcode   = offOpcodeMc2; \
     178        pCall->cbOpcode    = cbInstrMc2; \
     179        pCall->idxRange    = idxRangeMc2; \
    252180        pCall->auParams[0] = 0; \
    253181        pCall->auParams[1] = 0; \
     
    260188        PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
    261189        pCall->enmFunction = a_enmFunction; \
    262         pCall->offOpcode   = pTb->cbOpcodes; \
    263         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
     190        pCall->offOpcode   = offOpcodeMc2; \
     191        pCall->cbOpcode    = cbInstrMc2; \
     192        pCall->idxRange    = idxRangeMc2; \
    264193        pCall->auParams[0] = a_uArg0; \
    265194        pCall->auParams[1] = 0; \
     
    273202        PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
    274203        pCall->enmFunction = a_enmFunction; \
    275         pCall->offOpcode   = pTb->cbOpcodes; \
    276         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
     204        pCall->offOpcode   = offOpcodeMc2; \
     205        pCall->cbOpcode    = cbInstrMc2; \
     206        pCall->idxRange    = idxRangeMc2; \
    277207        pCall->auParams[0] = a_uArg0; \
    278208        pCall->auParams[1] = a_uArg1; \
     
    287217        PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
    288218        pCall->enmFunction = a_enmFunction; \
    289         pCall->offOpcode   = pTb->cbOpcodes; \
    290         pCall->cbOpcode    = IEM_GET_INSTR_LEN(pVCpu); \
     219        pCall->offOpcode   = offOpcodeMc2; \
     220        pCall->cbOpcode    = cbInstrMc2; \
     221        pCall->idxRange    = idxRangeMc2; \
    291222        pCall->auParams[0] = a_uArg0; \
    292223        pCall->auParams[1] = a_uArg1; \
     
    295226
    296227#define IEM_MC2_END_EMIT_CALLS() \
     228        pTb->cInstructions++; \
    297229    } while (0)
    298230
     
    683615            if (pTb->pabOpcodes)
    684616            {
    685                 pTb->Thrd.cAllocated    = cCalls;
    686                 pTb->cbOpcodesAllocated = cCalls * 16;
    687                 pTb->Thrd.cCalls        = 0;
    688                 pTb->cbOpcodes          = 0;
    689                 pTb->pNext              = NULL;
     617                pTb->Thrd.cAllocated        = cCalls;
     618                pTb->cbOpcodesAllocated     = cCalls * 16;
     619                pTb->Thrd.cCalls            = 0;
     620                pTb->cbOpcodes              = 0;
     621                pTb->pNext                  = NULL;
    690622                RTListInit(&pTb->LocalList);
    691                 pTb->GCPhysPc           = GCPhysPc;
    692                 pTb->x86.fAttr          = (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u;
    693                 pTb->fFlags             = (pVCpu->iem.s.fExec & IEMTB_F_IEM_F_MASK) | fExtraFlags;
     623                pTb->GCPhysPc               = GCPhysPc;
     624                pTb->x86.fAttr              = (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u;
     625                pTb->fFlags                 = (pVCpu->iem.s.fExec & IEMTB_F_IEM_F_MASK) | fExtraFlags;
     626
     627                /* Init the first opcode range. */
     628                pTb->cRanges                = 1;
     629                pTb->aRanges[0].cbOpcodes   = 0;
     630                pTb->aRanges[0].offOpcodes  = 0;
     631                pTb->aRanges[0].offPhysPage = GCPhysPc & GUEST_PAGE_OFFSET_MASK;
     632                pTb->aRanges[0].u2Unused    = 0;
     633                pTb->aRanges[0].idxPhysPage = 0;
     634                pTb->aGCPhysPages[0]        = NIL_RTGCPHYS;
     635                pTb->aGCPhysPages[1]        = NIL_RTGCPHYS;
     636
    694637                pVCpu->iem.s.cTbAllocs++;
    695638                return pTb;
     
    746689    RTMemFree(pTb);
    747690    pVCpu->iem.s.cTbFrees++;
     691}
     692
     693
     694/**
     695 * Called by opcode verifier functions when they detect a problem.
     696 */
     697void iemThreadedTbObsolete(PVMCPUCC pVCpu, PIEMTB pTb)
     698{
     699    iemThreadedTbFree(pVCpu->CTX_SUFF(pVM), pVCpu, pTb);
    748700}
    749701
     
    901853        pVCpu->iem.s.rcPassUp               = VINF_SUCCESS;
    902854        pVCpu->iem.s.fEndTb                 = false;
     855        pVCpu->iem.s.fTbCheckOpcodes        = false;
     856        pVCpu->iem.s.fTbBranched            = false;
     857        pVCpu->iem.s.fTbCrossedPage         = false;
    903858    }
    904859    else
     
    907862        Assert(pVCpu->iem.s.rcPassUp        == VINF_SUCCESS);
    908863        Assert(pVCpu->iem.s.fEndTb          == false);
     864        Assert(pVCpu->iem.s.fTbCrossedPage  == false);
    909865    }
    910866
     
    992948
    993949
     950DECLINLINE(void) iemThreadedCopyOpcodeBytesInline(PCVMCPUCC pVCpu, uint8_t *pbDst, uint8_t cbInstr)
     951{
     952    switch (cbInstr)
     953    {
     954        default: AssertMsgFailed(("%#x\n", cbInstr)); RT_FALL_THROUGH();
     955        case 15:    pbDst[14] = pVCpu->iem.s.abOpcode[14]; RT_FALL_THROUGH();
     956        case 14:    pbDst[13] = pVCpu->iem.s.abOpcode[13]; RT_FALL_THROUGH();
     957        case 13:    pbDst[12] = pVCpu->iem.s.abOpcode[12]; RT_FALL_THROUGH();
     958        case 12:    pbDst[11] = pVCpu->iem.s.abOpcode[11]; RT_FALL_THROUGH();
     959        case 11:    pbDst[10] = pVCpu->iem.s.abOpcode[10]; RT_FALL_THROUGH();
     960        case 10:    pbDst[9]  = pVCpu->iem.s.abOpcode[9];  RT_FALL_THROUGH();
     961        case 9:     pbDst[8]  = pVCpu->iem.s.abOpcode[8];  RT_FALL_THROUGH();
     962        case 8:     pbDst[7]  = pVCpu->iem.s.abOpcode[7];  RT_FALL_THROUGH();
     963        case 7:     pbDst[6]  = pVCpu->iem.s.abOpcode[6];  RT_FALL_THROUGH();
     964        case 6:     pbDst[5]  = pVCpu->iem.s.abOpcode[5];  RT_FALL_THROUGH();
     965        case 5:     pbDst[4]  = pVCpu->iem.s.abOpcode[4];  RT_FALL_THROUGH();
     966        case 4:     pbDst[3]  = pVCpu->iem.s.abOpcode[3];  RT_FALL_THROUGH();
     967        case 3:     pbDst[2]  = pVCpu->iem.s.abOpcode[2];  RT_FALL_THROUGH();
     968        case 2:     pbDst[1]  = pVCpu->iem.s.abOpcode[1];  RT_FALL_THROUGH();
     969        case 1:     pbDst[0]  = pVCpu->iem.s.abOpcode[0];  break;
     970    }
     971}
     972
     973
     974/**
     975 * Called by IEM_MC2_BEGIN_EMIT_CALLS() under one of these conditions:
     976 *
     977 *      - CS LIM check required.
     978 *      - Must recheck opcode bytes.
     979 *      - Previous instruction branched.
     980 *      - TLB load detected, probably due to page crossing.
     981 *
     982 * @returns true if everything went well, false if we're out of space in the TB
     983 *          (e.g. opcode ranges).
     984 * @param   pVCpu       The cross context virtual CPU structure of the calling
     985 *                      thread.
     986 * @param   pTb         The translation block being compiled.
     987 */
     988static bool iemThreadedCompileBeginEmitCallsComplications(PVMCPUCC pVCpu, PIEMTB pTb)
     989{
     990    Assert((pVCpu->iem.s.GCPhysInstrBuf & GUEST_PAGE_OFFSET_MASK) == 0);
     991
     992    /*
     993     * Prepare call now, even before we know if can accept the instruction in this TB.
     994     * This allows us amending parameters w/o making every case suffer.
     995     */
     996    uint8_t const             cbInstr   = IEM_GET_INSTR_LEN(pVCpu);
     997    uint16_t const            offOpcode = pTb->cbOpcodes;
     998    uint8_t                   idxRange  = pTb->cRanges - 1;
     999
     1000    PIEMTHRDEDCALLENTRY const pCall     = &pTb->Thrd.paCalls[pTb->Thrd.cCalls];
     1001    pCall->offOpcode   = offOpcode;
     1002    pCall->idxRange    = idxRange;
     1003    pCall->cbOpcode    = cbInstr;
     1004    pCall->auParams[0] = cbInstr;
     1005    pCall->auParams[1] = idxRange;
     1006    pCall->auParams[2] = offOpcode - pTb->aRanges[idxRange].offOpcodes;
     1007
     1008/** @todo check if we require IEMTB_F_CS_LIM_CHECKS for any new page we've
     1009 *        gotten onto.  If we do, stop */
     1010
     1011    /*
     1012     * Case 1: We've branched (RIP changed).
     1013     *
     1014     * Sub-case 1a: Same page, no TLB load, so fTbCrossedPage is false.
     1015     *         Req: 1 extra range, no extra phys.
     1016     *
     1017     * Sub-case 1b: Different page, so TLB load necessary and fTbCrossedPage is true.
     1018     *         Req: 1 extra range, probably 1 extra phys page entry.
     1019     *
     1020     * Sub-case 1c: Different page, so TLB load necessary and fTbCrossedPage is true,
     1021     *              but in addition we cross into the following page and require
     1022     *              another TLB load.
     1023     *         Req: 2 extra ranges, probably 2 extra phys page entries.
     1024     *
     1025     * Sub-case 1d: Same page, so no initial TLB load necessary, but we cross into
     1026     *              the following page and thus fTbCrossedPage is true.
     1027     *         Req: 2 extra ranges, probably 1 extra phys page entry.
     1028     *
     1029     * Note! We do not currently optimize branching to the next instruction (sorry
     1030     *       32-bit PIC code).  We could maybe do that in the branching code that sets (or not) fTbBranched.
     1031     */
     1032    if (pVCpu->iem.s.fTbBranched)
     1033    {
     1034AssertFailed(); /** @todo enable including branches in TBs and debug this code. */
     1035        if (   !pVCpu->iem.s.fTbCrossedPage       /* 1a */
     1036            || pVCpu->iem.s.offCurInstrStart >= 0 /* 1b */ )
     1037        {
     1038            /* 1a + 1b - instruction fully within the branched to page. */
     1039            Assert(pVCpu->iem.s.offCurInstrStart >= 0);
     1040            Assert(pVCpu->iem.s.offCurInstrStart + cbInstr <= GUEST_PAGE_SIZE);
     1041
     1042            /* Check that we've got a free range. */
     1043            idxRange += 1;
     1044            if (idxRange < RT_ELEMENTS(pTb->aRanges))
     1045            { /* likely */ }
     1046            else
     1047                return false;
     1048            pCall->idxRange    = idxRange;
     1049            pCall->auParams[1] = idxRange;
     1050            pCall->auParams[2] = 0;
     1051
     1052            /* Check that we've got a free page slot. */
     1053            AssertCompile(RT_ELEMENTS(pTb->aGCPhysPages) == 2);
     1054            RTGCPHYS const GCPhysNew = pVCpu->iem.s.GCPhysInstrBuf & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
     1055            if ((pTb->GCPhysPc & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK) == GCPhysNew)
     1056                pTb->aRanges[idxRange].idxPhysPage = 0;
     1057            else if (   pTb->aGCPhysPages[0] == NIL_RTGCPHYS
     1058                     || pTb->aGCPhysPages[0] == GCPhysNew)
     1059            {
     1060                pTb->aGCPhysPages[0] = GCPhysNew;
     1061                pTb->aRanges[idxRange].idxPhysPage = 1;
     1062            }
     1063            else if (   pTb->aGCPhysPages[1] == NIL_RTGCPHYS
     1064                     || pTb->aGCPhysPages[1] == GCPhysNew)
     1065            {
     1066                pTb->aGCPhysPages[1] = GCPhysNew;
     1067                pTb->aRanges[idxRange].idxPhysPage = 2;
     1068            }
     1069            else
     1070                return false;
     1071
     1072            /* Finish setting up the new range. */
     1073            pTb->aRanges[idxRange].offPhysPage = pVCpu->iem.s.offCurInstrStart;
     1074            pTb->aRanges[idxRange].offOpcodes  = offOpcode;
     1075            pTb->aRanges[idxRange].cbOpcodes   = cbInstr;
     1076            pTb->cRanges++;
     1077
     1078            /* Determin which function we need to load & check.
     1079               Note! For jumps to a new page, we'll set both fTbBranched and
     1080                     fTbCrossedPage to avoid unnecessary TLB work for intra
     1081                     page branching */
     1082            if (pVCpu->iem.s.fTbCrossedPage)
     1083                pCall->enmFunction = pTb->fFlags & IEMTB_F_CS_LIM_CHECKS
     1084                                   ? kIemThreadedFunc_CheckCsLimAndOpcodesLoadingTlb
     1085                                   : kIemThreadedFunc_CheckOpcodesLoadingTlb;
     1086            else
     1087                pCall->enmFunction = pTb->fFlags & IEMTB_F_CS_LIM_CHECKS
     1088                                   ? kIemThreadedFunc_CheckCsLimAndOpcodes
     1089                                   : kIemThreadedFunc_CheckOpcodes;
     1090        }
     1091        else
     1092        {
     1093            /* 1c + 1d - instruction crosses pages. */
     1094            Assert(pVCpu->iem.s.offCurInstrStart < 0);
     1095            Assert(pVCpu->iem.s.offCurInstrStart + cbInstr > 0);
     1096
     1097            /* Lazy bird: Check that this isn't case 1c, since we've already
     1098                          load the first physical address.  End the TB and
     1099                          make it a case 2b instead.
     1100
     1101                          Hmm. Too much bother to detect, so just do the same
     1102                          with case 1d as well. */
     1103#if 0       /** @todo get back to this later when we've got the actual branch code in
     1104             *        place. */
     1105            uint8_t const cbStartPage = (uint8_t)-pVCpu->iem.s.offCurInstrStart;
     1106
     1107            /* Check that we've got two free ranges. */
     1108            if (idxRange + 2 < RT_ELEMENTS(pTb->aRanges))
     1109            { /* likely */ }
     1110            else
     1111                return false;
     1112            idxRange += 1;
     1113            pCall->idxRange    = idxRange;
     1114            pCall->auParams[1] = idxRange;
     1115            pCall->auParams[2] = 0;
     1116
     1117            /* ... */
     1118
     1119#else
     1120            return false;
     1121#endif
     1122        }
     1123    }
     1124
     1125    /*
     1126     * Case 2: Page crossing.
     1127     *
     1128     * Sub-case 2a: The instruction starts on the first byte in the next page.
     1129     *
     1130     * Sub-case 2b: The instruction has opcode bytes in both the current and
     1131     *              following page.
     1132     *
     1133     * Both cases requires a new range table entry and probably a new physical
     1134     * page entry.  The difference is in which functions to emit and whether to
     1135     * add bytes to the current range.
     1136     */
     1137    else if (pVCpu->iem.s.fTbCrossedPage)
     1138    {
     1139        /* Check that we've got a free range. */
     1140        idxRange += 1;
     1141        if (idxRange < RT_ELEMENTS(pTb->aRanges))
     1142        { /* likely */ }
     1143        else
     1144            return false;
     1145
     1146        /* Check that we've got a free page slot. */
     1147        AssertCompile(RT_ELEMENTS(pTb->aGCPhysPages) == 2);
     1148        RTGCPHYS const GCPhysNew = pVCpu->iem.s.GCPhysInstrBuf & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
     1149        if ((pTb->GCPhysPc & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK) == GCPhysNew)
     1150            pTb->aRanges[idxRange].idxPhysPage = 0;
     1151        else if (   pTb->aGCPhysPages[0] == NIL_RTGCPHYS
     1152                 || pTb->aGCPhysPages[0] == GCPhysNew)
     1153        {
     1154            pTb->aGCPhysPages[0] = GCPhysNew;
     1155            pTb->aRanges[idxRange].idxPhysPage = 1;
     1156        }
     1157        else if (   pTb->aGCPhysPages[1] == NIL_RTGCPHYS
     1158                 || pTb->aGCPhysPages[1] == GCPhysNew)
     1159        {
     1160            pTb->aGCPhysPages[1] = GCPhysNew;
     1161            pTb->aRanges[idxRange].idxPhysPage = 2;
     1162        }
     1163        else
     1164            return false;
     1165
     1166        if (((pTb->aRanges[idxRange - 1].offPhysPage + pTb->aRanges[idxRange - 1].cbOpcodes) & GUEST_PAGE_OFFSET_MASK) == 0)
     1167        {
     1168            Assert(pVCpu->iem.s.offCurInstrStart == 0);
     1169            pCall->idxRange    = idxRange;
     1170            pCall->auParams[1] = idxRange;
     1171            pCall->auParams[2] = 0;
     1172
     1173            /* Finish setting up the new range. */
     1174            pTb->aRanges[idxRange].offPhysPage = pVCpu->iem.s.offCurInstrStart;
     1175            pTb->aRanges[idxRange].offOpcodes  = offOpcode;
     1176            pTb->aRanges[idxRange].cbOpcodes   = cbInstr;
     1177            pTb->cRanges++;
     1178
     1179            /* Determin which function we need to load & check. */
     1180            pCall->enmFunction = pTb->fFlags & IEMTB_F_CS_LIM_CHECKS
     1181                               ? kIemThreadedFunc_CheckCsLimAndOpcodesLoadingTlb
     1182                               : kIemThreadedFunc_CheckOpcodesLoadingTlb;
     1183        }
     1184        else
     1185        {
     1186            Assert(pVCpu->iem.s.offCurInstrStart < 0);
     1187            Assert(pVCpu->iem.s.offCurInstrStart + cbInstr > 0);
     1188            uint8_t const cbStartPage = (uint8_t)-pVCpu->iem.s.offCurInstrStart;
     1189            pCall->auParams[0] |= (uint64_t)cbStartPage << 32;
     1190
     1191            /* We've good. Split the instruction over the old and new range table entries. */
     1192            pTb->aRanges[idxRange - 1].cbOpcodes += cbStartPage;
     1193
     1194            pTb->aRanges[idxRange].offPhysPage    = 0;
     1195            pTb->aRanges[idxRange].offOpcodes     = offOpcode + cbStartPage;
     1196            pTb->aRanges[idxRange].cbOpcodes      = cbInstr   - cbStartPage;
     1197            pTb->cRanges++;
     1198
     1199            /* Determin which function we need to load & check. */
     1200            if (pVCpu->iem.s.fTbCheckOpcodes)
     1201                pCall->enmFunction = pTb->fFlags & IEMTB_F_CS_LIM_CHECKS
     1202                                   ? kIemThreadedFunc_CheckCsLimAndOpcodesAcrossPageLoadingTlb
     1203                                   : kIemThreadedFunc_CheckOpcodesAcrossPageLoadingTlb;
     1204            else
     1205                pCall->enmFunction = pTb->fFlags & IEMTB_F_CS_LIM_CHECKS
     1206                                   ? kIemThreadedFunc_CheckCsLimAndOpcodesOnNextPageLoadingTlb
     1207                                   : kIemThreadedFunc_CheckOpcodesOnNextPageLoadingTlb;
     1208        }
     1209    }
     1210
     1211    /*
     1212     * Regular case: No new range required.
     1213     */
     1214    else
     1215    {
     1216        Assert(pVCpu->iem.s.fTbCheckOpcodes || (pTb->fFlags & IEMTB_F_CS_LIM_CHECKS));
     1217        if (pVCpu->iem.s.fTbCheckOpcodes)
     1218            pCall->enmFunction = pTb->fFlags & IEMTB_F_CS_LIM_CHECKS
     1219                               ? kIemThreadedFunc_CheckCsLimAndOpcodes
     1220                               : kIemThreadedFunc_CheckOpcodes;
     1221        else
     1222            pCall->enmFunction = kIemThreadedFunc_CheckCsLim;
     1223
     1224        iemThreadedCopyOpcodeBytesInline(pVCpu, &pTb->pabOpcodes[offOpcode], cbInstr);
     1225        pTb->cbOpcodes                    = offOpcode + cbInstr;
     1226        pTb->aRanges[idxRange].cbOpcodes += cbInstr;
     1227        Assert(pTb->cbOpcodes <= pTb->cbOpcodesAllocated);
     1228    }
     1229
     1230    /*
     1231     * Commit the call.
     1232     */
     1233    pTb->Thrd.cCalls++;
     1234
     1235    /*
     1236     * Clear state.
     1237     */
     1238    pVCpu->iem.s.fTbBranched     = false;
     1239    pVCpu->iem.s.fTbCrossedPage  = false;
     1240    pVCpu->iem.s.fTbCheckOpcodes = false;
     1241
     1242    /*
     1243     * Copy opcode bytes.
     1244     */
     1245    iemThreadedCopyOpcodeBytesInline(pVCpu, &pTb->pabOpcodes[offOpcode], cbInstr);
     1246    pTb->cbOpcodes = offOpcode + cbInstr;
     1247    Assert(pTb->cbOpcodes <= pTb->cbOpcodesAllocated);
     1248
     1249    return true;
     1250}
     1251
     1252
     1253
    9941254/**
    9951255 * Compiles a new TB and executes it.
     
    10451305            Assert(cCallsPrev - pTb->Thrd.cCalls < 5);
    10461306
    1047             memcpy(&pTb->pabOpcodes[pTb->cbOpcodes], pVCpu->iem.s.abOpcode, pVCpu->iem.s.offOpcode);
    1048             pTb->cbOpcodes += pVCpu->iem.s.offOpcode;
    1049             Assert(pTb->cbOpcodes <= pTb->cbOpcodesAllocated);
    10501307            pVCpu->iem.s.cInstructions++;
    10511308        }
    1052         else if (pTb->Thrd.cCalls > 0)
    1053         {
    1054             Log8(("%04x:%08RX64: End TB - %u calls, rc=%d\n", uCsLog, uRipLog, pTb->Thrd.cCalls, VBOXSTRICTRC_VAL(rcStrict)));
    1055 
    1056             if (cCallsPrev != pTb->Thrd.cCalls)
     1309        else
     1310        {
     1311            Log8(("%04x:%08RX64: End TB - %u instr, %u calls, rc=%d\n",
     1312                  uCsLog, uRipLog, pTb->cInstructions, pTb->Thrd.cCalls, VBOXSTRICTRC_VAL(rcStrict)));
     1313            if (rcStrict == VINF_IEM_RECOMPILE_END_TB)
     1314                rcStrict = VINF_SUCCESS;
     1315
     1316            if (pTb->Thrd.cCalls > 0)
    10571317            {
    1058                 memcpy(&pTb->pabOpcodes[pTb->cbOpcodes], pVCpu->iem.s.abOpcode, pVCpu->iem.s.offOpcode);
    1059                 pTb->cbOpcodes += pVCpu->iem.s.offOpcode;
    1060                 Assert(pTb->cbOpcodes <= pTb->cbOpcodesAllocated);
    1061                 pVCpu->iem.s.cInstructions++;
     1318                if (cCallsPrev != pTb->Thrd.cCalls)
     1319                    pVCpu->iem.s.cInstructions++;
     1320                break;
    10621321            }
    1063             break;
    1064         }
    1065         else
    1066         {
    1067             Log8(("%04x:%08RX64: End TB - 0 calls, rc=%d\n", uCsLog, uRipLog, VBOXSTRICTRC_VAL(rcStrict)));
     1322
    10681323            pVCpu->iem.s.pCurTbR3 = NULL;
    10691324            iemThreadedTbFree(pVM, pVCpu, pTb);
     
    10721327
    10731328        /* Still space in the TB? */
    1074         if (pTb->Thrd.cCalls + 5 < pTb->Thrd.cAllocated)
     1329        if (   pTb->Thrd.cCalls + 5 < pTb->Thrd.cAllocated
     1330            && pTb->cbOpcodes + 16 <= pTb->cbOpcodesAllocated)
    10751331            iemThreadedCompileInitDecoder(pVCpu, true /*fReInit*/);
    10761332        else
    10771333        {
    1078             Log8(("%04x:%08RX64: End TB - %u calls - full\n", uCsLog, uRipLog, pTb->Thrd.cCalls));
     1334            Log8(("%04x:%08RX64: End TB - %u instr, %u calls, %u opcode bytes - full\n",
     1335                  uCsLog, uRipLog, pTb->cInstructions, pTb->Thrd.cCalls, pTb->cbOpcodes));
    10791336            break;
    10801337        }
     
    11151372    else
    11161373    {
    1117         Log11(("TB obsolete: %p GCPhys=%RGp\n", pTb, pTb->GCPhysPc));
     1374        Log7(("TB obsolete: %p GCPhys=%RGp\n", pTb, pTb->GCPhysPc));
    11181375        iemThreadedTbFree(pVCpu->pVMR3, pVCpu, pTb);
    11191376        return VINF_SUCCESS;
  • trunk/src/VBox/VMM/include/IEMInternal.h

    r100672 r100694  
    3939
    4040#include <iprt/setjmp-without-sigmask.h>
     41#include <iprt/list.h>
    4142
    4243
     
    536537
    537538
    538 /** Pointer to a translation block. */
    539 typedef struct IEMTB *PIEMTB;
    540 
    541539/** @name IEM_F_XXX - Execution mode flags (IEMCPU::fExec, IEMTB::fFlags).
    542540 *
     
    720718AssertCompile(  IEM_F_MODE_X86_64BIT              & IEM_F_MODE_X86_PROT_MASK);
    721719AssertCompile(!(IEM_F_MODE_X86_64BIT              & IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK));
     720
     721/**
     722 * A call for the threaded call table.
     723 */
     724typedef struct IEMTHRDEDCALLENTRY
     725{
     726    /** The function to call (IEMTHREADEDFUNCS). */
     727    uint16_t    enmFunction;
     728    uint16_t    uUnused0;
     729
     730    /** Offset into IEMTB::pabOpcodes. */
     731    uint16_t    offOpcode;
     732    /** The opcode length. */
     733    uint8_t     cbOpcode;
     734    /** Index in to IEMTB::aRanges. */
     735    uint8_t     idxRange;
     736
     737    /** Generic parameters. */
     738    uint64_t    auParams[3];
     739} IEMTHRDEDCALLENTRY;
     740AssertCompileSize(IEMTHRDEDCALLENTRY, sizeof(uint64_t) * 4);
     741/** Pointer to a threaded call entry. */
     742typedef struct IEMTHRDEDCALLENTRY *PIEMTHRDEDCALLENTRY;
     743/** Pointer to a const threaded call entry. */
     744typedef IEMTHRDEDCALLENTRY const *PCIEMTHRDEDCALLENTRY;
     745
     746/**
     747 * Translation block.
     748 */
     749#pragma pack(2) /* to prevent the Thrd structure from being padded unnecessarily */
     750typedef struct IEMTB
     751{
     752    /** Next block with the same hash table entry. */
     753    struct IEMTB * volatile pNext;
     754    /** List on the local VCPU for blocks. */
     755    RTLISTNODE          LocalList;
     756
     757    /** @name What uniquely identifies the block.
     758     * @{ */
     759    RTGCPHYS            GCPhysPc;
     760    /** IEMTB_F_XXX (i.e. IEM_F_XXX ++). */
     761    uint32_t            fFlags;
     762    union
     763    {
     764        struct
     765        {
     766            /**< Relevant CS X86DESCATTR_XXX bits. */
     767            uint16_t    fAttr;
     768        } x86;
     769    };
     770    /** @} */
     771
     772    /** Number of opcode ranges. */
     773    uint8_t             cRanges;
     774    /** Statistics: Number of instructions in the block. */
     775    uint8_t             cInstructions;
     776
     777    /** Type specific info. */
     778    union
     779    {
     780        struct
     781        {
     782            /** The call sequence table. */
     783            PIEMTHRDEDCALLENTRY paCalls;
     784            /** Number of calls in paCalls. */
     785            uint16_t            cCalls;
     786            /** Number of calls allocated. */
     787            uint16_t            cAllocated;
     788        } Thrd;
     789    };
     790
     791    /** Number of bytes of opcodes stored in pabOpcodes. */
     792    uint16_t            cbOpcodes;
     793    /** The max storage available in the pabOpcodes block. */
     794    uint16_t            cbOpcodesAllocated;
     795    /** Pointer to the opcode bytes this block was recompiled from. */
     796    uint8_t            *pabOpcodes;
     797
     798    /* --- 64 byte cache line end --- */
     799
     800    /** Opcode ranges.
     801     *
     802     * The opcode checkers and maybe TLB loading functions will use this to figure
     803     * out what to do.  The parameter will specify an entry and the opcode offset to
     804     * start at and the minimum number of bytes to verify (instruction length).
     805     *
     806     * When VT-x and AMD-V looks up the opcode bytes for an exitting instruction,
     807     * they'll first translate RIP (+ cbInstr - 1) to a physical address using the
     808     * code TLB (must have a valid entry for that address) and scan the ranges to
     809     * locate the corresponding opcodes. Probably.
     810     */
     811    struct IEMTBOPCODERANGE
     812    {
     813        /** Offset within pabOpcodes. */
     814        uint16_t        offOpcodes;
     815        /** Number of bytes. */
     816        uint16_t        cbOpcodes;
     817        /** The page offset. */
     818        RT_GCC_EXTENSION
     819        uint16_t        offPhysPage : 12;
     820        /** Unused bits. */
     821        RT_GCC_EXTENSION
     822        uint16_t        u2Unused    :  2;
     823        /** Index into GCPhysPc + aGCPhysPages for the physical page address. */
     824        RT_GCC_EXTENSION
     825        uint16_t        idxPhysPage :  2;
     826    } aRanges[8];
     827
     828    /** Physical pages that this TB covers.
     829     * The GCPhysPc w/o page offset is element zero, so starting here with 1. */
     830    RTGCPHYS            aGCPhysPages[2];
     831} IEMTB;
     832#pragma pack()
     833AssertCompileMemberOffset(IEMTB, x86, 36);
     834AssertCompileMemberOffset(IEMTB, cRanges, 38);
     835AssertCompileMemberOffset(IEMTB, Thrd, 40);
     836AssertCompileMemberOffset(IEMTB, Thrd.cCalls, 48);
     837AssertCompileMemberOffset(IEMTB, cbOpcodes, 52);
     838AssertCompileMemberSize(IEMTB, aRanges[0], 6);
     839AssertCompileSize(IEMTB, 128);
     840/** Pointer to a translation block. */
     841typedef IEMTB *PIEMTB;
     842/** Pointer to a const translation block. */
     843typedef IEMTB const *PCIEMTB;
    722844
    723845
     
    10141136    /** Number of TBs executed. */
    10151137    uint64_t                cTbExec;
     1138    /** Whether we need to check the opcode bytes for the current instruction.
     1139     * This is set by a previous instruction if it modified memory or similar.  */
     1140    bool                    fTbCheckOpcodes;
     1141    /** Whether we just branched and need to start a new opcode range and emit code
     1142     * to do a TLB load and check them again. */
     1143    bool                    fTbBranched;
     1144    /** Set when GCPhysInstrBuf is updated because of a page crossing. */
     1145    bool                    fTbCrossedPage;
    10161146    /** Whether to end the current TB. */
    10171147    bool                    fEndTb;
    10181148    /** Spaced reserved for recompiler data / alignment. */
    1019     bool                    afRecompilerStuff1[7];
     1149    bool                    afRecompilerStuff1[4];
    10201150    /** @} */
    10211151
     
    47644894IEM_CIMPL_PROTO_1(iemCImpl_Hypercall, uint16_t, uDisOpcode); /* both */
    47654895
     4896void            iemThreadedTbObsolete(PVMCPUCC pVCpu, PIEMTB pTb);
     4897IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckMode,
     4898                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4899IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLim,
     4900                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4901IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodes,
     4902                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4903IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodesAcrossPageLoadingTlb,
     4904                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4905IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodesLoadingTlb,
     4906                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4907IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckCsLimAndOpcodesOnNextPageLoadingTlb,
     4908                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4909IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodes,
     4910                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4911IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodesAcrossPageLoadingTlb,
     4912                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4913IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodesLoadingTlb,
     4914                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4915IEM_DECL_IMPL_PROTO(VBOXSTRICTRC, iemThreadedFunc_BltIn_CheckOpcodesOnNextPageLoadingTlb,
     4916                    (PVMCPU pVCpu, uint64_t uParam0, uint64_t uParam1, uint64_t uParam2));
     4917
    47664918
    47674919extern const PFNIEMOP g_apfnIemInterpretOnlyOneByteMap[256];
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette