VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/EMAll.cpp@ 45991

Last change on this file since 45991 was 45907, checked in by vboxsync, 12 years ago

VBOX_WITH_IEM bitrot and stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 139.5 KB
Line 
1/* $Id: EMAll.cpp 45907 2013-05-06 12:54:22Z vboxsync $ */
2/** @file
3 * EM - Execution Monitor(/Manager) - All contexts
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_EM
22#include <VBox/vmm/em.h>
23#include <VBox/vmm/mm.h>
24#include <VBox/vmm/selm.h>
25#include <VBox/vmm/patm.h>
26#include <VBox/vmm/csam.h>
27#include <VBox/vmm/pgm.h>
28#ifdef VBOX_WITH_IEM
29# include <VBox/vmm/iem.h>
30#endif
31#include <VBox/vmm/iom.h>
32#include <VBox/vmm/stam.h>
33#include "EMInternal.h"
34#include <VBox/vmm/vm.h>
35#include <VBox/vmm/vmm.h>
36#include <VBox/vmm/hm.h>
37#include <VBox/vmm/tm.h>
38#include <VBox/vmm/pdmapi.h>
39#include <VBox/param.h>
40#include <VBox/err.h>
41#include <VBox/dis.h>
42#include <VBox/disopcode.h>
43#include <VBox/log.h>
44#include "internal/pgm.h"
45#include <iprt/assert.h>
46#include <iprt/asm.h>
47#include <iprt/string.h>
48
49#ifndef IN_RC
50#undef VBOX_WITH_IEM
51#endif
52#ifdef VBOX_WITH_IEM
53//# define VBOX_COMPARE_IEM_AND_EM /* debugging... */
54//# define VBOX_SAME_AS_EM
55//# define VBOX_COMPARE_IEM_LAST
56#endif
57
58#ifdef VBOX_WITH_RAW_RING1
59# define EM_EMULATE_SMSW
60#endif
61
62
63/*******************************************************************************
64* Defined Constants And Macros *
65*******************************************************************************/
66/** @def EM_ASSERT_FAULT_RETURN
67 * Safety check.
68 *
69 * Could in theory misfire on a cross page boundary access...
70 *
71 * Currently disabled because the CSAM (+ PATM) patch monitoring occasionally
72 * turns up an alias page instead of the original faulting one and annoying the
73 * heck out of anyone running a debug build. See @bugref{2609} and @bugref{1931}.
74 */
75#if 0
76# define EM_ASSERT_FAULT_RETURN(expr, rc) AssertReturn(expr, rc)
77#else
78# define EM_ASSERT_FAULT_RETURN(expr, rc) do { } while (0)
79#endif
80
81
82/*******************************************************************************
83* Internal Functions *
84*******************************************************************************/
85#if !defined(VBOX_WITH_IEM) || defined(VBOX_COMPARE_IEM_AND_EM)
86DECLINLINE(VBOXSTRICTRC) emInterpretInstructionCPUOuter(PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame,
87 RTGCPTR pvFault, EMCODETYPE enmCodeType, uint32_t *pcbSize);
88#endif
89
90
91/*******************************************************************************
92* Global Variables *
93*******************************************************************************/
94#ifdef VBOX_COMPARE_IEM_AND_EM
95static const uint32_t g_fInterestingFFs = VMCPU_FF_TO_R3
96 | VMCPU_FF_CSAM_PENDING_ACTION | VMCPU_FF_CSAM_SCAN_PAGE | VMCPU_FF_INHIBIT_INTERRUPTS
97 | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_TSS | VMCPU_FF_TRPM_SYNC_IDT
98 | VMCPU_FF_TLB_FLUSH | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL;
99static uint32_t g_fIncomingFFs;
100static CPUMCTX g_IncomingCtx;
101static bool g_fIgnoreRaxRdx = false;
102
103static uint32_t g_fEmFFs;
104static CPUMCTX g_EmCtx;
105static uint8_t g_abEmWrote[256];
106static size_t g_cbEmWrote;
107
108static uint32_t g_fIemFFs;
109static CPUMCTX g_IemCtx;
110extern uint8_t g_abIemWrote[256];
111#if defined(VBOX_COMPARE_IEM_FIRST) || defined(VBOX_COMPARE_IEM_LAST)
112extern size_t g_cbIemWrote;
113#else
114static size_t g_cbIemWrote;
115#endif
116#endif
117
118
119/**
120 * Get the current execution manager status.
121 *
122 * @returns Current status.
123 * @param pVCpu Pointer to the VMCPU.
124 */
125VMM_INT_DECL(EMSTATE) EMGetState(PVMCPU pVCpu)
126{
127 return pVCpu->em.s.enmState;
128}
129
130/**
131 * Sets the current execution manager status. (use only when you know what you're doing!)
132 *
133 * @param pVCpu Pointer to the VMCPU.
134 */
135VMM_INT_DECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState)
136{
137 /* Only allowed combination: */
138 Assert(pVCpu->em.s.enmState == EMSTATE_WAIT_SIPI && enmNewState == EMSTATE_HALTED);
139 pVCpu->em.s.enmState = enmNewState;
140}
141
142
143/**
144 * Sets the PC for which interrupts should be inhibited.
145 *
146 * @param pVCpu Pointer to the VMCPU.
147 * @param PC The PC.
148 */
149VMMDECL(void) EMSetInhibitInterruptsPC(PVMCPU pVCpu, RTGCUINTPTR PC)
150{
151 pVCpu->em.s.GCPtrInhibitInterrupts = PC;
152 VMCPU_FF_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
153}
154
155
156/**
157 * Gets the PC for which interrupts should be inhibited.
158 *
159 * There are a few instructions which inhibits or delays interrupts
160 * for the instruction following them. These instructions are:
161 * - STI
162 * - MOV SS, r/m16
163 * - POP SS
164 *
165 * @returns The PC for which interrupts should be inhibited.
166 * @param pVCpu Pointer to the VMCPU.
167 *
168 */
169VMMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVMCPU pVCpu)
170{
171 return pVCpu->em.s.GCPtrInhibitInterrupts;
172}
173
174
175/**
176 * Prepare an MWAIT - essentials of the MONITOR instruction.
177 *
178 * @returns VINF_SUCCESS
179 * @param pVCpu The current CPU.
180 * @param rax The content of RAX.
181 * @param rcx The content of RCX.
182 * @param rdx The content of RDX.
183 */
184VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx)
185{
186 pVCpu->em.s.MWait.uMonitorRAX = rax;
187 pVCpu->em.s.MWait.uMonitorRCX = rcx;
188 pVCpu->em.s.MWait.uMonitorRDX = rdx;
189 pVCpu->em.s.MWait.fWait |= EMMWAIT_FLAG_MONITOR_ACTIVE;
190 /** @todo Complete MONITOR implementation. */
191 return VINF_SUCCESS;
192}
193
194
195/**
196 * Performs an MWAIT.
197 *
198 * @returns VINF_SUCCESS
199 * @param pVCpu The current CPU.
200 * @param rax The content of RAX.
201 * @param rcx The content of RCX.
202 */
203VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx)
204{
205 pVCpu->em.s.MWait.uMWaitRAX = rax;
206 pVCpu->em.s.MWait.uMWaitRCX = rcx;
207 pVCpu->em.s.MWait.fWait |= EMMWAIT_FLAG_ACTIVE;
208 if (rcx)
209 pVCpu->em.s.MWait.fWait |= EMMWAIT_FLAG_BREAKIRQIF0;
210 else
211 pVCpu->em.s.MWait.fWait &= ~EMMWAIT_FLAG_BREAKIRQIF0;
212 /** @todo not completely correct?? */
213 return VINF_EM_HALT;
214}
215
216
217
218/**
219 * Determine if we should continue after encountering a hlt or mwait
220 * instruction.
221 *
222 * Clears MWAIT flags if returning @c true.
223 *
224 * @returns boolean
225 * @param pVCpu Pointer to the VMCPU.
226 * @param pCtx Current CPU context.
227 */
228VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx)
229{
230 if ( pCtx->eflags.Bits.u1IF
231 || ( (pVCpu->em.s.MWait.fWait & (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0))
232 == (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0)) )
233 {
234 pVCpu->em.s.MWait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0);
235 return !!VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC));
236 }
237
238 return false;
239}
240
241
242/**
243 * Locks REM execution to a single VCPU.
244 *
245 * @param pVM Pointer to the VM.
246 */
247VMMDECL(void) EMRemLock(PVM pVM)
248{
249#ifdef VBOX_WITH_REM
250 if (!PDMCritSectIsInitialized(&pVM->em.s.CritSectREM))
251 return; /* early init */
252
253 Assert(!PGMIsLockOwner(pVM));
254 Assert(!IOMIsLockWriteOwner(pVM));
255 int rc = PDMCritSectEnter(&pVM->em.s.CritSectREM, VERR_SEM_BUSY);
256 AssertRCSuccess(rc);
257#endif
258}
259
260
261/**
262 * Unlocks REM execution
263 *
264 * @param pVM Pointer to the VM.
265 */
266VMMDECL(void) EMRemUnlock(PVM pVM)
267{
268#ifdef VBOX_WITH_REM
269 if (!PDMCritSectIsInitialized(&pVM->em.s.CritSectREM))
270 return; /* early init */
271
272 PDMCritSectLeave(&pVM->em.s.CritSectREM);
273#endif
274}
275
276
277/**
278 * Check if this VCPU currently owns the REM lock.
279 *
280 * @returns bool owner/not owner
281 * @param pVM Pointer to the VM.
282 */
283VMMDECL(bool) EMRemIsLockOwner(PVM pVM)
284{
285#ifdef VBOX_WITH_REM
286 if (!PDMCritSectIsInitialized(&pVM->em.s.CritSectREM))
287 return true; /* early init */
288
289 return PDMCritSectIsOwner(&pVM->em.s.CritSectREM);
290#else
291 return true;
292#endif
293}
294
295
296/**
297 * Try to acquire the REM lock.
298 *
299 * @returns VBox status code
300 * @param pVM Pointer to the VM.
301 */
302VMM_INT_DECL(int) EMRemTryLock(PVM pVM)
303{
304#ifdef VBOX_WITH_REM
305 if (!PDMCritSectIsInitialized(&pVM->em.s.CritSectREM))
306 return VINF_SUCCESS; /* early init */
307
308 return PDMCritSectTryEnter(&pVM->em.s.CritSectREM);
309#else
310 return VINF_SUCCESS;
311#endif
312}
313
314
315/**
316 * @callback_method_impl{FNDISREADBYTES}
317 */
318static DECLCALLBACK(int) emReadBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
319{
320 PVMCPU pVCpu = (PVMCPU)pDis->pvUser;
321#if defined(IN_RC) || defined(IN_RING3)
322 PVM pVM = pVCpu->CTX_SUFF(pVM);
323#endif
324 RTUINTPTR uSrcAddr = pDis->uInstrAddr + offInstr;
325 int rc;
326
327 /*
328 * Figure how much we can or must read.
329 */
330 size_t cbToRead = PAGE_SIZE - (uSrcAddr & PAGE_OFFSET_MASK);
331 if (cbToRead > cbMaxRead)
332 cbToRead = cbMaxRead;
333 else if (cbToRead < cbMinRead)
334 cbToRead = cbMinRead;
335
336#if defined(VBOX_WITH_RAW_MODE) && (defined(IN_RC) || defined(IN_RING3))
337 /*
338 * We might be called upon to interpret an instruction in a patch.
339 */
340 if (PATMIsPatchGCAddr(pVCpu->CTX_SUFF(pVM), uSrcAddr))
341 {
342# ifdef IN_RC
343 memcpy(&pDis->abInstr[offInstr], (void *)(uintptr_t)uSrcAddr, cbToRead);
344# else
345 memcpy(&pDis->abInstr[offInstr], PATMR3GCPtrToHCPtr(pVCpu->CTX_SUFF(pVM), uSrcAddr), cbToRead);
346# endif
347 rc = VINF_SUCCESS;
348 }
349 else
350#endif
351 {
352# ifdef IN_RC
353 /*
354 * Try access it thru the shadow page tables first. Fall back on the
355 * slower PGM method if it fails because the TLB or page table was
356 * modified recently.
357 */
358 rc = MMGCRamRead(pVCpu->pVMRC, &pDis->abInstr[offInstr], (void *)(uintptr_t)uSrcAddr, cbToRead);
359 if (rc == VERR_ACCESS_DENIED && cbToRead > cbMinRead)
360 {
361 cbToRead = cbMinRead;
362 rc = MMGCRamRead(pVCpu->pVMRC, &pDis->abInstr[offInstr], (void *)(uintptr_t)uSrcAddr, cbToRead);
363 }
364 if (rc == VERR_ACCESS_DENIED)
365#endif
366 {
367 rc = PGMPhysSimpleReadGCPtr(pVCpu, &pDis->abInstr[offInstr], uSrcAddr, cbToRead);
368 if (RT_FAILURE(rc))
369 {
370 if (cbToRead > cbMinRead)
371 {
372 cbToRead = cbMinRead;
373 rc = PGMPhysSimpleReadGCPtr(pVCpu, &pDis->abInstr[offInstr], uSrcAddr, cbToRead);
374 }
375 if (RT_FAILURE(rc))
376 {
377#ifndef IN_RC
378 /*
379 * If we fail to find the page via the guest's page tables
380 * we invalidate the page in the host TLB (pertaining to
381 * the guest in the NestedPaging case). See @bugref{6043}.
382 */
383 if (rc == VERR_PAGE_TABLE_NOT_PRESENT || rc == VERR_PAGE_NOT_PRESENT)
384 {
385 HMInvalidatePage(pVCpu, uSrcAddr);
386 if (((uSrcAddr + cbToRead - 1) >> PAGE_SHIFT) != (uSrcAddr >> PAGE_SHIFT))
387 HMInvalidatePage(pVCpu, uSrcAddr + cbToRead - 1);
388 }
389#endif
390 }
391 }
392 }
393 }
394
395 pDis->cbCachedInstr = offInstr + (uint8_t)cbToRead;
396 return rc;
397}
398
399
400DECLINLINE(int) emDisCoreOne(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
401{
402 return DISInstrWithReader(InstrGC, (DISCPUMODE)pDis->uCpuMode, emReadBytes, pVCpu, pDis, pOpsize);
403}
404
405
406/**
407 * Disassembles the current instruction.
408 *
409 * @returns VBox status code, see SELMToFlatEx and EMInterpretDisasOneEx for
410 * details.
411 *
412 * @param pVM Pointer to the VM.
413 * @param pVCpu Pointer to the VMCPU.
414 * @param pDis Where to return the parsed instruction info.
415 * @param pcbInstr Where to return the instruction size. (optional)
416 */
417VMM_INT_DECL(int) EMInterpretDisasCurrent(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, unsigned *pcbInstr)
418{
419 PCPUMCTXCORE pCtxCore = CPUMCTX2CORE(CPUMQueryGuestCtxPtr(pVCpu));
420 RTGCPTR GCPtrInstr;
421#if 0
422 int rc = SELMToFlatEx(pVCpu, DISSELREG_CS, pCtxCore, pCtxCore->rip, 0, &GCPtrInstr);
423#else
424/** @todo Get the CPU mode as well while we're at it! */
425 int rc = SELMValidateAndConvertCSAddr(pVCpu, pCtxCore->eflags, pCtxCore->ss.Sel, pCtxCore->cs.Sel, &pCtxCore->cs,
426 pCtxCore->rip, &GCPtrInstr);
427#endif
428 if (RT_FAILURE(rc))
429 {
430 Log(("EMInterpretDisasOne: Failed to convert %RTsel:%RGv (cpl=%d) - rc=%Rrc !!\n",
431 pCtxCore->cs.Sel, (RTGCPTR)pCtxCore->rip, pCtxCore->ss.Sel & X86_SEL_RPL, rc));
432 return rc;
433 }
434 return EMInterpretDisasOneEx(pVM, pVCpu, (RTGCUINTPTR)GCPtrInstr, pCtxCore, pDis, pcbInstr);
435}
436
437
438/**
439 * Disassembles one instruction.
440 *
441 * This is used by internally by the interpreter and by trap/access handlers.
442 *
443 * @returns VBox status code.
444 *
445 * @param pVM Pointer to the VM.
446 * @param pVCpu Pointer to the VMCPU.
447 * @param GCPtrInstr The flat address of the instruction.
448 * @param pCtxCore The context core (used to determine the cpu mode).
449 * @param pDis Where to return the parsed instruction info.
450 * @param pcbInstr Where to return the instruction size. (optional)
451 */
452VMM_INT_DECL(int) EMInterpretDisasOneEx(PVM pVM, PVMCPU pVCpu, RTGCUINTPTR GCPtrInstr, PCCPUMCTXCORE pCtxCore,
453 PDISCPUSTATE pDis, unsigned *pcbInstr)
454{
455 Assert(pCtxCore == CPUMGetGuestCtxCore(pVCpu));
456 DISCPUMODE enmCpuMode = CPUMGetGuestDisMode(pVCpu);
457 /** @todo Deal with too long instruction (=> \#GP), opcode read errors (=>
458 * \#PF, \#GP, \#??), undefined opcodes (=> \#UD), and such. */
459 int rc = DISInstrWithReader(GCPtrInstr, enmCpuMode, emReadBytes, pVCpu, pDis, pcbInstr);
460 if (RT_SUCCESS(rc))
461 return VINF_SUCCESS;
462 AssertMsg(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("DISCoreOne failed to GCPtrInstr=%RGv rc=%Rrc\n", GCPtrInstr, rc));
463 return rc;
464}
465
466
467#if defined(VBOX_COMPARE_IEM_FIRST) || defined(VBOX_COMPARE_IEM_LAST)
468static void emCompareWithIem(PVMCPU pVCpu, PCCPUMCTX pEmCtx, PCCPUMCTX pIemCtx,
469 VBOXSTRICTRC rcEm, VBOXSTRICTRC rcIem,
470 uint32_t cbEm, uint32_t cbIem)
471{
472 /* Quick compare. */
473 if ( rcEm == rcIem
474 && cbEm == cbIem
475 && g_cbEmWrote == g_cbIemWrote
476 && memcmp(g_abIemWrote, g_abEmWrote, g_cbIemWrote) == 0
477 && memcmp(pIemCtx, pEmCtx, sizeof(*pIemCtx)) == 0
478 && (g_fEmFFs & g_fInterestingFFs) == (g_fIemFFs & g_fInterestingFFs)
479 )
480 return;
481
482 /* Report exact differences. */
483 RTLogPrintf("! EM and IEM differs at %04x:%08RGv !\n", g_IncomingCtx.cs.Sel, g_IncomingCtx.rip);
484 if (rcEm != rcIem)
485 RTLogPrintf(" * rcIem=%Rrc rcEm=%Rrc\n", VBOXSTRICTRC_VAL(rcIem), VBOXSTRICTRC_VAL(rcEm));
486 else if (cbEm != cbIem)
487 RTLogPrintf(" * cbIem=%#x cbEm=%#x\n", cbIem, cbEm);
488
489 if (RT_SUCCESS(rcEm) && RT_SUCCESS(rcIem))
490 {
491 if (g_cbIemWrote != g_cbEmWrote)
492 RTLogPrintf("!! g_cbIemWrote=%#x g_cbEmWrote=%#x\n", g_cbIemWrote, g_cbEmWrote);
493 else if (memcmp(g_abIemWrote, g_abEmWrote, g_cbIemWrote))
494 {
495 RTLogPrintf("!! IemWrote %.*Rhxs\n", RT_MIN(RT_MAX(1, g_cbIemWrote), 64), g_abIemWrote);
496 RTLogPrintf("!! EemWrote %.*Rhxs\n", RT_MIN(RT_MAX(1, g_cbIemWrote), 64), g_abIemWrote);
497 }
498
499 if ((g_fEmFFs & g_fInterestingFFs) != (g_fIemFFs & g_fInterestingFFs))
500 RTLogPrintf("!! g_fIemFFs=%#x g_fEmFFs=%#x (diff=%#x)\n", g_fIemFFs & g_fInterestingFFs,
501 g_fEmFFs & g_fInterestingFFs, (g_fIemFFs ^ g_fEmFFs) & g_fInterestingFFs);
502
503# define CHECK_FIELD(a_Field) \
504 do \
505 { \
506 if (pEmCtx->a_Field != pIemCtx->a_Field) \
507 { \
508 switch (sizeof(pEmCtx->a_Field)) \
509 { \
510 case 1: RTLogPrintf("!! %8s differs - iem=%02x - em=%02x\n", #a_Field, pIemCtx->a_Field, pEmCtx->a_Field); break; \
511 case 2: RTLogPrintf("!! %8s differs - iem=%04x - em=%04x\n", #a_Field, pIemCtx->a_Field, pEmCtx->a_Field); break; \
512 case 4: RTLogPrintf("!! %8s differs - iem=%08x - em=%08x\n", #a_Field, pIemCtx->a_Field, pEmCtx->a_Field); break; \
513 case 8: RTLogPrintf("!! %8s differs - iem=%016llx - em=%016llx\n", #a_Field, pIemCtx->a_Field, pEmCtx->a_Field); break; \
514 default: RTLogPrintf("!! %8s differs\n", #a_Field); break; \
515 } \
516 cDiffs++; \
517 } \
518 } while (0)
519
520# define CHECK_BIT_FIELD(a_Field) \
521 do \
522 { \
523 if (pEmCtx->a_Field != pIemCtx->a_Field) \
524 { \
525 RTLogPrintf("!! %8s differs - iem=%02x - em=%02x\n", #a_Field, pIemCtx->a_Field, pEmCtx->a_Field); \
526 cDiffs++; \
527 } \
528 } while (0)
529
530# define CHECK_SEL(a_Sel) \
531 do \
532 { \
533 CHECK_FIELD(a_Sel.Sel); \
534 CHECK_FIELD(a_Sel.Attr.u); \
535 CHECK_FIELD(a_Sel.u64Base); \
536 CHECK_FIELD(a_Sel.u32Limit); \
537 CHECK_FIELD(a_Sel.fFlags); \
538 } while (0)
539
540 unsigned cDiffs = 0;
541 if (memcmp(&pEmCtx->fpu, &pIemCtx->fpu, sizeof(pIemCtx->fpu)))
542 {
543 RTLogPrintf(" the FPU state differs\n");
544 cDiffs++;
545 CHECK_FIELD(fpu.FCW);
546 CHECK_FIELD(fpu.FSW);
547 CHECK_FIELD(fpu.FTW);
548 CHECK_FIELD(fpu.FOP);
549 CHECK_FIELD(fpu.FPUIP);
550 CHECK_FIELD(fpu.CS);
551 CHECK_FIELD(fpu.Rsrvd1);
552 CHECK_FIELD(fpu.FPUDP);
553 CHECK_FIELD(fpu.DS);
554 CHECK_FIELD(fpu.Rsrvd2);
555 CHECK_FIELD(fpu.MXCSR);
556 CHECK_FIELD(fpu.MXCSR_MASK);
557 CHECK_FIELD(fpu.aRegs[0].au64[0]); CHECK_FIELD(fpu.aRegs[0].au64[1]);
558 CHECK_FIELD(fpu.aRegs[1].au64[0]); CHECK_FIELD(fpu.aRegs[1].au64[1]);
559 CHECK_FIELD(fpu.aRegs[2].au64[0]); CHECK_FIELD(fpu.aRegs[2].au64[1]);
560 CHECK_FIELD(fpu.aRegs[3].au64[0]); CHECK_FIELD(fpu.aRegs[3].au64[1]);
561 CHECK_FIELD(fpu.aRegs[4].au64[0]); CHECK_FIELD(fpu.aRegs[4].au64[1]);
562 CHECK_FIELD(fpu.aRegs[5].au64[0]); CHECK_FIELD(fpu.aRegs[5].au64[1]);
563 CHECK_FIELD(fpu.aRegs[6].au64[0]); CHECK_FIELD(fpu.aRegs[6].au64[1]);
564 CHECK_FIELD(fpu.aRegs[7].au64[0]); CHECK_FIELD(fpu.aRegs[7].au64[1]);
565 CHECK_FIELD(fpu.aXMM[ 0].au64[0]); CHECK_FIELD(fpu.aXMM[ 0].au64[1]);
566 CHECK_FIELD(fpu.aXMM[ 1].au64[0]); CHECK_FIELD(fpu.aXMM[ 1].au64[1]);
567 CHECK_FIELD(fpu.aXMM[ 2].au64[0]); CHECK_FIELD(fpu.aXMM[ 2].au64[1]);
568 CHECK_FIELD(fpu.aXMM[ 3].au64[0]); CHECK_FIELD(fpu.aXMM[ 3].au64[1]);
569 CHECK_FIELD(fpu.aXMM[ 4].au64[0]); CHECK_FIELD(fpu.aXMM[ 4].au64[1]);
570 CHECK_FIELD(fpu.aXMM[ 5].au64[0]); CHECK_FIELD(fpu.aXMM[ 5].au64[1]);
571 CHECK_FIELD(fpu.aXMM[ 6].au64[0]); CHECK_FIELD(fpu.aXMM[ 6].au64[1]);
572 CHECK_FIELD(fpu.aXMM[ 7].au64[0]); CHECK_FIELD(fpu.aXMM[ 7].au64[1]);
573 CHECK_FIELD(fpu.aXMM[ 8].au64[0]); CHECK_FIELD(fpu.aXMM[ 8].au64[1]);
574 CHECK_FIELD(fpu.aXMM[ 9].au64[0]); CHECK_FIELD(fpu.aXMM[ 9].au64[1]);
575 CHECK_FIELD(fpu.aXMM[10].au64[0]); CHECK_FIELD(fpu.aXMM[10].au64[1]);
576 CHECK_FIELD(fpu.aXMM[11].au64[0]); CHECK_FIELD(fpu.aXMM[11].au64[1]);
577 CHECK_FIELD(fpu.aXMM[12].au64[0]); CHECK_FIELD(fpu.aXMM[12].au64[1]);
578 CHECK_FIELD(fpu.aXMM[13].au64[0]); CHECK_FIELD(fpu.aXMM[13].au64[1]);
579 CHECK_FIELD(fpu.aXMM[14].au64[0]); CHECK_FIELD(fpu.aXMM[14].au64[1]);
580 CHECK_FIELD(fpu.aXMM[15].au64[0]); CHECK_FIELD(fpu.aXMM[15].au64[1]);
581 for (unsigned i = 0; i < RT_ELEMENTS(pEmCtx->fpu.au32RsrvdRest); i++)
582 CHECK_FIELD(fpu.au32RsrvdRest[i]);
583 }
584 CHECK_FIELD(rip);
585 if (pEmCtx->rflags.u != pIemCtx->rflags.u)
586 {
587 RTLogPrintf("!! rflags differs - iem=%08llx em=%08llx\n", pIemCtx->rflags.u, pEmCtx->rflags.u);
588 CHECK_BIT_FIELD(rflags.Bits.u1CF);
589 CHECK_BIT_FIELD(rflags.Bits.u1Reserved0);
590 CHECK_BIT_FIELD(rflags.Bits.u1PF);
591 CHECK_BIT_FIELD(rflags.Bits.u1Reserved1);
592 CHECK_BIT_FIELD(rflags.Bits.u1AF);
593 CHECK_BIT_FIELD(rflags.Bits.u1Reserved2);
594 CHECK_BIT_FIELD(rflags.Bits.u1ZF);
595 CHECK_BIT_FIELD(rflags.Bits.u1SF);
596 CHECK_BIT_FIELD(rflags.Bits.u1TF);
597 CHECK_BIT_FIELD(rflags.Bits.u1IF);
598 CHECK_BIT_FIELD(rflags.Bits.u1DF);
599 CHECK_BIT_FIELD(rflags.Bits.u1OF);
600 CHECK_BIT_FIELD(rflags.Bits.u2IOPL);
601 CHECK_BIT_FIELD(rflags.Bits.u1NT);
602 CHECK_BIT_FIELD(rflags.Bits.u1Reserved3);
603 CHECK_BIT_FIELD(rflags.Bits.u1RF);
604 CHECK_BIT_FIELD(rflags.Bits.u1VM);
605 CHECK_BIT_FIELD(rflags.Bits.u1AC);
606 CHECK_BIT_FIELD(rflags.Bits.u1VIF);
607 CHECK_BIT_FIELD(rflags.Bits.u1VIP);
608 CHECK_BIT_FIELD(rflags.Bits.u1ID);
609 }
610
611 if (!g_fIgnoreRaxRdx)
612 CHECK_FIELD(rax);
613 CHECK_FIELD(rcx);
614 if (!g_fIgnoreRaxRdx)
615 CHECK_FIELD(rdx);
616 CHECK_FIELD(rbx);
617 CHECK_FIELD(rsp);
618 CHECK_FIELD(rbp);
619 CHECK_FIELD(rsi);
620 CHECK_FIELD(rdi);
621 CHECK_FIELD(r8);
622 CHECK_FIELD(r9);
623 CHECK_FIELD(r10);
624 CHECK_FIELD(r11);
625 CHECK_FIELD(r12);
626 CHECK_FIELD(r13);
627 CHECK_SEL(cs);
628 CHECK_SEL(ss);
629 CHECK_SEL(ds);
630 CHECK_SEL(es);
631 CHECK_SEL(fs);
632 CHECK_SEL(gs);
633 CHECK_FIELD(cr0);
634 CHECK_FIELD(cr2);
635 CHECK_FIELD(cr3);
636 CHECK_FIELD(cr4);
637 CHECK_FIELD(dr[0]);
638 CHECK_FIELD(dr[1]);
639 CHECK_FIELD(dr[2]);
640 CHECK_FIELD(dr[3]);
641 CHECK_FIELD(dr[6]);
642 CHECK_FIELD(dr[7]);
643 CHECK_FIELD(gdtr.cbGdt);
644 CHECK_FIELD(gdtr.pGdt);
645 CHECK_FIELD(idtr.cbIdt);
646 CHECK_FIELD(idtr.pIdt);
647 CHECK_SEL(ldtr);
648 CHECK_SEL(tr);
649 CHECK_FIELD(SysEnter.cs);
650 CHECK_FIELD(SysEnter.eip);
651 CHECK_FIELD(SysEnter.esp);
652 CHECK_FIELD(msrEFER);
653 CHECK_FIELD(msrSTAR);
654 CHECK_FIELD(msrPAT);
655 CHECK_FIELD(msrLSTAR);
656 CHECK_FIELD(msrCSTAR);
657 CHECK_FIELD(msrSFMASK);
658 CHECK_FIELD(msrKERNELGSBASE);
659
660# undef CHECK_FIELD
661# undef CHECK_BIT_FIELD
662 }
663}
664#endif /* VBOX_COMPARE_IEM_AND_EM */
665
666
667/**
668 * Interprets the current instruction.
669 *
670 * @returns VBox status code.
671 * @retval VINF_* Scheduling instructions.
672 * @retval VERR_EM_INTERPRETER Something we can't cope with.
673 * @retval VERR_* Fatal errors.
674 *
675 * @param pVCpu Pointer to the VMCPU.
676 * @param pRegFrame The register frame.
677 * Updates the EIP if an instruction was executed successfully.
678 * @param pvFault The fault address (CR2).
679 * @param pcbSize Size of the write (if applicable).
680 *
681 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
682 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
683 * to worry about e.g. invalid modrm combinations (!)
684 */
685VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
686{
687 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
688 LogFlow(("EMInterpretInstruction %RGv fault %RGv\n", (RTGCPTR)pRegFrame->rip, pvFault));
689#ifdef VBOX_WITH_IEM
690 NOREF(pvFault);
691
692# ifdef VBOX_COMPARE_IEM_AND_EM
693 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
694 g_IncomingCtx = *pCtx;
695 g_fIncomingFFs = pVCpu->fLocalForcedActions;
696 g_cbEmWrote = g_cbIemWrote = 0;
697
698# ifdef VBOX_COMPARE_IEM_FIRST
699 /* IEM */
700 VBOXSTRICTRC rcIem = IEMExecOneBypassEx(pVCpu, pRegFrame, NULL);
701 if (RT_UNLIKELY( rcIem == VERR_IEM_ASPECT_NOT_IMPLEMENTED
702 || rcIem == VERR_IEM_INSTR_NOT_IMPLEMENTED))
703 rcIem = VERR_EM_INTERPRETER;
704 g_IemCtx = *pCtx;
705 g_fIemFFs = pVCpu->fLocalForcedActions;
706 pVCpu->fLocalForcedActions = (pVCpu->fLocalForcedActions & ~g_fInterestingFFs) | (g_fIncomingFFs & g_fInterestingFFs);
707 *pCtx = g_IncomingCtx;
708# endif
709
710 /* EM */
711 RTGCPTR pbCode;
712 VBOXSTRICTRC rcEm = SELMToFlatEx(pVCpu, DISSELREG_CS, pRegFrame, pRegFrame->rip, 0, &pbCode);
713 if (RT_SUCCESS(rcEm))
714 {
715 uint32_t cbOp;
716 PDISCPUSTATE pDis = &pVCpu->em.s.DisState;
717 pDis->uCpuMode = CPUMGetGuestDisMode(pVCpu);
718 rcEm = emDisCoreOne(pVCpu->CTX_SUFF(pVM), pVCpu, pDis, (RTGCUINTPTR)pbCode, &cbOp);
719 if (RT_SUCCESS(rcEm))
720 {
721 Assert(cbOp == pDis->cbInstr);
722 uint32_t cbIgnored;
723 rcEm = emInterpretInstructionCPUOuter(pVCpu, pDis, pRegFrame, pvFault, EMCODETYPE_SUPERVISOR, &cbIgnored);
724 if (RT_SUCCESS(rcEm))
725 pRegFrame->rip += cbOp; /* Move on to the next instruction. */
726
727 }
728 rcEm = VERR_EM_INTERPRETER;
729 }
730 else
731 rcEm = VERR_EM_INTERPRETER;
732# ifdef VBOX_SAME_AS_EM
733 if (rcEm == VERR_EM_INTERPRETER)
734 {
735 Log(("EMInterpretInstruction: returns %Rrc\n", VBOXSTRICTRC_VAL(rcEm)));
736 return rcEm;
737 }
738# endif
739 g_EmCtx = *pCtx;
740 g_fEmFFs = pVCpu->fLocalForcedActions;
741 VBOXSTRICTRC rc = rcEm;
742
743# ifdef VBOX_COMPARE_IEM_LAST
744 /* IEM */
745 pVCpu->fLocalForcedActions = (pVCpu->fLocalForcedActions & ~g_fInterestingFFs) | (g_fIncomingFFs & g_fInterestingFFs);
746 *pCtx = g_IncomingCtx;
747 VBOXSTRICTRC rcIem = IEMExecOneBypassEx(pVCpu, pRegFrame, NULL);
748 if (RT_UNLIKELY( rcIem == VERR_IEM_ASPECT_NOT_IMPLEMENTED
749 || rcIem == VERR_IEM_INSTR_NOT_IMPLEMENTED))
750 rcIem = VERR_EM_INTERPRETER;
751 g_IemCtx = *pCtx;
752 g_fIemFFs = pVCpu->fLocalForcedActions;
753 rc = rcIem;
754# endif
755
756# if defined(VBOX_COMPARE_IEM_LAST) || defined(VBOX_COMPARE_IEM_FIRST)
757 emCompareWithIem(pVCpu, &g_EmCtx, &g_IemCtx, rcEm, rcIem, 0, 0);
758# endif
759
760# else
761 VBOXSTRICTRC rc = IEMExecOneBypassEx(pVCpu, pRegFrame, NULL);
762 if (RT_UNLIKELY( rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED
763 || rc == VERR_IEM_INSTR_NOT_IMPLEMENTED))
764 rc = VERR_EM_INTERPRETER;
765# endif
766 if (rc != VINF_SUCCESS)
767 Log(("EMInterpretInstruction: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
768
769 return rc;
770#else
771 RTGCPTR pbCode;
772 VBOXSTRICTRC rc = SELMToFlatEx(pVCpu, DISSELREG_CS, pRegFrame, pRegFrame->rip, 0, &pbCode);
773 if (RT_SUCCESS(rc))
774 {
775 uint32_t cbOp;
776 PDISCPUSTATE pDis = &pVCpu->em.s.DisState;
777 pDis->uCpuMode = CPUMGetGuestDisMode(pVCpu);
778 rc = emDisCoreOne(pVCpu->CTX_SUFF(pVM), pVCpu, pDis, (RTGCUINTPTR)pbCode, &cbOp);
779 if (RT_SUCCESS(rc))
780 {
781 Assert(cbOp == pDis->cbInstr);
782 uint32_t cbIgnored;
783 rc = emInterpretInstructionCPUOuter(pVCpu, pDis, pRegFrame, pvFault, EMCODETYPE_SUPERVISOR, &cbIgnored);
784 if (RT_SUCCESS(rc))
785 pRegFrame->rip += cbOp; /* Move on to the next instruction. */
786
787 return rc;
788 }
789 }
790 return VERR_EM_INTERPRETER;
791#endif
792}
793
794
795/**
796 * Interprets the current instruction.
797 *
798 * @returns VBox status code.
799 * @retval VINF_* Scheduling instructions.
800 * @retval VERR_EM_INTERPRETER Something we can't cope with.
801 * @retval VERR_* Fatal errors.
802 *
803 * @param pVM Pointer to the VM.
804 * @param pVCpu Pointer to the VMCPU.
805 * @param pRegFrame The register frame.
806 * Updates the EIP if an instruction was executed successfully.
807 * @param pvFault The fault address (CR2).
808 * @param pcbWritten Size of the write (if applicable).
809 *
810 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
811 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
812 * to worry about e.g. invalid modrm combinations (!)
813 */
814VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionEx(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbWritten)
815{
816 LogFlow(("EMInterpretInstructionEx %RGv fault %RGv\n", (RTGCPTR)pRegFrame->rip, pvFault));
817 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
818#ifdef VBOX_WITH_IEM
819 NOREF(pvFault);
820
821# ifdef VBOX_COMPARE_IEM_AND_EM
822 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
823 g_IncomingCtx = *pCtx;
824 g_fIncomingFFs = pVCpu->fLocalForcedActions;
825 g_cbEmWrote = g_cbIemWrote = 0;
826
827# ifdef VBOX_COMPARE_IEM_FIRST
828 /* IEM */
829 uint32_t cbIemWritten = 0;
830 VBOXSTRICTRC rcIem = IEMExecOneBypassEx(pVCpu, pRegFrame, &cbIemWritten);
831 if (RT_UNLIKELY( rcIem == VERR_IEM_ASPECT_NOT_IMPLEMENTED
832 || rcIem == VERR_IEM_INSTR_NOT_IMPLEMENTED))
833 rcIem = VERR_EM_INTERPRETER;
834 g_IemCtx = *pCtx;
835 g_fIemFFs = pVCpu->fLocalForcedActions;
836 pVCpu->fLocalForcedActions = (pVCpu->fLocalForcedActions & ~g_fInterestingFFs) | (g_fIncomingFFs & g_fInterestingFFs);
837 *pCtx = g_IncomingCtx;
838# endif
839
840 /* EM */
841 uint32_t cbEmWritten = 0;
842 RTGCPTR pbCode;
843 VBOXSTRICTRC rcEm = SELMToFlatEx(pVCpu, DISSELREG_CS, pRegFrame, pRegFrame->rip, 0, &pbCode);
844 if (RT_SUCCESS(rcEm))
845 {
846 uint32_t cbOp;
847 PDISCPUSTATE pDis = &pVCpu->em.s.DisState;
848 pDis->uCpuMode = CPUMGetGuestDisMode(pVCpu);
849 rcEm = emDisCoreOne(pVCpu->CTX_SUFF(pVM), pVCpu, pDis, (RTGCUINTPTR)pbCode, &cbOp);
850 if (RT_SUCCESS(rcEm))
851 {
852 Assert(cbOp == pDis->cbInstr);
853 rcEm = emInterpretInstructionCPUOuter(pVCpu, pDis, pRegFrame, pvFault, EMCODETYPE_SUPERVISOR, &cbEmWritten);
854 if (RT_SUCCESS(rcEm))
855 pRegFrame->rip += cbOp; /* Move on to the next instruction. */
856
857 }
858 else
859 rcEm = VERR_EM_INTERPRETER;
860 }
861 else
862 rcEm = VERR_EM_INTERPRETER;
863# ifdef VBOX_SAME_AS_EM
864 if (rcEm == VERR_EM_INTERPRETER)
865 {
866 Log(("EMInterpretInstruction: returns %Rrc\n", VBOXSTRICTRC_VAL(rcEm)));
867 return rcEm;
868 }
869# endif
870 g_EmCtx = *pCtx;
871 g_fEmFFs = pVCpu->fLocalForcedActions;
872 *pcbWritten = cbEmWritten;
873 VBOXSTRICTRC rc = rcEm;
874
875# ifdef VBOX_COMPARE_IEM_LAST
876 /* IEM */
877 pVCpu->fLocalForcedActions = (pVCpu->fLocalForcedActions & ~g_fInterestingFFs) | (g_fIncomingFFs & g_fInterestingFFs);
878 *pCtx = g_IncomingCtx;
879 uint32_t cbIemWritten = 0;
880 VBOXSTRICTRC rcIem = IEMExecOneBypassEx(pVCpu, pRegFrame, &cbIemWritten);
881 if (RT_UNLIKELY( rcIem == VERR_IEM_ASPECT_NOT_IMPLEMENTED
882 || rcIem == VERR_IEM_INSTR_NOT_IMPLEMENTED))
883 rcIem = VERR_EM_INTERPRETER;
884 g_IemCtx = *pCtx;
885 g_fIemFFs = pVCpu->fLocalForcedActions;
886 *pcbWritten = cbIemWritten;
887 rc = rcIem;
888# endif
889
890# if defined(VBOX_COMPARE_IEM_LAST) || defined(VBOX_COMPARE_IEM_FIRST)
891 emCompareWithIem(pVCpu, &g_EmCtx, &g_IemCtx, rcEm, rcIem, cbEmWritten, cbIemWritten);
892# endif
893
894# else
895 VBOXSTRICTRC rc = IEMExecOneBypassEx(pVCpu, pRegFrame, pcbWritten);
896 if (RT_UNLIKELY( rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED
897 || rc == VERR_IEM_INSTR_NOT_IMPLEMENTED))
898 rc = VERR_EM_INTERPRETER;
899# endif
900 if (rc != VINF_SUCCESS)
901 Log(("EMInterpretInstructionEx: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
902
903 return rc;
904#else
905 RTGCPTR pbCode;
906 VBOXSTRICTRC rc = SELMToFlatEx(pVCpu, DISSELREG_CS, pRegFrame, pRegFrame->rip, 0, &pbCode);
907 if (RT_SUCCESS(rc))
908 {
909 uint32_t cbOp;
910 PDISCPUSTATE pDis = &pVCpu->em.s.DisState;
911 pDis->uCpuMode = CPUMGetGuestDisMode(pVCpu);
912 rc = emDisCoreOne(pVCpu->CTX_SUFF(pVM), pVCpu, pDis, (RTGCUINTPTR)pbCode, &cbOp);
913 if (RT_SUCCESS(rc))
914 {
915 Assert(cbOp == pDis->cbInstr);
916 rc = emInterpretInstructionCPUOuter(pVCpu, pDis, pRegFrame, pvFault, EMCODETYPE_SUPERVISOR, pcbWritten);
917 if (RT_SUCCESS(rc))
918 pRegFrame->rip += cbOp; /* Move on to the next instruction. */
919
920 return rc;
921 }
922 }
923 return VERR_EM_INTERPRETER;
924#endif
925}
926
927
928/**
929 * Interprets the current instruction using the supplied DISCPUSTATE structure.
930 *
931 * IP/EIP/RIP *IS* updated!
932 *
933 * @returns VBox strict status code.
934 * @retval VINF_* Scheduling instructions. When these are returned, it
935 * starts to get a bit tricky to know whether code was
936 * executed or not... We'll address this when it becomes a problem.
937 * @retval VERR_EM_INTERPRETER Something we can't cope with.
938 * @retval VERR_* Fatal errors.
939 *
940 * @param pVM Pointer to the VM.
941 * @param pVCpu Pointer to the VMCPU.
942 * @param pDis The disassembler cpu state for the instruction to be
943 * interpreted.
944 * @param pRegFrame The register frame. IP/EIP/RIP *IS* changed!
945 * @param pvFault The fault address (CR2).
946 * @param pcbSize Size of the write (if applicable).
947 * @param enmCodeType Code type (user/supervisor)
948 *
949 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
950 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
951 * to worry about e.g. invalid modrm combinations (!)
952 *
953 * @todo At this time we do NOT check if the instruction overwrites vital information.
954 * Make sure this can't happen!! (will add some assertions/checks later)
955 */
956VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame,
957 RTGCPTR pvFault, EMCODETYPE enmCodeType)
958{
959 LogFlow(("EMInterpretInstructionDisasState %RGv fault %RGv\n", (RTGCPTR)pRegFrame->rip, pvFault));
960 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
961#ifdef VBOX_WITH_IEM
962 NOREF(pDis); NOREF(pvFault); NOREF(enmCodeType);
963
964# ifdef VBOX_COMPARE_IEM_AND_EM
965 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
966 g_IncomingCtx = *pCtx;
967 g_fIncomingFFs = pVCpu->fLocalForcedActions;
968 g_cbEmWrote = g_cbIemWrote = 0;
969
970# ifdef VBOX_COMPARE_IEM_FIRST
971 VBOXSTRICTRC rcIem = IEMExecOneBypassWithPrefetchedByPC(pVCpu, pRegFrame, pRegFrame->rip, pDis->abInstr, pDis->cbCachedInstr);
972 if (RT_UNLIKELY( rcIem == VERR_IEM_ASPECT_NOT_IMPLEMENTED
973 || rcIem == VERR_IEM_INSTR_NOT_IMPLEMENTED))
974 rcIem = VERR_EM_INTERPRETER;
975 g_IemCtx = *pCtx;
976 g_fIemFFs = pVCpu->fLocalForcedActions;
977 pVCpu->fLocalForcedActions = (pVCpu->fLocalForcedActions & ~g_fInterestingFFs) | (g_fIncomingFFs & g_fInterestingFFs);
978 *pCtx = g_IncomingCtx;
979# endif
980
981 /* EM */
982 uint32_t cbIgnored;
983 VBOXSTRICTRC rcEm = emInterpretInstructionCPUOuter(pVCpu, pDis, pRegFrame, pvFault, enmCodeType, &cbIgnored);
984 if (RT_SUCCESS(rcEm))
985 pRegFrame->rip += pDis->cbInstr; /* Move on to the next instruction. */
986# ifdef VBOX_SAME_AS_EM
987 if (rcEm == VERR_EM_INTERPRETER)
988 {
989 Log(("EMInterpretInstruction: returns %Rrc\n", VBOXSTRICTRC_VAL(rcEm)));
990 return rcEm;
991 }
992# endif
993 g_EmCtx = *pCtx;
994 g_fEmFFs = pVCpu->fLocalForcedActions;
995 VBOXSTRICTRC rc = rcEm;
996
997# ifdef VBOX_COMPARE_IEM_LAST
998 /* IEM */
999 pVCpu->fLocalForcedActions = (pVCpu->fLocalForcedActions & ~g_fInterestingFFs) | (g_fIncomingFFs & g_fInterestingFFs);
1000 *pCtx = g_IncomingCtx;
1001 VBOXSTRICTRC rcIem = IEMExecOneBypassWithPrefetchedByPC(pVCpu, pRegFrame, pRegFrame->rip, pDis->abInstr, pDis->cbCachedInstr);
1002 if (RT_UNLIKELY( rcIem == VERR_IEM_ASPECT_NOT_IMPLEMENTED
1003 || rcIem == VERR_IEM_INSTR_NOT_IMPLEMENTED))
1004 rcIem = VERR_EM_INTERPRETER;
1005 g_IemCtx = *pCtx;
1006 g_fIemFFs = pVCpu->fLocalForcedActions;
1007 rc = rcIem;
1008# endif
1009
1010# if defined(VBOX_COMPARE_IEM_LAST) || defined(VBOX_COMPARE_IEM_FIRST)
1011 emCompareWithIem(pVCpu, &g_EmCtx, &g_IemCtx, rcEm, rcIem, 0, 0);
1012# endif
1013
1014# else
1015 VBOXSTRICTRC rc = IEMExecOneBypassWithPrefetchedByPC(pVCpu, pRegFrame, pRegFrame->rip, pDis->abInstr, pDis->cbCachedInstr);
1016 if (RT_UNLIKELY( rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED
1017 || rc == VERR_IEM_INSTR_NOT_IMPLEMENTED))
1018 rc = VERR_EM_INTERPRETER;
1019# endif
1020
1021 if (rc != VINF_SUCCESS)
1022 Log(("EMInterpretInstructionDisasState: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
1023
1024 return rc;
1025#else
1026 uint32_t cbIgnored;
1027 VBOXSTRICTRC rc = emInterpretInstructionCPUOuter(pVCpu, pDis, pRegFrame, pvFault, enmCodeType, &cbIgnored);
1028 if (RT_SUCCESS(rc))
1029 pRegFrame->rip += pDis->cbInstr; /* Move on to the next instruction. */
1030 return rc;
1031#endif
1032}
1033
1034#ifdef IN_RC
1035
1036DECLINLINE(int) emRCStackRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCPTR GCPtrSrc, uint32_t cb)
1037{
1038 int rc = MMGCRamRead(pVM, pvDst, (void *)(uintptr_t)GCPtrSrc, cb);
1039 if (RT_LIKELY(rc != VERR_ACCESS_DENIED))
1040 return rc;
1041 return PGMPhysInterpretedReadNoHandlers(pVCpu, pCtxCore, pvDst, GCPtrSrc, cb, /*fMayTrap*/ false);
1042}
1043
1044
1045/**
1046 * Interpret IRET (currently only to V86 code) - PATM only.
1047 *
1048 * @returns VBox status code.
1049 * @param pVM Pointer to the VM.
1050 * @param pVCpu Pointer to the VMCPU.
1051 * @param pRegFrame The register frame.
1052 *
1053 */
1054VMM_INT_DECL(int) EMInterpretIretV86ForPatm(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1055{
1056 RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp;
1057 RTGCUINTPTR eip, cs, esp, ss, eflags, ds, es, fs, gs, uMask;
1058 int rc;
1059
1060 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1061 Assert(!CPUMIsGuestIn64BitCode(pVCpu));
1062 /** @todo Rainy day: Test what happens when VERR_EM_INTERPRETER is returned by
1063 * this function. Fear that it may guru on us, thus not converted to
1064 * IEM. */
1065
1066 rc = emRCStackRead(pVM, pVCpu, pRegFrame, &eip, (RTGCPTR)pIretStack , 4);
1067 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &cs, (RTGCPTR)(pIretStack + 4), 4);
1068 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &eflags, (RTGCPTR)(pIretStack + 8), 4);
1069 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1070 AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER);
1071
1072 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &esp, (RTGCPTR)(pIretStack + 12), 4);
1073 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &ss, (RTGCPTR)(pIretStack + 16), 4);
1074 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &es, (RTGCPTR)(pIretStack + 20), 4);
1075 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &ds, (RTGCPTR)(pIretStack + 24), 4);
1076 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &fs, (RTGCPTR)(pIretStack + 28), 4);
1077 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &gs, (RTGCPTR)(pIretStack + 32), 4);
1078 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1079
1080 pRegFrame->eip = eip & 0xffff;
1081 pRegFrame->cs.Sel = cs;
1082
1083 /* Mask away all reserved bits */
1084 uMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_RF | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_ID;
1085 eflags &= uMask;
1086
1087 CPUMRawSetEFlags(pVCpu, eflags);
1088 Assert((pRegFrame->eflags.u32 & (X86_EFL_IF|X86_EFL_IOPL)) == X86_EFL_IF);
1089
1090 pRegFrame->esp = esp;
1091 pRegFrame->ss.Sel = ss;
1092 pRegFrame->ds.Sel = ds;
1093 pRegFrame->es.Sel = es;
1094 pRegFrame->fs.Sel = fs;
1095 pRegFrame->gs.Sel = gs;
1096
1097 return VINF_SUCCESS;
1098}
1099
1100/**
1101 * IRET Emulation.
1102 */
1103static int emInterpretIret(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1104{
1105#ifdef VBOX_WITH_RAW_RING1
1106 NOREF(pvFault); NOREF(pcbSize);
1107 if (EMIsRawRing1Enabled(pVM))
1108 {
1109 RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp;
1110 RTGCUINTPTR eip, cs, esp, ss, eflags, uMask;
1111 int rc;
1112 uint32_t cpl, rpl;
1113
1114 /* We only execute 32-bits protected mode code in raw mode, so no need to bother to check for 16-bits code here. */
1115 /* @todo: we don't verify all the edge cases that generate #GP faults */
1116
1117 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1118 Assert(!CPUMIsGuestIn64BitCode(pVCpu));
1119 /** @todo Rainy day: Test what happens when VERR_EM_INTERPRETER is returned by
1120 * this function. Fear that it may guru on us, thus not converted to
1121 * IEM. */
1122
1123 rc = emRCStackRead(pVM, pVCpu, pRegFrame, &eip, (RTGCPTR)pIretStack , 4);
1124 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &cs, (RTGCPTR)(pIretStack + 4), 4);
1125 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &eflags, (RTGCPTR)(pIretStack + 8), 4);
1126 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1127 AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER);
1128
1129 /* Deal with V86 above. */
1130 if (eflags & X86_EFL_VM)
1131 return EMInterpretIretV86ForPatm(pVM, pVCpu, pRegFrame);
1132
1133 cpl = CPUMRCGetGuestCPL(pVCpu, pRegFrame);
1134 rpl = cs & X86_SEL_RPL;
1135
1136 Log(("emInterpretIret: iret to CS:EIP=%04X:%08X eflags=%x\n", cs, eip, eflags));
1137 if (rpl != cpl)
1138 {
1139 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &esp, (RTGCPTR)(pIretStack + 12), 4);
1140 rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &ss, (RTGCPTR)(pIretStack + 16), 4);
1141 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1142 Log(("emInterpretIret: return to different privilege level (rpl=%d cpl=%d)\n", rpl, cpl));
1143 Log(("emInterpretIret: SS:ESP=%04X:08X\n", ss, esp));
1144 pRegFrame->ss.Sel = ss;
1145 pRegFrame->esp = esp;
1146 }
1147 pRegFrame->cs.Sel = cs;
1148 pRegFrame->eip = eip;
1149
1150 /* Adjust CS & SS as required. */
1151 CPUMRCRecheckRawState(pVCpu, pRegFrame);
1152
1153 /* Mask away all reserved bits */
1154 uMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_RF | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_ID;
1155 eflags &= uMask;
1156
1157 CPUMRawSetEFlags(pVCpu, eflags);
1158 Assert((pRegFrame->eflags.u32 & (X86_EFL_IF|X86_EFL_IOPL)) == X86_EFL_IF);
1159 return VINF_SUCCESS;
1160 }
1161#else
1162 NOREF(pVM); NOREF(pVCpu); NOREF(pDis); NOREF(pRegFrame); NOREF(pvFault); NOREF(pcbSize);
1163#endif
1164 return VERR_EM_INTERPRETER;
1165}
1166
1167#endif /* IN_RC */
1168
1169
1170
1171/*
1172 *
1173 * Old interpreter primitives used by HM, move/eliminate later.
1174 * Old interpreter primitives used by HM, move/eliminate later.
1175 * Old interpreter primitives used by HM, move/eliminate later.
1176 * Old interpreter primitives used by HM, move/eliminate later.
1177 * Old interpreter primitives used by HM, move/eliminate later.
1178 *
1179 */
1180
1181
1182/**
1183 * Interpret CPUID given the parameters in the CPU context.
1184 *
1185 * @returns VBox status code.
1186 * @param pVM Pointer to the VM.
1187 * @param pVCpu Pointer to the VMCPU.
1188 * @param pRegFrame The register frame.
1189 *
1190 */
1191VMM_INT_DECL(int) EMInterpretCpuId(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1192{
1193 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1194 uint32_t iLeaf = pRegFrame->eax;
1195 NOREF(pVM);
1196
1197 /* cpuid clears the high dwords of the affected 64 bits registers. */
1198 pRegFrame->rax = 0;
1199 pRegFrame->rbx = 0;
1200 pRegFrame->rcx &= UINT64_C(0x00000000ffffffff);
1201 pRegFrame->rdx = 0;
1202
1203 /* Note: operates the same in 64 and non-64 bits mode. */
1204 CPUMGetGuestCpuId(pVCpu, iLeaf, &pRegFrame->eax, &pRegFrame->ebx, &pRegFrame->ecx, &pRegFrame->edx);
1205 Log(("Emulate: CPUID %x -> %08x %08x %08x %08x\n", iLeaf, pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx));
1206 return VINF_SUCCESS;
1207}
1208
1209
1210/**
1211 * Interpret RDTSC.
1212 *
1213 * @returns VBox status code.
1214 * @param pVM Pointer to the VM.
1215 * @param pVCpu Pointer to the VMCPU.
1216 * @param pRegFrame The register frame.
1217 *
1218 */
1219VMM_INT_DECL(int) EMInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1220{
1221 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1222 unsigned uCR4 = CPUMGetGuestCR4(pVCpu);
1223
1224 if (uCR4 & X86_CR4_TSD)
1225 return VERR_EM_INTERPRETER; /* genuine #GP */
1226
1227 uint64_t uTicks = TMCpuTickGet(pVCpu);
1228
1229 /* Same behaviour in 32 & 64 bits mode */
1230 pRegFrame->rax = (uint32_t)uTicks;
1231 pRegFrame->rdx = (uTicks >> 32ULL);
1232#ifdef VBOX_COMPARE_IEM_AND_EM
1233 g_fIgnoreRaxRdx = true;
1234#endif
1235
1236 NOREF(pVM);
1237 return VINF_SUCCESS;
1238}
1239
1240/**
1241 * Interpret RDTSCP.
1242 *
1243 * @returns VBox status code.
1244 * @param pVM Pointer to the VM.
1245 * @param pVCpu Pointer to the VMCPU.
1246 * @param pCtx The CPU context.
1247 *
1248 */
1249VMM_INT_DECL(int) EMInterpretRdtscp(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1250{
1251 Assert(pCtx == CPUMQueryGuestCtxPtr(pVCpu));
1252 uint32_t uCR4 = CPUMGetGuestCR4(pVCpu);
1253
1254 if (!CPUMGetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_RDTSCP))
1255 {
1256 AssertFailed();
1257 return VERR_EM_INTERPRETER; /* genuine #UD */
1258 }
1259
1260 if (uCR4 & X86_CR4_TSD)
1261 return VERR_EM_INTERPRETER; /* genuine #GP */
1262
1263 uint64_t uTicks = TMCpuTickGet(pVCpu);
1264
1265 /* Same behaviour in 32 & 64 bits mode */
1266 pCtx->rax = (uint32_t)uTicks;
1267 pCtx->rdx = (uTicks >> 32ULL);
1268#ifdef VBOX_COMPARE_IEM_AND_EM
1269 g_fIgnoreRaxRdx = true;
1270#endif
1271 /* Low dword of the TSC_AUX msr only. */
1272 CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX, &pCtx->rcx);
1273 pCtx->rcx &= UINT32_C(0xffffffff);
1274
1275 return VINF_SUCCESS;
1276}
1277
1278/**
1279 * Interpret RDPMC.
1280 *
1281 * @returns VBox status code.
1282 * @param pVM Pointer to the VM.
1283 * @param pVCpu Pointer to the VMCPU.
1284 * @param pRegFrame The register frame.
1285 *
1286 */
1287VMM_INT_DECL(int) EMInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1288{
1289 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1290 uint32_t uCR4 = CPUMGetGuestCR4(pVCpu);
1291
1292 /* If X86_CR4_PCE is not set, then CPL must be zero. */
1293 if ( !(uCR4 & X86_CR4_PCE)
1294 && CPUMGetGuestCPL(pVCpu) != 0)
1295 {
1296 Assert(CPUMGetGuestCR0(pVCpu) & X86_CR0_PE);
1297 return VERR_EM_INTERPRETER; /* genuine #GP */
1298 }
1299
1300 /* Just return zero here; rather tricky to properly emulate this, especially as the specs are a mess. */
1301 pRegFrame->rax = 0;
1302 pRegFrame->rdx = 0;
1303 /** @todo We should trigger a #GP here if the CPU doesn't support the index in ecx
1304 * but see @bugref{3472}! */
1305
1306 NOREF(pVM);
1307 return VINF_SUCCESS;
1308}
1309
1310
1311/**
1312 * MWAIT Emulation.
1313 */
1314VMM_INT_DECL(VBOXSTRICTRC) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1315{
1316 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1317 uint32_t u32Dummy, u32ExtFeatures, cpl, u32MWaitFeatures;
1318 NOREF(pVM);
1319
1320 /* Get the current privilege level. */
1321 cpl = CPUMGetGuestCPL(pVCpu);
1322 if (cpl != 0)
1323 return VERR_EM_INTERPRETER; /* supervisor only */
1324
1325 CPUMGetGuestCpuId(pVCpu, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
1326 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
1327 return VERR_EM_INTERPRETER; /* not supported */
1328
1329 /*
1330 * CPUID.05H.ECX[0] defines support for power management extensions (eax)
1331 * CPUID.05H.ECX[1] defines support for interrupts as break events for mwait even when IF=0
1332 */
1333 CPUMGetGuestCpuId(pVCpu, 5, &u32Dummy, &u32Dummy, &u32MWaitFeatures, &u32Dummy);
1334 if (pRegFrame->ecx > 1)
1335 {
1336 Log(("EMInterpretMWait: unexpected ecx value %x -> recompiler\n", pRegFrame->ecx));
1337 return VERR_EM_INTERPRETER; /* illegal value. */
1338 }
1339
1340 if (pRegFrame->ecx && !(u32MWaitFeatures & X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
1341 {
1342 Log(("EMInterpretMWait: unsupported X86_CPUID_MWAIT_ECX_BREAKIRQIF0 -> recompiler\n"));
1343 return VERR_EM_INTERPRETER; /* illegal value. */
1344 }
1345
1346 return EMMonitorWaitPerform(pVCpu, pRegFrame->rax, pRegFrame->rcx);
1347}
1348
1349
1350/**
1351 * MONITOR Emulation.
1352 */
1353VMM_INT_DECL(int) EMInterpretMonitor(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1354{
1355 uint32_t u32Dummy, u32ExtFeatures, cpl;
1356 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1357 NOREF(pVM);
1358
1359 if (pRegFrame->ecx != 0)
1360 {
1361 Log(("emInterpretMonitor: unexpected ecx=%x -> recompiler!!\n", pRegFrame->ecx));
1362 return VERR_EM_INTERPRETER; /* illegal value. */
1363 }
1364
1365 /* Get the current privilege level. */
1366 cpl = CPUMGetGuestCPL(pVCpu);
1367 if (cpl != 0)
1368 return VERR_EM_INTERPRETER; /* supervisor only */
1369
1370 CPUMGetGuestCpuId(pVCpu, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
1371 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
1372 return VERR_EM_INTERPRETER; /* not supported */
1373
1374 EMMonitorWaitPrepare(pVCpu, pRegFrame->rax, pRegFrame->rcx, pRegFrame->rdx);
1375 return VINF_SUCCESS;
1376}
1377
1378
1379/* VT-x only: */
1380
1381/**
1382 * Interpret INVLPG.
1383 *
1384 * @returns VBox status code.
1385 * @param pVM Pointer to the VM.
1386 * @param pVCpu Pointer to the VMCPU.
1387 * @param pRegFrame The register frame.
1388 * @param pAddrGC Operand address.
1389 *
1390 */
1391VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInvlpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC)
1392{
1393 /** @todo is addr always a flat linear address or ds based
1394 * (in absence of segment override prefixes)????
1395 */
1396 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1397 NOREF(pVM); NOREF(pRegFrame);
1398#ifdef IN_RC
1399 LogFlow(("RC: EMULATE: invlpg %RGv\n", pAddrGC));
1400#endif
1401 VBOXSTRICTRC rc = PGMInvalidatePage(pVCpu, pAddrGC);
1402 if ( rc == VINF_SUCCESS
1403 || rc == VINF_PGM_SYNC_CR3 /* we can rely on the FF */)
1404 return VINF_SUCCESS;
1405 AssertMsgReturn(rc == VINF_EM_RAW_EMULATE_INSTR,
1406 ("%Rrc addr=%RGv\n", VBOXSTRICTRC_VAL(rc), pAddrGC),
1407 VERR_EM_INTERPRETER);
1408 return rc;
1409}
1410
1411
1412/**
1413 * Update CRx.
1414 *
1415 * @returns VBox status code.
1416 * @param pVM Pointer to the VM.
1417 * @param pVCpu Pointer to the VMCPU.
1418 * @param pRegFrame The register frame.
1419 * @param DestRegCRx CRx register index (DISUSE_REG_CR*)
1420 * @param val New CRx value
1421 *
1422 */
1423static int emUpdateCRx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint64_t val)
1424{
1425 uint64_t oldval;
1426 uint64_t msrEFER;
1427 int rc, rc2;
1428 NOREF(pVM);
1429
1430 /** @todo Clean up this mess. */
1431 LogFlow(("EMInterpretCRxWrite at %RGv CR%d <- %RX64\n", (RTGCPTR)pRegFrame->rip, DestRegCrx, val));
1432 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1433 switch (DestRegCrx)
1434 {
1435 case DISCREG_CR0:
1436 oldval = CPUMGetGuestCR0(pVCpu);
1437#ifdef IN_RC
1438 /* CR0.WP and CR0.AM changes require a reschedule run in ring 3. */
1439 if ( (val & (X86_CR0_WP | X86_CR0_AM))
1440 != (oldval & (X86_CR0_WP | X86_CR0_AM)))
1441 return VERR_EM_INTERPRETER;
1442#endif
1443 rc = VINF_SUCCESS;
1444#if !defined(VBOX_COMPARE_IEM_AND_EM) || !defined(VBOX_COMPARE_IEM_LAST)
1445 CPUMSetGuestCR0(pVCpu, val);
1446#else
1447 CPUMQueryGuestCtxPtr(pVCpu)->cr0 = val | X86_CR0_ET;
1448#endif
1449 val = CPUMGetGuestCR0(pVCpu);
1450 if ( (oldval & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
1451 != (val & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))
1452 {
1453 /* global flush */
1454 rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true /* global */);
1455 AssertRCReturn(rc, rc);
1456 }
1457
1458 /* Deal with long mode enabling/disabling. */
1459 msrEFER = CPUMGetGuestEFER(pVCpu);
1460 if (msrEFER & MSR_K6_EFER_LME)
1461 {
1462 if ( !(oldval & X86_CR0_PG)
1463 && (val & X86_CR0_PG))
1464 {
1465 /* Illegal to have an active 64 bits CS selector (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */
1466 if (pRegFrame->cs.Attr.n.u1Long)
1467 {
1468 AssertMsgFailed(("Illegal enabling of paging with CS.u1Long = 1!!\n"));
1469 return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */
1470 }
1471
1472 /* Illegal to switch to long mode before activating PAE first (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */
1473 if (!(CPUMGetGuestCR4(pVCpu) & X86_CR4_PAE))
1474 {
1475 AssertMsgFailed(("Illegal enabling of paging with PAE disabled!!\n"));
1476 return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */
1477 }
1478 msrEFER |= MSR_K6_EFER_LMA;
1479 }
1480 else
1481 if ( (oldval & X86_CR0_PG)
1482 && !(val & X86_CR0_PG))
1483 {
1484 msrEFER &= ~MSR_K6_EFER_LMA;
1485 /* @todo Do we need to cut off rip here? High dword of rip is undefined, so it shouldn't really matter. */
1486 }
1487 CPUMSetGuestEFER(pVCpu, msrEFER);
1488 }
1489 rc2 = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu));
1490 return rc2 == VINF_SUCCESS ? rc : rc2;
1491
1492 case DISCREG_CR2:
1493 rc = CPUMSetGuestCR2(pVCpu, val); AssertRC(rc);
1494 return VINF_SUCCESS;
1495
1496 case DISCREG_CR3:
1497 /* Reloading the current CR3 means the guest just wants to flush the TLBs */
1498 rc = CPUMSetGuestCR3(pVCpu, val); AssertRC(rc);
1499 if (CPUMGetGuestCR0(pVCpu) & X86_CR0_PG)
1500 {
1501 /* flush */
1502 rc = PGMFlushTLB(pVCpu, val, !(CPUMGetGuestCR4(pVCpu) & X86_CR4_PGE));
1503 AssertRC(rc);
1504 }
1505 return rc;
1506
1507 case DISCREG_CR4:
1508 oldval = CPUMGetGuestCR4(pVCpu);
1509 rc = CPUMSetGuestCR4(pVCpu, val); AssertRC(rc);
1510 val = CPUMGetGuestCR4(pVCpu);
1511
1512 /* Illegal to disable PAE when long mode is active. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */
1513 msrEFER = CPUMGetGuestEFER(pVCpu);
1514 if ( (msrEFER & MSR_K6_EFER_LMA)
1515 && (oldval & X86_CR4_PAE)
1516 && !(val & X86_CR4_PAE))
1517 {
1518 return VERR_EM_INTERPRETER; /** @todo generate #GP(0) */
1519 }
1520
1521 rc = VINF_SUCCESS;
1522 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))
1523 != (val & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)))
1524 {
1525 /* global flush */
1526 rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true /* global */);
1527 AssertRCReturn(rc, rc);
1528 }
1529
1530 /* Feeling extremely lazy. */
1531# ifdef IN_RC
1532 if ( (oldval & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME))
1533 != (val & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME)))
1534 {
1535 Log(("emInterpretMovCRx: CR4: %#RX64->%#RX64 => R3\n", oldval, val));
1536 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
1537 }
1538# endif
1539# ifdef VBOX_WITH_RAW_MODE
1540 if (((val ^ oldval) & X86_CR4_VME) && !HMIsEnabled(pVM))
1541 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
1542# endif
1543
1544 rc2 = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu));
1545 return rc2 == VINF_SUCCESS ? rc : rc2;
1546
1547 case DISCREG_CR8:
1548 return PDMApicSetTPR(pVCpu, val << 4); /* cr8 bits 3-0 correspond to bits 7-4 of the task priority mmio register. */
1549
1550 default:
1551 AssertFailed();
1552 case DISCREG_CR1: /* illegal op */
1553 break;
1554 }
1555 return VERR_EM_INTERPRETER;
1556}
1557
1558
1559/**
1560 * Interpret CRx write.
1561 *
1562 * @returns VBox status code.
1563 * @param pVM Pointer to the VM.
1564 * @param pVCpu Pointer to the VMCPU.
1565 * @param pRegFrame The register frame.
1566 * @param DestRegCRx CRx register index (DISUSE_REG_CR*)
1567 * @param SrcRegGen General purpose register index (USE_REG_E**))
1568 *
1569 */
1570VMM_INT_DECL(int) EMInterpretCRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)
1571{
1572 uint64_t val;
1573 int rc;
1574 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1575
1576 if (CPUMIsGuestIn64BitCode(pVCpu))
1577 rc = DISFetchReg64(pRegFrame, SrcRegGen, &val);
1578 else
1579 {
1580 uint32_t val32;
1581 rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1582 val = val32;
1583 }
1584
1585 if (RT_SUCCESS(rc))
1586 return emUpdateCRx(pVM, pVCpu, pRegFrame, DestRegCrx, val);
1587
1588 return VERR_EM_INTERPRETER;
1589}
1590
1591/**
1592 * Interpret LMSW.
1593 *
1594 * @returns VBox status code.
1595 * @param pVM Pointer to the VM.
1596 * @param pVCpu Pointer to the VMCPU.
1597 * @param pRegFrame The register frame.
1598 * @param u16Data LMSW source data.
1599 *
1600 */
1601VMM_INT_DECL(int) EMInterpretLMSW(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint16_t u16Data)
1602{
1603 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1604 uint64_t OldCr0 = CPUMGetGuestCR0(pVCpu);
1605
1606 /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */
1607 uint64_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
1608 | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS));
1609
1610 return emUpdateCRx(pVM, pVCpu, pRegFrame, DISCREG_CR0, NewCr0);
1611}
1612
1613
1614/**
1615 * Interpret CLTS.
1616 *
1617 * @returns VBox status code.
1618 * @param pVM Pointer to the VM.
1619 * @param pVCpu Pointer to the VMCPU.
1620 *
1621 */
1622VMM_INT_DECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu)
1623{
1624 NOREF(pVM);
1625
1626 uint64_t cr0 = CPUMGetGuestCR0(pVCpu);
1627 if (!(cr0 & X86_CR0_TS))
1628 return VINF_SUCCESS;
1629 return CPUMSetGuestCR0(pVCpu, cr0 & ~X86_CR0_TS);
1630}
1631
1632
1633#ifdef LOG_ENABLED
1634static const char *emMSRtoString(uint32_t uMsr)
1635{
1636 switch (uMsr)
1637 {
1638 case MSR_IA32_APICBASE: return "MSR_IA32_APICBASE";
1639 case MSR_IA32_CR_PAT: return "MSR_IA32_CR_PAT";
1640 case MSR_IA32_SYSENTER_CS: return "MSR_IA32_SYSENTER_CS";
1641 case MSR_IA32_SYSENTER_EIP: return "MSR_IA32_SYSENTER_EIP";
1642 case MSR_IA32_SYSENTER_ESP: return "MSR_IA32_SYSENTER_ESP";
1643 case MSR_K6_EFER: return "MSR_K6_EFER";
1644 case MSR_K8_SF_MASK: return "MSR_K8_SF_MASK";
1645 case MSR_K6_STAR: return "MSR_K6_STAR";
1646 case MSR_K8_LSTAR: return "MSR_K8_LSTAR";
1647 case MSR_K8_CSTAR: return "MSR_K8_CSTAR";
1648 case MSR_K8_FS_BASE: return "MSR_K8_FS_BASE";
1649 case MSR_K8_GS_BASE: return "MSR_K8_GS_BASE";
1650 case MSR_K8_KERNEL_GS_BASE: return "MSR_K8_KERNEL_GS_BASE";
1651 case MSR_K8_TSC_AUX: return "MSR_K8_TSC_AUX";
1652 case MSR_IA32_BIOS_SIGN_ID: return "Unsupported MSR_IA32_BIOS_SIGN_ID";
1653 case MSR_IA32_PLATFORM_ID: return "Unsupported MSR_IA32_PLATFORM_ID";
1654 case MSR_IA32_BIOS_UPDT_TRIG: return "Unsupported MSR_IA32_BIOS_UPDT_TRIG";
1655 case MSR_IA32_TSC: return "MSR_IA32_TSC";
1656 case MSR_IA32_MISC_ENABLE: return "MSR_IA32_MISC_ENABLE";
1657 case MSR_IA32_MTRR_CAP: return "MSR_IA32_MTRR_CAP";
1658 case MSR_IA32_MCP_CAP: return "Unsupported MSR_IA32_MCP_CAP";
1659 case MSR_IA32_MCP_STATUS: return "Unsupported MSR_IA32_MCP_STATUS";
1660 case MSR_IA32_MCP_CTRL: return "Unsupported MSR_IA32_MCP_CTRL";
1661 case MSR_IA32_MTRR_DEF_TYPE: return "MSR_IA32_MTRR_DEF_TYPE";
1662 case MSR_K7_EVNTSEL0: return "Unsupported MSR_K7_EVNTSEL0";
1663 case MSR_K7_EVNTSEL1: return "Unsupported MSR_K7_EVNTSEL1";
1664 case MSR_K7_EVNTSEL2: return "Unsupported MSR_K7_EVNTSEL2";
1665 case MSR_K7_EVNTSEL3: return "Unsupported MSR_K7_EVNTSEL3";
1666 case MSR_IA32_MC0_CTL: return "Unsupported MSR_IA32_MC0_CTL";
1667 case MSR_IA32_MC0_STATUS: return "Unsupported MSR_IA32_MC0_STATUS";
1668 case MSR_IA32_PERFEVTSEL0: return "Unsupported MSR_IA32_PERFEVTSEL0";
1669 case MSR_IA32_PERFEVTSEL1: return "Unsupported MSR_IA32_PERFEVTSEL1";
1670 case MSR_IA32_PERF_STATUS: return "MSR_IA32_PERF_STATUS";
1671 case MSR_IA32_PLATFORM_INFO: return "MSR_IA32_PLATFORM_INFO";
1672 case MSR_IA32_PERF_CTL: return "Unsupported MSR_IA32_PERF_CTL";
1673 case MSR_K7_PERFCTR0: return "Unsupported MSR_K7_PERFCTR0";
1674 case MSR_K7_PERFCTR1: return "Unsupported MSR_K7_PERFCTR1";
1675 case MSR_K7_PERFCTR2: return "Unsupported MSR_K7_PERFCTR2";
1676 case MSR_K7_PERFCTR3: return "Unsupported MSR_K7_PERFCTR3";
1677 case MSR_IA32_PMC0: return "Unsupported MSR_IA32_PMC0";
1678 case MSR_IA32_PMC1: return "Unsupported MSR_IA32_PMC1";
1679 case MSR_IA32_PMC2: return "Unsupported MSR_IA32_PMC2";
1680 case MSR_IA32_PMC3: return "Unsupported MSR_IA32_PMC3";
1681 }
1682 return "Unknown MSR";
1683}
1684#endif /* LOG_ENABLED */
1685
1686
1687/**
1688 * Interpret RDMSR
1689 *
1690 * @returns VBox status code.
1691 * @param pVM Pointer to the VM.
1692 * @param pVCpu Pointer to the VMCPU.
1693 * @param pRegFrame The register frame.
1694 */
1695VMM_INT_DECL(int) EMInterpretRdmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1696{
1697 NOREF(pVM);
1698
1699 /* Get the current privilege level. */
1700 if (CPUMGetGuestCPL(pVCpu) != 0)
1701 {
1702 Log4(("EM: Refuse RDMSR: CPL != 0\n"));
1703 return VERR_EM_INTERPRETER; /* supervisor only */
1704 }
1705
1706 uint64_t uValue;
1707 int rc = CPUMQueryGuestMsr(pVCpu, pRegFrame->ecx, &uValue);
1708 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1709 {
1710 Assert(rc == VERR_CPUM_RAISE_GP_0);
1711 Log4(("EM: Refuse RDMSR: rc=%Rrc\n", rc));
1712 return VERR_EM_INTERPRETER;
1713 }
1714 pRegFrame->rax = (uint32_t) uValue;
1715 pRegFrame->rdx = (uint32_t)(uValue >> 32);
1716 LogFlow(("EMInterpretRdmsr %s (%x) -> %RX64\n", emMSRtoString(pRegFrame->ecx), pRegFrame->ecx, uValue));
1717 return rc;
1718}
1719
1720
1721/**
1722 * Interpret WRMSR
1723 *
1724 * @returns VBox status code.
1725 * @param pVM Pointer to the VM.
1726 * @param pVCpu Pointer to the VMCPU.
1727 * @param pRegFrame The register frame.
1728 */
1729VMM_INT_DECL(int) EMInterpretWrmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1730{
1731 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1732
1733 /* Check the current privilege level, this instruction is supervisor only. */
1734 if (CPUMGetGuestCPL(pVCpu) != 0)
1735 {
1736 Log4(("EM: Refuse WRMSR: CPL != 0\n"));
1737 return VERR_EM_INTERPRETER; /** @todo raise \#GP(0) */
1738 }
1739
1740 int rc = CPUMSetGuestMsr(pVCpu, pRegFrame->ecx, RT_MAKE_U64(pRegFrame->eax, pRegFrame->edx));
1741 if (rc != VINF_SUCCESS)
1742 {
1743 Assert(rc == VERR_CPUM_RAISE_GP_0);
1744 Log4(("EM: Refuse WRMSR: rc=%d\n", rc));
1745 return VERR_EM_INTERPRETER;
1746 }
1747 LogFlow(("EMInterpretWrmsr %s (%x) val=%RX64\n", emMSRtoString(pRegFrame->ecx), pRegFrame->ecx,
1748 RT_MAKE_U64(pRegFrame->eax, pRegFrame->edx)));
1749 NOREF(pVM);
1750 return rc;
1751}
1752
1753
1754/**
1755 * Interpret CRx read.
1756 *
1757 * @returns VBox status code.
1758 * @param pVM Pointer to the VM.
1759 * @param pVCpu Pointer to the VMCPU.
1760 * @param pRegFrame The register frame.
1761 * @param DestRegGen General purpose register index (USE_REG_E**))
1762 * @param SrcRegCRx CRx register index (DISUSE_REG_CR*)
1763 *
1764 */
1765VMM_INT_DECL(int) EMInterpretCRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx)
1766{
1767 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1768 uint64_t val64;
1769 int rc = CPUMGetGuestCRx(pVCpu, SrcRegCrx, &val64);
1770 AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER);
1771 NOREF(pVM);
1772
1773 if (CPUMIsGuestIn64BitCode(pVCpu))
1774 rc = DISWriteReg64(pRegFrame, DestRegGen, val64);
1775 else
1776 rc = DISWriteReg32(pRegFrame, DestRegGen, val64);
1777
1778 if (RT_SUCCESS(rc))
1779 {
1780 LogFlow(("MOV_CR: gen32=%d CR=%d val=%RX64\n", DestRegGen, SrcRegCrx, val64));
1781 return VINF_SUCCESS;
1782 }
1783 return VERR_EM_INTERPRETER;
1784}
1785
1786
1787/**
1788 * Interpret DRx write.
1789 *
1790 * @returns VBox status code.
1791 * @param pVM Pointer to the VM.
1792 * @param pVCpu Pointer to the VMCPU.
1793 * @param pRegFrame The register frame.
1794 * @param DestRegDRx DRx register index (USE_REG_DR*)
1795 * @param SrcRegGen General purpose register index (USE_REG_E**))
1796 *
1797 */
1798VMM_INT_DECL(int) EMInterpretDRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)
1799{
1800 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1801 uint64_t val;
1802 int rc;
1803 NOREF(pVM);
1804
1805 if (CPUMIsGuestIn64BitCode(pVCpu))
1806 rc = DISFetchReg64(pRegFrame, SrcRegGen, &val);
1807 else
1808 {
1809 uint32_t val32;
1810 rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1811 val = val32;
1812 }
1813
1814 if (RT_SUCCESS(rc))
1815 {
1816 /** @todo we don't fail if illegal bits are set/cleared for e.g. dr7 */
1817 rc = CPUMSetGuestDRx(pVCpu, DestRegDrx, val);
1818 if (RT_SUCCESS(rc))
1819 return rc;
1820 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx));
1821 }
1822 return VERR_EM_INTERPRETER;
1823}
1824
1825
1826/**
1827 * Interpret DRx read.
1828 *
1829 * @returns VBox status code.
1830 * @param pVM Pointer to the VM.
1831 * @param pVCpu Pointer to the VMCPU.
1832 * @param pRegFrame The register frame.
1833 * @param DestRegGen General purpose register index (USE_REG_E**))
1834 * @param SrcRegDRx DRx register index (USE_REG_DR*)
1835 *
1836 */
1837VMM_INT_DECL(int) EMInterpretDRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)
1838{
1839 uint64_t val64;
1840 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
1841 NOREF(pVM);
1842
1843 int rc = CPUMGetGuestDRx(pVCpu, SrcRegDrx, &val64);
1844 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER);
1845 if (CPUMIsGuestIn64BitCode(pVCpu))
1846 rc = DISWriteReg64(pRegFrame, DestRegGen, val64);
1847 else
1848 rc = DISWriteReg32(pRegFrame, DestRegGen, (uint32_t)val64);
1849
1850 if (RT_SUCCESS(rc))
1851 return VINF_SUCCESS;
1852
1853 return VERR_EM_INTERPRETER;
1854}
1855
1856
1857#if !defined(VBOX_WITH_IEM) || defined(VBOX_COMPARE_IEM_AND_EM)
1858
1859
1860
1861
1862
1863
1864/*
1865 *
1866 * The old interpreter.
1867 * The old interpreter.
1868 * The old interpreter.
1869 * The old interpreter.
1870 * The old interpreter.
1871 *
1872 */
1873
1874DECLINLINE(int) emRamRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCPTR GCPtrSrc, uint32_t cb)
1875{
1876#ifdef IN_RC
1877 int rc = MMGCRamRead(pVM, pvDst, (void *)(uintptr_t)GCPtrSrc, cb);
1878 if (RT_LIKELY(rc != VERR_ACCESS_DENIED))
1879 return rc;
1880 /*
1881 * The page pool cache may end up here in some cases because it
1882 * flushed one of the shadow mappings used by the trapping
1883 * instruction and it either flushed the TLB or the CPU reused it.
1884 */
1885#else
1886 NOREF(pVM);
1887#endif
1888 return PGMPhysInterpretedReadNoHandlers(pVCpu, pCtxCore, pvDst, GCPtrSrc, cb, /*fMayTrap*/ false);
1889}
1890
1891
1892DECLINLINE(int) emRamWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, const void *pvSrc, uint32_t cb)
1893{
1894 /* Don't use MMGCRamWrite here as it does not respect zero pages, shared
1895 pages or write monitored pages. */
1896 NOREF(pVM);
1897#if !defined(VBOX_COMPARE_IEM_AND_EM) || !defined(VBOX_COMPARE_IEM_LAST)
1898 int rc = PGMPhysInterpretedWriteNoHandlers(pVCpu, pCtxCore, GCPtrDst, pvSrc, cb, /*fMayTrap*/ false);
1899#else
1900 int rc = VINF_SUCCESS;
1901#endif
1902#ifdef VBOX_COMPARE_IEM_AND_EM
1903 Log(("EM Wrote: %RGv %.*Rhxs rc=%Rrc\n", GCPtrDst, RT_MAX(RT_MIN(cb, 64), 1), pvSrc, rc));
1904 g_cbEmWrote = cb;
1905 memcpy(g_abEmWrote, pvSrc, RT_MIN(cb, sizeof(g_abEmWrote)));
1906#endif
1907 return rc;
1908}
1909
1910
1911/** Convert sel:addr to a flat GC address. */
1912DECLINLINE(RTGCPTR) emConvertToFlatAddr(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pDis, PDISOPPARAM pParam, RTGCPTR pvAddr)
1913{
1914 DISSELREG enmPrefixSeg = DISDetectSegReg(pDis, pParam);
1915 return SELMToFlat(pVM, enmPrefixSeg, pRegFrame, pvAddr);
1916}
1917
1918
1919#if defined(VBOX_STRICT) || defined(LOG_ENABLED)
1920/**
1921 * Get the mnemonic for the disassembled instruction.
1922 *
1923 * GC/R0 doesn't include the strings in the DIS tables because
1924 * of limited space.
1925 */
1926static const char *emGetMnemonic(PDISCPUSTATE pDis)
1927{
1928 switch (pDis->pCurInstr->uOpcode)
1929 {
1930 case OP_XCHG: return "Xchg";
1931 case OP_DEC: return "Dec";
1932 case OP_INC: return "Inc";
1933 case OP_POP: return "Pop";
1934 case OP_OR: return "Or";
1935 case OP_AND: return "And";
1936 case OP_MOV: return "Mov";
1937 case OP_INVLPG: return "InvlPg";
1938 case OP_CPUID: return "CpuId";
1939 case OP_MOV_CR: return "MovCRx";
1940 case OP_MOV_DR: return "MovDRx";
1941 case OP_LLDT: return "LLdt";
1942 case OP_LGDT: return "LGdt";
1943 case OP_LIDT: return "LIdt";
1944 case OP_CLTS: return "Clts";
1945 case OP_MONITOR: return "Monitor";
1946 case OP_MWAIT: return "MWait";
1947 case OP_RDMSR: return "Rdmsr";
1948 case OP_WRMSR: return "Wrmsr";
1949 case OP_ADD: return "Add";
1950 case OP_ADC: return "Adc";
1951 case OP_SUB: return "Sub";
1952 case OP_SBB: return "Sbb";
1953 case OP_RDTSC: return "Rdtsc";
1954 case OP_STI: return "Sti";
1955 case OP_CLI: return "Cli";
1956 case OP_XADD: return "XAdd";
1957 case OP_HLT: return "Hlt";
1958 case OP_IRET: return "Iret";
1959 case OP_MOVNTPS: return "MovNTPS";
1960 case OP_STOSWD: return "StosWD";
1961 case OP_WBINVD: return "WbInvd";
1962 case OP_XOR: return "Xor";
1963 case OP_BTR: return "Btr";
1964 case OP_BTS: return "Bts";
1965 case OP_BTC: return "Btc";
1966 case OP_LMSW: return "Lmsw";
1967 case OP_SMSW: return "Smsw";
1968 case OP_CMPXCHG: return pDis->fPrefix & DISPREFIX_LOCK ? "Lock CmpXchg" : "CmpXchg";
1969 case OP_CMPXCHG8B: return pDis->fPrefix & DISPREFIX_LOCK ? "Lock CmpXchg8b" : "CmpXchg8b";
1970
1971 default:
1972 Log(("Unknown opcode %d\n", pDis->pCurInstr->uOpcode));
1973 return "???";
1974 }
1975}
1976#endif /* VBOX_STRICT || LOG_ENABLED */
1977
1978
1979/**
1980 * XCHG instruction emulation.
1981 */
1982static int emInterpretXchg(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1983{
1984 DISQPVPARAMVAL param1, param2;
1985 NOREF(pvFault);
1986
1987 /* Source to make DISQueryParamVal read the register value - ugly hack */
1988 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
1989 if(RT_FAILURE(rc))
1990 return VERR_EM_INTERPRETER;
1991
1992 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
1993 if(RT_FAILURE(rc))
1994 return VERR_EM_INTERPRETER;
1995
1996#ifdef IN_RC
1997 if (TRPMHasTrap(pVCpu))
1998 {
1999 if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW)
2000 {
2001#endif
2002 RTGCPTR pParam1 = 0, pParam2 = 0;
2003 uint64_t valpar1, valpar2;
2004
2005 AssertReturn(pDis->Param1.cb == pDis->Param2.cb, VERR_EM_INTERPRETER);
2006 switch(param1.type)
2007 {
2008 case DISQPV_TYPE_IMMEDIATE: /* register type is translated to this one too */
2009 valpar1 = param1.val.val64;
2010 break;
2011
2012 case DISQPV_TYPE_ADDRESS:
2013 pParam1 = (RTGCPTR)param1.val.val64;
2014 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pParam1);
2015 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault, VERR_EM_INTERPRETER);
2016 rc = emRamRead(pVM, pVCpu, pRegFrame, &valpar1, pParam1, param1.size);
2017 if (RT_FAILURE(rc))
2018 {
2019 AssertMsgFailed(("MMGCRamRead %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2020 return VERR_EM_INTERPRETER;
2021 }
2022 break;
2023
2024 default:
2025 AssertFailed();
2026 return VERR_EM_INTERPRETER;
2027 }
2028
2029 switch(param2.type)
2030 {
2031 case DISQPV_TYPE_ADDRESS:
2032 pParam2 = (RTGCPTR)param2.val.val64;
2033 pParam2 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param2, pParam2);
2034 EM_ASSERT_FAULT_RETURN(pParam2 == pvFault, VERR_EM_INTERPRETER);
2035 rc = emRamRead(pVM, pVCpu, pRegFrame, &valpar2, pParam2, param2.size);
2036 if (RT_FAILURE(rc))
2037 {
2038 AssertMsgFailed(("MMGCRamRead %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2039 }
2040 break;
2041
2042 case DISQPV_TYPE_IMMEDIATE:
2043 valpar2 = param2.val.val64;
2044 break;
2045
2046 default:
2047 AssertFailed();
2048 return VERR_EM_INTERPRETER;
2049 }
2050
2051 /* Write value of parameter 2 to parameter 1 (reg or memory address) */
2052 if (pParam1 == 0)
2053 {
2054 Assert(param1.type == DISQPV_TYPE_IMMEDIATE); /* register actually */
2055 switch(param1.size)
2056 {
2057 case 1: //special case for AH etc
2058 rc = DISWriteReg8(pRegFrame, pDis->Param1.Base.idxGenReg, (uint8_t )valpar2); break;
2059 case 2: rc = DISWriteReg16(pRegFrame, pDis->Param1.Base.idxGenReg, (uint16_t)valpar2); break;
2060 case 4: rc = DISWriteReg32(pRegFrame, pDis->Param1.Base.idxGenReg, (uint32_t)valpar2); break;
2061 case 8: rc = DISWriteReg64(pRegFrame, pDis->Param1.Base.idxGenReg, valpar2); break;
2062 default: AssertFailedReturn(VERR_EM_INTERPRETER);
2063 }
2064 if (RT_FAILURE(rc))
2065 return VERR_EM_INTERPRETER;
2066 }
2067 else
2068 {
2069 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam1, &valpar2, param1.size);
2070 if (RT_FAILURE(rc))
2071 {
2072 AssertMsgFailed(("emRamWrite %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2073 return VERR_EM_INTERPRETER;
2074 }
2075 }
2076
2077 /* Write value of parameter 1 to parameter 2 (reg or memory address) */
2078 if (pParam2 == 0)
2079 {
2080 Assert(param2.type == DISQPV_TYPE_IMMEDIATE); /* register actually */
2081 switch(param2.size)
2082 {
2083 case 1: //special case for AH etc
2084 rc = DISWriteReg8(pRegFrame, pDis->Param2.Base.idxGenReg, (uint8_t )valpar1); break;
2085 case 2: rc = DISWriteReg16(pRegFrame, pDis->Param2.Base.idxGenReg, (uint16_t)valpar1); break;
2086 case 4: rc = DISWriteReg32(pRegFrame, pDis->Param2.Base.idxGenReg, (uint32_t)valpar1); break;
2087 case 8: rc = DISWriteReg64(pRegFrame, pDis->Param2.Base.idxGenReg, valpar1); break;
2088 default: AssertFailedReturn(VERR_EM_INTERPRETER);
2089 }
2090 if (RT_FAILURE(rc))
2091 return VERR_EM_INTERPRETER;
2092 }
2093 else
2094 {
2095 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam2, &valpar1, param2.size);
2096 if (RT_FAILURE(rc))
2097 {
2098 AssertMsgFailed(("emRamWrite %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2099 return VERR_EM_INTERPRETER;
2100 }
2101 }
2102
2103 *pcbSize = param2.size;
2104 return VINF_SUCCESS;
2105#ifdef IN_RC
2106 }
2107 }
2108 return VERR_EM_INTERPRETER;
2109#endif
2110}
2111
2112
2113/**
2114 * INC and DEC emulation.
2115 */
2116static int emInterpretIncDec(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
2117 PFNEMULATEPARAM2 pfnEmulate)
2118{
2119 DISQPVPARAMVAL param1;
2120 NOREF(pvFault);
2121
2122 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2123 if(RT_FAILURE(rc))
2124 return VERR_EM_INTERPRETER;
2125
2126#ifdef IN_RC
2127 if (TRPMHasTrap(pVCpu))
2128 {
2129 if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW)
2130 {
2131#endif
2132 RTGCPTR pParam1 = 0;
2133 uint64_t valpar1;
2134
2135 if (param1.type == DISQPV_TYPE_ADDRESS)
2136 {
2137 pParam1 = (RTGCPTR)param1.val.val64;
2138 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pParam1);
2139#ifdef IN_RC
2140 /* Safety check (in theory it could cross a page boundary and fault there though) */
2141 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault, VERR_EM_INTERPRETER);
2142#endif
2143 rc = emRamRead(pVM, pVCpu, pRegFrame, &valpar1, pParam1, param1.size);
2144 if (RT_FAILURE(rc))
2145 {
2146 AssertMsgFailed(("emRamRead %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2147 return VERR_EM_INTERPRETER;
2148 }
2149 }
2150 else
2151 {
2152 AssertFailed();
2153 return VERR_EM_INTERPRETER;
2154 }
2155
2156 uint32_t eflags;
2157
2158 eflags = pfnEmulate(&valpar1, param1.size);
2159
2160 /* Write result back */
2161 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam1, &valpar1, param1.size);
2162 if (RT_FAILURE(rc))
2163 {
2164 AssertMsgFailed(("emRamWrite %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2165 return VERR_EM_INTERPRETER;
2166 }
2167
2168 /* Update guest's eflags and finish. */
2169 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
2170 | (eflags & (X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
2171
2172 /* All done! */
2173 *pcbSize = param1.size;
2174 return VINF_SUCCESS;
2175#ifdef IN_RC
2176 }
2177 }
2178 return VERR_EM_INTERPRETER;
2179#endif
2180}
2181
2182
2183/**
2184 * POP Emulation.
2185 */
2186static int emInterpretPop(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2187{
2188 Assert(pDis->uCpuMode != DISCPUMODE_64BIT); /** @todo check */
2189 DISQPVPARAMVAL param1;
2190 NOREF(pvFault);
2191
2192 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2193 if(RT_FAILURE(rc))
2194 return VERR_EM_INTERPRETER;
2195
2196#ifdef IN_RC
2197 if (TRPMHasTrap(pVCpu))
2198 {
2199 if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW)
2200 {
2201#endif
2202 RTGCPTR pParam1 = 0;
2203 uint32_t valpar1;
2204 RTGCPTR pStackVal;
2205
2206 /* Read stack value first */
2207 if (CPUMGetGuestCodeBits(pVCpu) == 16)
2208 return VERR_EM_INTERPRETER; /* No legacy 16 bits stuff here, please. */
2209
2210 /* Convert address; don't bother checking limits etc, as we only read here */
2211 pStackVal = SELMToFlat(pVM, DISSELREG_SS, pRegFrame, (RTGCPTR)pRegFrame->esp);
2212 if (pStackVal == 0)
2213 return VERR_EM_INTERPRETER;
2214
2215 rc = emRamRead(pVM, pVCpu, pRegFrame, &valpar1, pStackVal, param1.size);
2216 if (RT_FAILURE(rc))
2217 {
2218 AssertMsgFailed(("emRamRead %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2219 return VERR_EM_INTERPRETER;
2220 }
2221
2222 if (param1.type == DISQPV_TYPE_ADDRESS)
2223 {
2224 pParam1 = (RTGCPTR)param1.val.val64;
2225
2226 /* pop [esp+xx] uses esp after the actual pop! */
2227 AssertCompile(DISGREG_ESP == DISGREG_SP);
2228 if ( (pDis->Param1.fUse & DISUSE_BASE)
2229 && (pDis->Param1.fUse & (DISUSE_REG_GEN16|DISUSE_REG_GEN32))
2230 && pDis->Param1.Base.idxGenReg == DISGREG_ESP
2231 )
2232 pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + param1.size);
2233
2234 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pParam1);
2235 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault || (RTGCPTR)pRegFrame->esp == pvFault, VERR_EM_INTERPRETER);
2236 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam1, &valpar1, param1.size);
2237 if (RT_FAILURE(rc))
2238 {
2239 AssertMsgFailed(("emRamWrite %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2240 return VERR_EM_INTERPRETER;
2241 }
2242
2243 /* Update ESP as the last step */
2244 pRegFrame->esp += param1.size;
2245 }
2246 else
2247 {
2248#ifndef DEBUG_bird // annoying assertion.
2249 AssertFailed();
2250#endif
2251 return VERR_EM_INTERPRETER;
2252 }
2253
2254 /* All done! */
2255 *pcbSize = param1.size;
2256 return VINF_SUCCESS;
2257#ifdef IN_RC
2258 }
2259 }
2260 return VERR_EM_INTERPRETER;
2261#endif
2262}
2263
2264
2265/**
2266 * XOR/OR/AND Emulation.
2267 */
2268static int emInterpretOrXorAnd(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
2269 PFNEMULATEPARAM3 pfnEmulate)
2270{
2271 DISQPVPARAMVAL param1, param2;
2272 NOREF(pvFault);
2273
2274 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2275 if(RT_FAILURE(rc))
2276 return VERR_EM_INTERPRETER;
2277
2278 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
2279 if(RT_FAILURE(rc))
2280 return VERR_EM_INTERPRETER;
2281
2282#ifdef IN_RC
2283 if (TRPMHasTrap(pVCpu))
2284 {
2285 if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW)
2286 {
2287#endif
2288 RTGCPTR pParam1;
2289 uint64_t valpar1, valpar2;
2290
2291 if (pDis->Param1.cb != pDis->Param2.cb)
2292 {
2293 if (pDis->Param1.cb < pDis->Param2.cb)
2294 {
2295 AssertMsgFailed(("%s at %RGv parameter mismatch %d vs %d!!\n", emGetMnemonic(pDis), (RTGCPTR)pRegFrame->rip, pDis->Param1.cb, pDis->Param2.cb)); /* should never happen! */
2296 return VERR_EM_INTERPRETER;
2297 }
2298 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
2299 pDis->Param2.cb = pDis->Param1.cb;
2300 param2.size = param1.size;
2301 }
2302
2303 /* The destination is always a virtual address */
2304 if (param1.type == DISQPV_TYPE_ADDRESS)
2305 {
2306 pParam1 = (RTGCPTR)param1.val.val64;
2307 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pParam1);
2308 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault, VERR_EM_INTERPRETER);
2309 rc = emRamRead(pVM, pVCpu, pRegFrame, &valpar1, pParam1, param1.size);
2310 if (RT_FAILURE(rc))
2311 {
2312 AssertMsgFailed(("emRamRead %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2313 return VERR_EM_INTERPRETER;
2314 }
2315 }
2316 else
2317 {
2318 AssertFailed();
2319 return VERR_EM_INTERPRETER;
2320 }
2321
2322 /* Register or immediate data */
2323 switch(param2.type)
2324 {
2325 case DISQPV_TYPE_IMMEDIATE: /* both immediate data and register (ugly) */
2326 valpar2 = param2.val.val64;
2327 break;
2328
2329 default:
2330 AssertFailed();
2331 return VERR_EM_INTERPRETER;
2332 }
2333
2334 LogFlow(("emInterpretOrXorAnd %s %RGv %RX64 - %RX64 size %d (%d)\n", emGetMnemonic(pDis), pParam1, valpar1, valpar2, param2.size, param1.size));
2335
2336 /* Data read, emulate instruction. */
2337 uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
2338
2339 LogFlow(("emInterpretOrXorAnd %s result %RX64\n", emGetMnemonic(pDis), valpar1));
2340
2341 /* Update guest's eflags and finish. */
2342 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
2343 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
2344
2345 /* And write it back */
2346 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam1, &valpar1, param1.size);
2347 if (RT_SUCCESS(rc))
2348 {
2349 /* All done! */
2350 *pcbSize = param2.size;
2351 return VINF_SUCCESS;
2352 }
2353#ifdef IN_RC
2354 }
2355 }
2356#endif
2357 return VERR_EM_INTERPRETER;
2358}
2359
2360
2361#ifndef VBOX_COMPARE_IEM_AND_EM
2362/**
2363 * LOCK XOR/OR/AND Emulation.
2364 */
2365static int emInterpretLockOrXorAnd(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault,
2366 uint32_t *pcbSize, PFNEMULATELOCKPARAM3 pfnEmulate)
2367{
2368 void *pvParam1;
2369 DISQPVPARAMVAL param1, param2;
2370 NOREF(pvFault);
2371
2372#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0)
2373 Assert(pDis->Param1.cb <= 4);
2374#endif
2375
2376 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2377 if(RT_FAILURE(rc))
2378 return VERR_EM_INTERPRETER;
2379
2380 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
2381 if(RT_FAILURE(rc))
2382 return VERR_EM_INTERPRETER;
2383
2384 if (pDis->Param1.cb != pDis->Param2.cb)
2385 {
2386 AssertMsgReturn(pDis->Param1.cb >= pDis->Param2.cb, /* should never happen! */
2387 ("%s at %RGv parameter mismatch %d vs %d!!\n", emGetMnemonic(pDis), (RTGCPTR)pRegFrame->rip, pDis->Param1.cb, pDis->Param2.cb),
2388 VERR_EM_INTERPRETER);
2389
2390 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
2391 pDis->Param2.cb = pDis->Param1.cb;
2392 param2.size = param1.size;
2393 }
2394
2395#ifdef IN_RC
2396 /* Safety check (in theory it could cross a page boundary and fault there though) */
2397 Assert( TRPMHasTrap(pVCpu)
2398 && (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW));
2399 EM_ASSERT_FAULT_RETURN(GCPtrPar1 == pvFault, VERR_EM_INTERPRETER);
2400#endif
2401
2402 /* Register and immediate data == DISQPV_TYPE_IMMEDIATE */
2403 AssertReturn(param2.type == DISQPV_TYPE_IMMEDIATE, VERR_EM_INTERPRETER);
2404 RTGCUINTREG ValPar2 = param2.val.val64;
2405
2406 /* The destination is always a virtual address */
2407 AssertReturn(param1.type == DISQPV_TYPE_ADDRESS, VERR_EM_INTERPRETER);
2408
2409 RTGCPTR GCPtrPar1 = param1.val.val64;
2410 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, GCPtrPar1);
2411 PGMPAGEMAPLOCK Lock;
2412 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrPar1, &pvParam1, &Lock);
2413 AssertRCReturn(rc, VERR_EM_INTERPRETER);
2414
2415 /* Try emulate it with a one-shot #PF handler in place. (RC) */
2416 Log2(("%s %RGv imm%d=%RX64\n", emGetMnemonic(pDis), GCPtrPar1, pDis->Param2.cb*8, ValPar2));
2417
2418 RTGCUINTREG32 eflags = 0;
2419 rc = pfnEmulate(pvParam1, ValPar2, pDis->Param2.cb, &eflags);
2420 PGMPhysReleasePageMappingLock(pVM, &Lock);
2421 if (RT_FAILURE(rc))
2422 {
2423 Log(("%s %RGv imm%d=%RX64-> emulation failed due to page fault!\n", emGetMnemonic(pDis), GCPtrPar1, pDis->Param2.cb*8, ValPar2));
2424 return VERR_EM_INTERPRETER;
2425 }
2426
2427 /* Update guest's eflags and finish. */
2428 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
2429 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
2430
2431 *pcbSize = param2.size;
2432 return VINF_SUCCESS;
2433}
2434#endif /* !VBOX_COMPARE_IEM_AND_EM */
2435
2436
2437/**
2438 * ADD, ADC & SUB Emulation.
2439 */
2440static int emInterpretAddSub(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
2441 PFNEMULATEPARAM3 pfnEmulate)
2442{
2443 NOREF(pvFault);
2444 DISQPVPARAMVAL param1, param2;
2445 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2446 if(RT_FAILURE(rc))
2447 return VERR_EM_INTERPRETER;
2448
2449 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
2450 if(RT_FAILURE(rc))
2451 return VERR_EM_INTERPRETER;
2452
2453#ifdef IN_RC
2454 if (TRPMHasTrap(pVCpu))
2455 {
2456 if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW)
2457 {
2458#endif
2459 RTGCPTR pParam1;
2460 uint64_t valpar1, valpar2;
2461
2462 if (pDis->Param1.cb != pDis->Param2.cb)
2463 {
2464 if (pDis->Param1.cb < pDis->Param2.cb)
2465 {
2466 AssertMsgFailed(("%s at %RGv parameter mismatch %d vs %d!!\n", emGetMnemonic(pDis), (RTGCPTR)pRegFrame->rip, pDis->Param1.cb, pDis->Param2.cb)); /* should never happen! */
2467 return VERR_EM_INTERPRETER;
2468 }
2469 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
2470 pDis->Param2.cb = pDis->Param1.cb;
2471 param2.size = param1.size;
2472 }
2473
2474 /* The destination is always a virtual address */
2475 if (param1.type == DISQPV_TYPE_ADDRESS)
2476 {
2477 pParam1 = (RTGCPTR)param1.val.val64;
2478 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pParam1);
2479 EM_ASSERT_FAULT_RETURN(pParam1 == pvFault, VERR_EM_INTERPRETER);
2480 rc = emRamRead(pVM, pVCpu, pRegFrame, &valpar1, pParam1, param1.size);
2481 if (RT_FAILURE(rc))
2482 {
2483 AssertMsgFailed(("emRamRead %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2484 return VERR_EM_INTERPRETER;
2485 }
2486 }
2487 else
2488 {
2489#ifndef DEBUG_bird
2490 AssertFailed();
2491#endif
2492 return VERR_EM_INTERPRETER;
2493 }
2494
2495 /* Register or immediate data */
2496 switch(param2.type)
2497 {
2498 case DISQPV_TYPE_IMMEDIATE: /* both immediate data and register (ugly) */
2499 valpar2 = param2.val.val64;
2500 break;
2501
2502 default:
2503 AssertFailed();
2504 return VERR_EM_INTERPRETER;
2505 }
2506
2507 /* Data read, emulate instruction. */
2508 uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
2509
2510 /* Update guest's eflags and finish. */
2511 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
2512 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
2513
2514 /* And write it back */
2515 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam1, &valpar1, param1.size);
2516 if (RT_SUCCESS(rc))
2517 {
2518 /* All done! */
2519 *pcbSize = param2.size;
2520 return VINF_SUCCESS;
2521 }
2522#ifdef IN_RC
2523 }
2524 }
2525#endif
2526 return VERR_EM_INTERPRETER;
2527}
2528
2529
2530/**
2531 * ADC Emulation.
2532 */
2533static int emInterpretAdc(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2534{
2535 if (pRegFrame->eflags.Bits.u1CF)
2536 return emInterpretAddSub(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize, EMEmulateAdcWithCarrySet);
2537 else
2538 return emInterpretAddSub(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize, EMEmulateAdd);
2539}
2540
2541
2542/**
2543 * BTR/C/S Emulation.
2544 */
2545static int emInterpretBitTest(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
2546 PFNEMULATEPARAM2UINT32 pfnEmulate)
2547{
2548 DISQPVPARAMVAL param1, param2;
2549 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2550 if(RT_FAILURE(rc))
2551 return VERR_EM_INTERPRETER;
2552
2553 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
2554 if(RT_FAILURE(rc))
2555 return VERR_EM_INTERPRETER;
2556
2557#ifdef IN_RC
2558 if (TRPMHasTrap(pVCpu))
2559 {
2560 if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW)
2561 {
2562#endif
2563 RTGCPTR pParam1;
2564 uint64_t valpar1 = 0, valpar2;
2565 uint32_t eflags;
2566
2567 /* The destination is always a virtual address */
2568 if (param1.type != DISQPV_TYPE_ADDRESS)
2569 return VERR_EM_INTERPRETER;
2570
2571 pParam1 = (RTGCPTR)param1.val.val64;
2572 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pParam1);
2573
2574 /* Register or immediate data */
2575 switch(param2.type)
2576 {
2577 case DISQPV_TYPE_IMMEDIATE: /* both immediate data and register (ugly) */
2578 valpar2 = param2.val.val64;
2579 break;
2580
2581 default:
2582 AssertFailed();
2583 return VERR_EM_INTERPRETER;
2584 }
2585
2586 Log2(("emInterpret%s: pvFault=%RGv pParam1=%RGv val2=%x\n", emGetMnemonic(pDis), pvFault, pParam1, valpar2));
2587 pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + valpar2/8);
2588 EM_ASSERT_FAULT_RETURN((RTGCPTR)((RTGCUINTPTR)pParam1 & ~3) == pvFault, VERR_EM_INTERPRETER);
2589 rc = emRamRead(pVM, pVCpu, pRegFrame, &valpar1, pParam1, 1);
2590 if (RT_FAILURE(rc))
2591 {
2592 AssertMsgFailed(("emRamRead %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
2593 return VERR_EM_INTERPRETER;
2594 }
2595
2596 Log2(("emInterpretBtx: val=%x\n", valpar1));
2597 /* Data read, emulate bit test instruction. */
2598 eflags = pfnEmulate(&valpar1, valpar2 & 0x7);
2599
2600 Log2(("emInterpretBtx: val=%x CF=%d\n", valpar1, !!(eflags & X86_EFL_CF)));
2601
2602 /* Update guest's eflags and finish. */
2603 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
2604 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
2605
2606 /* And write it back */
2607 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam1, &valpar1, 1);
2608 if (RT_SUCCESS(rc))
2609 {
2610 /* All done! */
2611 *pcbSize = 1;
2612 return VINF_SUCCESS;
2613 }
2614#ifdef IN_RC
2615 }
2616 }
2617#endif
2618 return VERR_EM_INTERPRETER;
2619}
2620
2621
2622#ifndef VBOX_COMPARE_IEM_AND_EM
2623/**
2624 * LOCK BTR/C/S Emulation.
2625 */
2626static int emInterpretLockBitTest(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault,
2627 uint32_t *pcbSize, PFNEMULATELOCKPARAM2 pfnEmulate)
2628{
2629 void *pvParam1;
2630
2631 DISQPVPARAMVAL param1, param2;
2632 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2633 if(RT_FAILURE(rc))
2634 return VERR_EM_INTERPRETER;
2635
2636 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
2637 if(RT_FAILURE(rc))
2638 return VERR_EM_INTERPRETER;
2639
2640 /* The destination is always a virtual address */
2641 if (param1.type != DISQPV_TYPE_ADDRESS)
2642 return VERR_EM_INTERPRETER;
2643
2644 /* Register and immediate data == DISQPV_TYPE_IMMEDIATE */
2645 AssertReturn(param2.type == DISQPV_TYPE_IMMEDIATE, VERR_EM_INTERPRETER);
2646 uint64_t ValPar2 = param2.val.val64;
2647
2648 /* Adjust the parameters so what we're dealing with is a bit within the byte pointed to. */
2649 RTGCPTR GCPtrPar1 = param1.val.val64;
2650 GCPtrPar1 = (GCPtrPar1 + ValPar2 / 8);
2651 ValPar2 &= 7;
2652
2653 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, GCPtrPar1);
2654#ifdef IN_RC
2655 Assert(TRPMHasTrap(pVCpu));
2656 EM_ASSERT_FAULT_RETURN((RTGCPTR)((RTGCUINTPTR)GCPtrPar1 & ~(RTGCUINTPTR)3) == pvFault, VERR_EM_INTERPRETER);
2657#endif
2658
2659 PGMPAGEMAPLOCK Lock;
2660 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrPar1, &pvParam1, &Lock);
2661 AssertRCReturn(rc, VERR_EM_INTERPRETER);
2662
2663 Log2(("emInterpretLockBitTest %s: pvFault=%RGv GCPtrPar1=%RGv imm=%RX64\n", emGetMnemonic(pDis), pvFault, GCPtrPar1, ValPar2));
2664
2665 /* Try emulate it with a one-shot #PF handler in place. (RC) */
2666 RTGCUINTREG32 eflags = 0;
2667 rc = pfnEmulate(pvParam1, ValPar2, &eflags);
2668 PGMPhysReleasePageMappingLock(pVM, &Lock);
2669 if (RT_FAILURE(rc))
2670 {
2671 Log(("emInterpretLockBitTest %s: %RGv imm%d=%RX64 -> emulation failed due to page fault!\n",
2672 emGetMnemonic(pDis), GCPtrPar1, pDis->Param2.cb*8, ValPar2));
2673 return VERR_EM_INTERPRETER;
2674 }
2675
2676 Log2(("emInterpretLockBitTest %s: GCPtrPar1=%RGv imm=%RX64 CF=%d\n", emGetMnemonic(pDis), GCPtrPar1, ValPar2, !!(eflags & X86_EFL_CF)));
2677
2678 /* Update guest's eflags and finish. */
2679 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
2680 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
2681
2682 *pcbSize = 1;
2683 return VINF_SUCCESS;
2684}
2685#endif /* !VBOX_COMPARE_IEM_AND_EM */
2686
2687
2688/**
2689 * MOV emulation.
2690 */
2691static int emInterpretMov(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2692{
2693 NOREF(pvFault);
2694 DISQPVPARAMVAL param1, param2;
2695 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_DST);
2696 if(RT_FAILURE(rc))
2697 return VERR_EM_INTERPRETER;
2698
2699 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
2700 if(RT_FAILURE(rc))
2701 return VERR_EM_INTERPRETER;
2702
2703 if (param1.type == DISQPV_TYPE_ADDRESS)
2704 {
2705 RTGCPTR pDest;
2706 uint64_t val64;
2707
2708 switch(param1.type)
2709 {
2710 case DISQPV_TYPE_IMMEDIATE:
2711 if(!(param1.flags & (DISQPV_FLAG_32|DISQPV_FLAG_64)))
2712 return VERR_EM_INTERPRETER;
2713 /* fallthru */
2714
2715 case DISQPV_TYPE_ADDRESS:
2716 pDest = (RTGCPTR)param1.val.val64;
2717 pDest = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pDest);
2718 break;
2719
2720 default:
2721 AssertFailed();
2722 return VERR_EM_INTERPRETER;
2723 }
2724
2725 switch(param2.type)
2726 {
2727 case DISQPV_TYPE_IMMEDIATE: /* register type is translated to this one too */
2728 val64 = param2.val.val64;
2729 break;
2730
2731 default:
2732 Log(("emInterpretMov: unexpected type=%d rip=%RGv\n", param2.type, (RTGCPTR)pRegFrame->rip));
2733 return VERR_EM_INTERPRETER;
2734 }
2735#ifdef LOG_ENABLED
2736 if (pDis->uCpuMode == DISCPUMODE_64BIT)
2737 LogFlow(("EMInterpretInstruction at %RGv: OP_MOV %RGv <- %RX64 (%d) &val64=%RHv\n", (RTGCPTR)pRegFrame->rip, pDest, val64, param2.size, &val64));
2738 else
2739 LogFlow(("EMInterpretInstruction at %08RX64: OP_MOV %RGv <- %08X (%d) &val64=%RHv\n", pRegFrame->rip, pDest, (uint32_t)val64, param2.size, &val64));
2740#endif
2741
2742 Assert(param2.size <= 8 && param2.size > 0);
2743 EM_ASSERT_FAULT_RETURN(pDest == pvFault, VERR_EM_INTERPRETER);
2744 rc = emRamWrite(pVM, pVCpu, pRegFrame, pDest, &val64, param2.size);
2745 if (RT_FAILURE(rc))
2746 return VERR_EM_INTERPRETER;
2747
2748 *pcbSize = param2.size;
2749 }
2750#if defined(IN_RC) && defined(VBOX_WITH_RAW_RING1)
2751 /* mov xx, cs instruction is dangerous in raw mode and replaced by an 'int3' by csam/patm. */
2752 else if ( param1.type == DISQPV_TYPE_REGISTER
2753 && param2.type == DISQPV_TYPE_REGISTER)
2754 {
2755 AssertReturn((pDis->Param1.fUse & (DISUSE_REG_GEN8|DISUSE_REG_GEN16|DISUSE_REG_GEN32)), VERR_EM_INTERPRETER);
2756 AssertReturn(pDis->Param2.fUse == DISUSE_REG_SEG, VERR_EM_INTERPRETER);
2757 AssertReturn(pDis->Param2.Base.idxSegReg == DISSELREG_CS, VERR_EM_INTERPRETER);
2758
2759 uint32_t u32Cpl = CPUMRCGetGuestCPL(pVCpu, pRegFrame);
2760 uint32_t uValCS = (pRegFrame->cs.Sel & ~X86_SEL_RPL) | u32Cpl;
2761
2762 Log(("EMInterpretInstruction: OP_MOV cs=%x->%x\n", pRegFrame->cs.Sel, uValCS));
2763 switch (param1.size)
2764 {
2765 case 1: rc = DISWriteReg8(pRegFrame, pDis->Param1.Base.idxGenReg, (uint8_t) uValCS); break;
2766 case 2: rc = DISWriteReg16(pRegFrame, pDis->Param1.Base.idxGenReg, (uint16_t)uValCS); break;
2767 case 4: rc = DISWriteReg32(pRegFrame, pDis->Param1.Base.idxGenReg, (uint32_t)uValCS); break;
2768 default:
2769 AssertFailed();
2770 return VERR_EM_INTERPRETER;
2771 }
2772 AssertRCReturn(rc, rc);
2773 }
2774#endif
2775 else
2776 { /* read fault */
2777 RTGCPTR pSrc;
2778 uint64_t val64;
2779
2780 /* Source */
2781 switch(param2.type)
2782 {
2783 case DISQPV_TYPE_IMMEDIATE:
2784 if(!(param2.flags & (DISQPV_FLAG_32|DISQPV_FLAG_64)))
2785 return VERR_EM_INTERPRETER;
2786 /* fallthru */
2787
2788 case DISQPV_TYPE_ADDRESS:
2789 pSrc = (RTGCPTR)param2.val.val64;
2790 pSrc = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param2, pSrc);
2791 break;
2792
2793 default:
2794 return VERR_EM_INTERPRETER;
2795 }
2796
2797 Assert(param1.size <= 8 && param1.size > 0);
2798 EM_ASSERT_FAULT_RETURN(pSrc == pvFault, VERR_EM_INTERPRETER);
2799 rc = emRamRead(pVM, pVCpu, pRegFrame, &val64, pSrc, param1.size);
2800 if (RT_FAILURE(rc))
2801 return VERR_EM_INTERPRETER;
2802
2803 /* Destination */
2804 switch(param1.type)
2805 {
2806 case DISQPV_TYPE_REGISTER:
2807 switch(param1.size)
2808 {
2809 case 1: rc = DISWriteReg8(pRegFrame, pDis->Param1.Base.idxGenReg, (uint8_t) val64); break;
2810 case 2: rc = DISWriteReg16(pRegFrame, pDis->Param1.Base.idxGenReg, (uint16_t)val64); break;
2811 case 4: rc = DISWriteReg32(pRegFrame, pDis->Param1.Base.idxGenReg, (uint32_t)val64); break;
2812 case 8: rc = DISWriteReg64(pRegFrame, pDis->Param1.Base.idxGenReg, val64); break;
2813 default:
2814 return VERR_EM_INTERPRETER;
2815 }
2816 if (RT_FAILURE(rc))
2817 return rc;
2818 break;
2819
2820 default:
2821 return VERR_EM_INTERPRETER;
2822 }
2823#ifdef LOG_ENABLED
2824 if (pDis->uCpuMode == DISCPUMODE_64BIT)
2825 LogFlow(("EMInterpretInstruction: OP_MOV %RGv -> %RX64 (%d)\n", pSrc, val64, param1.size));
2826 else
2827 LogFlow(("EMInterpretInstruction: OP_MOV %RGv -> %08X (%d)\n", pSrc, (uint32_t)val64, param1.size));
2828#endif
2829 }
2830 return VINF_SUCCESS;
2831}
2832
2833
2834#ifndef IN_RC
2835/**
2836 * [REP] STOSWD emulation
2837 */
2838static int emInterpretStosWD(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2839{
2840 int rc;
2841 RTGCPTR GCDest, GCOffset;
2842 uint32_t cbSize;
2843 uint64_t cTransfers;
2844 int offIncrement;
2845 NOREF(pvFault);
2846
2847 /* Don't support any but these three prefix bytes. */
2848 if ((pDis->fPrefix & ~(DISPREFIX_ADDRSIZE|DISPREFIX_OPSIZE|DISPREFIX_REP|DISPREFIX_REX)))
2849 return VERR_EM_INTERPRETER;
2850
2851 switch (pDis->uAddrMode)
2852 {
2853 case DISCPUMODE_16BIT:
2854 GCOffset = pRegFrame->di;
2855 cTransfers = pRegFrame->cx;
2856 break;
2857 case DISCPUMODE_32BIT:
2858 GCOffset = pRegFrame->edi;
2859 cTransfers = pRegFrame->ecx;
2860 break;
2861 case DISCPUMODE_64BIT:
2862 GCOffset = pRegFrame->rdi;
2863 cTransfers = pRegFrame->rcx;
2864 break;
2865 default:
2866 AssertFailed();
2867 return VERR_EM_INTERPRETER;
2868 }
2869
2870 GCDest = SELMToFlat(pVM, DISSELREG_ES, pRegFrame, GCOffset);
2871 switch (pDis->uOpMode)
2872 {
2873 case DISCPUMODE_16BIT:
2874 cbSize = 2;
2875 break;
2876 case DISCPUMODE_32BIT:
2877 cbSize = 4;
2878 break;
2879 case DISCPUMODE_64BIT:
2880 cbSize = 8;
2881 break;
2882 default:
2883 AssertFailed();
2884 return VERR_EM_INTERPRETER;
2885 }
2886
2887 offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
2888
2889 if (!(pDis->fPrefix & DISPREFIX_REP))
2890 {
2891 LogFlow(("emInterpretStosWD dest=%04X:%RGv (%RGv) cbSize=%d\n", pRegFrame->es.Sel, GCOffset, GCDest, cbSize));
2892
2893 rc = emRamWrite(pVM, pVCpu, pRegFrame, GCDest, &pRegFrame->rax, cbSize);
2894 if (RT_FAILURE(rc))
2895 return VERR_EM_INTERPRETER;
2896 Assert(rc == VINF_SUCCESS);
2897
2898 /* Update (e/r)di. */
2899 switch (pDis->uAddrMode)
2900 {
2901 case DISCPUMODE_16BIT:
2902 pRegFrame->di += offIncrement;
2903 break;
2904 case DISCPUMODE_32BIT:
2905 pRegFrame->edi += offIncrement;
2906 break;
2907 case DISCPUMODE_64BIT:
2908 pRegFrame->rdi += offIncrement;
2909 break;
2910 default:
2911 AssertFailed();
2912 return VERR_EM_INTERPRETER;
2913 }
2914
2915 }
2916 else
2917 {
2918 if (!cTransfers)
2919 return VINF_SUCCESS;
2920
2921 /*
2922 * Do *not* try emulate cross page stuff here because we don't know what might
2923 * be waiting for us on the subsequent pages. The caller has only asked us to
2924 * ignore access handlers fro the current page.
2925 * This also fends off big stores which would quickly kill PGMR0DynMap.
2926 */
2927 if ( cbSize > PAGE_SIZE
2928 || cTransfers > PAGE_SIZE
2929 || (GCDest >> PAGE_SHIFT) != ((GCDest + offIncrement * cTransfers) >> PAGE_SHIFT))
2930 {
2931 Log(("STOSWD is crosses pages, chicken out to the recompiler; GCDest=%RGv cbSize=%#x offIncrement=%d cTransfers=%#x\n",
2932 GCDest, cbSize, offIncrement, cTransfers));
2933 return VERR_EM_INTERPRETER;
2934 }
2935
2936 LogFlow(("emInterpretStosWD dest=%04X:%RGv (%RGv) cbSize=%d cTransfers=%x DF=%d\n", pRegFrame->es.Sel, GCOffset, GCDest, cbSize, cTransfers, pRegFrame->eflags.Bits.u1DF));
2937 /* Access verification first; we currently can't recover properly from traps inside this instruction */
2938 rc = PGMVerifyAccess(pVCpu, GCDest - ((offIncrement > 0) ? 0 : ((cTransfers-1) * cbSize)),
2939 cTransfers * cbSize,
2940 X86_PTE_RW | (CPUMGetGuestCPL(pVCpu) == 3 ? X86_PTE_US : 0));
2941 if (rc != VINF_SUCCESS)
2942 {
2943 Log(("STOSWD will generate a trap -> recompiler, rc=%d\n", rc));
2944 return VERR_EM_INTERPRETER;
2945 }
2946
2947 /* REP case */
2948 while (cTransfers)
2949 {
2950 rc = emRamWrite(pVM, pVCpu, pRegFrame, GCDest, &pRegFrame->rax, cbSize);
2951 if (RT_FAILURE(rc))
2952 {
2953 rc = VERR_EM_INTERPRETER;
2954 break;
2955 }
2956
2957 Assert(rc == VINF_SUCCESS);
2958 GCOffset += offIncrement;
2959 GCDest += offIncrement;
2960 cTransfers--;
2961 }
2962
2963 /* Update the registers. */
2964 switch (pDis->uAddrMode)
2965 {
2966 case DISCPUMODE_16BIT:
2967 pRegFrame->di = GCOffset;
2968 pRegFrame->cx = cTransfers;
2969 break;
2970 case DISCPUMODE_32BIT:
2971 pRegFrame->edi = GCOffset;
2972 pRegFrame->ecx = cTransfers;
2973 break;
2974 case DISCPUMODE_64BIT:
2975 pRegFrame->rdi = GCOffset;
2976 pRegFrame->rcx = cTransfers;
2977 break;
2978 default:
2979 AssertFailed();
2980 return VERR_EM_INTERPRETER;
2981 }
2982 }
2983
2984 *pcbSize = cbSize;
2985 return rc;
2986}
2987#endif /* !IN_RC */
2988
2989
2990/**
2991 * [LOCK] CMPXCHG emulation.
2992 */
2993static int emInterpretCmpXchg(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2994{
2995 DISQPVPARAMVAL param1, param2;
2996 NOREF(pvFault);
2997
2998#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0)
2999 Assert(pDis->Param1.cb <= 4);
3000#endif
3001
3002 /* Source to make DISQueryParamVal read the register value - ugly hack */
3003 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3004 if(RT_FAILURE(rc))
3005 return VERR_EM_INTERPRETER;
3006
3007 rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param2, &param2, DISQPVWHICH_SRC);
3008 if(RT_FAILURE(rc))
3009 return VERR_EM_INTERPRETER;
3010
3011 uint64_t valpar;
3012 switch(param2.type)
3013 {
3014 case DISQPV_TYPE_IMMEDIATE: /* register actually */
3015 valpar = param2.val.val64;
3016 break;
3017
3018 default:
3019 return VERR_EM_INTERPRETER;
3020 }
3021
3022 PGMPAGEMAPLOCK Lock;
3023 RTGCPTR GCPtrPar1;
3024 void *pvParam1;
3025 uint64_t eflags;
3026
3027 AssertReturn(pDis->Param1.cb == pDis->Param2.cb, VERR_EM_INTERPRETER);
3028 switch(param1.type)
3029 {
3030 case DISQPV_TYPE_ADDRESS:
3031 GCPtrPar1 = param1.val.val64;
3032 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, GCPtrPar1);
3033
3034 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrPar1, &pvParam1, &Lock);
3035 AssertRCReturn(rc, VERR_EM_INTERPRETER);
3036 break;
3037
3038 default:
3039 return VERR_EM_INTERPRETER;
3040 }
3041
3042 LogFlow(("%s %RGv rax=%RX64 %RX64\n", emGetMnemonic(pDis), GCPtrPar1, pRegFrame->rax, valpar));
3043
3044#ifndef VBOX_COMPARE_IEM_AND_EM
3045 if (pDis->fPrefix & DISPREFIX_LOCK)
3046 eflags = EMEmulateLockCmpXchg(pvParam1, &pRegFrame->rax, valpar, pDis->Param2.cb);
3047 else
3048 eflags = EMEmulateCmpXchg(pvParam1, &pRegFrame->rax, valpar, pDis->Param2.cb);
3049#else /* VBOX_COMPARE_IEM_AND_EM */
3050 uint64_t u64;
3051 switch (pDis->Param2.cb)
3052 {
3053 case 1: u64 = *(uint8_t *)pvParam1; break;
3054 case 2: u64 = *(uint16_t *)pvParam1; break;
3055 case 4: u64 = *(uint32_t *)pvParam1; break;
3056 default:
3057 case 8: u64 = *(uint64_t *)pvParam1; break;
3058 }
3059 eflags = EMEmulateCmpXchg(&u64, &pRegFrame->rax, valpar, pDis->Param2.cb);
3060 int rc2 = emRamWrite(pVM, pVCpu, pRegFrame, GCPtrPar1, &u64, pDis->Param2.cb); AssertRCSuccess(rc2);
3061#endif /* VBOX_COMPARE_IEM_AND_EM */
3062
3063 LogFlow(("%s %RGv rax=%RX64 %RX64 ZF=%d\n", emGetMnemonic(pDis), GCPtrPar1, pRegFrame->rax, valpar, !!(eflags & X86_EFL_ZF)));
3064
3065 /* Update guest's eflags and finish. */
3066 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
3067 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
3068
3069 *pcbSize = param2.size;
3070 PGMPhysReleasePageMappingLock(pVM, &Lock);
3071 return VINF_SUCCESS;
3072}
3073
3074
3075/**
3076 * [LOCK] CMPXCHG8B emulation.
3077 */
3078static int emInterpretCmpXchg8b(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3079{
3080 Assert(pDis->uCpuMode != DISCPUMODE_64BIT); /** @todo check */
3081 DISQPVPARAMVAL param1;
3082 NOREF(pvFault);
3083
3084 /* Source to make DISQueryParamVal read the register value - ugly hack */
3085 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3086 if(RT_FAILURE(rc))
3087 return VERR_EM_INTERPRETER;
3088
3089 RTGCPTR GCPtrPar1;
3090 void *pvParam1;
3091 uint64_t eflags;
3092 PGMPAGEMAPLOCK Lock;
3093
3094 AssertReturn(pDis->Param1.cb == 8, VERR_EM_INTERPRETER);
3095 switch(param1.type)
3096 {
3097 case DISQPV_TYPE_ADDRESS:
3098 GCPtrPar1 = param1.val.val64;
3099 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, GCPtrPar1);
3100
3101 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrPar1, &pvParam1, &Lock);
3102 AssertRCReturn(rc, VERR_EM_INTERPRETER);
3103 break;
3104
3105 default:
3106 return VERR_EM_INTERPRETER;
3107 }
3108
3109 LogFlow(("%s %RGv=%08x eax=%08x\n", emGetMnemonic(pDis), pvParam1, pRegFrame->eax));
3110
3111#ifndef VBOX_COMPARE_IEM_AND_EM
3112 if (pDis->fPrefix & DISPREFIX_LOCK)
3113 eflags = EMEmulateLockCmpXchg8b(pvParam1, &pRegFrame->eax, &pRegFrame->edx, pRegFrame->ebx, pRegFrame->ecx);
3114 else
3115 eflags = EMEmulateCmpXchg8b(pvParam1, &pRegFrame->eax, &pRegFrame->edx, pRegFrame->ebx, pRegFrame->ecx);
3116#else /* VBOX_COMPARE_IEM_AND_EM */
3117 uint64_t u64 = *(uint64_t *)pvParam1;
3118 eflags = EMEmulateCmpXchg8b(&u64, &pRegFrame->eax, &pRegFrame->edx, pRegFrame->ebx, pRegFrame->ecx);
3119 int rc2 = emRamWrite(pVM, pVCpu, pRegFrame, GCPtrPar1, &u64, sizeof(u64)); AssertRCSuccess(rc2);
3120#endif /* VBOX_COMPARE_IEM_AND_EM */
3121
3122 LogFlow(("%s %RGv=%08x eax=%08x ZF=%d\n", emGetMnemonic(pDis), pvParam1, pRegFrame->eax, !!(eflags & X86_EFL_ZF)));
3123
3124 /* Update guest's eflags and finish; note that *only* ZF is affected. */
3125 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_ZF))
3126 | (eflags & (X86_EFL_ZF));
3127
3128 *pcbSize = 8;
3129 PGMPhysReleasePageMappingLock(pVM, &Lock);
3130 return VINF_SUCCESS;
3131}
3132
3133
3134#ifdef IN_RC /** @todo test+enable for HM as well. */
3135/**
3136 * [LOCK] XADD emulation.
3137 */
3138static int emInterpretXAdd(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3139{
3140 Assert(pDis->uCpuMode != DISCPUMODE_64BIT); /** @todo check */
3141 DISQPVPARAMVAL param1;
3142 void *pvParamReg2;
3143 size_t cbParamReg2;
3144 NOREF(pvFault);
3145
3146 /* Source to make DISQueryParamVal read the register value - ugly hack */
3147 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3148 if(RT_FAILURE(rc))
3149 return VERR_EM_INTERPRETER;
3150
3151 rc = DISQueryParamRegPtr(pRegFrame, pDis, &pDis->Param2, &pvParamReg2, &cbParamReg2);
3152 Assert(cbParamReg2 <= 4);
3153 if(RT_FAILURE(rc))
3154 return VERR_EM_INTERPRETER;
3155
3156#ifdef IN_RC
3157 if (TRPMHasTrap(pVCpu))
3158 {
3159 if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW)
3160 {
3161#endif
3162 RTGCPTR GCPtrPar1;
3163 void *pvParam1;
3164 uint32_t eflags;
3165 PGMPAGEMAPLOCK Lock;
3166
3167 AssertReturn(pDis->Param1.cb == pDis->Param2.cb, VERR_EM_INTERPRETER);
3168 switch(param1.type)
3169 {
3170 case DISQPV_TYPE_ADDRESS:
3171 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, (RTRCUINTPTR)param1.val.val64);
3172#ifdef IN_RC
3173 EM_ASSERT_FAULT_RETURN(GCPtrPar1 == pvFault, VERR_EM_INTERPRETER);
3174#endif
3175
3176 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrPar1, &pvParam1, &Lock);
3177 AssertRCReturn(rc, VERR_EM_INTERPRETER);
3178 break;
3179
3180 default:
3181 return VERR_EM_INTERPRETER;
3182 }
3183
3184 LogFlow(("XAdd %RGv=%p reg=%08llx\n", GCPtrPar1, pvParam1, *(uint64_t *)pvParamReg2));
3185
3186#ifndef VBOX_COMPARE_IEM_AND_EM
3187 if (pDis->fPrefix & DISPREFIX_LOCK)
3188 eflags = EMEmulateLockXAdd(pvParam1, pvParamReg2, cbParamReg2);
3189 else
3190 eflags = EMEmulateXAdd(pvParam1, pvParamReg2, cbParamReg2);
3191#else /* VBOX_COMPARE_IEM_AND_EM */
3192 uint64_t u64;
3193 switch (cbParamReg2)
3194 {
3195 case 1: u64 = *(uint8_t *)pvParam1; break;
3196 case 2: u64 = *(uint16_t *)pvParam1; break;
3197 case 4: u64 = *(uint32_t *)pvParam1; break;
3198 default:
3199 case 8: u64 = *(uint64_t *)pvParam1; break;
3200 }
3201 eflags = EMEmulateXAdd(&u64, pvParamReg2, cbParamReg2);
3202 int rc2 = emRamWrite(pVM, pVCpu, pRegFrame, GCPtrPar1, &u64, pDis->Param2.cb); AssertRCSuccess(rc2);
3203#endif /* VBOX_COMPARE_IEM_AND_EM */
3204
3205 LogFlow(("XAdd %RGv=%p reg=%08llx ZF=%d\n", GCPtrPar1, pvParam1, *(uint64_t *)pvParamReg2, !!(eflags & X86_EFL_ZF) ));
3206
3207 /* Update guest's eflags and finish. */
3208 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
3209 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
3210
3211 *pcbSize = cbParamReg2;
3212 PGMPhysReleasePageMappingLock(pVM, &Lock);
3213 return VINF_SUCCESS;
3214#ifdef IN_RC
3215 }
3216 }
3217
3218 return VERR_EM_INTERPRETER;
3219#endif
3220}
3221#endif /* IN_RC */
3222
3223
3224/**
3225 * WBINVD Emulation.
3226 */
3227static int emInterpretWbInvd(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3228{
3229 /* Nothing to do. */
3230 NOREF(pVM); NOREF(pVCpu); NOREF(pDis); NOREF(pRegFrame); NOREF(pvFault); NOREF(pcbSize);
3231 return VINF_SUCCESS;
3232}
3233
3234
3235/**
3236 * INVLPG Emulation.
3237 */
3238static VBOXSTRICTRC emInterpretInvlPg(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3239{
3240 DISQPVPARAMVAL param1;
3241 RTGCPTR addr;
3242 NOREF(pvFault); NOREF(pVM); NOREF(pcbSize);
3243
3244 VBOXSTRICTRC rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3245 if(RT_FAILURE(rc))
3246 return VERR_EM_INTERPRETER;
3247
3248 switch(param1.type)
3249 {
3250 case DISQPV_TYPE_IMMEDIATE:
3251 case DISQPV_TYPE_ADDRESS:
3252 if(!(param1.flags & (DISQPV_FLAG_32|DISQPV_FLAG_64)))
3253 return VERR_EM_INTERPRETER;
3254 addr = (RTGCPTR)param1.val.val64;
3255 break;
3256
3257 default:
3258 return VERR_EM_INTERPRETER;
3259 }
3260
3261 /** @todo is addr always a flat linear address or ds based
3262 * (in absence of segment override prefixes)????
3263 */
3264#ifdef IN_RC
3265 LogFlow(("RC: EMULATE: invlpg %RGv\n", addr));
3266#endif
3267 rc = PGMInvalidatePage(pVCpu, addr);
3268 if ( rc == VINF_SUCCESS
3269 || rc == VINF_PGM_SYNC_CR3 /* we can rely on the FF */)
3270 return VINF_SUCCESS;
3271 AssertMsgReturn(rc == VINF_EM_RAW_EMULATE_INSTR,
3272 ("%Rrc addr=%RGv\n", VBOXSTRICTRC_VAL(rc), addr),
3273 VERR_EM_INTERPRETER);
3274 return rc;
3275}
3276
3277/** @todo change all these EMInterpretXXX methods to VBOXSTRICTRC. */
3278
3279/**
3280 * CPUID Emulation.
3281 */
3282static int emInterpretCpuId(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3283{
3284 NOREF(pVM); NOREF(pVCpu); NOREF(pDis); NOREF(pRegFrame); NOREF(pvFault); NOREF(pcbSize);
3285 int rc = EMInterpretCpuId(pVM, pVCpu, pRegFrame);
3286 return rc;
3287}
3288
3289
3290/**
3291 * CLTS Emulation.
3292 */
3293static int emInterpretClts(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3294{
3295 NOREF(pDis); NOREF(pRegFrame); NOREF(pvFault); NOREF(pcbSize);
3296 return EMInterpretCLTS(pVM, pVCpu);
3297}
3298
3299
3300/**
3301 * LMSW Emulation.
3302 */
3303static int emInterpretLmsw(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3304{
3305 DISQPVPARAMVAL param1;
3306 uint32_t val;
3307 NOREF(pvFault); NOREF(pcbSize);
3308
3309 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3310 if(RT_FAILURE(rc))
3311 return VERR_EM_INTERPRETER;
3312
3313 switch(param1.type)
3314 {
3315 case DISQPV_TYPE_IMMEDIATE:
3316 case DISQPV_TYPE_ADDRESS:
3317 if(!(param1.flags & DISQPV_FLAG_16))
3318 return VERR_EM_INTERPRETER;
3319 val = param1.val.val32;
3320 break;
3321
3322 default:
3323 return VERR_EM_INTERPRETER;
3324 }
3325
3326 LogFlow(("emInterpretLmsw %x\n", val));
3327 return EMInterpretLMSW(pVM, pVCpu, pRegFrame, val);
3328}
3329
3330#ifdef EM_EMULATE_SMSW
3331/**
3332 * SMSW Emulation.
3333 */
3334static int emInterpretSmsw(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3335{
3336 DISQPVPARAMVAL param1;
3337 uint64_t cr0 = CPUMGetGuestCR0(pVCpu);
3338
3339 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3340 if(RT_FAILURE(rc))
3341 return VERR_EM_INTERPRETER;
3342
3343 switch(param1.type)
3344 {
3345 case DISQPV_TYPE_IMMEDIATE:
3346 if(param1.size != sizeof(uint16_t))
3347 return VERR_EM_INTERPRETER;
3348 LogFlow(("emInterpretSmsw %d <- cr0 (%x)\n", pDis->Param1.Base.idxGenReg, cr0));
3349 rc = DISWriteReg16(pRegFrame, pDis->Param1.Base.idxGenReg, cr0);
3350 break;
3351
3352 case DISQPV_TYPE_ADDRESS:
3353 {
3354 RTGCPTR pParam1;
3355
3356 /* Actually forced to 16 bits regardless of the operand size. */
3357 if(param1.size != sizeof(uint16_t))
3358 return VERR_EM_INTERPRETER;
3359
3360 pParam1 = (RTGCPTR)param1.val.val64;
3361 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pParam1);
3362 LogFlow(("emInterpretSmsw %RGv <- cr0 (%x)\n", pParam1, cr0));
3363
3364 rc = emRamWrite(pVM, pVCpu, pRegFrame, pParam1, &cr0, sizeof(uint16_t));
3365 if (RT_FAILURE(rc))
3366 {
3367 AssertMsgFailed(("emRamWrite %RGv size=%d failed with %Rrc\n", pParam1, param1.size, rc));
3368 return VERR_EM_INTERPRETER;
3369 }
3370 break;
3371 }
3372
3373 default:
3374 return VERR_EM_INTERPRETER;
3375 }
3376
3377 LogFlow(("emInterpretSmsw %x\n", cr0));
3378 return rc;
3379}
3380#endif
3381
3382/**
3383 * MOV CRx
3384 */
3385static int emInterpretMovCRx(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3386{
3387 NOREF(pvFault); NOREF(pcbSize);
3388 if ((pDis->Param1.fUse == DISUSE_REG_GEN32 || pDis->Param1.fUse == DISUSE_REG_GEN64) && pDis->Param2.fUse == DISUSE_REG_CR)
3389 return EMInterpretCRxRead(pVM, pVCpu, pRegFrame, pDis->Param1.Base.idxGenReg, pDis->Param2.Base.idxCtrlReg);
3390
3391 if (pDis->Param1.fUse == DISUSE_REG_CR && (pDis->Param2.fUse == DISUSE_REG_GEN32 || pDis->Param2.fUse == DISUSE_REG_GEN64))
3392 return EMInterpretCRxWrite(pVM, pVCpu, pRegFrame, pDis->Param1.Base.idxCtrlReg, pDis->Param2.Base.idxGenReg);
3393
3394 AssertMsgFailedReturn(("Unexpected control register move\n"), VERR_EM_INTERPRETER);
3395}
3396
3397
3398/**
3399 * MOV DRx
3400 */
3401static int emInterpretMovDRx(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3402{
3403 int rc = VERR_EM_INTERPRETER;
3404 NOREF(pvFault); NOREF(pcbSize);
3405
3406 if((pDis->Param1.fUse == DISUSE_REG_GEN32 || pDis->Param1.fUse == DISUSE_REG_GEN64) && pDis->Param2.fUse == DISUSE_REG_DBG)
3407 {
3408 rc = EMInterpretDRxRead(pVM, pVCpu, pRegFrame, pDis->Param1.Base.idxGenReg, pDis->Param2.Base.idxDbgReg);
3409 }
3410 else
3411 if(pDis->Param1.fUse == DISUSE_REG_DBG && (pDis->Param2.fUse == DISUSE_REG_GEN32 || pDis->Param2.fUse == DISUSE_REG_GEN64))
3412 {
3413 rc = EMInterpretDRxWrite(pVM, pVCpu, pRegFrame, pDis->Param1.Base.idxDbgReg, pDis->Param2.Base.idxGenReg);
3414 }
3415 else
3416 AssertMsgFailed(("Unexpected debug register move\n"));
3417
3418 return rc;
3419}
3420
3421
3422/**
3423 * LLDT Emulation.
3424 */
3425static int emInterpretLLdt(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3426{
3427 DISQPVPARAMVAL param1;
3428 RTSEL sel;
3429 NOREF(pVM); NOREF(pvFault); NOREF(pcbSize);
3430
3431 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3432 if(RT_FAILURE(rc))
3433 return VERR_EM_INTERPRETER;
3434
3435 switch(param1.type)
3436 {
3437 case DISQPV_TYPE_ADDRESS:
3438 return VERR_EM_INTERPRETER; //feeling lazy right now
3439
3440 case DISQPV_TYPE_IMMEDIATE:
3441 if(!(param1.flags & DISQPV_FLAG_16))
3442 return VERR_EM_INTERPRETER;
3443 sel = (RTSEL)param1.val.val16;
3444 break;
3445
3446 default:
3447 return VERR_EM_INTERPRETER;
3448 }
3449
3450#ifdef IN_RING0
3451 /* Only for the VT-x real-mode emulation case. */
3452 AssertReturn(CPUMIsGuestInRealMode(pVCpu), VERR_EM_INTERPRETER);
3453 CPUMSetGuestLDTR(pVCpu, sel);
3454 return VINF_SUCCESS;
3455#else
3456 if (sel == 0)
3457 {
3458 if (CPUMGetHyperLDTR(pVCpu) == 0)
3459 {
3460 // this simple case is most frequent in Windows 2000 (31k - boot & shutdown)
3461 return VINF_SUCCESS;
3462 }
3463 }
3464 //still feeling lazy
3465 return VERR_EM_INTERPRETER;
3466#endif
3467}
3468
3469#ifdef IN_RING0
3470/**
3471 * LIDT/LGDT Emulation.
3472 */
3473static int emInterpretLIGdt(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3474{
3475 DISQPVPARAMVAL param1;
3476 RTGCPTR pParam1;
3477 X86XDTR32 dtr32;
3478 NOREF(pvFault); NOREF(pcbSize);
3479
3480 Log(("Emulate %s at %RGv\n", emGetMnemonic(pDis), (RTGCPTR)pRegFrame->rip));
3481
3482 /* Only for the VT-x real-mode emulation case. */
3483 AssertReturn(CPUMIsGuestInRealMode(pVCpu), VERR_EM_INTERPRETER);
3484
3485 int rc = DISQueryParamVal(pRegFrame, pDis, &pDis->Param1, &param1, DISQPVWHICH_SRC);
3486 if(RT_FAILURE(rc))
3487 return VERR_EM_INTERPRETER;
3488
3489 switch(param1.type)
3490 {
3491 case DISQPV_TYPE_ADDRESS:
3492 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, param1.val.val16);
3493 break;
3494
3495 default:
3496 return VERR_EM_INTERPRETER;
3497 }
3498
3499 rc = emRamRead(pVM, pVCpu, pRegFrame, &dtr32, pParam1, sizeof(dtr32));
3500 AssertRCReturn(rc, VERR_EM_INTERPRETER);
3501
3502 if (!(pDis->fPrefix & DISPREFIX_OPSIZE))
3503 dtr32.uAddr &= 0xffffff; /* 16 bits operand size */
3504
3505 if (pDis->pCurInstr->uOpcode == OP_LIDT)
3506 CPUMSetGuestIDTR(pVCpu, dtr32.uAddr, dtr32.cb);
3507 else
3508 CPUMSetGuestGDTR(pVCpu, dtr32.uAddr, dtr32.cb);
3509
3510 return VINF_SUCCESS;
3511}
3512#endif
3513
3514
3515#ifdef IN_RC
3516/**
3517 * STI Emulation.
3518 *
3519 * @remark the instruction following sti is guaranteed to be executed before any interrupts are dispatched
3520 */
3521static int emInterpretSti(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3522{
3523 NOREF(pcbSize);
3524 PPATMGCSTATE pGCState = PATMGetGCState(pVM);
3525
3526 if(!pGCState)
3527 {
3528 Assert(pGCState);
3529 return VERR_EM_INTERPRETER;
3530 }
3531 pGCState->uVMFlags |= X86_EFL_IF;
3532
3533 Assert(pRegFrame->eflags.u32 & X86_EFL_IF);
3534 Assert(pvFault == SELMToFlat(pVM, DISSELREG_CS, pRegFrame, (RTGCPTR)pRegFrame->rip));
3535
3536 pVCpu->em.s.GCPtrInhibitInterrupts = pRegFrame->eip + pDis->cbInstr;
3537 VMCPU_FF_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
3538
3539 return VINF_SUCCESS;
3540}
3541#endif /* IN_RC */
3542
3543
3544/**
3545 * HLT Emulation.
3546 */
3547static VBOXSTRICTRC
3548emInterpretHlt(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3549{
3550 NOREF(pVM); NOREF(pVCpu); NOREF(pDis); NOREF(pRegFrame); NOREF(pvFault); NOREF(pcbSize);
3551 return VINF_EM_HALT;
3552}
3553
3554
3555/**
3556 * RDTSC Emulation.
3557 */
3558static int emInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3559{
3560 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
3561 return EMInterpretRdtsc(pVM, pVCpu, pRegFrame);
3562}
3563
3564/**
3565 * RDPMC Emulation
3566 */
3567static int emInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3568{
3569 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
3570 return EMInterpretRdpmc(pVM, pVCpu, pRegFrame);
3571}
3572
3573
3574static int emInterpretMonitor(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3575{
3576 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
3577 return EMInterpretMonitor(pVM, pVCpu, pRegFrame);
3578}
3579
3580
3581static VBOXSTRICTRC emInterpretMWait(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3582{
3583 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
3584 return EMInterpretMWait(pVM, pVCpu, pRegFrame);
3585}
3586
3587
3588/**
3589 * RDMSR Emulation.
3590 */
3591static int emInterpretRdmsr(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3592{
3593 /* Note: The Intel manual claims there's a REX version of RDMSR that's slightly
3594 different, so we play safe by completely disassembling the instruction. */
3595 Assert(!(pDis->fPrefix & DISPREFIX_REX));
3596 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
3597 return EMInterpretRdmsr(pVM, pVCpu, pRegFrame);
3598}
3599
3600
3601/**
3602 * WRMSR Emulation.
3603 */
3604static int emInterpretWrmsr(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
3605{
3606 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
3607 return EMInterpretWrmsr(pVM, pVCpu, pRegFrame);
3608}
3609
3610
3611/**
3612 * Internal worker.
3613 * @copydoc emInterpretInstructionCPUOuter
3614 */
3615DECLINLINE(VBOXSTRICTRC) emInterpretInstructionCPU(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame,
3616 RTGCPTR pvFault, EMCODETYPE enmCodeType, uint32_t *pcbSize)
3617{
3618 Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu));
3619 Assert(enmCodeType == EMCODETYPE_SUPERVISOR || enmCodeType == EMCODETYPE_ALL);
3620 Assert(pcbSize);
3621 *pcbSize = 0;
3622
3623 if (enmCodeType == EMCODETYPE_SUPERVISOR)
3624 {
3625 /*
3626 * Only supervisor guest code!!
3627 * And no complicated prefixes.
3628 */
3629 /* Get the current privilege level. */
3630 uint32_t cpl = CPUMGetGuestCPL(pVCpu);
3631#ifdef VBOX_WITH_RAW_RING1
3632 if ( !EMIsRawRing1Enabled(pVM)
3633 || cpl > 1
3634 || pRegFrame->eflags.Bits.u2IOPL > cpl
3635 )
3636#endif
3637 {
3638 if ( cpl != 0
3639 && pDis->pCurInstr->uOpcode != OP_RDTSC) /* rdtsc requires emulation in ring 3 as well */
3640 {
3641 Log(("WARNING: refusing instruction emulation for user-mode code!!\n"));
3642 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FailedUserMode));
3643 return VERR_EM_INTERPRETER;
3644 }
3645 }
3646 }
3647 else
3648 Log2(("emInterpretInstructionCPU allowed to interpret user-level code!!\n"));
3649
3650#ifdef IN_RC
3651 if ( (pDis->fPrefix & (DISPREFIX_REPNE | DISPREFIX_REP))
3652 || ( (pDis->fPrefix & DISPREFIX_LOCK)
3653 && pDis->pCurInstr->uOpcode != OP_CMPXCHG
3654 && pDis->pCurInstr->uOpcode != OP_CMPXCHG8B
3655 && pDis->pCurInstr->uOpcode != OP_XADD
3656 && pDis->pCurInstr->uOpcode != OP_OR
3657 && pDis->pCurInstr->uOpcode != OP_AND
3658 && pDis->pCurInstr->uOpcode != OP_XOR
3659 && pDis->pCurInstr->uOpcode != OP_BTR
3660 )
3661 )
3662#else
3663 if ( (pDis->fPrefix & DISPREFIX_REPNE)
3664 || ( (pDis->fPrefix & DISPREFIX_REP)
3665 && pDis->pCurInstr->uOpcode != OP_STOSWD
3666 )
3667 || ( (pDis->fPrefix & DISPREFIX_LOCK)
3668 && pDis->pCurInstr->uOpcode != OP_OR
3669 && pDis->pCurInstr->uOpcode != OP_AND
3670 && pDis->pCurInstr->uOpcode != OP_XOR
3671 && pDis->pCurInstr->uOpcode != OP_BTR
3672 && pDis->pCurInstr->uOpcode != OP_CMPXCHG
3673 && pDis->pCurInstr->uOpcode != OP_CMPXCHG8B
3674 )
3675 )
3676#endif
3677 {
3678 //Log(("EMInterpretInstruction: wrong prefix!!\n"));
3679 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FailedPrefix));
3680 Log4(("EM: Refuse %u on REP/REPNE/LOCK prefix grounds\n", pDis->pCurInstr->uOpcode));
3681 return VERR_EM_INTERPRETER;
3682 }
3683
3684#if HC_ARCH_BITS == 32
3685 /*
3686 * Unable to emulate most >4 bytes accesses in 32 bits mode.
3687 * Whitelisted instructions are safe.
3688 */
3689 if ( pDis->Param1.cb > 4
3690 && CPUMIsGuestIn64BitCode(pVCpu))
3691 {
3692 uint32_t uOpCode = pDis->pCurInstr->uOpcode;
3693 if ( uOpCode != OP_STOSWD
3694 && uOpCode != OP_MOV
3695 && uOpCode != OP_CMPXCHG8B
3696 && uOpCode != OP_XCHG
3697 && uOpCode != OP_BTS
3698 && uOpCode != OP_BTR
3699 && uOpCode != OP_BTC
3700# ifdef VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
3701 && uOpCode != OP_CMPXCHG /* solaris */
3702 && uOpCode != OP_AND /* windows */
3703 && uOpCode != OP_OR /* windows */
3704 && uOpCode != OP_XOR /* because we can */
3705 && uOpCode != OP_ADD /* windows (dripple) */
3706 && uOpCode != OP_ADC /* because we can */
3707 && uOpCode != OP_SUB /* because we can */
3708 /** @todo OP_BTS or is that a different kind of failure? */
3709# endif
3710 )
3711 {
3712# ifdef VBOX_WITH_STATISTICS
3713 switch (pDis->pCurInstr->uOpcode)
3714 {
3715# define INTERPRET_FAILED_CASE(opcode, Instr) \
3716 case opcode: STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Failed##Instr)); break;
3717 INTERPRET_FAILED_CASE(OP_XCHG,Xchg);
3718 INTERPRET_FAILED_CASE(OP_DEC,Dec);
3719 INTERPRET_FAILED_CASE(OP_INC,Inc);
3720 INTERPRET_FAILED_CASE(OP_POP,Pop);
3721 INTERPRET_FAILED_CASE(OP_OR, Or);
3722 INTERPRET_FAILED_CASE(OP_XOR,Xor);
3723 INTERPRET_FAILED_CASE(OP_AND,And);
3724 INTERPRET_FAILED_CASE(OP_MOV,Mov);
3725 INTERPRET_FAILED_CASE(OP_STOSWD,StosWD);
3726 INTERPRET_FAILED_CASE(OP_INVLPG,InvlPg);
3727 INTERPRET_FAILED_CASE(OP_CPUID,CpuId);
3728 INTERPRET_FAILED_CASE(OP_MOV_CR,MovCRx);
3729 INTERPRET_FAILED_CASE(OP_MOV_DR,MovDRx);
3730 INTERPRET_FAILED_CASE(OP_LLDT,LLdt);
3731 INTERPRET_FAILED_CASE(OP_LIDT,LIdt);
3732 INTERPRET_FAILED_CASE(OP_LGDT,LGdt);
3733 INTERPRET_FAILED_CASE(OP_LMSW,Lmsw);
3734 INTERPRET_FAILED_CASE(OP_CLTS,Clts);
3735 INTERPRET_FAILED_CASE(OP_MONITOR,Monitor);
3736 INTERPRET_FAILED_CASE(OP_MWAIT,MWait);
3737 INTERPRET_FAILED_CASE(OP_RDMSR,Rdmsr);
3738 INTERPRET_FAILED_CASE(OP_WRMSR,Wrmsr);
3739 INTERPRET_FAILED_CASE(OP_ADD,Add);
3740 INTERPRET_FAILED_CASE(OP_SUB,Sub);
3741 INTERPRET_FAILED_CASE(OP_ADC,Adc);
3742 INTERPRET_FAILED_CASE(OP_BTR,Btr);
3743 INTERPRET_FAILED_CASE(OP_BTS,Bts);
3744 INTERPRET_FAILED_CASE(OP_BTC,Btc);
3745 INTERPRET_FAILED_CASE(OP_RDTSC,Rdtsc);
3746 INTERPRET_FAILED_CASE(OP_CMPXCHG, CmpXchg);
3747 INTERPRET_FAILED_CASE(OP_STI, Sti);
3748 INTERPRET_FAILED_CASE(OP_XADD,XAdd);
3749 INTERPRET_FAILED_CASE(OP_CMPXCHG8B,CmpXchg8b);
3750 INTERPRET_FAILED_CASE(OP_HLT, Hlt);
3751 INTERPRET_FAILED_CASE(OP_IRET,Iret);
3752 INTERPRET_FAILED_CASE(OP_WBINVD,WbInvd);
3753 INTERPRET_FAILED_CASE(OP_MOVNTPS,MovNTPS);
3754# undef INTERPRET_FAILED_CASE
3755 default:
3756 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FailedMisc));
3757 break;
3758 }
3759# endif /* VBOX_WITH_STATISTICS */
3760 Log4(("EM: Refuse %u on grounds of accessing %u bytes\n", pDis->pCurInstr->uOpcode, pDis->Param1.cb));
3761 return VERR_EM_INTERPRETER;
3762 }
3763 }
3764#endif
3765
3766 VBOXSTRICTRC rc;
3767#if (defined(VBOX_STRICT) || defined(LOG_ENABLED))
3768 LogFlow(("emInterpretInstructionCPU %s\n", emGetMnemonic(pDis)));
3769#endif
3770 switch (pDis->pCurInstr->uOpcode)
3771 {
3772 /*
3773 * Macros for generating the right case statements.
3774 */
3775# ifndef VBOX_COMPARE_IEM_AND_EM
3776# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
3777 case opcode:\
3778 if (pDis->fPrefix & DISPREFIX_LOCK) \
3779 rc = emInterpretLock##InstrFn(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize, pfnEmulateLock); \
3780 else \
3781 rc = emInterpret##InstrFn(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize, pfnEmulate); \
3782 if (RT_SUCCESS(rc)) \
3783 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Instr)); \
3784 else \
3785 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Failed##Instr)); \
3786 return rc
3787# else /* VBOX_COMPARE_IEM_AND_EM */
3788# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
3789 case opcode:\
3790 rc = emInterpret##InstrFn(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize, pfnEmulate); \
3791 if (RT_SUCCESS(rc)) \
3792 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Instr)); \
3793 else \
3794 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Failed##Instr)); \
3795 return rc
3796# endif /* VBOX_COMPARE_IEM_AND_EM */
3797
3798#define INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate) \
3799 case opcode:\
3800 rc = emInterpret##InstrFn(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize, pfnEmulate); \
3801 if (RT_SUCCESS(rc)) \
3802 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Instr)); \
3803 else \
3804 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Failed##Instr)); \
3805 return rc
3806
3807#define INTERPRET_CASE_EX_PARAM2(opcode, Instr, InstrFn, pfnEmulate) \
3808 INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate)
3809#define INTERPRET_CASE_EX_LOCK_PARAM2(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
3810 INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock)
3811
3812#define INTERPRET_CASE(opcode, Instr) \
3813 case opcode:\
3814 rc = emInterpret##Instr(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize); \
3815 if (RT_SUCCESS(rc)) \
3816 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Instr)); \
3817 else \
3818 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Failed##Instr)); \
3819 return rc
3820
3821#define INTERPRET_CASE_EX_DUAL_PARAM2(opcode, Instr, InstrFn) \
3822 case opcode:\
3823 rc = emInterpret##InstrFn(pVM, pVCpu, pDis, pRegFrame, pvFault, pcbSize); \
3824 if (RT_SUCCESS(rc)) \
3825 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Instr)); \
3826 else \
3827 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Failed##Instr)); \
3828 return rc
3829
3830#define INTERPRET_STAT_CASE(opcode, Instr) \
3831 case opcode: STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Failed##Instr)); return VERR_EM_INTERPRETER;
3832
3833 /*
3834 * The actual case statements.
3835 */
3836 INTERPRET_CASE(OP_XCHG,Xchg);
3837 INTERPRET_CASE_EX_PARAM2(OP_DEC,Dec, IncDec, EMEmulateDec);
3838 INTERPRET_CASE_EX_PARAM2(OP_INC,Inc, IncDec, EMEmulateInc);
3839 INTERPRET_CASE(OP_POP,Pop);
3840 INTERPRET_CASE_EX_LOCK_PARAM3(OP_OR, Or, OrXorAnd, EMEmulateOr, EMEmulateLockOr);
3841 INTERPRET_CASE_EX_LOCK_PARAM3(OP_XOR,Xor, OrXorAnd, EMEmulateXor, EMEmulateLockXor);
3842 INTERPRET_CASE_EX_LOCK_PARAM3(OP_AND,And, OrXorAnd, EMEmulateAnd, EMEmulateLockAnd);
3843 INTERPRET_CASE(OP_MOV,Mov);
3844#ifndef IN_RC
3845 INTERPRET_CASE(OP_STOSWD,StosWD);
3846#endif
3847 INTERPRET_CASE(OP_INVLPG,InvlPg);
3848 INTERPRET_CASE(OP_CPUID,CpuId);
3849 INTERPRET_CASE(OP_MOV_CR,MovCRx);
3850 INTERPRET_CASE(OP_MOV_DR,MovDRx);
3851#ifdef IN_RING0
3852 INTERPRET_CASE_EX_DUAL_PARAM2(OP_LIDT, LIdt, LIGdt);
3853 INTERPRET_CASE_EX_DUAL_PARAM2(OP_LGDT, LGdt, LIGdt);
3854#endif
3855 INTERPRET_CASE(OP_LLDT,LLdt);
3856 INTERPRET_CASE(OP_LMSW,Lmsw);
3857#ifdef EM_EMULATE_SMSW
3858 INTERPRET_CASE(OP_SMSW,Smsw);
3859#endif
3860 INTERPRET_CASE(OP_CLTS,Clts);
3861 INTERPRET_CASE(OP_MONITOR, Monitor);
3862 INTERPRET_CASE(OP_MWAIT, MWait);
3863 INTERPRET_CASE(OP_RDMSR, Rdmsr);
3864 INTERPRET_CASE(OP_WRMSR, Wrmsr);
3865 INTERPRET_CASE_EX_PARAM3(OP_ADD,Add, AddSub, EMEmulateAdd);
3866 INTERPRET_CASE_EX_PARAM3(OP_SUB,Sub, AddSub, EMEmulateSub);
3867 INTERPRET_CASE(OP_ADC,Adc);
3868 INTERPRET_CASE_EX_LOCK_PARAM2(OP_BTR,Btr, BitTest, EMEmulateBtr, EMEmulateLockBtr);
3869 INTERPRET_CASE_EX_PARAM2(OP_BTS,Bts, BitTest, EMEmulateBts);
3870 INTERPRET_CASE_EX_PARAM2(OP_BTC,Btc, BitTest, EMEmulateBtc);
3871 INTERPRET_CASE(OP_RDPMC,Rdpmc);
3872 INTERPRET_CASE(OP_RDTSC,Rdtsc);
3873 INTERPRET_CASE(OP_CMPXCHG, CmpXchg);
3874#ifdef IN_RC
3875 INTERPRET_CASE(OP_STI,Sti);
3876 INTERPRET_CASE(OP_XADD, XAdd);
3877 INTERPRET_CASE(OP_IRET,Iret);
3878#endif
3879 INTERPRET_CASE(OP_CMPXCHG8B, CmpXchg8b);
3880 INTERPRET_CASE(OP_HLT,Hlt);
3881 INTERPRET_CASE(OP_WBINVD,WbInvd);
3882#ifdef VBOX_WITH_STATISTICS
3883# ifndef IN_RC
3884 INTERPRET_STAT_CASE(OP_XADD, XAdd);
3885# endif
3886 INTERPRET_STAT_CASE(OP_MOVNTPS,MovNTPS);
3887#endif
3888
3889 default:
3890 Log3(("emInterpretInstructionCPU: opcode=%d\n", pDis->pCurInstr->uOpcode));
3891 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FailedMisc));
3892 return VERR_EM_INTERPRETER;
3893
3894#undef INTERPRET_CASE_EX_PARAM2
3895#undef INTERPRET_STAT_CASE
3896#undef INTERPRET_CASE_EX
3897#undef INTERPRET_CASE
3898 } /* switch (opcode) */
3899 /* not reached */
3900}
3901
3902/**
3903 * Interprets the current instruction using the supplied DISCPUSTATE structure.
3904 *
3905 * EIP is *NOT* updated!
3906 *
3907 * @returns VBox strict status code.
3908 * @retval VINF_* Scheduling instructions. When these are returned, it
3909 * starts to get a bit tricky to know whether code was
3910 * executed or not... We'll address this when it becomes a problem.
3911 * @retval VERR_EM_INTERPRETER Something we can't cope with.
3912 * @retval VERR_* Fatal errors.
3913 *
3914 * @param pVCpu Pointer to the VMCPU.
3915 * @param pDis The disassembler cpu state for the instruction to be
3916 * interpreted.
3917 * @param pRegFrame The register frame. EIP is *NOT* changed!
3918 * @param pvFault The fault address (CR2).
3919 * @param pcbSize Size of the write (if applicable).
3920 * @param enmCodeType Code type (user/supervisor)
3921 *
3922 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
3923 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
3924 * to worry about e.g. invalid modrm combinations (!)
3925 *
3926 * @todo At this time we do NOT check if the instruction overwrites vital information.
3927 * Make sure this can't happen!! (will add some assertions/checks later)
3928 */
3929DECLINLINE(VBOXSTRICTRC) emInterpretInstructionCPUOuter(PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame,
3930 RTGCPTR pvFault, EMCODETYPE enmCodeType, uint32_t *pcbSize)
3931{
3932 STAM_PROFILE_START(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Emulate), a);
3933 VBOXSTRICTRC rc = emInterpretInstructionCPU(pVCpu->CTX_SUFF(pVM), pVCpu, pDis, pRegFrame, pvFault, enmCodeType, pcbSize);
3934 STAM_PROFILE_STOP(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Emulate), a);
3935 if (RT_SUCCESS(rc))
3936 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InterpretSucceeded));
3937 else
3938 STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InterpretFailed));
3939 return rc;
3940}
3941
3942
3943#endif /* !VBOX_WITH_IEM */
Note: See TracBrowser for help on using the repository browser.

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