VirtualBox

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

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

SELM function changes for v86 mode code.
CPL check fixes for V86 mode code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 64.1 KB
Line 
1/* $Id: EMAll.cpp 1359 2007-03-09 10:40:44Z vboxsync $ */
2/** @file
3 * EM - Execution Monitor(/Manager) - All contexts
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_EM
27#include <VBox/em.h>
28#include <VBox/mm.h>
29#include <VBox/selm.h>
30#include <VBox/patm.h>
31#include <VBox/csam.h>
32#include <VBox/pgm.h>
33#include <VBox/iom.h>
34#include <VBox/stam.h>
35#include "EMInternal.h"
36#include <VBox/vm.h>
37#include <VBox/hwaccm.h>
38#include <VBox/tm.h>
39
40#include <VBox/param.h>
41#include <VBox/err.h>
42#include <VBox/dis.h>
43#include <VBox/disopcode.h>
44#include <VBox/log.h>
45#include <iprt/assert.h>
46#include <iprt/asm.h>
47#include <iprt/string.h>
48
49
50/*******************************************************************************
51 * Internal Functions *
52 *******************************************************************************/
53
54DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize);
55
56
57/**
58 * Get the current execution manager status.
59 *
60 * @returns Current status.
61 */
62EMDECL(EMSTATE) EMGetState(PVM pVM)
63{
64 return pVM->em.s.enmState;
65}
66
67
68#ifndef IN_GC
69/**
70 * Read callback for disassembly function; supports reading bytes that cross a page boundary
71 *
72 * @returns VBox status code.
73 * @param pSrc GC source pointer
74 * @param pDest HC destination pointer
75 * @param size Number of bytes to read
76 * @param dwUserdata Callback specific user data (pCpu)
77 *
78 */
79DECLCALLBACK(int32_t) EMReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, uint32_t size, RTHCUINTPTR dwUserdata)
80{
81 DISCPUSTATE *pCpu = (DISCPUSTATE *)dwUserdata;
82 PVM pVM = (PVM)pCpu->dwUserData[0];
83#ifdef IN_RING0
84 int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
85 AssertRC(rc);
86#else
87 if (!PATMIsPatchGCAddr(pVM, pSrc))
88 {
89 int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
90 AssertRC(rc);
91 }
92 else
93 {
94 for (uint32_t i = 0; i < size; i++)
95 {
96 uint8_t opcode;
97 if (VBOX_SUCCESS(PATMR3QueryOpcode(pVM, (RTGCPTR)pSrc + i, &opcode)))
98 {
99 *(pDest+i) = opcode;
100 }
101 }
102 }
103#endif /* IN_RING0 */
104 return VINF_SUCCESS;
105}
106
107inline int emDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
108{
109 return DISCoreOneEx(InstrGC, pCpu->mode, EMReadBytes, pVM, pCpu, pOpsize);
110}
111
112#else
113
114inline int emDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
115{
116 return DISCoreOne(pCpu, InstrGC, pOpsize);
117}
118
119#endif
120
121
122/**
123 * Disassembles one instruction.
124 *
125 * @param pVM The VM handle.
126 * @param pCtxCore The context core (used for both the mode and instruction).
127 * @param pCpu Where to return the parsed instruction info.
128 * @param pcbInstr Where to return the instruction size. (optional)
129 */
130EMDECL(int) EMInterpretDisasOne(PVM pVM, PCCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, unsigned *pcbInstr)
131{
132 RTGCPTR GCPtrInstr;
133 int rc = SELMValidateAndConvertCSAddr(pVM, pCtxCore->eflags, pCtxCore->ss, pCtxCore->cs, (PCPUMSELREGHID)&pCtxCore->csHid, (RTGCPTR)pCtxCore->eip, &GCPtrInstr);
134 if (VBOX_FAILURE(rc))
135 {
136 Log(("EMInterpretDisasOne: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
137 pCtxCore->cs, pCtxCore->eip, pCtxCore->ss & X86_SEL_RPL, rc));
138 return rc;
139 }
140 return EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)GCPtrInstr, pCtxCore, pCpu, pcbInstr);
141}
142
143
144/**
145 * Disassembles one instruction.
146 *
147 * This is used by internally by the interpreter and by trap/access handlers.
148 *
149 * @param pVM The VM handle.
150 * @param GCPtrInstr The flat address of the instruction.
151 * @param pCtxCore The context core (used to determin the cpu mode).
152 * @param pCpu Where to return the parsed instruction info.
153 * @param pcbInstr Where to return the instruction size. (optional)
154 */
155EMDECL(int) EMInterpretDisasOneEx(PVM pVM, RTGCUINTPTR GCPtrInstr, PCCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, unsigned *pcbInstr)
156{
157 int rc = DISCoreOneEx(GCPtrInstr, SELMIsSelector32Bit(pVM, pCtxCore->eflags, pCtxCore->cs, (PCPUMSELREGHID)&pCtxCore->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT,
158#ifdef IN_GC
159 NULL, NULL,
160#else
161 EMReadBytes, pVM,
162#endif
163 pCpu, pcbInstr);
164 if (VBOX_SUCCESS(rc))
165 return VINF_SUCCESS;
166 AssertMsgFailed(("DISCoreOne failed to GCPtrInstr=%VGv rc=%Vrc\n", GCPtrInstr, rc));
167 return VERR_INTERNAL_ERROR;
168}
169
170
171/**
172 * Interprets the current instruction.
173 *
174 * @returns VBox status code.
175 * @retval VINF_* Scheduling instructions.
176 * @retval VERR_EM_INTERPRETER Something we can't cope with.
177 * @retval VERR_* Fatal errors.
178 *
179 * @param pVM The VM handle.
180 * @param pRegFrame The register frame.
181 * Updates the EIP if an instruction was executed successfully.
182 * @param pvFault The fault address (CR2).
183 * @param pcbSize Size of the write (if applicable).
184 *
185 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
186 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
187 * to worry about e.g. invalid modrm combinations (!)
188 */
189EMDECL(int) EMInterpretInstruction(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
190{
191 /*
192 * Only allow 32-bit code.
193 */
194 if (SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
195 {
196 RTGCPTR pbCode;
197 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &pbCode);
198 if (VBOX_SUCCESS(rc))
199 {
200 uint32_t cbOp;
201 DISCPUSTATE Cpu;
202 Cpu.mode = CPUMODE_32BIT;
203 rc = emDisCoreOne(pVM, &Cpu, (RTGCUINTPTR)pbCode, &cbOp);
204 if (VBOX_SUCCESS(rc))
205 {
206 Assert(cbOp == Cpu.opsize);
207 rc = EMInterpretInstructionCPU(pVM, &Cpu, pRegFrame, pvFault, pcbSize);
208 if (VBOX_SUCCESS(rc))
209 {
210 pRegFrame->eip += cbOp; /* Move on to the next instruction. */
211 }
212 return rc;
213 }
214 }
215 }
216 return VERR_EM_INTERPRETER;
217}
218
219/**
220 * Interprets the current instruction using the supplied DISCPUSTATE structure.
221 *
222 * EIP is *NOT* updated!
223 *
224 * @returns VBox status code.
225 * @retval VINF_* Scheduling instructions. When these are returned, it
226 * starts to get a bit tricky to know whether code was
227 * executed or not... We'll address this when it becomes a problem.
228 * @retval VERR_EM_INTERPRETER Something we can't cope with.
229 * @retval VERR_* Fatal errors.
230 *
231 * @param pVM The VM handle.
232 * @param pCpu The disassembler cpu state for the instruction to be interpreted.
233 * @param pRegFrame The register frame. EIP is *NOT* changed!
234 * @param pvFault The fault address (CR2).
235 * @param pcbSize Size of the write (if applicable).
236 *
237 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
238 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
239 * to worry about e.g. invalid modrm combinations (!)
240 *
241 * @todo At this time we do NOT check if the instruction overwrites vital information.
242 * Make sure this can't happen!! (will add some assertions/checks later)
243 */
244EMDECL(int) EMInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
245{
246 STAM_PROFILE_START(&CTXMID(pVM->em.s.CTXSUFF(pStats)->Stat,Emulate), a);
247 int rc = emInterpretInstructionCPU(pVM, pCpu, pRegFrame, pvFault, pcbSize);
248 STAM_PROFILE_STOP(&CTXMID(pVM->em.s.CTXSUFF(pStats)->Stat,Emulate), a);
249 if (VBOX_SUCCESS(rc))
250 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,InterpretSucceeded));
251 else
252 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,InterpretFailed));
253 return rc;
254}
255
256
257/**
258 * Interpret a port I/O instruction.
259 *
260 * @returns VBox status code suitable for scheduling.
261 * @param pVM The VM handle.
262 * @param pCtxCore The context core. This will be updated on successful return.
263 * @param pCpu The instruction to interpret.
264 * @param cbOp The size of the instruction.
265 * @remark This may raise exceptions.
266 */
267EMDECL(int) EMInterpretPortIO(PVM pVM, PCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, uint32_t cbOp)
268{
269 /*
270 * Hand it on to IOM.
271 */
272#ifdef IN_GC
273 int rc = IOMGCIOPortHandler(pVM, pCtxCore, pCpu);
274 if (rc == VINF_SUCCESS)
275 pCtxCore->eip += cbOp;
276 return rc;
277#else
278 AssertReleaseMsgFailed(("not implemented\n"));
279 return VERR_NOT_IMPLEMENTED;
280#endif
281}
282
283
284inline int emRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
285{
286#ifdef IN_GC
287 return MMGCRamRead(pVM, pDest, GCSrc, cb);
288#else
289 int rc;
290 RTGCPHYS GCPhys;
291 RTGCUINTPTR offset;
292
293 offset = GCSrc & PAGE_OFFSET_MASK;
294
295 rc = PGMPhysGCPtr2GCPhys(pVM, GCSrc, &GCPhys);
296 AssertRCReturn(rc, rc);
297 PGMPhysRead(pVM, GCPhys + offset, pDest, cb);
298 return VINF_SUCCESS;
299#endif
300}
301
302inline int emRamWrite(PVM pVM, RTGCPTR GCDest, void *pSrc, uint32_t cb)
303{
304#ifdef IN_GC
305 return MMGCRamWrite(pVM, GCDest, pSrc, cb);
306#else
307 int rc;
308 RTGCPHYS GCPhys;
309 RTGCUINTPTR offset;
310
311 offset = GCDest & PAGE_OFFSET_MASK;
312 rc = PGMPhysGCPtr2GCPhys(pVM, GCDest, &GCPhys);
313 AssertRCReturn(rc, rc);
314 PGMPhysWrite(pVM, GCPhys + offset, pSrc, cb);
315 return VINF_SUCCESS;
316#endif
317}
318
319/**
320 * XCHG instruction emulation.
321 */
322static int emInterpretXchg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
323{
324 OP_PARAMVAL param1, param2;
325
326 /* Source to make DISQueryParamVal read the register value - ugly hack */
327 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
328 if(VBOX_FAILURE(rc))
329 return VERR_EM_INTERPRETER;
330
331 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
332 if(VBOX_FAILURE(rc))
333 return VERR_EM_INTERPRETER;
334
335#ifdef IN_GC
336 if (TRPMHasTrap(pVM))
337 {
338 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
339 {
340#endif
341 RTGCPTR pParam1 = 0, pParam2 = 0;
342 uint32_t valpar1, valpar2;
343
344 AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
345 switch(param1.type)
346 {
347 case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
348 valpar1 = param1.val.val32;
349 break;
350
351 case PARMTYPE_ADDRESS:
352 pParam1 = (RTGCPTR)param1.val.val32;
353#ifdef IN_GC
354 /* Safety check (in theory it could cross a page boundary and fault there though) */
355 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
356#endif
357 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
358 if (VBOX_FAILURE(rc))
359 {
360 AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
361 return VERR_EM_INTERPRETER;
362 }
363 break;
364
365 default:
366 AssertFailed();
367 return VERR_EM_INTERPRETER;
368 }
369
370 switch(param2.type)
371 {
372 case PARMTYPE_ADDRESS:
373 pParam2 = (RTGCPTR)param2.val.val32;
374#ifdef IN_GC
375 /* Safety check (in theory it could cross a page boundary and fault there though) */
376 AssertReturn(pParam2 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
377#endif
378 rc = emRamRead(pVM, &valpar2, pParam2, param2.size);
379 if (VBOX_FAILURE(rc))
380 {
381 AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
382 }
383 break;
384
385 case PARMTYPE_IMMEDIATE:
386 valpar2 = param2.val.val32;
387 break;
388
389 default:
390 AssertFailed();
391 return VERR_EM_INTERPRETER;
392 }
393
394 /* Write value of parameter 2 to parameter 1 (reg or memory address) */
395 if (pParam1 == 0)
396 {
397 Assert(param1.type == PARMTYPE_IMMEDIATE); /* register actually */
398 switch(param1.size)
399 {
400 case 1: //special case for AH etc
401 rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen8, (uint8_t)valpar2); break;
402 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen32, (uint16_t)valpar2); break;
403 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen32, valpar2); break;
404 default: AssertFailedReturn(VERR_EM_INTERPRETER);
405 }
406 if (VBOX_FAILURE(rc))
407 return VERR_EM_INTERPRETER;
408 }
409 else
410 {
411 rc = emRamWrite(pVM, pParam1, &valpar2, param1.size);
412 if (VBOX_FAILURE(rc))
413 {
414 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
415 return VERR_EM_INTERPRETER;
416 }
417 }
418
419 /* Write value of parameter 1 to parameter 2 (reg or memory address) */
420 if (pParam2 == 0)
421 {
422 Assert(param2.type == PARMTYPE_IMMEDIATE); /* register actually */
423 switch(param2.size)
424 {
425 case 1: //special case for AH etc
426 rc = DISWriteReg8(pRegFrame, pCpu->param2.base.reg_gen8, (uint8_t)valpar1); break;
427 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param2.base.reg_gen32, (uint16_t)valpar1); break;
428 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param2.base.reg_gen32, valpar1); break;
429 default: AssertFailedReturn(VERR_EM_INTERPRETER);
430 }
431 if (VBOX_FAILURE(rc))
432 return VERR_EM_INTERPRETER;
433 }
434 else
435 {
436 rc = emRamWrite(pVM, pParam2, &valpar1, param2.size);
437 if (VBOX_FAILURE(rc))
438 {
439 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
440 return VERR_EM_INTERPRETER;
441 }
442 }
443
444 *pcbSize = param2.size;
445 return VINF_SUCCESS;
446#ifdef IN_GC
447 }
448 }
449#endif
450 return VERR_EM_INTERPRETER;
451}
452
453
454/**
455 * INC and DEC emulation.
456 */
457static int emInterpretIncDec(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
458{
459 OP_PARAMVAL param1;
460
461 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
462 if(VBOX_FAILURE(rc))
463 return VERR_EM_INTERPRETER;
464
465#ifdef IN_GC
466 if (TRPMHasTrap(pVM))
467 {
468 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
469 {
470#endif
471 RTGCPTR pParam1 = 0;
472 uint32_t valpar1;
473
474 if (param1.type == PARMTYPE_ADDRESS)
475 {
476 pParam1 = (RTGCPTR)param1.val.val32;
477#ifdef IN_GC
478 /* Safety check (in theory it could cross a page boundary and fault there though) */
479 AssertReturn(pParam1 == (RTGCPTR)pvFault, VERR_EM_INTERPRETER);
480#endif
481 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
482 if (VBOX_FAILURE(rc))
483 {
484 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
485 return VERR_EM_INTERPRETER;
486 }
487 }
488 else
489 {
490 AssertFailed();
491 return VERR_EM_INTERPRETER;
492 }
493
494 uint32_t eflags;
495
496 if (pCpu->pCurInstr->opcode == OP_DEC)
497 eflags = EMEmulateDec(&valpar1, param1.size);
498 else
499 eflags = EMEmulateInc(&valpar1, param1.size);
500
501 /* Write result back */
502 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
503 if (VBOX_FAILURE(rc))
504 {
505 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
506 return VERR_EM_INTERPRETER;
507 }
508
509 /* Update guest's eflags and finish. */
510 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
511 | (eflags & (X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
512
513 /* All done! */
514 *pcbSize = param1.size;
515 return VINF_SUCCESS;
516#ifdef IN_GC
517 }
518 }
519#endif
520 return VERR_EM_INTERPRETER;
521}
522
523/**
524 * POP Emulation.
525 */
526static int emInterpretPop(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
527{
528 OP_PARAMVAL param1;
529 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
530 if(VBOX_FAILURE(rc))
531 return VERR_EM_INTERPRETER;
532
533#ifdef IN_GC
534 if (TRPMHasTrap(pVM))
535 {
536 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
537 {
538#endif
539 RTGCPTR pParam1 = 0;
540 uint32_t valpar1;
541 RTGCPTR pStackVal;
542
543 /* Read stack value first */
544 if (SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid) == false)
545 return VERR_EM_INTERPRETER; /* No legacy 16 bits stuff here, please. */
546
547 /* Convert address; don't bother checking limits etc, as we only read here */
548 pStackVal = SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid, (RTGCPTR)pRegFrame->esp);
549 if (pStackVal == 0)
550 return VERR_EM_INTERPRETER;
551
552 rc = emRamRead(pVM, &valpar1, pStackVal, param1.size);
553 if (VBOX_FAILURE(rc))
554 {
555 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
556 return VERR_EM_INTERPRETER;
557 }
558
559 if (param1.type == PARMTYPE_ADDRESS)
560 {
561 pParam1 = (RTGCPTR)param1.val.val32;
562
563#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->eflags, 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->eflags, 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