VirtualBox

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

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

Removed stray doxygen comment.

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