VirtualBox

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

Last change on this file since 25550 was 25550, checked in by vboxsync, 15 years ago

Raw mode: deal with invalidated tlb entries during disassembly (long overdue)

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