VirtualBox

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

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

Corrected parameter types (const).
Use SELMToFlatEx instead of SELMValidateAndConvertCSAddr when disassembling instructions.
(the latter is too strict)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette