Changeset 108226 in vbox for trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllMem-x86.cpp
- Timestamp:
- Feb 14, 2025 3:54:48 PM (4 weeks ago)
- svn:sync-xref-src-repo-rev:
- 167546
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllMem-x86.cpp
r108220 r108226 1 1 /* $Id$ */ 2 2 /** @file 3 * IEM - Interpreted Execution Manager - All Contexts.3 * IEM - Interpreted Execution Manager - x86 target, memory. 4 4 */ 5 5 … … 27 27 28 28 29 /** @page pg_iem IEM - Interpreted Execution Manager30 *31 * The interpreted exeuction manager (IEM) is for executing short guest code32 * sequences that are causing too many exits / virtualization traps. It will33 * also be used to interpret single instructions, thus replacing the selective34 * interpreters in EM and IOM.35 *36 * Design goals:37 * - Relatively small footprint, although we favour speed and correctness38 * over size.39 * - Reasonably fast.40 * - Correctly handle lock prefixed instructions.41 * - Complete instruction set - eventually.42 * - Refactorable into a recompiler, maybe.43 * - Replace EMInterpret*.44 *45 * Using the existing disassembler has been considered, however this is thought46 * to conflict with speed as the disassembler chews things a bit too much while47 * leaving us with a somewhat complicated state to interpret afterwards.48 *49 *50 * The current code is very much work in progress. You've been warned!51 *52 *53 * @section sec_iem_fpu_instr FPU Instructions54 *55 * On x86 and AMD64 hosts, the FPU instructions are implemented by executing the56 * same or equivalent instructions on the host FPU. To make life easy, we also57 * let the FPU prioritize the unmasked exceptions for us. This however, only58 * works reliably when CR0.NE is set, i.e. when using \#MF instead the IRQ 1359 * for FPU exception delivery, because with CR0.NE=0 there is a window where we60 * can trigger spurious FPU exceptions.61 *62 * The guest FPU state is not loaded into the host CPU and kept there till we63 * leave IEM because the calling conventions have declared an all year open64 * season on much of the FPU state. For instance an innocent looking call to65 * memcpy might end up using a whole bunch of XMM or MM registers if the66 * particular implementation finds it worthwhile.67 *68 *69 * @section sec_iem_logging Logging70 *71 * The IEM code uses the \"IEM\" log group for the main logging. The different72 * logging levels/flags are generally used for the following purposes:73 * - Level 1 (Log) : Errors, exceptions, interrupts and such major events.74 * - Flow (LogFlow) : Basic enter/exit IEM state info.75 * - Level 2 (Log2) : ?76 * - Level 3 (Log3) : More detailed enter/exit IEM state info.77 * - Level 4 (Log4) : Decoding mnemonics w/ EIP.78 * - Level 5 (Log5) : Decoding details.79 * - Level 6 (Log6) : Enables/disables the lockstep comparison with REM.80 * - Level 7 (Log7) : iret++ execution logging.81 * - Level 8 (Log8) :82 * - Level 9 (Log9) :83 * - Level 10 (Log10): TLBs.84 * - Level 11 (Log11): Unmasked FPU exceptions.85 *86 * The \"IEM_MEM\" log group covers most of memory related details logging,87 * except for errors and exceptions:88 * - Level 1 (Log) : Reads.89 * - Level 2 (Log2) : Read fallbacks.90 * - Level 3 (Log3) : MemMap read.91 * - Level 4 (Log4) : MemMap read fallbacks.92 * - Level 5 (Log5) : Writes93 * - Level 6 (Log6) : Write fallbacks.94 * - Level 7 (Log7) : MemMap writes and read-writes.95 * - Level 8 (Log8) : MemMap write and read-write fallbacks.96 * - Level 9 (Log9) : Stack reads.97 * - Level 10 (Log10): Stack read fallbacks.98 * - Level 11 (Log11): Stack writes.99 * - Level 12 (Log12): Stack write fallbacks.100 * - Flow (LogFlow) :101 *102 * The SVM (AMD-V) and VMX (VT-x) code has the following assignments:103 * - Level 1 (Log) : Errors and other major events.104 * - Flow (LogFlow) : Misc flow stuff (cleanup?)105 * - Level 2 (Log2) : VM exits.106 *107 * The syscall logging level assignments:108 * - Level 1: DOS and BIOS.109 * - Level 2: Windows 3.x110 * - Level 3: Linux.111 */112 113 /* Disabled warning C4505: 'iemRaisePageFaultJmp' : unreferenced local function has been removed */114 #ifdef _MSC_VER115 # pragma warning(disable:4505)116 #endif117 118 119 29 /********************************************************************************************************************************* 120 30 * Header Files * 121 31 *********************************************************************************************************************************/ 122 #define LOG_GROUP LOG_GROUP_IEM32 #define LOG_GROUP LOG_GROUP_IEM_MEM 123 33 #define VMCPU_INCL_CPUM_GST_CTX 124 34 #ifdef IN_RING0 … … 127 37 #include <VBox/vmm/iem.h> 128 38 #include <VBox/vmm/cpum.h> 129 #include <VBox/vmm/pdmapic.h>130 #include <VBox/vmm/pdm.h>131 39 #include <VBox/vmm/pgm.h> 132 #include <VBox/vmm/iom.h>133 #include <VBox/vmm/em.h>134 #include <VBox/vmm/hm.h>135 #include <VBox/vmm/nem.h>136 #include <VBox/vmm/gcm.h>137 #include <VBox/vmm/gim.h>138 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM139 # include <VBox/vmm/em.h>140 # include <VBox/vmm/hm_svm.h>141 #endif142 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX143 # include <VBox/vmm/hmvmxinline.h>144 #endif145 #include <VBox/vmm/tm.h>146 40 #include <VBox/vmm/dbgf.h> 147 #include <VBox/vmm/dbgftrace.h>148 41 #include "IEMInternal.h" 149 42 #include <VBox/vmm/vmcc.h> 150 43 #include <VBox/log.h> 151 44 #include <VBox/err.h> 152 #include <VBox/param.h>153 #include <VBox/dis.h>154 #include <iprt/asm-math.h>155 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)156 # include <iprt/asm-amd64-x86.h>157 #elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)158 # include <iprt/asm-arm.h>159 #endif160 45 #include <iprt/assert.h> 161 46 #include <iprt/string.h> … … 163 48 164 49 #include "IEMInline.h" 165 166 167 /********************************************************************************************************************************* 168 * Structures and Typedefs * 169 *********************************************************************************************************************************/ 170 /** 171 * CPU exception classes. 172 */ 173 typedef enum IEMXCPTCLASS 174 { 175 IEMXCPTCLASS_BENIGN, 176 IEMXCPTCLASS_CONTRIBUTORY, 177 IEMXCPTCLASS_PAGE_FAULT, 178 IEMXCPTCLASS_DOUBLE_FAULT 179 } IEMXCPTCLASS; 180 181 182 /********************************************************************************************************************************* 183 * Global Variables * 184 *********************************************************************************************************************************/ 185 #if defined(IEM_LOG_MEMORY_WRITES) 186 /** What IEM just wrote. */ 187 uint8_t g_abIemWrote[256]; 188 /** How much IEM just wrote. */ 189 size_t g_cbIemWrote; 190 #endif 191 192 193 /** 194 * Calculates IEM_F_BRK_PENDING_XXX (IEM_F_PENDING_BRK_MASK) flags, slow code 195 * path. 196 * 197 * This will also invalidate TLB entries for any pages with active data 198 * breakpoints on them. 199 * 200 * @returns IEM_F_BRK_PENDING_XXX or zero. 201 * @param pVCpu The cross context virtual CPU structure of the 202 * calling thread. 203 * 204 * @note Don't call directly, use iemCalcExecDbgFlags instead. 205 */ 206 uint32_t iemCalcExecDbgFlagsSlow(PVMCPUCC pVCpu) 207 { 208 uint32_t fExec = 0; 209 210 /* 211 * Helper for invalidate the data TLB for breakpoint addresses. 212 * 213 * This is to make sure any access to the page will always trigger a TLB 214 * load for as long as the breakpoint is enabled. 215 */ 216 #ifdef IEM_WITH_DATA_TLB 217 # define INVALID_TLB_ENTRY_FOR_BP(a_uValue) do { \ 218 RTGCPTR uTagNoRev = (a_uValue); \ 219 uTagNoRev = IEMTLB_CALC_TAG_NO_REV(uTagNoRev); \ 220 /** @todo do large page accounting */ \ 221 uintptr_t const idxEven = IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev); \ 222 if (pVCpu->iem.s.DataTlb.aEntries[idxEven].uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevision)) \ 223 pVCpu->iem.s.DataTlb.aEntries[idxEven].uTag = 0; \ 224 if (pVCpu->iem.s.DataTlb.aEntries[idxEven + 1].uTag == (uTagNoRev | pVCpu->iem.s.DataTlb.uTlbRevisionGlobal)) \ 225 pVCpu->iem.s.DataTlb.aEntries[idxEven + 1].uTag = 0; \ 226 } while (0) 227 #else 228 # define INVALID_TLB_ENTRY_FOR_BP(a_uValue) do { } while (0) 229 #endif 230 231 /* 232 * Process guest breakpoints. 233 */ 234 #define PROCESS_ONE_BP(a_fDr7, a_iBp, a_uValue) do { \ 235 if (a_fDr7 & X86_DR7_L_G(a_iBp)) \ 236 { \ 237 switch (X86_DR7_GET_RW(a_fDr7, a_iBp)) \ 238 { \ 239 case X86_DR7_RW_EO: \ 240 fExec |= IEM_F_PENDING_BRK_INSTR; \ 241 break; \ 242 case X86_DR7_RW_WO: \ 243 case X86_DR7_RW_RW: \ 244 fExec |= IEM_F_PENDING_BRK_DATA; \ 245 INVALID_TLB_ENTRY_FOR_BP(a_uValue); \ 246 break; \ 247 case X86_DR7_RW_IO: \ 248 fExec |= IEM_F_PENDING_BRK_X86_IO; \ 249 break; \ 250 } \ 251 } \ 252 } while (0) 253 254 uint32_t const fGstDr7 = (uint32_t)pVCpu->cpum.GstCtx.dr[7]; 255 if (fGstDr7 & X86_DR7_ENABLED_MASK) 256 { 257 /** @todo extract more details here to simplify matching later. */ 258 #ifdef IEM_WITH_DATA_TLB 259 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_DR0_DR3); 260 #endif 261 PROCESS_ONE_BP(fGstDr7, 0, pVCpu->cpum.GstCtx.dr[0]); 262 PROCESS_ONE_BP(fGstDr7, 1, pVCpu->cpum.GstCtx.dr[1]); 263 PROCESS_ONE_BP(fGstDr7, 2, pVCpu->cpum.GstCtx.dr[2]); 264 PROCESS_ONE_BP(fGstDr7, 3, pVCpu->cpum.GstCtx.dr[3]); 265 } 266 267 /* 268 * Process hypervisor breakpoints. 269 */ 270 PVMCC const pVM = pVCpu->CTX_SUFF(pVM); 271 uint32_t const fHyperDr7 = DBGFBpGetDR7(pVM); 272 if (fHyperDr7 & X86_DR7_ENABLED_MASK) 273 { 274 /** @todo extract more details here to simplify matching later. */ 275 PROCESS_ONE_BP(fHyperDr7, 0, DBGFBpGetDR0(pVM)); 276 PROCESS_ONE_BP(fHyperDr7, 1, DBGFBpGetDR1(pVM)); 277 PROCESS_ONE_BP(fHyperDr7, 2, DBGFBpGetDR2(pVM)); 278 PROCESS_ONE_BP(fHyperDr7, 3, DBGFBpGetDR3(pVM)); 279 } 280 281 return fExec; 282 } 283 284 285 /** 286 * Initializes the decoder state. 287 * 288 * iemReInitDecoder is mostly a copy of this function. 289 * 290 * @param pVCpu The cross context virtual CPU structure of the 291 * calling thread. 292 * @param fExecOpts Optional execution flags: 293 * - IEM_F_BYPASS_HANDLERS 294 * - IEM_F_X86_DISREGARD_LOCK 295 */ 296 DECLINLINE(void) iemInitDecoder(PVMCPUCC pVCpu, uint32_t fExecOpts) 297 { 298 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_MUST_MASK); 299 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IEM)); 300 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs)); 301 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss)); 302 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.es)); 303 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ds)); 304 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.fs)); 305 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.gs)); 306 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ldtr)); 307 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.tr)); 308 309 /* Execution state: */ 310 uint32_t fExec; 311 pVCpu->iem.s.fExec = fExec = iemCalcExecFlags(pVCpu) | fExecOpts; 312 313 /* Decoder state: */ 314 pVCpu->iem.s.enmDefAddrMode = fExec & IEM_F_MODE_CPUMODE_MASK; /** @todo check if this is correct... */ 315 pVCpu->iem.s.enmEffAddrMode = fExec & IEM_F_MODE_CPUMODE_MASK; 316 if ((fExec & IEM_F_MODE_CPUMODE_MASK) != IEMMODE_64BIT) 317 { 318 pVCpu->iem.s.enmDefOpSize = fExec & IEM_F_MODE_CPUMODE_MASK; /** @todo check if this is correct... */ 319 pVCpu->iem.s.enmEffOpSize = fExec & IEM_F_MODE_CPUMODE_MASK; 320 } 321 else 322 { 323 pVCpu->iem.s.enmDefOpSize = IEMMODE_32BIT; 324 pVCpu->iem.s.enmEffOpSize = IEMMODE_32BIT; 325 } 326 pVCpu->iem.s.fPrefixes = 0; 327 pVCpu->iem.s.uRexReg = 0; 328 pVCpu->iem.s.uRexB = 0; 329 pVCpu->iem.s.uRexIndex = 0; 330 pVCpu->iem.s.idxPrefix = 0; 331 pVCpu->iem.s.uVex3rdReg = 0; 332 pVCpu->iem.s.uVexLength = 0; 333 pVCpu->iem.s.fEvexStuff = 0; 334 pVCpu->iem.s.iEffSeg = X86_SREG_DS; 335 #ifdef IEM_WITH_CODE_TLB 336 pVCpu->iem.s.pbInstrBuf = NULL; 337 pVCpu->iem.s.offInstrNextByte = 0; 338 pVCpu->iem.s.offCurInstrStart = 0; 339 # ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF 340 pVCpu->iem.s.offOpcode = 0; 341 # endif 342 # ifdef VBOX_STRICT 343 pVCpu->iem.s.GCPhysInstrBuf = NIL_RTGCPHYS; 344 pVCpu->iem.s.cbInstrBuf = UINT16_MAX; 345 pVCpu->iem.s.cbInstrBufTotal = UINT16_MAX; 346 pVCpu->iem.s.uInstrBufPc = UINT64_C(0xc0ffc0ffcff0c0ff); 347 # endif 348 #else 349 pVCpu->iem.s.offOpcode = 0; 350 pVCpu->iem.s.cbOpcode = 0; 351 #endif 352 pVCpu->iem.s.offModRm = 0; 353 pVCpu->iem.s.cActiveMappings = 0; 354 pVCpu->iem.s.iNextMapping = 0; 355 pVCpu->iem.s.rcPassUp = VINF_SUCCESS; 356 357 #ifdef DBGFTRACE_ENABLED 358 switch (IEM_GET_CPU_MODE(pVCpu)) 359 { 360 case IEMMODE_64BIT: 361 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I64/%u %08llx", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.rip); 362 break; 363 case IEMMODE_32BIT: 364 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I32/%u %04x:%08x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip); 365 break; 366 case IEMMODE_16BIT: 367 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I16/%u %04x:%04x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip); 368 break; 369 } 370 #endif 371 } 372 373 374 /** 375 * Reinitializes the decoder state 2nd+ loop of IEMExecLots. 376 * 377 * This is mostly a copy of iemInitDecoder. 378 * 379 * @param pVCpu The cross context virtual CPU structure of the calling EMT. 380 */ 381 DECLINLINE(void) iemReInitDecoder(PVMCPUCC pVCpu) 382 { 383 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IEM)); 384 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs)); 385 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss)); 386 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.es)); 387 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ds)); 388 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.fs)); 389 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.gs)); 390 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ldtr)); 391 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.tr)); 392 393 /* ASSUMES: Anyone changing CPU state affecting the fExec bits will update them! */ 394 AssertMsg((pVCpu->iem.s.fExec & ~IEM_F_USER_OPTS) == iemCalcExecFlags(pVCpu), 395 ("fExec=%#x iemCalcExecModeFlags=%#x\n", pVCpu->iem.s.fExec, iemCalcExecFlags(pVCpu))); 396 397 IEMMODE const enmMode = IEM_GET_CPU_MODE(pVCpu); 398 pVCpu->iem.s.enmDefAddrMode = enmMode; /** @todo check if this is correct... */ 399 pVCpu->iem.s.enmEffAddrMode = enmMode; 400 if (enmMode != IEMMODE_64BIT) 401 { 402 pVCpu->iem.s.enmDefOpSize = enmMode; /** @todo check if this is correct... */ 403 pVCpu->iem.s.enmEffOpSize = enmMode; 404 } 405 else 406 { 407 pVCpu->iem.s.enmDefOpSize = IEMMODE_32BIT; 408 pVCpu->iem.s.enmEffOpSize = IEMMODE_32BIT; 409 } 410 pVCpu->iem.s.fPrefixes = 0; 411 pVCpu->iem.s.uRexReg = 0; 412 pVCpu->iem.s.uRexB = 0; 413 pVCpu->iem.s.uRexIndex = 0; 414 pVCpu->iem.s.idxPrefix = 0; 415 pVCpu->iem.s.uVex3rdReg = 0; 416 pVCpu->iem.s.uVexLength = 0; 417 pVCpu->iem.s.fEvexStuff = 0; 418 pVCpu->iem.s.iEffSeg = X86_SREG_DS; 419 #ifdef IEM_WITH_CODE_TLB 420 if (pVCpu->iem.s.pbInstrBuf) 421 { 422 uint64_t off = (enmMode == IEMMODE_64BIT 423 ? pVCpu->cpum.GstCtx.rip 424 : pVCpu->cpum.GstCtx.eip + (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base) 425 - pVCpu->iem.s.uInstrBufPc; 426 if (off < pVCpu->iem.s.cbInstrBufTotal) 427 { 428 pVCpu->iem.s.offInstrNextByte = (uint32_t)off; 429 pVCpu->iem.s.offCurInstrStart = (uint16_t)off; 430 if ((uint16_t)off + 15 <= pVCpu->iem.s.cbInstrBufTotal) 431 pVCpu->iem.s.cbInstrBuf = (uint16_t)off + 15; 432 else 433 pVCpu->iem.s.cbInstrBuf = pVCpu->iem.s.cbInstrBufTotal; 434 } 435 else 436 { 437 pVCpu->iem.s.pbInstrBuf = NULL; 438 pVCpu->iem.s.offInstrNextByte = 0; 439 pVCpu->iem.s.offCurInstrStart = 0; 440 pVCpu->iem.s.cbInstrBuf = 0; 441 pVCpu->iem.s.cbInstrBufTotal = 0; 442 pVCpu->iem.s.GCPhysInstrBuf = NIL_RTGCPHYS; 443 } 444 } 445 else 446 { 447 pVCpu->iem.s.offInstrNextByte = 0; 448 pVCpu->iem.s.offCurInstrStart = 0; 449 pVCpu->iem.s.cbInstrBuf = 0; 450 pVCpu->iem.s.cbInstrBufTotal = 0; 451 # ifdef VBOX_STRICT 452 pVCpu->iem.s.GCPhysInstrBuf = NIL_RTGCPHYS; 453 # endif 454 } 455 # ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF 456 pVCpu->iem.s.offOpcode = 0; 457 # endif 458 #else /* !IEM_WITH_CODE_TLB */ 459 pVCpu->iem.s.cbOpcode = 0; 460 pVCpu->iem.s.offOpcode = 0; 461 #endif /* !IEM_WITH_CODE_TLB */ 462 pVCpu->iem.s.offModRm = 0; 463 Assert(pVCpu->iem.s.cActiveMappings == 0); 464 pVCpu->iem.s.iNextMapping = 0; 465 Assert(pVCpu->iem.s.rcPassUp == VINF_SUCCESS); 466 Assert(!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS)); 467 468 #ifdef DBGFTRACE_ENABLED 469 switch (enmMode) 470 { 471 case IEMMODE_64BIT: 472 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I64/%u %08llx", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.rip); 473 break; 474 case IEMMODE_32BIT: 475 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I32/%u %04x:%08x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip); 476 break; 477 case IEMMODE_16BIT: 478 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "I16/%u %04x:%04x", IEM_GET_CPL(pVCpu), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip); 479 break; 480 } 481 #endif 482 } 483 484 485 486 /** 487 * Prefetch opcodes the first time when starting executing. 488 * 489 * @returns Strict VBox status code. 490 * @param pVCpu The cross context virtual CPU structure of the 491 * calling thread. 492 * @param fExecOpts Optional execution flags: 493 * - IEM_F_BYPASS_HANDLERS 494 * - IEM_F_X86_DISREGARD_LOCK 495 */ 496 static VBOXSTRICTRC iemInitDecoderAndPrefetchOpcodes(PVMCPUCC pVCpu, uint32_t fExecOpts) RT_NOEXCEPT 497 { 498 iemInitDecoder(pVCpu, fExecOpts); 499 500 #ifndef IEM_WITH_CODE_TLB 501 /* 502 * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap. 503 * 504 * First translate CS:rIP to a physical address. 505 * 506 * Note! The iemOpcodeFetchMoreBytes code depends on this here code to fetch 507 * all relevant bytes from the first page, as it ASSUMES it's only ever 508 * called for dealing with CS.LIM, page crossing and instructions that 509 * are too long. 510 */ 511 uint32_t cbToTryRead; 512 RTGCPTR GCPtrPC; 513 if (IEM_IS_64BIT_CODE(pVCpu)) 514 { 515 cbToTryRead = GUEST_PAGE_SIZE; 516 GCPtrPC = pVCpu->cpum.GstCtx.rip; 517 if (IEM_IS_CANONICAL(GCPtrPC)) 518 cbToTryRead = GUEST_PAGE_SIZE - (GCPtrPC & GUEST_PAGE_OFFSET_MASK); 519 else 520 return iemRaiseGeneralProtectionFault0(pVCpu); 521 } 522 else 523 { 524 uint32_t GCPtrPC32 = pVCpu->cpum.GstCtx.eip; 525 AssertMsg(!(GCPtrPC32 & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu), ("%04x:%RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip)); 526 if (GCPtrPC32 <= pVCpu->cpum.GstCtx.cs.u32Limit) 527 cbToTryRead = pVCpu->cpum.GstCtx.cs.u32Limit - GCPtrPC32 + 1; 528 else 529 return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION); 530 if (cbToTryRead) { /* likely */ } 531 else /* overflowed */ 532 { 533 Assert(GCPtrPC32 == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX); 534 cbToTryRead = UINT32_MAX; 535 } 536 GCPtrPC = (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base + GCPtrPC32; 537 Assert(GCPtrPC <= UINT32_MAX); 538 } 539 540 PGMPTWALKFAST WalkFast; 541 int rc = PGMGstQueryPageFast(pVCpu, GCPtrPC, 542 IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE, 543 &WalkFast); 544 if (RT_SUCCESS(rc)) 545 Assert(WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED); 546 else 547 { 548 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - rc=%Rrc\n", GCPtrPC, rc)); 549 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT 550 /** @todo This isn't quite right yet, as PGM_GST_SLAT_NAME_EPT(Walk) doesn't 551 * know about what kind of access we're making! See PGM_GST_NAME(WalkFast). */ 552 if (WalkFast.fFailed & PGM_WALKFAIL_EPT) 553 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */); 554 # endif 555 return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, rc); 556 } 557 #if 0 558 if ((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3) { /* likely */ } 559 else 560 { 561 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - supervisor page\n", GCPtrPC)); 562 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT 563 /** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/ 564 # error completely wrong 565 if (WalkFast.fFailed & PGM_WALKFAIL_EPT) 566 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */); 567 # endif 568 return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED); 569 } 570 if (!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)) { /* likely */ } 571 else 572 { 573 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - NX\n", GCPtrPC)); 574 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT 575 /** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/ 576 # error completely wrong. 577 if (WalkFast.fFailed & PGM_WALKFAIL_EPT) 578 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */); 579 # endif 580 return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED); 581 } 582 #else 583 Assert((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3); 584 Assert(!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)); 585 #endif 586 RTGCPHYS const GCPhys = WalkFast.GCPhys; 587 588 /* 589 * Read the bytes at this address. 590 */ 591 uint32_t cbLeftOnPage = GUEST_PAGE_SIZE - (GCPtrPC & GUEST_PAGE_OFFSET_MASK); 592 if (cbToTryRead > cbLeftOnPage) 593 cbToTryRead = cbLeftOnPage; 594 if (cbToTryRead > sizeof(pVCpu->iem.s.abOpcode)) 595 cbToTryRead = sizeof(pVCpu->iem.s.abOpcode); 596 597 if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS)) 598 { 599 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhys, pVCpu->iem.s.abOpcode, cbToTryRead, PGMACCESSORIGIN_IEM); 600 if (RT_LIKELY(rcStrict == VINF_SUCCESS)) 601 { /* likely */ } 602 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict)) 603 { 604 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n", 605 GCPtrPC, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead)); 606 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict); 607 } 608 else 609 { 610 Log((RT_SUCCESS(rcStrict) 611 ? "iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n" 612 : "iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n", 613 GCPtrPC, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead)); 614 return rcStrict; 615 } 616 } 617 else 618 { 619 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pVCpu->iem.s.abOpcode, GCPhys, cbToTryRead); 620 if (RT_SUCCESS(rc)) 621 { /* likely */ } 622 else 623 { 624 Log(("iemInitDecoderAndPrefetchOpcodes: %RGv/%RGp LB %#x - read error - rc=%Rrc (!!)\n", 625 GCPtrPC, GCPhys, rc, cbToTryRead)); 626 return rc; 627 } 628 } 629 pVCpu->iem.s.cbOpcode = cbToTryRead; 630 #endif /* !IEM_WITH_CODE_TLB */ 631 return VINF_SUCCESS; 632 } 633 634 635 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 636 /** 637 * Helper for doing large page accounting at TLB load time. 638 */ 639 template<bool const a_fGlobal> 640 DECL_FORCE_INLINE(void) iemTlbLoadedLargePage(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR uTagNoRev, bool f2MbLargePages) 641 { 642 if (a_fGlobal) 643 pTlb->cTlbGlobalLargePageCurLoads++; 644 else 645 pTlb->cTlbNonGlobalLargePageCurLoads++; 646 647 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP 648 RTGCPTR const idxBit = IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + a_fGlobal; 649 ASMBitSet(pTlb->bmLargePage, idxBit); 650 # endif 651 652 AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U); 653 uint32_t const fMask = (f2MbLargePages ? _2M - 1U : _4M - 1U) >> GUEST_PAGE_SHIFT; 654 IEMTLB::LARGEPAGERANGE * const pRange = a_fGlobal 655 ? &pTlb->GlobalLargePageRange 656 : &pTlb->NonGlobalLargePageRange; 657 uTagNoRev &= ~(RTGCPTR)fMask; 658 if (uTagNoRev < pRange->uFirstTag) 659 pRange->uFirstTag = uTagNoRev; 660 661 uTagNoRev |= fMask; 662 if (uTagNoRev > pRange->uLastTag) 663 pRange->uLastTag = uTagNoRev; 664 665 RT_NOREF_PV(pVCpu); 666 } 667 #endif 668 669 670 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 671 /** 672 * Worker for iemTlbInvalidateAll. 673 */ 674 template<bool a_fGlobal> 675 DECL_FORCE_INLINE(void) iemTlbInvalidateOne(IEMTLB *pTlb) 676 { 677 if (!a_fGlobal) 678 pTlb->cTlsFlushes++; 679 else 680 pTlb->cTlsGlobalFlushes++; 681 682 pTlb->uTlbRevision += IEMTLB_REVISION_INCR; 683 if (RT_LIKELY(pTlb->uTlbRevision != 0)) 684 { /* very likely */ } 685 else 686 { 687 pTlb->uTlbRevision = IEMTLB_REVISION_INCR; 688 pTlb->cTlbRevisionRollovers++; 689 unsigned i = RT_ELEMENTS(pTlb->aEntries) / 2; 690 while (i-- > 0) 691 pTlb->aEntries[i * 2].uTag = 0; 692 } 693 694 pTlb->cTlbNonGlobalLargePageCurLoads = 0; 695 pTlb->NonGlobalLargePageRange.uLastTag = 0; 696 pTlb->NonGlobalLargePageRange.uFirstTag = UINT64_MAX; 697 698 if (a_fGlobal) 699 { 700 pTlb->uTlbRevisionGlobal += IEMTLB_REVISION_INCR; 701 if (RT_LIKELY(pTlb->uTlbRevisionGlobal != 0)) 702 { /* very likely */ } 703 else 704 { 705 pTlb->uTlbRevisionGlobal = IEMTLB_REVISION_INCR; 706 pTlb->cTlbRevisionRollovers++; 707 unsigned i = RT_ELEMENTS(pTlb->aEntries) / 2; 708 while (i-- > 0) 709 pTlb->aEntries[i * 2 + 1].uTag = 0; 710 } 711 712 pTlb->cTlbGlobalLargePageCurLoads = 0; 713 pTlb->GlobalLargePageRange.uLastTag = 0; 714 pTlb->GlobalLargePageRange.uFirstTag = UINT64_MAX; 715 } 716 } 717 #endif 718 719 720 /** 721 * Worker for IEMTlbInvalidateAll and IEMTlbInvalidateAllGlobal. 722 */ 723 template<bool a_fGlobal> 724 DECL_FORCE_INLINE(void) iemTlbInvalidateAll(PVMCPUCC pVCpu) 725 { 726 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 727 Log10(("IEMTlbInvalidateAll\n")); 728 729 # ifdef IEM_WITH_CODE_TLB 730 pVCpu->iem.s.cbInstrBufTotal = 0; 731 iemTlbInvalidateOne<a_fGlobal>(&pVCpu->iem.s.CodeTlb); 732 if (a_fGlobal) 733 IEMTLBTRACE_FLUSH_GLOBAL(pVCpu, pVCpu->iem.s.CodeTlb.uTlbRevision, pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal, false); 734 else 735 IEMTLBTRACE_FLUSH(pVCpu, pVCpu->iem.s.CodeTlb.uTlbRevision, false); 736 # endif 737 738 # ifdef IEM_WITH_DATA_TLB 739 iemTlbInvalidateOne<a_fGlobal>(&pVCpu->iem.s.DataTlb); 740 if (a_fGlobal) 741 IEMTLBTRACE_FLUSH_GLOBAL(pVCpu, pVCpu->iem.s.DataTlb.uTlbRevision, pVCpu->iem.s.DataTlb.uTlbRevisionGlobal, true); 742 else 743 IEMTLBTRACE_FLUSH(pVCpu, pVCpu->iem.s.DataTlb.uTlbRevision, true); 744 # endif 745 #else 746 RT_NOREF(pVCpu); 747 #endif 748 } 749 750 751 /** 752 * Invalidates non-global the IEM TLB entries. 753 * 754 * This is called internally as well as by PGM when moving GC mappings. 755 * 756 * @param pVCpu The cross context virtual CPU structure of the calling 757 * thread. 758 */ 759 VMM_INT_DECL(void) IEMTlbInvalidateAll(PVMCPUCC pVCpu) 760 { 761 iemTlbInvalidateAll<false>(pVCpu); 762 } 763 764 765 /** 766 * Invalidates all the IEM TLB entries. 767 * 768 * This is called internally as well as by PGM when moving GC mappings. 769 * 770 * @param pVCpu The cross context virtual CPU structure of the calling 771 * thread. 772 */ 773 VMM_INT_DECL(void) IEMTlbInvalidateAllGlobal(PVMCPUCC pVCpu) 774 { 775 iemTlbInvalidateAll<true>(pVCpu); 776 } 777 778 779 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 780 781 /** @todo graduate this to cdefs.h or asm-mem.h. */ 782 # ifdef RT_ARCH_ARM64 /** @todo RT_CACHELINE_SIZE is wrong for M1 */ 783 # undef RT_CACHELINE_SIZE 784 # define RT_CACHELINE_SIZE 128 785 # endif 786 787 # if defined(_MM_HINT_T0) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) 788 # define MY_PREFETCH(a_pvAddr) _mm_prefetch((const char *)(a_pvAddr), _MM_HINT_T0) 789 # elif defined(_MSC_VER) && (defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)) 790 # define MY_PREFETCH(a_pvAddr) __prefetch((a_pvAddr)) 791 # elif defined(__GNUC__) || RT_CLANG_HAS_FEATURE(__builtin_prefetch) 792 # define MY_PREFETCH(a_pvAddr) __builtin_prefetch((a_pvAddr), 0 /*rw*/, 3 /*locality*/) 793 # else 794 # define MY_PREFETCH(a_pvAddr) ((void)0) 795 # endif 796 # if 0 797 # undef MY_PREFETCH 798 # define MY_PREFETCH(a_pvAddr) ((void)0) 799 # endif 800 801 /** @def MY_PREFETCH_64 802 * 64 byte prefetch hint, could be more depending on cache line size. */ 803 /** @def MY_PREFETCH_128 804 * 128 byte prefetch hint. */ 805 /** @def MY_PREFETCH_256 806 * 256 byte prefetch hint. */ 807 # if RT_CACHELINE_SIZE >= 128 808 /* 128 byte cache lines */ 809 # define MY_PREFETCH_64(a_pvAddr) MY_PREFETCH(a_pvAddr) 810 # define MY_PREFETCH_128(a_pvAddr) MY_PREFETCH(a_pvAddr) 811 # define MY_PREFETCH_256(a_pvAddr) do { \ 812 MY_PREFETCH(a_pvAddr); \ 813 MY_PREFETCH((uint8_t const *)a_pvAddr + 128); \ 814 } while (0) 815 # else 816 /* 64 byte cache lines */ 817 # define MY_PREFETCH_64(a_pvAddr) MY_PREFETCH(a_pvAddr) 818 # define MY_PREFETCH_128(a_pvAddr) do { \ 819 MY_PREFETCH(a_pvAddr); \ 820 MY_PREFETCH((uint8_t const *)a_pvAddr + 64); \ 821 } while (0) 822 # define MY_PREFETCH_256(a_pvAddr) do { \ 823 MY_PREFETCH(a_pvAddr); \ 824 MY_PREFETCH((uint8_t const *)a_pvAddr + 64); \ 825 MY_PREFETCH((uint8_t const *)a_pvAddr + 128); \ 826 MY_PREFETCH((uint8_t const *)a_pvAddr + 192); \ 827 } while (0) 828 # endif 829 830 template<bool const a_fDataTlb, bool const a_f2MbLargePage, bool const a_fGlobal, bool const a_fNonGlobal> 831 DECLINLINE(void) iemTlbInvalidateLargePageWorkerInner(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag, 832 RTGCPTR GCPtrInstrBufPcTag) RT_NOEXCEPT 833 { 834 IEMTLBTRACE_LARGE_SCAN(pVCpu, a_fGlobal, a_fNonGlobal, a_fDataTlb); 835 AssertCompile(IEMTLB_ENTRY_COUNT >= 16); /* prefetching + unroll assumption */ 836 837 if (a_fGlobal) 838 pTlb->cTlbInvlPgLargeGlobal += 1; 839 if (a_fNonGlobal) 840 pTlb->cTlbInvlPgLargeNonGlobal += 1; 841 842 /* 843 * Set up the scan. 844 * 845 * GCPtrTagMask: A 2MB page consists of 512 4K pages, so a 256 TLB will map 846 * offset zero and offset 1MB to the same slot pair. Our GCPtrTag[Globl] 847 * values are for the range 0-1MB, or slots 0-256. So, we construct a mask 848 * that fold large page offsets 1MB-2MB into the 0-1MB range. 849 * 850 * For our example with 2MB pages and a 256 entry TLB: 0xfffffffffffffeff 851 * 852 * MY_PREFETCH: Hope that prefetching 256 bytes at the time is okay for 853 * relevant host architectures. 854 */ 855 /** @todo benchmark this code from the guest side. */ 856 bool const fPartialScan = IEMTLB_ENTRY_COUNT > (a_f2MbLargePage ? 512 : 1024); 857 #ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP 858 uintptr_t idxBitmap = fPartialScan ? IEMTLB_TAG_TO_EVEN_INDEX(GCPtrTag) / 64 : 0; 859 uintptr_t const idxBitmapEnd = fPartialScan ? idxBitmap + ((a_f2MbLargePage ? 512 : 1024) * 2) / 64 860 : IEMTLB_ENTRY_COUNT * 2 / 64; 861 #else 862 uintptr_t idxEven = fPartialScan ? IEMTLB_TAG_TO_EVEN_INDEX(GCPtrTag) : 0; 863 MY_PREFETCH_256(&pTlb->aEntries[idxEven + !a_fNonGlobal]); 864 uintptr_t const idxEvenEnd = fPartialScan ? idxEven + ((a_f2MbLargePage ? 512 : 1024) * 2) : IEMTLB_ENTRY_COUNT * 2; 865 #endif 866 RTGCPTR const GCPtrTagMask = fPartialScan ? ~(RTGCPTR)0 867 : ~(RTGCPTR)( (RT_BIT_32(a_f2MbLargePage ? 9 : 10) - 1U) 868 & ~(uint32_t)(RT_BIT_32(IEMTLB_ENTRY_COUNT_AS_POWER_OF_TWO) - 1U)); 869 870 /* 871 * Set cbInstrBufTotal to zero if GCPtrInstrBufPcTag is within any of the tag ranges. 872 * We make ASSUMPTIONS about IEMTLB_CALC_TAG_NO_REV here. 873 */ 874 AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U); 875 if ( !a_fDataTlb 876 && GCPtrInstrBufPcTag - GCPtrTag < (a_f2MbLargePage ? 512U : 1024U)) 877 pVCpu->iem.s.cbInstrBufTotal = 0; 878 879 /* 880 * Combine TAG values with the TLB revisions. 881 */ 882 RTGCPTR GCPtrTagGlob = a_fGlobal ? GCPtrTag | pTlb->uTlbRevisionGlobal : 0; 883 if (a_fNonGlobal) 884 GCPtrTag |= pTlb->uTlbRevision; 885 886 /* 887 * Do the scanning. 888 */ 889 #ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP 890 uint64_t const bmMask = a_fGlobal && a_fNonGlobal ? UINT64_MAX 891 : a_fGlobal ? UINT64_C(0xaaaaaaaaaaaaaaaa) : UINT64_C(0x5555555555555555); 892 /* Scan bitmap entries (64 bits at the time): */ 893 for (;;) 894 { 895 # if 1 896 uint64_t bmEntry = pTlb->bmLargePage[idxBitmap] & bmMask; 897 if (bmEntry) 898 { 899 /* Scan the non-zero 64-bit value in groups of 8 bits: */ 900 uint64_t bmToClear = 0; 901 uintptr_t idxEven = idxBitmap * 64; 902 uint32_t idxTag = 0; 903 for (;;) 904 { 905 if (bmEntry & 0xff) 906 { 907 # define ONE_PAIR(a_idxTagIter, a_idxEvenIter, a_bmNonGlobal, a_bmGlobal) \ 908 if (a_fNonGlobal) \ 909 { \ 910 if (bmEntry & a_bmNonGlobal) \ 911 { \ 912 Assert(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \ 913 if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == (GCPtrTag + a_idxTagIter)) \ 914 { \ 915 IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag + a_idxTagIter, \ 916 pTlb->aEntries[a_idxEvenIter].GCPhys, \ 917 a_idxEvenIter, a_fDataTlb); \ 918 pTlb->aEntries[a_idxEvenIter].uTag = 0; \ 919 bmToClearSub8 |= a_bmNonGlobal; \ 920 } \ 921 } \ 922 else \ 923 Assert( !(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\ 924 || (pTlb->aEntries[a_idxEvenIter].uTag & IEMTLB_REVISION_MASK) \ 925 != (GCPtrTag & IEMTLB_REVISION_MASK)); \ 926 } \ 927 if (a_fGlobal) \ 928 { \ 929 if (bmEntry & a_bmGlobal) \ 930 { \ 931 Assert(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \ 932 if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == (GCPtrTagGlob + a_idxTagIter)) \ 933 { \ 934 IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTagGlob + a_idxTagIter, \ 935 pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \ 936 a_idxEvenIter + 1, a_fDataTlb); \ 937 pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \ 938 bmToClearSub8 |= a_bmGlobal; \ 939 } \ 940 } \ 941 else \ 942 Assert( !(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\ 943 || (pTlb->aEntries[a_idxEvenIter + 1].uTag & IEMTLB_REVISION_MASK) \ 944 != (GCPtrTagGlob & IEMTLB_REVISION_MASK)); \ 945 } 946 uint64_t bmToClearSub8 = 0; 947 ONE_PAIR(idxTag + 0, idxEven + 0, 0x01, 0x02) 948 ONE_PAIR(idxTag + 1, idxEven + 2, 0x04, 0x08) 949 ONE_PAIR(idxTag + 2, idxEven + 4, 0x10, 0x20) 950 ONE_PAIR(idxTag + 3, idxEven + 6, 0x40, 0x80) 951 bmToClear |= bmToClearSub8 << (idxTag * 2); 952 # undef ONE_PAIR 953 } 954 955 /* advance to the next 8 bits. */ 956 bmEntry >>= 8; 957 if (!bmEntry) 958 break; 959 idxEven += 8; 960 idxTag += 4; 961 } 962 963 /* Clear the large page flags we covered. */ 964 pTlb->bmLargePage[idxBitmap] &= ~bmToClear; 965 } 966 # else 967 uint64_t const bmEntry = pTlb->bmLargePage[idxBitmap] & bmMask; 968 if (bmEntry) 969 { 970 /* Scan the non-zero 64-bit value completely unrolled: */ 971 uintptr_t const idxEven = idxBitmap * 64; 972 uint64_t bmToClear = 0; 973 # define ONE_PAIR(a_idxTagIter, a_idxEvenIter, a_bmNonGlobal, a_bmGlobal) \ 974 if (a_fNonGlobal) \ 975 { \ 976 if (bmEntry & a_bmNonGlobal) \ 977 { \ 978 Assert(pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \ 979 if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == (GCPtrTag + a_idxTagIter)) \ 980 { \ 981 IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag + a_idxTagIter, \ 982 pTlb->aEntries[a_idxEvenIter].GCPhys, \ 983 a_idxEvenIter, a_fDataTlb); \ 984 pTlb->aEntries[a_idxEvenIter].uTag = 0; \ 985 bmToClear |= a_bmNonGlobal; \ 986 } \ 987 } \ 988 else \ 989 Assert( !(pTlb->aEntriqes[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\ 990 || (pTlb->aEntries[a_idxEvenIter].uTag & IEMTLB_REVISION_MASK) \ 991 != (GCPtrTag & IEMTLB_REVISION_MASK)); \ 992 } \ 993 if (a_fGlobal) \ 994 { \ 995 if (bmEntry & a_bmGlobal) \ 996 { \ 997 Assert(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE); \ 998 if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == (GCPtrTagGlob + a_idxTagIter)) \ 999 { \ 1000 IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTagGlob + a_idxTagIter, \ 1001 pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \ 1002 a_idxEvenIter + 1, a_fDataTlb); \ 1003 pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \ 1004 bmToClear |= a_bmGlobal; \ 1005 } \ 1006 } \ 1007 else \ 1008 Assert( !(pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE)\ 1009 || (pTlb->aEntries[a_idxEvenIter + 1].uTag & IEMTLB_REVISION_MASK) \ 1010 != (GCPtrTagGlob & IEMTLB_REVISION_MASK)); \ 1011 } ((void)0) 1012 # define FOUR_PAIRS(a_iByte, a_cShift) \ 1013 ONE_PAIR(0 + a_iByte * 4, idxEven + 0 + a_iByte * 8, UINT64_C(0x01) << a_cShift, UINT64_C(0x02) << a_cShift); \ 1014 ONE_PAIR(1 + a_iByte * 4, idxEven + 2 + a_iByte * 8, UINT64_C(0x04) << a_cShift, UINT64_C(0x08) << a_cShift); \ 1015 ONE_PAIR(2 + a_iByte * 4, idxEven + 4 + a_iByte * 8, UINT64_C(0x10) << a_cShift, UINT64_C(0x20) << a_cShift); \ 1016 ONE_PAIR(3 + a_iByte * 4, idxEven + 6 + a_iByte * 8, UINT64_C(0x40) << a_cShift, UINT64_C(0x80) << a_cShift) 1017 if (bmEntry & (uint32_t)UINT16_MAX) 1018 { 1019 FOUR_PAIRS(0, 0); 1020 FOUR_PAIRS(1, 8); 1021 } 1022 if (bmEntry & ((uint32_t)UINT16_MAX << 16)) 1023 { 1024 FOUR_PAIRS(2, 16); 1025 FOUR_PAIRS(3, 24); 1026 } 1027 if (bmEntry & ((uint64_t)UINT16_MAX << 32)) 1028 { 1029 FOUR_PAIRS(4, 32); 1030 FOUR_PAIRS(5, 40); 1031 } 1032 if (bmEntry & ((uint64_t)UINT16_MAX << 16)) 1033 { 1034 FOUR_PAIRS(6, 48); 1035 FOUR_PAIRS(7, 56); 1036 } 1037 # undef FOUR_PAIRS 1038 1039 /* Clear the large page flags we covered. */ 1040 pTlb->bmLargePage[idxBitmap] &= ~bmToClear; 1041 } 1042 # endif 1043 1044 /* advance */ 1045 idxBitmap++; 1046 if (idxBitmap >= idxBitmapEnd) 1047 break; 1048 if (a_fNonGlobal) 1049 GCPtrTag += 32; 1050 if (a_fGlobal) 1051 GCPtrTagGlob += 32; 1052 } 1053 1054 #else /* !IEMTLB_WITH_LARGE_PAGE_BITMAP */ 1055 1056 for (; idxEven < idxEvenEnd; idxEven += 8) 1057 { 1058 # define ONE_ITERATION(a_idxEvenIter) \ 1059 if (a_fNonGlobal) \ 1060 { \ 1061 if ((pTlb->aEntries[a_idxEvenIter].uTag & GCPtrTagMask) == GCPtrTag) \ 1062 { \ 1063 if (pTlb->aEntries[a_idxEvenIter].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE) \ 1064 { \ 1065 IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[a_idxEvenIter].GCPhys, \ 1066 a_idxEvenIter, a_fDataTlb); \ 1067 pTlb->aEntries[a_idxEvenIter].uTag = 0; \ 1068 } \ 1069 } \ 1070 GCPtrTag++; \ 1071 } \ 1072 \ 1073 if (a_fGlobal) \ 1074 { \ 1075 if ((pTlb->aEntries[a_idxEvenIter + 1].uTag & GCPtrTagMask) == GCPtrTagGlob) \ 1076 { \ 1077 if (pTlb->aEntries[a_idxEvenIter + 1].fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE) \ 1078 { \ 1079 IEMTLBTRACE_LARGE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[a_idxEvenIter + 1].GCPhys, \ 1080 a_idxEvenIter + 1, a_fDataTlb); \ 1081 pTlb->aEntries[a_idxEvenIter + 1].uTag = 0; \ 1082 } \ 1083 } \ 1084 GCPtrTagGlob++; \ 1085 } 1086 if (idxEven < idxEvenEnd - 4) 1087 MY_PREFETCH_256(&pTlb->aEntries[idxEven + 8 + !a_fNonGlobal]); 1088 ONE_ITERATION(idxEven) 1089 ONE_ITERATION(idxEven + 2) 1090 ONE_ITERATION(idxEven + 4) 1091 ONE_ITERATION(idxEven + 6) 1092 # undef ONE_ITERATION 1093 } 1094 #endif /* !IEMTLB_WITH_LARGE_PAGE_BITMAP */ 1095 } 1096 1097 template<bool const a_fDataTlb, bool const a_f2MbLargePage> 1098 DECLINLINE(void) iemTlbInvalidateLargePageWorker(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag, 1099 RTGCPTR GCPtrInstrBufPcTag) RT_NOEXCEPT 1100 { 1101 AssertCompile(IEMTLB_CALC_TAG_NO_REV((RTGCPTR)0x8731U << GUEST_PAGE_SHIFT) == 0x8731U); 1102 1103 GCPtrTag &= ~(RTGCPTR)(RT_BIT_64((a_f2MbLargePage ? 21 : 22) - GUEST_PAGE_SHIFT) - 1U); 1104 if ( GCPtrTag >= pTlb->GlobalLargePageRange.uFirstTag 1105 && GCPtrTag <= pTlb->GlobalLargePageRange.uLastTag) 1106 { 1107 if ( GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag 1108 || GCPtrTag > pTlb->NonGlobalLargePageRange.uLastTag) 1109 iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, false>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag); 1110 else 1111 iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, true, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag); 1112 } 1113 else if ( GCPtrTag < pTlb->NonGlobalLargePageRange.uFirstTag 1114 || GCPtrTag > pTlb->NonGlobalLargePageRange.uLastTag) 1115 { 1116 /* Large pages aren't as likely in the non-global TLB half. */ 1117 IEMTLBTRACE_LARGE_SCAN(pVCpu, false, false, a_fDataTlb); 1118 } 1119 else 1120 iemTlbInvalidateLargePageWorkerInner<a_fDataTlb, a_f2MbLargePage, false, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag); 1121 } 1122 1123 template<bool const a_fDataTlb> 1124 DECLINLINE(void) iemTlbInvalidatePageWorker(PVMCPUCC pVCpu, IEMTLB *pTlb, RTGCPTR GCPtrTag, uintptr_t idxEven) RT_NOEXCEPT 1125 { 1126 pTlb->cTlbInvlPg += 1; 1127 1128 /* 1129 * Flush the entry pair. 1130 */ 1131 if (pTlb->aEntries[idxEven].uTag == (GCPtrTag | pTlb->uTlbRevision)) 1132 { 1133 IEMTLBTRACE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[idxEven].GCPhys, idxEven, a_fDataTlb); 1134 pTlb->aEntries[idxEven].uTag = 0; 1135 if (!a_fDataTlb && GCPtrTag == IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc)) 1136 pVCpu->iem.s.cbInstrBufTotal = 0; 1137 } 1138 if (pTlb->aEntries[idxEven + 1].uTag == (GCPtrTag | pTlb->uTlbRevisionGlobal)) 1139 { 1140 IEMTLBTRACE_EVICT_SLOT(pVCpu, GCPtrTag, pTlb->aEntries[idxEven + 1].GCPhys, idxEven + 1, a_fDataTlb); 1141 pTlb->aEntries[idxEven + 1].uTag = 0; 1142 if (!a_fDataTlb && GCPtrTag == IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc)) 1143 pVCpu->iem.s.cbInstrBufTotal = 0; 1144 } 1145 1146 /* 1147 * If there are (or has been) large pages in the TLB, we must check if the 1148 * address being flushed may involve one of those, as then we'd have to 1149 * scan for entries relating to the same page and flush those as well. 1150 */ 1151 # if 0 /** @todo do accurate counts or currently loaded large stuff and we can use those */ 1152 if (pTlb->cTlbGlobalLargePageCurLoads || pTlb->cTlbNonGlobalLargePageCurLoads) 1153 # else 1154 if (pTlb->GlobalLargePageRange.uLastTag || pTlb->NonGlobalLargePageRange.uLastTag) 1155 # endif 1156 { 1157 RTGCPTR const GCPtrInstrBufPcTag = a_fDataTlb ? 0 : IEMTLB_CALC_TAG_NO_REV(pVCpu->iem.s.uInstrBufPc); 1158 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE) 1159 iemTlbInvalidateLargePageWorker<a_fDataTlb, true>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag); 1160 else 1161 iemTlbInvalidateLargePageWorker<a_fDataTlb, false>(pVCpu, pTlb, GCPtrTag, GCPtrInstrBufPcTag); 1162 } 1163 } 1164 1165 #endif /* defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) */ 1166 1167 /** 1168 * Invalidates a page in the TLBs. 1169 * 1170 * @param pVCpu The cross context virtual CPU structure of the calling 1171 * thread. 1172 * @param GCPtr The address of the page to invalidate 1173 * @thread EMT(pVCpu) 1174 */ 1175 VMM_INT_DECL(void) IEMTlbInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtr) 1176 { 1177 IEMTLBTRACE_INVLPG(pVCpu, GCPtr); 1178 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 1179 Log10(("IEMTlbInvalidatePage: GCPtr=%RGv\n", GCPtr)); 1180 GCPtr = IEMTLB_CALC_TAG_NO_REV(GCPtr); 1181 Assert(!(GCPtr >> (48 - X86_PAGE_SHIFT))); 1182 uintptr_t const idxEven = IEMTLB_TAG_TO_EVEN_INDEX(GCPtr); 1183 1184 # ifdef IEM_WITH_CODE_TLB 1185 iemTlbInvalidatePageWorker<false>(pVCpu, &pVCpu->iem.s.CodeTlb, GCPtr, idxEven); 1186 # endif 1187 # ifdef IEM_WITH_DATA_TLB 1188 iemTlbInvalidatePageWorker<true>(pVCpu, &pVCpu->iem.s.DataTlb, GCPtr, idxEven); 1189 # endif 1190 #else 1191 NOREF(pVCpu); NOREF(GCPtr); 1192 #endif 1193 } 1194 1195 1196 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 1197 /** 1198 * Invalid both TLBs slow fashion following a rollover. 1199 * 1200 * Worker for IEMTlbInvalidateAllPhysical, 1201 * IEMTlbInvalidateAllPhysicalAllCpus, iemOpcodeFetchBytesJmp, iemMemMap, 1202 * iemMemMapJmp and others. 1203 * 1204 * @thread EMT(pVCpu) 1205 */ 1206 static void IEMTlbInvalidateAllPhysicalSlow(PVMCPUCC pVCpu) 1207 { 1208 Log10(("IEMTlbInvalidateAllPhysicalSlow\n")); 1209 ASMAtomicWriteU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2); 1210 ASMAtomicWriteU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, IEMTLB_PHYS_REV_INCR * 2); 1211 1212 unsigned i; 1213 # ifdef IEM_WITH_CODE_TLB 1214 i = RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries); 1215 while (i-- > 0) 1216 { 1217 pVCpu->iem.s.CodeTlb.aEntries[i].pbMappingR3 = NULL; 1218 pVCpu->iem.s.CodeTlb.aEntries[i].fFlagsAndPhysRev &= ~( IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PG_NO_READ 1219 | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PHYS_REV); 1220 } 1221 pVCpu->iem.s.CodeTlb.cTlbPhysRevRollovers++; 1222 pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++; 1223 # endif 1224 # ifdef IEM_WITH_DATA_TLB 1225 i = RT_ELEMENTS(pVCpu->iem.s.DataTlb.aEntries); 1226 while (i-- > 0) 1227 { 1228 pVCpu->iem.s.DataTlb.aEntries[i].pbMappingR3 = NULL; 1229 pVCpu->iem.s.DataTlb.aEntries[i].fFlagsAndPhysRev &= ~( IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PG_NO_READ 1230 | IEMTLBE_F_PG_UNASSIGNED | IEMTLBE_F_PHYS_REV); 1231 } 1232 pVCpu->iem.s.DataTlb.cTlbPhysRevRollovers++; 1233 pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++; 1234 # endif 1235 1236 } 1237 #endif 1238 1239 1240 /** 1241 * Invalidates the host physical aspects of the IEM TLBs. 1242 * 1243 * This is called internally as well as by PGM when moving GC mappings. 1244 * 1245 * @param pVCpu The cross context virtual CPU structure of the calling 1246 * thread. 1247 * @note Currently not used. 1248 */ 1249 VMM_INT_DECL(void) IEMTlbInvalidateAllPhysical(PVMCPUCC pVCpu) 1250 { 1251 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 1252 /* Note! This probably won't end up looking exactly like this, but it give an idea... */ 1253 Log10(("IEMTlbInvalidateAllPhysical\n")); 1254 1255 # ifdef IEM_WITH_CODE_TLB 1256 pVCpu->iem.s.cbInstrBufTotal = 0; 1257 # endif 1258 uint64_t uTlbPhysRev = pVCpu->iem.s.CodeTlb.uTlbPhysRev + IEMTLB_PHYS_REV_INCR; 1259 if (RT_LIKELY(uTlbPhysRev > IEMTLB_PHYS_REV_INCR * 2)) 1260 { 1261 pVCpu->iem.s.CodeTlb.uTlbPhysRev = uTlbPhysRev; 1262 pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++; 1263 pVCpu->iem.s.DataTlb.uTlbPhysRev = uTlbPhysRev; 1264 pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++; 1265 } 1266 else 1267 IEMTlbInvalidateAllPhysicalSlow(pVCpu); 1268 #else 1269 NOREF(pVCpu); 1270 #endif 1271 } 1272 1273 1274 /** 1275 * Invalidates the host physical aspects of the IEM TLBs. 1276 * 1277 * This is called internally as well as by PGM when moving GC mappings. 1278 * 1279 * @param pVM The cross context VM structure. 1280 * @param idCpuCaller The ID of the calling EMT if available to the caller, 1281 * otherwise NIL_VMCPUID. 1282 * @param enmReason The reason we're called. 1283 * 1284 * @remarks Caller holds the PGM lock. 1285 */ 1286 VMM_INT_DECL(void) IEMTlbInvalidateAllPhysicalAllCpus(PVMCC pVM, VMCPUID idCpuCaller, IEMTLBPHYSFLUSHREASON enmReason) 1287 { 1288 #if defined(IEM_WITH_CODE_TLB) || defined(IEM_WITH_DATA_TLB) 1289 PVMCPUCC const pVCpuCaller = idCpuCaller >= pVM->cCpus ? VMMGetCpu(pVM) : VMMGetCpuById(pVM, idCpuCaller); 1290 if (pVCpuCaller) 1291 VMCPU_ASSERT_EMT(pVCpuCaller); 1292 Log10(("IEMTlbInvalidateAllPhysicalAllCpus: %d\n", enmReason)); RT_NOREF(enmReason); 1293 1294 VMCC_FOR_EACH_VMCPU(pVM) 1295 { 1296 # ifdef IEM_WITH_CODE_TLB 1297 if (pVCpuCaller == pVCpu) 1298 pVCpu->iem.s.cbInstrBufTotal = 0; 1299 # endif 1300 1301 uint64_t const uTlbPhysRevPrev = ASMAtomicUoReadU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev); 1302 uint64_t uTlbPhysRevNew = uTlbPhysRevPrev + IEMTLB_PHYS_REV_INCR; 1303 if (RT_LIKELY(uTlbPhysRevNew > IEMTLB_PHYS_REV_INCR * 2)) 1304 { /* likely */} 1305 else if (pVCpuCaller != pVCpu) 1306 uTlbPhysRevNew = IEMTLB_PHYS_REV_INCR; 1307 else 1308 { 1309 IEMTlbInvalidateAllPhysicalSlow(pVCpu); 1310 continue; 1311 } 1312 if (ASMAtomicCmpXchgU64(&pVCpu->iem.s.CodeTlb.uTlbPhysRev, uTlbPhysRevNew, uTlbPhysRevPrev)) 1313 pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes++; 1314 1315 if (ASMAtomicCmpXchgU64(&pVCpu->iem.s.DataTlb.uTlbPhysRev, uTlbPhysRevNew, uTlbPhysRevPrev)) 1316 pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes++; 1317 } 1318 VMCC_FOR_EACH_VMCPU_END(pVM); 1319 1320 #else 1321 RT_NOREF(pVM, idCpuCaller, enmReason); 1322 #endif 1323 } 1324 1325 1326 /** 1327 * Flushes the prefetch buffer, light version. 1328 */ 1329 void iemOpcodeFlushLight(PVMCPUCC pVCpu, uint8_t cbInstr) 1330 { 1331 #ifndef IEM_WITH_CODE_TLB 1332 pVCpu->iem.s.cbOpcode = cbInstr; 1333 #else 1334 RT_NOREF(pVCpu, cbInstr); 1335 #endif 1336 } 1337 1338 1339 /** 1340 * Flushes the prefetch buffer, heavy version. 1341 */ 1342 void iemOpcodeFlushHeavy(PVMCPUCC pVCpu, uint8_t cbInstr) 1343 { 1344 #ifndef IEM_WITH_CODE_TLB 1345 pVCpu->iem.s.cbOpcode = cbInstr; /* Note! SVM and VT-x may set this to zero on exit, rather than the instruction length. */ 1346 #elif 1 1347 pVCpu->iem.s.cbInstrBufTotal = 0; 1348 RT_NOREF(cbInstr); 1349 #else 1350 RT_NOREF(pVCpu, cbInstr); 1351 #endif 1352 } 1353 1354 1355 1356 #ifdef IEM_WITH_CODE_TLB 1357 1358 /** 1359 * Tries to fetches @a cbDst opcode bytes, raise the appropriate exception on 1360 * failure and jumps. 1361 * 1362 * We end up here for a number of reasons: 1363 * - pbInstrBuf isn't yet initialized. 1364 * - Advancing beyond the buffer boundrary (e.g. cross page). 1365 * - Advancing beyond the CS segment limit. 1366 * - Fetching from non-mappable page (e.g. MMIO). 1367 * - TLB loading in the recompiler (@a pvDst = NULL, @a cbDst = 0). 1368 * 1369 * @param pVCpu The cross context virtual CPU structure of the 1370 * calling thread. 1371 * @param pvDst Where to return the bytes. 1372 * @param cbDst Number of bytes to read. A value of zero is 1373 * allowed for initializing pbInstrBuf (the 1374 * recompiler does this). In this case it is best 1375 * to set pbInstrBuf to NULL prior to the call. 1376 */ 1377 void iemOpcodeFetchBytesJmp(PVMCPUCC pVCpu, size_t cbDst, void *pvDst) IEM_NOEXCEPT_MAY_LONGJMP 1378 { 1379 # ifdef IN_RING3 1380 for (;;) 1381 { 1382 Assert(cbDst <= 8); 1383 uint32_t offBuf = pVCpu->iem.s.offInstrNextByte; 1384 1385 /* 1386 * We might have a partial buffer match, deal with that first to make the 1387 * rest simpler. This is the first part of the cross page/buffer case. 1388 */ 1389 uint8_t const * const pbInstrBuf = pVCpu->iem.s.pbInstrBuf; 1390 if (pbInstrBuf != NULL) 1391 { 1392 Assert(cbDst != 0); /* pbInstrBuf shall be NULL in case of a TLB load */ 1393 uint32_t const cbInstrBuf = pVCpu->iem.s.cbInstrBuf; 1394 if (offBuf < cbInstrBuf) 1395 { 1396 Assert(offBuf + cbDst > cbInstrBuf); 1397 uint32_t const cbCopy = cbInstrBuf - offBuf; 1398 memcpy(pvDst, &pbInstrBuf[offBuf], cbCopy); 1399 1400 cbDst -= cbCopy; 1401 pvDst = (uint8_t *)pvDst + cbCopy; 1402 offBuf += cbCopy; 1403 } 1404 } 1405 1406 /* 1407 * Check segment limit, figuring how much we're allowed to access at this point. 1408 * 1409 * We will fault immediately if RIP is past the segment limit / in non-canonical 1410 * territory. If we do continue, there are one or more bytes to read before we 1411 * end up in trouble and we need to do that first before faulting. 1412 */ 1413 RTGCPTR GCPtrFirst; 1414 uint32_t cbMaxRead; 1415 if (IEM_IS_64BIT_CODE(pVCpu)) 1416 { 1417 GCPtrFirst = pVCpu->cpum.GstCtx.rip + (offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart); 1418 if (RT_LIKELY(IEM_IS_CANONICAL(GCPtrFirst))) 1419 { /* likely */ } 1420 else 1421 iemRaiseGeneralProtectionFault0Jmp(pVCpu); 1422 cbMaxRead = X86_PAGE_SIZE - ((uint32_t)GCPtrFirst & X86_PAGE_OFFSET_MASK); 1423 } 1424 else 1425 { 1426 GCPtrFirst = pVCpu->cpum.GstCtx.eip + (offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart); 1427 /* Assert(!(GCPtrFirst & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu)); - this is allowed */ 1428 if (RT_LIKELY((uint32_t)GCPtrFirst <= pVCpu->cpum.GstCtx.cs.u32Limit)) 1429 { /* likely */ } 1430 else /** @todo For CPUs older than the 386, we should not necessarily generate \#GP here but wrap around! */ 1431 iemRaiseSelectorBoundsJmp(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION); 1432 cbMaxRead = pVCpu->cpum.GstCtx.cs.u32Limit - (uint32_t)GCPtrFirst + 1; 1433 if (cbMaxRead != 0) 1434 { /* likely */ } 1435 else 1436 { 1437 /* Overflowed because address is 0 and limit is max. */ 1438 Assert(GCPtrFirst == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX); 1439 cbMaxRead = X86_PAGE_SIZE; 1440 } 1441 GCPtrFirst = (uint32_t)GCPtrFirst + (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base; 1442 uint32_t cbMaxRead2 = X86_PAGE_SIZE - ((uint32_t)GCPtrFirst & X86_PAGE_OFFSET_MASK); 1443 if (cbMaxRead2 < cbMaxRead) 1444 cbMaxRead = cbMaxRead2; 1445 /** @todo testcase: unreal modes, both huge 16-bit and 32-bit. */ 1446 } 1447 1448 /* 1449 * Get the TLB entry for this piece of code. 1450 */ 1451 uint64_t const uTagNoRev = IEMTLB_CALC_TAG_NO_REV(GCPtrFirst); 1452 PIEMTLBENTRY pTlbe = IEMTLB_TAG_TO_EVEN_ENTRY(&pVCpu->iem.s.CodeTlb, uTagNoRev); 1453 if ( pTlbe->uTag == (uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevision) 1454 || (pTlbe = pTlbe + 1)->uTag == (uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal)) 1455 { 1456 /* likely when executing lots of code, otherwise unlikely */ 1457 # ifdef IEM_WITH_TLB_STATISTICS 1458 pVCpu->iem.s.CodeTlb.cTlbCoreHits++; 1459 # endif 1460 Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED)); 1461 1462 /* Check TLB page table level access flags. */ 1463 if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_EXEC)) 1464 { 1465 if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) && IEM_GET_CPL(pVCpu) == 3) 1466 { 1467 Log(("iemOpcodeFetchBytesJmp: %RGv - supervisor page\n", GCPtrFirst)); 1468 iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED); 1469 } 1470 if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)) 1471 { 1472 Log(("iemOpcodeFetchMoreBytes: %RGv - NX\n", GCPtrFirst)); 1473 iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED); 1474 } 1475 } 1476 1477 /* Look up the physical page info if necessary. */ 1478 if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.CodeTlb.uTlbPhysRev) 1479 { /* not necessary */ } 1480 else 1481 { 1482 if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR)) 1483 { /* likely */ } 1484 else 1485 IEMTlbInvalidateAllPhysicalSlow(pVCpu); 1486 pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK; 1487 int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.CodeTlb.uTlbPhysRev, 1488 &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev); 1489 AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc)); 1490 } 1491 } 1492 else 1493 { 1494 pVCpu->iem.s.CodeTlb.cTlbCoreMisses++; 1495 1496 /* This page table walking will set A bits as required by the access while performing the walk. 1497 ASSUMES these are set when the address is translated rather than on commit... */ 1498 /** @todo testcase: check when A bits are actually set by the CPU for code. */ 1499 PGMPTWALKFAST WalkFast; 1500 int rc = PGMGstQueryPageFast(pVCpu, GCPtrFirst, 1501 IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE, 1502 &WalkFast); 1503 if (RT_SUCCESS(rc)) 1504 Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS); 1505 else 1506 { 1507 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT 1508 /** @todo Nested VMX: Need to handle EPT violation/misconfig here? OF COURSE! */ 1509 Assert(!(Walk.fFailed & PGM_WALKFAIL_EPT)); 1510 # endif 1511 Log(("iemOpcodeFetchMoreBytes: %RGv - rc=%Rrc\n", GCPtrFirst, rc)); 1512 iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, rc); 1513 } 1514 1515 AssertCompile(IEMTLBE_F_PT_NO_EXEC == 1); 1516 if ( !(WalkFast.fEffective & PGM_PTATTRS_G_MASK) 1517 || IEM_GET_CPL(pVCpu) != 0) /* optimization: Only use the PTE.G=1 entries in ring-0. */ 1518 { 1519 pTlbe--; 1520 pTlbe->uTag = uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevision; 1521 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE) 1522 iemTlbLoadedLargePage<false>(pVCpu, &pVCpu->iem.s.CodeTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE)); 1523 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP 1524 else 1525 ASMBitClear(pVCpu->iem.s.CodeTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev)); 1526 # endif 1527 } 1528 else 1529 { 1530 pVCpu->iem.s.CodeTlb.cTlbCoreGlobalLoads++; 1531 pTlbe->uTag = uTagNoRev | pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal; 1532 if (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE) 1533 iemTlbLoadedLargePage<true>(pVCpu, &pVCpu->iem.s.CodeTlb, uTagNoRev, RT_BOOL(pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE)); 1534 # ifdef IEMTLB_WITH_LARGE_PAGE_BITMAP 1535 else 1536 ASMBitClear(pVCpu->iem.s.CodeTlb.bmLargePage, IEMTLB_TAG_TO_EVEN_INDEX(uTagNoRev) + 1); 1537 # endif 1538 } 1539 pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A)) 1540 | (WalkFast.fEffective >> X86_PTE_PAE_BIT_NX) /*IEMTLBE_F_PT_NO_EXEC*/ 1541 | (WalkFast.fInfo & PGM_WALKINFO_BIG_PAGE); 1542 RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK; 1543 pTlbe->GCPhys = GCPhysPg; 1544 pTlbe->pbMappingR3 = NULL; 1545 Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)); 1546 Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) || IEM_GET_CPL(pVCpu) != 3); 1547 Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED)); 1548 1549 if (!((uintptr_t)pTlbe & (sizeof(*pTlbe) * 2 - 1))) 1550 IEMTLBTRACE_LOAD( pVCpu, GCPtrFirst, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, false); 1551 else 1552 IEMTLBTRACE_LOAD_GLOBAL(pVCpu, GCPtrFirst, pTlbe->GCPhys, (uint32_t)pTlbe->fFlagsAndPhysRev, false); 1553 1554 /* Resolve the physical address. */ 1555 if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR)) 1556 { /* likely */ } 1557 else 1558 IEMTlbInvalidateAllPhysicalSlow(pVCpu); 1559 Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK)); 1560 rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.CodeTlb.uTlbPhysRev, 1561 &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev); 1562 AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc)); 1563 } 1564 1565 # if defined(IN_RING3) || defined(IN_RING0) /** @todo fixme */ 1566 /* 1567 * Try do a direct read using the pbMappingR3 pointer. 1568 * Note! Do not recheck the physical TLB revision number here as we have the 1569 * wrong response to changes in the else case. If someone is updating 1570 * pVCpu->iem.s.CodeTlb.uTlbPhysRev in parallel to us, we should be fine 1571 * pretending we always won the race. 1572 */ 1573 if ( (pTlbe->fFlagsAndPhysRev & (/*IEMTLBE_F_PHYS_REV |*/ IEMTLBE_F_NO_MAPPINGR3 | IEMTLBE_F_PG_NO_READ)) 1574 == /*pVCpu->iem.s.CodeTlb.uTlbPhysRev*/ 0U) 1575 { 1576 uint32_t const offPg = (GCPtrFirst & X86_PAGE_OFFSET_MASK); 1577 pVCpu->iem.s.cbInstrBufTotal = offPg + cbMaxRead; 1578 if (offBuf == (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart) 1579 { 1580 pVCpu->iem.s.cbInstrBuf = offPg + RT_MIN(15, cbMaxRead); 1581 pVCpu->iem.s.offCurInstrStart = (int16_t)offPg; 1582 } 1583 else 1584 { 1585 uint32_t const cbInstr = offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart; 1586 if (cbInstr + (uint32_t)cbDst <= 15) 1587 { 1588 pVCpu->iem.s.cbInstrBuf = offPg + RT_MIN(cbMaxRead + cbInstr, 15) - cbInstr; 1589 pVCpu->iem.s.offCurInstrStart = (int16_t)(offPg - cbInstr); 1590 } 1591 else 1592 { 1593 Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n", 1594 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst)); 1595 iemRaiseGeneralProtectionFault0Jmp(pVCpu); 1596 } 1597 } 1598 if (cbDst <= cbMaxRead) 1599 { 1600 pVCpu->iem.s.fTbCrossedPage |= offPg == 0 || pVCpu->iem.s.fTbBranched != 0; /** @todo Spurious load effect on branch handling? */ 1601 # if 0 /* unused */ 1602 pVCpu->iem.s.GCPhysInstrBufPrev = pVCpu->iem.s.GCPhysInstrBuf; 1603 # endif 1604 pVCpu->iem.s.offInstrNextByte = offPg + (uint32_t)cbDst; 1605 pVCpu->iem.s.uInstrBufPc = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK; 1606 pVCpu->iem.s.GCPhysInstrBuf = pTlbe->GCPhys; 1607 pVCpu->iem.s.pbInstrBuf = pTlbe->pbMappingR3; 1608 if (cbDst > 0) /* To make ASAN happy in the TLB load case. */ 1609 memcpy(pvDst, &pTlbe->pbMappingR3[offPg], cbDst); 1610 else 1611 Assert(!pvDst); 1612 return; 1613 } 1614 pVCpu->iem.s.pbInstrBuf = NULL; 1615 1616 memcpy(pvDst, &pTlbe->pbMappingR3[offPg], cbMaxRead); 1617 pVCpu->iem.s.offInstrNextByte = offPg + cbMaxRead; 1618 } 1619 # else 1620 # error "refactor as needed" 1621 /* 1622 * If there is no special read handling, so we can read a bit more and 1623 * put it in the prefetch buffer. 1624 */ 1625 if ( cbDst < cbMaxRead 1626 && (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PHYS_REV | IEMTLBE_F_PG_NO_READ)) == pVCpu->iem.s.CodeTlb.uTlbPhysRev) 1627 { 1628 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys, 1629 &pVCpu->iem.s.abOpcode[0], cbToTryRead, PGMACCESSORIGIN_IEM); 1630 if (RT_LIKELY(rcStrict == VINF_SUCCESS)) 1631 { /* likely */ } 1632 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict)) 1633 { 1634 Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n", 1635 GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead)); 1636 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict); 1637 AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICRC_VAL(rcStrict))); 1638 } 1639 else 1640 { 1641 Log((RT_SUCCESS(rcStrict) 1642 ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n" 1643 : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n", 1644 GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead)); 1645 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)); 1646 } 1647 } 1648 # endif 1649 /* 1650 * Special read handling, so only read exactly what's needed. 1651 * This is a highly unlikely scenario. 1652 */ 1653 else 1654 { 1655 pVCpu->iem.s.CodeTlb.cTlbSlowCodeReadPath++; 1656 1657 /* Check instruction length. */ 1658 uint32_t const cbInstr = offBuf - (uint32_t)(int32_t)pVCpu->iem.s.offCurInstrStart; 1659 if (RT_LIKELY(cbInstr + cbDst <= 15)) 1660 { /* likely */ } 1661 else 1662 { 1663 Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0) [slow]\n", 1664 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, cbInstr, cbDst)); 1665 iemRaiseGeneralProtectionFault0Jmp(pVCpu); 1666 } 1667 1668 /* Do the reading. */ 1669 uint32_t const cbToRead = RT_MIN((uint32_t)cbDst, cbMaxRead); 1670 if (cbToRead > 0) 1671 { 1672 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), 1673 pvDst, cbToRead, PGMACCESSORIGIN_IEM); 1674 if (RT_LIKELY(rcStrict == VINF_SUCCESS)) 1675 { /* likely */ } 1676 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict)) 1677 { 1678 Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n", 1679 GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead)); 1680 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict); 1681 AssertStmt(rcStrict == VINF_SUCCESS, IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict))); 1682 } 1683 else 1684 { 1685 Log((RT_SUCCESS(rcStrict) 1686 ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n" 1687 : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n", 1688 GCPtrFirst, pTlbe->GCPhys + (GCPtrFirst & X86_PAGE_OFFSET_MASK), VBOXSTRICTRC_VAL(rcStrict), cbToRead)); 1689 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)); 1690 } 1691 } 1692 1693 /* Update the state and probably return. */ 1694 uint32_t const offPg = (GCPtrFirst & X86_PAGE_OFFSET_MASK); 1695 pVCpu->iem.s.fTbCrossedPage |= offPg == 0 || pVCpu->iem.s.fTbBranched != 0; 1696 # if 0 /* unused */ 1697 pVCpu->iem.s.GCPhysInstrBufPrev = pVCpu->iem.s.GCPhysInstrBuf; 1698 # endif 1699 pVCpu->iem.s.offCurInstrStart = (int16_t)(offPg - cbInstr); 1700 pVCpu->iem.s.offInstrNextByte = offPg + cbInstr + cbToRead; 1701 pVCpu->iem.s.cbInstrBuf = offPg + RT_MIN(15, cbMaxRead + cbInstr) - cbToRead - cbInstr; 1702 pVCpu->iem.s.cbInstrBufTotal = X86_PAGE_SIZE; /** @todo ??? */ 1703 pVCpu->iem.s.GCPhysInstrBuf = pTlbe->GCPhys; 1704 pVCpu->iem.s.uInstrBufPc = GCPtrFirst & ~(RTGCPTR)X86_PAGE_OFFSET_MASK; 1705 pVCpu->iem.s.pbInstrBuf = NULL; 1706 if (cbToRead == cbDst) 1707 return; 1708 Assert(cbToRead == cbMaxRead); 1709 } 1710 1711 /* 1712 * More to read, loop. 1713 */ 1714 cbDst -= cbMaxRead; 1715 pvDst = (uint8_t *)pvDst + cbMaxRead; 1716 } 1717 # else /* !IN_RING3 */ 1718 RT_NOREF(pvDst, cbDst); 1719 if (pvDst || cbDst) 1720 IEM_DO_LONGJMP(pVCpu, VERR_INTERNAL_ERROR); 1721 # endif /* !IN_RING3 */ 1722 } 1723 1724 #else /* !IEM_WITH_CODE_TLB */ 1725 1726 /** 1727 * Try fetch at least @a cbMin bytes more opcodes, raise the appropriate 1728 * exception if it fails. 1729 * 1730 * @returns Strict VBox status code. 1731 * @param pVCpu The cross context virtual CPU structure of the 1732 * calling thread. 1733 * @param cbMin The minimum number of bytes relative offOpcode 1734 * that must be read. 1735 */ 1736 VBOXSTRICTRC iemOpcodeFetchMoreBytes(PVMCPUCC pVCpu, size_t cbMin) RT_NOEXCEPT 1737 { 1738 /* 1739 * What we're doing here is very similar to iemMemMap/iemMemBounceBufferMap. 1740 * 1741 * First translate CS:rIP to a physical address. 1742 */ 1743 uint8_t const cbOpcode = pVCpu->iem.s.cbOpcode; 1744 uint8_t const offOpcode = pVCpu->iem.s.offOpcode; 1745 uint8_t const cbLeft = cbOpcode - offOpcode; 1746 Assert(cbLeft < cbMin); 1747 Assert(cbOpcode <= sizeof(pVCpu->iem.s.abOpcode)); 1748 1749 uint32_t cbToTryRead; 1750 RTGCPTR GCPtrNext; 1751 if (IEM_IS_64BIT_CODE(pVCpu)) 1752 { 1753 GCPtrNext = pVCpu->cpum.GstCtx.rip + cbOpcode; 1754 if (!IEM_IS_CANONICAL(GCPtrNext)) 1755 return iemRaiseGeneralProtectionFault0(pVCpu); 1756 cbToTryRead = GUEST_PAGE_SIZE - (GCPtrNext & GUEST_PAGE_OFFSET_MASK); 1757 } 1758 else 1759 { 1760 uint32_t GCPtrNext32 = pVCpu->cpum.GstCtx.eip; 1761 /* Assert(!(GCPtrNext32 & ~(uint32_t)UINT16_MAX) || IEM_IS_32BIT_CODE(pVCpu)); - this is allowed */ 1762 GCPtrNext32 += cbOpcode; 1763 if (GCPtrNext32 > pVCpu->cpum.GstCtx.cs.u32Limit) 1764 /** @todo For CPUs older than the 386, we should not generate \#GP here but wrap around! */ 1765 return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION); 1766 cbToTryRead = pVCpu->cpum.GstCtx.cs.u32Limit - GCPtrNext32 + 1; 1767 if (!cbToTryRead) /* overflowed */ 1768 { 1769 Assert(GCPtrNext32 == 0); Assert(pVCpu->cpum.GstCtx.cs.u32Limit == UINT32_MAX); 1770 cbToTryRead = UINT32_MAX; 1771 /** @todo check out wrapping around the code segment. */ 1772 } 1773 if (cbToTryRead < cbMin - cbLeft) 1774 return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION); 1775 GCPtrNext = (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base + GCPtrNext32; 1776 1777 uint32_t cbLeftOnPage = GUEST_PAGE_SIZE - (GCPtrNext & GUEST_PAGE_OFFSET_MASK); 1778 if (cbToTryRead > cbLeftOnPage) 1779 cbToTryRead = cbLeftOnPage; 1780 } 1781 1782 /* Restrict to opcode buffer space. 1783 1784 We're making ASSUMPTIONS here based on work done previously in 1785 iemInitDecoderAndPrefetchOpcodes, where bytes from the first page will 1786 be fetched in case of an instruction crossing two pages. */ 1787 if (cbToTryRead > sizeof(pVCpu->iem.s.abOpcode) - cbOpcode) 1788 cbToTryRead = sizeof(pVCpu->iem.s.abOpcode) - cbOpcode; 1789 if (RT_LIKELY(cbToTryRead + cbLeft >= cbMin)) 1790 { /* likely */ } 1791 else 1792 { 1793 Log(("iemOpcodeFetchMoreBytes: %04x:%08RX64 LB %#x + %#zx -> #GP(0)\n", 1794 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, offOpcode, cbMin)); 1795 return iemRaiseGeneralProtectionFault0(pVCpu); 1796 } 1797 1798 PGMPTWALKFAST WalkFast; 1799 int rc = PGMGstQueryPageFast(pVCpu, GCPtrNext, 1800 IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE, 1801 &WalkFast); 1802 if (RT_SUCCESS(rc)) 1803 Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS); 1804 else 1805 { 1806 Log(("iemOpcodeFetchMoreBytes: %RGv - rc=%Rrc\n", GCPtrNext, rc)); 1807 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT 1808 if (WalkFast.fFailed & PGM_WALKFAIL_EPT) 1809 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */); 1810 #endif 1811 return iemRaisePageFault(pVCpu, GCPtrNext, 1, IEM_ACCESS_INSTRUCTION, rc); 1812 } 1813 Assert((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3); 1814 Assert(!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)); 1815 1816 RTGCPHYS const GCPhys = WalkFast.GCPhys; 1817 Log5(("GCPtrNext=%RGv GCPhys=%RGp cbOpcodes=%#x\n", GCPtrNext, GCPhys, cbOpcode)); 1818 1819 /* 1820 * Read the bytes at this address. 1821 * 1822 * We read all unpatched bytes in iemInitDecoderAndPrefetchOpcodes already, 1823 * and since PATM should only patch the start of an instruction there 1824 * should be no need to check again here. 1825 */ 1826 if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS)) 1827 { 1828 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhys, &pVCpu->iem.s.abOpcode[cbOpcode], 1829 cbToTryRead, PGMACCESSORIGIN_IEM); 1830 if (RT_LIKELY(rcStrict == VINF_SUCCESS)) 1831 { /* likely */ } 1832 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict)) 1833 { 1834 Log(("iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n", 1835 GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead)); 1836 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict); 1837 } 1838 else 1839 { 1840 Log((RT_SUCCESS(rcStrict) 1841 ? "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read status - rcStrict=%Rrc\n" 1842 : "iemOpcodeFetchMoreBytes: %RGv/%RGp LB %#x - read error - rcStrict=%Rrc (!!)\n", 1843 GCPtrNext, GCPhys, VBOXSTRICTRC_VAL(rcStrict), cbToTryRead)); 1844 return rcStrict; 1845 } 1846 } 1847 else 1848 { 1849 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.abOpcode[cbOpcode], GCPhys, cbToTryRead); 1850 if (RT_SUCCESS(rc)) 1851 { /* likely */ } 1852 else 1853 { 1854 Log(("iemOpcodeFetchMoreBytes: %RGv - read error - rc=%Rrc (!!)\n", GCPtrNext, rc)); 1855 return rc; 1856 } 1857 } 1858 pVCpu->iem.s.cbOpcode = cbOpcode + cbToTryRead; 1859 Log5(("%.*Rhxs\n", pVCpu->iem.s.cbOpcode, pVCpu->iem.s.abOpcode)); 1860 1861 return VINF_SUCCESS; 1862 } 1863 1864 #endif /* !IEM_WITH_CODE_TLB */ 1865 #ifndef IEM_WITH_SETJMP 1866 1867 /** 1868 * Deals with the problematic cases that iemOpcodeGetNextU8 doesn't like. 1869 * 1870 * @returns Strict VBox status code. 1871 * @param pVCpu The cross context virtual CPU structure of the 1872 * calling thread. 1873 * @param pb Where to return the opcode byte. 1874 */ 1875 VBOXSTRICTRC iemOpcodeGetNextU8Slow(PVMCPUCC pVCpu, uint8_t *pb) RT_NOEXCEPT 1876 { 1877 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 1); 1878 if (rcStrict == VINF_SUCCESS) 1879 { 1880 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 1881 *pb = pVCpu->iem.s.abOpcode[offOpcode]; 1882 pVCpu->iem.s.offOpcode = offOpcode + 1; 1883 } 1884 else 1885 *pb = 0; 1886 return rcStrict; 1887 } 1888 1889 #else /* IEM_WITH_SETJMP */ 1890 1891 /** 1892 * Deals with the problematic cases that iemOpcodeGetNextU8Jmp doesn't like, longjmp on error. 1893 * 1894 * @returns The opcode byte. 1895 * @param pVCpu The cross context virtual CPU structure of the calling thread. 1896 */ 1897 uint8_t iemOpcodeGetNextU8SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP 1898 { 1899 # ifdef IEM_WITH_CODE_TLB 1900 uint8_t u8; 1901 iemOpcodeFetchBytesJmp(pVCpu, sizeof(u8), &u8); 1902 return u8; 1903 # else 1904 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 1); 1905 if (rcStrict == VINF_SUCCESS) 1906 return pVCpu->iem.s.abOpcode[pVCpu->iem.s.offOpcode++]; 1907 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)); 1908 # endif 1909 } 1910 1911 #endif /* IEM_WITH_SETJMP */ 1912 1913 #ifndef IEM_WITH_SETJMP 1914 1915 /** 1916 * Deals with the problematic cases that iemOpcodeGetNextS8SxU16 doesn't like. 1917 * 1918 * @returns Strict VBox status code. 1919 * @param pVCpu The cross context virtual CPU structure of the calling thread. 1920 * @param pu16 Where to return the opcode dword. 1921 */ 1922 VBOXSTRICTRC iemOpcodeGetNextS8SxU16Slow(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT 1923 { 1924 uint8_t u8; 1925 VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8); 1926 if (rcStrict == VINF_SUCCESS) 1927 *pu16 = (int8_t)u8; 1928 return rcStrict; 1929 } 1930 1931 1932 /** 1933 * Deals with the problematic cases that iemOpcodeGetNextS8SxU32 doesn't like. 1934 * 1935 * @returns Strict VBox status code. 1936 * @param pVCpu The cross context virtual CPU structure of the calling thread. 1937 * @param pu32 Where to return the opcode dword. 1938 */ 1939 VBOXSTRICTRC iemOpcodeGetNextS8SxU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT 1940 { 1941 uint8_t u8; 1942 VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8); 1943 if (rcStrict == VINF_SUCCESS) 1944 *pu32 = (int8_t)u8; 1945 return rcStrict; 1946 } 1947 1948 1949 /** 1950 * Deals with the problematic cases that iemOpcodeGetNextS8SxU64 doesn't like. 1951 * 1952 * @returns Strict VBox status code. 1953 * @param pVCpu The cross context virtual CPU structure of the calling thread. 1954 * @param pu64 Where to return the opcode qword. 1955 */ 1956 VBOXSTRICTRC iemOpcodeGetNextS8SxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT 1957 { 1958 uint8_t u8; 1959 VBOXSTRICTRC rcStrict = iemOpcodeGetNextU8Slow(pVCpu, &u8); 1960 if (rcStrict == VINF_SUCCESS) 1961 *pu64 = (int8_t)u8; 1962 return rcStrict; 1963 } 1964 1965 #endif /* !IEM_WITH_SETJMP */ 1966 1967 1968 #ifndef IEM_WITH_SETJMP 1969 1970 /** 1971 * Deals with the problematic cases that iemOpcodeGetNextU16 doesn't like. 1972 * 1973 * @returns Strict VBox status code. 1974 * @param pVCpu The cross context virtual CPU structure of the calling thread. 1975 * @param pu16 Where to return the opcode word. 1976 */ 1977 VBOXSTRICTRC iemOpcodeGetNextU16Slow(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT 1978 { 1979 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2); 1980 if (rcStrict == VINF_SUCCESS) 1981 { 1982 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 1983 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS 1984 *pu16 = *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode]; 1985 # else 1986 *pu16 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]); 1987 # endif 1988 pVCpu->iem.s.offOpcode = offOpcode + 2; 1989 } 1990 else 1991 *pu16 = 0; 1992 return rcStrict; 1993 } 1994 1995 #else /* IEM_WITH_SETJMP */ 1996 1997 /** 1998 * Deals with the problematic cases that iemOpcodeGetNextU16Jmp doesn't like, longjmp on error 1999 * 2000 * @returns The opcode word. 2001 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2002 */ 2003 uint16_t iemOpcodeGetNextU16SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP 2004 { 2005 # ifdef IEM_WITH_CODE_TLB 2006 uint16_t u16; 2007 iemOpcodeFetchBytesJmp(pVCpu, sizeof(u16), &u16); 2008 return u16; 2009 # else 2010 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2); 2011 if (rcStrict == VINF_SUCCESS) 2012 { 2013 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2014 pVCpu->iem.s.offOpcode += 2; 2015 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS 2016 return *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode]; 2017 # else 2018 return RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]); 2019 # endif 2020 } 2021 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)); 2022 # endif 2023 } 2024 2025 #endif /* IEM_WITH_SETJMP */ 2026 2027 #ifndef IEM_WITH_SETJMP 2028 2029 /** 2030 * Deals with the problematic cases that iemOpcodeGetNextU16ZxU32 doesn't like. 2031 * 2032 * @returns Strict VBox status code. 2033 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2034 * @param pu32 Where to return the opcode double word. 2035 */ 2036 VBOXSTRICTRC iemOpcodeGetNextU16ZxU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT 2037 { 2038 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2); 2039 if (rcStrict == VINF_SUCCESS) 2040 { 2041 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2042 *pu32 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]); 2043 pVCpu->iem.s.offOpcode = offOpcode + 2; 2044 } 2045 else 2046 *pu32 = 0; 2047 return rcStrict; 2048 } 2049 2050 2051 /** 2052 * Deals with the problematic cases that iemOpcodeGetNextU16ZxU64 doesn't like. 2053 * 2054 * @returns Strict VBox status code. 2055 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2056 * @param pu64 Where to return the opcode quad word. 2057 */ 2058 VBOXSTRICTRC iemOpcodeGetNextU16ZxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT 2059 { 2060 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 2); 2061 if (rcStrict == VINF_SUCCESS) 2062 { 2063 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2064 *pu64 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]); 2065 pVCpu->iem.s.offOpcode = offOpcode + 2; 2066 } 2067 else 2068 *pu64 = 0; 2069 return rcStrict; 2070 } 2071 2072 #endif /* !IEM_WITH_SETJMP */ 2073 2074 #ifndef IEM_WITH_SETJMP 2075 2076 /** 2077 * Deals with the problematic cases that iemOpcodeGetNextU32 doesn't like. 2078 * 2079 * @returns Strict VBox status code. 2080 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2081 * @param pu32 Where to return the opcode dword. 2082 */ 2083 VBOXSTRICTRC iemOpcodeGetNextU32Slow(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT 2084 { 2085 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4); 2086 if (rcStrict == VINF_SUCCESS) 2087 { 2088 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2089 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS 2090 *pu32 = *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode]; 2091 # else 2092 *pu32 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode], 2093 pVCpu->iem.s.abOpcode[offOpcode + 1], 2094 pVCpu->iem.s.abOpcode[offOpcode + 2], 2095 pVCpu->iem.s.abOpcode[offOpcode + 3]); 2096 # endif 2097 pVCpu->iem.s.offOpcode = offOpcode + 4; 2098 } 2099 else 2100 *pu32 = 0; 2101 return rcStrict; 2102 } 2103 2104 #else /* IEM_WITH_SETJMP */ 2105 2106 /** 2107 * Deals with the problematic cases that iemOpcodeGetNextU32Jmp doesn't like, longjmp on error. 2108 * 2109 * @returns The opcode dword. 2110 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2111 */ 2112 uint32_t iemOpcodeGetNextU32SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP 2113 { 2114 # ifdef IEM_WITH_CODE_TLB 2115 uint32_t u32; 2116 iemOpcodeFetchBytesJmp(pVCpu, sizeof(u32), &u32); 2117 return u32; 2118 # else 2119 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4); 2120 if (rcStrict == VINF_SUCCESS) 2121 { 2122 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2123 pVCpu->iem.s.offOpcode = offOpcode + 4; 2124 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS 2125 return *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode]; 2126 # else 2127 return RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode], 2128 pVCpu->iem.s.abOpcode[offOpcode + 1], 2129 pVCpu->iem.s.abOpcode[offOpcode + 2], 2130 pVCpu->iem.s.abOpcode[offOpcode + 3]); 2131 # endif 2132 } 2133 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)); 2134 # endif 2135 } 2136 2137 #endif /* IEM_WITH_SETJMP */ 2138 2139 #ifndef IEM_WITH_SETJMP 2140 2141 /** 2142 * Deals with the problematic cases that iemOpcodeGetNextU32ZxU64 doesn't like. 2143 * 2144 * @returns Strict VBox status code. 2145 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2146 * @param pu64 Where to return the opcode dword. 2147 */ 2148 VBOXSTRICTRC iemOpcodeGetNextU32ZxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT 2149 { 2150 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4); 2151 if (rcStrict == VINF_SUCCESS) 2152 { 2153 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2154 *pu64 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode], 2155 pVCpu->iem.s.abOpcode[offOpcode + 1], 2156 pVCpu->iem.s.abOpcode[offOpcode + 2], 2157 pVCpu->iem.s.abOpcode[offOpcode + 3]); 2158 pVCpu->iem.s.offOpcode = offOpcode + 4; 2159 } 2160 else 2161 *pu64 = 0; 2162 return rcStrict; 2163 } 2164 2165 2166 /** 2167 * Deals with the problematic cases that iemOpcodeGetNextS32SxU64 doesn't like. 2168 * 2169 * @returns Strict VBox status code. 2170 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2171 * @param pu64 Where to return the opcode qword. 2172 */ 2173 VBOXSTRICTRC iemOpcodeGetNextS32SxU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT 2174 { 2175 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 4); 2176 if (rcStrict == VINF_SUCCESS) 2177 { 2178 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2179 *pu64 = (int32_t)RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode], 2180 pVCpu->iem.s.abOpcode[offOpcode + 1], 2181 pVCpu->iem.s.abOpcode[offOpcode + 2], 2182 pVCpu->iem.s.abOpcode[offOpcode + 3]); 2183 pVCpu->iem.s.offOpcode = offOpcode + 4; 2184 } 2185 else 2186 *pu64 = 0; 2187 return rcStrict; 2188 } 2189 2190 #endif /* !IEM_WITH_SETJMP */ 2191 2192 #ifndef IEM_WITH_SETJMP 2193 2194 /** 2195 * Deals with the problematic cases that iemOpcodeGetNextU64 doesn't like. 2196 * 2197 * @returns Strict VBox status code. 2198 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2199 * @param pu64 Where to return the opcode qword. 2200 */ 2201 VBOXSTRICTRC iemOpcodeGetNextU64Slow(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT 2202 { 2203 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 8); 2204 if (rcStrict == VINF_SUCCESS) 2205 { 2206 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2207 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS 2208 *pu64 = *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode]; 2209 # else 2210 *pu64 = RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode], 2211 pVCpu->iem.s.abOpcode[offOpcode + 1], 2212 pVCpu->iem.s.abOpcode[offOpcode + 2], 2213 pVCpu->iem.s.abOpcode[offOpcode + 3], 2214 pVCpu->iem.s.abOpcode[offOpcode + 4], 2215 pVCpu->iem.s.abOpcode[offOpcode + 5], 2216 pVCpu->iem.s.abOpcode[offOpcode + 6], 2217 pVCpu->iem.s.abOpcode[offOpcode + 7]); 2218 # endif 2219 pVCpu->iem.s.offOpcode = offOpcode + 8; 2220 } 2221 else 2222 *pu64 = 0; 2223 return rcStrict; 2224 } 2225 2226 #else /* IEM_WITH_SETJMP */ 2227 2228 /** 2229 * Deals with the problematic cases that iemOpcodeGetNextU64Jmp doesn't like, longjmp on error. 2230 * 2231 * @returns The opcode qword. 2232 * @param pVCpu The cross context virtual CPU structure of the calling thread. 2233 */ 2234 uint64_t iemOpcodeGetNextU64SlowJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP 2235 { 2236 # ifdef IEM_WITH_CODE_TLB 2237 uint64_t u64; 2238 iemOpcodeFetchBytesJmp(pVCpu, sizeof(u64), &u64); 2239 return u64; 2240 # else 2241 VBOXSTRICTRC rcStrict = iemOpcodeFetchMoreBytes(pVCpu, 8); 2242 if (rcStrict == VINF_SUCCESS) 2243 { 2244 uint8_t offOpcode = pVCpu->iem.s.offOpcode; 2245 pVCpu->iem.s.offOpcode = offOpcode + 8; 2246 # ifdef IEM_USE_UNALIGNED_DATA_ACCESS 2247 return *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode]; 2248 # else 2249 return RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode], 2250 pVCpu->iem.s.abOpcode[offOpcode + 1], 2251 pVCpu->iem.s.abOpcode[offOpcode + 2], 2252 pVCpu->iem.s.abOpcode[offOpcode + 3], 2253 pVCpu->iem.s.abOpcode[offOpcode + 4], 2254 pVCpu->iem.s.abOpcode[offOpcode + 5], 2255 pVCpu->iem.s.abOpcode[offOpcode + 6], 2256 pVCpu->iem.s.abOpcode[offOpcode + 7]); 2257 # endif 2258 } 2259 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict)); 2260 # endif 2261 } 2262 2263 #endif /* IEM_WITH_SETJMP */ 2264 2265 2266 2267 /** @name Register Access. 50 #include "IEMAllTlbInline-x86.h" 51 52 53 /** @name Memory access. 54 * 2268 55 * @{ 2269 56 */ 2270 2271 /**2272 * Adds a 8-bit signed jump offset to RIP/EIP/IP.2273 *2274 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code2275 * segment limit.2276 *2277 * @param pVCpu The cross context virtual CPU structure of the calling thread.2278 * @param cbInstr Instruction size.2279 * @param offNextInstr The offset of the next instruction.2280 * @param enmEffOpSize Effective operand size.2281 */2282 VBOXSTRICTRC iemRegRipRelativeJumpS8AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int8_t offNextInstr,2283 IEMMODE enmEffOpSize) RT_NOEXCEPT2284 {2285 switch (enmEffOpSize)2286 {2287 case IEMMODE_16BIT:2288 {2289 uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + (int16_t)offNextInstr;2290 if (RT_LIKELY( uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit2291 || IEM_IS_64BIT_CODE(pVCpu) /* no CS limit checks in 64-bit mode */))2292 pVCpu->cpum.GstCtx.rip = uNewIp;2293 else2294 return iemRaiseGeneralProtectionFault0(pVCpu);2295 break;2296 }2297 2298 case IEMMODE_32BIT:2299 {2300 Assert(!IEM_IS_64BIT_CODE(pVCpu));2301 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX);2302 2303 uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + (int32_t)offNextInstr;2304 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))2305 pVCpu->cpum.GstCtx.rip = uNewEip;2306 else2307 return iemRaiseGeneralProtectionFault0(pVCpu);2308 break;2309 }2310 2311 case IEMMODE_64BIT:2312 {2313 Assert(IEM_IS_64BIT_CODE(pVCpu));2314 2315 uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;2316 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))2317 pVCpu->cpum.GstCtx.rip = uNewRip;2318 else2319 return iemRaiseGeneralProtectionFault0(pVCpu);2320 break;2321 }2322 2323 IEM_NOT_REACHED_DEFAULT_CASE_RET();2324 }2325 2326 #ifndef IEM_WITH_CODE_TLB2327 /* Flush the prefetch buffer. */2328 pVCpu->iem.s.cbOpcode = cbInstr;2329 #endif2330 2331 /*2332 * Clear RF and finish the instruction (maybe raise #DB).2333 */2334 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);2335 }2336 2337 2338 /**2339 * Adds a 16-bit signed jump offset to RIP/EIP/IP.2340 *2341 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code2342 * segment limit.2343 *2344 * @returns Strict VBox status code.2345 * @param pVCpu The cross context virtual CPU structure of the calling thread.2346 * @param cbInstr Instruction size.2347 * @param offNextInstr The offset of the next instruction.2348 */2349 VBOXSTRICTRC iemRegRipRelativeJumpS16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int16_t offNextInstr) RT_NOEXCEPT2350 {2351 Assert(pVCpu->iem.s.enmEffOpSize == IEMMODE_16BIT);2352 2353 uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + offNextInstr;2354 if (RT_LIKELY( uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit2355 || IEM_IS_64BIT_CODE(pVCpu) /* no limit checking in 64-bit mode */))2356 pVCpu->cpum.GstCtx.rip = uNewIp;2357 else2358 return iemRaiseGeneralProtectionFault0(pVCpu);2359 2360 #ifndef IEM_WITH_CODE_TLB2361 /* Flush the prefetch buffer. */2362 pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);2363 #endif2364 2365 /*2366 * Clear RF and finish the instruction (maybe raise #DB).2367 */2368 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);2369 }2370 2371 2372 /**2373 * Adds a 32-bit signed jump offset to RIP/EIP/IP.2374 *2375 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code2376 * segment limit.2377 *2378 * @returns Strict VBox status code.2379 * @param pVCpu The cross context virtual CPU structure of the calling thread.2380 * @param cbInstr Instruction size.2381 * @param offNextInstr The offset of the next instruction.2382 * @param enmEffOpSize Effective operand size.2383 */2384 VBOXSTRICTRC iemRegRipRelativeJumpS32AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int32_t offNextInstr,2385 IEMMODE enmEffOpSize) RT_NOEXCEPT2386 {2387 if (enmEffOpSize == IEMMODE_32BIT)2388 {2389 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX); Assert(!IEM_IS_64BIT_CODE(pVCpu));2390 2391 uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + offNextInstr;2392 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))2393 pVCpu->cpum.GstCtx.rip = uNewEip;2394 else2395 return iemRaiseGeneralProtectionFault0(pVCpu);2396 }2397 else2398 {2399 Assert(enmEffOpSize == IEMMODE_64BIT);2400 2401 uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;2402 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))2403 pVCpu->cpum.GstCtx.rip = uNewRip;2404 else2405 return iemRaiseGeneralProtectionFault0(pVCpu);2406 }2407 2408 #ifndef IEM_WITH_CODE_TLB2409 /* Flush the prefetch buffer. */2410 pVCpu->iem.s.cbOpcode = IEM_GET_INSTR_LEN(pVCpu);2411 #endif2412 2413 /*2414 * Clear RF and finish the instruction (maybe raise #DB).2415 */2416 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);2417 }2418 2419 /** @} */2420 2421 2422 /** @name Memory access.2423 *2424 * @{2425 */2426 2427 #undef LOG_GROUP2428 #define LOG_GROUP LOG_GROUP_IEM_MEM2429 57 2430 58 /** … … 2612 240 } 2613 241 2614 #if 0 /*unused*/2615 /**2616 * Looks up a memory mapping entry.2617 *2618 * @returns The mapping index (positive) or VERR_NOT_FOUND (negative).2619 * @param pVCpu The cross context virtual CPU structure of the calling thread.2620 * @param pvMem The memory address.2621 * @param fAccess The access to.2622 */2623 DECLINLINE(int) iemMapLookup(PVMCPUCC pVCpu, void *pvMem, uint32_t fAccess)2624 {2625 Assert(pVCpu->iem.s.cActiveMappings <= RT_ELEMENTS(pVCpu->iem.s.aMemMappings));2626 fAccess &= IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK;2627 if ( pVCpu->iem.s.aMemMappings[0].pv == pvMem2628 && (pVCpu->iem.s.aMemMappings[0].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)2629 return 0;2630 if ( pVCpu->iem.s.aMemMappings[1].pv == pvMem2631 && (pVCpu->iem.s.aMemMappings[1].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)2632 return 1;2633 if ( pVCpu->iem.s.aMemMappings[2].pv == pvMem2634 && (pVCpu->iem.s.aMemMappings[2].fAccess & (IEM_ACCESS_WHAT_MASK | IEM_ACCESS_TYPE_MASK)) == fAccess)2635 return 2;2636 return VERR_NOT_FOUND;2637 }2638 #endif2639 242 2640 243 /** … … 2667 270 2668 271 /** 2669 * Commits a bounce buffer that needs writing back and unmaps it.2670 *2671 * @returns Strict VBox status code.2672 * @param pVCpu The cross context virtual CPU structure of the calling thread.2673 * @param iMemMap The index of the buffer to commit.2674 * @param fPostponeFail Whether we can postpone writer failures to ring-3.2675 * Always false in ring-3, obviously.2676 */2677 static VBOXSTRICTRC iemMemBounceBufferCommitAndUnmap(PVMCPUCC pVCpu, unsigned iMemMap, bool fPostponeFail)2678 {2679 Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED);2680 Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE);2681 #ifdef IN_RING32682 Assert(!fPostponeFail);2683 RT_NOREF_PV(fPostponeFail);2684 #endif2685 2686 /*2687 * Do the writing.2688 */2689 PVMCC pVM = pVCpu->CTX_SUFF(pVM);2690 if (!pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned)2691 {2692 uint16_t const cbFirst = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst;2693 uint16_t const cbSecond = pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;2694 uint8_t const *pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];2695 if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))2696 {2697 /*2698 * Carefully and efficiently dealing with access handler return2699 * codes make this a little bloated.2700 */2701 VBOXSTRICTRC rcStrict = PGMPhysWrite(pVM,2702 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,2703 pbBuf,2704 cbFirst,2705 PGMACCESSORIGIN_IEM);2706 if (rcStrict == VINF_SUCCESS)2707 {2708 if (cbSecond)2709 {2710 rcStrict = PGMPhysWrite(pVM,2711 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,2712 pbBuf + cbFirst,2713 cbSecond,2714 PGMACCESSORIGIN_IEM);2715 if (rcStrict == VINF_SUCCESS)2716 { /* nothing */ }2717 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))2718 {2719 LogEx(LOG_GROUP_IEM,2720 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc\n",2721 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,2722 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));2723 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);2724 }2725 #ifndef IN_RING32726 else if (fPostponeFail)2727 {2728 LogEx(LOG_GROUP_IEM,2729 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",2730 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,2731 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));2732 pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_2ND;2733 VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);2734 return iemSetPassUpStatus(pVCpu, rcStrict);2735 }2736 #endif2737 else2738 {2739 LogEx(LOG_GROUP_IEM,2740 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (!!)\n",2741 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,2742 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));2743 return rcStrict;2744 }2745 }2746 }2747 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))2748 {2749 if (!cbSecond)2750 {2751 LogEx(LOG_GROUP_IEM,2752 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc\n",2753 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict) ));2754 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);2755 }2756 else2757 {2758 VBOXSTRICTRC rcStrict2 = PGMPhysWrite(pVM,2759 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,2760 pbBuf + cbFirst,2761 cbSecond,2762 PGMACCESSORIGIN_IEM);2763 if (rcStrict2 == VINF_SUCCESS)2764 {2765 LogEx(LOG_GROUP_IEM,2766 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x\n",2767 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),2768 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));2769 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);2770 }2771 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))2772 {2773 LogEx(LOG_GROUP_IEM,2774 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x %Rrc\n",2775 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),2776 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict2) ));2777 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);2778 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);2779 }2780 #ifndef IN_RING32781 else if (fPostponeFail)2782 {2783 LogEx(LOG_GROUP_IEM,2784 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",2785 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,2786 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));2787 pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_2ND;2788 VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);2789 return iemSetPassUpStatus(pVCpu, rcStrict);2790 }2791 #endif2792 else2793 {2794 LogEx(LOG_GROUP_IEM,2795 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc GCPhysSecond=%RGp/%#x %Rrc (!!)\n",2796 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),2797 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict2) ));2798 return rcStrict2;2799 }2800 }2801 }2802 #ifndef IN_RING32803 else if (fPostponeFail)2804 {2805 LogEx(LOG_GROUP_IEM,2806 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (postponed)\n",2807 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,2808 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, VBOXSTRICTRC_VAL(rcStrict) ));2809 if (!cbSecond)2810 pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_1ST;2811 else2812 pVCpu->iem.s.aMemMappings[iMemMap].fAccess |= IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND;2813 VMCPU_FF_SET(pVCpu, VMCPU_FF_IEM);2814 return iemSetPassUpStatus(pVCpu, rcStrict);2815 }2816 #endif2817 else2818 {2819 LogEx(LOG_GROUP_IEM,2820 ("iemMemBounceBufferCommitAndUnmap: PGMPhysWrite GCPhysFirst=%RGp/%#x %Rrc [GCPhysSecond=%RGp/%#x] (!!)\n",2821 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, VBOXSTRICTRC_VAL(rcStrict),2822 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));2823 return rcStrict;2824 }2825 }2826 else2827 {2828 /*2829 * No access handlers, much simpler.2830 */2831 int rc = PGMPhysSimpleWriteGCPhys(pVM, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pbBuf, cbFirst);2832 if (RT_SUCCESS(rc))2833 {2834 if (cbSecond)2835 {2836 rc = PGMPhysSimpleWriteGCPhys(pVM, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, pbBuf + cbFirst, cbSecond);2837 if (RT_SUCCESS(rc))2838 { /* likely */ }2839 else2840 {2841 LogEx(LOG_GROUP_IEM,2842 ("iemMemBounceBufferCommitAndUnmap: PGMPhysSimpleWriteGCPhys GCPhysFirst=%RGp/%#x GCPhysSecond=%RGp/%#x %Rrc (!!)\n",2843 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,2844 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond, rc));2845 return rc;2846 }2847 }2848 }2849 else2850 {2851 LogEx(LOG_GROUP_IEM,2852 ("iemMemBounceBufferCommitAndUnmap: PGMPhysSimpleWriteGCPhys GCPhysFirst=%RGp/%#x %Rrc [GCPhysSecond=%RGp/%#x] (!!)\n",2853 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst, rc,2854 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond));2855 return rc;2856 }2857 }2858 }2859 2860 #if defined(IEM_LOG_MEMORY_WRITES)2861 Log5(("IEM Wrote %RGp: %.*Rhxs\n", pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,2862 RT_MAX(RT_MIN(pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst, 64), 1), &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0]));2863 if (pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond)2864 Log5(("IEM Wrote %RGp: %.*Rhxs [2nd page]\n", pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,2865 RT_MIN(pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond, 64),2866 &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst]));2867 2868 size_t cbWrote = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst + pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;2869 g_cbIemWrote = cbWrote;2870 memcpy(g_abIemWrote, &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0], RT_MIN(cbWrote, sizeof(g_abIemWrote)));2871 #endif2872 2873 /*2874 * Free the mapping entry.2875 */2876 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;2877 Assert(pVCpu->iem.s.cActiveMappings != 0);2878 pVCpu->iem.s.cActiveMappings--;2879 return VINF_SUCCESS;2880 }2881 2882 2883 /**2884 272 * Helper for iemMemMap, iemMemMapJmp and iemMemBounceBufferMapCrossPage. 273 * @todo duplicated 2885 274 */ 2886 275 DECL_FORCE_INLINE(uint32_t) … … 2892 281 return DBGFBpCheckDataRead(pVM, pVCpu, GCPtrMem, (uint32_t)cbMem, fSysAccess); 2893 282 } 2894 2895 2896 /**2897 * iemMemMap worker that deals with a request crossing pages.2898 */2899 static VBOXSTRICTRC2900 iemMemBounceBufferMapCrossPage(PVMCPUCC pVCpu, int iMemMap, void **ppvMem, uint8_t *pbUnmapInfo,2901 size_t cbMem, RTGCPTR GCPtrFirst, uint32_t fAccess)2902 {2903 STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferCrossPage);2904 Assert(cbMem <= GUEST_PAGE_SIZE);2905 2906 /*2907 * Do the address translations.2908 */2909 uint32_t const cbFirstPage = GUEST_PAGE_SIZE - (uint32_t)(GCPtrFirst & GUEST_PAGE_OFFSET_MASK);2910 RTGCPHYS GCPhysFirst;2911 VBOXSTRICTRC rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, GCPtrFirst, cbFirstPage, fAccess, &GCPhysFirst);2912 if (rcStrict != VINF_SUCCESS)2913 return rcStrict;2914 Assert((GCPhysFirst & GUEST_PAGE_OFFSET_MASK) == (GCPtrFirst & GUEST_PAGE_OFFSET_MASK));2915 2916 uint32_t const cbSecondPage = (uint32_t)cbMem - cbFirstPage;2917 RTGCPHYS GCPhysSecond;2918 rcStrict = iemMemPageTranslateAndCheckAccess(pVCpu, (GCPtrFirst + (cbMem - 1)) & ~(RTGCPTR)GUEST_PAGE_OFFSET_MASK,2919 cbSecondPage, fAccess, &GCPhysSecond);2920 if (rcStrict != VINF_SUCCESS)2921 return rcStrict;2922 Assert((GCPhysSecond & GUEST_PAGE_OFFSET_MASK) == 0);2923 GCPhysSecond &= ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK; /** @todo why? */2924 2925 PVMCC pVM = pVCpu->CTX_SUFF(pVM);2926 2927 /*2928 * Check for data breakpoints.2929 */2930 if (RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_DATA)))2931 { /* likely */ }2932 else2933 {2934 uint32_t fDataBps = iemMemCheckDataBreakpoint(pVM, pVCpu, GCPtrFirst, cbFirstPage, fAccess);2935 fDataBps |= iemMemCheckDataBreakpoint(pVM, pVCpu, (GCPtrFirst + (cbMem - 1)) & ~(RTGCPTR)GUEST_PAGE_OFFSET_MASK,2936 cbSecondPage, fAccess);2937 pVCpu->cpum.GstCtx.eflags.uBoth |= fDataBps & (CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);2938 if (fDataBps > 1)2939 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapCrossPage: Data breakpoint: fDataBps=%#x for %RGv LB %zx; fAccess=%#x cs:rip=%04x:%08RX64\n",2940 fDataBps, GCPtrFirst, cbMem, fAccess, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));2941 }2942 2943 /*2944 * Read in the current memory content if it's a read, execute or partial2945 * write access.2946 */2947 uint8_t * const pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];2948 2949 if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC | IEM_ACCESS_PARTIAL_WRITE))2950 {2951 if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))2952 {2953 /*2954 * Must carefully deal with access handler status codes here,2955 * makes the code a bit bloated.2956 */2957 rcStrict = PGMPhysRead(pVM, GCPhysFirst, pbBuf, cbFirstPage, PGMACCESSORIGIN_IEM);2958 if (rcStrict == VINF_SUCCESS)2959 {2960 rcStrict = PGMPhysRead(pVM, GCPhysSecond, pbBuf + cbFirstPage, cbSecondPage, PGMACCESSORIGIN_IEM);2961 if (rcStrict == VINF_SUCCESS)2962 { /*likely */ }2963 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))2964 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);2965 else2966 {2967 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysSecond=%RGp rcStrict2=%Rrc (!!)\n",2968 GCPhysSecond, VBOXSTRICTRC_VAL(rcStrict) ));2969 return rcStrict;2970 }2971 }2972 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))2973 {2974 VBOXSTRICTRC rcStrict2 = PGMPhysRead(pVM, GCPhysSecond, pbBuf + cbFirstPage, cbSecondPage, PGMACCESSORIGIN_IEM);2975 if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))2976 {2977 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);2978 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);2979 }2980 else2981 {2982 LogEx(LOG_GROUP_IEM,2983 ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysSecond=%RGp rcStrict2=%Rrc (rcStrict=%Rrc) (!!)\n",2984 GCPhysSecond, VBOXSTRICTRC_VAL(rcStrict2), VBOXSTRICTRC_VAL(rcStrict2) ));2985 return rcStrict2;2986 }2987 }2988 else2989 {2990 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",2991 GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));2992 return rcStrict;2993 }2994 }2995 else2996 {2997 /*2998 * No informational status codes here, much more straight forward.2999 */3000 int rc = PGMPhysSimpleReadGCPhys(pVM, pbBuf, GCPhysFirst, cbFirstPage);3001 if (RT_SUCCESS(rc))3002 {3003 Assert(rc == VINF_SUCCESS);3004 rc = PGMPhysSimpleReadGCPhys(pVM, pbBuf + cbFirstPage, GCPhysSecond, cbSecondPage);3005 if (RT_SUCCESS(rc))3006 Assert(rc == VINF_SUCCESS);3007 else3008 {3009 LogEx(LOG_GROUP_IEM,3010 ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysSecond=%RGp rc=%Rrc (!!)\n", GCPhysSecond, rc));3011 return rc;3012 }3013 }3014 else3015 {3016 LogEx(LOG_GROUP_IEM,3017 ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysFirst=%RGp rc=%Rrc (!!)\n", GCPhysFirst, rc));3018 return rc;3019 }3020 }3021 }3022 #ifdef VBOX_STRICT3023 else3024 memset(pbBuf, 0xcc, cbMem);3025 if (cbMem < sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab))3026 memset(pbBuf + cbMem, 0xaa, sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab) - cbMem);3027 #endif3028 AssertCompileMemberAlignment(VMCPU, iem.s.aBounceBuffers, 64);3029 3030 /*3031 * Commit the bounce buffer entry.3032 */3033 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst = GCPhysFirst;3034 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond = GCPhysSecond;3035 pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst = (uint16_t)cbFirstPage;3036 pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond = (uint16_t)cbSecondPage;3037 pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned = false;3038 pVCpu->iem.s.aMemMappings[iMemMap].pv = pbBuf;3039 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;3040 pVCpu->iem.s.iNextMapping = iMemMap + 1;3041 pVCpu->iem.s.cActiveMappings++;3042 3043 *ppvMem = pbBuf;3044 *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);3045 return VINF_SUCCESS;3046 }3047 3048 3049 /**3050 * iemMemMap woker that deals with iemMemPageMap failures.3051 */3052 static VBOXSTRICTRC iemMemBounceBufferMapPhys(PVMCPUCC pVCpu, unsigned iMemMap, void **ppvMem, uint8_t *pbUnmapInfo, size_t cbMem,3053 RTGCPHYS GCPhysFirst, uint32_t fAccess, VBOXSTRICTRC rcMap)3054 {3055 STAM_COUNTER_INC(&pVCpu->iem.s.StatMemBounceBufferMapPhys);3056 3057 /*3058 * Filter out conditions we can handle and the ones which shouldn't happen.3059 */3060 if ( rcMap != VERR_PGM_PHYS_TLB_CATCH_WRITE3061 && rcMap != VERR_PGM_PHYS_TLB_CATCH_ALL3062 && rcMap != VERR_PGM_PHYS_TLB_UNASSIGNED)3063 {3064 AssertReturn(RT_FAILURE_NP(rcMap), VERR_IEM_IPE_8);3065 return rcMap;3066 }3067 pVCpu->iem.s.cPotentialExits++;3068 3069 /*3070 * Read in the current memory content if it's a read, execute or partial3071 * write access.3072 */3073 uint8_t *pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];3074 if (fAccess & (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_EXEC | IEM_ACCESS_PARTIAL_WRITE))3075 {3076 if (rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED)3077 memset(pbBuf, 0xff, cbMem);3078 else3079 {3080 int rc;3081 if (!(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS))3082 {3083 VBOXSTRICTRC rcStrict = PGMPhysRead(pVCpu->CTX_SUFF(pVM), GCPhysFirst, pbBuf, cbMem, PGMACCESSORIGIN_IEM);3084 if (rcStrict == VINF_SUCCESS)3085 { /* nothing */ }3086 else if (PGM_PHYS_RW_IS_SUCCESS(rcStrict))3087 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict);3088 else3089 {3090 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysRead GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",3091 GCPhysFirst, VBOXSTRICTRC_VAL(rcStrict) ));3092 return rcStrict;3093 }3094 }3095 else3096 {3097 rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pbBuf, GCPhysFirst, cbMem);3098 if (RT_SUCCESS(rc))3099 { /* likely */ }3100 else3101 {3102 LogEx(LOG_GROUP_IEM, ("iemMemBounceBufferMapPhys: PGMPhysSimpleReadGCPhys GCPhysFirst=%RGp rcStrict=%Rrc (!!)\n",3103 GCPhysFirst, rc));3104 return rc;3105 }3106 }3107 }3108 }3109 #ifdef VBOX_STRICT3110 else3111 memset(pbBuf, 0xcc, cbMem);3112 #endif3113 #ifdef VBOX_STRICT3114 if (cbMem < sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab))3115 memset(pbBuf + cbMem, 0xaa, sizeof(pVCpu->iem.s.aBounceBuffers[iMemMap].ab) - cbMem);3116 #endif3117 3118 /*3119 * Commit the bounce buffer entry.3120 */3121 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst = GCPhysFirst;3122 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond = NIL_RTGCPHYS;3123 pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst = (uint16_t)cbMem;3124 pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond = 0;3125 pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned = rcMap == VERR_PGM_PHYS_TLB_UNASSIGNED;3126 pVCpu->iem.s.aMemMappings[iMemMap].pv = pbBuf;3127 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = fAccess | IEM_ACCESS_BOUNCE_BUFFERED;3128 pVCpu->iem.s.iNextMapping = iMemMap + 1;3129 pVCpu->iem.s.cActiveMappings++;3130 3131 *ppvMem = pbBuf;3132 *pbUnmapInfo = iMemMap | 0x08 | ((fAccess & IEM_ACCESS_TYPE_MASK) << 4);3133 return VINF_SUCCESS;3134 }3135 3136 283 3137 284 … … 3328 475 { /* likely */ } 3329 476 else 3330 IEMTlbInvalidateAllPhysicalSlow(pVCpu);477 iemTlbInvalidateAllPhysicalSlow(pVCpu); 3331 478 pTlbe->pbMappingR3 = NULL; 3332 479 pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK; … … 3509 656 3510 657 return VINF_SUCCESS; 3511 }3512 3513 3514 /**3515 * Commits the guest memory if bounce buffered and unmaps it.3516 *3517 * @returns Strict VBox status code.3518 * @param pVCpu The cross context virtual CPU structure of the calling thread.3519 * @param bUnmapInfo Unmap info set by iemMemMap.3520 */3521 VBOXSTRICTRC iemMemCommitAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT3522 {3523 uintptr_t const iMemMap = bUnmapInfo & 0x7;3524 AssertMsgReturn( (bUnmapInfo & 0x08)3525 && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)3526 && (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf)) == ((unsigned)bUnmapInfo >> 4),3527 ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess),3528 VERR_NOT_FOUND);3529 3530 /* If it's bounce buffered, we may need to write back the buffer. */3531 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)3532 {3533 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)3534 return iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, false /*fPostponeFail*/);3535 }3536 /* Otherwise unlock it. */3537 else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))3538 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);3539 3540 /* Free the entry. */3541 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;3542 Assert(pVCpu->iem.s.cActiveMappings != 0);3543 pVCpu->iem.s.cActiveMappings--;3544 return VINF_SUCCESS;3545 }3546 3547 3548 /**3549 * Rolls back the guest memory (conceptually only) and unmaps it.3550 *3551 * @param pVCpu The cross context virtual CPU structure of the calling thread.3552 * @param bUnmapInfo Unmap info set by iemMemMap.3553 */3554 void iemMemRollbackAndUnmap(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT3555 {3556 uintptr_t const iMemMap = bUnmapInfo & 0x7;3557 AssertMsgReturnVoid( (bUnmapInfo & 0x08)3558 && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)3559 && (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))3560 == ((unsigned)bUnmapInfo >> 4),3561 ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess));3562 3563 /* Unlock it if necessary. */3564 if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))3565 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);3566 3567 /* Free the entry. */3568 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;3569 Assert(pVCpu->iem.s.cActiveMappings != 0);3570 pVCpu->iem.s.cActiveMappings--;3571 658 } 3572 659 … … 4011 1098 } 4012 1099 4013 4014 /**4015 * Commits the guest memory if bounce buffered and unmaps it, longjmp on error.4016 *4017 * @param pVCpu The cross context virtual CPU structure of the calling thread.4018 * @param pvMem The mapping.4019 * @param fAccess The kind of access.4020 */4021 void iemMemCommitAndUnmapJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP4022 {4023 uintptr_t const iMemMap = bUnmapInfo & 0x7;4024 AssertMsgReturnVoid( (bUnmapInfo & 0x08)4025 && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)4026 && (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))4027 == ((unsigned)bUnmapInfo >> 4),4028 ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess));4029 4030 /* If it's bounce buffered, we may need to write back the buffer. */4031 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)4032 {4033 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)4034 {4035 VBOXSTRICTRC rcStrict = iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, false /*fPostponeFail*/);4036 if (rcStrict == VINF_SUCCESS)4037 return;4038 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));4039 }4040 }4041 /* Otherwise unlock it. */4042 else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))4043 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);4044 4045 /* Free the entry. */4046 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;4047 Assert(pVCpu->iem.s.cActiveMappings != 0);4048 pVCpu->iem.s.cActiveMappings--;4049 }4050 4051 4052 /** Fallback for iemMemCommitAndUnmapRwJmp. */4053 void iemMemCommitAndUnmapRwSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP4054 {4055 Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_WRITE));4056 iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);4057 }4058 4059 4060 /** Fallback for iemMemCommitAndUnmapAtJmp. */4061 void iemMemCommitAndUnmapAtSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP4062 {4063 Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == (IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_WRITE));4064 iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);4065 }4066 4067 4068 /** Fallback for iemMemCommitAndUnmapWoJmp. */4069 void iemMemCommitAndUnmapWoSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP4070 {4071 Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_WRITE);4072 iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);4073 }4074 4075 4076 /** Fallback for iemMemCommitAndUnmapRoJmp. */4077 void iemMemCommitAndUnmapRoSafeJmp(PVMCPUCC pVCpu, uint8_t bUnmapInfo) IEM_NOEXCEPT_MAY_LONGJMP4078 {4079 Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_READ);4080 iemMemCommitAndUnmapJmp(pVCpu, bUnmapInfo);4081 }4082 4083 4084 /** Fallback for iemMemRollbackAndUnmapWo. */4085 void iemMemRollbackAndUnmapWoSafe(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT4086 {4087 Assert(((bUnmapInfo >> 4) & IEM_ACCESS_TYPE_MASK) == IEM_ACCESS_TYPE_WRITE);4088 iemMemRollbackAndUnmap(pVCpu, bUnmapInfo);4089 }4090 4091 1100 #endif /* IEM_WITH_SETJMP */ 4092 4093 #ifndef IN_RING34094 /**4095 * Commits the guest memory if bounce buffered and unmaps it, if any bounce4096 * buffer part shows trouble it will be postponed to ring-3 (sets FF and stuff).4097 *4098 * Allows the instruction to be completed and retired, while the IEM user will4099 * return to ring-3 immediately afterwards and do the postponed writes there.4100 *4101 * @returns VBox status code (no strict statuses). Caller must check4102 * VMCPU_FF_IEM before repeating string instructions and similar stuff.4103 * @param pVCpu The cross context virtual CPU structure of the calling thread.4104 * @param pvMem The mapping.4105 * @param fAccess The kind of access.4106 */4107 VBOXSTRICTRC iemMemCommitAndUnmapPostponeTroubleToR3(PVMCPUCC pVCpu, uint8_t bUnmapInfo) RT_NOEXCEPT4108 {4109 uintptr_t const iMemMap = bUnmapInfo & 0x7;4110 AssertMsgReturn( (bUnmapInfo & 0x08)4111 && iMemMap < RT_ELEMENTS(pVCpu->iem.s.aMemMappings)4112 && (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_TYPE_MASK | 0xf))4113 == ((unsigned)bUnmapInfo >> 4),4114 ("%#x fAccess=%#x\n", bUnmapInfo, pVCpu->iem.s.aMemMappings[iMemMap].fAccess),4115 VERR_NOT_FOUND);4116 4117 /* If it's bounce buffered, we may need to write back the buffer. */4118 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED)4119 {4120 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE)4121 return iemMemBounceBufferCommitAndUnmap(pVCpu, iMemMap, true /*fPostponeFail*/);4122 }4123 /* Otherwise unlock it. */4124 else if (!(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_NOT_LOCKED))4125 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);4126 4127 /* Free the entry. */4128 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;4129 Assert(pVCpu->iem.s.cActiveMappings != 0);4130 pVCpu->iem.s.cActiveMappings--;4131 return VINF_SUCCESS;4132 }4133 #endif4134 4135 4136 /**4137 * Rollbacks mappings, releasing page locks and such.4138 *4139 * The caller shall only call this after checking cActiveMappings.4140 *4141 * @param pVCpu The cross context virtual CPU structure of the calling thread.4142 */4143 void iemMemRollback(PVMCPUCC pVCpu) RT_NOEXCEPT4144 {4145 Assert(pVCpu->iem.s.cActiveMappings > 0);4146 4147 uint32_t iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);4148 while (iMemMap-- > 0)4149 {4150 uint32_t const fAccess = pVCpu->iem.s.aMemMappings[iMemMap].fAccess;4151 if (fAccess != IEM_ACCESS_INVALID)4152 {4153 AssertMsg(!(fAccess & ~IEM_ACCESS_VALID_MASK) && fAccess != 0, ("%#x\n", fAccess));4154 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;4155 if (!(fAccess & (IEM_ACCESS_BOUNCE_BUFFERED | IEM_ACCESS_NOT_LOCKED)))4156 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &pVCpu->iem.s.aMemMappingLocks[iMemMap].Lock);4157 AssertMsg(pVCpu->iem.s.cActiveMappings > 0,4158 ("iMemMap=%u fAccess=%#x pv=%p GCPhysFirst=%RGp GCPhysSecond=%RGp\n",4159 iMemMap, fAccess, pVCpu->iem.s.aMemMappings[iMemMap].pv,4160 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond));4161 pVCpu->iem.s.cActiveMappings--;4162 }4163 }4164 }4165 1101 4166 1102 … … 4174 1110 #define TMPL_MEM_FMT_TYPE "%#04x" 4175 1111 #define TMPL_MEM_FMT_DESC "byte" 4176 #include "IEMAllMemRWTmpl .cpp.h"1112 #include "IEMAllMemRWTmpl-x86.cpp.h" 4177 1113 4178 1114 #define TMPL_MEM_TYPE uint16_t … … 4180 1116 #define TMPL_MEM_FMT_TYPE "%#06x" 4181 1117 #define TMPL_MEM_FMT_DESC "word" 4182 #include "IEMAllMemRWTmpl .cpp.h"1118 #include "IEMAllMemRWTmpl-x86.cpp.h" 4183 1119 4184 1120 #define TMPL_WITH_PUSH_SREG … … 4187 1123 #define TMPL_MEM_FMT_TYPE "%#010x" 4188 1124 #define TMPL_MEM_FMT_DESC "dword" 4189 #include "IEMAllMemRWTmpl .cpp.h"1125 #include "IEMAllMemRWTmpl-x86.cpp.h" 4190 1126 #undef TMPL_WITH_PUSH_SREG 4191 1127 … … 4194 1130 #define TMPL_MEM_FMT_TYPE "%#018RX64" 4195 1131 #define TMPL_MEM_FMT_DESC "qword" 4196 #include "IEMAllMemRWTmpl .cpp.h"1132 #include "IEMAllMemRWTmpl-x86.cpp.h" 4197 1133 4198 1134 #undef TMPL_MEM_WITH_STACK … … 4203 1139 #define TMPL_MEM_FMT_TYPE "%#010x" 4204 1140 #define TMPL_MEM_FMT_DESC "dword" 4205 #include "IEMAllMemRWTmpl .cpp.h"1141 #include "IEMAllMemRWTmpl-x86.cpp.h" 4206 1142 #undef TMPL_WITH_PUSH_SREG 4207 1143 … … 4211 1147 #define TMPL_MEM_FMT_TYPE "%#018RX64" 4212 1148 #define TMPL_MEM_FMT_DESC "qword" 4213 #include "IEMAllMemRWTmpl .cpp.h"1149 #include "IEMAllMemRWTmpl-x86.cpp.h" 4214 1150 4215 1151 #define TMPL_MEM_TYPE uint64_t … … 4218 1154 #define TMPL_MEM_FMT_TYPE "%#018RX64" 4219 1155 #define TMPL_MEM_FMT_DESC "qword" 4220 #include "IEMAllMemRWTmpl .cpp.h"1156 #include "IEMAllMemRWTmpl-x86.cpp.h" 4221 1157 4222 1158 /* See IEMAllMemRWTmplInline.cpp.h */ … … 4228 1164 #define TMPL_MEM_FMT_TYPE "%.10Rhxs" 4229 1165 #define TMPL_MEM_FMT_DESC "tword" 4230 #include "IEMAllMemRWTmpl .cpp.h"1166 #include "IEMAllMemRWTmpl-x86.cpp.h" 4231 1167 4232 1168 #define TMPL_MEM_TYPE RTPBCD80U … … 4235 1171 #define TMPL_MEM_FMT_TYPE "%.10Rhxs" 4236 1172 #define TMPL_MEM_FMT_DESC "tword" 4237 #include "IEMAllMemRWTmpl .cpp.h"1173 #include "IEMAllMemRWTmpl-x86.cpp.h" 4238 1174 4239 1175 #define TMPL_MEM_TYPE RTUINT128U … … 4242 1178 #define TMPL_MEM_FMT_TYPE "%.16Rhxs" 4243 1179 #define TMPL_MEM_FMT_DESC "dqword" 4244 #include "IEMAllMemRWTmpl .cpp.h"1180 #include "IEMAllMemRWTmpl-x86.cpp.h" 4245 1181 4246 1182 #define TMPL_MEM_TYPE RTUINT128U … … 4250 1186 #define TMPL_MEM_FMT_TYPE "%.16Rhxs" 4251 1187 #define TMPL_MEM_FMT_DESC "dqword" 4252 #include "IEMAllMemRWTmpl .cpp.h"1188 #include "IEMAllMemRWTmpl-x86.cpp.h" 4253 1189 4254 1190 #define TMPL_MEM_TYPE RTUINT128U … … 4257 1193 #define TMPL_MEM_FMT_TYPE "%.16Rhxs" 4258 1194 #define TMPL_MEM_FMT_DESC "dqword" 4259 #include "IEMAllMemRWTmpl .cpp.h"1195 #include "IEMAllMemRWTmpl-x86.cpp.h" 4260 1196 4261 1197 #define TMPL_MEM_TYPE RTUINT256U … … 4264 1200 #define TMPL_MEM_FMT_TYPE "%.32Rhxs" 4265 1201 #define TMPL_MEM_FMT_DESC "qqword" 4266 #include "IEMAllMemRWTmpl .cpp.h"1202 #include "IEMAllMemRWTmpl-x86.cpp.h" 4267 1203 4268 1204 #define TMPL_MEM_TYPE RTUINT256U … … 4272 1208 #define TMPL_MEM_FMT_TYPE "%.32Rhxs" 4273 1209 #define TMPL_MEM_FMT_DESC "qqword" 4274 #include "IEMAllMemRWTmpl.cpp.h" 1210 #include "IEMAllMemRWTmpl-x86.cpp.h" 1211 4275 1212 4276 1213 /** … … 4935 1872 } 4936 1873 4937 4938 #undef LOG_GROUP4939 #define LOG_GROUP LOG_GROUP_IEM4940 4941 1874 /** @} */ 4942 1875 4943 /** @name Opcode Helpers.4944 * @{4945 */4946 4947 /**4948 * Calculates the effective address of a ModR/M memory operand.4949 *4950 * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.4951 *4952 * @return Strict VBox status code.4953 * @param pVCpu The cross context virtual CPU structure of the calling thread.4954 * @param bRm The ModRM byte.4955 * @param cbImmAndRspOffset - First byte: The size of any immediate4956 * following the effective address opcode bytes4957 * (only for RIP relative addressing).4958 * - Second byte: RSP displacement (for POP [ESP]).4959 * @param pGCPtrEff Where to return the effective address.4960 */4961 VBOXSTRICTRC iemOpHlpCalcRmEffAddr(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, PRTGCPTR pGCPtrEff) RT_NOEXCEPT4962 {4963 Log5(("iemOpHlpCalcRmEffAddr: bRm=%#x\n", bRm));4964 # define SET_SS_DEF() \4965 do \4966 { \4967 if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \4968 pVCpu->iem.s.iEffSeg = X86_SREG_SS; \4969 } while (0)4970 4971 if (!IEM_IS_64BIT_CODE(pVCpu))4972 {4973 /** @todo Check the effective address size crap! */4974 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)4975 {4976 uint16_t u16EffAddr;4977 4978 /* Handle the disp16 form with no registers first. */4979 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)4980 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);4981 else4982 {4983 /* Get the displacment. */4984 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)4985 {4986 case 0: u16EffAddr = 0; break;4987 case 1: IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;4988 case 2: IEM_OPCODE_GET_NEXT_U16(&u16EffAddr); break;4989 default: AssertFailedReturn(VERR_IEM_IPE_1); /* (caller checked for these) */4990 }4991 4992 /* Add the base and index registers to the disp. */4993 switch (bRm & X86_MODRM_RM_MASK)4994 {4995 case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;4996 case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;4997 case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;4998 case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;4999 case 4: u16EffAddr += pVCpu->cpum.GstCtx.si; break;5000 case 5: u16EffAddr += pVCpu->cpum.GstCtx.di; break;5001 case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp; SET_SS_DEF(); break;5002 case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx; break;5003 }5004 }5005 5006 *pGCPtrEff = u16EffAddr;5007 }5008 else5009 {5010 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5011 uint32_t u32EffAddr;5012 5013 /* Handle the disp32 form with no registers first. */5014 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)5015 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);5016 else5017 {5018 /* Get the register (or SIB) value. */5019 switch ((bRm & X86_MODRM_RM_MASK))5020 {5021 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;5022 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;5023 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;5024 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;5025 case 4: /* SIB */5026 {5027 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);5028 5029 /* Get the index and scale it. */5030 switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)5031 {5032 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;5033 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;5034 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;5035 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;5036 case 4: u32EffAddr = 0; /*none */ break;5037 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;5038 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;5039 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;5040 IEM_NOT_REACHED_DEFAULT_CASE_RET();5041 }5042 u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;5043 5044 /* add base */5045 switch (bSib & X86_SIB_BASE_MASK)5046 {5047 case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;5048 case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;5049 case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;5050 case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;5051 case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;5052 case 5:5053 if ((bRm & X86_MODRM_MOD_MASK) != 0)5054 {5055 u32EffAddr += pVCpu->cpum.GstCtx.ebp;5056 SET_SS_DEF();5057 }5058 else5059 {5060 uint32_t u32Disp;5061 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5062 u32EffAddr += u32Disp;5063 }5064 break;5065 case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;5066 case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;5067 IEM_NOT_REACHED_DEFAULT_CASE_RET();5068 }5069 break;5070 }5071 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;5072 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;5073 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;5074 IEM_NOT_REACHED_DEFAULT_CASE_RET();5075 }5076 5077 /* Get and add the displacement. */5078 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5079 {5080 case 0:5081 break;5082 case 1:5083 {5084 int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);5085 u32EffAddr += i8Disp;5086 break;5087 }5088 case 2:5089 {5090 uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);5091 u32EffAddr += u32Disp;5092 break;5093 }5094 default:5095 AssertFailedReturn(VERR_IEM_IPE_2); /* (caller checked for these) */5096 }5097 5098 }5099 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5100 *pGCPtrEff = u32EffAddr;5101 }5102 }5103 else5104 {5105 uint64_t u64EffAddr;5106 5107 /* Handle the rip+disp32 form with no registers first. */5108 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)5109 {5110 IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);5111 u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));5112 }5113 else5114 {5115 /* Get the register (or SIB) value. */5116 switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)5117 {5118 case 0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;5119 case 1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;5120 case 2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;5121 case 3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;5122 case 5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;5123 case 6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;5124 case 7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;5125 case 8: u64EffAddr = pVCpu->cpum.GstCtx.r8; break;5126 case 9: u64EffAddr = pVCpu->cpum.GstCtx.r9; break;5127 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;5128 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;5129 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;5130 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;5131 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;5132 /* SIB */5133 case 4:5134 case 12:5135 {5136 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);5137 5138 /* Get the index and scale it. */5139 switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)5140 {5141 case 0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;5142 case 1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;5143 case 2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;5144 case 3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;5145 case 4: u64EffAddr = 0; /*none */ break;5146 case 5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;5147 case 6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;5148 case 7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;5149 case 8: u64EffAddr = pVCpu->cpum.GstCtx.r8; break;5150 case 9: u64EffAddr = pVCpu->cpum.GstCtx.r9; break;5151 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;5152 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;5153 case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;5154 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;5155 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;5156 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;5157 IEM_NOT_REACHED_DEFAULT_CASE_RET();5158 }5159 u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;5160 5161 /* add base */5162 switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)5163 {5164 case 0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;5165 case 1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;5166 case 2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;5167 case 3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;5168 case 4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;5169 case 6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;5170 case 7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;5171 case 8: u64EffAddr += pVCpu->cpum.GstCtx.r8; break;5172 case 9: u64EffAddr += pVCpu->cpum.GstCtx.r9; break;5173 case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;5174 case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;5175 case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;5176 case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;5177 case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;5178 /* complicated encodings */5179 case 5:5180 case 13:5181 if ((bRm & X86_MODRM_MOD_MASK) != 0)5182 {5183 if (!pVCpu->iem.s.uRexB)5184 {5185 u64EffAddr += pVCpu->cpum.GstCtx.rbp;5186 SET_SS_DEF();5187 }5188 else5189 u64EffAddr += pVCpu->cpum.GstCtx.r13;5190 }5191 else5192 {5193 uint32_t u32Disp;5194 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5195 u64EffAddr += (int32_t)u32Disp;5196 }5197 break;5198 IEM_NOT_REACHED_DEFAULT_CASE_RET();5199 }5200 break;5201 }5202 IEM_NOT_REACHED_DEFAULT_CASE_RET();5203 }5204 5205 /* Get and add the displacement. */5206 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5207 {5208 case 0:5209 break;5210 case 1:5211 {5212 int8_t i8Disp;5213 IEM_OPCODE_GET_NEXT_S8(&i8Disp);5214 u64EffAddr += i8Disp;5215 break;5216 }5217 case 2:5218 {5219 uint32_t u32Disp;5220 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5221 u64EffAddr += (int32_t)u32Disp;5222 break;5223 }5224 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* (caller checked for these) */5225 }5226 5227 }5228 5229 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)5230 *pGCPtrEff = u64EffAddr;5231 else5232 {5233 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5234 *pGCPtrEff = u64EffAddr & UINT32_MAX;5235 }5236 }5237 5238 Log5(("iemOpHlpCalcRmEffAddr: EffAddr=%#010RGv\n", *pGCPtrEff));5239 return VINF_SUCCESS;5240 }5241 5242 5243 #ifdef IEM_WITH_SETJMP5244 /**5245 * Calculates the effective address of a ModR/M memory operand.5246 *5247 * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.5248 *5249 * May longjmp on internal error.5250 *5251 * @return The effective address.5252 * @param pVCpu The cross context virtual CPU structure of the calling thread.5253 * @param bRm The ModRM byte.5254 * @param cbImmAndRspOffset - First byte: The size of any immediate5255 * following the effective address opcode bytes5256 * (only for RIP relative addressing).5257 * - Second byte: RSP displacement (for POP [ESP]).5258 */5259 RTGCPTR iemOpHlpCalcRmEffAddrJmp(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset) IEM_NOEXCEPT_MAY_LONGJMP5260 {5261 Log5(("iemOpHlpCalcRmEffAddrJmp: bRm=%#x\n", bRm));5262 # define SET_SS_DEF() \5263 do \5264 { \5265 if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \5266 pVCpu->iem.s.iEffSeg = X86_SREG_SS; \5267 } while (0)5268 5269 if (!IEM_IS_64BIT_CODE(pVCpu))5270 {5271 /** @todo Check the effective address size crap! */5272 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)5273 {5274 uint16_t u16EffAddr;5275 5276 /* Handle the disp16 form with no registers first. */5277 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)5278 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);5279 else5280 {5281 /* Get the displacment. */5282 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5283 {5284 case 0: u16EffAddr = 0; break;5285 case 1: IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;5286 case 2: IEM_OPCODE_GET_NEXT_U16(&u16EffAddr); break;5287 default: AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_1)); /* (caller checked for these) */5288 }5289 5290 /* Add the base and index registers to the disp. */5291 switch (bRm & X86_MODRM_RM_MASK)5292 {5293 case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;5294 case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;5295 case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;5296 case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;5297 case 4: u16EffAddr += pVCpu->cpum.GstCtx.si; break;5298 case 5: u16EffAddr += pVCpu->cpum.GstCtx.di; break;5299 case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp; SET_SS_DEF(); break;5300 case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx; break;5301 }5302 }5303 5304 Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#06RX16\n", u16EffAddr));5305 return u16EffAddr;5306 }5307 5308 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5309 uint32_t u32EffAddr;5310 5311 /* Handle the disp32 form with no registers first. */5312 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)5313 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);5314 else5315 {5316 /* Get the register (or SIB) value. */5317 switch ((bRm & X86_MODRM_RM_MASK))5318 {5319 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;5320 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;5321 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;5322 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;5323 case 4: /* SIB */5324 {5325 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);5326 5327 /* Get the index and scale it. */5328 switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)5329 {5330 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;5331 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;5332 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;5333 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;5334 case 4: u32EffAddr = 0; /*none */ break;5335 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;5336 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;5337 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;5338 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);5339 }5340 u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;5341 5342 /* add base */5343 switch (bSib & X86_SIB_BASE_MASK)5344 {5345 case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;5346 case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;5347 case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;5348 case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;5349 case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;5350 case 5:5351 if ((bRm & X86_MODRM_MOD_MASK) != 0)5352 {5353 u32EffAddr += pVCpu->cpum.GstCtx.ebp;5354 SET_SS_DEF();5355 }5356 else5357 {5358 uint32_t u32Disp;5359 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5360 u32EffAddr += u32Disp;5361 }5362 break;5363 case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;5364 case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;5365 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);5366 }5367 break;5368 }5369 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;5370 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;5371 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;5372 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);5373 }5374 5375 /* Get and add the displacement. */5376 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5377 {5378 case 0:5379 break;5380 case 1:5381 {5382 int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);5383 u32EffAddr += i8Disp;5384 break;5385 }5386 case 2:5387 {5388 uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);5389 u32EffAddr += u32Disp;5390 break;5391 }5392 default:5393 AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_2)); /* (caller checked for these) */5394 }5395 }5396 5397 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5398 Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RX32\n", u32EffAddr));5399 return u32EffAddr;5400 }5401 5402 uint64_t u64EffAddr;5403 5404 /* Handle the rip+disp32 form with no registers first. */5405 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)5406 {5407 IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);5408 u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));5409 }5410 else5411 {5412 /* Get the register (or SIB) value. */5413 switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)5414 {5415 case 0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;5416 case 1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;5417 case 2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;5418 case 3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;5419 case 5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;5420 case 6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;5421 case 7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;5422 case 8: u64EffAddr = pVCpu->cpum.GstCtx.r8; break;5423 case 9: u64EffAddr = pVCpu->cpum.GstCtx.r9; break;5424 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;5425 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;5426 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;5427 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;5428 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;5429 /* SIB */5430 case 4:5431 case 12:5432 {5433 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);5434 5435 /* Get the index and scale it. */5436 switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)5437 {5438 case 0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;5439 case 1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;5440 case 2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;5441 case 3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;5442 case 4: u64EffAddr = 0; /*none */ break;5443 case 5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;5444 case 6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;5445 case 7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;5446 case 8: u64EffAddr = pVCpu->cpum.GstCtx.r8; break;5447 case 9: u64EffAddr = pVCpu->cpum.GstCtx.r9; break;5448 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;5449 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;5450 case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;5451 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;5452 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;5453 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;5454 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);5455 }5456 u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;5457 5458 /* add base */5459 switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)5460 {5461 case 0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;5462 case 1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;5463 case 2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;5464 case 3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;5465 case 4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;5466 case 6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;5467 case 7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;5468 case 8: u64EffAddr += pVCpu->cpum.GstCtx.r8; break;5469 case 9: u64EffAddr += pVCpu->cpum.GstCtx.r9; break;5470 case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;5471 case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;5472 case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;5473 case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;5474 case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;5475 /* complicated encodings */5476 case 5:5477 case 13:5478 if ((bRm & X86_MODRM_MOD_MASK) != 0)5479 {5480 if (!pVCpu->iem.s.uRexB)5481 {5482 u64EffAddr += pVCpu->cpum.GstCtx.rbp;5483 SET_SS_DEF();5484 }5485 else5486 u64EffAddr += pVCpu->cpum.GstCtx.r13;5487 }5488 else5489 {5490 uint32_t u32Disp;5491 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5492 u64EffAddr += (int32_t)u32Disp;5493 }5494 break;5495 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);5496 }5497 break;5498 }5499 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);5500 }5501 5502 /* Get and add the displacement. */5503 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5504 {5505 case 0:5506 break;5507 case 1:5508 {5509 int8_t i8Disp;5510 IEM_OPCODE_GET_NEXT_S8(&i8Disp);5511 u64EffAddr += i8Disp;5512 break;5513 }5514 case 2:5515 {5516 uint32_t u32Disp;5517 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5518 u64EffAddr += (int32_t)u32Disp;5519 break;5520 }5521 IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX); /* (caller checked for these) */5522 }5523 5524 }5525 5526 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)5527 {5528 Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv\n", u64EffAddr));5529 return u64EffAddr;5530 }5531 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5532 Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv\n", u64EffAddr & UINT32_MAX));5533 return u64EffAddr & UINT32_MAX;5534 }5535 #endif /* IEM_WITH_SETJMP */5536 5537 5538 /**5539 * Calculates the effective address of a ModR/M memory operand, extended version5540 * for use in the recompilers.5541 *5542 * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.5543 *5544 * @return Strict VBox status code.5545 * @param pVCpu The cross context virtual CPU structure of the calling thread.5546 * @param bRm The ModRM byte.5547 * @param cbImmAndRspOffset - First byte: The size of any immediate5548 * following the effective address opcode bytes5549 * (only for RIP relative addressing).5550 * - Second byte: RSP displacement (for POP [ESP]).5551 * @param pGCPtrEff Where to return the effective address.5552 * @param puInfo Extra info: 32-bit displacement (bits 31:0) and5553 * SIB byte (bits 39:32).5554 */5555 VBOXSTRICTRC iemOpHlpCalcRmEffAddrEx(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, PRTGCPTR pGCPtrEff, uint64_t *puInfo) RT_NOEXCEPT5556 {5557 Log5(("iemOpHlpCalcRmEffAddr: bRm=%#x\n", bRm));5558 # define SET_SS_DEF() \5559 do \5560 { \5561 if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \5562 pVCpu->iem.s.iEffSeg = X86_SREG_SS; \5563 } while (0)5564 5565 uint64_t uInfo;5566 if (!IEM_IS_64BIT_CODE(pVCpu))5567 {5568 /** @todo Check the effective address size crap! */5569 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)5570 {5571 uint16_t u16EffAddr;5572 5573 /* Handle the disp16 form with no registers first. */5574 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)5575 {5576 IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);5577 uInfo = u16EffAddr;5578 }5579 else5580 {5581 /* Get the displacment. */5582 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5583 {5584 case 0: u16EffAddr = 0; break;5585 case 1: IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;5586 case 2: IEM_OPCODE_GET_NEXT_U16(&u16EffAddr); break;5587 default: AssertFailedReturn(VERR_IEM_IPE_1); /* (caller checked for these) */5588 }5589 uInfo = u16EffAddr;5590 5591 /* Add the base and index registers to the disp. */5592 switch (bRm & X86_MODRM_RM_MASK)5593 {5594 case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;5595 case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;5596 case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;5597 case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;5598 case 4: u16EffAddr += pVCpu->cpum.GstCtx.si; break;5599 case 5: u16EffAddr += pVCpu->cpum.GstCtx.di; break;5600 case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp; SET_SS_DEF(); break;5601 case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx; break;5602 }5603 }5604 5605 *pGCPtrEff = u16EffAddr;5606 }5607 else5608 {5609 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5610 uint32_t u32EffAddr;5611 5612 /* Handle the disp32 form with no registers first. */5613 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)5614 {5615 IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);5616 uInfo = u32EffAddr;5617 }5618 else5619 {5620 /* Get the register (or SIB) value. */5621 uInfo = 0;5622 switch ((bRm & X86_MODRM_RM_MASK))5623 {5624 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;5625 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;5626 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;5627 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;5628 case 4: /* SIB */5629 {5630 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);5631 uInfo = (uint64_t)bSib << 32;5632 5633 /* Get the index and scale it. */5634 switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)5635 {5636 case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;5637 case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;5638 case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;5639 case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;5640 case 4: u32EffAddr = 0; /*none */ break;5641 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;5642 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;5643 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;5644 IEM_NOT_REACHED_DEFAULT_CASE_RET();5645 }5646 u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;5647 5648 /* add base */5649 switch (bSib & X86_SIB_BASE_MASK)5650 {5651 case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;5652 case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;5653 case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;5654 case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;5655 case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;5656 case 5:5657 if ((bRm & X86_MODRM_MOD_MASK) != 0)5658 {5659 u32EffAddr += pVCpu->cpum.GstCtx.ebp;5660 SET_SS_DEF();5661 }5662 else5663 {5664 uint32_t u32Disp;5665 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5666 u32EffAddr += u32Disp;5667 uInfo |= u32Disp;5668 }5669 break;5670 case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;5671 case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;5672 IEM_NOT_REACHED_DEFAULT_CASE_RET();5673 }5674 break;5675 }5676 case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;5677 case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;5678 case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;5679 IEM_NOT_REACHED_DEFAULT_CASE_RET();5680 }5681 5682 /* Get and add the displacement. */5683 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5684 {5685 case 0:5686 break;5687 case 1:5688 {5689 int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);5690 u32EffAddr += i8Disp;5691 uInfo |= (uint32_t)(int32_t)i8Disp;5692 break;5693 }5694 case 2:5695 {5696 uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);5697 u32EffAddr += u32Disp;5698 uInfo |= (uint32_t)u32Disp;5699 break;5700 }5701 default:5702 AssertFailedReturn(VERR_IEM_IPE_2); /* (caller checked for these) */5703 }5704 5705 }5706 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5707 *pGCPtrEff = u32EffAddr;5708 }5709 }5710 else5711 {5712 uint64_t u64EffAddr;5713 5714 /* Handle the rip+disp32 form with no registers first. */5715 if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)5716 {5717 IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);5718 uInfo = (uint32_t)u64EffAddr;5719 u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));5720 }5721 else5722 {5723 /* Get the register (or SIB) value. */5724 uInfo = 0;5725 switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)5726 {5727 case 0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;5728 case 1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;5729 case 2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;5730 case 3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;5731 case 5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;5732 case 6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;5733 case 7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;5734 case 8: u64EffAddr = pVCpu->cpum.GstCtx.r8; break;5735 case 9: u64EffAddr = pVCpu->cpum.GstCtx.r9; break;5736 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;5737 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;5738 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;5739 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;5740 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;5741 /* SIB */5742 case 4:5743 case 12:5744 {5745 uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);5746 uInfo = (uint64_t)bSib << 32;5747 5748 /* Get the index and scale it. */5749 switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)5750 {5751 case 0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;5752 case 1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;5753 case 2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;5754 case 3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;5755 case 4: u64EffAddr = 0; /*none */ break;5756 case 5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;5757 case 6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;5758 case 7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;5759 case 8: u64EffAddr = pVCpu->cpum.GstCtx.r8; break;5760 case 9: u64EffAddr = pVCpu->cpum.GstCtx.r9; break;5761 case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;5762 case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;5763 case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;5764 case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;5765 case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;5766 case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;5767 IEM_NOT_REACHED_DEFAULT_CASE_RET();5768 }5769 u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;5770 5771 /* add base */5772 switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)5773 {5774 case 0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;5775 case 1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;5776 case 2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;5777 case 3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;5778 case 4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;5779 case 6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;5780 case 7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;5781 case 8: u64EffAddr += pVCpu->cpum.GstCtx.r8; break;5782 case 9: u64EffAddr += pVCpu->cpum.GstCtx.r9; break;5783 case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;5784 case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;5785 case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;5786 case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;5787 case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;5788 /* complicated encodings */5789 case 5:5790 case 13:5791 if ((bRm & X86_MODRM_MOD_MASK) != 0)5792 {5793 if (!pVCpu->iem.s.uRexB)5794 {5795 u64EffAddr += pVCpu->cpum.GstCtx.rbp;5796 SET_SS_DEF();5797 }5798 else5799 u64EffAddr += pVCpu->cpum.GstCtx.r13;5800 }5801 else5802 {5803 uint32_t u32Disp;5804 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5805 u64EffAddr += (int32_t)u32Disp;5806 uInfo |= u32Disp;5807 }5808 break;5809 IEM_NOT_REACHED_DEFAULT_CASE_RET();5810 }5811 break;5812 }5813 IEM_NOT_REACHED_DEFAULT_CASE_RET();5814 }5815 5816 /* Get and add the displacement. */5817 switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)5818 {5819 case 0:5820 break;5821 case 1:5822 {5823 int8_t i8Disp;5824 IEM_OPCODE_GET_NEXT_S8(&i8Disp);5825 u64EffAddr += i8Disp;5826 uInfo |= (uint32_t)(int32_t)i8Disp;5827 break;5828 }5829 case 2:5830 {5831 uint32_t u32Disp;5832 IEM_OPCODE_GET_NEXT_U32(&u32Disp);5833 u64EffAddr += (int32_t)u32Disp;5834 uInfo |= u32Disp;5835 break;5836 }5837 IEM_NOT_REACHED_DEFAULT_CASE_RET(); /* (caller checked for these) */5838 }5839 5840 }5841 5842 if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)5843 *pGCPtrEff = u64EffAddr;5844 else5845 {5846 Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);5847 *pGCPtrEff = u64EffAddr & UINT32_MAX;5848 }5849 }5850 *puInfo = uInfo;5851 5852 Log5(("iemOpHlpCalcRmEffAddrEx: EffAddr=%#010RGv uInfo=%RX64\n", *pGCPtrEff, uInfo));5853 return VINF_SUCCESS;5854 }5855 5856 /** @} */5857 5858 5859 #ifdef LOG_ENABLED5860 /**5861 * Logs the current instruction.5862 * @param pVCpu The cross context virtual CPU structure of the calling EMT.5863 * @param fSameCtx Set if we have the same context information as the VMM,5864 * clear if we may have already executed an instruction in5865 * our debug context. When clear, we assume IEMCPU holds5866 * valid CPU mode info.5867 *5868 * The @a fSameCtx parameter is now misleading and obsolete.5869 * @param pszFunction The IEM function doing the execution.5870 */5871 static void iemLogCurInstr(PVMCPUCC pVCpu, bool fSameCtx, const char *pszFunction) RT_NOEXCEPT5872 {5873 # ifdef IN_RING35874 if (LogIs2Enabled())5875 {5876 char szInstr[256];5877 uint32_t cbInstr = 0;5878 if (fSameCtx)5879 DBGFR3DisasInstrEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, 0, 0,5880 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,5881 szInstr, sizeof(szInstr), &cbInstr);5882 else5883 {5884 uint32_t fFlags = 0;5885 switch (IEM_GET_CPU_MODE(pVCpu))5886 {5887 case IEMMODE_64BIT: fFlags |= DBGF_DISAS_FLAGS_64BIT_MODE; break;5888 case IEMMODE_32BIT: fFlags |= DBGF_DISAS_FLAGS_32BIT_MODE; break;5889 case IEMMODE_16BIT:5890 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE) || pVCpu->cpum.GstCtx.eflags.Bits.u1VM)5891 fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE;5892 else5893 fFlags |= DBGF_DISAS_FLAGS_16BIT_MODE;5894 break;5895 }5896 DBGFR3DisasInstrEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fFlags,5897 szInstr, sizeof(szInstr), &cbInstr);5898 }5899 5900 PCX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;5901 Log2(("**** %s fExec=%x\n"5902 " eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"5903 " eip=%08x esp=%08x ebp=%08x iopl=%d tr=%04x\n"5904 " cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x efl=%08x\n"5905 " fsw=%04x fcw=%04x ftw=%02x mxcsr=%04x/%04x\n"5906 " %s\n"5907 , pszFunction, pVCpu->iem.s.fExec,5908 pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ebx, pVCpu->cpum.GstCtx.ecx, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.esi, pVCpu->cpum.GstCtx.edi,5909 pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.esp, pVCpu->cpum.GstCtx.ebp, pVCpu->cpum.GstCtx.eflags.Bits.u2IOPL, pVCpu->cpum.GstCtx.tr.Sel,5910 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.ds.Sel, pVCpu->cpum.GstCtx.es.Sel,5911 pVCpu->cpum.GstCtx.fs.Sel, pVCpu->cpum.GstCtx.gs.Sel, pVCpu->cpum.GstCtx.eflags.u,5912 pFpuCtx->FSW, pFpuCtx->FCW, pFpuCtx->FTW, pFpuCtx->MXCSR, pFpuCtx->MXCSR_MASK,5913 szInstr));5914 5915 /* This stuff sucks atm. as it fills the log with MSRs. */5916 //if (LogIs3Enabled())5917 // DBGFR3InfoEx(pVCpu->pVMR3->pUVM, pVCpu->idCpu, "cpumguest", "verbose", NULL);5918 }5919 else5920 # endif5921 LogFlow(("%s: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x\n", pszFunction, pVCpu->cpum.GstCtx.cs.Sel,5922 pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u));5923 RT_NOREF_PV(pVCpu); RT_NOREF_PV(fSameCtx);5924 }5925 #endif /* LOG_ENABLED */5926 5927 5928 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX5929 /**5930 * Deals with VMCPU_FF_VMX_APIC_WRITE, VMCPU_FF_VMX_MTF, VMCPU_FF_VMX_NMI_WINDOW,5931 * VMCPU_FF_VMX_PREEMPT_TIMER and VMCPU_FF_VMX_INT_WINDOW.5932 *5933 * @returns Modified rcStrict.5934 * @param pVCpu The cross context virtual CPU structure of the calling thread.5935 * @param rcStrict The instruction execution status.5936 */5937 static VBOXSTRICTRC iemHandleNestedInstructionBoundaryFFs(PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict) RT_NOEXCEPT5938 {5939 Assert(CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)));5940 if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF))5941 {5942 /* VMX preemption timer takes priority over NMI-window exits. */5943 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))5944 {5945 rcStrict = iemVmxVmexitPreemptTimer(pVCpu);5946 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER));5947 }5948 /*5949 * Check remaining intercepts.5950 *5951 * NMI-window and Interrupt-window VM-exits.5952 * Interrupt shadow (block-by-STI and Mov SS) inhibits interrupts and may also block NMIs.5953 * Event injection during VM-entry takes priority over NMI-window and interrupt-window VM-exits.5954 *5955 * See Intel spec. 26.7.6 "NMI-Window Exiting".5956 * See Intel spec. 26.7.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".5957 */5958 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW | VMCPU_FF_VMX_INT_WINDOW)5959 && !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)5960 && !TRPMHasTrap(pVCpu))5961 {5962 Assert(CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));5963 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW)5964 && CPUMIsGuestVmxVirtNmiBlocking(&pVCpu->cpum.GstCtx))5965 {5966 rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_NMI_WINDOW, 0 /* u64ExitQual */);5967 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW));5968 }5969 else if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW)5970 && CPUMIsGuestVmxVirtIntrEnabled(&pVCpu->cpum.GstCtx))5971 {5972 rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_INT_WINDOW, 0 /* u64ExitQual */);5973 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW));5974 }5975 }5976 }5977 /* TPR-below threshold/APIC write has the highest priority. */5978 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))5979 {5980 rcStrict = iemVmxApicWriteEmulation(pVCpu);5981 Assert(!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx));5982 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE));5983 }5984 /* MTF takes priority over VMX-preemption timer. */5985 else5986 {5987 rcStrict = iemVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* u64ExitQual */);5988 Assert(!CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx));5989 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF));5990 }5991 return rcStrict;5992 }5993 #endif /* VBOX_WITH_NESTED_HWVIRT_VMX */5994 5995 5996 /**5997 * The actual code execution bits of IEMExecOne, IEMExecOneWithPrefetchedByPC,5998 * IEMExecOneBypass and friends.5999 *6000 * Similar code is found in IEMExecLots.6001 *6002 * @return Strict VBox status code.6003 * @param pVCpu The cross context virtual CPU structure of the calling EMT.6004 * @param fExecuteInhibit If set, execute the instruction following CLI,6005 * POP SS and MOV SS,GR.6006 * @param pszFunction The calling function name.6007 */6008 DECLINLINE(VBOXSTRICTRC) iemExecOneInner(PVMCPUCC pVCpu, bool fExecuteInhibit, const char *pszFunction)6009 {6010 AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));6011 AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));6012 AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));6013 RT_NOREF_PV(pszFunction);6014 6015 #ifdef IEM_WITH_SETJMP6016 VBOXSTRICTRC rcStrict;6017 IEM_TRY_SETJMP(pVCpu, rcStrict)6018 {6019 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);6020 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6021 }6022 IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);6023 {6024 pVCpu->iem.s.cLongJumps++;6025 }6026 IEM_CATCH_LONGJMP_END(pVCpu);6027 #else6028 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);6029 VBOXSTRICTRC rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6030 #endif6031 if (rcStrict == VINF_SUCCESS)6032 pVCpu->iem.s.cInstructions++;6033 if (pVCpu->iem.s.cActiveMappings > 0)6034 {6035 Assert(rcStrict != VINF_SUCCESS);6036 iemMemRollback(pVCpu);6037 }6038 AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));6039 AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));6040 AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));6041 6042 //#ifdef DEBUG6043 // AssertMsg(IEM_GET_INSTR_LEN(pVCpu) == cbInstr || rcStrict != VINF_SUCCESS, ("%u %u\n", IEM_GET_INSTR_LEN(pVCpu), cbInstr));6044 //#endif6045 6046 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6047 /*6048 * Perform any VMX nested-guest instruction boundary actions.6049 *6050 * If any of these causes a VM-exit, we must skip executing the next6051 * instruction (would run into stale page tables). A VM-exit makes sure6052 * there is no interrupt-inhibition, so that should ensure we don't go6053 * to try execute the next instruction. Clearing fExecuteInhibit is6054 * problematic because of the setjmp/longjmp clobbering above.6055 */6056 if ( !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER6057 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)6058 || rcStrict != VINF_SUCCESS)6059 { /* likely */ }6060 else6061 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6062 #endif6063 6064 /* Execute the next instruction as well if a cli, pop ss or6065 mov ss, Gr has just completed successfully. */6066 if ( fExecuteInhibit6067 && rcStrict == VINF_SUCCESS6068 && CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))6069 {6070 rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, pVCpu->iem.s.fExec & (IEM_F_BYPASS_HANDLERS | IEM_F_X86_DISREGARD_LOCK));6071 if (rcStrict == VINF_SUCCESS)6072 {6073 #ifdef LOG_ENABLED6074 iemLogCurInstr(pVCpu, false, pszFunction);6075 #endif6076 #ifdef IEM_WITH_SETJMP6077 IEM_TRY_SETJMP_AGAIN(pVCpu, rcStrict)6078 {6079 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);6080 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6081 }6082 IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);6083 {6084 pVCpu->iem.s.cLongJumps++;6085 }6086 IEM_CATCH_LONGJMP_END(pVCpu);6087 #else6088 IEM_OPCODE_GET_FIRST_U8(&b);6089 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6090 #endif6091 if (rcStrict == VINF_SUCCESS)6092 {6093 pVCpu->iem.s.cInstructions++;6094 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6095 if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER6096 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW))6097 { /* likely */ }6098 else6099 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6100 #endif6101 }6102 if (pVCpu->iem.s.cActiveMappings > 0)6103 {6104 Assert(rcStrict != VINF_SUCCESS);6105 iemMemRollback(pVCpu);6106 }6107 AssertMsg(pVCpu->iem.s.aMemMappings[0].fAccess == IEM_ACCESS_INVALID, ("0: %#x %RGp\n", pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemBbMappings[0].GCPhysFirst));6108 AssertMsg(pVCpu->iem.s.aMemMappings[1].fAccess == IEM_ACCESS_INVALID, ("1: %#x %RGp\n", pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemBbMappings[1].GCPhysFirst));6109 AssertMsg(pVCpu->iem.s.aMemMappings[2].fAccess == IEM_ACCESS_INVALID, ("2: %#x %RGp\n", pVCpu->iem.s.aMemMappings[2].fAccess, pVCpu->iem.s.aMemBbMappings[2].GCPhysFirst));6110 }6111 else if (pVCpu->iem.s.cActiveMappings > 0)6112 iemMemRollback(pVCpu);6113 /** @todo drop this after we bake this change into RIP advancing. */6114 CPUMClearInterruptShadow(&pVCpu->cpum.GstCtx); /* hope this is correct for all exceptional cases... */6115 }6116 6117 /*6118 * Return value fiddling, statistics and sanity assertions.6119 */6120 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6121 6122 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));6123 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));6124 return rcStrict;6125 }6126 6127 6128 /**6129 * Execute one instruction.6130 *6131 * @return Strict VBox status code.6132 * @param pVCpu The cross context virtual CPU structure of the calling EMT.6133 */6134 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOne(PVMCPUCC pVCpu)6135 {6136 AssertCompile(sizeof(pVCpu->iem.s) <= sizeof(pVCpu->iem.padding)); /* (tstVMStruct can't do it's job w/o instruction stats) */6137 #ifdef LOG_ENABLED6138 iemLogCurInstr(pVCpu, true, "IEMExecOne");6139 #endif6140 6141 /*6142 * Do the decoding and emulation.6143 */6144 VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);6145 if (rcStrict == VINF_SUCCESS)6146 rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOne");6147 else if (pVCpu->iem.s.cActiveMappings > 0)6148 iemMemRollback(pVCpu);6149 6150 if (rcStrict != VINF_SUCCESS)6151 LogFlow(("IEMExecOne: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",6152 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));6153 return rcStrict;6154 }6155 6156 6157 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC,6158 const void *pvOpcodeBytes, size_t cbOpcodeBytes)6159 {6160 VBOXSTRICTRC rcStrict;6161 if ( cbOpcodeBytes6162 && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)6163 {6164 iemInitDecoder(pVCpu, 0 /*fExecOpts*/);6165 #ifdef IEM_WITH_CODE_TLB6166 pVCpu->iem.s.uInstrBufPc = OpcodeBytesPC;6167 pVCpu->iem.s.pbInstrBuf = (uint8_t const *)pvOpcodeBytes;6168 pVCpu->iem.s.cbInstrBufTotal = (uint16_t)RT_MIN(X86_PAGE_SIZE, cbOpcodeBytes);6169 pVCpu->iem.s.offCurInstrStart = 0;6170 pVCpu->iem.s.offInstrNextByte = 0;6171 pVCpu->iem.s.GCPhysInstrBuf = NIL_RTGCPHYS;6172 #else6173 pVCpu->iem.s.cbOpcode = (uint8_t)RT_MIN(cbOpcodeBytes, sizeof(pVCpu->iem.s.abOpcode));6174 memcpy(pVCpu->iem.s.abOpcode, pvOpcodeBytes, pVCpu->iem.s.cbOpcode);6175 #endif6176 rcStrict = VINF_SUCCESS;6177 }6178 else6179 rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);6180 if (rcStrict == VINF_SUCCESS)6181 rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOneWithPrefetchedByPC");6182 else if (pVCpu->iem.s.cActiveMappings > 0)6183 iemMemRollback(pVCpu);6184 6185 return rcStrict;6186 }6187 6188 6189 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneBypass(PVMCPUCC pVCpu)6190 {6191 VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_BYPASS_HANDLERS);6192 if (rcStrict == VINF_SUCCESS)6193 rcStrict = iemExecOneInner(pVCpu, false, "IEMExecOneBypass");6194 else if (pVCpu->iem.s.cActiveMappings > 0)6195 iemMemRollback(pVCpu);6196 6197 return rcStrict;6198 }6199 6200 6201 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneBypassWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC,6202 const void *pvOpcodeBytes, size_t cbOpcodeBytes)6203 {6204 VBOXSTRICTRC rcStrict;6205 if ( cbOpcodeBytes6206 && pVCpu->cpum.GstCtx.rip == OpcodeBytesPC)6207 {6208 iemInitDecoder(pVCpu, IEM_F_BYPASS_HANDLERS);6209 #ifdef IEM_WITH_CODE_TLB6210 pVCpu->iem.s.uInstrBufPc = OpcodeBytesPC;6211 pVCpu->iem.s.pbInstrBuf = (uint8_t const *)pvOpcodeBytes;6212 pVCpu->iem.s.cbInstrBufTotal = (uint16_t)RT_MIN(X86_PAGE_SIZE, cbOpcodeBytes);6213 pVCpu->iem.s.offCurInstrStart = 0;6214 pVCpu->iem.s.offInstrNextByte = 0;6215 pVCpu->iem.s.GCPhysInstrBuf = NIL_RTGCPHYS;6216 #else6217 pVCpu->iem.s.cbOpcode = (uint8_t)RT_MIN(cbOpcodeBytes, sizeof(pVCpu->iem.s.abOpcode));6218 memcpy(pVCpu->iem.s.abOpcode, pvOpcodeBytes, pVCpu->iem.s.cbOpcode);6219 #endif6220 rcStrict = VINF_SUCCESS;6221 }6222 else6223 rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_BYPASS_HANDLERS);6224 if (rcStrict == VINF_SUCCESS)6225 rcStrict = iemExecOneInner(pVCpu, false, "IEMExecOneBypassWithPrefetchedByPC");6226 else if (pVCpu->iem.s.cActiveMappings > 0)6227 iemMemRollback(pVCpu);6228 6229 return rcStrict;6230 }6231 6232 6233 /**6234 * For handling split cacheline lock operations when the host has split-lock6235 * detection enabled.6236 *6237 * This will cause the interpreter to disregard the lock prefix and implicit6238 * locking (xchg).6239 *6240 * @returns Strict VBox status code.6241 * @param pVCpu The cross context virtual CPU structure of the calling EMT.6242 */6243 VMM_INT_DECL(VBOXSTRICTRC) IEMExecOneIgnoreLock(PVMCPUCC pVCpu)6244 {6245 /*6246 * Do the decoding and emulation.6247 */6248 VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, IEM_F_X86_DISREGARD_LOCK);6249 if (rcStrict == VINF_SUCCESS)6250 rcStrict = iemExecOneInner(pVCpu, true, "IEMExecOneIgnoreLock");6251 else if (pVCpu->iem.s.cActiveMappings > 0)6252 iemMemRollback(pVCpu);6253 6254 if (rcStrict != VINF_SUCCESS)6255 LogFlow(("IEMExecOneIgnoreLock: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",6256 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));6257 return rcStrict;6258 }6259 6260 6261 /**6262 * Code common to IEMExecLots and IEMExecRecompilerThreaded that attempts to6263 * inject a pending TRPM trap.6264 */6265 VBOXSTRICTRC iemExecInjectPendingTrap(PVMCPUCC pVCpu)6266 {6267 Assert(TRPMHasTrap(pVCpu));6268 6269 if ( !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)6270 && !CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))6271 {6272 /** @todo Can we centralize this under CPUMCanInjectInterrupt()? */6273 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)6274 bool fIntrEnabled = CPUMGetGuestGif(&pVCpu->cpum.GstCtx);6275 if (fIntrEnabled)6276 {6277 if (!CPUMIsGuestInNestedHwvirtMode(IEM_GET_CTX(pVCpu)))6278 fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;6279 else if (CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)))6280 fIntrEnabled = CPUMIsGuestVmxPhysIntrEnabled(IEM_GET_CTX(pVCpu));6281 else6282 {6283 Assert(CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)));6284 fIntrEnabled = CPUMIsGuestSvmPhysIntrEnabled(pVCpu, IEM_GET_CTX(pVCpu));6285 }6286 }6287 #else6288 bool fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;6289 #endif6290 if (fIntrEnabled)6291 {6292 uint8_t u8TrapNo;6293 TRPMEVENT enmType;6294 uint32_t uErrCode;6295 RTGCPTR uCr2;6296 int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2, NULL /*pu8InstLen*/, NULL /*fIcebp*/);6297 AssertRC(rc2);6298 Assert(enmType == TRPM_HARDWARE_INT);6299 VBOXSTRICTRC rcStrict = IEMInjectTrap(pVCpu, u8TrapNo, enmType, (uint16_t)uErrCode, uCr2, 0 /*cbInstr*/);6300 6301 TRPMResetTrap(pVCpu);6302 6303 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)6304 /* Injecting an event may cause a VM-exit. */6305 if ( rcStrict != VINF_SUCCESS6306 && rcStrict != VINF_IEM_RAISED_XCPT)6307 return iemExecStatusCodeFiddling(pVCpu, rcStrict);6308 #else6309 NOREF(rcStrict);6310 #endif6311 }6312 }6313 6314 return VINF_SUCCESS;6315 }6316 6317 6318 VMM_INT_DECL(VBOXSTRICTRC) IEMExecLots(PVMCPUCC pVCpu, uint32_t cMaxInstructions, uint32_t cPollRate, uint32_t *pcInstructions)6319 {6320 uint32_t const cInstructionsAtStart = pVCpu->iem.s.cInstructions;6321 AssertMsg(RT_IS_POWER_OF_TWO(cPollRate + 1), ("%#x\n", cPollRate));6322 Assert(cMaxInstructions > 0);6323 6324 /*6325 * See if there is an interrupt pending in TRPM, inject it if we can.6326 */6327 /** @todo What if we are injecting an exception and not an interrupt? Is that6328 * possible here? For now we assert it is indeed only an interrupt. */6329 if (!TRPMHasTrap(pVCpu))6330 { /* likely */ }6331 else6332 {6333 VBOXSTRICTRC rcStrict = iemExecInjectPendingTrap(pVCpu);6334 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6335 { /*likely */ }6336 else6337 return rcStrict;6338 }6339 6340 /*6341 * Initial decoder init w/ prefetch, then setup setjmp.6342 */6343 VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);6344 if (rcStrict == VINF_SUCCESS)6345 {6346 #ifdef IEM_WITH_SETJMP6347 pVCpu->iem.s.cActiveMappings = 0; /** @todo wtf? */6348 IEM_TRY_SETJMP(pVCpu, rcStrict)6349 #endif6350 {6351 /*6352 * The run loop. We limit ourselves to 4096 instructions right now.6353 */6354 uint32_t cMaxInstructionsGccStupidity = cMaxInstructions;6355 PVMCC pVM = pVCpu->CTX_SUFF(pVM);6356 for (;;)6357 {6358 /*6359 * Log the state.6360 */6361 #ifdef LOG_ENABLED6362 iemLogCurInstr(pVCpu, true, "IEMExecLots");6363 #endif6364 6365 /*6366 * Do the decoding and emulation.6367 */6368 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);6369 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6370 #ifdef VBOX_STRICT6371 CPUMAssertGuestRFlagsCookie(pVM, pVCpu);6372 #endif6373 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6374 {6375 Assert(pVCpu->iem.s.cActiveMappings == 0);6376 pVCpu->iem.s.cInstructions++;6377 6378 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6379 /* Perform any VMX nested-guest instruction boundary actions. */6380 uint64_t fCpu = pVCpu->fLocalForcedActions;6381 if (!(fCpu & ( VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER6382 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))6383 { /* likely */ }6384 else6385 {6386 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6387 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6388 fCpu = pVCpu->fLocalForcedActions;6389 else6390 {6391 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6392 break;6393 }6394 }6395 #endif6396 if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))6397 {6398 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX6399 uint64_t fCpu = pVCpu->fLocalForcedActions;6400 #endif6401 fCpu &= VMCPU_FF_ALL_MASK & ~( VMCPU_FF_PGM_SYNC_CR36402 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL6403 | VMCPU_FF_TLB_FLUSH6404 | VMCPU_FF_UNHALT );6405 6406 if (RT_LIKELY( ( !fCpu6407 || ( !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))6408 && !pVCpu->cpum.GstCtx.rflags.Bits.u1IF) )6409 && !VM_FF_IS_ANY_SET(pVM, VM_FF_ALL_MASK) ))6410 {6411 if (--cMaxInstructionsGccStupidity > 0)6412 {6413 /* Poll timers every now an then according to the caller's specs. */6414 if ( (cMaxInstructionsGccStupidity & cPollRate) != 06415 || !TMTimerPollBool(pVM, pVCpu))6416 {6417 Assert(pVCpu->iem.s.cActiveMappings == 0);6418 iemReInitDecoder(pVCpu);6419 continue;6420 }6421 }6422 }6423 }6424 Assert(pVCpu->iem.s.cActiveMappings == 0);6425 }6426 else if (pVCpu->iem.s.cActiveMappings > 0)6427 iemMemRollback(pVCpu);6428 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6429 break;6430 }6431 }6432 #ifdef IEM_WITH_SETJMP6433 IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);6434 {6435 if (pVCpu->iem.s.cActiveMappings > 0)6436 iemMemRollback(pVCpu);6437 # if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)6438 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6439 # endif6440 pVCpu->iem.s.cLongJumps++;6441 }6442 IEM_CATCH_LONGJMP_END(pVCpu);6443 #endif6444 6445 /*6446 * Assert hidden register sanity (also done in iemInitDecoder and iemReInitDecoder).6447 */6448 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));6449 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));6450 }6451 else6452 {6453 if (pVCpu->iem.s.cActiveMappings > 0)6454 iemMemRollback(pVCpu);6455 6456 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)6457 /*6458 * When a nested-guest causes an exception intercept (e.g. #PF) when fetching6459 * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.6460 */6461 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6462 #endif6463 }6464 6465 /*6466 * Maybe re-enter raw-mode and log.6467 */6468 if (rcStrict != VINF_SUCCESS)6469 LogFlow(("IEMExecLots: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc\n",6470 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp, pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict)));6471 if (pcInstructions)6472 *pcInstructions = pVCpu->iem.s.cInstructions - cInstructionsAtStart;6473 return rcStrict;6474 }6475 6476 6477 /**6478 * Interface used by EMExecuteExec, does exit statistics and limits.6479 *6480 * @returns Strict VBox status code.6481 * @param pVCpu The cross context virtual CPU structure.6482 * @param fWillExit To be defined.6483 * @param cMinInstructions Minimum number of instructions to execute before checking for FFs.6484 * @param cMaxInstructions Maximum number of instructions to execute.6485 * @param cMaxInstructionsWithoutExits6486 * The max number of instructions without exits.6487 * @param pStats Where to return statistics.6488 */6489 VMM_INT_DECL(VBOXSTRICTRC)6490 IEMExecForExits(PVMCPUCC pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions,6491 uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats)6492 {6493 NOREF(fWillExit); /** @todo define flexible exit crits */6494 6495 /*6496 * Initialize return stats.6497 */6498 pStats->cInstructions = 0;6499 pStats->cExits = 0;6500 pStats->cMaxExitDistance = 0;6501 pStats->cReserved = 0;6502 6503 /*6504 * Initial decoder init w/ prefetch, then setup setjmp.6505 */6506 VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, 0 /*fExecOpts*/);6507 if (rcStrict == VINF_SUCCESS)6508 {6509 #ifdef IEM_WITH_SETJMP6510 pVCpu->iem.s.cActiveMappings = 0; /** @todo wtf?!? */6511 IEM_TRY_SETJMP(pVCpu, rcStrict)6512 #endif6513 {6514 #ifdef IN_RING06515 bool const fCheckPreemptionPending = !RTThreadPreemptIsPossible() || !RTThreadPreemptIsEnabled(NIL_RTTHREAD);6516 #endif6517 uint32_t cInstructionSinceLastExit = 0;6518 6519 /*6520 * The run loop. We limit ourselves to 4096 instructions right now.6521 */6522 PVM pVM = pVCpu->CTX_SUFF(pVM);6523 for (;;)6524 {6525 /*6526 * Log the state.6527 */6528 #ifdef LOG_ENABLED6529 iemLogCurInstr(pVCpu, true, "IEMExecForExits");6530 #endif6531 6532 /*6533 * Do the decoding and emulation.6534 */6535 uint32_t const cPotentialExits = pVCpu->iem.s.cPotentialExits;6536 6537 uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);6538 rcStrict = FNIEMOP_CALL(g_apfnIemInterpretOnlyOneByteMap[b]);6539 6540 if ( cPotentialExits != pVCpu->iem.s.cPotentialExits6541 && cInstructionSinceLastExit > 0 /* don't count the first */ )6542 {6543 pStats->cExits += 1;6544 if (cInstructionSinceLastExit > pStats->cMaxExitDistance)6545 pStats->cMaxExitDistance = cInstructionSinceLastExit;6546 cInstructionSinceLastExit = 0;6547 }6548 6549 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6550 {6551 Assert(pVCpu->iem.s.cActiveMappings == 0);6552 pVCpu->iem.s.cInstructions++;6553 pStats->cInstructions++;6554 cInstructionSinceLastExit++;6555 6556 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6557 /* Perform any VMX nested-guest instruction boundary actions. */6558 uint64_t fCpu = pVCpu->fLocalForcedActions;6559 if (!(fCpu & ( VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER6560 | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW)))6561 { /* likely */ }6562 else6563 {6564 rcStrict = iemHandleNestedInstructionBoundaryFFs(pVCpu, rcStrict);6565 if (RT_LIKELY(rcStrict == VINF_SUCCESS))6566 fCpu = pVCpu->fLocalForcedActions;6567 else6568 {6569 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6570 break;6571 }6572 }6573 #endif6574 if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))6575 {6576 #ifndef VBOX_WITH_NESTED_HWVIRT_VMX6577 uint64_t fCpu = pVCpu->fLocalForcedActions;6578 #endif6579 fCpu &= VMCPU_FF_ALL_MASK & ~( VMCPU_FF_PGM_SYNC_CR36580 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL6581 | VMCPU_FF_TLB_FLUSH6582 | VMCPU_FF_UNHALT );6583 if (RT_LIKELY( ( ( !fCpu6584 || ( !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))6585 && !pVCpu->cpum.GstCtx.rflags.Bits.u1IF))6586 && !VM_FF_IS_ANY_SET(pVM, VM_FF_ALL_MASK) )6587 || pStats->cInstructions < cMinInstructions))6588 {6589 if (pStats->cInstructions < cMaxInstructions)6590 {6591 if (cInstructionSinceLastExit <= cMaxInstructionsWithoutExits)6592 {6593 #ifdef IN_RING06594 if ( !fCheckPreemptionPending6595 || !RTThreadPreemptIsPending(NIL_RTTHREAD))6596 #endif6597 {6598 Assert(pVCpu->iem.s.cActiveMappings == 0);6599 iemReInitDecoder(pVCpu);6600 continue;6601 }6602 #ifdef IN_RING06603 rcStrict = VINF_EM_RAW_INTERRUPT;6604 break;6605 #endif6606 }6607 }6608 }6609 Assert(!(fCpu & VMCPU_FF_IEM));6610 }6611 Assert(pVCpu->iem.s.cActiveMappings == 0);6612 }6613 else if (pVCpu->iem.s.cActiveMappings > 0)6614 iemMemRollback(pVCpu);6615 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6616 break;6617 }6618 }6619 #ifdef IEM_WITH_SETJMP6620 IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);6621 {6622 if (pVCpu->iem.s.cActiveMappings > 0)6623 iemMemRollback(pVCpu);6624 pVCpu->iem.s.cLongJumps++;6625 }6626 IEM_CATCH_LONGJMP_END(pVCpu);6627 #endif6628 6629 /*6630 * Assert hidden register sanity (also done in iemInitDecoder and iemReInitDecoder).6631 */6632 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));6633 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));6634 }6635 else6636 {6637 if (pVCpu->iem.s.cActiveMappings > 0)6638 iemMemRollback(pVCpu);6639 6640 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)6641 /*6642 * When a nested-guest causes an exception intercept (e.g. #PF) when fetching6643 * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.6644 */6645 rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);6646 #endif6647 }6648 6649 /*6650 * Maybe re-enter raw-mode and log.6651 */6652 if (rcStrict != VINF_SUCCESS)6653 LogFlow(("IEMExecForExits: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc; ins=%u exits=%u maxdist=%u\n",6654 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp,6655 pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict), pStats->cInstructions, pStats->cExits, pStats->cMaxExitDistance));6656 return rcStrict;6657 }6658 6659 6660 /**6661 * Injects a trap, fault, abort, software interrupt or external interrupt.6662 *6663 * The parameter list matches TRPMQueryTrapAll pretty closely.6664 *6665 * @returns Strict VBox status code.6666 * @param pVCpu The cross context virtual CPU structure of the calling EMT.6667 * @param u8TrapNo The trap number.6668 * @param enmType What type is it (trap/fault/abort), software6669 * interrupt or hardware interrupt.6670 * @param uErrCode The error code if applicable.6671 * @param uCr2 The CR2 value if applicable.6672 * @param cbInstr The instruction length (only relevant for6673 * software interrupts).6674 * @note x86 specific, but difficult to move due to iemInitDecoder dep.6675 */6676 VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2,6677 uint8_t cbInstr)6678 {6679 iemInitDecoder(pVCpu, 0 /*fExecOpts*/); /** @todo wrong init function! */6680 #ifdef DBGFTRACE_ENABLED6681 RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "IEMInjectTrap: %x %d %x %llx",6682 u8TrapNo, enmType, uErrCode, uCr2);6683 #endif6684 6685 uint32_t fFlags;6686 switch (enmType)6687 {6688 case TRPM_HARDWARE_INT:6689 Log(("IEMInjectTrap: %#4x ext\n", u8TrapNo));6690 fFlags = IEM_XCPT_FLAGS_T_EXT_INT;6691 uErrCode = uCr2 = 0;6692 break;6693 6694 case TRPM_SOFTWARE_INT:6695 Log(("IEMInjectTrap: %#4x soft\n", u8TrapNo));6696 fFlags = IEM_XCPT_FLAGS_T_SOFT_INT;6697 uErrCode = uCr2 = 0;6698 break;6699 6700 case TRPM_TRAP:6701 case TRPM_NMI: /** @todo Distinguish NMI from exception 2. */6702 Log(("IEMInjectTrap: %#4x trap err=%#x cr2=%#RGv\n", u8TrapNo, uErrCode, uCr2));6703 fFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;6704 if (u8TrapNo == X86_XCPT_PF)6705 fFlags |= IEM_XCPT_FLAGS_CR2;6706 switch (u8TrapNo)6707 {6708 case X86_XCPT_DF:6709 case X86_XCPT_TS:6710 case X86_XCPT_NP:6711 case X86_XCPT_SS:6712 case X86_XCPT_PF:6713 case X86_XCPT_AC:6714 case X86_XCPT_GP:6715 fFlags |= IEM_XCPT_FLAGS_ERR;6716 break;6717 }6718 break;6719 6720 IEM_NOT_REACHED_DEFAULT_CASE_RET();6721 }6722 6723 VBOXSTRICTRC rcStrict = iemRaiseXcptOrInt(pVCpu, cbInstr, u8TrapNo, fFlags, uErrCode, uCr2);6724 6725 if (pVCpu->iem.s.cActiveMappings > 0)6726 iemMemRollback(pVCpu);6727 6728 return rcStrict;6729 }6730 6731 6732 /**6733 * Injects the active TRPM event.6734 *6735 * @returns Strict VBox status code.6736 * @param pVCpu The cross context virtual CPU structure.6737 */6738 VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrpmEvent(PVMCPUCC pVCpu)6739 {6740 #ifndef IEM_IMPLEMENTS_TASKSWITCH6741 IEM_RETURN_ASPECT_NOT_IMPLEMENTED_LOG(("Event injection\n"));6742 #else6743 uint8_t u8TrapNo;6744 TRPMEVENT enmType;6745 uint32_t uErrCode;6746 RTGCUINTPTR uCr2;6747 uint8_t cbInstr;6748 int rc = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2, &cbInstr, NULL /* fIcebp */);6749 if (RT_FAILURE(rc))6750 return rc;6751 6752 /** @todo r=ramshankar: Pass ICEBP info. to IEMInjectTrap() below and handle6753 * ICEBP \#DB injection as a special case. */6754 VBOXSTRICTRC rcStrict = IEMInjectTrap(pVCpu, u8TrapNo, enmType, uErrCode, uCr2, cbInstr);6755 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM6756 if (rcStrict == VINF_SVM_VMEXIT)6757 rcStrict = VINF_SUCCESS;6758 #endif6759 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX6760 if (rcStrict == VINF_VMX_VMEXIT)6761 rcStrict = VINF_SUCCESS;6762 #endif6763 /** @todo Are there any other codes that imply the event was successfully6764 * delivered to the guest? See @bugref{6607}. */6765 if ( rcStrict == VINF_SUCCESS6766 || rcStrict == VINF_IEM_RAISED_XCPT)6767 TRPMResetTrap(pVCpu);6768 6769 return rcStrict;6770 #endif6771 }6772 6773 6774 VMM_INT_DECL(int) IEMBreakpointSet(PVM pVM, RTGCPTR GCPtrBp)6775 {6776 RT_NOREF_PV(pVM); RT_NOREF_PV(GCPtrBp);6777 return VERR_NOT_IMPLEMENTED;6778 }6779 6780 6781 VMM_INT_DECL(int) IEMBreakpointClear(PVM pVM, RTGCPTR GCPtrBp)6782 {6783 RT_NOREF_PV(pVM); RT_NOREF_PV(GCPtrBp);6784 return VERR_NOT_IMPLEMENTED;6785 }6786 6787 #ifdef IN_RING36788 6789 /**6790 * Handles the unlikely and probably fatal merge cases.6791 *6792 * @returns Merged status code.6793 * @param rcStrict Current EM status code.6794 * @param rcStrictCommit The IOM I/O or MMIO write commit status to merge6795 * with @a rcStrict.6796 * @param iMemMap The memory mapping index. For error reporting only.6797 * @param pVCpu The cross context virtual CPU structure of the calling6798 * thread, for error reporting only.6799 */6800 DECL_NO_INLINE(static, VBOXSTRICTRC) iemR3MergeStatusSlow(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit,6801 unsigned iMemMap, PVMCPUCC pVCpu)6802 {6803 if (RT_FAILURE_NP(rcStrict))6804 return rcStrict;6805 6806 if (RT_FAILURE_NP(rcStrictCommit))6807 return rcStrictCommit;6808 6809 if (rcStrict == rcStrictCommit)6810 return rcStrictCommit;6811 6812 AssertLogRelMsgFailed(("rcStrictCommit=%Rrc rcStrict=%Rrc iMemMap=%u fAccess=%#x FirstPg=%RGp LB %u SecondPg=%RGp LB %u\n",6813 VBOXSTRICTRC_VAL(rcStrictCommit), VBOXSTRICTRC_VAL(rcStrict), iMemMap,6814 pVCpu->iem.s.aMemMappings[iMemMap].fAccess,6815 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst,6816 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond));6817 return VERR_IOM_FF_STATUS_IPE;6818 }6819 6820 6821 /**6822 * Helper for IOMR3ProcessForceFlag.6823 *6824 * @returns Merged status code.6825 * @param rcStrict Current EM status code.6826 * @param rcStrictCommit The IOM I/O or MMIO write commit status to merge6827 * with @a rcStrict.6828 * @param iMemMap The memory mapping index. For error reporting only.6829 * @param pVCpu The cross context virtual CPU structure of the calling6830 * thread, for error reporting only.6831 */6832 DECLINLINE(VBOXSTRICTRC) iemR3MergeStatus(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit, unsigned iMemMap, PVMCPUCC pVCpu)6833 {6834 /* Simple. */6835 if (RT_LIKELY(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RAW_TO_R3))6836 return rcStrictCommit;6837 6838 if (RT_LIKELY(rcStrictCommit == VINF_SUCCESS))6839 return rcStrict;6840 6841 /* EM scheduling status codes. */6842 if (RT_LIKELY( rcStrict >= VINF_EM_FIRST6843 && rcStrict <= VINF_EM_LAST))6844 {6845 if (RT_LIKELY( rcStrictCommit >= VINF_EM_FIRST6846 && rcStrictCommit <= VINF_EM_LAST))6847 return rcStrict < rcStrictCommit ? rcStrict : rcStrictCommit;6848 }6849 6850 /* Unlikely */6851 return iemR3MergeStatusSlow(rcStrict, rcStrictCommit, iMemMap, pVCpu);6852 }6853 6854 6855 /**6856 * Called by force-flag handling code when VMCPU_FF_IEM is set.6857 *6858 * @returns Merge between @a rcStrict and what the commit operation returned.6859 * @param pVM The cross context VM structure.6860 * @param pVCpu The cross context virtual CPU structure of the calling EMT.6861 * @param rcStrict The status code returned by ring-0 or raw-mode.6862 */6863 VMMR3_INT_DECL(VBOXSTRICTRC) IEMR3ProcessForceFlag(PVM pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict)6864 {6865 /*6866 * Reset the pending commit.6867 */6868 AssertMsg( (pVCpu->iem.s.aMemMappings[0].fAccess | pVCpu->iem.s.aMemMappings[1].fAccess | pVCpu->iem.s.aMemMappings[2].fAccess)6869 & (IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND),6870 ("%#x %#x %#x\n",6871 pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemMappings[2].fAccess));6872 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_IEM);6873 6874 /*6875 * Commit the pending bounce buffers (usually just one).6876 */6877 unsigned cBufs = 0;6878 unsigned iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);6879 while (iMemMap-- > 0)6880 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & (IEM_ACCESS_PENDING_R3_WRITE_1ST | IEM_ACCESS_PENDING_R3_WRITE_2ND))6881 {6882 Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_TYPE_WRITE);6883 Assert(pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_BOUNCE_BUFFERED);6884 Assert(!pVCpu->iem.s.aMemBbMappings[iMemMap].fUnassigned);6885 6886 uint16_t const cbFirst = pVCpu->iem.s.aMemBbMappings[iMemMap].cbFirst;6887 uint16_t const cbSecond = pVCpu->iem.s.aMemBbMappings[iMemMap].cbSecond;6888 uint8_t const *pbBuf = &pVCpu->iem.s.aBounceBuffers[iMemMap].ab[0];6889 6890 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_PENDING_R3_WRITE_1ST)6891 {6892 VBOXSTRICTRC rcStrictCommit1 = PGMPhysWrite(pVM,6893 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst,6894 pbBuf,6895 cbFirst,6896 PGMACCESSORIGIN_IEM);6897 rcStrict = iemR3MergeStatus(rcStrict, rcStrictCommit1, iMemMap, pVCpu);6898 Log(("IEMR3ProcessForceFlag: iMemMap=%u GCPhysFirst=%RGp LB %#x %Rrc => %Rrc\n",6899 iMemMap, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysFirst, cbFirst,6900 VBOXSTRICTRC_VAL(rcStrictCommit1), VBOXSTRICTRC_VAL(rcStrict)));6901 }6902 6903 if (pVCpu->iem.s.aMemMappings[iMemMap].fAccess & IEM_ACCESS_PENDING_R3_WRITE_2ND)6904 {6905 VBOXSTRICTRC rcStrictCommit2 = PGMPhysWrite(pVM,6906 pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond,6907 pbBuf + cbFirst,6908 cbSecond,6909 PGMACCESSORIGIN_IEM);6910 rcStrict = iemR3MergeStatus(rcStrict, rcStrictCommit2, iMemMap, pVCpu);6911 Log(("IEMR3ProcessForceFlag: iMemMap=%u GCPhysSecond=%RGp LB %#x %Rrc => %Rrc\n",6912 iMemMap, pVCpu->iem.s.aMemBbMappings[iMemMap].GCPhysSecond, cbSecond,6913 VBOXSTRICTRC_VAL(rcStrictCommit2), VBOXSTRICTRC_VAL(rcStrict)));6914 }6915 cBufs++;6916 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;6917 }6918 6919 AssertMsg(cBufs > 0 && cBufs == pVCpu->iem.s.cActiveMappings,6920 ("cBufs=%u cActiveMappings=%u - %#x %#x %#x\n", cBufs, pVCpu->iem.s.cActiveMappings,6921 pVCpu->iem.s.aMemMappings[0].fAccess, pVCpu->iem.s.aMemMappings[1].fAccess, pVCpu->iem.s.aMemMappings[2].fAccess));6922 pVCpu->iem.s.cActiveMappings = 0;6923 return rcStrict;6924 }6925 6926 #endif /* IN_RING3 */6927
Note:
See TracChangeset
for help on using the changeset viewer.