VirtualBox

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

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

Doxygen, comment typos.

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

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