VirtualBox

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

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

Use PGMPhysRead/WriteGCPtrSafe to respect access handlers, set dirty/accessed bits and deal with crossing page boundaries.

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

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