VirtualBox

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

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

Reduce the number of world switches caused by cr8 writes by checking if we really need to be notified. (only when
an interrupt is pending and masked by the TRP value)

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