VirtualBox

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

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

VBOX_WITH_RAW_MODE changes.

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

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