VirtualBox

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

Last change on this file since 62478 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

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