VirtualBox

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

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

Corrected flag handling in V86 iret.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 63.9 KB
Line 
1/* $Id: EMAll.cpp 1322 2007-03-08 10:52:22Z 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 * Interpret IRET (currently only to V86 code)
1275 *
1276 * @returns VBox status code.
1277 * @param pVM The VM handle.
1278 * @param pRegFrame The register frame.
1279 *
1280 */
1281EMDECL(int) EMInterpretIret(PVM pVM, PCPUMCTXCORE pRegFrame)
1282{
1283 RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp;
1284 RTGCUINTPTR eip, cs, esp, ss, eflags, ds, es, fs, gs, uMask;
1285 int rc;
1286
1287 rc = emRamRead(pVM, &eip, (RTGCPTR)pIretStack , 4);
1288 rc |= emRamRead(pVM, &cs, (RTGCPTR)(pIretStack + 4), 4);
1289 rc |= emRamRead(pVM, &eflags, (RTGCPTR)(pIretStack + 8), 4);
1290 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1291 AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER);
1292
1293 rc |= emRamRead(pVM, &esp, (RTGCPTR)(pIretStack + 12), 4);
1294 rc |= emRamRead(pVM, &ss, (RTGCPTR)(pIretStack + 16), 4);
1295 rc |= emRamRead(pVM, &es, (RTGCPTR)(pIretStack + 20), 4);
1296 rc |= emRamRead(pVM, &ds, (RTGCPTR)(pIretStack + 24), 4);
1297 rc |= emRamRead(pVM, &fs, (RTGCPTR)(pIretStack + 28), 4);
1298 rc |= emRamRead(pVM, &gs, (RTGCPTR)(pIretStack + 32), 4);
1299 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1300
1301 pRegFrame->eip = eip & 0xffff;
1302 pRegFrame->cs = cs;
1303
1304 /* Mask away all reserved bits */
1305 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;
1306 eflags &= uMask;
1307
1308#ifndef IN_RING0
1309 CPUMRawSetEFlags(pVM, pRegFrame, eflags);
1310#endif
1311 Assert((pRegFrame->eflags.u32 & (X86_EFL_IF|X86_EFL_IOPL)) == X86_EFL_IF);
1312
1313 pRegFrame->esp = esp;
1314 pRegFrame->ss = ss;
1315 pRegFrame->ds = ds;
1316 pRegFrame->es = es;
1317 pRegFrame->fs = fs;
1318 pRegFrame->gs = gs;
1319
1320 return VINF_SUCCESS;
1321}
1322
1323
1324/**
1325 * IRET Emulation.
1326 */
1327static int emInterpretIret(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1328{
1329 /* only allow direct calls to EMInterpretIret for now */
1330 return VERR_EM_INTERPRETER;
1331}
1332
1333/**
1334 * INVLPG Emulation.
1335 */
1336
1337/**
1338 * Interpret INVLPG
1339 *
1340 * @returns VBox status code.
1341 * @param pVM The VM handle.
1342 * @param pRegFrame The register frame.
1343 * @param pAddrGC Operand address
1344 *
1345 */
1346EMDECL(int) EMInterpretInvlpg(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC)
1347{
1348 int rc;
1349
1350 /** @todo is addr always a flat linear address or ds based
1351 * (in absence of segment override prefixes)????
1352 */
1353#ifdef IN_GC
1354 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1355 LogFlow(("GC: EMULATE: invlpg %08X\n", pAddrGC));
1356 rc = PGMGCInvalidatePage(pVM, pAddrGC);
1357#else
1358 rc = PGMInvalidatePage(pVM, pAddrGC);
1359#endif
1360 if (VBOX_SUCCESS(rc))
1361 return VINF_SUCCESS;
1362 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1363 return VERR_EM_INTERPRETER;
1364}
1365
1366static int emInterpretInvlPg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1367{
1368 OP_PARAMVAL param1;
1369 RTGCPTR addr;
1370
1371 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1372 if(VBOX_FAILURE(rc))
1373 return VERR_EM_INTERPRETER;
1374
1375 switch(param1.type)
1376 {
1377 case PARMTYPE_IMMEDIATE:
1378 case PARMTYPE_ADDRESS:
1379 if(!(param1.flags & PARAM_VAL32))
1380 return VERR_EM_INTERPRETER;
1381 addr = (RTGCPTR)param1.val.val32;
1382 break;
1383
1384 default:
1385 return VERR_EM_INTERPRETER;
1386 }
1387
1388 /** @todo is addr always a flat linear address or ds based
1389 * (in absence of segment override prefixes)????
1390 */
1391#ifdef IN_GC
1392 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1393 LogFlow(("GC: EMULATE: invlpg %08X\n", addr));
1394 rc = PGMGCInvalidatePage(pVM, addr);
1395#else
1396 rc = PGMInvalidatePage(pVM, addr);
1397#endif
1398 if (VBOX_SUCCESS(rc))
1399 return VINF_SUCCESS;
1400 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1401 return VERR_EM_INTERPRETER;
1402}
1403
1404/**
1405 * CPUID Emulation.
1406 */
1407
1408/**
1409 * Interpret CPUID given the parameters in the CPU context
1410 *
1411 * @returns VBox status code.
1412 * @param pVM The VM handle.
1413 * @param pRegFrame The register frame.
1414 *
1415 */
1416EMDECL(int) EMInterpretCpuId(PVM pVM, PCPUMCTXCORE pRegFrame)
1417{
1418 CPUMGetGuestCpuId(pVM, pRegFrame->eax, &pRegFrame->eax, &pRegFrame->ebx, &pRegFrame->ecx, &pRegFrame->edx);
1419 return VINF_SUCCESS;
1420}
1421
1422static int emInterpretCpuId(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1423{
1424 uint32_t iLeaf = pRegFrame->eax; NOREF(iLeaf);
1425
1426 int rc = EMInterpretCpuId(pVM, pRegFrame);
1427 Log(("Emulate: CPUID %x -> %08x %08x %08x %08x\n", iLeaf, pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx));
1428 return rc;
1429}
1430
1431/**
1432 * MOV CRx Emulation.
1433 */
1434
1435/**
1436 * Interpret CRx read
1437 *
1438 * @returns VBox status code.
1439 * @param pVM The VM handle.
1440 * @param pRegFrame The register frame.
1441 * @param DestRegGen General purpose register index (USE_REG_E**))
1442 * @param SrcRegCRx CRx register index (USE_REG_CR*)
1443 *
1444 */
1445EMDECL(int) EMInterpretCRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx)
1446{
1447 uint32_t val32;
1448
1449 int rc = CPUMGetGuestCRx(pVM, SrcRegCrx, &val32);
1450 AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER);
1451 rc = DISWriteReg32(pRegFrame, DestRegGen, val32);
1452 if(VBOX_SUCCESS(rc))
1453 {
1454 LogFlow(("MOV_CR: gen32=%d CR=%d val=%08x\n", DestRegGen, SrcRegCrx, val32));
1455 return VINF_SUCCESS;
1456 }
1457 return VERR_EM_INTERPRETER;
1458}
1459
1460
1461/**
1462 * Interpret LMSW
1463 *
1464 * @returns VBox status code.
1465 * @param pVM The VM handle.
1466 * @param u16Data LMSW source data.
1467 *
1468 */
1469EMDECL(int) EMInterpretLMSW(PVM pVM, uint16_t u16Data)
1470{
1471 uint32_t OldCr0 = CPUMGetGuestCR0(pVM);
1472
1473 /* don't use this path to go into protected mode! */
1474 Assert(OldCr0 & X86_CR0_PE);
1475 if (!(OldCr0 & X86_CR0_PE))
1476 return VERR_EM_INTERPRETER;
1477
1478 /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */
1479 uint32_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
1480 | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS));
1481
1482#ifdef IN_GC
1483 /* Need to change the hyper CR0? Doing it the lazy way then. */
1484 if ( (OldCr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | X86_CR0_AM | X86_CR0_WP))
1485 != (NewCr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | X86_CR0_AM | X86_CR0_WP)))
1486 {
1487 Log(("EMInterpretLMSW: CR0: %#x->%#x => R3\n", OldCr0, NewCr0));
1488 VM_FF_SET(pVM, VM_FF_TO_R3);
1489 }
1490#endif
1491
1492 return CPUMSetGuestCR0(pVM, NewCr0);
1493}
1494
1495
1496/**
1497 * Interpret CLTS
1498 *
1499 * @returns VBox status code.
1500 * @param pVM The VM handle.
1501 *
1502 */
1503EMDECL(int) EMInterpretCLTS(PVM pVM)
1504{
1505 uint32_t Cr0 = CPUMGetGuestCR0(pVM);
1506 if (!(Cr0 & X86_CR0_TS))
1507 return VINF_SUCCESS;
1508
1509#ifdef IN_GC
1510 /* Need to change the hyper CR0? Doing it the lazy way then. */
1511 Log(("EMInterpretCLTS: CR0: %#x->%#x => R3\n", Cr0, Cr0 & ~X86_CR0_TS));
1512 VM_FF_SET(pVM, VM_FF_TO_R3);
1513#endif
1514 return CPUMSetGuestCR0(pVM, Cr0 & ~X86_CR0_TS);
1515}
1516
1517
1518/**
1519 * Interpret CRx write
1520 *
1521 * @returns VBox status code.
1522 * @param pVM The VM handle.
1523 * @param pRegFrame The register frame.
1524 * @param DestRegCRx CRx register index (USE_REG_CR*)
1525 * @param SrcRegGen General purpose register index (USE_REG_E**))
1526 *
1527 */
1528EMDECL(int) EMInterpretCRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)
1529{
1530 uint32_t val32;
1531 uint32_t oldval;
1532/** @todo Clean up this mess. */
1533
1534 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1535 if (VBOX_SUCCESS(rc))
1536 {
1537 switch (DestRegCrx)
1538 {
1539 case USE_REG_CR0:
1540 oldval = CPUMGetGuestCR0(pVM);
1541#ifndef IN_RING3
1542 /* CR0.WP changes require a reschedule run in ring 3. */
1543 if ((val32 & X86_CR0_WP) != (oldval & X86_CR0_WP))
1544 return VERR_EM_INTERPRETER;
1545#endif
1546 rc = CPUMSetGuestCR0(pVM, val32); AssertRC(rc); /** @todo CPUSetGuestCR0 stuff should be void, this is silly. */
1547 val32 = CPUMGetGuestCR0(pVM);
1548 if ( (oldval & (X86_CR0_PG|X86_CR0_WP|X86_CR0_PE))
1549 != (val32 & (X86_CR0_PG|X86_CR0_WP|X86_CR0_PE)))
1550 {
1551 /* global flush */
1552 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1553 AssertRCReturn(rc, rc);
1554 }
1555# ifdef IN_GC
1556 /* Feeling extremely lazy. */
1557 if ( (oldval & (X86_CR0_TS|X86_CR0_EM|X86_CR0_MP|X86_CR0_AM))
1558 != (val32 & (X86_CR0_TS|X86_CR0_EM|X86_CR0_MP|X86_CR0_AM)))
1559 {
1560 Log(("emInterpretMovCRx: CR0: %#x->%#x => R3\n", oldval, val32));
1561 VM_FF_SET(pVM, VM_FF_TO_R3);
1562 }
1563# endif
1564 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), 0);
1565
1566 case USE_REG_CR2:
1567 rc = CPUMSetGuestCR2(pVM, val32); AssertRC(rc);
1568 return VINF_SUCCESS;
1569
1570 case USE_REG_CR3:
1571 /* Reloading the current CR3 means the guest just wants to flush the TLBs */
1572 rc = CPUMSetGuestCR3(pVM, val32); AssertRC(rc);
1573 if (CPUMGetGuestCR0(pVM) & X86_CR0_PG)
1574 {
1575 /* flush */
1576 rc = PGMFlushTLB(pVM, val32, !(CPUMGetGuestCR4(pVM) & X86_CR4_PGE));
1577 AssertRCReturn(rc, rc);
1578 }
1579 return VINF_SUCCESS;
1580
1581 case USE_REG_CR4:
1582 oldval = CPUMGetGuestCR4(pVM);
1583#ifndef IN_RING3
1584 /** @todo is flipping of the X86_CR4_PAE bit handled correctly here? */
1585#endif
1586 rc = CPUMSetGuestCR4(pVM, val32); AssertRC(rc);
1587 val32 = CPUMGetGuestCR4(pVM);
1588 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))
1589 != (val32 & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)))
1590 {
1591 /* global flush */
1592 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1593 AssertRCReturn(rc, rc);
1594 }
1595# ifndef IN_RING3 /** @todo check this out IN_RING0! */
1596 /* Feeling extremely lazy. */
1597 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))
1598 != (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)))
1599 {
1600 Log(("emInterpretMovCRx: CR4: %#x->%#x => R3\n", oldval, val32));
1601 VM_FF_SET(pVM, VM_FF_TO_R3);
1602 }
1603# endif
1604 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), 0);
1605
1606 default:
1607 AssertFailed();
1608 case USE_REG_CR1: /* illegal op */
1609 break;
1610 }
1611 }
1612 return VERR_EM_INTERPRETER;
1613}
1614
1615static int emInterpretMovCRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1616{
1617 if (pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_CR)
1618 return EMInterpretCRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_ctrl);
1619 if (pCpu->param1.flags == USE_REG_CR && pCpu->param2.flags == USE_REG_GEN32)
1620 return EMInterpretCRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_ctrl, pCpu->param2.base.reg_gen32);
1621 AssertMsgFailedReturn(("Unexpected control register move\n"), VERR_EM_INTERPRETER);
1622 return VERR_EM_INTERPRETER;
1623}
1624
1625/**
1626 * MOV DRx
1627 */
1628
1629/**
1630 * Interpret DRx write
1631 *
1632 * @returns VBox status code.
1633 * @param pVM The VM handle.
1634 * @param pRegFrame The register frame.
1635 * @param DestRegDRx DRx register index (USE_REG_DR*)
1636 * @param SrcRegGen General purpose register index (USE_REG_E**))
1637 *
1638 */
1639EMDECL(int) EMInterpretDRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)
1640{
1641 uint32_t val32;
1642
1643 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1644 if (VBOX_SUCCESS(rc))
1645 {
1646 rc = CPUMSetGuestDRx(pVM, DestRegDrx, val32);
1647 if (VBOX_SUCCESS(rc))
1648 return rc;
1649 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx));
1650 }
1651 return VERR_EM_INTERPRETER;
1652}
1653
1654/**
1655 * Interpret DRx read
1656 *
1657 * @returns VBox status code.
1658 * @param pVM The VM handle.
1659 * @param pRegFrame The register frame.
1660 * @param DestRegGen General purpose register index (USE_REG_E**))
1661 * @param SrcRegDRx DRx register index (USE_REG_DR*)
1662 *
1663 */
1664EMDECL(int) EMInterpretDRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)
1665{
1666 uint32_t val32;
1667
1668 int rc = CPUMGetGuestDRx(pVM, SrcRegDrx, &val32);
1669 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER);
1670 rc = DISWriteReg32(pRegFrame, DestRegGen, val32);
1671 if (VBOX_SUCCESS(rc))
1672 return VINF_SUCCESS;
1673 return VERR_EM_INTERPRETER;
1674}
1675
1676static int emInterpretMovDRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1677{
1678 int rc = VERR_EM_INTERPRETER;
1679
1680 if(pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_DBG)
1681 {
1682 rc = EMInterpretDRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_dbg);
1683 }
1684 else
1685 if(pCpu->param1.flags == USE_REG_DBG && pCpu->param2.flags == USE_REG_GEN32)
1686 {
1687 rc = EMInterpretDRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_dbg, pCpu->param2.base.reg_gen32);
1688 }
1689 else
1690 AssertMsgFailed(("Unexpected debug register move\n"));
1691 return rc;
1692}
1693
1694/**
1695 * LLDT Emulation.
1696 */
1697static int emInterpretLLdt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1698{
1699 OP_PARAMVAL param1;
1700 RTSEL sel;
1701
1702 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1703 if(VBOX_FAILURE(rc))
1704 return VERR_EM_INTERPRETER;
1705
1706 switch(param1.type)
1707 {
1708 case PARMTYPE_ADDRESS:
1709 return VERR_EM_INTERPRETER; //feeling lazy right now
1710
1711 case PARMTYPE_IMMEDIATE:
1712 if(!(param1.flags & PARAM_VAL16))
1713 return VERR_EM_INTERPRETER;
1714 sel = (RTSEL)param1.val.val16;
1715 break;
1716
1717 default:
1718 return VERR_EM_INTERPRETER;
1719 }
1720
1721 if (sel == 0)
1722 {
1723 if (CPUMGetHyperLDTR(pVM) == 0)
1724 {
1725 // this simple case is most frequent in Windows 2000 (31k - boot & shutdown)
1726 return VINF_SUCCESS;
1727 }
1728 }
1729 //still feeling lazy
1730 return VERR_EM_INTERPRETER;
1731}
1732
1733#ifdef IN_GC
1734/**
1735 * STI Emulation.
1736 *
1737 * @remark the instruction following sti is guaranteed to be executed before any interrupts are dispatched
1738 */
1739static int emInterpretSti(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1740{
1741 PPATMGCSTATE pGCState = PATMQueryGCState(pVM);
1742
1743 if(!pGCState)
1744 {
1745 Assert(pGCState);
1746 return VERR_EM_INTERPRETER;
1747 }
1748 pGCState->uVMFlags |= X86_EFL_IF;
1749
1750 Assert(pRegFrame->eflags.u32 & X86_EFL_IF);
1751 Assert(pvFault == SELMToFlat(pVM, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip));
1752
1753 pVM->em.s.GCPtrInhibitInterrupts = pRegFrame->eip + pCpu->opsize;
1754 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
1755
1756 return VINF_SUCCESS;
1757}
1758#endif /* IN_GC */
1759
1760
1761/**
1762 * HLT Emulation.
1763 */
1764static int emInterpretHlt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1765{
1766 return VINF_EM_HALT;
1767}
1768
1769
1770#ifdef IN_GC
1771/**
1772 * RDTSC Emulation.
1773 */
1774static int emInterpretRdtsc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1775{
1776 unsigned uCR4 = CPUMGetGuestCR4(pVM);
1777
1778 if (uCR4 & X86_CR4_TSD)
1779 return VERR_EM_INTERPRETER; /* genuine #GP */
1780
1781 uint64_t uTicks = TMCpuTickGet(pVM);
1782
1783 pRegFrame->eax = uTicks;
1784 pRegFrame->edx = (uTicks >> 32ULL);
1785
1786 return VINF_SUCCESS;
1787}
1788#endif
1789
1790/**
1791 * MONITOR Emulation.
1792 */
1793static int emInterpretMonitor(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1794{
1795 if (pRegFrame->ecx != 0)
1796 return VERR_EM_INTERPRETER; /* illegal value. */
1797
1798#ifdef IN_GC
1799 if (pRegFrame->eflags.Bits.u1VM || (pRegFrame->ss & X86_SEL_RPL) != 1)
1800#else
1801 if (pRegFrame->eflags.Bits.u1VM || (pRegFrame->ss & X86_SEL_RPL) != 0)
1802#endif
1803 return VERR_EM_INTERPRETER; /* supervisor only */
1804
1805 return VINF_SUCCESS;
1806}
1807
1808
1809/**
1810 * MWAIT Emulation.
1811 */
1812static int emInterpretMWait(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1813{
1814 if (pRegFrame->ecx != 0)
1815 return VERR_EM_INTERPRETER; /* illegal value. */
1816
1817#ifdef IN_GC
1818 if (pRegFrame->eflags.Bits.u1VM || (pRegFrame->ss & X86_SEL_RPL) != 1)
1819#else
1820 if (pRegFrame->eflags.Bits.u1VM || (pRegFrame->ss & X86_SEL_RPL) != 0)
1821#endif
1822 return VERR_EM_INTERPRETER; /* supervisor only */
1823
1824 /** @todo not completely correct */
1825 return VINF_EM_HALT;
1826}
1827
1828
1829/**
1830 * Internal worker.
1831 * @copydoc EMInterpretInstructionCPU
1832 */
1833DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1834{
1835 Assert(pcbSize);
1836 *pcbSize = 0;
1837
1838 /*
1839 * Only supervisor guest code!!
1840 * And no complicated prefixes.
1841 */
1842#ifdef IN_GC
1843 if (pRegFrame->eflags.Bits.u1VM || (pRegFrame->ss & X86_SEL_RPL) != 1)
1844#else
1845 if (pRegFrame->eflags.Bits.u1VM || (pRegFrame->ss & X86_SEL_RPL) != 0)
1846#endif
1847 {
1848 Log(("WARNING: refusing instruction emulation for user-mode code!!\n"));
1849 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedUserMode));
1850 return VERR_EM_INTERPRETER;
1851 }
1852
1853 /* In HWACCM mode we can execute 16 bits code. Our emulation above can't cope with that yet. */
1854 /** @note if not in HWACCM mode, then we will never execute 16 bits code, so don't bother checking. */
1855 if (HWACCMIsEnabled(pVM) && !SELMIsSelector32Bit(pVM, pRegFrame->cs, &pRegFrame->csHid))
1856 return VERR_EM_INTERPRETER;
1857
1858 /** @note we could ignore PREFIX_LOCK here. Need to take special precautions when/if we support SMP in the guest.
1859 */
1860 if (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_SEG | PREFIX_LOCK))
1861 {
1862 //Log(("EMInterpretInstruction: wrong prefix!!\n"));
1863 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedPrefix));
1864 return VERR_EM_INTERPRETER;
1865 }
1866
1867 int rc;
1868 switch (pCpu->pCurInstr->opcode)
1869 {
1870#define INTERPRET_CASE_EX(opcode,Instr,InstrFn) \
1871 case opcode:\
1872 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize); \
1873 if (VBOX_SUCCESS(rc)) \
1874 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
1875 else \
1876 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
1877 return rc
1878#define INTERPRET_CASE(opcode,Instr) INTERPRET_CASE_EX(opcode,Instr,Instr)
1879#define INTERPRET_STAT_CASE(opcode,Instr) \
1880 case opcode: STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); return VERR_EM_INTERPRETER;
1881
1882 INTERPRET_CASE(OP_XCHG,Xchg);
1883 INTERPRET_CASE_EX(OP_DEC,Dec,IncDec);
1884 INTERPRET_CASE_EX(OP_INC,Inc,IncDec);
1885 INTERPRET_CASE(OP_POP,Pop);
1886 INTERPRET_CASE(OP_OR,Or);
1887 INTERPRET_CASE(OP_XOR,Xor);
1888 INTERPRET_CASE(OP_MOV,Mov);
1889 INTERPRET_CASE(OP_AND,And);
1890 INTERPRET_CASE(OP_INVLPG,InvlPg);
1891 INTERPRET_CASE(OP_CPUID,CpuId);
1892 INTERPRET_CASE(OP_MOV_CR,MovCRx);
1893 INTERPRET_CASE(OP_MOV_DR,MovDRx);
1894 INTERPRET_CASE(OP_LLDT,LLdt);
1895 INTERPRET_CASE(OP_MONITOR, Monitor);
1896 INTERPRET_CASE(OP_MWAIT, MWait);
1897 INTERPRET_CASE(OP_ADD,Add);
1898 INTERPRET_CASE(OP_ADC,Adc);
1899 INTERPRET_CASE(OP_SUB,Sub);
1900#ifdef IN_GC
1901 INTERPRET_CASE(OP_RDTSC,Rdtsc);
1902 INTERPRET_CASE(OP_STI,Sti);
1903#endif
1904 INTERPRET_CASE(OP_HLT,Hlt);
1905 INTERPRET_CASE(OP_IRET,Iret);
1906#ifdef VBOX_WITH_STATISTICS
1907 INTERPRET_STAT_CASE(OP_BTR,Btr);
1908 INTERPRET_STAT_CASE(OP_BTS,Bts);
1909 INTERPRET_STAT_CASE(OP_CMPXCHG,CmpXchg);
1910 INTERPRET_STAT_CASE(OP_MOVNTPS,MovNTPS);
1911 INTERPRET_STAT_CASE(OP_STOSWD,StosWD);
1912 INTERPRET_STAT_CASE(OP_WBINVD,WbInvd);
1913#endif
1914 default:
1915 Log3(("emInterpretInstructionCPU: opcode=%d\n", pCpu->pCurInstr->opcode));
1916 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedMisc));
1917 return VERR_EM_INTERPRETER;
1918#undef INTERPRET_STAT_CASE
1919#undef INTERPRET_CASE
1920 }
1921 AssertFailed();
1922 return VERR_INTERNAL_ERROR;
1923}
1924
1925
1926/**
1927 * Sets the PC for which interrupts should be inhibited.
1928 *
1929 * @param pVM The VM handle.
1930 * @param PC The PC.
1931 */
1932EMDECL(void) EMSetInhibitInterruptsPC(PVM pVM, RTGCUINTPTR PC)
1933{
1934 pVM->em.s.GCPtrInhibitInterrupts = PC;
1935 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
1936}
1937
1938
1939/**
1940 * Gets the PC for which interrupts should be inhibited.
1941 *
1942 * There are a few instructions which inhibits or delays interrupts
1943 * for the instruction following them. These instructions are:
1944 * - STI
1945 * - MOV SS, r/m16
1946 * - POP SS
1947 *
1948 * @returns The PC for which interrupts should be inhibited.
1949 * @param pVM VM handle.
1950 *
1951 */
1952EMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVM pVM)
1953{
1954 return pVM->em.s.GCPtrInhibitInterrupts;
1955}
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