VirtualBox

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

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

Bigger lock for the pagefault handler.
Avoid deadlocks when syncing notification handlers with our recompiler.

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