VirtualBox

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

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

Cleaned up disassembler

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