VirtualBox

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

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

string.h & stdio.h + header cleanups.

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