VirtualBox

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

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

DRx access functions must use uint64_t now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 81.9 KB
Line 
1/* $Id: EMAll.cpp 9647 2008-06-12 09:34:27Z 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->eip, &GCPtrInstr);
146 if (VBOX_FAILURE(rc))
147 {
148 Log(("EMInterpretDisasOne: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
149 pCtxCore->cs, pCtxCore->eip, 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, SELMIsSelector32Bit(pVM, pCtxCore->eflags, pCtxCore->cs, (PCPUMSELREGHID)&pCtxCore->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT,
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 %VRv fault %VGv\n", pRegFrame->eip, pvFault));
206 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &pbCode);
207 if (VBOX_SUCCESS(rc))
208 {
209 uint32_t cbOp;
210 DISCPUSTATE Cpu;
211 Cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
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->eip += 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->eip += 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 int prefix_seg, rc;
347 RTSEL sel;
348 CPUMSELREGHID *pSelHidReg;
349
350 prefix_seg = DISDetectSegReg(pCpu, pParam);
351 rc = DISFetchRegSegEx(pRegFrame, prefix_seg, &sel, &pSelHidReg);
352 if (VBOX_FAILURE(rc))
353 return pvAddr;
354
355 return SELMToFlat(pVM, pRegFrame->eflags, sel, pSelHidReg, pvAddr);
356}
357
358#if defined(IN_GC) && (defined(VBOX_STRICT) || defined(LOG_ENABLED))
359/**
360 * Get the mnemonic for the disassembled instruction.
361 *
362 * GC/R0 doesn't include the strings in the DIS tables because
363 * of limited space.
364 */
365static const char *emGetMnemonic(PDISCPUSTATE pCpu)
366{
367 switch (pCpu->pCurInstr->opcode)
368 {
369 case OP_XCHG: return "Xchg";
370 case OP_DEC: return "Dec";
371 case OP_INC: return "Inc";
372 case OP_POP: return "Pop";
373 case OP_OR: return "Or";
374 case OP_AND: return "And";
375 case OP_MOV: return "Mov";
376 case OP_INVLPG: return "InvlPg";
377 case OP_CPUID: return "CpuId";
378 case OP_MOV_CR: return "MovCRx";
379 case OP_MOV_DR: return "MovDRx";
380 case OP_LLDT: return "LLdt";
381 case OP_CLTS: return "Clts";
382 case OP_MONITOR: return "Monitor";
383 case OP_MWAIT: return "MWait";
384 case OP_RDMSR: return "Rdmsr";
385 case OP_WRMSR: return "Wrmsr";
386 case OP_ADC: return "Adc";
387 case OP_BTC: return "Btc";
388 case OP_RDTSC: return "Rdtsc";
389 case OP_STI: return "Sti";
390 case OP_XADD: return "XAdd";
391 case OP_HLT: return "Hlt";
392 case OP_IRET: return "Iret";
393 case OP_CMPXCHG: return "CmpXchg";
394 case OP_CMPXCHG8B: return "CmpXchg8b";
395 case OP_MOVNTPS: return "MovNTPS";
396 case OP_STOSWD: return "StosWD";
397 case OP_WBINVD: return "WbInvd";
398 case OP_XOR: return "Xor";
399 case OP_BTR: return "Btr";
400 case OP_BTS: return "Bts";
401 default:
402 Log(("Unknown opcode %d\n", pCpu->pCurInstr->opcode));
403 return "???";
404 }
405}
406#endif
407
408/**
409 * XCHG instruction emulation.
410 */
411static int emInterpretXchg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
412{
413 OP_PARAMVAL param1, param2;
414
415 /* Source to make DISQueryParamVal read the register value - ugly hack */
416 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
417 if(VBOX_FAILURE(rc))
418 return VERR_EM_INTERPRETER;
419
420 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
421 if(VBOX_FAILURE(rc))
422 return VERR_EM_INTERPRETER;
423
424#ifdef IN_GC
425 if (TRPMHasTrap(pVM))
426 {
427 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
428 {
429#endif
430 RTGCPTR pParam1 = 0, pParam2 = 0;
431 uint32_t valpar1, valpar2;
432
433 AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
434 switch(param1.type)
435 {
436 case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
437 valpar1 = param1.val.val32;
438 break;
439
440 case PARMTYPE_ADDRESS:
441 pParam1 = (RTGCPTR)param1.val.val32;
442 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
443#ifdef IN_GC
444 /* Safety check (in theory it could cross a page boundary and fault there though) */
445 AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
446#endif
447 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
448 if (VBOX_FAILURE(rc))
449 {
450 AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
451 return VERR_EM_INTERPRETER;
452 }
453 break;
454
455 default:
456 AssertFailed();
457 return VERR_EM_INTERPRETER;
458 }
459
460 switch(param2.type)
461 {
462 case PARMTYPE_ADDRESS:
463 pParam2 = (RTGCPTR)param2.val.val32;
464 pParam2 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param2, pParam2);
465#ifdef IN_GC
466 /* Safety check (in theory it could cross a page boundary and fault there though) */
467 AssertReturn(pParam2 == pvFault, VERR_EM_INTERPRETER);
468#endif
469 rc = emRamRead(pVM, &valpar2, pParam2, param2.size);
470 if (VBOX_FAILURE(rc))
471 {
472 AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
473 }
474 break;
475
476 case PARMTYPE_IMMEDIATE:
477 valpar2 = param2.val.val32;
478 break;
479
480 default:
481 AssertFailed();
482 return VERR_EM_INTERPRETER;
483 }
484
485 /* Write value of parameter 2 to parameter 1 (reg or memory address) */
486 if (pParam1 == 0)
487 {
488 Assert(param1.type == PARMTYPE_IMMEDIATE); /* register actually */
489 switch(param1.size)
490 {
491 case 1: //special case for AH etc
492 rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen, (uint8_t)valpar2); break;
493 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen, (uint16_t)valpar2); break;
494 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen, valpar2); break;
495 default: AssertFailedReturn(VERR_EM_INTERPRETER);
496 }
497 if (VBOX_FAILURE(rc))
498 return VERR_EM_INTERPRETER;
499 }
500 else
501 {
502 rc = emRamWrite(pVM, pParam1, &valpar2, param1.size);
503 if (VBOX_FAILURE(rc))
504 {
505 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
506 return VERR_EM_INTERPRETER;
507 }
508 }
509
510 /* Write value of parameter 1 to parameter 2 (reg or memory address) */
511 if (pParam2 == 0)
512 {
513 Assert(param2.type == PARMTYPE_IMMEDIATE); /* register actually */
514 switch(param2.size)
515 {
516 case 1: //special case for AH etc
517 rc = DISWriteReg8(pRegFrame, pCpu->param2.base.reg_gen, (uint8_t)valpar1); break;
518 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param2.base.reg_gen, (uint16_t)valpar1); break;
519 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param2.base.reg_gen, valpar1); break;
520 default: AssertFailedReturn(VERR_EM_INTERPRETER);
521 }
522 if (VBOX_FAILURE(rc))
523 return VERR_EM_INTERPRETER;
524 }
525 else
526 {
527 rc = emRamWrite(pVM, pParam2, &valpar1, param2.size);
528 if (VBOX_FAILURE(rc))
529 {
530 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
531 return VERR_EM_INTERPRETER;
532 }
533 }
534
535 *pcbSize = param2.size;
536 return VINF_SUCCESS;
537#ifdef IN_GC
538 }
539 }
540#endif
541 return VERR_EM_INTERPRETER;
542}
543
544/**
545 * INC and DEC emulation.
546 */
547static int emInterpretIncDec(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
548 PFN_EMULATE_PARAM2 pfnEmulate)
549{
550 OP_PARAMVAL param1;
551
552 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
553 if(VBOX_FAILURE(rc))
554 return VERR_EM_INTERPRETER;
555
556#ifdef IN_GC
557 if (TRPMHasTrap(pVM))
558 {
559 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
560 {
561#endif
562 RTGCPTR pParam1 = 0;
563 uint32_t valpar1;
564
565 if (param1.type == PARMTYPE_ADDRESS)
566 {
567 pParam1 = (RTGCPTR)param1.val.val32;
568 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
569#ifdef IN_GC
570 /* Safety check (in theory it could cross a page boundary and fault there though) */
571 AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
572#endif
573 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
574 if (VBOX_FAILURE(rc))
575 {
576 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
577 return VERR_EM_INTERPRETER;
578 }
579 }
580 else
581 {
582 AssertFailed();
583 return VERR_EM_INTERPRETER;
584 }
585
586 uint32_t eflags;
587
588 eflags = pfnEmulate(&valpar1, param1.size);
589
590 /* Write result back */
591 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
592 if (VBOX_FAILURE(rc))
593 {
594 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
595 return VERR_EM_INTERPRETER;
596 }
597
598 /* Update guest's eflags and finish. */
599 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
600 | (eflags & (X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
601
602 /* All done! */
603 *pcbSize = param1.size;
604 return VINF_SUCCESS;
605#ifdef IN_GC
606 }
607 }
608#endif
609 return VERR_EM_INTERPRETER;
610}
611
612/**
613 * POP Emulation.
614 */
615static int emInterpretPop(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
616{
617 OP_PARAMVAL param1;
618 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
619 if(VBOX_FAILURE(rc))
620 return VERR_EM_INTERPRETER;
621
622#ifdef IN_GC
623 if (TRPMHasTrap(pVM))
624 {
625 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
626 {
627#endif
628 RTGCPTR pParam1 = 0;
629 uint32_t valpar1;
630 RTGCPTR pStackVal;
631
632 /* Read stack value first */
633 if (SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid) == false)
634 return VERR_EM_INTERPRETER; /* No legacy 16 bits stuff here, please. */
635
636 /* Convert address; don't bother checking limits etc, as we only read here */
637 pStackVal = SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid, (RTGCPTR)pRegFrame->esp);
638 if (pStackVal == 0)
639 return VERR_EM_INTERPRETER;
640
641 rc = emRamRead(pVM, &valpar1, pStackVal, param1.size);
642 if (VBOX_FAILURE(rc))
643 {
644 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
645 return VERR_EM_INTERPRETER;
646 }
647
648 if (param1.type == PARMTYPE_ADDRESS)
649 {
650 pParam1 = (RTGCPTR)param1.val.val32;
651
652 /* pop [esp+xx] uses esp after the actual pop! */
653 AssertCompile(USE_REG_ESP == USE_REG_SP);
654 if ( (pCpu->param1.flags & USE_BASE)
655 && (pCpu->param1.flags & (USE_REG_GEN16|USE_REG_GEN32))
656 && pCpu->param1.base.reg_gen == USE_REG_ESP
657 )
658 pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + param1.size);
659
660 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
661
662#ifdef IN_GC
663 /* Safety check (in theory it could cross a page boundary and fault there though) */
664 AssertMsgReturn(pParam1 == pvFault || (RTGCPTR)pRegFrame->esp == pvFault, ("%VGv != %VGv ss:esp=%04X:%08x\n", pParam1, pvFault, pRegFrame->ss, pRegFrame->esp), VERR_EM_INTERPRETER);
665#endif
666 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
667 if (VBOX_FAILURE(rc))
668 {
669 AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
670 return VERR_EM_INTERPRETER;
671 }
672
673 /* Update ESP as the last step */
674 pRegFrame->esp += param1.size;
675 }
676 else
677 {
678#ifndef DEBUG_bird // annoying assertion.
679 AssertFailed();
680#endif
681 return VERR_EM_INTERPRETER;
682 }
683
684 /* All done! */
685 *pcbSize = param1.size;
686 return VINF_SUCCESS;
687#ifdef IN_GC
688 }
689 }
690#endif
691 return VERR_EM_INTERPRETER;
692}
693
694
695/**
696 * XOR/OR/AND Emulation.
697 */
698static int emInterpretOrXorAnd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
699 PFN_EMULATE_PARAM3 pfnEmulate)
700{
701 OP_PARAMVAL param1, param2;
702 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
703 if(VBOX_FAILURE(rc))
704 return VERR_EM_INTERPRETER;
705
706 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
707 if(VBOX_FAILURE(rc))
708 return VERR_EM_INTERPRETER;
709
710#ifdef LOG_ENABLED
711 const char *pszInstr;
712
713 if (pCpu->pCurInstr->opcode == OP_XOR)
714 pszInstr = "Xor";
715 else if (pCpu->pCurInstr->opcode == OP_OR)
716 pszInstr = "Or";
717 else if (pCpu->pCurInstr->opcode == OP_AND)
718 pszInstr = "And";
719 else
720 pszInstr = "OrXorAnd??";
721#endif
722
723#ifdef IN_GC
724 if (TRPMHasTrap(pVM))
725 {
726 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
727 {
728#endif
729 RTGCPTR pParam1;
730 uint32_t valpar1, valpar2;
731
732 if (pCpu->param1.size != pCpu->param2.size)
733 {
734 if (pCpu->param1.size < pCpu->param2.size)
735 {
736 AssertMsgFailed(("%s at %VGv parameter mismatch %d vs %d!!\n", pszInstr, pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
737 return VERR_EM_INTERPRETER;
738 }
739 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
740 pCpu->param2.size = pCpu->param1.size;
741 param2.size = param1.size;
742 }
743
744 /* The destination is always a virtual address */
745 if (param1.type == PARMTYPE_ADDRESS)
746 {
747 pParam1 = (RTGCPTR)param1.val.val32;
748 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
749
750#ifdef IN_GC
751 /* Safety check (in theory it could cross a page boundary and fault there though) */
752 AssertMsgReturn(pParam1 == pvFault, ("eip=%VGv, pParam1=%VGv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
753#endif
754 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
755 if (VBOX_FAILURE(rc))
756 {
757 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
758 return VERR_EM_INTERPRETER;
759 }
760 }
761 else
762 {
763 AssertFailed();
764 return VERR_EM_INTERPRETER;
765 }
766
767 /* Register or immediate data */
768 switch(param2.type)
769 {
770 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
771 valpar2 = param2.val.val32;
772 break;
773
774 default:
775 AssertFailed();
776 return VERR_EM_INTERPRETER;
777 }
778
779 /* Data read, emulate instruction. */
780 uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
781
782 /* Update guest's eflags and finish. */
783 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
784 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
785
786 /* And write it back */
787 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
788 if (VBOX_SUCCESS(rc))
789 {
790 /* All done! */
791 *pcbSize = param2.size;
792 return VINF_SUCCESS;
793 }
794#ifdef IN_GC
795 }
796 }
797#endif
798 return VERR_EM_INTERPRETER;
799}
800
801#ifdef IN_GC
802/**
803 * LOCK XOR/OR/AND Emulation.
804 */
805static int emInterpretLockOrXorAnd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault,
806 uint32_t *pcbSize, PFNEMULATELOCKPARAM3 pfnEmulate)
807{
808 OP_PARAMVAL param1, param2;
809 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
810 if(VBOX_FAILURE(rc))
811 return VERR_EM_INTERPRETER;
812
813 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
814 if(VBOX_FAILURE(rc))
815 return VERR_EM_INTERPRETER;
816
817 if (pCpu->param1.size != pCpu->param2.size)
818 {
819 AssertMsgReturn(pCpu->param1.size >= pCpu->param2.size, /* should never happen! */
820 ("%s at %VGv parameter mismatch %d vs %d!!\n", emGetMnemonic(pCpu), pRegFrame->eip, pCpu->param1.size, pCpu->param2.size),
821 VERR_EM_INTERPRETER);
822
823 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
824 pCpu->param2.size = pCpu->param1.size;
825 param2.size = param1.size;
826 }
827
828 /* The destination is always a virtual address */
829 AssertReturn(param1.type == PARMTYPE_ADDRESS, VERR_EM_INTERPRETER);
830 RTGCPTR GCPtrPar1 = (RTGCPTR)param1.val.val32;
831 GCPtrPar1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, GCPtrPar1);
832
833# ifdef IN_GC
834 /* Safety check (in theory it could cross a page boundary and fault there though) */
835 Assert( TRPMHasTrap(pVM)
836 && (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW));
837 AssertMsgReturn(GCPtrPar1 == pvFault, ("eip=%VGv, GCPtrPar1=%VGv pvFault=%VGv\n", pRegFrame->eip, GCPtrPar1, pvFault), VERR_EM_INTERPRETER);
838# endif
839
840 /* Register and immediate data == PARMTYPE_IMMEDIATE */
841 AssertReturn(param2.type == PARMTYPE_IMMEDIATE, VERR_EM_INTERPRETER);
842 RTGCUINTREG32 ValPar2 = param2.val.val32;
843
844 /* Try emulate it with a one-shot #PF handler in place. */
845 Log2(("%s %RGv imm%d=%RGr\n", emGetMnemonic(pCpu), GCPtrPar1, pCpu->param2.size*8, ValPar2));
846
847 RTGCUINTREG32 eflags = 0;
848 MMGCRamRegisterTrapHandler(pVM);
849 rc = pfnEmulate((RTRCPTR)GCPtrPar1, ValPar2, pCpu->param2.size, &eflags);
850 MMGCRamDeregisterTrapHandler(pVM);
851
852 if (RT_FAILURE(rc))
853 {
854 Log(("%s %RGv imm%d=%RGr -> emulation failed due to page fault!\n", emGetMnemonic(pCpu), GCPtrPar1, pCpu->param2.size*8, ValPar2));
855 return VERR_EM_INTERPRETER;
856 }
857
858 /* Update guest's eflags and finish. */
859 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
860 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
861
862 *pcbSize = param2.size;
863 return VINF_SUCCESS;
864}
865#endif
866
867/**
868 * ADD, ADC & SUB Emulation.
869 */
870static int emInterpretAddSub(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
871 PFN_EMULATE_PARAM3 pfnEmulate)
872{
873 OP_PARAMVAL param1, param2;
874 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
875 if(VBOX_FAILURE(rc))
876 return VERR_EM_INTERPRETER;
877
878 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
879 if(VBOX_FAILURE(rc))
880 return VERR_EM_INTERPRETER;
881
882#ifdef LOG_ENABLED
883 const char *pszInstr;
884
885 if (pCpu->pCurInstr->opcode == OP_SUB)
886 pszInstr = "Sub";
887 else if (pCpu->pCurInstr->opcode == OP_ADD)
888 pszInstr = "Add";
889 else if (pCpu->pCurInstr->opcode == OP_ADC)
890 pszInstr = "Adc";
891 else
892 pszInstr = "AddSub??";
893#endif
894
895#ifdef IN_GC
896 if (TRPMHasTrap(pVM))
897 {
898 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
899 {
900#endif
901 RTGCPTR pParam1;
902 uint32_t valpar1, valpar2;
903
904 if (pCpu->param1.size != pCpu->param2.size)
905 {
906 if (pCpu->param1.size < pCpu->param2.size)
907 {
908 AssertMsgFailed(("%s at %VGv parameter mismatch %d vs %d!!\n", pszInstr, pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
909 return VERR_EM_INTERPRETER;
910 }
911 /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
912 pCpu->param2.size = pCpu->param1.size;
913 param2.size = param1.size;
914 }
915
916 /* The destination is always a virtual address */
917 if (param1.type == PARMTYPE_ADDRESS)
918 {
919 pParam1 = (RTGCPTR)param1.val.val32;
920 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
921
922#ifdef IN_GC
923 /* Safety check (in theory it could cross a page boundary and fault there though) */
924 AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
925#endif
926 rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
927 if (VBOX_FAILURE(rc))
928 {
929 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
930 return VERR_EM_INTERPRETER;
931 }
932 }
933 else
934 {
935#ifndef DEBUG_bird
936 AssertFailed();
937#endif
938 return VERR_EM_INTERPRETER;
939 }
940
941 /* Register or immediate data */
942 switch(param2.type)
943 {
944 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
945 valpar2 = param2.val.val32;
946 break;
947
948 default:
949 AssertFailed();
950 return VERR_EM_INTERPRETER;
951 }
952
953 /* Data read, emulate instruction. */
954 uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
955
956 /* Update guest's eflags and finish. */
957 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
958 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
959
960 /* And write it back */
961 rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
962 if (VBOX_SUCCESS(rc))
963 {
964 /* All done! */
965 *pcbSize = param2.size;
966 return VINF_SUCCESS;
967 }
968#ifdef IN_GC
969 }
970 }
971#endif
972 return VERR_EM_INTERPRETER;
973}
974
975/**
976 * ADC Emulation.
977 */
978static int emInterpretAdc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
979{
980 if (pRegFrame->eflags.Bits.u1CF)
981 return emInterpretAddSub(pVM, pCpu, pRegFrame, pvFault, pcbSize, EMEmulateAdcWithCarrySet);
982 else
983 return emInterpretAddSub(pVM, pCpu, pRegFrame, pvFault, pcbSize, EMEmulateAdd);
984}
985
986/**
987 * BTR/C/S Emulation.
988 */
989static int emInterpretBitTest(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
990 PFN_EMULATE_PARAM2_UINT32 pfnEmulate)
991{
992 OP_PARAMVAL param1, param2;
993 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
994 if(VBOX_FAILURE(rc))
995 return VERR_EM_INTERPRETER;
996
997 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
998 if(VBOX_FAILURE(rc))
999 return VERR_EM_INTERPRETER;
1000
1001#ifdef LOG_ENABLED
1002 const char *pszInstr;
1003
1004 if (pCpu->pCurInstr->opcode == OP_BTR)
1005 pszInstr = "Btr";
1006 else if (pCpu->pCurInstr->opcode == OP_BTS)
1007 pszInstr = "Bts";
1008 else if (pCpu->pCurInstr->opcode == OP_BTC)
1009 pszInstr = "Btc";
1010 else
1011 pszInstr = "Bit??";
1012#endif
1013
1014#ifdef IN_GC
1015 if (TRPMHasTrap(pVM))
1016 {
1017 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1018 {
1019#endif
1020 RTGCPTR pParam1;
1021 uint32_t valpar1 = 0, valpar2;
1022 uint32_t eflags;
1023
1024 /* The destination is always a virtual address */
1025 if (param1.type != PARMTYPE_ADDRESS)
1026 return VERR_EM_INTERPRETER;
1027
1028 pParam1 = (RTGCPTR)param1.val.val32;
1029 pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
1030
1031 /* Register or immediate data */
1032 switch(param2.type)
1033 {
1034 case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
1035 valpar2 = param2.val.val32;
1036 break;
1037
1038 default:
1039 AssertFailed();
1040 return VERR_EM_INTERPRETER;
1041 }
1042
1043 Log2(("emInterpret%s: pvFault=%VGv pParam1=%VGv val2=%x\n", pszInstr, pvFault, pParam1, valpar2));
1044 pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + valpar2/8);
1045#ifdef IN_GC
1046 /* Safety check. */
1047 AssertMsgReturn((RTGCPTR)((RTGCUINTPTR)pParam1 & ~3) == pvFault, ("pParam1=%VGv pvFault=%VGv\n", pParam1, pvFault), VERR_EM_INTERPRETER);
1048#endif
1049 rc = emRamRead(pVM, &valpar1, pParam1, 1);
1050 if (VBOX_FAILURE(rc))
1051 {
1052 AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
1053 return VERR_EM_INTERPRETER;
1054 }
1055
1056 Log2(("emInterpretBtx: val=%x\n", valpar1));
1057 /* Data read, emulate bit test instruction. */
1058 eflags = pfnEmulate(&valpar1, valpar2 & 0x7);
1059
1060 Log2(("emInterpretBtx: val=%x CF=%d\n", valpar1, !!(eflags & X86_EFL_CF)));
1061
1062 /* Update guest's eflags and finish. */
1063 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1064 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1065
1066 /* And write it back */
1067 rc = emRamWrite(pVM, pParam1, &valpar1, 1);
1068 if (VBOX_SUCCESS(rc))
1069 {
1070 /* All done! */
1071 *pcbSize = 1;
1072 return VINF_SUCCESS;
1073 }
1074#ifdef IN_GC
1075 }
1076 }
1077#endif
1078 return VERR_EM_INTERPRETER;
1079}
1080
1081#ifdef IN_GC
1082/**
1083 * LOCK BTR/C/S Emulation.
1084 */
1085static int emInterpretLockBitTest(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault,
1086 uint32_t *pcbSize, PFNEMULATELOCKPARAM2 pfnEmulate)
1087{
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.val32;
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 OP_PARAMVAL param1, param2;
1150 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_DEST);
1151 if(VBOX_FAILURE(rc))
1152 return VERR_EM_INTERPRETER;
1153
1154 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
1155 if(VBOX_FAILURE(rc))
1156 return VERR_EM_INTERPRETER;
1157
1158#ifdef IN_GC
1159 if (TRPMHasTrap(pVM))
1160 {
1161 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1162 {
1163#else
1164 /** @todo Make this the default and don't rely on TRPM information. */
1165 if (param1.type == PARMTYPE_ADDRESS)
1166 {
1167#endif
1168 RTGCPTR pDest;
1169 uint32_t val32;
1170
1171 switch(param1.type)
1172 {
1173 case PARMTYPE_IMMEDIATE:
1174 if(!(param1.flags & PARAM_VAL32))
1175 return VERR_EM_INTERPRETER;
1176 /* fallthru */
1177
1178 case PARMTYPE_ADDRESS:
1179 pDest = (RTGCPTR)param1.val.val32;
1180 pDest = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pDest);
1181 break;
1182
1183 default:
1184 AssertFailed();
1185 return VERR_EM_INTERPRETER;
1186 }
1187
1188 switch(param2.type)
1189 {
1190 case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
1191 val32 = param2.val.val32;
1192 break;
1193
1194 default:
1195 Log(("emInterpretMov: unexpected type=%d eip=%VRv\n", param2.type, pRegFrame->eip));
1196 return VERR_EM_INTERPRETER;
1197 }
1198 LogFlow(("EMInterpretInstruction at %08x: OP_MOV %VGv <- %08X (%d) &val32=%08x\n", pRegFrame->eip, pDest, val32, param2.size, &val32));
1199
1200 Assert(param2.size <= 4 && param2.size > 0);
1201
1202#if 0 /* CSAM/PATM translates aliases which causes this to incorrectly trigger. See #2609 and #1498. */
1203#ifdef IN_GC
1204 /* Safety check (in theory it could cross a page boundary and fault there though) */
1205 AssertMsgReturn(pDest == pvFault, ("eip=%VGv pDest=%VGv pvFault=%VGv\n", pRegFrame->eip, pDest, pvFault), VERR_EM_INTERPRETER);
1206#endif
1207#endif
1208 rc = emRamWrite(pVM, pDest, &val32, param2.size);
1209 if (VBOX_FAILURE(rc))
1210 return VERR_EM_INTERPRETER;
1211
1212 *pcbSize = param2.size;
1213 }
1214 else
1215 { /* read fault */
1216 RTGCPTR pSrc;
1217 uint32_t val32;
1218
1219 /* Source */
1220 switch(param2.type)
1221 {
1222 case PARMTYPE_IMMEDIATE:
1223 if(!(param2.flags & PARAM_VAL32))
1224 return VERR_EM_INTERPRETER;
1225 /* fallthru */
1226
1227 case PARMTYPE_ADDRESS:
1228 pSrc = (RTGCPTR)param2.val.val32;
1229 pSrc = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param2, pSrc);
1230 break;
1231
1232 default:
1233 return VERR_EM_INTERPRETER;
1234 }
1235
1236 Assert(param1.size <= 4 && param1.size > 0);
1237#ifdef IN_GC
1238 /* Safety check (in theory it could cross a page boundary and fault there though) */
1239 AssertReturn(pSrc == pvFault, VERR_EM_INTERPRETER);
1240#endif
1241 rc = emRamRead(pVM, &val32, pSrc, param1.size);
1242 if (VBOX_FAILURE(rc))
1243 return VERR_EM_INTERPRETER;
1244
1245 /* Destination */
1246 switch(param1.type)
1247 {
1248 case PARMTYPE_REGISTER:
1249 switch(param1.size)
1250 {
1251 case 1: rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen, (uint8_t)val32); break;
1252 case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen, (uint16_t)val32); break;
1253 case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen, val32); break;
1254 default:
1255 return VERR_EM_INTERPRETER;
1256 }
1257 if (VBOX_FAILURE(rc))
1258 return rc;
1259 break;
1260
1261 default:
1262 return VERR_EM_INTERPRETER;
1263 }
1264 LogFlow(("EMInterpretInstruction: OP_MOV %VGv -> %08X (%d)\n", pSrc, val32, param1.size));
1265 }
1266 return VINF_SUCCESS;
1267#ifdef IN_GC
1268 }
1269#endif
1270 return VERR_EM_INTERPRETER;
1271}
1272
1273/*
1274 * [LOCK] CMPXCHG emulation.
1275 */
1276#ifdef IN_GC
1277static int emInterpretCmpXchg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1278{
1279 OP_PARAMVAL param1, param2;
1280
1281#ifdef LOG_ENABLED
1282 const char *pszInstr;
1283
1284 if (pCpu->prefix & PREFIX_LOCK)
1285 pszInstr = "Lock CmpXchg";
1286 else
1287 pszInstr = "CmpXchg";
1288#endif
1289
1290 /* Source to make DISQueryParamVal read the register value - ugly hack */
1291 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1292 if(VBOX_FAILURE(rc))
1293 return VERR_EM_INTERPRETER;
1294
1295 rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, &param2, PARAM_SOURCE);
1296 if(VBOX_FAILURE(rc))
1297 return VERR_EM_INTERPRETER;
1298
1299 if (TRPMHasTrap(pVM))
1300 {
1301 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1302 {
1303 RTRCPTR pParam1;
1304 uint32_t valpar, eflags;
1305#ifdef VBOX_STRICT
1306 uint32_t valpar1 = 0; /// @todo used uninitialized...
1307#endif
1308
1309 AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
1310 switch(param1.type)
1311 {
1312 case PARMTYPE_ADDRESS:
1313 pParam1 = (RTRCPTR)param1.val.val32;
1314 pParam1 = (RTRCPTR)emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, (RTGCPTR)(RTRCUINTPTR)pParam1);
1315
1316 /* Safety check (in theory it could cross a page boundary and fault there though) */
1317 AssertMsgReturn(pParam1 == (RTRCPTR)pvFault, ("eip=%VRv pParam1=%VRv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
1318 break;
1319
1320 default:
1321 return VERR_EM_INTERPRETER;
1322 }
1323
1324 switch(param2.type)
1325 {
1326 case PARMTYPE_IMMEDIATE: /* register actually */
1327 valpar = param2.val.val32;
1328 break;
1329
1330 default:
1331 return VERR_EM_INTERPRETER;
1332 }
1333
1334 LogFlow(("%s %VRv=%08x eax=%08x %08x\n", pszInstr, pParam1, valpar1, pRegFrame->eax, valpar));
1335
1336 MMGCRamRegisterTrapHandler(pVM);
1337 if (pCpu->prefix & PREFIX_LOCK)
1338 rc = EMGCEmulateLockCmpXchg(pParam1, &pRegFrame->eax, valpar, pCpu->param2.size, &eflags);
1339 else
1340 rc = EMGCEmulateCmpXchg(pParam1, &pRegFrame->eax, valpar, pCpu->param2.size, &eflags);
1341 MMGCRamDeregisterTrapHandler(pVM);
1342
1343 if (VBOX_FAILURE(rc))
1344 {
1345 Log(("%s %VGv=%08x eax=%08x %08x -> emulation failed due to page fault!\n", pszInstr, pParam1, valpar1, pRegFrame->eax, valpar));
1346 return VERR_EM_INTERPRETER;
1347 }
1348
1349 LogFlow(("%s %VRv=%08x eax=%08x %08x ZF=%d\n", pszInstr, pParam1, valpar1, pRegFrame->eax, valpar, !!(eflags & X86_EFL_ZF)));
1350
1351 /* Update guest's eflags and finish. */
1352 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1353 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1354
1355 *pcbSize = param2.size;
1356 return VINF_SUCCESS;
1357 }
1358 }
1359 return VERR_EM_INTERPRETER;
1360}
1361
1362/*
1363 * [LOCK] CMPXCHG8B emulation.
1364 */
1365static int emInterpretCmpXchg8b(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1366{
1367 OP_PARAMVAL param1;
1368
1369#ifdef LOG_ENABLED
1370 const char *pszInstr;
1371
1372 if (pCpu->prefix & PREFIX_LOCK)
1373 pszInstr = "Lock CmpXchg8b";
1374 else
1375 pszInstr = "CmpXchg8b";
1376#endif
1377
1378 /* Source to make DISQueryParamVal read the register value - ugly hack */
1379 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1380 if(VBOX_FAILURE(rc))
1381 return VERR_EM_INTERPRETER;
1382
1383 if (TRPMHasTrap(pVM))
1384 {
1385 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1386 {
1387 RTRCPTR pParam1;
1388 uint32_t eflags;
1389
1390 AssertReturn(pCpu->param1.size == 8, VERR_EM_INTERPRETER);
1391 switch(param1.type)
1392 {
1393 case PARMTYPE_ADDRESS:
1394 pParam1 = (RTRCPTR)param1.val.val32;
1395 pParam1 = (RTRCPTR)emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, (RTGCPTR)(RTRCUINTPTR)pParam1);
1396
1397 /* Safety check (in theory it could cross a page boundary and fault there though) */
1398 AssertMsgReturn(pParam1 == (RTRCPTR)pvFault, ("eip=%VRv pParam1=%VRv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
1399 break;
1400
1401 default:
1402 return VERR_EM_INTERPRETER;
1403 }
1404
1405 LogFlow(("%s %VRv=%08x eax=%08x\n", pszInstr, pParam1, pRegFrame->eax));
1406
1407 MMGCRamRegisterTrapHandler(pVM);
1408 if (pCpu->prefix & PREFIX_LOCK)
1409 rc = EMGCEmulateLockCmpXchg8b(pParam1, &pRegFrame->eax, &pRegFrame->edx, pRegFrame->ebx, pRegFrame->ecx, &eflags);
1410 else
1411 rc = EMGCEmulateCmpXchg8b(pParam1, &pRegFrame->eax, &pRegFrame->edx, pRegFrame->ebx, pRegFrame->ecx, &eflags);
1412 MMGCRamDeregisterTrapHandler(pVM);
1413
1414 if (VBOX_FAILURE(rc))
1415 {
1416 Log(("%s %VGv=%08x eax=%08x -> emulation failed due to page fault!\n", pszInstr, pParam1, pRegFrame->eax));
1417 return VERR_EM_INTERPRETER;
1418 }
1419
1420 LogFlow(("%s %VGv=%08x eax=%08x ZF=%d\n", pszInstr, pParam1, pRegFrame->eax, !!(eflags & X86_EFL_ZF)));
1421
1422 /* Update guest's eflags and finish; note that *only* ZF is affected. */
1423 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_ZF))
1424 | (eflags & (X86_EFL_ZF));
1425
1426 *pcbSize = 8;
1427 return VINF_SUCCESS;
1428 }
1429 }
1430 return VERR_EM_INTERPRETER;
1431}
1432#endif
1433
1434/*
1435 * [LOCK] XADD emulation.
1436 */
1437#ifdef IN_GC
1438static int emInterpretXAdd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1439{
1440 OP_PARAMVAL param1;
1441 uint32_t *pParamReg2;
1442 size_t cbSizeParamReg2;
1443
1444 /* Source to make DISQueryParamVal read the register value - ugly hack */
1445 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1446 if(VBOX_FAILURE(rc))
1447 return VERR_EM_INTERPRETER;
1448
1449 rc = DISQueryParamRegPtr(pRegFrame, pCpu, &pCpu->param2, (void **)&pParamReg2, &cbSizeParamReg2);
1450 Assert(cbSizeParamReg2 <= 4);
1451 if(VBOX_FAILURE(rc))
1452 return VERR_EM_INTERPRETER;
1453
1454 if (TRPMHasTrap(pVM))
1455 {
1456 if (TRPMGetErrorCode(pVM) & X86_TRAP_PF_RW)
1457 {
1458 RTRCPTR pParam1;
1459 uint32_t eflags;
1460#ifdef VBOX_STRICT
1461 uint32_t valpar1 = 0; /// @todo used uninitialized...
1462#endif
1463
1464 AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
1465 switch(param1.type)
1466 {
1467 case PARMTYPE_ADDRESS:
1468 pParam1 = (RTRCPTR)param1.val.val32;
1469 pParam1 = (RTRCPTR)emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, (RTGCPTR)(RTRCUINTPTR)pParam1);
1470
1471 /* Safety check (in theory it could cross a page boundary and fault there though) */
1472 AssertMsgReturn(pParam1 == (RTRCPTR)pvFault, ("eip=%VRv pParam1=%VRv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
1473 break;
1474
1475 default:
1476 return VERR_EM_INTERPRETER;
1477 }
1478
1479 LogFlow(("XAdd %VRv=%08x reg=%08x\n", pParam1, *pParamReg2));
1480
1481 MMGCRamRegisterTrapHandler(pVM);
1482 if (pCpu->prefix & PREFIX_LOCK)
1483 rc = EMGCEmulateLockXAdd(pParam1, pParamReg2, cbSizeParamReg2, &eflags);
1484 else
1485 rc = EMGCEmulateXAdd(pParam1, pParamReg2, cbSizeParamReg2, &eflags);
1486 MMGCRamDeregisterTrapHandler(pVM);
1487
1488 if (VBOX_FAILURE(rc))
1489 {
1490 Log(("XAdd %VGv=%08x reg=%08x -> emulation failed due to page fault!\n", pParam1, valpar1, *pParamReg2));
1491 return VERR_EM_INTERPRETER;
1492 }
1493
1494 LogFlow(("XAdd %VGv=%08x reg=%08x ZF=%d\n", pParam1, valpar1, *pParamReg2, !!(eflags & X86_EFL_ZF)));
1495
1496 /* Update guest's eflags and finish. */
1497 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1498 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1499
1500 *pcbSize = cbSizeParamReg2;
1501 return VINF_SUCCESS;
1502 }
1503 }
1504 return VERR_EM_INTERPRETER;
1505}
1506#endif
1507
1508/**
1509 * Interpret IRET (currently only to V86 code)
1510 *
1511 * @returns VBox status code.
1512 * @param pVM The VM handle.
1513 * @param pRegFrame The register frame.
1514 *
1515 */
1516EMDECL(int) EMInterpretIret(PVM pVM, PCPUMCTXCORE pRegFrame)
1517{
1518 RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp;
1519 RTGCUINTPTR eip, cs, esp, ss, eflags, ds, es, fs, gs, uMask;
1520 int rc;
1521
1522 rc = emRamRead(pVM, &eip, (RTGCPTR)pIretStack , 4);
1523 rc |= emRamRead(pVM, &cs, (RTGCPTR)(pIretStack + 4), 4);
1524 rc |= emRamRead(pVM, &eflags, (RTGCPTR)(pIretStack + 8), 4);
1525 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1526 AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER);
1527
1528 rc |= emRamRead(pVM, &esp, (RTGCPTR)(pIretStack + 12), 4);
1529 rc |= emRamRead(pVM, &ss, (RTGCPTR)(pIretStack + 16), 4);
1530 rc |= emRamRead(pVM, &es, (RTGCPTR)(pIretStack + 20), 4);
1531 rc |= emRamRead(pVM, &ds, (RTGCPTR)(pIretStack + 24), 4);
1532 rc |= emRamRead(pVM, &fs, (RTGCPTR)(pIretStack + 28), 4);
1533 rc |= emRamRead(pVM, &gs, (RTGCPTR)(pIretStack + 32), 4);
1534 AssertRCReturn(rc, VERR_EM_INTERPRETER);
1535
1536 pRegFrame->eip = eip & 0xffff;
1537 pRegFrame->cs = cs;
1538
1539 /* Mask away all reserved bits */
1540 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;
1541 eflags &= uMask;
1542
1543#ifndef IN_RING0
1544 CPUMRawSetEFlags(pVM, pRegFrame, eflags);
1545#endif
1546 Assert((pRegFrame->eflags.u32 & (X86_EFL_IF|X86_EFL_IOPL)) == X86_EFL_IF);
1547
1548 pRegFrame->esp = esp;
1549 pRegFrame->ss = ss;
1550 pRegFrame->ds = ds;
1551 pRegFrame->es = es;
1552 pRegFrame->fs = fs;
1553 pRegFrame->gs = gs;
1554
1555 return VINF_SUCCESS;
1556}
1557
1558
1559/**
1560 * IRET Emulation.
1561 */
1562static int emInterpretIret(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1563{
1564 /* only allow direct calls to EMInterpretIret for now */
1565 return VERR_EM_INTERPRETER;
1566}
1567
1568/**
1569 * INVLPG Emulation.
1570 */
1571
1572/**
1573 * Interpret INVLPG
1574 *
1575 * @returns VBox status code.
1576 * @param pVM The VM handle.
1577 * @param pRegFrame The register frame.
1578 * @param pAddrGC Operand address
1579 *
1580 */
1581EMDECL(int) EMInterpretInvlpg(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC)
1582{
1583 int rc;
1584
1585 /** @todo is addr always a flat linear address or ds based
1586 * (in absence of segment override prefixes)????
1587 */
1588#ifdef IN_GC
1589 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1590 LogFlow(("GC: EMULATE: invlpg %08X\n", pAddrGC));
1591 rc = PGMGCInvalidatePage(pVM, pAddrGC);
1592#else
1593 rc = PGMInvalidatePage(pVM, pAddrGC);
1594#endif
1595 if (VBOX_SUCCESS(rc))
1596 return VINF_SUCCESS;
1597 Log(("PGMInvalidatePage %VGv returned %VGv (%d)\n", pAddrGC, rc, rc));
1598 Assert(rc == VERR_REM_FLUSHED_PAGES_OVERFLOW);
1599 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1600 return VERR_EM_INTERPRETER;
1601}
1602
1603static int emInterpretInvlPg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1604{
1605 OP_PARAMVAL param1;
1606 RTGCPTR addr;
1607
1608 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1609 if(VBOX_FAILURE(rc))
1610 return VERR_EM_INTERPRETER;
1611
1612 switch(param1.type)
1613 {
1614 case PARMTYPE_IMMEDIATE:
1615 case PARMTYPE_ADDRESS:
1616 if(!(param1.flags & PARAM_VAL32))
1617 return VERR_EM_INTERPRETER;
1618 addr = (RTGCPTR)param1.val.val32;
1619 break;
1620
1621 default:
1622 return VERR_EM_INTERPRETER;
1623 }
1624
1625 /** @todo is addr always a flat linear address or ds based
1626 * (in absence of segment override prefixes)????
1627 */
1628#ifdef IN_GC
1629 // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
1630 LogFlow(("GC: EMULATE: invlpg %08X\n", addr));
1631 rc = PGMGCInvalidatePage(pVM, addr);
1632#else
1633 rc = PGMInvalidatePage(pVM, addr);
1634#endif
1635 if (VBOX_SUCCESS(rc))
1636 return VINF_SUCCESS;
1637 /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
1638 return VERR_EM_INTERPRETER;
1639}
1640
1641/**
1642 * CPUID Emulation.
1643 */
1644
1645/**
1646 * Interpret CPUID given the parameters in the CPU context
1647 *
1648 * @returns VBox status code.
1649 * @param pVM The VM handle.
1650 * @param pRegFrame The register frame.
1651 *
1652 */
1653EMDECL(int) EMInterpretCpuId(PVM pVM, PCPUMCTXCORE pRegFrame)
1654{
1655 CPUMGetGuestCpuId(pVM, pRegFrame->eax, &pRegFrame->eax, &pRegFrame->ebx, &pRegFrame->ecx, &pRegFrame->edx);
1656 return VINF_SUCCESS;
1657}
1658
1659static int emInterpretCpuId(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1660{
1661 uint32_t iLeaf = pRegFrame->eax; NOREF(iLeaf);
1662
1663 int rc = EMInterpretCpuId(pVM, pRegFrame);
1664 Log(("Emulate: CPUID %x -> %08x %08x %08x %08x\n", iLeaf, pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx));
1665 return rc;
1666}
1667
1668/**
1669 * MOV CRx Emulation.
1670 */
1671
1672/**
1673 * Interpret CRx read
1674 *
1675 * @returns VBox status code.
1676 * @param pVM The VM handle.
1677 * @param pRegFrame The register frame.
1678 * @param DestRegGen General purpose register index (USE_REG_E**))
1679 * @param SrcRegCRx CRx register index (USE_REG_CR*)
1680 *
1681 */
1682EMDECL(int) EMInterpretCRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx)
1683{
1684 uint64_t val64;
1685
1686 int rc = CPUMGetGuestCRx(pVM, SrcRegCrx, &val64);
1687 AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER);
1688 /** @todo AMD64 */
1689 rc = DISWriteReg32(pRegFrame, DestRegGen, val64);
1690 if(VBOX_SUCCESS(rc))
1691 {
1692 LogFlow(("MOV_CR: gen32=%d CR=%d val=%VX64\n", DestRegGen, SrcRegCrx, val64));
1693 return VINF_SUCCESS;
1694 }
1695 return VERR_EM_INTERPRETER;
1696}
1697
1698
1699/**
1700 * Interpret LMSW
1701 *
1702 * @returns VBox status code.
1703 * @param pVM The VM handle.
1704 * @param u16Data LMSW source data.
1705 *
1706 */
1707EMDECL(int) EMInterpretLMSW(PVM pVM, uint16_t u16Data)
1708{
1709 uint32_t OldCr0 = CPUMGetGuestCR0(pVM);
1710
1711 /* don't use this path to go into protected mode! */
1712 Assert(OldCr0 & X86_CR0_PE);
1713 if (!(OldCr0 & X86_CR0_PE))
1714 return VERR_EM_INTERPRETER;
1715
1716 /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */
1717 uint32_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
1718 | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS));
1719
1720#ifdef IN_GC
1721 /* Need to change the hyper CR0? Doing it the lazy way then. */
1722 if ( (OldCr0 & (X86_CR0_AM | X86_CR0_WP))
1723 != (NewCr0 & (X86_CR0_AM | X86_CR0_WP)))
1724 {
1725 Log(("EMInterpretLMSW: CR0: %#x->%#x => R3\n", OldCr0, NewCr0));
1726 VM_FF_SET(pVM, VM_FF_TO_R3);
1727 }
1728#endif
1729
1730 return CPUMSetGuestCR0(pVM, NewCr0);
1731}
1732
1733
1734/**
1735 * Interpret CLTS
1736 *
1737 * @returns VBox status code.
1738 * @param pVM The VM handle.
1739 *
1740 */
1741EMDECL(int) EMInterpretCLTS(PVM pVM)
1742{
1743 uint32_t cr0 = CPUMGetGuestCR0(pVM);
1744 if (!(cr0 & X86_CR0_TS))
1745 return VINF_SUCCESS;
1746 return CPUMSetGuestCR0(pVM, cr0 & ~X86_CR0_TS);
1747}
1748
1749static int emInterpretClts(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1750{
1751 return EMInterpretCLTS(pVM);
1752}
1753
1754/**
1755 * Interpret CRx write
1756 *
1757 * @returns VBox status code.
1758 * @param pVM The VM handle.
1759 * @param pRegFrame The register frame.
1760 * @param DestRegCRx CRx register index (USE_REG_CR*)
1761 * @param SrcRegGen General purpose register index (USE_REG_E**))
1762 *
1763 */
1764EMDECL(int) EMInterpretCRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)
1765{
1766 uint32_t val32;
1767 uint32_t oldval;
1768/** @todo Clean up this mess. */
1769
1770/** @todo AMD64 */
1771 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1772 if (VBOX_SUCCESS(rc))
1773 {
1774 switch (DestRegCrx)
1775 {
1776 case USE_REG_CR0:
1777 oldval = CPUMGetGuestCR0(pVM);
1778#ifdef IN_GC
1779 /* CR0.WP and CR0.AM changes require a reschedule run in ring 3. */
1780 if ( (val32 & (X86_CR0_WP | X86_CR0_AM))
1781 != (oldval & (X86_CR0_WP | X86_CR0_AM)))
1782 return VERR_EM_INTERPRETER;
1783#endif
1784 CPUMSetGuestCR0(pVM, val32);
1785 val32 = CPUMGetGuestCR0(pVM);
1786 if ( (oldval & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
1787 != (val32 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))
1788 {
1789 /* global flush */
1790 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1791 AssertRCReturn(rc, rc);
1792 }
1793 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), CPUMGetGuestEFER(pVM));
1794
1795 case USE_REG_CR2:
1796 rc = CPUMSetGuestCR2(pVM, val32); AssertRC(rc);
1797 return VINF_SUCCESS;
1798
1799 case USE_REG_CR3:
1800 /* Reloading the current CR3 means the guest just wants to flush the TLBs */
1801 rc = CPUMSetGuestCR3(pVM, val32); AssertRC(rc);
1802 if (CPUMGetGuestCR0(pVM) & X86_CR0_PG)
1803 {
1804 /* flush */
1805 rc = PGMFlushTLB(pVM, val32, !(CPUMGetGuestCR4(pVM) & X86_CR4_PGE));
1806 AssertRCReturn(rc, rc);
1807 }
1808 return VINF_SUCCESS;
1809
1810 case USE_REG_CR4:
1811 oldval = CPUMGetGuestCR4(pVM);
1812 rc = CPUMSetGuestCR4(pVM, val32); AssertRC(rc);
1813 val32 = CPUMGetGuestCR4(pVM);
1814 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))
1815 != (val32 & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)))
1816 {
1817 /* global flush */
1818 rc = PGMFlushTLB(pVM, CPUMGetGuestCR3(pVM), true /* global */);
1819 AssertRCReturn(rc, rc);
1820 }
1821# ifdef IN_GC
1822 /* Feeling extremely lazy. */
1823 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))
1824 != (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)))
1825 {
1826 Log(("emInterpretMovCRx: CR4: %#x->%#x => R3\n", oldval, val32));
1827 VM_FF_SET(pVM, VM_FF_TO_R3);
1828 }
1829# endif
1830 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), CPUMGetGuestEFER(pVM));
1831
1832 default:
1833 AssertFailed();
1834 case USE_REG_CR1: /* illegal op */
1835 break;
1836 }
1837 }
1838 return VERR_EM_INTERPRETER;
1839}
1840
1841static int emInterpretMovCRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1842{
1843 if (pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_CR)
1844 return EMInterpretCRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen, pCpu->param2.base.reg_ctrl);
1845 if (pCpu->param1.flags == USE_REG_CR && pCpu->param2.flags == USE_REG_GEN32)
1846 return EMInterpretCRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_ctrl, pCpu->param2.base.reg_gen);
1847 AssertMsgFailedReturn(("Unexpected control register move\n"), VERR_EM_INTERPRETER);
1848 return VERR_EM_INTERPRETER;
1849}
1850
1851/**
1852 * MOV DRx
1853 */
1854
1855/**
1856 * Interpret DRx write
1857 *
1858 * @returns VBox status code.
1859 * @param pVM The VM handle.
1860 * @param pRegFrame The register frame.
1861 * @param DestRegDRx DRx register index (USE_REG_DR*)
1862 * @param SrcRegGen General purpose register index (USE_REG_E**))
1863 *
1864 */
1865EMDECL(int) EMInterpretDRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)
1866{
1867 uint32_t val32;
1868
1869 int rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);
1870 if (VBOX_SUCCESS(rc))
1871 {
1872 rc = CPUMSetGuestDRx(pVM, DestRegDrx, val32);
1873 if (VBOX_SUCCESS(rc))
1874 return rc;
1875 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx));
1876 }
1877 return VERR_EM_INTERPRETER;
1878}
1879
1880/**
1881 * Interpret DRx read
1882 *
1883 * @returns VBox status code.
1884 * @param pVM The VM handle.
1885 * @param pRegFrame The register frame.
1886 * @param DestRegGen General purpose register index (USE_REG_E**))
1887 * @param SrcRegDRx DRx register index (USE_REG_DR*)
1888 *
1889 */
1890EMDECL(int) EMInterpretDRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)
1891{
1892 uint64_t val64;
1893
1894 int rc = CPUMGetGuestDRx(pVM, SrcRegDrx, &val64);
1895 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER);
1896 rc = DISWriteReg32(pRegFrame, DestRegGen, (uint32_t)val64);
1897 if (VBOX_SUCCESS(rc))
1898 return VINF_SUCCESS;
1899 return VERR_EM_INTERPRETER;
1900}
1901
1902static int emInterpretMovDRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1903{
1904 int rc = VERR_EM_INTERPRETER;
1905
1906 if(pCpu->param1.flags == USE_REG_GEN32 && pCpu->param2.flags == USE_REG_DBG)
1907 {
1908 rc = EMInterpretDRxRead(pVM, pRegFrame, pCpu->param1.base.reg_gen, pCpu->param2.base.reg_dbg);
1909 }
1910 else
1911 if(pCpu->param1.flags == USE_REG_DBG && pCpu->param2.flags == USE_REG_GEN32)
1912 {
1913 rc = EMInterpretDRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_dbg, pCpu->param2.base.reg_gen);
1914 }
1915 else
1916 AssertMsgFailed(("Unexpected debug register move\n"));
1917 return rc;
1918}
1919
1920/**
1921 * LLDT Emulation.
1922 */
1923static int emInterpretLLdt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1924{
1925 OP_PARAMVAL param1;
1926 RTSEL sel;
1927
1928 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1929 if(VBOX_FAILURE(rc))
1930 return VERR_EM_INTERPRETER;
1931
1932 switch(param1.type)
1933 {
1934 case PARMTYPE_ADDRESS:
1935 return VERR_EM_INTERPRETER; //feeling lazy right now
1936
1937 case PARMTYPE_IMMEDIATE:
1938 if(!(param1.flags & PARAM_VAL16))
1939 return VERR_EM_INTERPRETER;
1940 sel = (RTSEL)param1.val.val16;
1941 break;
1942
1943 default:
1944 return VERR_EM_INTERPRETER;
1945 }
1946
1947 if (sel == 0)
1948 {
1949 if (CPUMGetHyperLDTR(pVM) == 0)
1950 {
1951 // this simple case is most frequent in Windows 2000 (31k - boot & shutdown)
1952 return VINF_SUCCESS;
1953 }
1954 }
1955 //still feeling lazy
1956 return VERR_EM_INTERPRETER;
1957}
1958
1959#ifdef IN_GC
1960/**
1961 * STI Emulation.
1962 *
1963 * @remark the instruction following sti is guaranteed to be executed before any interrupts are dispatched
1964 */
1965static int emInterpretSti(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1966{
1967 PPATMGCSTATE pGCState = PATMQueryGCState(pVM);
1968
1969 if(!pGCState)
1970 {
1971 Assert(pGCState);
1972 return VERR_EM_INTERPRETER;
1973 }
1974 pGCState->uVMFlags |= X86_EFL_IF;
1975
1976 Assert(pRegFrame->eflags.u32 & X86_EFL_IF);
1977 Assert(pvFault == SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip));
1978
1979 pVM->em.s.GCPtrInhibitInterrupts = pRegFrame->eip + pCpu->opsize;
1980 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
1981
1982 return VINF_SUCCESS;
1983}
1984#endif /* IN_GC */
1985
1986
1987/**
1988 * HLT Emulation.
1989 */
1990static int emInterpretHlt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
1991{
1992 return VINF_EM_HALT;
1993}
1994
1995
1996/**
1997 * RDTSC Emulation.
1998 */
1999
2000/**
2001 * Interpret RDTSC
2002 *
2003 * @returns VBox status code.
2004 * @param pVM The VM handle.
2005 * @param pRegFrame The register frame.
2006 *
2007 */
2008EMDECL(int) EMInterpretRdtsc(PVM pVM, PCPUMCTXCORE pRegFrame)
2009{
2010 unsigned uCR4 = CPUMGetGuestCR4(pVM);
2011
2012 if (uCR4 & X86_CR4_TSD)
2013 return VERR_EM_INTERPRETER; /* genuine #GP */
2014
2015 uint64_t uTicks = TMCpuTickGet(pVM);
2016
2017 pRegFrame->eax = uTicks;
2018 pRegFrame->edx = (uTicks >> 32ULL);
2019
2020 return VINF_SUCCESS;
2021}
2022
2023static int emInterpretRdtsc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2024{
2025 return EMInterpretRdtsc(pVM, pRegFrame);
2026}
2027
2028/**
2029 * MONITOR Emulation.
2030 */
2031static int emInterpretMonitor(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2032{
2033 uint32_t u32Dummy, u32ExtFeatures, cpl;
2034
2035 if (pRegFrame->ecx != 0)
2036 return VERR_EM_INTERPRETER; /* illegal value. */
2037
2038 /* Get the current privilege level. */
2039 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
2040 if (cpl != 0)
2041 return VERR_EM_INTERPRETER; /* supervisor only */
2042
2043 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
2044 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
2045 return VERR_EM_INTERPRETER; /* not supported */
2046
2047 return VINF_SUCCESS;
2048}
2049
2050
2051/**
2052 * MWAIT Emulation.
2053 */
2054static int emInterpretMWait(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2055{
2056 uint32_t u32Dummy, u32ExtFeatures, cpl;
2057
2058 if (pRegFrame->ecx != 0)
2059 return VERR_EM_INTERPRETER; /* illegal value. */
2060
2061 /* Get the current privilege level. */
2062 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
2063 if (cpl != 0)
2064 return VERR_EM_INTERPRETER; /* supervisor only */
2065
2066 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);
2067 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))
2068 return VERR_EM_INTERPRETER; /* not supported */
2069
2070 /** @todo not completely correct */
2071 return VINF_EM_HALT;
2072}
2073
2074/**
2075 * Interpret RDMSR
2076 *
2077 * @returns VBox status code.
2078 * @param pVM The VM handle.
2079 * @param pRegFrame The register frame.
2080 *
2081 */
2082EMDECL(int) EMInterpretRdmsr(PVM pVM, PCPUMCTXCORE pRegFrame)
2083{
2084 uint32_t u32Dummy, u32Features, cpl;
2085 uint64_t val;
2086 CPUMCTX *pCtx;
2087 int rc;
2088
2089 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);
2090 AssertRC(rc);
2091
2092 /* Get the current privilege level. */
2093 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
2094 if (cpl != 0)
2095 return VERR_EM_INTERPRETER; /* supervisor only */
2096
2097 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32Dummy, &u32Features);
2098 if (!(u32Features & X86_CPUID_FEATURE_EDX_MSR))
2099 return VERR_EM_INTERPRETER; /* not supported */
2100
2101 switch (pRegFrame->ecx)
2102 {
2103 case MSR_IA32_APICBASE:
2104 rc = PDMApicGetBase(pVM, &val);
2105 AssertRC(rc);
2106 break;
2107
2108 case MSR_IA32_CR_PAT:
2109 val = pCtx->msrPAT;
2110 break;
2111
2112 case MSR_IA32_SYSENTER_CS:
2113 val = pCtx->SysEnter.cs;
2114 break;
2115
2116 case MSR_IA32_SYSENTER_EIP:
2117 val = pCtx->SysEnter.eip;
2118 break;
2119
2120 case MSR_IA32_SYSENTER_ESP:
2121 val = pCtx->SysEnter.esp;
2122 break;
2123
2124 case MSR_K6_EFER:
2125 val = pCtx->msrEFER;
2126 break;
2127
2128 case MSR_K8_SF_MASK:
2129 val = pCtx->msrSFMASK;
2130 break;
2131
2132 case MSR_K6_STAR:
2133 val = pCtx->msrSTAR;
2134 break;
2135
2136 case MSR_K8_LSTAR:
2137 val = pCtx->msrLSTAR;
2138 break;
2139
2140 case MSR_K8_CSTAR:
2141 val = pCtx->msrCSTAR;
2142 break;
2143
2144 case MSR_K8_FS_BASE:
2145 val = pCtx->msrFSBASE;
2146 break;
2147
2148 case MSR_K8_GS_BASE:
2149 val = pCtx->msrGSBASE;
2150 break;
2151
2152 case MSR_K8_KERNEL_GS_BASE:
2153 val = pCtx->msrKERNELGSBASE;
2154 break;
2155
2156 default:
2157 /* We should actually trigger a #GP here, but don't as that might cause more trouble. */
2158 val = 0;
2159 break;
2160 }
2161 Log(("EMInterpretRdmsr %x -> val=%VX64\n", pRegFrame->ecx, val));
2162 pRegFrame->eax = (uint32_t) val;
2163 pRegFrame->edx = (uint32_t) (val >> 32ULL);
2164 return VINF_SUCCESS;
2165}
2166
2167/**
2168 * RDMSR Emulation.
2169 */
2170static int emInterpretRdmsr(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2171{
2172 return EMInterpretRdmsr(pVM, pRegFrame);
2173}
2174
2175/**
2176 * Interpret WRMSR
2177 *
2178 * @returns VBox status code.
2179 * @param pVM The VM handle.
2180 * @param pRegFrame The register frame.
2181 *
2182 */
2183EMDECL(int) EMInterpretWrmsr(PVM pVM, PCPUMCTXCORE pRegFrame)
2184{
2185 uint32_t u32Dummy, u32Features, cpl;
2186 uint64_t val;
2187 CPUMCTX *pCtx;
2188 int rc;
2189
2190 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);
2191 AssertRC(rc);
2192
2193 /* Get the current privilege level. */
2194 cpl = CPUMGetGuestCPL(pVM, pRegFrame);
2195 if (cpl != 0)
2196 return VERR_EM_INTERPRETER; /* supervisor only */
2197
2198 CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &u32Dummy, &u32Features);
2199 if (!(u32Features & X86_CPUID_FEATURE_EDX_MSR))
2200 return VERR_EM_INTERPRETER; /* not supported */
2201
2202 val = (uint64_t)pRegFrame->eax | ((uint64_t)pRegFrame->edx << 32ULL);
2203 Log(("EMInterpretWrmsr %x val=%VX64\n", pRegFrame->ecx, val));
2204 switch (pRegFrame->ecx)
2205 {
2206 case MSR_IA32_APICBASE:
2207 rc = PDMApicSetBase(pVM, val);
2208 AssertRC(rc);
2209 break;
2210
2211 case MSR_IA32_CR_PAT:
2212 pCtx->msrPAT = val;
2213 break;
2214
2215 case MSR_IA32_SYSENTER_CS:
2216 pCtx->SysEnter.cs = val;
2217 break;
2218
2219 case MSR_IA32_SYSENTER_EIP:
2220 pCtx->SysEnter.eip = val;
2221 break;
2222
2223 case MSR_IA32_SYSENTER_ESP:
2224 pCtx->SysEnter.esp = val;
2225 break;
2226
2227 case MSR_K6_EFER:
2228 AssertFailed();
2229 pCtx->msrEFER = val;
2230 break;
2231
2232 case MSR_K8_SF_MASK:
2233 pCtx->msrSFMASK = val;
2234 break;
2235
2236 case MSR_K6_STAR:
2237 pCtx->msrSTAR = val;
2238 break;
2239
2240 case MSR_K8_LSTAR:
2241 pCtx->msrLSTAR = val;
2242 break;
2243
2244 case MSR_K8_CSTAR:
2245 pCtx->msrCSTAR = val;
2246 break;
2247
2248 case MSR_K8_FS_BASE:
2249 pCtx->msrFSBASE = val;
2250 break;
2251
2252 case MSR_K8_GS_BASE:
2253 pCtx->msrGSBASE = val;
2254 break;
2255
2256 case MSR_K8_KERNEL_GS_BASE:
2257 pCtx->msrKERNELGSBASE = val;
2258 break;
2259
2260 default:
2261 /* We should actually trigger a #GP here, but don't as that might cause more trouble. */
2262 break;
2263 }
2264 return VINF_SUCCESS;
2265}
2266
2267/**
2268 * WRMSR Emulation.
2269 */
2270static int emInterpretWrmsr(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2271{
2272 return EMInterpretWrmsr(pVM, pRegFrame);
2273}
2274
2275/**
2276 * Internal worker.
2277 * @copydoc EMInterpretInstructionCPU
2278 */
2279DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
2280{
2281 Assert(pcbSize);
2282 *pcbSize = 0;
2283
2284 /*
2285 * Only supervisor guest code!!
2286 * And no complicated prefixes.
2287 */
2288 /* Get the current privilege level. */
2289 uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
2290 if ( cpl != 0
2291 && pCpu->pCurInstr->opcode != OP_RDTSC) /* rdtsc requires emulation in ring 3 as well */
2292 {
2293 Log(("WARNING: refusing instruction emulation for user-mode code!!\n"));
2294 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedUserMode));
2295 return VERR_EM_INTERPRETER;
2296 }
2297
2298#ifdef IN_GC
2299 if ( (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP))
2300 || ( (pCpu->prefix & PREFIX_LOCK)
2301 && pCpu->pCurInstr->opcode != OP_CMPXCHG
2302 && pCpu->pCurInstr->opcode != OP_CMPXCHG8B
2303 && pCpu->pCurInstr->opcode != OP_XADD
2304 && pCpu->pCurInstr->opcode != OP_OR
2305 && pCpu->pCurInstr->opcode != OP_BTR
2306 )
2307 )
2308#else
2309 if (pCpu->prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_LOCK))
2310#endif
2311 {
2312 //Log(("EMInterpretInstruction: wrong prefix!!\n"));
2313 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedPrefix));
2314 return VERR_EM_INTERPRETER;
2315 }
2316
2317 int rc;
2318#if defined(IN_GC) && (defined(VBOX_STRICT) || defined(LOG_ENABLED))
2319 LogFlow(("emInterpretInstructionCPU %s\n", emGetMnemonic(pCpu)));
2320#endif
2321 switch (pCpu->pCurInstr->opcode)
2322 {
2323#ifdef IN_GC
2324# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
2325 case opcode:\
2326 if (pCpu->prefix & PREFIX_LOCK) \
2327 rc = emInterpretLock##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulateLock); \
2328 else \
2329 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulate); \
2330 if (VBOX_SUCCESS(rc)) \
2331 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
2332 else \
2333 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
2334 return rc
2335#else
2336# define INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
2337 INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate)
2338#endif
2339#define INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate) \
2340 case opcode:\
2341 rc = emInterpret##InstrFn(pVM, pCpu, pRegFrame, pvFault, pcbSize, pfnEmulate); \
2342 if (VBOX_SUCCESS(rc)) \
2343 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
2344 else \
2345 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
2346 return rc
2347
2348#define INTERPRET_CASE_EX_PARAM2(opcode, Instr, InstrFn, pfnEmulate) \
2349 INTERPRET_CASE_EX_PARAM3(opcode, Instr, InstrFn, pfnEmulate)
2350#define INTERPRET_CASE_EX_LOCK_PARAM2(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock) \
2351 INTERPRET_CASE_EX_LOCK_PARAM3(opcode, Instr, InstrFn, pfnEmulate, pfnEmulateLock)
2352
2353#define INTERPRET_CASE(opcode, Instr) \
2354 case opcode:\
2355 rc = emInterpret##Instr(pVM, pCpu, pRegFrame, pvFault, pcbSize); \
2356 if (VBOX_SUCCESS(rc)) \
2357 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Instr)); \
2358 else \
2359 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); \
2360 return rc
2361#define INTERPRET_STAT_CASE(opcode, Instr) \
2362 case opcode: STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); return VERR_EM_INTERPRETER;
2363
2364 INTERPRET_CASE(OP_XCHG,Xchg);
2365 INTERPRET_CASE_EX_PARAM2(OP_DEC,Dec, IncDec, EMEmulateDec);
2366 INTERPRET_CASE_EX_PARAM2(OP_INC,Inc, IncDec, EMEmulateInc);
2367 INTERPRET_CASE(OP_POP,Pop);
2368 INTERPRET_CASE_EX_LOCK_PARAM3(OP_OR, Or, OrXorAnd, EMEmulateOr, EMEmulateLockOr);
2369 INTERPRET_CASE_EX_PARAM3(OP_XOR,Xor, OrXorAnd, EMEmulateXor);
2370 INTERPRET_CASE_EX_PARAM3(OP_AND,And, OrXorAnd, EMEmulateAnd);
2371 INTERPRET_CASE(OP_MOV,Mov);
2372 INTERPRET_CASE(OP_INVLPG,InvlPg);
2373 INTERPRET_CASE(OP_CPUID,CpuId);
2374 INTERPRET_CASE(OP_MOV_CR,MovCRx);
2375 INTERPRET_CASE(OP_MOV_DR,MovDRx);
2376 INTERPRET_CASE(OP_LLDT,LLdt);
2377 INTERPRET_CASE(OP_CLTS,Clts);
2378 INTERPRET_CASE(OP_MONITOR, Monitor);
2379 INTERPRET_CASE(OP_MWAIT, MWait);
2380#ifdef VBOX_WITH_MSR_EMULATION
2381 INTERPRET_CASE(OP_RDMSR, Rdmsr);
2382 INTERPRET_CASE(OP_WRMSR, Wrmsr);
2383#endif
2384 INTERPRET_CASE_EX_PARAM3(OP_ADD,Add, AddSub, EMEmulateAdd);
2385 INTERPRET_CASE_EX_PARAM3(OP_SUB,Sub, AddSub, EMEmulateSub);
2386 INTERPRET_CASE(OP_ADC,Adc);
2387 INTERPRET_CASE_EX_LOCK_PARAM2(OP_BTR,Btr, BitTest, EMEmulateBtr, EMEmulateLockBtr);
2388 INTERPRET_CASE_EX_PARAM2(OP_BTS,Bts, BitTest, EMEmulateBts);
2389 INTERPRET_CASE_EX_PARAM2(OP_BTC,Btc, BitTest, EMEmulateBtc);
2390 INTERPRET_CASE(OP_RDTSC,Rdtsc);
2391#ifdef IN_GC
2392 INTERPRET_CASE(OP_STI,Sti);
2393 INTERPRET_CASE(OP_CMPXCHG, CmpXchg);
2394 INTERPRET_CASE(OP_CMPXCHG8B, CmpXchg8b);
2395 INTERPRET_CASE(OP_XADD, XAdd);
2396#endif
2397 INTERPRET_CASE(OP_HLT,Hlt);
2398 INTERPRET_CASE(OP_IRET,Iret);
2399#ifdef VBOX_WITH_STATISTICS
2400#ifndef IN_GC
2401 INTERPRET_STAT_CASE(OP_CMPXCHG,CmpXchg);
2402 INTERPRET_STAT_CASE(OP_CMPXCHG8B, CmpXchg8b);
2403 INTERPRET_STAT_CASE(OP_XADD, XAdd);
2404#endif
2405 INTERPRET_STAT_CASE(OP_MOVNTPS,MovNTPS);
2406 INTERPRET_STAT_CASE(OP_STOSWD,StosWD);
2407 INTERPRET_STAT_CASE(OP_WBINVD,WbInvd);
2408#endif
2409 default:
2410 Log3(("emInterpretInstructionCPU: opcode=%d\n", pCpu->pCurInstr->opcode));
2411 STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,FailedMisc));
2412 return VERR_EM_INTERPRETER;
2413#undef INTERPRET_CASE_EX_PARAM2
2414#undef INTERPRET_STAT_CASE
2415#undef INTERPRET_CASE_EX
2416#undef INTERPRET_CASE
2417 }
2418 AssertFailed();
2419 return VERR_INTERNAL_ERROR;
2420}
2421
2422
2423/**
2424 * Sets the PC for which interrupts should be inhibited.
2425 *
2426 * @param pVM The VM handle.
2427 * @param PC The PC.
2428 */
2429EMDECL(void) EMSetInhibitInterruptsPC(PVM pVM, RTGCUINTPTR PC)
2430{
2431 pVM->em.s.GCPtrInhibitInterrupts = PC;
2432 VM_FF_SET(pVM, VM_FF_INHIBIT_INTERRUPTS);
2433}
2434
2435
2436/**
2437 * Gets the PC for which interrupts should be inhibited.
2438 *
2439 * There are a few instructions which inhibits or delays interrupts
2440 * for the instruction following them. These instructions are:
2441 * - STI
2442 * - MOV SS, r/m16
2443 * - POP SS
2444 *
2445 * @returns The PC for which interrupts should be inhibited.
2446 * @param pVM VM handle.
2447 *
2448 */
2449EMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVM pVM)
2450{
2451 return pVM->em.s.GCPtrInhibitInterrupts;
2452}
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