VirtualBox

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

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

pop [esp+xx] uses esp *after* the actual pop

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