VirtualBox

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

Last change on this file since 17517 was 17515, checked in by vboxsync, 16 years ago

build fix.

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