VirtualBox

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

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

VMM,INTNET: Addressing unused variable warnings.

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