VirtualBox

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

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

corrected assertion

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