VirtualBox

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

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

Backed out 23986

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette