VirtualBox

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

Last change on this file since 2018 was 2017, checked in by vboxsync, 18 years ago

more verbose assertion

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