VirtualBox

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

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

drop a double prediction and some blanks.

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