VirtualBox

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

Last change on this file since 2744 was 2554, checked in by vboxsync, 18 years ago

Added EMInterpretRdtsc

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