VirtualBox

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

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

CSAM,PATM: Don't bother initializing anything if HMIsEnabled(). Also, don't allow the components to be enabled.

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