VirtualBox

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

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

Doxygen

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

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