VirtualBox

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

Last change on this file since 9722 was 9722, checked in by vboxsync, 16 years ago

Enabled rd/wrmsr emulation

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