VirtualBox

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

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

cmpxchg8b only modifies ZF.

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