VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp@ 1507

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

SELM function changes for v86 mode code.
CPL check fixes for V86 mode code.

  • Property svn:keywords set to Id
File size: 45.2 KB
Line 
1/* $Id: IOMAllMMIO.cpp 1359 2007-03-09 10:40:44Z vboxsync $ */
2/** @file
3 * IOM - Input / Output Monitor - Guest Context.
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_IOM
27#include <VBox/iom.h>
28#include <VBox/cpum.h>
29#include <VBox/pgm.h>
30#include <VBox/selm.h>
31#include <VBox/mm.h>
32#include <VBox/em.h>
33#include <VBox/pgm.h>
34#include <VBox/trpm.h>
35#include "IOMInternal.h"
36#include <VBox/vm.h>
37
38#include <VBox/dis.h>
39#include <VBox/disopcode.h>
40#include <VBox/param.h>
41#include <VBox/err.h>
42#include <iprt/assert.h>
43#include <VBox/log.h>
44#include <iprt/asm.h>
45#include <iprt/string.h>
46
47#ifndef IN_RING3
48
49#ifndef IN_RING0
50/** @def IOMGC_MOVS_SUPPORT
51 * Define IOMGC_MOVS_SUPPORT for movsb/w/d support in GC.
52 */
53#define IOMGC_MOVS_SUPPORT
54#endif
55
56/*******************************************************************************
57* Internal Functions *
58*******************************************************************************/
59#if 0
60static bool iomGCCalcParamEA(PDISCPUSTATE pCpu, POP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, void **ppAddr);
61static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam);
62#endif
63static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize);
64static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t u32Data);
65
66
67/*******************************************************************************
68* Global Variables *
69*******************************************************************************/
70/**
71 * Array for accessing 32-bit general registers in VMMREGFRAME structure
72 * by register's index from disasm.
73 */
74static unsigned g_aReg32Index[] =
75{
76 RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_EAX */
77 RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_ECX */
78 RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_EDX */
79 RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_EBX */
80 RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_ESP */
81 RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_EBP */
82 RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_ESI */
83 RT_OFFSETOF(CPUMCTXCORE, edi) /* USE_REG_EDI */
84};
85
86/**
87 * Macro for accessing 32-bit general purpose registers in CPUMCTXCORE structure.
88 */
89#define ACCESS_REG32(p, idx) (*((uint32_t *)((char *)(p) + g_aReg32Index[idx])))
90
91/**
92 * Array for accessing 16-bit general registers in CPUMCTXCORE structure
93 * by register's index from disasm.
94 */
95static unsigned g_aReg16Index[] =
96{
97 RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AX */
98 RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CX */
99 RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DX */
100 RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BX */
101 RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_SP */
102 RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_BP */
103 RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_SI */
104 RT_OFFSETOF(CPUMCTXCORE, edi) /* USE_REG_DI */
105};
106
107/**
108 * Macro for accessing 16-bit general purpose registers in CPUMCTXCORE structure.
109 */
110#define ACCESS_REG16(p, idx) (*((uint16_t *)((char *)(p) + g_aReg16Index[idx])))
111
112/**
113 * Array for accessing 8-bit general registers in CPUMCTXCORE structure
114 * by register's index from disasm.
115 */
116static unsigned g_aReg8Index[] =
117{
118 RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AL */
119 RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CL */
120 RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DL */
121 RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BL */
122 RT_OFFSETOF(CPUMCTXCORE, eax) + 1, /* USE_REG_AH */
123 RT_OFFSETOF(CPUMCTXCORE, ecx) + 1, /* USE_REG_CH */
124 RT_OFFSETOF(CPUMCTXCORE, edx) + 1, /* USE_REG_DH */
125 RT_OFFSETOF(CPUMCTXCORE, ebx) + 1 /* USE_REG_BH */
126};
127
128/**
129 * Macro for accessing 8-bit general purpose registers in CPUMCTXCORE structure.
130 */
131#define ACCESS_REG8(p, idx) (*((uint8_t *)((char *)(p) + g_aReg8Index[idx])))
132
133/**
134 * Array for accessing segment registers in CPUMCTXCORE structure
135 * by register's index from disasm.
136 */
137static unsigned g_aRegSegIndex[] =
138{
139 RT_OFFSETOF(CPUMCTXCORE, es), /* USE_REG_ES */
140 RT_OFFSETOF(CPUMCTXCORE, cs), /* USE_REG_CS */
141 RT_OFFSETOF(CPUMCTXCORE, ss), /* USE_REG_SS */
142 RT_OFFSETOF(CPUMCTXCORE, ds), /* USE_REG_DS */
143 RT_OFFSETOF(CPUMCTXCORE, fs), /* USE_REG_FS */
144 RT_OFFSETOF(CPUMCTXCORE, gs) /* USE_REG_GS */
145};
146
147/**
148 * Macro for accessing segment registers in CPUMCTXCORE structure.
149 */
150#define ACCESS_REGSEG(p, idx) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])))
151
152/**
153 * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
154 */
155static const unsigned g_aSize2Shift[] =
156{
157 ~0, /* 0 - invalid */
158 0, /* *1 == 2^0 */
159 1, /* *2 == 2^1 */
160 ~0, /* 3 - invalid */
161 2, /* *4 == 2^2 */
162 ~0, /* 5 - invalid */
163 ~0, /* 6 - invalid */
164 ~0, /* 7 - invalid */
165 3 /* *8 == 2^3 */
166};
167
168/**
169 * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
170 */
171#define SIZE2SHIFT(cb) (g_aSize2Shift[cb])
172
173
174/**
175 * Wrapper which does the write and updates range statistics when such are enabled.
176 * @warning VBOX_SUCCESS(rc=VINF_IOM_HC_MMIO_WRITE) is TRUE!
177 */
178inline int iomGCMMIODoWrite(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, const void *pvData, unsigned cbSize)
179{
180#ifdef VBOX_WITH_STATISTICS
181 if (pRange->cbSize <= PAGE_SIZE)
182 {
183 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
184 if (!pStats)
185 return VINF_IOM_HC_MMIO_WRITE;
186
187 int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cbSize); /* @todo fix const!! */
188 if (rc != VINF_IOM_HC_MMIO_WRITE)
189 STAM_COUNTER_INC(&pStats->WriteGC);
190 return rc;
191 }
192#endif
193 return pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cbSize);
194}
195
196/**
197 * Wrapper which does the read and updates range statistics when such are enabled.
198 */
199inline int iomGCMMIODoRead(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, void *pvData, unsigned cbSize)
200{
201#ifdef VBOX_WITH_STATISTICS
202 if (pRange->cbSize <= PAGE_SIZE)
203 {
204 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
205 if (!pStats)
206 return VINF_IOM_HC_MMIO_READ;
207
208 int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cbSize);
209 if (rc != VINF_IOM_HC_MMIO_READ)
210 STAM_COUNTER_INC(&pStats->ReadGC);
211 return rc;
212 }
213#endif
214 return pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cbSize);
215}
216
217
218/**
219 * Returns the contents of register or immediate data of instruction's parameter.
220 *
221 * @returns true on success.
222 *
223 * @param pCpu Pointer to current disassembler context.
224 * @param pParam Pointer to parameter of instruction to proccess.
225 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
226 * @param pu32Data Where to store retrieved data.
227 * @param pcbSize Where to store the size of data (1, 2, 4).
228 */
229static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize)
230{
231 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
232 {
233 *pcbSize = 0;
234 *pu32Data = 0;
235 return false;
236 }
237
238 if (pParam->flags & USE_REG_GEN32)
239 {
240 *pcbSize = 4;
241 *pu32Data = ACCESS_REG32(pRegFrame, pParam->base.reg_gen32);
242 return true;
243 }
244
245 if (pParam->flags & USE_REG_GEN16)
246 {
247 *pcbSize = 2;
248 *pu32Data = ACCESS_REG16(pRegFrame, pParam->base.reg_gen16);
249 return true;
250 }
251
252 if (pParam->flags & USE_REG_GEN8)
253 {
254 *pcbSize = 1;
255 *pu32Data = ACCESS_REG8(pRegFrame, pParam->base.reg_gen8);
256 return true;
257 }
258
259 if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_SX8))
260 {
261 *pcbSize = 4;
262 *pu32Data = (uint32_t)pParam->parval;
263 return true;
264 }
265
266 if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_SX8))
267 {
268 *pcbSize = 2;
269 *pu32Data = (uint16_t)pParam->parval;
270 return true;
271 }
272
273 if (pParam->flags & USE_IMMEDIATE8)
274 {
275 *pcbSize = 1;
276 *pu32Data = (uint8_t)pParam->parval;
277 return true;
278 }
279
280 if (pParam->flags & USE_REG_SEG)
281 {
282 *pcbSize = 2;
283 *pu32Data = ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg);
284 return true;
285 } /* Else - error. */
286
287 *pcbSize = 0;
288 *pu32Data = 0;
289 return false;
290}
291
292
293/**
294 * Saves data to 8/16/32 general purpose or segment register defined by
295 * instruction's parameter.
296 *
297 * @returns true on success.
298 * @param pCpu Pointer to current disassembler context.
299 * @param pParam Pointer to parameter of instruction to proccess.
300 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
301 * @param u32Data 8/16/32 bit data to store.
302 */
303static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, unsigned u32Data)
304{
305 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8 | USE_IMMEDIATE16_SX8))
306 {
307 return false;
308 }
309
310 if (pParam->flags & USE_REG_GEN32)
311 {
312 ACCESS_REG32(pRegFrame, pParam->base.reg_gen32) = u32Data;
313 return true;
314 }
315
316 if (pParam->flags & USE_REG_GEN16)
317 {
318 ACCESS_REG16(pRegFrame, pParam->base.reg_gen16) = (uint16_t)u32Data;
319 return true;
320 }
321
322 if (pParam->flags & USE_REG_GEN8)
323 {
324 ACCESS_REG8(pRegFrame, pParam->base.reg_gen8) = (uint8_t)u32Data;
325 return true;
326 }
327
328 if (pParam->flags & USE_REG_SEG)
329 {
330 ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg) = (uint16_t)u32Data;
331 return true;
332 }
333
334 /* Else - error. */
335 return false;
336}
337
338
339/*
340 * Internal - statistics only.
341 */
342inline void iomGCMMIOStatLength(PVM pVM, unsigned cb)
343{
344#ifdef VBOX_WITH_STATISTICS
345 switch (cb)
346 {
347 case 1:
348 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO1Byte);
349 break;
350 case 2:
351 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO2Bytes);
352 break;
353 case 4:
354 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO4Bytes);
355 break;
356 default:
357 /* No way. */
358 AssertMsgFailed(("Invalid data length %d\n", cb));
359 break;
360 }
361#else
362 NOREF(pVM); NOREF(cb);
363#endif
364}
365
366
367/**
368 * MOV reg, mem (read)
369 * MOVZX reg, mem (read)
370 * MOVSX reg, mem (read)
371 *
372 * @returns VBox status code.
373 *
374 * @param pVM The virtual machine (GC pointer ofcourse).
375 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
376 * @param pCpu Disassembler CPU state.
377 * @param pRange Pointer MMIO range.
378 * @param GCPhysFault The GC physical address corresponding to pvFault.
379 */
380static int iomGCInterpretMOVxXRead(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
381{
382 /*
383 * If no read handler then go to ring-3 and handle it there.
384 */
385 if (!pRange->pfnReadCallback)
386 return VINF_IOM_HC_MMIO_READ;
387
388 /*
389 * Get the data size from parameter 2,
390 * and call the handler function to get the data.
391 */
392 unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param2);
393 AssertMsg(cbSize > 0 && cbSize <= sizeof(uint32_t), ("cbSize=%d\n", cbSize));
394
395 uint32_t u32Data = 0;
396 int rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &u32Data, cbSize);
397 if (rc == VINF_SUCCESS)
398 {
399 /*
400 * Do sign extension for MOVSX.
401 */
402 /** @todo checkup MOVSX implementation! */
403 if (pCpu->pCurInstr->opcode == OP_MOVSX)
404 {
405 if (cbSize == 1)
406 {
407 /* DWORD <- BYTE */
408 int32_t iData = (int8_t)u32Data;
409 u32Data = (uint32_t)iData;
410 }
411 else
412 {
413 /* DWORD <- WORD */
414 int32_t iData = (int16_t)u32Data;
415 u32Data = (uint32_t)iData;
416 }
417 }
418
419 /*
420 * Store the result to register (parameter 1).
421 */
422 bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data);
423 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
424 }
425
426 if (rc == VINF_SUCCESS)
427 iomGCMMIOStatLength(pVM, cbSize);
428 return rc;
429}
430
431
432/**
433 * MOV mem, reg|imm (write)
434 *
435 * @returns VBox status code.
436 *
437 * @param pVM The virtual machine (GC pointer ofcourse).
438 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
439 * @param pCpu Disassembler CPU state.
440 * @param pRange Pointer MMIO range.
441 * @param GCPhysFault The GC physical address corresponding to pvFault.
442 */
443static int iomGCInterpretMOVxXWrite(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
444{
445 /*
446 * If no write handler then go to ring-3 and handle it there.
447 */
448 if (!pRange->pfnWriteCallback)
449 return VINF_IOM_HC_MMIO_WRITE;
450
451 /*
452 * Get data to write from second parameter,
453 * and call the callback to write it.
454 */
455 unsigned cbSize = 0;
456 uint32_t u32Data = 0;
457 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u32Data, &cbSize);
458 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
459
460 int rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &u32Data, cbSize);
461 if (rc == VINF_SUCCESS)
462 iomGCMMIOStatLength(pVM, cbSize);
463 return rc;
464}
465
466
467/** @todo All the string MMIO stuff can do terrible things since physical contiguous mappings are
468 * assumed all over the place! This must be addressed in a general way, like for example let EM do
469 * all the interpretation and checking of selectors and addresses.
470 */
471
472
473#ifdef IOMGC_MOVS_SUPPORT
474/**
475 * [REP] MOVSB
476 * [REP] MOVSW
477 * [REP] MOVSD
478 *
479 * Restricted implementation.
480 *
481 *
482 * @returns VBox status code.
483 *
484 * @param pVM The virtual machine (GC pointer ofcourse).
485 * @param uErrorCode CPU Error code.
486 * @param pRegFrame Trap register frame.
487 * @param GCPhysFault The GC physical address corresponding to pvFault.
488 * @param pCpu Disassembler CPU state.
489 * @param pRange Pointer MMIO range.
490 */
491static int iomGCInterpretMOVS(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
492{
493 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovs, a);
494
495 /*
496 * We do not support segment prefixes, REPNE or 16-bit addressing.
497 */
498 if ( pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE)
499 || (pCpu->addrmode != CPUMODE_32BIT))
500 return VINF_IOM_HC_MMIO_READ_WRITE;
501
502
503 /*
504 * Get bytes/words/dwords count to copy.
505 */
506 uint32_t cTransfers = 1;
507 if (pCpu->prefix & PREFIX_REP)
508 {
509 cTransfers = pRegFrame->ecx;
510 if (!cTransfers)
511 return VINF_SUCCESS;
512 }
513
514 uint32_t cpl;
515 if (pRegFrame->eflags.Bits.u1VM)
516 cpl = 3;
517 else
518 cpl = (pRegFrame->ss & X86_SEL_RPL);
519
520 /*
521 * Get data size.
522 */
523 unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
524 Assert(cbSize);
525 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
526
527#ifdef VBOX_WITH_STATISTICS
528 if (pVM->iom.s.cMovsMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
529 pVM->iom.s.cMovsMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
530#endif
531
532 RTGCPHYS Phys = GCPhysFault;
533 int rc;
534 if (uErrorCode & X86_TRAP_PF_RW)
535 {
536 /*
537 * Write operation: [Mem] -> [MMIO]
538 * ds:esi (Virt Src) -> es:edi (Phys Dst)
539 */
540 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
541
542 /* Check callback. */
543 if (!pRange->pfnWriteCallback)
544 {
545 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
546 return VINF_IOM_HC_MMIO_WRITE;
547 }
548
549 /* Convert source address ds:esi. */
550 uint8_t *pu8Virt;
551 rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi,
552 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
553 (PRTGCPTR)&pu8Virt, NULL);
554 if (VBOX_SUCCESS(rc))
555 {
556
557 /* Access verification first; we currently can't recover properly from traps inside this instruction */
558 rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)pu8Virt, cTransfers * cbSize, (cpl == 3) ? X86_PTE_US : 0);
559 if (rc != VINF_SUCCESS)
560 {
561 Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
562 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
563 return VINF_EM_RAW_EMULATE_INSTR;
564 }
565
566 MMGCRamRegisterTrapHandler(pVM);
567
568 /* copy loop. */
569 while (cTransfers)
570 {
571 uint32_t u32Data = 0;
572 rc = MMGCRamReadNoTrapHandler(&u32Data, pu8Virt, cbSize);
573 if (rc != VINF_SUCCESS)
574 break;
575 rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
576 if (rc != VINF_SUCCESS)
577 break;
578
579 pu8Virt += offIncrement;
580 Phys += offIncrement;
581 pRegFrame->esi += offIncrement;
582 pRegFrame->edi += offIncrement;
583 cTransfers--;
584 }
585 MMGCRamDeregisterTrapHandler(pVM);
586
587 /* Update ecx. */
588 if (pCpu->prefix & PREFIX_REP)
589 pRegFrame->ecx = cTransfers;
590 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
591 }
592 else
593 rc = VINF_IOM_HC_MMIO_READ_WRITE;
594 }
595 else
596 {
597 /*
598 * Read operation: [MMIO] -> [mem] or [MMIO] -> [MMIO]
599 * ds:[eSI] (Phys Src) -> es:[eDI] (Virt Dst)
600 */
601 /* Check callback. */
602 if (!pRange->pfnReadCallback)
603 return VINF_IOM_HC_MMIO_READ;
604
605 /* Convert destination address. */
606 uint8_t *pu8Virt;
607 rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi,
608 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
609 (PRTGCPTR)&pu8Virt, NULL);
610 if (VBOX_FAILURE(rc))
611 return VINF_EM_RAW_GUEST_TRAP;
612
613 /* Check if destination address is MMIO. */
614 RTGCPHYS PhysDst;
615 rc = PGMGstGetPage(pVM, pu8Virt, NULL, &PhysDst);
616 if ( VBOX_SUCCESS(rc)
617 && iomMMIOGetRangeHC(&pVM->iom.s, PhysDst))
618 {
619 /*
620 * Extra: [MMIO] -> [MMIO]
621 */
622 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsMMIO, d);
623 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
624
625 PhysDst |= (RTGCUINTPTR)pu8Virt & PAGE_OFFSET_MASK;
626 PIOMMMIORANGEGC pMMIODst = iomMMIOGetRange(&pVM->iom.s, PhysDst);
627 if ( !pMMIODst
628 || !pMMIODst->pfnWriteCallback)
629 {
630 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
631 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
632 return VINF_IOM_HC_MMIO_READ_WRITE;
633 }
634
635 /* copy loop. */
636 while (cTransfers)
637 {
638 uint32_t u32Data;
639 rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
640 if (rc != VINF_SUCCESS)
641 break;
642 rc = iomGCMMIODoWrite(pVM, pMMIODst, PhysDst, &u32Data, cbSize);
643 if (rc != VINF_SUCCESS)
644 break;
645
646 Phys += offIncrement;
647 PhysDst += offIncrement;
648 pRegFrame->esi += offIncrement;
649 pRegFrame->edi += offIncrement;
650 cTransfers--;
651 }
652 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
653 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
654 }
655 else
656 {
657 /*
658 * Normal: [MMIO] -> [Mem]
659 */
660 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
661
662 /* Access verification first; we currently can't recover properly from traps inside this instruction */
663 rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)pu8Virt, cTransfers * cbSize, X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
664 if (rc != VINF_SUCCESS)
665 {
666 Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
667 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
668 return VINF_EM_RAW_EMULATE_INSTR;
669 }
670
671 /* copy loop. */
672 MMGCRamRegisterTrapHandler(pVM);
673 while (cTransfers)
674 {
675 uint32_t u32Data;
676 rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
677 if (rc != VINF_SUCCESS)
678 break;
679 rc = MMGCRamWriteNoTrapHandler(pu8Virt, &u32Data, cbSize);
680 if (rc != VINF_SUCCESS)
681 {
682 Log(("MMGCRamWriteNoTrapHandler %08X size=%d failed with %d\n", pu8Virt, cbSize, rc));
683 break;
684 }
685
686 pu8Virt += offIncrement;
687 Phys += offIncrement;
688 pRegFrame->esi += offIncrement;
689 pRegFrame->edi += offIncrement;
690 cTransfers--;
691 }
692 MMGCRamDeregisterTrapHandler(pVM);
693 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
694 }
695
696 /* Update ecx on exit. */
697 if (pCpu->prefix & PREFIX_REP)
698 pRegFrame->ecx = cTransfers;
699 }
700
701 /* work statistics. */
702 if (rc == VINF_SUCCESS)
703 {
704 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovs, a);
705 iomGCMMIOStatLength(pVM, cbSize);
706 }
707 return rc;
708}
709#endif /* IOMGC_MOVS_SUPPORT */
710
711
712
713/**
714 * [REP] STOSB
715 * [REP] STOSW
716 * [REP] STOSD
717 *
718 * Restricted implementation.
719 *
720 *
721 * @returns VBox status code.
722 *
723 * @param pVM The virtual machine (GC pointer ofcourse).
724 * @param pRegFrame Trap register frame.
725 * @param GCPhysFault The GC physical address corresponding to pvFault.
726 * @param pCpu Disassembler CPU state.
727 * @param pRange Pointer MMIO range.
728 */
729static int iomGCInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
730{
731 STAM_PROFILE_START(&pVM->iom.s.StatGCInstStos, a);
732
733 /*
734 * We do not support segment prefixes, REPNE or 16-bit addressing.
735 */
736 if ( pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE)
737 || (pCpu->addrmode != CPUMODE_32BIT))
738 return VINF_IOM_HC_MMIO_READ_WRITE;
739
740 /*
741 * Get bytes/words/dwords count to copy.
742 */
743 uint32_t cTransfers = 1;
744 if (pCpu->prefix & PREFIX_REP)
745 {
746 cTransfers = pRegFrame->ecx;
747 if (!cTransfers)
748 return VINF_SUCCESS;
749 }
750
751 /*
752 * Get data size.
753 */
754 unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
755 Assert(cbSize);
756 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
757
758#ifdef VBOX_WITH_STATISTICS
759 if (pVM->iom.s.cStosMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
760 pVM->iom.s.cStosMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
761#endif
762
763
764 RTGCPHYS Phys = GCPhysFault;
765 uint32_t u32Data = pRegFrame->eax;
766 int rc;
767 if (pRange->pfnFillCallback)
768 {
769 /*
770 * Use the fill callback.
771 */
772 /** @todo pfnFillCallback must return number of bytes successfully written!!! */
773 if (offIncrement > 0)
774 {
775 /* addr++ variant. */
776 rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, Phys, u32Data, cbSize, cTransfers);
777 if (rc == VINF_SUCCESS)
778 {
779 /* Update registers. */
780 pRegFrame->edi += cTransfers << SIZE2SHIFT(cbSize);
781 if (pCpu->prefix & PREFIX_REP)
782 pRegFrame->ecx = 0;
783 }
784 }
785 else
786 {
787 /* addr-- variant. */
788 rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, (Phys - (cTransfers - 1)) << SIZE2SHIFT(cbSize), u32Data, cbSize, cTransfers);
789 if (rc == VINF_SUCCESS)
790 {
791 /* Update registers. */
792 pRegFrame->edi -= cTransfers << SIZE2SHIFT(cbSize);
793 if (pCpu->prefix & PREFIX_REP)
794 pRegFrame->ecx = 0;
795 }
796 }
797 }
798 else
799 {
800 /*
801 * Use the write callback.
802 */
803 /* Check write callback. */
804 if (!pRange->pfnWriteCallback)
805 return VINF_IOM_HC_MMIO_WRITE;
806
807 /* fill loop. */
808 do
809 {
810 rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
811 if (rc != VINF_SUCCESS)
812 break;
813
814 Phys += offIncrement;
815 pRegFrame->edi += offIncrement;
816 cTransfers--;
817 } while (cTransfers);
818
819 /* Update ecx on exit. */
820 if (pCpu->prefix & PREFIX_REP)
821 pRegFrame->ecx = cTransfers;
822 }
823
824 /*
825 * Work statistics and return.
826 */
827 if (rc == VINF_SUCCESS)
828 {
829 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstStos, a);
830 iomGCMMIOStatLength(pVM, cbSize);
831 }
832 return rc;
833}
834
835
836/**
837 * [REP] LODSB
838 * [REP] LODSW
839 * [REP] LODSD
840 *
841 * Restricted implementation.
842 *
843 *
844 * @returns VBox status code.
845 *
846 * @param pVM The virtual machine (GC pointer ofcourse).
847 * @param pRegFrame Trap register frame.
848 * @param GCPhysFault The GC physical address corresponding to pvFault.
849 * @param pCpu Disassembler CPU state.
850 * @param pRange Pointer MMIO range.
851 */
852static int iomGCInterpretLODS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
853{
854 STAM_PROFILE_START(&pVM->iom.s.StatGCInstLods, a1);
855
856 /*
857 * We do not support segment prefixes, REP* or 16-bit addressing.
858 */
859 if ( (pCpu->prefix & (PREFIX_SEG | PREFIX_REP | PREFIX_REPNE))
860 || (pCpu->addrmode != CPUMODE_32BIT))
861 return VINF_IOM_HC_MMIO_READ_WRITE;
862
863 /* Check that we can handle it. */
864 if (!pRange->pfnReadCallback)
865 return VINF_IOM_HC_MMIO_READ;
866
867 /*
868 * Get data size.
869 */
870 unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param2);
871 Assert(cbSize);
872 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
873
874 /*
875 * Perform read.
876 */
877 int rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &pRegFrame->eax, cbSize);
878 if (rc == VINF_SUCCESS)
879 pRegFrame->esi += offIncrement;
880
881 /*
882 * Work statistics and return.
883 */
884 if (rc == VINF_SUCCESS)
885 {
886 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstLods, a1);
887 iomGCMMIOStatLength(pVM, cbSize);
888 }
889 return rc;
890}
891
892
893/**
894 * CMP [MMIO], reg|imm
895 * CMP reg|imm, [MMIO]
896 *
897 * Restricted implementation.
898 *
899 *
900 * @returns VBox status code.
901 *
902 * @param pVM The virtual machine (GC pointer ofcourse).
903 * @param pRegFrame Trap register frame.
904 * @param GCPhysFault The GC physical address corresponding to pvFault.
905 * @param pCpu Disassembler CPU state.
906 * @param pRange Pointer MMIO range.
907 */
908static int iomGCInterpretCMP(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
909{
910 STAM_PROFILE_START(&pVM->iom.s.StatGCInstCmp, a1);
911
912 /* Check read callback. */
913 if (!pRange->pfnReadCallback)
914 return VINF_EM_RAW_GUEST_TRAP;
915
916 /*
917 * Get the operands.
918 */
919 unsigned cbSize = 0;
920 uint32_t uData1;
921 uint32_t uData2;
922 int rc;
923 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
924 /* cmp reg, [MMIO]. */
925 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
926 else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
927 /* cmp [MMIO], reg|imm. */
928 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
929 else
930 {
931 AssertMsgFailed(("Disassember CMP problem..\n"));
932 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
933 }
934
935 if (rc == VINF_SUCCESS)
936 {
937 /* Emulate CMP and update guest flags. */
938 uint32_t eflags = EMEmulateCmp(uData1, uData2, cbSize);
939 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
940 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
941
942 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstCmp, a1);
943 iomGCMMIOStatLength(pVM, cbSize);
944 }
945
946 return rc;
947}
948
949
950/**
951 * AND [MMIO], reg|imm
952 * AND reg, [MMIO]
953 *
954 * Restricted implementation.
955 *
956 *
957 * @returns VBox status code.
958 *
959 * @param pVM The virtual machine (GC pointer ofcourse).
960 * @param pRegFrame Trap register frame.
961 * @param GCPhysFault The GC physical address corresponding to pvFault.
962 * @param pCpu Disassembler CPU state.
963 * @param pRange Pointer MMIO range.
964 */
965static int iomGCInterpretAND(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
966{
967 STAM_PROFILE_START(&pVM->iom.s.StatGCInstAnd, a1);
968
969 /* Check read callback. */
970
971 unsigned cbSize = 0;
972 uint32_t uData1;
973 uint32_t uData2;
974 bool fAndWrite;
975 int rc;
976 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
977 {
978 /* and reg, [MMIO]. */
979 fAndWrite = false;
980 if (pRange->pfnReadCallback)
981 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
982 else
983 rc = VINF_IOM_HC_MMIO_READ;
984 }
985 else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
986 {
987 /* and [MMIO], reg|imm. */
988 fAndWrite = true;
989 if (pRange->pfnReadCallback && pRange->pfnWriteCallback)
990 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
991 else
992 rc = VINF_IOM_HC_MMIO_READ_WRITE;
993 }
994 else
995 {
996 AssertMsgFailed(("Disassember AND problem..\n"));
997 return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
998 }
999
1000 if (rc == VINF_SUCCESS)
1001 {
1002 /* Emulate AND and update guest flags. */
1003 uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
1004 if (fAndWrite)
1005 /* Store result to MMIO. */
1006 rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
1007 else
1008 {
1009 /* Store result to register. */
1010 bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData1);
1011 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
1012 }
1013 if (rc == VINF_SUCCESS)
1014 {
1015 /* Update guest's eflags and finish. */
1016 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1017 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1018 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstAnd, a1);
1019 iomGCMMIOStatLength(pVM, cbSize);
1020 }
1021 }
1022
1023 return rc;
1024}
1025
1026
1027
1028/**
1029 * TEST [MMIO], reg|imm
1030 * TEST reg, [MMIO]
1031 *
1032 * Restricted implementation.
1033 *
1034 *
1035 * @returns VBox status code.
1036 *
1037 * @param pVM The virtual machine (GC pointer ofcourse).
1038 * @param pRegFrame Trap register frame.
1039 * @param GCPhysFault The GC physical address corresponding to pvFault.
1040 * @param pCpu Disassembler CPU state.
1041 * @param pRange Pointer MMIO range.
1042 */
1043static int iomGCInterpretTEST(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
1044{
1045 STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
1046
1047 /* Check read callback. */
1048
1049 unsigned cbSize = 0;
1050 uint32_t uData1;
1051 uint32_t uData2;
1052 int rc;
1053
1054 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
1055 {
1056 /* and test, [MMIO]. */
1057 if (pRange->pfnReadCallback)
1058 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
1059 else
1060 rc = VINF_IOM_HC_MMIO_READ;
1061 }
1062 else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
1063 {
1064 /* test [MMIO], reg|imm. */
1065 if (pRange->pfnReadCallback)
1066 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
1067 else
1068 rc = VINF_IOM_HC_MMIO_READ;
1069 }
1070 else
1071 {
1072 AssertMsgFailed(("Disassember TEST problem..\n"));
1073 return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
1074 }
1075
1076 if (rc == VINF_SUCCESS)
1077 {
1078 /* Emulate TEST (=AND without write back) and update guest EFLAGS. */
1079 uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
1080 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1081 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1082 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
1083 iomGCMMIOStatLength(pVM, cbSize);
1084 }
1085
1086 return rc;
1087}
1088
1089/**
1090 * XCHG [MMIO], reg
1091 * XCHG reg, [MMIO]
1092 *
1093 * Restricted implementation.
1094 *
1095 *
1096 * @returns VBox status code.
1097 *
1098 * @param pVM The virtual machine (GC pointer ofcourse).
1099 * @param pRegFrame Trap register frame.
1100 * @param GCPhysFault The GC physical address corresponding to pvFault.
1101 * @param pCpu Disassembler CPU state.
1102 * @param pRange Pointer MMIO range.
1103 */
1104static int iomGCInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
1105{
1106 STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
1107
1108 /* Check read callback. */
1109 unsigned cbSize = 0;
1110 uint32_t uData1;
1111 uint32_t uData2;
1112 int rc;
1113
1114 if (!pRange->pfnReadCallback || !pRange->pfnWriteCallback)
1115 {
1116 rc = VINF_IOM_HC_MMIO_READ;
1117 goto end;
1118 }
1119
1120 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
1121 {
1122 /* xchg reg, [MMIO]. */
1123 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
1124 if (rc == VINF_SUCCESS)
1125 {
1126 /* Store result to MMIO. */
1127 rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
1128
1129 if (rc == VINF_SUCCESS)
1130 {
1131 /* Store result to register. */
1132 bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData2);
1133 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
1134 }
1135 else
1136 Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
1137 }
1138 else
1139 Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
1140 }
1141 else
1142 if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
1143 {
1144 /* xchg [MMIO], reg. */
1145 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
1146 if (rc == VINF_SUCCESS)
1147 {
1148 /* Store result to MMIO. */
1149 rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData2, cbSize);
1150
1151 if (rc == VINF_SUCCESS)
1152 {
1153 /* Store result to register. */
1154 bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param2, pRegFrame, uData1);
1155 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
1156 }
1157 else
1158 Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
1159 }
1160 else
1161 Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
1162 }
1163 else
1164 {
1165 AssertMsgFailed(("Disassember XCHG problem..\n"));
1166 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
1167 goto end;
1168 }
1169
1170end:
1171 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
1172 return rc;
1173}
1174
1175
1176#ifdef IN_RING0
1177
1178/**
1179 * Read callback for disassembly function; supports reading bytes that cross a page boundary
1180 *
1181 * @returns VBox status code.
1182 * @param pSrc GC source pointer
1183 * @param pDest HC destination pointer
1184 * @param size Number of bytes to read
1185 * @param dwUserdata Callback specific user data (pCpu)
1186 *
1187 */
1188DECLCALLBACK(int32_t) iomReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, uint32_t size, RTHCUINTPTR dwUserdata)
1189{
1190 DISCPUSTATE *pCpu = (DISCPUSTATE *)dwUserdata;
1191 PVM pVM = (PVM)pCpu->dwUserData[0];
1192
1193 int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
1194 AssertRC(rc);
1195 return rc;
1196}
1197
1198inline bool iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
1199{
1200 return VBOX_SUCCESS(DISCoreOneEx(InstrGC, pCpu->mode, iomReadBytes, pVM, pCpu, pOpsize));
1201}
1202#else
1203inline bool iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
1204{
1205 return DISCoreOne(pCpu, InstrGC, pOpsize);
1206}
1207
1208#endif
1209
1210/**
1211 * \#PF Handler callback for MMIO ranges.
1212 * Note: we are on ring0 in Hypervisor and interrupts are disabled.
1213 *
1214 * @returns VBox status code (appropriate for GC return).
1215 * @param pVM VM Handle.
1216 * @param uErrorCode CPU Error code.
1217 * @param pRegFrame Trap register frame.
1218 * @param pvFault The fault address (cr2).
1219 * @param GCPhysFault The GC physical address corresponding to pvFault.
1220 * @param pvUser Pointer to the MMIO ring-3 range entry.
1221 */
1222IOMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1223{
1224 STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
1225 NOREF(pvUser); /** @todo implement pvUser usage! */
1226 Log3(("IOMMMIOHandler: GCPhys=%RGp uErr=%#x pvFault=%p eip=%RGv\n",
1227 GCPhysFault, uErrorCode, pvFault, pRegFrame->eip));
1228
1229 /*
1230 * Find the corresponding MMIO range.
1231 */
1232 CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysFault);
1233 if (!pRange)
1234 {
1235#ifdef VBOX_WITH_STATISTICS
1236 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
1237 if (pStats)
1238 {
1239 if (uErrorCode & X86_TRAP_PF_RW)
1240 STAM_COUNTER_INC(&pStats->WriteGCToR3);
1241 else
1242 STAM_COUNTER_INC(&pStats->ReadGCToR3);
1243 }
1244#endif
1245 PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhysFault);
1246 if (pRangeR3)
1247 {
1248 STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
1249 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
1250 return (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
1251 }
1252
1253 /*
1254 * Now, why are we here...
1255 */
1256 AssertMsgFailed(("Internal error! GCPhysFault=%x\n", GCPhysFault));
1257 return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
1258 }
1259
1260 /*
1261 * Convert CS:EIP to linear address and initialize the disassembler.
1262 */
1263 DISCPUSTATE cpu;
1264 cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
1265
1266 RTGCPTR pvCode;
1267 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)(cpu.mode == CPUMODE_32BIT ? pRegFrame->eip : pRegFrame->eip & 0xffff), &pvCode);
1268 if (VBOX_FAILURE(rc))
1269 {
1270 AssertMsgFailed(("Internal error! cs:eip=%04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
1271 return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
1272 }
1273
1274 /*
1275 * Disassemble the instruction and interprete it.
1276 */
1277 unsigned cbOp;
1278 if (iomDisCoreOne(pVM, &cpu, (RTGCUINTPTR)pvCode, &cbOp))
1279 {
1280 switch (cpu.pCurInstr->opcode)
1281 {
1282 case OP_MOV:
1283 case OP_MOVZX:
1284 case OP_MOVSX:
1285 {
1286 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMov, b);
1287 if (uErrorCode & X86_TRAP_PF_RW)
1288 rc = iomGCInterpretMOVxXWrite(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
1289 else
1290 rc = iomGCInterpretMOVxXRead(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
1291 if (rc == VINF_SUCCESS)
1292 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMov, b);
1293 break;
1294 }
1295
1296
1297#ifdef IOMGC_MOVS_SUPPORT
1298 case OP_MOVSB:
1299 case OP_MOVSWD:
1300 rc = iomGCInterpretMOVS(pVM, uErrorCode, pRegFrame, GCPhysFault, &cpu, pRange);
1301 break;
1302#endif
1303
1304 case OP_STOSB:
1305 case OP_STOSWD:
1306 Assert(uErrorCode & X86_TRAP_PF_RW);
1307 rc = iomGCInterpretSTOS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1308 break;
1309
1310 case OP_LODSB:
1311 case OP_LODSWD:
1312 Assert(!(uErrorCode & X86_TRAP_PF_RW));
1313 rc = iomGCInterpretLODS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1314 break;
1315
1316
1317 case OP_CMP:
1318 Assert(!(uErrorCode & X86_TRAP_PF_RW));
1319 rc = iomGCInterpretCMP(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1320 break;
1321
1322 case OP_AND:
1323 rc = iomGCInterpretAND(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1324 break;
1325
1326 case OP_TEST:
1327 Assert(!(uErrorCode & X86_TRAP_PF_RW));
1328 rc = iomGCInterpretTEST(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1329 break;
1330
1331 case OP_XCHG:
1332 rc = iomGCInterpretXCHG(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1333 break;
1334
1335
1336 /*
1337 * The instruction isn't supported. Hand it on to ring-3.
1338 */
1339 default:
1340 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOther);
1341 rc = (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
1342 break;
1343 }
1344 }
1345 else
1346 {
1347 AssertMsgFailed(("Disassembler freaked out!\n"));
1348 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
1349 }
1350
1351 /*
1352 * On success advance EIP.
1353 */
1354 if (rc == VINF_SUCCESS)
1355 pRegFrame->eip += cbOp;
1356 else
1357 {
1358 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
1359#ifdef VBOX_WITH_STATISTICS
1360 switch (rc)
1361 {
1362 case VINF_IOM_HC_MMIO_READ:
1363 case VINF_IOM_HC_MMIO_WRITE:
1364 case VINF_IOM_HC_MMIO_READ_WRITE:
1365 {
1366 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
1367 if (pStats)
1368 {
1369 if (uErrorCode & X86_TRAP_PF_RW)
1370 STAM_COUNTER_INC(&pStats->WriteGCToR3);
1371 else
1372 STAM_COUNTER_INC(&pStats->ReadGCToR3);
1373 }
1374 }
1375 break;
1376 }
1377#endif
1378 }
1379 STAM_PROFILE_STOP(&pVM->iom.s.StatGCMMIOHandler, a);
1380 return rc;
1381}
1382
1383
1384#endif /* !IN_RING3 */
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