VirtualBox

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

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

IEM,EM: We can safely assume that all CPUMCTXCORE and CPUMCTX arguments are pointing to the one in the VMCPU/CPUMCPU structure and no more stuff on the stack.

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

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