VirtualBox

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

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

Disabled microcode version passthru. Code is sufficient to make sure Windows XP doesn't attempt to update the microcode (which we don't allow).

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