VirtualBox

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

Last change on this file since 2230 was 2136, checked in by vboxsync, 18 years ago

Drop the 32 bits code requirement from EMInterpretInstruction.

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