VirtualBox

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

Last change on this file since 42261 was 42186, checked in by vboxsync, 13 years ago

SELM,DIS,CPUM,EM: Hidden selector register cleanups.

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

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