VirtualBox

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

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

Moved rdtsc emulation into EM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 61.9 KB
Line 
1/* $Id: EMAll.cpp 468 2007-01-31 15:20:06Z 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->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->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->cs, &pRegFrame->csHid))
195 {
196 RTGCPTR pbCode;
197 int rc = SELMValidateAndConvertCSAddr(pVM, 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->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->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#ifdef IN_GC
564 /* Safety check (in theory it could cross a page boundary and fault there though) */
565 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
566#endif
567 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
568 if (VBOX_FAILURE(rc))
569 {
570 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
571 return VERR_EM_INTERPRETER;
572 }
573
574 /* Update ESP as the last step */
575 pRegFrame->esp += param1.size;
576 }
577 else
578 {
579#ifndef DEBUG_bird // annoying assertion.
580 AssertFailed();
581#endif
582 return VERR_EM_INTERPRETER;
583 }
584
585 /* All done! */
586 *pcbSize = param1.size;
587 return VINF_SUCCESS;
588#ifdef IN_GC
589 }
590 }
591#endif
592 return VERR_EM_INTERPRETER;
593}
594
595/**
596 * OR Emulation.
597 */
598static int emInterpretOr(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
599{
600 OP_PARAMVAL param1, param2;
601 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
602 if(VBOX_FAILURE(rc))
603 return VERR_EM_INTERPRETER;
604
605 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
606 if(VBOX_FAILURE(rc))
607 return VERR_EM_INTERPRETER;
608
609#ifdef IN_GC
610 if (TRPMHasTrap(pVM))
611 {
612 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
613 {
614#endif
615 RTGCPTR pParam1;
616 uint32_t valpar1, valpar2;
617
618 if (pCpu->param1.size != pCpu->param2.size)
619 {
620 if (pCpu->param1.size < pCpu->param2.size)
621 {
622 AssertMsgFailed(("Or at %VGv parameter mismatch %d vs %d!!\n", pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
623 return VERR_EM_INTERPRETER;
624 }
625 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
626 pCpu->param2.size = pCpu->param1.size;
627 param2.size = param1.size;
628 }
629
630 /* The destination is always a virtual address */
631 if (param1.type == PARMTYPE_ADDRESS)
632 {
633 pParam1 = (RTGCPTR)param1.val.val32;
634
635#ifdef IN_GC
636 /* Safety check (in theory it could cross a page boundary and fault there though) */
637 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
638#endif
639 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
640 if (VBOX_FAILURE(rc))
641 {
642 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
643 return VERR_EM_INTERPRETER;
644 }
645 }
646 else
647 {
648 AssertFailed();
649 return VERR_EM_INTERPRETER;
650 }
651
652 /* Register or immediate data */
653 switch(param2.type)
654 {
655 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
656 valpar2 = param2.val.val32;
657 break;
658
659 default:
660 AssertFailed();
661 return VERR_EM_INTERPRETER;
662 }
663
664 /* Data read, emulate OR. */
665 uint32_t eflags = EMEmulateOr(&valpar1, valpar2, param2.size);
666
667 /* Update guest's eflags and finish. */
668 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
669 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
670
671 /* And write it back */
672 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
673 if (VBOX_SUCCESS(rc))
674 {
675 /* All done! */
676 *pcbSize = param2.size;
677 return VINF_SUCCESS;
678 }
679#ifdef IN_GC
680 }
681 }
682#endif
683 return VERR_EM_INTERPRETER;
684}
685
686/**
687 * XOR Emulation.
688 */
689static int emInterpretXor(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
690{
691 OP_PARAMVAL param1, param2;
692 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
693 if(VBOX_FAILURE(rc))
694 return VERR_EM_INTERPRETER;
695
696 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
697 if(VBOX_FAILURE(rc))
698 return VERR_EM_INTERPRETER;
699
700#ifdef IN_GC
701 if (TRPMHasTrap(pVM))
702 {
703 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
704 {
705#endif
706 RTGCPTR pParam1;
707 uint32_t valpar1, valpar2;
708
709 if (pCpu->param1.size != pCpu->param2.size)
710 {
711 if (pCpu->param1.size < pCpu->param2.size)
712 {
713 AssertMsgFailed(("Xor at %VGv parameter mismatch %d vs %d!!\n", pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
714 return VERR_EM_INTERPRETER;
715 }
716 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
717 pCpu->param2.size = pCpu->param1.size;
718 param2.size = param1.size;
719 }
720
721 /* The destination is always a virtual address */
722 if (param1.type == PARMTYPE_ADDRESS)
723 {
724 pParam1 = (RTGCPTR)param1.val.val32;
725
726#ifdef IN_GC
727 /* Safety check (in theory it could cross a page boundary and fault there though) */
728 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
729#endif
730 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
731 if (VBOX_FAILURE(rc))
732 {
733 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
734 return VERR_EM_INTERPRETER;
735 }
736 }
737 else
738 {
739 AssertFailed();
740 return VERR_EM_INTERPRETER;
741 }
742
743 /* Register or immediate data */
744 switch(param2.type)
745 {
746 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
747 valpar2 = param2.val.val32;
748 break;
749
750 default:
751 AssertFailed();
752 return VERR_EM_INTERPRETER;
753 }
754
755 /* Data read, emulate XOR. */
756 uint32_t eflags = EMEmulateXor(&valpar1, valpar2, param2.size);
757
758 /* Update guest's eflags and finish. */
759 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
760 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
761
762 /* And write it back */
763 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
764 if (VBOX_SUCCESS(rc))
765 {
766 /* All done! */
767 *pcbSize = param2.size;
768 return VINF_SUCCESS;
769 }
770#ifdef IN_GC
771 }
772 }
773#endif
774 return VERR_EM_INTERPRETER;
775}
776
777/**
778 * AND Emulation.
779 */
780static int emInterpretAnd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
781{
782 OP_PARAMVAL param1, param2;
783 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
784 if(VBOX_FAILURE(rc))
785 return VERR_EM_INTERPRETER;
786
787 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
788 if(VBOX_FAILURE(rc))
789 return VERR_EM_INTERPRETER;
790
791#ifdef IN_GC
792 if (TRPMHasTrap(pVM))
793 {
794 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
795 {
796#endif
797 RTGCPTR pParam1;
798 uint32_t valpar1, valpar2;
799
800 if (pCpu->param1.size != pCpu->param2.size)
801 {
802 if (pCpu->param1.size < pCpu->param2.size)
803 {
804 AssertMsgFailed(("And at %VGv parameter mismatch %d vs %d!!\n", pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
805 return VERR_EM_INTERPRETER;
806 }
807 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
808 pCpu->param2.size = pCpu->param1.size;
809 param2.size = param1.size;
810 }
811
812 /* The destination is always a virtual address */
813 if (param1.type == PARMTYPE_ADDRESS)
814 {
815 pParam1 = (RTGCPTR)param1.val.val32;
816
817#ifdef IN_GC
818 /* Safety check (in theory it could cross a page boundary and fault there though) */
819 AssertMsgReturn(pParam1 == pvFault, ("pParam1 = %VGv pvFault = %VGv\n", pParam1, pvFault), VERR_EM_INTERPRETER);
820#endif
821 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
822 if (VBOX_FAILURE(rc))
823 {
824 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
825 return VERR_EM_INTERPRETER;
826 }
827 }
828 else
829 {
830#ifndef DEBUG_bird
831 AssertFailed();
832#endif
833 return VERR_EM_INTERPRETER;
834 }
835
836 /* Register or immediate data */
837 switch(param2.type)
838 {
839 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
840 valpar2 = param2.val.val32;
841 break;
842
843 default:
844 AssertFailed();
845 return VERR_EM_INTERPRETER;
846 }
847
848 /* Data read, emulate AND. */
849 uint32_t eflags = EMEmulateAnd(&valpar1, valpar2, param2.size);
850
851 /* Update guest's eflags and finish. */
852 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
853 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
854
855 /* And write it back */
856 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
857 if (VBOX_SUCCESS(rc))
858 {
859 /* All done! */
860 *pcbSize = param2.size;
861 return VINF_SUCCESS;
862 }
863#ifdef IN_GC
864 }
865 }
866#endif
867 return VERR_EM_INTERPRETER;
868}
869
870/**
871 * ADD Emulation.
872 */
873static int emInterpretAdd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
874{
875 OP_PARAMVAL param1, param2;
876 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
877 if(VBOX_FAILURE(rc))
878 return VERR_EM_INTERPRETER;
879
880 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
881 if(VBOX_FAILURE(rc))
882 return VERR_EM_INTERPRETER;
883
884#ifdef IN_GC
885 if (TRPMHasTrap(pVM))
886 {
887 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
888 {
889#endif
890 RTGCPTR pParam1;
891 uint32_t valpar1, valpar2;
892
893 if (pCpu->param1.size != pCpu->param2.size)
894 {
895 if (pCpu->param1.size < pCpu->param2.size)
896 {
897 AssertMsgFailed(("Add at %VGv parameter mismatch %d vs %d!!\n", pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
898 return VERR_EM_INTERPRETER;
899 }
900 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
901 pCpu->param2.size = pCpu->param1.size;
902 param2.size = param1.size;
903 }
904
905 /* The destination is always a virtual address */
906 if (param1.type == PARMTYPE_ADDRESS)
907 {
908 pParam1 = (RTGCPTR)param1.val.val32;
909
910#ifdef IN_GC
911 /* Safety check (in theory it could cross a page boundary and fault there though) */
912 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
913#endif
914 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
915 if (VBOX_FAILURE(rc))
916 {
917 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
918 return VERR_EM_INTERPRETER;
919 }
920 }
921 else
922 {
923#ifndef DEBUG_bird
924 AssertFailed();
925#endif
926 return VERR_EM_INTERPRETER;
927 }
928
929 /* Register or immediate data */
930 switch(param2.type)
931 {
932 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
933 valpar2 = param2.val.val32;
934 break;
935
936 default:
937 AssertFailed();
938 return VERR_EM_INTERPRETER;
939 }
940
941 /* Data read, emulate ADD. */
942 uint32_t eflags = EMEmulateAdd(&valpar1, valpar2, param2.size);
943
944 /* Update guest's eflags and finish. */
945 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
946 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
947
948 /* And write it back */
949 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
950 if (VBOX_SUCCESS(rc))
951 {
952 /* All done! */
953 *pcbSize = param2.size;
954 return VINF_SUCCESS;
955 }
956#ifdef IN_GC
957 }
958 }
959#endif
960 return VERR_EM_INTERPRETER;
961}
962
963/**
964 * ADC Emulation.
965 * @todo combine with add
966 */
967static int emInterpretAdc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
968{
969 OP_PARAMVAL param1, param2;
970 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
971 if(VBOX_FAILURE(rc))
972 return VERR_EM_INTERPRETER;
973
974 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
975 if(VBOX_FAILURE(rc))
976 return VERR_EM_INTERPRETER;
977
978#ifdef IN_GC
979 if (TRPMHasTrap(pVM))
980 {
981 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
982 {
983#endif
984 RTGCPTR pParam1;
985 uint32_t valpar1, valpar2;
986
987 if (pCpu->param1.size != pCpu->param2.size)
988 {
989 if (pCpu->param1.size < pCpu->param2.size)
990 {
991 AssertMsgFailed(("Adc at %VGv parameter mismatch %d vs %d!!\n", pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
992 return VERR_EM_INTERPRETER;
993 }
994 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
995 pCpu->param2.size = pCpu->param1.size;
996 param2.size = param1.size;
997 }
998
999 /* The destination is always a virtual address */
1000 if (param1.type == PARMTYPE_ADDRESS)
1001 {
1002 pParam1 = (RTGCPTR)param1.val.val32;
1003
1004#ifdef IN_GC
1005 /* Safety check (in theory it could cross a page boundary and fault there though) */
1006 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
1007#endif
1008 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
1009 if (VBOX_FAILURE(rc))
1010 {
1011 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
1012 return VERR_EM_INTERPRETER;
1013 }
1014 }
1015 else
1016 {
1017#ifndef DEBUG_bird
1018 AssertFailed();
1019#endif
1020 return VERR_EM_INTERPRETER;
1021 }
1022
1023 /* Register or immediate data */
1024 switch(param2.type)
1025 {
1026 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
1027 valpar2 = param2.val.val32;
1028 break;
1029
1030 default:
1031 AssertFailed();
1032 return VERR_EM_INTERPRETER;
1033 }
1034
1035 /* Data read, emulate ADC. */
1036 uint32_t eflags;
1037
1038 if (pRegFrame->eflags.u32 & X86_EFL_CF)
1039 eflags = EMEmulateAdcWithCarrySet(&valpar1, valpar2, param2.size);
1040 else
1041 eflags = EMEmulateAdd(&valpar1, valpar2, param2.size);
1042
1043 /* Update guest's eflags and finish. */
1044 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1045 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1046
1047 /* And write it back */
1048 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
1049 if (VBOX_SUCCESS(rc))
1050 {
1051 /* All done! */
1052 *pcbSize = param2.size;
1053 return VINF_SUCCESS;
1054 }
1055#ifdef IN_GC
1056 }
1057 }
1058#endif
1059 return VERR_EM_INTERPRETER;
1060}
1061
1062/**
1063 * SUB Emulation.
1064 */
1065static int emInterpretSub(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1066{
1067 OP_PARAMVAL param1, param2;
1068 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
1069 if(VBOX_FAILURE(rc))
1070 return VERR_EM_INTERPRETER;
1071
1072 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
1073 if(VBOX_FAILURE(rc))
1074 return VERR_EM_INTERPRETER;
1075
1076#ifdef IN_GC
1077 if (TRPMHasTrap(pVM))
1078 {
1079 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1080 {
1081#endif
1082 RTGCPTR pParam1;
1083 uint32_t valpar1, valpar2;
1084
1085 if (pCpu->param1.size != pCpu->param2.size)
1086 {
1087 if (pCpu->param1.size < pCpu->param2.size)
1088 {
1089 AssertMsgFailed(("Sub at %VGv parameter mismatch %d vs %d!!\n", pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
1090 return VERR_EM_INTERPRETER;
1091 }
1092 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
1093 pCpu->param2.size = pCpu->param1.size;
1094 param2.size = param1.size;
1095 }
1096
1097 /* The destination is always a virtual address */
1098 if (param1.type == PARMTYPE_ADDRESS)
1099 {
1100 pParam1 = (RTGCPTR)param1.val.val32;
1101
1102#ifdef IN_GC
1103 /* Safety check (in theory it could cross a page boundary and fault there though) */
1104 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
1105#endif
1106 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
1107 if (VBOX_FAILURE(rc))
1108 {
1109 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
1110 return VERR_EM_INTERPRETER;
1111 }
1112 }
1113 else
1114 {
1115#ifndef DEBUG_bird
1116 AssertFailed();
1117#endif
1118 return VERR_EM_INTERPRETER;
1119 }
1120
1121 /* Register or immediate data */
1122 switch(param2.type)
1123 {
1124 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
1125 valpar2 = param2.val.val32;
1126 break;
1127
1128 default:
1129 AssertFailed();
1130 return VERR_EM_INTERPRETER;
1131 }
1132
1133 /* Data read, emulate SUB. */
1134 uint32_t eflags = EMEmulateSub(&valpar1, valpar2, param2.size);
1135
1136 /* Update guest's eflags and finish. */
1137 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1138 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1139
1140 /* And write it back */
1141 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
1142 if (VBOX_SUCCESS(rc))
1143 {
1144 /* All done! */
1145 *pcbSize = param2.size;
1146 return VINF_SUCCESS;
1147 }
1148#ifdef IN_GC
1149 }
1150 }
1151#endif
1152 return VERR_EM_INTERPRETER;
1153}
1154
1155/**
1156 * MOV emulation.
1157 */
1158static int emInterpretMov(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1159{
1160 OP_PARAMVAL param1, param2;
1161 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
1162 if(VBOX_FAILURE(rc))
1163 return VERR_EM_INTERPRETER;
1164
1165 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
1166 if(VBOX_FAILURE(rc))
1167 return VERR_EM_INTERPRETER;
1168
1169#ifdef IN_GC
1170 if (TRPMHasTrap(pVM))
1171 {
1172 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1173 {
1174#else
1175 /** @todo Make this the default and don't rely on TRPM information. */
1176 if (param1.type == PARMTYPE_ADDRESS)
1177 {
1178#endif
1179 RTGCPTR pDest;
1180 uint32_t val32;
1181
1182 switch(param1.type)
1183 {
1184 case PARMTYPE_IMMEDIATE:
1185 if(!(param1.flags & PARAM_VAL32))
1186 return VERR_EM_INTERPRETER;
1187 /* fallthru */
1188
1189 case PARMTYPE_ADDRESS:
1190 pDest = (RTGCPTR)param1.val.val32;
1191 break;
1192
1193 default:
1194 AssertFailed();
1195 return VERR_EM_INTERPRETER;
1196 }
1197
1198 switch(param2.type)
1199 {
1200 case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
1201 val32 = param2.val.val32;
1202 break;
1203
1204 default:
1205 Log(("emInterpretMov: unexpected type=%d eip=%VGv\n", param2.type, pRegFrame->eip));
1206 return VERR_EM_INTERPRETER;
1207 }
1208 LogFlow(("EMInterpretInstruction at %08x: OP_MOV %08X <- %08X (%d) &val32=%08x\n", pRegFrame->eip, pDest, val32, param2.size, &val32));
1209
1210 Assert(param2.size <= 4 && param2.size > 0);
1211
1212 rc = emRamWrite(pVM, pDest, &val32, param2.size);
1213 if (VBOX_FAILURE(rc))
1214 return VERR_EM_INTERPRETER;
1215
1216 *pcbSize = param2.size;
1217 }
1218 else
1219 { /* read fault */
1220 RTGCPTR pSrc;
1221 uint32_t val32;
1222
1223 /* Source */
1224 switch(param2.type)
1225 {
1226 case PARMTYPE_IMMEDIATE:
1227 if(!(param2.flags & PARAM_VAL32))
1228 return VERR_EM_INTERPRETER;
1229 /* fallthru */
1230
1231 case PARMTYPE_ADDRESS:
1232 pSrc = (RTGCPTR)param2.val.val32;
1233 break;
1234
1235 default:
1236 return VERR_EM_INTERPRETER;
1237 }
1238
1239 Assert(param1.size <= 4 && param1.size > 0);
1240 rc = emRamRead(pVM, &val32, pSrc, param1.size);
1241 if (VBOX_FAILURE(rc))
1242 return VERR_EM_INTERPRETER;
1243
1244 /* Destination */
1245 switch(param1.type)
1246 {
1247 case PARMTYPE_REGISTER:
1248 switch(param1.size)
1249 {
1250 case 1: rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen8, (uint8_t)val32); break;
1251 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen16, (uint16_t)val32); break;
1252 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen32, val32); break;
1253 default:
1254 return VERR_EM_INTERPRETER;
1255 }
1256 if (VBOX_FAILURE(rc))
1257 return rc;
1258 break;
1259
1260 default:
1261 return VERR_EM_INTERPRETER;
1262 }
1263 LogFlow(("EMInterpretInstruction: OP_MOV %08X -> %08X (%d)\n", pSrc, val32, param1.size));
1264 }
1265 return VINF_SUCCESS;
1266#ifdef IN_GC
1267 }
1268#endif
1269 return VERR_EM_INTERPRETER;
1270}
1271
1272
1273/**
1274 * INVLPG Emulation.
1275 */
1276
1277/**
1278 * Interpret INVLPG
1279 *
1280 * @returns VBox status code.
1281 * @param pVM The VM handle.
1282 * @param pRegFrame The register frame.
1283 * @param pAddrGC Operand address
1284 *
1285 */
1286EMDECL(int) EMInterpretInvlpg(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC)
1287{
1288 int rc;
1289
1290 /** @todo is addr always a flat linear address or ds based
1291 * (in absence of segment override prefixes)????
1292 */
1293#ifdef IN_GC
1294 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1295 LogFlow(("GC: EMULATE: invlpg %08X\n", pAddrGC));
1296 rc = PGMGCInvalidatePage(pVM, pAddrGC);
1297#else
1298 rc = PGMInvalidatePage(pVM, pAddrGC);
1299#endif
1300 if (VBOX_SUCCESS(rc))
1301 return VINF_SUCCESS;
1302 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1303 return VERR_EM_INTERPRETER;
1304}
1305
1306static int emInterpretInvlPg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1307{
1308 OP_PARAMVAL param1;
1309 RTGCPTR addr;
1310
1311 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1312 if(VBOX_FAILURE(rc))
1313 return VERR_EM_INTERPRETER;
1314
1315 switch(param1.type)
1316 {
1317 case PARMTYPE_IMMEDIATE:
1318 case PARMTYPE_ADDRESS:
1319 if(!(param1.flags & PARAM_VAL32))
1320 return VERR_EM_INTERPRETER;
1321 addr = (RTGCPTR)param1.val.val32;
1322 break;
1323
1324 default:
1325 return VERR_EM_INTERPRETER;
1326 }
1327
1328 /** @todo is addr always a flat linear address or ds based
1329 * (in absence of segment override prefixes)????
1330 */
1331#ifdef IN_GC
1332 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1333 LogFlow(("GC: EMULATE: invlpg %08X\n", addr));
1334 rc = PGMGCInvalidatePage(pVM, addr);
1335#else
1336 rc = PGMInvalidatePage(pVM, addr);
1337#endif
1338 if (VBOX_SUCCESS(rc))
1339 return VINF_SUCCESS;
1340 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1341 return VERR_EM_INTERPRETER;
1342}
1343
1344/**
1345 * CPUID Emulation.
1346 */
1347
1348/**
1349 * Interpret CPUID given the parameters in the CPU context
1350 *
1351 * @returns VBox status code.
1352 * @param pVM The VM handle.
1353 * @param pRegFrame The register frame.
1354 *
1355 */
1356EMDECL(int) EMInterpretCpuId(PVM pVM, PCPUMCTXCORE pRegFrame)
1357{
1358 CPUMGetGuestCpuId(pVM, pRegFrame->eax, &pRegFrame->eax, &pRegFrame->ebx, &pRegFrame->ecx, &pRegFrame->edx);
1359 return VINF_SUCCESS;
1360}
1361
1362static int emInterpretCpuId(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1363{
1364 uint32_t iLeaf = pRegFrame->eax; NOREF(iLeaf);
1365
1366 int rc = EMInterpretCpuId(pVM, pRegFrame);
1367 Log(("Emulate: CPUID %x -> %08x %08x %08x %08x\n", iLeaf, pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx));
1368 return rc;
1369}
1370
1371/**
1372 * MOV CRx Emulation.
1373 */
1374
1375/**
1376 * Interpret CRx read
1377 *
1378 * @returns VBox status code.
1379 * @param pVM The VM handle.
1380 * @param pRegFrame The register frame.
1381 * @param DestRegGen General purpose register index (USE_REG_E**))
1382 * @param SrcRegCRx CRx register index (USE_REG_CR*)
1383 *
1384 */
1385EMDECL(int) EMInterpretCRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx)
1386{
1387 uint32_t val32;
1388
1389 int rc = CPUMGetGuestCRx(pVM, SrcRegCrx, &val32);
1390 AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER);
1391 rc = DISWriteReg32(pRegFrame, DestRegGen, val32);
1392 if(VBOX_SUCCESS(rc))
1393 {
1394 LogFlow(("MOV_CR: gen32=%d CR=%d val=%08x\n", DestRegGen, SrcRegCrx, val32));
1395 return VINF_SUCCESS;
1396 }
1397 return VERR_EM_INTERPRETER;
1398}
1399
1400
1401/**
1402 * Interpret LMSW
1403 *
1404 * @returns VBox status code.
1405 * @param pVM The VM handle.
1406 * @param u16Data LMSW source data.
1407 *
1408 */
1409EMDECL(int) EMInterpretLMSW(PVM pVM, uint16_t u16Data)
1410{
1411 uint32_t OldCr0 = CPUMGetGuestCR0(pVM);
1412
1413 /* don't use this path to go into protected mode! */
1414 Assert(OldCr0 & X86_CR0_PE);
1415 if (!(OldCr0 & X86_CR0_PE))
1416 return VERR_EM_INTERPRETER;
1417
1418 /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */
1419 uint32_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
1420 | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS));
1421
1422#ifdef IN_GC
1423 /* Need to change the hyper CR0? Doing it the lazy way then. */
1424 if ( (OldCr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | X86_CR0_AM | X86_CR0_WP))
1425 != (NewCr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | X86_CR0_AM | X86_CR0_WP)))
1426 {
1427 Log(("EMInterpretLMSW: CR0: %#x->%#x => R3\n", OldCr0, NewCr0));
1428 VM_FF_SET(pVM, VM_FF_TO_R3);
1429 }
1430#endif
1431
1432 return CPUMSetGuestCR0(pVM, NewCr0);
1433}
1434
1435
1436/**
1437 * Interpret CLTS
1438 *
1439 * @returns VBox status code.
1440 * @param pVM The VM handle.
1441 *
1442 */
1443EMDECL(int) EMInterpretCLTS(PVM pVM)
1444{
1445 uint32_t Cr0 = CPUMGetGuestCR0(pVM);
1446 if (!(Cr0 & X86_CR0_TS))
1447 return VINF_SUCCESS;
1448
1449#ifdef IN_GC
1450 /* Need to change the hyper CR0? Doing it the lazy way then. */
1451 Log(("EMInterpretCLTS: CR0: %#x->%#x => R3\n", Cr0, Cr0 & ~X86_CR0_TS));
1452 VM_FF_SET(pVM, VM_FF_TO_R3);
1453#endif
1454 return CPUMSetGuestCR0(pVM, Cr0 & ~X86_CR0_TS);
1455}
1456
1457
1458/**
1459 * Interpret CRx write
1460 *
1461 * @returns VBox status code.
1462 * @param pVM The VM handle.
1463 * @param pRegFrame The register frame.
1464 * @param DestRegCRx CRx register index (USE_REG_CR*)
1465 * @param SrcRegGen General purpose register index (USE_REG_E**))
1466 *
1467 */
1468EMDECL(int) EMInterpretCRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)
1469{
1470 uint32_t val32;
1471 uint32_t oldval;
1472/** @todo Clean up this mess. */
1473
1474 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1475 if (VBOX_SUCCESS(rc))
1476 {
1477 switch (DestRegCrx)
1478 {
1479 case USE_REG_CR0:
1480 oldval = CPUMGetGuestCR0(pVM);
1481#ifndef IN_RING3
1482 /* CR0.WP changes require a reschedule run in ring 3. */
1483 if ((val32 & X86_CR0_WP) != (oldval & X86_CR0_WP))
1484 return VERR_EM_INTERPRETER;
1485#endif
1486 rc = CPUMSetGuestCR0(pVM, val32); AssertRC(rc); /** @todo CPUSetGuestCR0 stuff should be void, this is silly. */
1487 val32 = CPUMGetGuestCR0(pVM);
1488 if ( (oldval & (X86_CR0_PG|X86_CR0_WP|X86_CR0_PE))
1489 != (val32 & (X86_CR0_PG|X86_CR0_WP|X86_CR0_PE)))
1490 {
1491 /* global flush */
1492 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1493 AssertRCReturn(rc, rc);
1494 }
1495# ifdef IN_GC
1496 /* Feeling extremely lazy. */
1497 if ( (oldval & (X86_CR0_TS|X86_CR0_EM|X86_CR0_MP|X86_CR0_AM))
1498 != (val32 & (X86_CR0_TS|X86_CR0_EM|X86_CR0_MP|X86_CR0_AM)))
1499 {
1500 Log(("emInterpretMovCRx: CR0: %#x->%#x => R3\n", oldval, val32));
1501 VM_FF_SET(pVM, VM_FF_TO_R3);
1502 }
1503# endif
1504 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), 0);
1505
1506 case USE_REG_CR2:
1507 rc = CPUMSetGuestCR2(pVM, val32); AssertRC(rc);
1508 return VINF_SUCCESS;
1509
1510 case USE_REG_CR3:
1511 /* Reloading the current CR3 means the guest just wants to flush the TLBs */
1512 rc = CPUMSetGuestCR3(pVM, val32); AssertRC(rc);
1513 if (CPUMGetGuestCR0(pVM) & X86_CR0_PG)
1514 {
1515 /* flush */
1516 rc = PGMFlushTLB(pVM, val32, !(CPUMGetGuestCR4(pVM) & X86_CR4_PGE));
1517 AssertRCReturn(rc, rc);
1518 }
1519 return VINF_SUCCESS;
1520
1521 case USE_REG_CR4:
1522 oldval = CPUMGetGuestCR4(pVM);
1523#ifndef IN_RING3
1524 /** @todo is flipping of the X86_CR4_PAE bit handled correctly here? */
1525#endif
1526 rc = CPUMSetGuestCR4(pVM, val32); AssertRC(rc);
1527 val32 = CPUMGetGuestCR4(pVM);
1528 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))
1529 != (val32 & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)))
1530 {
1531 /* global flush */
1532 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1533 AssertRCReturn(rc, rc);
1534 }
1535# ifndef IN_RING3 /** @todo check this out IN_RING0! */
1536 /* Feeling extremely lazy. */
1537 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))
1538 != (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)))
1539 {
1540 Log(("emInterpretMovCRx: CR4: %#x->%#x => R3\n", oldval, val32));
1541 VM_FF_SET(pVM, VM_FF_TO_R3);
1542 }
1543# endif
1544 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), 0);
1545
1546 default:
1547 AssertFailed();
1548 case USE_REG_CR1: /* illegal op */
1549 break;
1550 }
1551 }
1552 return VERR_EM_INTERPRETER;
1553}
1554
1555static int emInterpretMovCRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1556{
1557 if (pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_CR)
1558 return EMInterpretCRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_ctrl);
1559 if (pCpu->param1.flags == USE_REG_CR && pCpu->param2.flags == USE_REG_GEN32)
1560 return EMInterpretCRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_ctrl, pCpu->param2.base.reg_gen32);
1561 AssertMsgFailedReturn(("Unexpected control register move\n"), VERR_EM_INTERPRETER);
1562 return VERR_EM_INTERPRETER;
1563}
1564
1565/**
1566 * MOV DRx
1567 */
1568
1569/**
1570 * Interpret DRx write
1571 *
1572 * @returns VBox status code.
1573 * @param pVM The VM handle.
1574 * @param pRegFrame The register frame.
1575 * @param DestRegDRx DRx register index (USE_REG_DR*)
1576 * @param SrcRegGen General purpose register index (USE_REG_E**))
1577 *
1578 */
1579EMDECL(int) EMInterpretDRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)
1580{
1581 uint32_t val32;
1582
1583 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1584 if (VBOX_SUCCESS(rc))
1585 {
1586 rc = CPUMSetGuestDRx(pVM, DestRegDrx, val32);
1587 if (VBOX_SUCCESS(rc))
1588 return rc;
1589 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx));
1590 }
1591 return VERR_EM_INTERPRETER;
1592}
1593
1594/**
1595 * Interpret DRx read
1596 *
1597 * @returns VBox status code.
1598 * @param pVM The VM handle.
1599 * @param pRegFrame The register frame.
1600 * @param DestRegGen General purpose register index (USE_REG_E**))
1601 * @param SrcRegDRx DRx register index (USE_REG_DR*)
1602 *
1603 */
1604EMDECL(int) EMInterpretDRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)
1605{
1606 uint32_t val32;
1607
1608 int rc = CPUMGetGuestDRx(pVM, SrcRegDrx, &val32);
1609 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER);
1610 rc = DISWriteReg32(pRegFrame, DestRegGen, val32);
1611 if (VBOX_SUCCESS(rc))
1612 return VINF_SUCCESS;
1613 return VERR_EM_INTERPRETER;
1614}
1615
1616static int emInterpretMovDRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1617{
1618 int rc = VERR_EM_INTERPRETER;
1619
1620 if(pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_DBG)
1621 {
1622 rc = EMInterpretDRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_dbg);
1623 }
1624 else
1625 if(pCpu->param1.flags == USE_REG_DBG && pCpu->param2.flags == USE_REG_GEN32)
1626 {
1627 rc = EMInterpretDRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_dbg, pCpu->param2.base.reg_gen32);
1628 }
1629 else
1630 AssertMsgFailed(("Unexpected debug register move\n"));
1631 return rc;
1632}
1633
1634/**
1635 * LLDT Emulation.
1636 */
1637static int emInterpretLLdt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1638{
1639 OP_PARAMVAL param1;
1640 RTSEL sel;
1641
1642 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1643 if(VBOX_FAILURE(rc))
1644 return VERR_EM_INTERPRETER;
1645
1646 switch(param1.type)
1647 {
1648 case PARMTYPE_ADDRESS:
1649 return VERR_EM_INTERPRETER; //feeling lazy right now
1650
1651 case PARMTYPE_IMMEDIATE:
1652 if(!(param1.flags & PARAM_VAL16))
1653 return VERR_EM_INTERPRETER;
1654 sel = (RTSEL)param1.val.val16;
1655 break;
1656
1657 default:
1658 return VERR_EM_INTERPRETER;
1659 }
1660
1661 if (sel == 0)
1662 {
1663 if (CPUMGetHyperLDTR(pVM) == 0)
1664 {
1665 // this simple case is most frequent in Windows 2000 (31k - boot & shutdown)
1666 return VINF_SUCCESS;
1667 }
1668 }
1669 //still feeling lazy
1670 return VERR_EM_INTERPRETER;
1671}
1672
1673#ifdef IN_GC
1674/**
1675 * STI Emulation.
1676 *
1677 * @remark the instruction following sti is guaranteed to be executed before any interrupts are dispatched
1678 */
1679static int emInterpretSti(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1680{
1681 PPATMGCSTATE pGCState = PATMQueryGCState(pVM);
1682
1683 if(!pGCState)
1684 {
1685 Assert(pGCState);
1686 return VERR_EM_INTERPRETER;
1687 }
1688 pGCState->uVMFlags |= X86_EFL_IF;
1689
1690 Assert(pRegFrame->eflags.u32 & X86_EFL_IF);
1691 Assert(pvFault == (RTGCPTR)pRegFrame->eip);
1692
1693 pVM->em.s.GCPtrInhibitInterrupts = pRegFrame->eip + pCpu->opsize;
1694 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
1695
1696 return VINF_SUCCESS;
1697}
1698#endif /* IN_GC */
1699
1700
1701/**
1702 * HLT Emulation.
1703 */
1704static int emInterpretHlt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1705{
1706 return VINF_EM_HALT;
1707}
1708
1709
1710/**
1711 * IRET Emulation.
1712 */
1713static int emInterpretIret(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1714{
1715 return VERR_EM_INTERPRETER;
1716}
1717
1718#ifdef IN_GC
1719/**
1720 * RDTSC Emulation.
1721 */
1722static int emInterpretRdtsc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1723{
1724 unsigned uCR4 = CPUMGetGuestCR4(pVM);
1725
1726 if (uCR4 & X86_CR4_TSD)
1727 return VERR_EM_INTERPRETER; /* genuine #GP */
1728
1729 uint64_t uTicks = TMCpuTickGet(pVM);
1730
1731 pRegFrame->eax = uTicks;
1732 pRegFrame->edx = (uTicks >> 32ULL);
1733
1734 return VINF_SUCCESS;
1735}
1736#endif
1737
1738/**
1739 * MONITOR Emulation.
1740 */
1741static int emInterpretMonitor(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1742{
1743 if (pRegFrame->ecx != 0)
1744 return VERR_EM_INTERPRETER; /* illegal value. */
1745
1746#ifdef IN_GC
1747 if ((pRegFrame->ss & X86_SEL_RPL) != 1)
1748#else
1749 if ((pRegFrame->ss & X86_SEL_RPL) != 0)
1750#endif
1751 return VERR_EM_INTERPRETER; /* supervisor only */
1752
1753 return VINF_SUCCESS;
1754}
1755
1756
1757/**
1758 * MWAIT Emulation.
1759 */
1760static int emInterpretMWait(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1761{
1762 if (pRegFrame->ecx != 0)
1763 return VERR_EM_INTERPRETER; /* illegal value. */
1764
1765#ifdef IN_GC
1766 if ((pRegFrame->ss & X86_SEL_RPL) != 1)
1767#else
1768 if ((pRegFrame->ss & X86_SEL_RPL) != 0)
1769#endif
1770 return VERR_EM_INTERPRETER; /* supervisor only */
1771
1772 /** @todo not completely correct */
1773 return VINF_EM_HALT;
1774}
1775
1776
1777/**
1778 * Internal worker.
1779 * @copydoc EMInterpretInstructionCPU
1780 */
1781DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1782{
1783 Assert(pcbSize);
1784 *pcbSize = 0;
1785
1786 /*
1787 * Only supervisor guest code!!
1788 * And no complicated prefixes.
1789 */
1790#ifdef IN_GC
1791 if ((pRegFrame->ss & X86_SEL_RPL) != 1)
1792#else
1793 if ((pRegFrame->ss & X86_SEL_RPL) != 0)
1794#endif
1795 {
1796 Log(("WARNING: refusing instruction emulation for user-mode code!!\n"));
1797 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedUserMode));
1798 return VERR_EM_INTERPRETER;
1799 }
1800
1801 /* In HWACCM mode we can execute 16 bits code. Our emulation above can't cope with that yet. */
1802 /** @note if not in HWACCM mode, then we will never execute 16 bits code, so don't bother checking. */
1803 if (HWACCMIsEnabled(pVM) && !SELMIsSelector32Bit(pVM, pRegFrame->cs, &pRegFrame->csHid))
1804 return VERR_EM_INTERPRETER;
1805
1806 /** @note we could ignore PREFIX_LOCK here. Need to take special precautions when/if we support SMP in the guest.
1807 */
1808 if (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_SEG | PREFIX_LOCK))
1809 {
1810 //Log(("EMInterpretInstruction: wrong prefix!!\n"));
1811 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedPrefix));
1812 return VERR_EM_INTERPRETER;
1813 }
1814
1815 int rc;
1816 switch (pCpu->pCurInstr->opcode)
1817 {
1818#define INTERPRET_CASE_EX(opcode,Instr,InstrFn) \
1819 case opcode:\
1820 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize); \
1821 if (VBOX_SUCCESS(rc)) \
1822 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
1823 else \
1824 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
1825 return rc
1826#define INTERPRET_CASE(opcode,Instr) INTERPRET_CASE_EX(opcode,Instr,Instr)
1827#define INTERPRET_STAT_CASE(opcode,Instr) \
1828 case opcode: STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); return VERR_EM_INTERPRETER;
1829
1830 INTERPRET_CASE(OP_XCHG,Xchg);
1831 INTERPRET_CASE_EX(OP_DEC,Dec,IncDec);
1832 INTERPRET_CASE_EX(OP_INC,Inc,IncDec);
1833 INTERPRET_CASE(OP_POP,Pop);
1834 INTERPRET_CASE(OP_OR,Or);
1835 INTERPRET_CASE(OP_XOR,Xor);
1836 INTERPRET_CASE(OP_MOV,Mov);
1837 INTERPRET_CASE(OP_AND,And);
1838 INTERPRET_CASE(OP_INVLPG,InvlPg);
1839 INTERPRET_CASE(OP_CPUID,CpuId);
1840 INTERPRET_CASE(OP_MOV_CR,MovCRx);
1841 INTERPRET_CASE(OP_MOV_DR,MovDRx);
1842 INTERPRET_CASE(OP_LLDT,LLdt);
1843 INTERPRET_CASE(OP_MONITOR, Monitor);
1844 INTERPRET_CASE(OP_MWAIT, MWait);
1845 INTERPRET_CASE(OP_ADD,Add);
1846 INTERPRET_CASE(OP_ADC,Adc);
1847 INTERPRET_CASE(OP_SUB,Sub);
1848#ifdef IN_GC
1849 INTERPRET_CASE(OP_RDTSC,Rdtsc);
1850 INTERPRET_CASE(OP_STI,Sti);
1851#endif
1852 INTERPRET_CASE(OP_HLT,Hlt);
1853 INTERPRET_CASE(OP_IRET,Iret);
1854#ifdef VBOX_WITH_STATISTICS
1855 INTERPRET_STAT_CASE(OP_BTR,Btr);
1856 INTERPRET_STAT_CASE(OP_BTS,Bts);
1857 INTERPRET_STAT_CASE(OP_CMPXCHG,CmpXchg);
1858 INTERPRET_STAT_CASE(OP_MOVNTPS,MovNTPS);
1859 INTERPRET_STAT_CASE(OP_STOSWD,StosWD);
1860 INTERPRET_STAT_CASE(OP_WBINVD,WbInvd);
1861#endif
1862 default:
1863 Log3(("emInterpretInstructionCPU: opcode=%d\n", pCpu->pCurInstr->opcode));
1864 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedMisc));
1865 return VERR_EM_INTERPRETER;
1866#undef INTERPRET_STAT_CASE
1867#undef INTERPRET_CASE
1868 }
1869 AssertFailed();
1870 return VERR_INTERNAL_ERROR;
1871}
1872
1873
1874/**
1875 * Sets the PC for which interrupts should be inhibited.
1876 *
1877 * @param pVM The VM handle.
1878 * @param PC The PC.
1879 */
1880EMDECL(void) EMSetInhibitInterruptsPC(PVM pVM, RTGCUINTPTR PC)
1881{
1882 pVM->em.s.GCPtrInhibitInterrupts = PC;
1883 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
1884}
1885
1886
1887/**
1888 * Gets the PC for which interrupts should be inhibited.
1889 *
1890 * There are a few instructions which inhibits or delays interrupts
1891 * for the instruction following them. These instructions are:
1892 * - STI
1893 * - MOV SS, r/m16
1894 * - POP SS
1895 *
1896 * @returns The PC for which interrupts should be inhibited.
1897 * @param pVM VM handle.
1898 *
1899 */
1900EMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVM pVM)
1901{
1902 return pVM->em.s.GCPtrInhibitInterrupts;
1903}
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