VirtualBox

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

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

LOCK BTR and LOCK OR (for Solaris guests).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 70.3 KB
Line 
1/* $Id: EMAll.cpp 5384 2007-10-19 14:13:42Z 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_TS | X86_CR0_EM | X86_CR0_MP | X86_CR0_AM | X86_CR0_WP))
1529 != (NewCr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | 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
1553#ifdef IN_GC
1554 /* Need to change the hyper CR0? Doing it the lazy way then. */
1555 Log(("EMInterpretCLTS: CR0: %#x->%#x => R3\n", Cr0, Cr0 & ~X86_CR0_TS));
1556 VM_FF_SET(pVM, VM_FF_TO_R3);
1557#endif
1558 return CPUMSetGuestCR0(pVM, Cr0 & ~X86_CR0_TS);
1559}
1560
1561static int emInterpretClts(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1562{
1563 return EMInterpretCLTS(pVM);
1564}
1565
1566/**
1567 * Interpret CRx write
1568 *
1569 * @returns VBox status code.
1570 * @param pVM The VM handle.
1571 * @param pRegFrame The register frame.
1572 * @param DestRegCRx CRx register index (USE_REG_CR*)
1573 * @param SrcRegGen General purpose register index (USE_REG_E**))
1574 *
1575 */
1576EMDECL(int) EMInterpretCRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)
1577{
1578 uint32_t val32;
1579 uint32_t oldval;
1580/** @todo Clean up this mess. */
1581
1582 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1583 if (VBOX_SUCCESS(rc))
1584 {
1585 switch (DestRegCrx)
1586 {
1587 case USE_REG_CR0:
1588 oldval = CPUMGetGuestCR0(pVM);
1589#ifndef IN_RING3
1590 /* CR0.WP changes require a reschedule run in ring 3. */
1591 if ((val32 & X86_CR0_WP) != (oldval & X86_CR0_WP))
1592 return VERR_EM_INTERPRETER;
1593#endif
1594 rc = CPUMSetGuestCR0(pVM, val32); AssertRC(rc); /** @todo CPUSetGuestCR0 stuff should be void, this is silly. */
1595 val32 = CPUMGetGuestCR0(pVM);
1596 if ( (oldval & (X86_CR0_PG|X86_CR0_WP|X86_CR0_PE))
1597 != (val32 & (X86_CR0_PG|X86_CR0_WP|X86_CR0_PE)))
1598 {
1599 /* global flush */
1600 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1601 AssertRCReturn(rc, rc);
1602 }
1603# ifdef IN_GC
1604 /* Feeling extremely lazy. */
1605 if ( (oldval & (X86_CR0_TS|X86_CR0_EM|X86_CR0_MP|X86_CR0_AM))
1606 != (val32 & (X86_CR0_TS|X86_CR0_EM|X86_CR0_MP|X86_CR0_AM)))
1607 {
1608 Log(("emInterpretMovCRx: CR0: %#x->%#x => R3\n", oldval, val32));
1609 VM_FF_SET(pVM, VM_FF_TO_R3);
1610 }
1611# endif
1612 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), 0);
1613
1614 case USE_REG_CR2:
1615 rc = CPUMSetGuestCR2(pVM, val32); AssertRC(rc);
1616 return VINF_SUCCESS;
1617
1618 case USE_REG_CR3:
1619 /* Reloading the current CR3 means the guest just wants to flush the TLBs */
1620 rc = CPUMSetGuestCR3(pVM, val32); AssertRC(rc);
1621 if (CPUMGetGuestCR0(pVM) & X86_CR0_PG)
1622 {
1623 /* flush */
1624 rc = PGMFlushTLB(pVM, val32, !(CPUMGetGuestCR4(pVM) & X86_CR4_PGE));
1625 AssertRCReturn(rc, rc);
1626 }
1627 return VINF_SUCCESS;
1628
1629 case USE_REG_CR4:
1630 oldval = CPUMGetGuestCR4(pVM);
1631#ifndef IN_RING3
1632 /** @todo is flipping of the X86_CR4_PAE bit handled correctly here? */
1633#endif
1634 rc = CPUMSetGuestCR4(pVM, val32); AssertRC(rc);
1635 val32 = CPUMGetGuestCR4(pVM);
1636 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))
1637 != (val32 & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)))
1638 {
1639 /* global flush */
1640 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1641 AssertRCReturn(rc, rc);
1642 }
1643# ifndef IN_RING3 /** @todo check this out IN_RING0! */
1644 /* Feeling extremely lazy. */
1645 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))
1646 != (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)))
1647 {
1648 Log(("emInterpretMovCRx: CR4: %#x->%#x => R3\n", oldval, val32));
1649 VM_FF_SET(pVM, VM_FF_TO_R3);
1650 }
1651# endif
1652 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), 0);
1653
1654 default:
1655 AssertFailed();
1656 case USE_REG_CR1: /* illegal op */
1657 break;
1658 }
1659 }
1660 return VERR_EM_INTERPRETER;
1661}
1662
1663static int emInterpretMovCRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1664{
1665 if (pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_CR)
1666 return EMInterpretCRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_ctrl);
1667 if (pCpu->param1.flags == USE_REG_CR && pCpu->param2.flags == USE_REG_GEN32)
1668 return EMInterpretCRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_ctrl, pCpu->param2.base.reg_gen32);
1669 AssertMsgFailedReturn(("Unexpected control register move\n"), VERR_EM_INTERPRETER);
1670 return VERR_EM_INTERPRETER;
1671}
1672
1673/**
1674 * MOV DRx
1675 */
1676
1677/**
1678 * Interpret DRx write
1679 *
1680 * @returns VBox status code.
1681 * @param pVM The VM handle.
1682 * @param pRegFrame The register frame.
1683 * @param DestRegDRx DRx register index (USE_REG_DR*)
1684 * @param SrcRegGen General purpose register index (USE_REG_E**))
1685 *
1686 */
1687EMDECL(int) EMInterpretDRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)
1688{
1689 uint32_t val32;
1690
1691 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1692 if (VBOX_SUCCESS(rc))
1693 {
1694 rc = CPUMSetGuestDRx(pVM, DestRegDrx, val32);
1695 if (VBOX_SUCCESS(rc))
1696 return rc;
1697 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx));
1698 }
1699 return VERR_EM_INTERPRETER;
1700}
1701
1702/**
1703 * Interpret DRx read
1704 *
1705 * @returns VBox status code.
1706 * @param pVM The VM handle.
1707 * @param pRegFrame The register frame.
1708 * @param DestRegGen General purpose register index (USE_REG_E**))
1709 * @param SrcRegDRx DRx register index (USE_REG_DR*)
1710 *
1711 */
1712EMDECL(int) EMInterpretDRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)
1713{
1714 uint32_t val32;
1715
1716 int rc = CPUMGetGuestDRx(pVM, SrcRegDrx, &val32);
1717 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER);
1718 rc = DISWriteReg32(pRegFrame, DestRegGen, val32);
1719 if (VBOX_SUCCESS(rc))
1720 return VINF_SUCCESS;
1721 return VERR_EM_INTERPRETER;
1722}
1723
1724static int emInterpretMovDRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1725{
1726 int rc = VERR_EM_INTERPRETER;
1727
1728 if(pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_DBG)
1729 {
1730 rc = EMInterpretDRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen32, pCpu->param2.base.reg_dbg);
1731 }
1732 else
1733 if(pCpu->param1.flags == USE_REG_DBG && pCpu->param2.flags == USE_REG_GEN32)
1734 {
1735 rc = EMInterpretDRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_dbg, pCpu->param2.base.reg_gen32);
1736 }
1737 else
1738 AssertMsgFailed(("Unexpected debug register move\n"));
1739 return rc;
1740}
1741
1742/**
1743 * LLDT Emulation.
1744 */
1745static int emInterpretLLdt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1746{
1747 OP_PARAMVAL param1;
1748 RTSEL sel;
1749
1750 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1751 if(VBOX_FAILURE(rc))
1752 return VERR_EM_INTERPRETER;
1753
1754 switch(param1.type)
1755 {
1756 case PARMTYPE_ADDRESS:
1757 return VERR_EM_INTERPRETER; //feeling lazy right now
1758
1759 case PARMTYPE_IMMEDIATE:
1760 if(!(param1.flags & PARAM_VAL16))
1761 return VERR_EM_INTERPRETER;
1762 sel = (RTSEL)param1.val.val16;
1763 break;
1764
1765 default:
1766 return VERR_EM_INTERPRETER;
1767 }
1768
1769 if (sel == 0)
1770 {
1771 if (CPUMGetHyperLDTR(pVM) == 0)
1772 {
1773 // this simple case is most frequent in Windows 2000 (31k - boot & shutdown)
1774 return VINF_SUCCESS;
1775 }
1776 }
1777 //still feeling lazy
1778 return VERR_EM_INTERPRETER;
1779}
1780
1781#ifdef IN_GC
1782/**
1783 * STI Emulation.
1784 *
1785 * @remark the instruction following sti is guaranteed to be executed before any interrupts are dispatched
1786 */
1787static int emInterpretSti(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1788{
1789 PPATMGCSTATE pGCState = PATMQueryGCState(pVM);
1790
1791 if(!pGCState)
1792 {
1793 Assert(pGCState);
1794 return VERR_EM_INTERPRETER;
1795 }
1796 pGCState->uVMFlags |= X86_EFL_IF;
1797
1798 Assert(pRegFrame->eflags.u32 & X86_EFL_IF);
1799 Assert(pvFault == SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip));
1800
1801 pVM->em.s.GCPtrInhibitInterrupts = pRegFrame->eip + pCpu->opsize;
1802 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
1803
1804 return VINF_SUCCESS;
1805}
1806#endif /* IN_GC */
1807
1808
1809/**
1810 * HLT Emulation.
1811 */
1812static int emInterpretHlt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1813{
1814 return VINF_EM_HALT;
1815}
1816
1817
1818/**
1819 * RDTSC Emulation.
1820 */
1821
1822/**
1823 * Interpret RDTSC
1824 *
1825 * @returns VBox status code.
1826 * @param pVM The VM handle.
1827 * @param pRegFrame The register frame.
1828 *
1829 */
1830EMDECL(int) EMInterpretRdtsc(PVM pVM, PCPUMCTXCORE pRegFrame)
1831{
1832 unsigned uCR4 = CPUMGetGuestCR4(pVM);
1833
1834 if (uCR4 & X86_CR4_TSD)
1835 return VERR_EM_INTERPRETER; /* genuine #GP */
1836
1837 uint64_t uTicks = TMCpuTickGet(pVM);
1838
1839 pRegFrame->eax = uTicks;
1840 pRegFrame->edx = (uTicks >> 32ULL);
1841
1842 return VINF_SUCCESS;
1843}
1844
1845static int emInterpretRdtsc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1846{
1847 return EMInterpretRdtsc(pVM, pRegFrame);
1848}
1849
1850/**
1851 * MONITOR Emulation.
1852 */
1853static int emInterpretMonitor(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1854{
1855 uint32_t u32Dummy, u32ExtFeatures, cpl;
1856
1857 if (pRegFrame->ecx != 0)
1858 return VERR_EM_INTERPRETER; /* illegal value. */
1859
1860 /* Get the current privilege level. */
1861 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
1862 if (cpl != 0)
1863 return VERR_EM_INTERPRETER; /* supervisor only */
1864
1865 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
1866 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
1867 return VERR_EM_INTERPRETER; /* not supported */
1868
1869 return VINF_SUCCESS;
1870}
1871
1872
1873/**
1874 * MWAIT Emulation.
1875 */
1876static int emInterpretMWait(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1877{
1878 uint32_t u32Dummy, u32ExtFeatures, cpl;
1879
1880 if (pRegFrame->ecx != 0)
1881 return VERR_EM_INTERPRETER; /* illegal value. */
1882
1883 /* Get the current privilege level. */
1884 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
1885 if (cpl != 0)
1886 return VERR_EM_INTERPRETER; /* supervisor only */
1887
1888 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
1889 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
1890 return VERR_EM_INTERPRETER; /* not supported */
1891
1892 /** @todo not completely correct */
1893 return VINF_EM_HALT;
1894}
1895
1896
1897/**
1898 * Internal worker.
1899 * @copydoc EMInterpretInstructionCPU
1900 */
1901DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1902{
1903 Assert(pcbSize);
1904 *pcbSize = 0;
1905
1906 /*
1907 * Only supervisor guest code!!
1908 * And no complicated prefixes.
1909 */
1910 /* Get the current privilege level. */
1911 uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
1912 if ( cpl != 0
1913 && pCpu->pCurInstr->opcode != OP_RDTSC) /* rdtsc requires emulation in ring 3 as well */
1914 {
1915 Log(("WARNING: refusing instruction emulation for user-mode code!!\n"));
1916 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedUserMode));
1917 return VERR_EM_INTERPRETER;
1918 }
1919
1920#ifdef IN_GC
1921 if ( (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP))
1922 || ( (pCpu->prefix & PREFIX_LOCK)
1923 && pCpu->pCurInstr->opcode != OP_CMPXCHG
1924 && pCpu->pCurInstr->opcode != OP_OR
1925 && pCpu->pCurInstr->opcode != OP_BTR
1926 )
1927 )
1928#else
1929 if (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_LOCK))
1930#endif
1931 {
1932 //Log(("EMInterpretInstruction: wrong prefix!!\n"));
1933 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedPrefix));
1934 return VERR_EM_INTERPRETER;
1935 }
1936
1937 int rc;
1938 switch (pCpu->pCurInstr->opcode)
1939 {
1940#ifdef IN_GC
1941# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
1942 case opcode:\
1943 if (pCpu->prefix & PREFIX_LOCK) \
1944 rc = emInterpretLock##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulateLock); \
1945 else \
1946 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulate); \
1947 if (VBOX_SUCCESS(rc)) \
1948 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
1949 else \
1950 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
1951 return rc
1952#else
1953# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
1954 INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate)
1955#endif
1956#define INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate) \
1957 case opcode:\
1958 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulate); \
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
1965#define INTERPRET_CASE_EX_PARAM2(opcode, Instr, InstrFn, pfnEmulate) \
1966 INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate)
1967#define INTERPRET_CASE_EX_LOCK_PARAM2(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
1968 INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock)
1969
1970#define INTERPRET_CASE(opcode, Instr) \
1971 case opcode:\
1972 rc = emInterpret##Instr(pVM, pCpu, pRegFrame, pvFault, pcbSize); \
1973 if (VBOX_SUCCESS(rc)) \
1974 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
1975 else \
1976 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
1977 return rc
1978#define INTERPRET_STAT_CASE(opcode, Instr) \
1979 case opcode: STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); return VERR_EM_INTERPRETER;
1980
1981 INTERPRET_CASE(OP_XCHG,Xchg);
1982 INTERPRET_CASE_EX_PARAM2(OP_DEC,Dec, IncDec, EMEmulateDec);
1983 INTERPRET_CASE_EX_PARAM2(OP_INC,Inc, IncDec, EMEmulateInc);
1984 INTERPRET_CASE(OP_POP,Pop);
1985 INTERPRET_CASE_EX_LOCK_PARAM3(OP_OR, Or, OrXorAnd, EMEmulateOr, EMEmulateLockOr);
1986 INTERPRET_CASE_EX_PARAM3(OP_XOR,Xor, OrXorAnd, EMEmulateXor);
1987 INTERPRET_CASE_EX_PARAM3(OP_AND,And, OrXorAnd, EMEmulateAnd);
1988 INTERPRET_CASE(OP_MOV,Mov);
1989 INTERPRET_CASE(OP_INVLPG,InvlPg);
1990 INTERPRET_CASE(OP_CPUID,CpuId);
1991 INTERPRET_CASE(OP_MOV_CR,MovCRx);
1992 INTERPRET_CASE(OP_MOV_DR,MovDRx);
1993 INTERPRET_CASE(OP_LLDT,LLdt);
1994 INTERPRET_CASE(OP_CLTS,Clts);
1995 INTERPRET_CASE(OP_MONITOR, Monitor);
1996 INTERPRET_CASE(OP_MWAIT, MWait);
1997 INTERPRET_CASE_EX_PARAM3(OP_ADD,Add, AddSub, EMEmulateAdd);
1998 INTERPRET_CASE_EX_PARAM3(OP_SUB,Sub, AddSub, EMEmulateSub);
1999 INTERPRET_CASE(OP_ADC,Adc);
2000 INTERPRET_CASE_EX_LOCK_PARAM2(OP_BTR,Btr, BitTest, EMEmulateBtr, EMEmulateLockBtr);
2001 INTERPRET_CASE_EX_PARAM2(OP_BTS,Bts, BitTest, EMEmulateBts);
2002 INTERPRET_CASE_EX_PARAM2(OP_BTC,Btc, BitTest, EMEmulateBtc);
2003 INTERPRET_CASE(OP_RDTSC,Rdtsc);
2004#ifdef IN_GC
2005 INTERPRET_CASE(OP_STI,Sti);
2006 INTERPRET_CASE(OP_CMPXCHG, CmpXchg);
2007#endif
2008 INTERPRET_CASE(OP_HLT,Hlt);
2009 INTERPRET_CASE(OP_IRET,Iret);
2010#ifdef VBOX_WITH_STATISTICS
2011#ifndef IN_GC
2012 INTERPRET_STAT_CASE(OP_CMPXCHG,CmpXchg);
2013#endif
2014 INTERPRET_STAT_CASE(OP_MOVNTPS,MovNTPS);
2015 INTERPRET_STAT_CASE(OP_STOSWD,StosWD);
2016 INTERPRET_STAT_CASE(OP_WBINVD,WbInvd);
2017#endif
2018 default:
2019 Log3(("emInterpretInstructionCPU: opcode=%d\n", pCpu->pCurInstr->opcode));
2020 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedMisc));
2021 return VERR_EM_INTERPRETER;
2022#undef INTERPRET_CASE_EX_PARAM2
2023#undef INTERPRET_STAT_CASE
2024#undef INTERPRET_CASE_EX
2025#undef INTERPRET_CASE
2026 }
2027 AssertFailed();
2028 return VERR_INTERNAL_ERROR;
2029}
2030
2031
2032/**
2033 * Sets the PC for which interrupts should be inhibited.
2034 *
2035 * @param pVM The VM handle.
2036 * @param PC The PC.
2037 */
2038EMDECL(void) EMSetInhibitInterruptsPC(PVM pVM, RTGCUINTPTR PC)
2039{
2040 pVM->em.s.GCPtrInhibitInterrupts = PC;
2041 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
2042}
2043
2044
2045/**
2046 * Gets the PC for which interrupts should be inhibited.
2047 *
2048 * There are a few instructions which inhibits or delays interrupts
2049 * for the instruction following them. These instructions are:
2050 * - STI
2051 * - MOV SS, r/m16
2052 * - POP SS
2053 *
2054 * @returns The PC for which interrupts should be inhibited.
2055 * @param pVM VM handle.
2056 *
2057 */
2058EMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVM pVM)
2059{
2060 return pVM->em.s.GCPtrInhibitInterrupts;
2061}
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