VirtualBox

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

Last change on this file since 41867 was 41830, checked in by vboxsync, 13 years ago

EMAll/IEM work.

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

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