VirtualBox

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

Last change on this file since 18646 was 18338, checked in by vboxsync, 16 years ago

EMInterpretDisasOne: return val spec.

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