VirtualBox

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

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

Compile fix

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