VirtualBox

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

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

Extra logging of Intel performance counter MSR accesses

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