VirtualBox

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

Last change on this file since 41406 was 41072, checked in by vboxsync, 13 years ago

VMM: fix VERR_PAGE_TABLE_NOT_PRESENT guru meditation caused by failing to disassemble an instruction because the guest's PDE/PTE is invalid, see #6043 for details.

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