VirtualBox

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

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

small logging fixes

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