VirtualBox

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

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

MSRs and MTRRs, CPUM saved state changed. (linux 2.4.31 seems to ignore the capabilites when it comes to fixed MTRRs.)

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