VirtualBox

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

Last change on this file since 7737 was 7737, checked in by vboxsync, 17 years ago

Allow PGM mode changes in ring 0 (hwaccm)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 72.6 KB
Line 
1/* $Id: EMAll.cpp 7737 2008-04-04 11:13:40Z vboxsync $ */
2/** @file
3 * EM - Execution Monitor(/Manager) - All contexts
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_EM
23#include <VBox/em.h>
24#include <VBox/mm.h>
25#include <VBox/selm.h>
26#include <VBox/patm.h>
27#include <VBox/csam.h>
28#include <VBox/pgm.h>
29#include <VBox/iom.h>
30#include <VBox/stam.h>
31#include "EMInternal.h"
32#include <VBox/vm.h>
33#include <VBox/hwaccm.h>
34#include <VBox/tm.h>
35
36#include <VBox/param.h>
37#include <VBox/err.h>
38#include <VBox/dis.h>
39#include <VBox/disopcode.h>
40#include <VBox/log.h>
41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/string.h>
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49typedef DECLCALLBACK(uint32_t) PFN_EMULATE_PARAM2_UINT32(uint32_t *pu32Param1, uint32_t val2);
50typedef DECLCALLBACK(uint32_t) PFN_EMULATE_PARAM2(uint32_t *pu32Param1, size_t val2);
51typedef DECLCALLBACK(uint32_t) PFN_EMULATE_PARAM3(uint32_t *pu32Param1, uint32_t val2, size_t val3);
52typedef DECLCALLBACK(int) FNEMULATELOCKPARAM2(RTGCPTR GCPtrParam1, RTGCUINTREG Val2, uint32_t *pf);
53typedef FNEMULATELOCKPARAM2 *PFNEMULATELOCKPARAM2;
54typedef DECLCALLBACK(int) FNEMULATELOCKPARAM3(RTGCPTR GCPtrParam1, RTGCUINTREG Val2, size_t cb, uint32_t *pf);
55typedef FNEMULATELOCKPARAM3 *PFNEMULATELOCKPARAM3;
56
57
58/*******************************************************************************
59* Internal Functions *
60*******************************************************************************/
61DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize);
62
63
64/**
65 * Get the current execution manager status.
66 *
67 * @returns Current status.
68 */
69EMDECL(EMSTATE) EMGetState(PVM pVM)
70{
71 return pVM->em.s.enmState;
72}
73
74
75#ifndef IN_GC
76/**
77 * Read callback for disassembly function; supports reading bytes that cross a page boundary
78 *
79 * @returns VBox status code.
80 * @param pSrc GC source pointer
81 * @param pDest HC destination pointer
82 * @param size Number of bytes to read
83 * @param dwUserdata Callback specific user data (pCpu)
84 *
85 */
86DECLCALLBACK(int) EMReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata)
87{
88 DISCPUSTATE *pCpu = (DISCPUSTATE *)pvUserdata;
89 PVM pVM = (PVM)pCpu->apvUserData[0];
90#ifdef IN_RING0
91 int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
92 AssertRC(rc);
93#else
94 if (!PATMIsPatchGCAddr(pVM, pSrc))
95 {
96 int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
97 AssertRC(rc);
98 }
99 else
100 {
101 for (uint32_t i = 0; i < size; i++)
102 {
103 uint8_t opcode;
104 if (VBOX_SUCCESS(PATMR3QueryOpcode(pVM, (RTGCPTR)pSrc + i, &opcode)))
105 {
106 *(pDest+i) = opcode;
107 }
108 }
109 }
110#endif /* IN_RING0 */
111 return VINF_SUCCESS;
112}
113
114DECLINLINE(int) emDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
115{
116 return DISCoreOneEx(InstrGC, pCpu->mode, EMReadBytes, pVM, pCpu, pOpsize);
117}
118
119#else
120
121DECLINLINE(int) emDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
122{
123 return DISCoreOne(pCpu, InstrGC, pOpsize);
124}
125
126#endif
127
128
129/**
130 * Disassembles one instruction.
131 *
132 * @param pVM The VM handle.
133 * @param pCtxCore The context core (used for both the mode and instruction).
134 * @param pCpu Where to return the parsed instruction info.
135 * @param pcbInstr Where to return the instruction size. (optional)
136 */
137EMDECL(int) EMInterpretDisasOne(PVM pVM, PCCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, unsigned *pcbInstr)
138{
139 RTGCPTR GCPtrInstr;
140 int rc = SELMValidateAndConvertCSAddr(pVM, pCtxCore->eflags, pCtxCore->ss, pCtxCore->cs, (PCPUMSELREGHID)&pCtxCore->csHid, (RTGCPTR)pCtxCore->eip, &GCPtrInstr);
141 if (VBOX_FAILURE(rc))
142 {
143 Log(("EMInterpretDisasOne: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
144 pCtxCore->cs, pCtxCore->eip, pCtxCore->ss & X86_SEL_RPL, rc));
145 return rc;
146 }
147 return EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)GCPtrInstr, pCtxCore, pCpu, pcbInstr);
148}
149
150
151/**
152 * Disassembles one instruction.
153 *
154 * This is used by internally by the interpreter and by trap/access handlers.
155 *
156 * @param pVM The VM handle.
157 * @param GCPtrInstr The flat address of the instruction.
158 * @param pCtxCore The context core (used to determin the cpu mode).
159 * @param pCpu Where to return the parsed instruction info.
160 * @param pcbInstr Where to return the instruction size. (optional)
161 */
162EMDECL(int) EMInterpretDisasOneEx(PVM pVM, RTGCUINTPTR GCPtrInstr, PCCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, unsigned *pcbInstr)
163{
164 int rc = DISCoreOneEx(GCPtrInstr, SELMIsSelector32Bit(pVM, pCtxCore->eflags, pCtxCore->cs, (PCPUMSELREGHID)&pCtxCore->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT,
165#ifdef IN_GC
166 NULL, NULL,
167#else
168 EMReadBytes, pVM,
169#endif
170 pCpu, pcbInstr);
171 if (VBOX_SUCCESS(rc))
172 return VINF_SUCCESS;
173 AssertMsgFailed(("DISCoreOne failed to GCPtrInstr=%VGv rc=%Vrc\n", GCPtrInstr, rc));
174 return VERR_INTERNAL_ERROR;
175}
176
177
178/**
179 * Interprets the current instruction.
180 *
181 * @returns VBox status code.
182 * @retval VINF_* Scheduling instructions.
183 * @retval VERR_EM_INTERPRETER Something we can't cope with.
184 * @retval VERR_* Fatal errors.
185 *
186 * @param pVM The VM handle.
187 * @param pRegFrame The register frame.
188 * Updates the EIP if an instruction was executed successfully.
189 * @param pvFault The fault address (CR2).
190 * @param pcbSize Size of the write (if applicable).
191 *
192 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
193 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
194 * to worry about e.g. invalid modrm combinations (!)
195 */
196EMDECL(int) EMInterpretInstruction(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
197{
198 RTGCPTR pbCode;
199 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &pbCode);
200 if (VBOX_SUCCESS(rc))
201 {
202 uint32_t cbOp;
203 DISCPUSTATE Cpu;
204 Cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
205 rc = emDisCoreOne(pVM, &Cpu, (RTGCUINTPTR)pbCode, &cbOp);
206 if (VBOX_SUCCESS(rc))
207 {
208 Assert(cbOp == Cpu.opsize);
209 rc = EMInterpretInstructionCPU(pVM, &Cpu, pRegFrame, pvFault, pcbSize);
210 if (VBOX_SUCCESS(rc))
211 {
212 pRegFrame->eip += cbOp; /* Move on to the next instruction. */
213 }
214 return rc;
215 }
216 }
217 return VERR_EM_INTERPRETER;
218}
219
220/**
221 * Interprets the current instruction using the supplied DISCPUSTATE structure.
222 *
223 * EIP is *NOT* updated!
224 *
225 * @returns VBox status code.
226 * @retval VINF_* Scheduling instructions. When these are returned, it
227 * starts to get a bit tricky to know whether code was
228 * executed or not... We'll address this when it becomes a problem.
229 * @retval VERR_EM_INTERPRETER Something we can't cope with.
230 * @retval VERR_* Fatal errors.
231 *
232 * @param pVM The VM handle.
233 * @param pCpu The disassembler cpu state for the instruction to be interpreted.
234 * @param pRegFrame The register frame. EIP is *NOT* changed!
235 * @param pvFault The fault address (CR2).
236 * @param pcbSize Size of the write (if applicable).
237 *
238 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
239 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
240 * to worry about e.g. invalid modrm combinations (!)
241 *
242 * @todo At this time we do NOT check if the instruction overwrites vital information.
243 * Make sure this can't happen!! (will add some assertions/checks later)
244 */
245EMDECL(int) EMInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
246{
247 STAM_PROFILE_START(&CTXMID(pVM->em.s.CTXSUFF(pStats)->Stat,Emulate), a);
248 int rc = emInterpretInstructionCPU(pVM, pCpu, pRegFrame, pvFault, pcbSize);
249 STAM_PROFILE_STOP(&CTXMID(pVM->em.s.CTXSUFF(pStats)->Stat,Emulate), a);
250 if (VBOX_SUCCESS(rc))
251 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,InterpretSucceeded));
252 else
253 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,InterpretFailed));
254 return rc;
255}
256
257
258/**
259 * Interpret a port I/O instruction.
260 *
261 * @returns VBox status code suitable for scheduling.
262 * @param pVM The VM handle.
263 * @param pCtxCore The context core. This will be updated on successful return.
264 * @param pCpu The instruction to interpret.
265 * @param cbOp The size of the instruction.
266 * @remark This may raise exceptions.
267 */
268EMDECL(int) EMInterpretPortIO(PVM pVM, PCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, uint32_t cbOp)
269{
270 /*
271 * Hand it on to IOM.
272 */
273#ifdef IN_GC
274 int rc = IOMGCIOPortHandler(pVM, pCtxCore, pCpu);
275 if (IOM_SUCCESS(rc))
276 pCtxCore->eip += cbOp;
277 return rc;
278#else
279 AssertReleaseMsgFailed(("not implemented\n"));
280 return VERR_NOT_IMPLEMENTED;
281#endif
282}
283
284
285DECLINLINE(int) emRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
286{
287#ifdef IN_GC
288 int rc = MMGCRamRead(pVM, pDest, GCSrc, cb);
289 if (RT_LIKELY(rc != VERR_ACCESS_DENIED))
290 return rc;
291 /*
292 * The page pool cache may end up here in some cases because it
293 * flushed one of the shadow mappings used by the trapping
294 * instruction and it either flushed the TLB or the CPU reused it.
295 */
296 RTGCPHYS GCPhys;
297 rc = PGMPhysGCPtr2GCPhys(pVM, GCSrc, &GCPhys);
298 AssertRCReturn(rc, rc);
299 PGMPhysRead(pVM, GCPhys, pDest, cb);
300 return VINF_SUCCESS;
301#else
302 return PGMPhysReadGCPtrSafe(pVM, pDest, GCSrc, cb);
303#endif
304}
305
306DECLINLINE(int) emRamWrite(PVM pVM, RTGCPTR GCDest, void *pSrc, uint32_t cb)
307{
308#ifdef IN_GC
309 int rc = MMGCRamWrite(pVM, GCDest, pSrc, cb);
310 if (RT_LIKELY(rc != VERR_ACCESS_DENIED))
311 return rc;
312 /*
313 * The page pool cache may end up here in some cases because it
314 * flushed one of the shadow mappings used by the trapping
315 * instruction and it either flushed the TLB or the CPU reused it.
316 * We want to play safe here, verifying that we've got write
317 * access doesn't cost us much (see PGMPhysGCPtr2GCPhys()).
318 */
319 uint64_t fFlags;
320 RTGCPHYS GCPhys;
321 rc = PGMGstGetPage(pVM, GCDest, &fFlags, &GCPhys);
322 if (RT_FAILURE(rc))
323 return rc;
324 if ( !(fFlags & X86_PTE_RW)
325 && (CPUMGetGuestCR0(pVM) & X86_CR0_WP))
326 return VERR_ACCESS_DENIED;
327
328 PGMPhysWrite(pVM, GCPhys + ((RTGCUINTPTR)GCDest & PAGE_OFFSET_MASK), pSrc, cb);
329 return VINF_SUCCESS;
330
331#else
332 return PGMPhysWriteGCPtrSafe(pVM, GCDest, pSrc, cb);
333#endif
334}
335
336/* Convert sel:addr to a flat GC address */
337static RTGCPTR emConvertToFlatAddr(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, POP_PARAMETER pParam, RTGCPTR pvAddr)
338{
339 int prefix_seg, rc;
340 RTSEL sel;
341 CPUMSELREGHID *pSelHidReg;
342
343 prefix_seg = DISDetectSegReg(pCpu, pParam);
344 rc = DISFetchRegSegEx(pRegFrame, prefix_seg, &sel, &pSelHidReg);
345 if (VBOX_FAILURE(rc))
346 return pvAddr;
347
348 return SELMToFlat(pVM, pRegFrame->eflags, sel, pSelHidReg, pvAddr);
349}
350
351#if defined(VBOX_STRICT) || defined(LOG_ENABLED)
352/**
353 * Get the mnemonic for the disassembled instruction.
354 *
355 * GC/R0 doesn't include the strings in the DIS tables because
356 * of limited space.
357 */
358static const char *emGetMnemonic(PDISCPUSTATE pCpu)
359{
360 switch (pCpu->pCurInstr->opcode)
361 {
362 case OP_XOR: return "Xor";
363 case OP_OR: return "Or";
364 case OP_AND: return "And";
365 case OP_BTR: return "Btr";
366 case OP_BTS: return "Bts";
367 default:
368 AssertMsgFailed(("%d\n", pCpu->pCurInstr->opcode));
369 return "???";
370 }
371}
372#endif
373
374/**
375 * XCHG instruction emulation.
376 */
377static int emInterpretXchg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
378{
379 OP_PARAMVAL param1, param2;
380
381 /* Source to make DISQueryParamVal read the register value - ugly hack */
382 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
383 if(VBOX_FAILURE(rc))
384 return VERR_EM_INTERPRETER;
385
386 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
387 if(VBOX_FAILURE(rc))
388 return VERR_EM_INTERPRETER;
389
390#ifdef IN_GC
391 if (TRPMHasTrap(pVM))
392 {
393 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
394 {
395#endif
396 RTGCPTR pParam1 = 0, pParam2 = 0;
397 uint32_t valpar1, valpar2;
398
399 AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
400 switch(param1.type)
401 {
402 case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
403 valpar1 = param1.val.val32;
404 break;
405
406 case PARMTYPE_ADDRESS:
407 pParam1 = (RTGCPTR)param1.val.val32;
408 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
409#ifdef IN_GC
410 /* Safety check (in theory it could cross a page boundary and fault there though) */
411 AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
412#endif
413 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
414 if (VBOX_FAILURE(rc))
415 {
416 AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
417 return VERR_EM_INTERPRETER;
418 }
419 break;
420
421 default:
422 AssertFailed();
423 return VERR_EM_INTERPRETER;
424 }
425
426 switch(param2.type)
427 {
428 case PARMTYPE_ADDRESS:
429 pParam2 = (RTGCPTR)param2.val.val32;
430 pParam2 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param2, pParam2);
431#ifdef IN_GC
432 /* Safety check (in theory it could cross a page boundary and fault there though) */
433 AssertReturn(pParam2 == pvFault, VERR_EM_INTERPRETER);
434#endif
435 rc = emRamRead(pVM, &valpar2, pParam2, param2.size);
436 if (VBOX_FAILURE(rc))
437 {
438 AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
439 }
440 break;
441
442 case PARMTYPE_IMMEDIATE:
443 valpar2 = param2.val.val32;
444 break;
445
446 default:
447 AssertFailed();
448 return VERR_EM_INTERPRETER;
449 }
450
451 /* Write value of parameter 2 to parameter 1 (reg or memory address) */
452 if (pParam1 == 0)
453 {
454 Assert(param1.type == PARMTYPE_IMMEDIATE); /* register actually */
455 switch(param1.size)
456 {
457 case 1: //special case for AH etc
458 rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen8, (uint8_t)valpar2); break;
459 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen32, (uint16_t)valpar2); break;
460 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen32, valpar2); break;
461 default: AssertFailedReturn(VERR_EM_INTERPRETER);
462 }
463 if (VBOX_FAILURE(rc))
464 return VERR_EM_INTERPRETER;
465 }
466 else
467 {
468 rc = emRamWrite(pVM, pParam1, &valpar2, param1.size);
469 if (VBOX_FAILURE(rc))
470 {
471 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
472 return VERR_EM_INTERPRETER;
473 }
474 }
475
476 /* Write value of parameter 1 to parameter 2 (reg or memory address) */
477 if (pParam2 == 0)
478 {
479 Assert(param2.type == PARMTYPE_IMMEDIATE); /* register actually */
480 switch(param2.size)
481 {
482 case 1: //special case for AH etc
483 rc = DISWriteReg8(pRegFrame, pCpu->param2.base.reg_gen8, (uint8_t)valpar1); break;
484 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param2.base.reg_gen32, (uint16_t)valpar1); break;
485 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param2.base.reg_gen32, valpar1); break;
486 default: AssertFailedReturn(VERR_EM_INTERPRETER);
487 }
488 if (VBOX_FAILURE(rc))
489 return VERR_EM_INTERPRETER;
490 }
491 else
492 {
493 rc = emRamWrite(pVM, pParam2, &valpar1, param2.size);
494 if (VBOX_FAILURE(rc))
495 {
496 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
497 return VERR_EM_INTERPRETER;
498 }
499 }
500
501 *pcbSize = param2.size;
502 return VINF_SUCCESS;
503#ifdef IN_GC
504 }
505 }
506#endif
507 return VERR_EM_INTERPRETER;
508}
509
510/**
511 * INC and DEC emulation.
512 */
513static int emInterpretIncDec(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
514 PFN_EMULATE_PARAM2 pfnEmulate)
515{
516 OP_PARAMVAL param1;
517
518 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
519 if(VBOX_FAILURE(rc))
520 return VERR_EM_INTERPRETER;
521
522#ifdef IN_GC
523 if (TRPMHasTrap(pVM))
524 {
525 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
526 {
527#endif
528 RTGCPTR pParam1 = 0;
529 uint32_t valpar1;
530
531 if (param1.type == PARMTYPE_ADDRESS)
532 {
533 pParam1 = (RTGCPTR)param1.val.val32;
534 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
535#ifdef IN_GC
536 /* Safety check (in theory it could cross a page boundary and fault there though) */
537 AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
538#endif
539 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
540 if (VBOX_FAILURE(rc))
541 {
542 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
543 return VERR_EM_INTERPRETER;
544 }
545 }
546 else
547 {
548 AssertFailed();
549 return VERR_EM_INTERPRETER;
550 }
551
552 uint32_t eflags;
553
554 eflags = pfnEmulate(&valpar1, param1.size);
555
556 /* Write result back */
557 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
558 if (VBOX_FAILURE(rc))
559 {
560 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
561 return VERR_EM_INTERPRETER;
562 }
563
564 /* Update guest's eflags and finish. */
565 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
566 | (eflags & (X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
567
568 /* All done! */
569 *pcbSize = param1.size;
570 return VINF_SUCCESS;
571#ifdef IN_GC
572 }
573 }
574#endif
575 return VERR_EM_INTERPRETER;
576}
577
578/**
579 * POP Emulation.
580 */
581static int emInterpretPop(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
582{
583 OP_PARAMVAL param1;
584 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
585 if(VBOX_FAILURE(rc))
586 return VERR_EM_INTERPRETER;
587
588#ifdef IN_GC
589 if (TRPMHasTrap(pVM))
590 {
591 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
592 {
593#endif
594 RTGCPTR pParam1 = 0;
595 uint32_t valpar1;
596 RTGCPTR pStackVal;
597
598 /* Read stack value first */
599 if (SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid) == false)
600 return VERR_EM_INTERPRETER; /* No legacy 16 bits stuff here, please. */
601
602 /* Convert address; don't bother checking limits etc, as we only read here */
603 pStackVal = SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid, (RTGCPTR)pRegFrame->esp);
604 if (pStackVal == 0)
605 return VERR_EM_INTERPRETER;
606
607 rc = emRamRead(pVM, &valpar1, pStackVal, param1.size);
608 if (VBOX_FAILURE(rc))
609 {
610 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
611 return VERR_EM_INTERPRETER;
612 }
613
614 if (param1.type == PARMTYPE_ADDRESS)
615 {
616 pParam1 = (RTGCPTR)param1.val.val32;
617
618 /* pop [esp+xx] uses esp after the actual pop! */
619 AssertCompile(USE_REG_ESP == USE_REG_SP);
620 if ( (pCpu->param1.flags & USE_BASE)
621 && (pCpu->param1.flags & (USE_REG_GEN16|USE_REG_GEN32))
622 && pCpu->param1.base.reg_gen32 == USE_REG_ESP
623 )
624 pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + param1.size);
625
626 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
627
628#ifdef IN_GC
629 /* Safety check (in theory it could cross a page boundary and fault there though) */
630 AssertMsgReturn(pParam1 == pvFault || (RTGCPTR)pRegFrame->esp == pvFault, ("%VGv != %VGv ss:esp=%04X:%VGv\n", pParam1, pvFault, pRegFrame->ss, pRegFrame->esp), VERR_EM_INTERPRETER);
631#endif
632 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
633 if (VBOX_FAILURE(rc))
634 {
635 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
636 return VERR_EM_INTERPRETER;
637 }
638
639 /* Update ESP as the last step */
640 pRegFrame->esp += param1.size;
641 }
642 else
643 {
644#ifndef DEBUG_bird // annoying assertion.
645 AssertFailed();
646#endif
647 return VERR_EM_INTERPRETER;
648 }
649
650 /* All done! */
651 *pcbSize = param1.size;
652 return VINF_SUCCESS;
653#ifdef IN_GC
654 }
655 }
656#endif
657 return VERR_EM_INTERPRETER;
658}
659
660
661/**
662 * XOR/OR/AND Emulation.
663 */
664static int emInterpretOrXorAnd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
665 PFN_EMULATE_PARAM3 pfnEmulate)
666{
667 OP_PARAMVAL param1, param2;
668 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
669 if(VBOX_FAILURE(rc))
670 return VERR_EM_INTERPRETER;
671
672 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
673 if(VBOX_FAILURE(rc))
674 return VERR_EM_INTERPRETER;
675
676#ifdef DEBUG
677 const char *pszInstr;
678
679 if (pCpu->pCurInstr->opcode == OP_XOR)
680 pszInstr = "Xor";
681 else
682 if (pCpu->pCurInstr->opcode == OP_OR)
683 pszInstr = "Or";
684 else
685 if (pCpu->pCurInstr->opcode == OP_AND)
686 pszInstr = "And";
687#endif
688
689#ifdef IN_GC
690 if (TRPMHasTrap(pVM))
691 {
692 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
693 {
694#endif
695 RTGCPTR pParam1;
696 uint32_t valpar1, valpar2;
697
698 if (pCpu->param1.size != pCpu->param2.size)
699 {
700 if (pCpu->param1.size < pCpu->param2.size)
701 {
702 AssertMsgFailed(("%s at %VGv parameter mismatch %d vs %d!!\n", pszInstr, pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
703 return VERR_EM_INTERPRETER;
704 }
705 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
706 pCpu->param2.size = pCpu->param1.size;
707 param2.size = param1.size;
708 }
709
710 /* The destination is always a virtual address */
711 if (param1.type == PARMTYPE_ADDRESS)
712 {
713 pParam1 = (RTGCPTR)param1.val.val32;
714 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
715
716#ifdef IN_GC
717 /* Safety check (in theory it could cross a page boundary and fault there though) */
718 AssertMsgReturn(pParam1 == pvFault, ("eip=%VGv, pParam1=%VGv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
719#endif
720 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
721 if (VBOX_FAILURE(rc))
722 {
723 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
724 return VERR_EM_INTERPRETER;
725 }
726 }
727 else
728 {
729 AssertFailed();
730 return VERR_EM_INTERPRETER;
731 }
732
733 /* Register or immediate data */
734 switch(param2.type)
735 {
736 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
737 valpar2 = param2.val.val32;
738 break;
739
740 default:
741 AssertFailed();
742 return VERR_EM_INTERPRETER;
743 }
744
745 /* Data read, emulate instruction. */
746 uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
747
748 /* Update guest's eflags and finish. */
749 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
750 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
751
752 /* And write it back */
753 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
754 if (VBOX_SUCCESS(rc))
755 {
756 /* All done! */
757 *pcbSize = param2.size;
758 return VINF_SUCCESS;
759 }
760#ifdef IN_GC
761 }
762 }
763#endif
764 return VERR_EM_INTERPRETER;
765}
766
767#ifdef IN_GC
768/**
769 * LOCK XOR/OR/AND Emulation.
770 */
771static int emInterpretLockOrXorAnd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault,
772 uint32_t *pcbSize, PFNEMULATELOCKPARAM3 pfnEmulate)
773{
774 OP_PARAMVAL param1, param2;
775 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
776 if(VBOX_FAILURE(rc))
777 return VERR_EM_INTERPRETER;
778
779 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
780 if(VBOX_FAILURE(rc))
781 return VERR_EM_INTERPRETER;
782
783 if (pCpu->param1.size != pCpu->param2.size)
784 {
785 AssertMsgReturn(pCpu->param1.size >= pCpu->param2.size, /* should never happen! */
786 ("%s at %VGv parameter mismatch %d vs %d!!\n", emGetMnemonic(pCpu), pRegFrame->eip, pCpu->param1.size, pCpu->param2.size),
787 VERR_EM_INTERPRETER);
788
789 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
790 pCpu->param2.size = pCpu->param1.size;
791 param2.size = param1.size;
792 }
793
794 /* The destination is always a virtual address */
795 AssertReturn(param1.type == PARMTYPE_ADDRESS, VERR_EM_INTERPRETER);
796 RTGCPTR GCPtrPar1 = (RTGCPTR)param1.val.val32;
797 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, GCPtrPar1);
798
799# ifdef IN_GC
800 /* Safety check (in theory it could cross a page boundary and fault there though) */
801 Assert( TRPMHasTrap(pVM)
802 && (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW));
803 AssertMsgReturn(GCPtrPar1 == pvFault, ("eip=%VGv, GCPtrPar1=%VGv pvFault=%VGv\n", pRegFrame->eip, GCPtrPar1, pvFault), VERR_EM_INTERPRETER);
804# endif
805
806 /* Register and immediate data == PARMTYPE_IMMEDIATE */
807 AssertReturn(param2.type == PARMTYPE_IMMEDIATE, VERR_EM_INTERPRETER);
808 RTGCUINTREG ValPar2 = param2.val.val32;
809
810 /* Try emulate it with a one-shot #PF handler in place. */
811 Log2(("%s %RGv imm%d=%RGr\n", emGetMnemonic(pCpu), GCPtrPar1, pCpu->param2.size*8, ValPar2));
812
813 RTGCUINTREG eflags = 0;
814 MMGCRamRegisterTrapHandler(pVM);
815 rc = pfnEmulate(GCPtrPar1, ValPar2, pCpu->param2.size, &eflags);
816 MMGCRamDeregisterTrapHandler(pVM);
817
818 if (RT_FAILURE(rc))
819 {
820 Log(("%s %RGv imm%d=%RGr -> emulation failed due to page fault!\n", emGetMnemonic(pCpu), GCPtrPar1, pCpu->param2.size*8, ValPar2));
821 return VERR_EM_INTERPRETER;
822 }
823
824 /* Update guest's eflags and finish. */
825 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
826 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
827
828 *pcbSize = param2.size;
829 return VINF_SUCCESS;
830}
831#endif
832
833/**
834 * ADD, ADC & SUB Emulation.
835 */
836static int emInterpretAddSub(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
837 PFN_EMULATE_PARAM3 pfnEmulate)
838{
839 OP_PARAMVAL param1, param2;
840 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
841 if(VBOX_FAILURE(rc))
842 return VERR_EM_INTERPRETER;
843
844 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
845 if(VBOX_FAILURE(rc))
846 return VERR_EM_INTERPRETER;
847
848#ifdef DEBUG
849 const char *pszInstr;
850
851 if (pCpu->pCurInstr->opcode == OP_SUB)
852 pszInstr = "Sub";
853 else
854 if (pCpu->pCurInstr->opcode == OP_ADD)
855 pszInstr = "Add";
856 else
857 if (pCpu->pCurInstr->opcode == OP_ADC)
858 pszInstr = "Adc";
859#endif
860
861#ifdef IN_GC
862 if (TRPMHasTrap(pVM))
863 {
864 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
865 {
866#endif
867 RTGCPTR pParam1;
868 uint32_t valpar1, valpar2;
869
870 if (pCpu->param1.size != pCpu->param2.size)
871 {
872 if (pCpu->param1.size < pCpu->param2.size)
873 {
874 AssertMsgFailed(("%s at %VGv parameter mismatch %d vs %d!!\n", pszInstr, pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
875 return VERR_EM_INTERPRETER;
876 }
877 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
878 pCpu->param2.size = pCpu->param1.size;
879 param2.size = param1.size;
880 }
881
882 /* The destination is always a virtual address */
883 if (param1.type == PARMTYPE_ADDRESS)
884 {
885 pParam1 = (RTGCPTR)param1.val.val32;
886 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
887
888#ifdef IN_GC
889 /* Safety check (in theory it could cross a page boundary and fault there though) */
890 AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
891#endif
892 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
893 if (VBOX_FAILURE(rc))
894 {
895 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
896 return VERR_EM_INTERPRETER;
897 }
898 }
899 else
900 {
901#ifndef DEBUG_bird
902 AssertFailed();
903#endif
904 return VERR_EM_INTERPRETER;
905 }
906
907 /* Register or immediate data */
908 switch(param2.type)
909 {
910 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
911 valpar2 = param2.val.val32;
912 break;
913
914 default:
915 AssertFailed();
916 return VERR_EM_INTERPRETER;
917 }
918
919 /* Data read, emulate instruction. */
920 uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
921
922 /* Update guest's eflags and finish. */
923 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
924 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
925
926 /* And write it back */
927 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
928 if (VBOX_SUCCESS(rc))
929 {
930 /* All done! */
931 *pcbSize = param2.size;
932 return VINF_SUCCESS;
933 }
934#ifdef IN_GC
935 }
936 }
937#endif
938 return VERR_EM_INTERPRETER;
939}
940
941/**
942 * ADC Emulation.
943 */
944static int emInterpretAdc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
945{
946 if (pRegFrame->eflags.Bits.u1CF)
947 return emInterpretAddSub(pVM, pCpu, pRegFrame, pvFault, pcbSize, EMEmulateAdcWithCarrySet);
948 else
949 return emInterpretAddSub(pVM, pCpu, pRegFrame, pvFault, pcbSize, EMEmulateAdd);
950}
951
952/**
953 * BTR/C/S Emulation.
954 */
955static int emInterpretBitTest(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
956 PFN_EMULATE_PARAM2_UINT32 pfnEmulate)
957{
958 OP_PARAMVAL param1, param2;
959 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
960 if(VBOX_FAILURE(rc))
961 return VERR_EM_INTERPRETER;
962
963 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
964 if(VBOX_FAILURE(rc))
965 return VERR_EM_INTERPRETER;
966
967#ifdef LOG_ENABLED
968 const char *pszInstr;
969
970 if (pCpu->pCurInstr->opcode == OP_BTR)
971 pszInstr = "Btr";
972 else
973 if (pCpu->pCurInstr->opcode == OP_BTS)
974 pszInstr = "Bts";
975 else
976 if (pCpu->pCurInstr->opcode == OP_BTC)
977 pszInstr = "Btc";
978#endif
979
980#ifdef IN_GC
981 if (TRPMHasTrap(pVM))
982 {
983 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
984 {
985#endif
986 RTGCPTR pParam1;
987 uint32_t valpar1 = 0, valpar2;
988 uint32_t eflags;
989
990 /* The destination is always a virtual address */
991 if (param1.type != PARMTYPE_ADDRESS)
992 return VERR_EM_INTERPRETER;
993
994 pParam1 = (RTGCPTR)param1.val.val32;
995 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
996
997 /* Register or immediate data */
998 switch(param2.type)
999 {
1000 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
1001 valpar2 = param2.val.val32;
1002 break;
1003
1004 default:
1005 AssertFailed();
1006 return VERR_EM_INTERPRETER;
1007 }
1008
1009 Log2(("emInterpret%s: pvFault=%VGv pParam1=%VGv val2=%x\n", pszInstr, pvFault, pParam1, valpar2));
1010 pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + valpar2/8);
1011#ifdef IN_GC
1012 /* Safety check. */
1013 AssertMsgReturn((RTGCPTR)((RTGCUINTPTR)pParam1 & ~3) == pvFault, ("pParam1=%VGv pvFault=%VGv\n", pParam1, pvFault), VERR_EM_INTERPRETER);
1014#endif
1015 rc = emRamRead(pVM, &valpar1, pParam1, 1);
1016 if (VBOX_FAILURE(rc))
1017 {
1018 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
1019 return VERR_EM_INTERPRETER;
1020 }
1021
1022 Log2(("emInterpretBtx: val=%x\n", valpar1));
1023 /* Data read, emulate bit test instruction. */
1024 eflags = pfnEmulate(&valpar1, valpar2 & 0x7);
1025
1026 Log2(("emInterpretBtx: val=%x CF=%d\n", valpar1, !!(eflags & X86_EFL_CF)));
1027
1028 /* Update guest's eflags and finish. */
1029 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1030 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1031
1032 /* And write it back */
1033 rc = emRamWrite(pVM, pParam1, &valpar1, 1);
1034 if (VBOX_SUCCESS(rc))
1035 {
1036 /* All done! */
1037 *pcbSize = 1;
1038 return VINF_SUCCESS;
1039 }
1040#ifdef IN_GC
1041 }
1042 }
1043#endif
1044 return VERR_EM_INTERPRETER;
1045}
1046
1047#ifdef IN_GC
1048/**
1049 * LOCK BTR/C/S Emulation.
1050 */
1051static int emInterpretLockBitTest(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault,
1052 uint32_t *pcbSize, PFNEMULATELOCKPARAM2 pfnEmulate)
1053{
1054 OP_PARAMVAL param1, param2;
1055 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
1056 if(VBOX_FAILURE(rc))
1057 return VERR_EM_INTERPRETER;
1058
1059 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
1060 if(VBOX_FAILURE(rc))
1061 return VERR_EM_INTERPRETER;
1062
1063 /* The destination is always a virtual address */
1064 if (param1.type != PARMTYPE_ADDRESS)
1065 return VERR_EM_INTERPRETER;
1066
1067 RTGCPTR GCPtrPar1 = (RTGCPTR)param1.val.val32;
1068 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, GCPtrPar1);
1069
1070 /* Register and immediate data == PARMTYPE_IMMEDIATE */
1071 AssertReturn(param2.type == PARMTYPE_IMMEDIATE, VERR_EM_INTERPRETER);
1072 RTGCUINTREG ValPar2 = param2.val.val32;
1073
1074 Log2(("emInterpretLockBitTest %s: pvFault=%VGv GCPtrPar1=%RGv imm=%RGr\n", emGetMnemonic(pCpu), pvFault, GCPtrPar1, ValPar2));
1075
1076 /* Adjust the parameters so what we're dealing with is a bit within the byte pointed to. */
1077 GCPtrPar1 = (RTGCPTR)((RTGCUINTPTR)GCPtrPar1 + ValPar2 / 8);
1078 ValPar2 &= 7;
1079# ifdef IN_GC
1080 Assert(TRPMHasTrap(pVM));
1081 AssertMsgReturn((RTGCPTR)((RTGCUINTPTR)GCPtrPar1 & ~(RTGCUINTPTR)3) == pvFault,
1082 ("GCPtrPar1=%VGv pvFault=%VGv\n", GCPtrPar1, pvFault),
1083 VERR_EM_INTERPRETER);
1084# endif
1085
1086 /* Try emulate it with a one-shot #PF handler in place. */
1087 RTGCUINTREG eflags = 0;
1088 MMGCRamRegisterTrapHandler(pVM);
1089 rc = pfnEmulate(GCPtrPar1, ValPar2, &eflags);
1090 MMGCRamDeregisterTrapHandler(pVM);
1091
1092 if (RT_FAILURE(rc))
1093 {
1094 Log(("emInterpretLockBitTest %s: %RGv imm%d=%RGr -> emulation failed due to page fault!\n",
1095 emGetMnemonic(pCpu), GCPtrPar1, pCpu->param2.size*8, ValPar2));
1096 return VERR_EM_INTERPRETER;
1097 }
1098
1099 Log2(("emInterpretLockBitTest %s: GCPtrPar1=%RGv imm=%RGr CF=%d\n", emGetMnemonic(pCpu), GCPtrPar1, ValPar2, !!(eflags & X86_EFL_CF)));
1100
1101 /* Update guest's eflags and finish. */
1102 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1103 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1104
1105 *pcbSize = 1;
1106 return VINF_SUCCESS;
1107}
1108#endif /* IN_GC */
1109
1110/**
1111 * MOV emulation.
1112 */
1113static int emInterpretMov(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1114{
1115 OP_PARAMVAL param1, param2;
1116 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
1117 if(VBOX_FAILURE(rc))
1118 return VERR_EM_INTERPRETER;
1119
1120 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
1121 if(VBOX_FAILURE(rc))
1122 return VERR_EM_INTERPRETER;
1123
1124#ifdef IN_GC
1125 if (TRPMHasTrap(pVM))
1126 {
1127 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1128 {
1129#else
1130 /** @todo Make this the default and don't rely on TRPM information. */
1131 if (param1.type == PARMTYPE_ADDRESS)
1132 {
1133#endif
1134 RTGCPTR pDest;
1135 uint32_t val32;
1136
1137 switch(param1.type)
1138 {
1139 case PARMTYPE_IMMEDIATE:
1140 if(!(param1.flags & PARAM_VAL32))
1141 return VERR_EM_INTERPRETER;
1142 /* fallthru */
1143
1144 case PARMTYPE_ADDRESS:
1145 pDest = (RTGCPTR)param1.val.val32;
1146 pDest = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pDest);
1147 break;
1148
1149 default:
1150 AssertFailed();
1151 return VERR_EM_INTERPRETER;
1152 }
1153
1154 switch(param2.type)
1155 {
1156 case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
1157 val32 = param2.val.val32;
1158 break;
1159
1160 default:
1161 Log(("emInterpretMov: unexpected type=%d eip=%VGv\n", param2.type, pRegFrame->eip));
1162 return VERR_EM_INTERPRETER;
1163 }
1164 LogFlow(("EMInterpretInstruction at %08x: OP_MOV %08X <- %08X (%d) &val32=%08x\n", pRegFrame->eip, pDest, val32, param2.size, &val32));
1165
1166 Assert(param2.size <= 4 && param2.size > 0);
1167
1168#if 0 /* CSAM/PATM translates aliases which causes this to incorrectly trigger. See #2609 and #1498. */
1169#ifdef IN_GC
1170 /* Safety check (in theory it could cross a page boundary and fault there though) */
1171 AssertMsgReturn(pDest == pvFault, ("eip=%VGv pDest=%VGv pvFault=%VGv\n", pRegFrame->eip, pDest, pvFault), VERR_EM_INTERPRETER);
1172#endif
1173#endif
1174 rc = emRamWrite(pVM, pDest, &val32, param2.size);
1175 if (VBOX_FAILURE(rc))
1176 return VERR_EM_INTERPRETER;
1177
1178 *pcbSize = param2.size;
1179 }
1180 else
1181 { /* read fault */
1182 RTGCPTR pSrc;
1183 uint32_t val32;
1184
1185 /* Source */
1186 switch(param2.type)
1187 {
1188 case PARMTYPE_IMMEDIATE:
1189 if(!(param2.flags & PARAM_VAL32))
1190 return VERR_EM_INTERPRETER;
1191 /* fallthru */
1192
1193 case PARMTYPE_ADDRESS:
1194 pSrc = (RTGCPTR)param2.val.val32;
1195 pSrc = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param2, pSrc);
1196 break;
1197
1198 default:
1199 return VERR_EM_INTERPRETER;
1200 }
1201
1202 Assert(param1.size <= 4 && param1.size > 0);
1203#ifdef IN_GC
1204 /* Safety check (in theory it could cross a page boundary and fault there though) */
1205 AssertReturn(pSrc == pvFault, VERR_EM_INTERPRETER);
1206#endif
1207 rc = emRamRead(pVM, &val32, pSrc, param1.size);
1208 if (VBOX_FAILURE(rc))
1209 return VERR_EM_INTERPRETER;
1210
1211 /* Destination */
1212 switch(param1.type)
1213 {
1214 case PARMTYPE_REGISTER:
1215 switch(param1.size)
1216 {
1217 case 1: rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen8, (uint8_t)val32); break;
1218 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen16, (uint16_t)val32); break;
1219 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen32, val32); break;
1220 default:
1221 return VERR_EM_INTERPRETER;
1222 }
1223 if (VBOX_FAILURE(rc))
1224 return rc;
1225 break;
1226
1227 default:
1228 return VERR_EM_INTERPRETER;
1229 }
1230 LogFlow(("EMInterpretInstruction: OP_MOV %08X -> %08X (%d)\n", pSrc, val32, param1.size));
1231 }
1232 return VINF_SUCCESS;
1233#ifdef IN_GC
1234 }
1235#endif
1236 return VERR_EM_INTERPRETER;
1237}
1238
1239/*
1240 * [LOCK] CMPXCHG emulation.
1241 */
1242#ifdef IN_GC
1243static int emInterpretCmpXchg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1244{
1245 OP_PARAMVAL param1, param2;
1246
1247 /* Source to make DISQueryParamVal read the register value - ugly hack */
1248 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1249 if(VBOX_FAILURE(rc))
1250 return VERR_EM_INTERPRETER;
1251
1252 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
1253 if(VBOX_FAILURE(rc))
1254 return VERR_EM_INTERPRETER;
1255
1256 if (TRPMHasTrap(pVM))
1257 {
1258 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1259 {
1260 RTGCPTR pParam1;
1261 uint32_t valpar, eflags;
1262#ifdef VBOX_STRICT
1263 uint32_t valpar1 = 0; /// @todo used uninitialized...
1264#endif
1265
1266 AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
1267 switch(param1.type)
1268 {
1269 case PARMTYPE_ADDRESS:
1270 pParam1 = (RTGCPTR)param1.val.val32;
1271 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
1272
1273 /* Safety check (in theory it could cross a page boundary and fault there though) */
1274 AssertMsgReturn(pParam1 == pvFault, ("eip=%VGv pParam1=%VGv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
1275 break;
1276
1277 default:
1278 return VERR_EM_INTERPRETER;
1279 }
1280
1281 switch(param2.type)
1282 {
1283 case PARMTYPE_IMMEDIATE: /* register actually */
1284 valpar = param2.val.val32;
1285 break;
1286
1287 default:
1288 return VERR_EM_INTERPRETER;
1289 }
1290
1291 LogFlow(("CmpXchg %VGv=%08x eax=%08x %08x\n", pParam1, valpar1, pRegFrame->eax, valpar));
1292
1293 MMGCRamRegisterTrapHandler(pVM);
1294 if (pCpu->prefix & PREFIX_LOCK)
1295 rc = EMGCEmulateLockCmpXchg(pParam1, &pRegFrame->eax, valpar, pCpu->param2.size, &eflags);
1296 else
1297 rc = EMGCEmulateCmpXchg(pParam1, &pRegFrame->eax, valpar, pCpu->param2.size, &eflags);
1298 MMGCRamDeregisterTrapHandler(pVM);
1299
1300 if (VBOX_FAILURE(rc))
1301 {
1302 Log(("CmpXchg %VGv=%08x eax=%08x %08x -> emulation failed due to page fault!\n", pParam1, valpar1, pRegFrame->eax, valpar));
1303 return VERR_EM_INTERPRETER;
1304 }
1305
1306 LogFlow(("CmpXchg %VGv=%08x eax=%08x %08x ZF=%d\n", pParam1, valpar1, pRegFrame->eax, valpar, !!(eflags & X86_EFL_ZF)));
1307
1308 /* Update guest's eflags and finish. */
1309 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1310 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1311
1312 *pcbSize = param2.size;
1313 return VINF_SUCCESS;
1314 }
1315 }
1316 return VERR_EM_INTERPRETER;
1317}
1318#endif
1319
1320/*
1321 * [LOCK] XADD emulation.
1322 */
1323#ifdef IN_GC
1324static int emInterpretXAdd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1325{
1326 OP_PARAMVAL param1;
1327 uint32_t *pParamReg2;
1328 size_t cbSizeParamReg2;
1329
1330 /* Source to make DISQueryParamVal read the register value - ugly hack */
1331 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1332 if(VBOX_FAILURE(rc))
1333 return VERR_EM_INTERPRETER;
1334
1335 rc = DISQueryParamRegPtr(pRegFrame, pCpu, &pCpu->param2, &pParamReg2, &cbSizeParamReg2);
1336 if(VBOX_FAILURE(rc))
1337 return VERR_EM_INTERPRETER;
1338
1339 if (TRPMHasTrap(pVM))
1340 {
1341 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1342 {
1343 RTGCPTR pParam1;
1344 uint32_t eflags;
1345#ifdef VBOX_STRICT
1346 uint32_t valpar1 = 0; /// @todo used uninitialized...
1347#endif
1348
1349 AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
1350 switch(param1.type)
1351 {
1352 case PARMTYPE_ADDRESS:
1353 pParam1 = (RTGCPTR)param1.val.val32;
1354 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
1355
1356 /* Safety check (in theory it could cross a page boundary and fault there though) */
1357 AssertMsgReturn(pParam1 == pvFault, ("eip=%VGv pParam1=%VGv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
1358 break;
1359
1360 default:
1361 return VERR_EM_INTERPRETER;
1362 }
1363
1364 LogFlow(("XAdd %VGv=%08x reg=%08x\n", pParam1, *pParamReg2));
1365
1366 MMGCRamRegisterTrapHandler(pVM);
1367 if (pCpu->prefix & PREFIX_LOCK)
1368 rc = EMGCEmulateLockXAdd(pParam1, pParamReg2, cbSizeParamReg2, &eflags);
1369 else
1370 rc = EMGCEmulateXAdd(pParam1, pParamReg2, cbSizeParamReg2, &eflags);
1371 MMGCRamDeregisterTrapHandler(pVM);
1372
1373 if (VBOX_FAILURE(rc))
1374 {
1375 Log(("XAdd %VGv=%08x reg=%08x -> emulation failed due to page fault!\n", pParam1, valpar1, *pParamReg2));
1376 return VERR_EM_INTERPRETER;
1377 }
1378
1379 LogFlow(("XAdd %VGv=%08x reg=%08x ZF=%d\n", pParam1, valpar1, *pParamReg2, !!(eflags & X86_EFL_ZF)));
1380
1381 /* Update guest's eflags and finish. */
1382 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1383 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1384
1385 *pcbSize = cbSizeParamReg2;
1386 return VINF_SUCCESS;
1387 }
1388 }
1389 return VERR_EM_INTERPRETER;
1390}
1391#endif
1392
1393/**
1394 * Interpret IRET (currently only to V86 code)
1395 *
1396 * @returns VBox status code.
1397 * @param pVM The VM handle.
1398 * @param pRegFrame The register frame.
1399 *
1400 */
1401EMDECL(int) EMInterpretIret(PVM pVM, PCPUMCTXCORE pRegFrame)
1402{
1403 RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp;
1404 RTGCUINTPTR eip, cs, esp, ss, eflags, ds, es, fs, gs, uMask;
1405 int rc;
1406
1407 rc = emRamRead(pVM, &eip, (RTGCPTR)pIretStack , 4);
1408 rc |= emRamRead(pVM, &cs, (RTGCPTR)(pIretStack + 4), 4);
1409 rc |= emRamRead(pVM, &eflags, (RTGCPTR)(pIretStack + 8), 4);
1410 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1411 AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER);
1412
1413 rc |= emRamRead(pVM, &esp, (RTGCPTR)(pIretStack + 12), 4);
1414 rc |= emRamRead(pVM, &ss, (RTGCPTR)(pIretStack + 16), 4);
1415 rc |= emRamRead(pVM, &es, (RTGCPTR)(pIretStack + 20), 4);
1416 rc |= emRamRead(pVM, &ds, (RTGCPTR)(pIretStack + 24), 4);
1417 rc |= emRamRead(pVM, &fs, (RTGCPTR)(pIretStack + 28), 4);
1418 rc |= emRamRead(pVM, &gs, (RTGCPTR)(pIretStack + 32), 4);
1419 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1420
1421 pRegFrame->eip = eip & 0xffff;
1422 pRegFrame->cs = cs;
1423
1424 /* Mask away all reserved bits */
1425 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;
1426 eflags &= uMask;
1427
1428#ifndef IN_RING0
1429 CPUMRawSetEFlags(pVM, pRegFrame, eflags);
1430#endif
1431 Assert((pRegFrame->eflags.u32 & (X86_EFL_IF|X86_EFL_IOPL)) == X86_EFL_IF);
1432
1433 pRegFrame->esp = esp;
1434 pRegFrame->ss = ss;
1435 pRegFrame->ds = ds;
1436 pRegFrame->es = es;
1437 pRegFrame->fs = fs;
1438 pRegFrame->gs = gs;
1439
1440 return VINF_SUCCESS;
1441}
1442
1443
1444/**
1445 * IRET Emulation.
1446 */
1447static int emInterpretIret(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1448{
1449 /* only allow direct calls to EMInterpretIret for now */
1450 return VERR_EM_INTERPRETER;
1451}
1452
1453/**
1454 * INVLPG Emulation.
1455 */
1456
1457/**
1458 * Interpret INVLPG
1459 *
1460 * @returns VBox status code.
1461 * @param pVM The VM handle.
1462 * @param pRegFrame The register frame.
1463 * @param pAddrGC Operand address
1464 *
1465 */
1466EMDECL(int) EMInterpretInvlpg(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC)
1467{
1468 int rc;
1469
1470 /** @todo is addr always a flat linear address or ds based
1471 * (in absence of segment override prefixes)????
1472 */
1473#ifdef IN_GC
1474 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1475 LogFlow(("GC: EMULATE: invlpg %08X\n", pAddrGC));
1476 rc = PGMGCInvalidatePage(pVM, pAddrGC);
1477#else
1478 rc = PGMInvalidatePage(pVM, pAddrGC);
1479#endif
1480 if (VBOX_SUCCESS(rc))
1481 return VINF_SUCCESS;
1482 Log(("PGMInvalidatePage %VGv returned %VGv (%d)\n", pAddrGC, rc, rc));
1483 Assert(rc == VERR_REM_FLUSHED_PAGES_OVERFLOW);
1484 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1485 return VERR_EM_INTERPRETER;
1486}
1487
1488static int emInterpretInvlPg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1489{
1490 OP_PARAMVAL param1;
1491 RTGCPTR addr;
1492
1493 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1494 if(VBOX_FAILURE(rc))
1495 return VERR_EM_INTERPRETER;
1496
1497 switch(param1.type)
1498 {
1499 case PARMTYPE_IMMEDIATE:
1500 case PARMTYPE_ADDRESS:
1501 if(!(param1.flags & PARAM_VAL32))
1502 return VERR_EM_INTERPRETER;
1503 addr = (RTGCPTR)param1.val.val32;
1504 break;
1505
1506 default:
1507 return VERR_EM_INTERPRETER;
1508 }
1509
1510 /** @todo is addr always a flat linear address or ds based
1511 * (in absence of segment override prefixes)????
1512 */
1513#ifdef IN_GC
1514 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1515 LogFlow(("GC: EMULATE: invlpg %08X\n", addr));
1516 rc = PGMGCInvalidatePage(pVM, addr);
1517#else
1518 rc = PGMInvalidatePage(pVM, addr);
1519#endif
1520 if (VBOX_SUCCESS(rc))
1521 return VINF_SUCCESS;
1522 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1523 return VERR_EM_INTERPRETER;
1524}
1525
1526/**
1527 * CPUID Emulation.
1528 */
1529
1530/**
1531 * Interpret CPUID given the parameters in the CPU context
1532 *
1533 * @returns VBox status code.
1534 * @param pVM The VM handle.
1535 * @param pRegFrame The register frame.
1536 *
1537 */
1538EMDECL(int) EMInterpretCpuId(PVM pVM, PCPUMCTXCORE pRegFrame)
1539{
1540 CPUMGetGuestCpuId(pVM, pRegFrame->eax, &pRegFrame->eax, &pRegFrame->ebx, &pRegFrame->ecx, &pRegFrame->edx);
1541 return VINF_SUCCESS;
1542}
1543
1544static int emInterpretCpuId(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1545{
1546 uint32_t iLeaf = pRegFrame->eax; NOREF(iLeaf);
1547
1548 int rc = EMInterpretCpuId(pVM, pRegFrame);
1549 Log(("Emulate: CPUID %x -> %08x %08x %08x %08x\n", iLeaf, pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx));
1550 return rc;
1551}
1552
1553/**
1554 * MOV CRx Emulation.
1555 */
1556
1557/**
1558 * Interpret CRx read
1559 *
1560 * @returns VBox status code.
1561 * @param pVM The VM handle.
1562 * @param pRegFrame The register frame.
1563 * @param DestRegGen General purpose register index (USE_REG_E**))
1564 * @param SrcRegCRx CRx register index (USE_REG_CR*)
1565 *
1566 */
1567EMDECL(int) EMInterpretCRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx)
1568{
1569 uint32_t val32;
1570
1571 int rc = CPUMGetGuestCRx(pVM, SrcRegCrx, &val32);
1572 AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER);
1573 rc = DISWriteReg32(pRegFrame, DestRegGen, val32);
1574 if(VBOX_SUCCESS(rc))
1575 {
1576 LogFlow(("MOV_CR: gen32=%d CR=%d val=%08x\n", DestRegGen, SrcRegCrx, val32));
1577 return VINF_SUCCESS;
1578 }
1579 return VERR_EM_INTERPRETER;
1580}
1581
1582
1583/**
1584 * Interpret LMSW
1585 *
1586 * @returns VBox status code.
1587 * @param pVM The VM handle.
1588 * @param u16Data LMSW source data.
1589 *
1590 */
1591EMDECL(int) EMInterpretLMSW(PVM pVM, uint16_t u16Data)
1592{
1593 uint32_t OldCr0 = CPUMGetGuestCR0(pVM);
1594
1595 /* don't use this path to go into protected mode! */
1596 Assert(OldCr0 & X86_CR0_PE);
1597 if (!(OldCr0 & X86_CR0_PE))
1598 return VERR_EM_INTERPRETER;
1599
1600 /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */
1601 uint32_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
1602 | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS));
1603
1604#ifdef IN_GC
1605 /* Need to change the hyper CR0? Doing it the lazy way then. */
1606 if ( (OldCr0 & (X86_CR0_AM | X86_CR0_WP))
1607 != (NewCr0 & (X86_CR0_AM | X86_CR0_WP)))
1608 {
1609 Log(("EMInterpretLMSW: CR0: %#x->%#x => R3\n", OldCr0, NewCr0));
1610 VM_FF_SET(pVM, VM_FF_TO_R3);
1611 }
1612#endif
1613
1614 return CPUMSetGuestCR0(pVM, NewCr0);
1615}
1616
1617
1618/**
1619 * Interpret CLTS
1620 *
1621 * @returns VBox status code.
1622 * @param pVM The VM handle.
1623 *
1624 */
1625EMDECL(int) EMInterpretCLTS(PVM pVM)
1626{
1627 uint32_t cr0 = CPUMGetGuestCR0(pVM);
1628 if (!(cr0 & X86_CR0_TS))
1629 return VINF_SUCCESS;
1630 return CPUMSetGuestCR0(pVM, cr0 & ~X86_CR0_TS);
1631}
1632
1633static int emInterpretClts(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1634{
1635 return EMInterpretCLTS(pVM);
1636}
1637
1638/**
1639 * Interpret CRx write
1640 *
1641 * @returns VBox status code.
1642 * @param pVM The VM handle.
1643 * @param pRegFrame The register frame.
1644 * @param DestRegCRx CRx register index (USE_REG_CR*)
1645 * @param SrcRegGen General purpose register index (USE_REG_E**))
1646 *
1647 */
1648EMDECL(int) EMInterpretCRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)
1649{
1650 uint32_t val32;
1651 uint32_t oldval;
1652/** @todo Clean up this mess. */
1653
1654 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1655 if (VBOX_SUCCESS(rc))
1656 {
1657 switch (DestRegCrx)
1658 {
1659 case USE_REG_CR0:
1660 oldval = CPUMGetGuestCR0(pVM);
1661#ifdef IN_GC
1662 /* CR0.WP and CR0.AM changes require a reschedule run in ring 3. */
1663 if ( (val32 & (X86_CR0_WP | X86_CR0_AM))
1664 != (oldval & (X86_CR0_WP | X86_CR0_AM)))
1665 return VERR_EM_INTERPRETER;
1666#endif
1667 CPUMSetGuestCR0(pVM, val32);
1668 val32 = CPUMGetGuestCR0(pVM);
1669 if ( (oldval & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
1670 != (val32 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))
1671 {
1672 /* global flush */
1673 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1674 AssertRCReturn(rc, rc);
1675 }
1676 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), CPUMGetGuestEFER(pVM));
1677
1678 case USE_REG_CR2:
1679 rc = CPUMSetGuestCR2(pVM, val32); AssertRC(rc);
1680 return VINF_SUCCESS;
1681
1682 case USE_REG_CR3:
1683 /* Reloading the current CR3 means the guest just wants to flush the TLBs */
1684 rc = CPUMSetGuestCR3(pVM, val32); AssertRC(rc);
1685 if (CPUMGetGuestCR0(pVM) & X86_CR0_PG)
1686 {
1687 /* flush */
1688 rc = PGMFlushTLB(pVM, val32, !(CPUMGetGuestCR4(pVM) & X86_CR4_PGE));
1689 AssertRCReturn(rc, rc);
1690 }
1691 return VINF_SUCCESS;
1692
1693 case USE_REG_CR4:
1694 oldval = CPUMGetGuestCR4(pVM);
1695#ifndef IN_RING3
1696 /** @todo is flipping of the X86_CR4_PAE bit handled correctly here? */
1697#endif
1698 rc = CPUMSetGuestCR4(pVM, val32); AssertRC(rc);
1699 val32 = CPUMGetGuestCR4(pVM);
1700 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))
1701 != (val32 & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)))
1702 {
1703 /* global flush */
1704 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1705 AssertRCReturn(rc, rc);
1706 }
1707# ifdef IN_GC
1708 /* Feeling extremely lazy. */
1709 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))
1710 != (val32 & (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)))
1711 {
1712 Log(("emInterpretMovCRx: CR4: %#x->%#x => R3\n", oldval, val32));
1713 VM_FF_SET(pVM, VM_FF_TO_R3);
1714 }
1715# endif
1716 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), CPUMGetGuestEFER(pVM));
1717
1718 default:
1719 AssertFailed();
1720 case USE_REG_CR1: /* illegal op */
1721 break;
1722 }
1723 }
1724 return VERR_EM_INTERPRETER;
1725}
1726
1727static int emInterpretMovCRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1728{
1729 if (pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_CR)
1730 return EMInterpretCRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_ctrl);
1731 if (pCpu->param1.flags == USE_REG_CR && pCpu->param2.flags == USE_REG_GEN32)
1732 return EMInterpretCRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_ctrl, pCpu->param2.base.reg_gen32);
1733 AssertMsgFailedReturn(("Unexpected control register move\n"), VERR_EM_INTERPRETER);
1734 return VERR_EM_INTERPRETER;
1735}
1736
1737/**
1738 * MOV DRx
1739 */
1740
1741/**
1742 * Interpret DRx write
1743 *
1744 * @returns VBox status code.
1745 * @param pVM The VM handle.
1746 * @param pRegFrame The register frame.
1747 * @param DestRegDRx DRx register index (USE_REG_DR*)
1748 * @param SrcRegGen General purpose register index (USE_REG_E**))
1749 *
1750 */
1751EMDECL(int) EMInterpretDRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)
1752{
1753 uint32_t val32;
1754
1755 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1756 if (VBOX_SUCCESS(rc))
1757 {
1758 rc = CPUMSetGuestDRx(pVM, DestRegDrx, val32);
1759 if (VBOX_SUCCESS(rc))
1760 return rc;
1761 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx));
1762 }
1763 return VERR_EM_INTERPRETER;
1764}
1765
1766/**
1767 * Interpret DRx read
1768 *
1769 * @returns VBox status code.
1770 * @param pVM The VM handle.
1771 * @param pRegFrame The register frame.
1772 * @param DestRegGen General purpose register index (USE_REG_E**))
1773 * @param SrcRegDRx DRx register index (USE_REG_DR*)
1774 *
1775 */
1776EMDECL(int) EMInterpretDRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)
1777{
1778 uint32_t val32;
1779
1780 int rc = CPUMGetGuestDRx(pVM, SrcRegDrx, &val32);
1781 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER);
1782 rc = DISWriteReg32(pRegFrame, DestRegGen, val32);
1783 if (VBOX_SUCCESS(rc))
1784 return VINF_SUCCESS;
1785 return VERR_EM_INTERPRETER;
1786}
1787
1788static int emInterpretMovDRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1789{
1790 int rc = VERR_EM_INTERPRETER;
1791
1792 if(pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_DBG)
1793 {
1794 rc = EMInterpretDRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_dbg);
1795 }
1796 else
1797 if(pCpu->param1.flags == USE_REG_DBG && pCpu->param2.flags == USE_REG_GEN32)
1798 {
1799 rc = EMInterpretDRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_dbg, pCpu->param2.base.reg_gen32);
1800 }
1801 else
1802 AssertMsgFailed(("Unexpected debug register move\n"));
1803 return rc;
1804}
1805
1806/**
1807 * LLDT Emulation.
1808 */
1809static int emInterpretLLdt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1810{
1811 OP_PARAMVAL param1;
1812 RTSEL sel;
1813
1814 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1815 if(VBOX_FAILURE(rc))
1816 return VERR_EM_INTERPRETER;
1817
1818 switch(param1.type)
1819 {
1820 case PARMTYPE_ADDRESS:
1821 return VERR_EM_INTERPRETER; //feeling lazy right now
1822
1823 case PARMTYPE_IMMEDIATE:
1824 if(!(param1.flags & PARAM_VAL16))
1825 return VERR_EM_INTERPRETER;
1826 sel = (RTSEL)param1.val.val16;
1827 break;
1828
1829 default:
1830 return VERR_EM_INTERPRETER;
1831 }
1832
1833 if (sel == 0)
1834 {
1835 if (CPUMGetHyperLDTR(pVM) == 0)
1836 {
1837 // this simple case is most frequent in Windows 2000 (31k - boot & shutdown)
1838 return VINF_SUCCESS;
1839 }
1840 }
1841 //still feeling lazy
1842 return VERR_EM_INTERPRETER;
1843}
1844
1845#ifdef IN_GC
1846/**
1847 * STI Emulation.
1848 *
1849 * @remark the instruction following sti is guaranteed to be executed before any interrupts are dispatched
1850 */
1851static int emInterpretSti(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1852{
1853 PPATMGCSTATE pGCState = PATMQueryGCState(pVM);
1854
1855 if(!pGCState)
1856 {
1857 Assert(pGCState);
1858 return VERR_EM_INTERPRETER;
1859 }
1860 pGCState->uVMFlags |= X86_EFL_IF;
1861
1862 Assert(pRegFrame->eflags.u32 & X86_EFL_IF);
1863 Assert(pvFault == SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip));
1864
1865 pVM->em.s.GCPtrInhibitInterrupts = pRegFrame->eip + pCpu->opsize;
1866 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
1867
1868 return VINF_SUCCESS;
1869}
1870#endif /* IN_GC */
1871
1872
1873/**
1874 * HLT Emulation.
1875 */
1876static int emInterpretHlt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1877{
1878 return VINF_EM_HALT;
1879}
1880
1881
1882/**
1883 * RDTSC Emulation.
1884 */
1885
1886/**
1887 * Interpret RDTSC
1888 *
1889 * @returns VBox status code.
1890 * @param pVM The VM handle.
1891 * @param pRegFrame The register frame.
1892 *
1893 */
1894EMDECL(int) EMInterpretRdtsc(PVM pVM, PCPUMCTXCORE pRegFrame)
1895{
1896 unsigned uCR4 = CPUMGetGuestCR4(pVM);
1897
1898 if (uCR4 & X86_CR4_TSD)
1899 return VERR_EM_INTERPRETER; /* genuine #GP */
1900
1901 uint64_t uTicks = TMCpuTickGet(pVM);
1902
1903 pRegFrame->eax = uTicks;
1904 pRegFrame->edx = (uTicks >> 32ULL);
1905
1906 return VINF_SUCCESS;
1907}
1908
1909static int emInterpretRdtsc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1910{
1911 return EMInterpretRdtsc(pVM, pRegFrame);
1912}
1913
1914/**
1915 * MONITOR Emulation.
1916 */
1917static int emInterpretMonitor(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1918{
1919 uint32_t u32Dummy, u32ExtFeatures, cpl;
1920
1921 if (pRegFrame->ecx != 0)
1922 return VERR_EM_INTERPRETER; /* illegal value. */
1923
1924 /* Get the current privilege level. */
1925 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
1926 if (cpl != 0)
1927 return VERR_EM_INTERPRETER; /* supervisor only */
1928
1929 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
1930 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
1931 return VERR_EM_INTERPRETER; /* not supported */
1932
1933 return VINF_SUCCESS;
1934}
1935
1936
1937/**
1938 * MWAIT Emulation.
1939 */
1940static int emInterpretMWait(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1941{
1942 uint32_t u32Dummy, u32ExtFeatures, cpl;
1943
1944 if (pRegFrame->ecx != 0)
1945 return VERR_EM_INTERPRETER; /* illegal value. */
1946
1947 /* Get the current privilege level. */
1948 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
1949 if (cpl != 0)
1950 return VERR_EM_INTERPRETER; /* supervisor only */
1951
1952 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
1953 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
1954 return VERR_EM_INTERPRETER; /* not supported */
1955
1956 /** @todo not completely correct */
1957 return VINF_EM_HALT;
1958}
1959
1960
1961/**
1962 * Internal worker.
1963 * @copydoc EMInterpretInstructionCPU
1964 */
1965DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1966{
1967 Assert(pcbSize);
1968 *pcbSize = 0;
1969
1970 /*
1971 * Only supervisor guest code!!
1972 * And no complicated prefixes.
1973 */
1974 /* Get the current privilege level. */
1975 uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
1976 if ( cpl != 0
1977 && pCpu->pCurInstr->opcode != OP_RDTSC) /* rdtsc requires emulation in ring 3 as well */
1978 {
1979 Log(("WARNING: refusing instruction emulation for user-mode code!!\n"));
1980 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedUserMode));
1981 return VERR_EM_INTERPRETER;
1982 }
1983
1984#ifdef IN_GC
1985 if ( (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP))
1986 || ( (pCpu->prefix & PREFIX_LOCK)
1987 && pCpu->pCurInstr->opcode != OP_CMPXCHG
1988 && pCpu->pCurInstr->opcode != OP_XADD
1989 && pCpu->pCurInstr->opcode != OP_OR
1990 && pCpu->pCurInstr->opcode != OP_BTR
1991 )
1992 )
1993#else
1994 if (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_LOCK))
1995#endif
1996 {
1997 //Log(("EMInterpretInstruction: wrong prefix!!\n"));
1998 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedPrefix));
1999 return VERR_EM_INTERPRETER;
2000 }
2001
2002 int rc;
2003 switch (pCpu->pCurInstr->opcode)
2004 {
2005#ifdef IN_GC
2006# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
2007 case opcode:\
2008 if (pCpu->prefix & PREFIX_LOCK) \
2009 rc = emInterpretLock##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulateLock); \
2010 else \
2011 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulate); \
2012 if (VBOX_SUCCESS(rc)) \
2013 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
2014 else \
2015 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
2016 return rc
2017#else
2018# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
2019 INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate)
2020#endif
2021#define INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate) \
2022 case opcode:\
2023 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulate); \
2024 if (VBOX_SUCCESS(rc)) \
2025 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
2026 else \
2027 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
2028 return rc
2029
2030#define INTERPRET_CASE_EX_PARAM2(opcode, Instr, InstrFn, pfnEmulate) \
2031 INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate)
2032#define INTERPRET_CASE_EX_LOCK_PARAM2(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
2033 INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock)
2034
2035#define INTERPRET_CASE(opcode, Instr) \
2036 case opcode:\
2037 rc = emInterpret##Instr(pVM, pCpu, pRegFrame, pvFault, pcbSize); \
2038 if (VBOX_SUCCESS(rc)) \
2039 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
2040 else \
2041 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
2042 return rc
2043#define INTERPRET_STAT_CASE(opcode, Instr) \
2044 case opcode: STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); return VERR_EM_INTERPRETER;
2045
2046 INTERPRET_CASE(OP_XCHG,Xchg);
2047 INTERPRET_CASE_EX_PARAM2(OP_DEC,Dec, IncDec, EMEmulateDec);
2048 INTERPRET_CASE_EX_PARAM2(OP_INC,Inc, IncDec, EMEmulateInc);
2049 INTERPRET_CASE(OP_POP,Pop);
2050 INTERPRET_CASE_EX_LOCK_PARAM3(OP_OR, Or, OrXorAnd, EMEmulateOr, EMEmulateLockOr);
2051 INTERPRET_CASE_EX_PARAM3(OP_XOR,Xor, OrXorAnd, EMEmulateXor);
2052 INTERPRET_CASE_EX_PARAM3(OP_AND,And, OrXorAnd, EMEmulateAnd);
2053 INTERPRET_CASE(OP_MOV,Mov);
2054 INTERPRET_CASE(OP_INVLPG,InvlPg);
2055 INTERPRET_CASE(OP_CPUID,CpuId);
2056 INTERPRET_CASE(OP_MOV_CR,MovCRx);
2057 INTERPRET_CASE(OP_MOV_DR,MovDRx);
2058 INTERPRET_CASE(OP_LLDT,LLdt);
2059 INTERPRET_CASE(OP_CLTS,Clts);
2060 INTERPRET_CASE(OP_MONITOR, Monitor);
2061 INTERPRET_CASE(OP_MWAIT, MWait);
2062 INTERPRET_CASE_EX_PARAM3(OP_ADD,Add, AddSub, EMEmulateAdd);
2063 INTERPRET_CASE_EX_PARAM3(OP_SUB,Sub, AddSub, EMEmulateSub);
2064 INTERPRET_CASE(OP_ADC,Adc);
2065 INTERPRET_CASE_EX_LOCK_PARAM2(OP_BTR,Btr, BitTest, EMEmulateBtr, EMEmulateLockBtr);
2066 INTERPRET_CASE_EX_PARAM2(OP_BTS,Bts, BitTest, EMEmulateBts);
2067 INTERPRET_CASE_EX_PARAM2(OP_BTC,Btc, BitTest, EMEmulateBtc);
2068 INTERPRET_CASE(OP_RDTSC,Rdtsc);
2069#ifdef IN_GC
2070 INTERPRET_CASE(OP_STI,Sti);
2071 INTERPRET_CASE(OP_CMPXCHG, CmpXchg);
2072 INTERPRET_CASE(OP_XADD, XAdd);
2073#endif
2074 INTERPRET_CASE(OP_HLT,Hlt);
2075 INTERPRET_CASE(OP_IRET,Iret);
2076#ifdef VBOX_WITH_STATISTICS
2077#ifndef IN_GC
2078 INTERPRET_STAT_CASE(OP_CMPXCHG,CmpXchg);
2079 INTERPRET_STAT_CASE(OP_XADD, XAdd);
2080#endif
2081 INTERPRET_STAT_CASE(OP_MOVNTPS,MovNTPS);
2082 INTERPRET_STAT_CASE(OP_STOSWD,StosWD);
2083 INTERPRET_STAT_CASE(OP_WBINVD,WbInvd);
2084#endif
2085 default:
2086 Log3(("emInterpretInstructionCPU: opcode=%d\n", pCpu->pCurInstr->opcode));
2087 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedMisc));
2088 return VERR_EM_INTERPRETER;
2089#undef INTERPRET_CASE_EX_PARAM2
2090#undef INTERPRET_STAT_CASE
2091#undef INTERPRET_CASE_EX
2092#undef INTERPRET_CASE
2093 }
2094 AssertFailed();
2095 return VERR_INTERNAL_ERROR;
2096}
2097
2098
2099/**
2100 * Sets the PC for which interrupts should be inhibited.
2101 *
2102 * @param pVM The VM handle.
2103 * @param PC The PC.
2104 */
2105EMDECL(void) EMSetInhibitInterruptsPC(PVM pVM, RTGCUINTPTR PC)
2106{
2107 pVM->em.s.GCPtrInhibitInterrupts = PC;
2108 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
2109}
2110
2111
2112/**
2113 * Gets the PC for which interrupts should be inhibited.
2114 *
2115 * There are a few instructions which inhibits or delays interrupts
2116 * for the instruction following them. These instructions are:
2117 * - STI
2118 * - MOV SS, r/m16
2119 * - POP SS
2120 *
2121 * @returns The PC for which interrupts should be inhibited.
2122 * @param pVM VM handle.
2123 *
2124 */
2125EMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVM pVM)
2126{
2127 return pVM->em.s.GCPtrInhibitInterrupts;
2128}
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