VirtualBox

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

Last change on this file since 5393 was 5389, checked in by vboxsync, 17 years ago

Fully deal with CR0.EM/TS/MP changes in GC.

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