VirtualBox

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

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

Cleaned up cpl checking.

  • Property svn:keywords set to Id
File size: 45.2 KB
Line 
1/* $Id: IOMAllMMIO.cpp 1828 2007-03-30 12:52:55Z 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 /* Get the current privilege level. */
515 uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
516
517 /*
518 * Get data size.
519 */
520 unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
521 Assert(cbSize);
522 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
523
524#ifdef VBOX_WITH_STATISTICS
525 if (pVM->iom.s.cMovsMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
526 pVM->iom.s.cMovsMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
527#endif
528
529 RTGCPHYS Phys = GCPhysFault;
530 int rc;
531 if (uErrorCode & X86_TRAP_PF_RW)
532 {
533 /*
534 * Write operation: [Mem] -> [MMIO]
535 * ds:esi (Virt Src) -> es:edi (Phys Dst)
536 */
537 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
538
539 /* Check callback. */
540 if (!pRange->pfnWriteCallback)
541 {
542 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
543 return VINF_IOM_HC_MMIO_WRITE;
544 }
545
546 /* Convert source address ds:esi. */
547 uint8_t *pu8Virt;
548 rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi,
549 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
550 (PRTGCPTR)&pu8Virt, NULL);
551 if (VBOX_SUCCESS(rc))
552 {
553
554 /* Access verification first; we currently can't recover properly from traps inside this instruction */
555 rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)pu8Virt, cTransfers * cbSize, (cpl == 3) ? X86_PTE_US : 0);
556 if (rc != VINF_SUCCESS)
557 {
558 Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
559 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
560 return VINF_EM_RAW_EMULATE_INSTR;
561 }
562
563 MMGCRamRegisterTrapHandler(pVM);
564
565 /* copy loop. */
566 while (cTransfers)
567 {
568 uint32_t u32Data = 0;
569 rc = MMGCRamReadNoTrapHandler(&u32Data, pu8Virt, cbSize);
570 if (rc != VINF_SUCCESS)
571 break;
572 rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
573 if (rc != VINF_SUCCESS)
574 break;
575
576 pu8Virt += offIncrement;
577 Phys += offIncrement;
578 pRegFrame->esi += offIncrement;
579 pRegFrame->edi += offIncrement;
580 cTransfers--;
581 }
582 MMGCRamDeregisterTrapHandler(pVM);
583
584 /* Update ecx. */
585 if (pCpu->prefix & PREFIX_REP)
586 pRegFrame->ecx = cTransfers;
587 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
588 }
589 else
590 rc = VINF_IOM_HC_MMIO_READ_WRITE;
591 }
592 else
593 {
594 /*
595 * Read operation: [MMIO] -> [mem] or [MMIO] -> [MMIO]
596 * ds:[eSI] (Phys Src) -> es:[eDI] (Virt Dst)
597 */
598 /* Check callback. */
599 if (!pRange->pfnReadCallback)
600 return VINF_IOM_HC_MMIO_READ;
601
602 /* Convert destination address. */
603 uint8_t *pu8Virt;
604 rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi,
605 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
606 (PRTGCPTR)&pu8Virt, NULL);
607 if (VBOX_FAILURE(rc))
608 return VINF_EM_RAW_GUEST_TRAP;
609
610 /* Check if destination address is MMIO. */
611 RTGCPHYS PhysDst;
612 rc = PGMGstGetPage(pVM, pu8Virt, NULL, &PhysDst);
613 if ( VBOX_SUCCESS(rc)
614 && iomMMIOGetRangeHC(&pVM->iom.s, PhysDst))
615 {
616 /*
617 * Extra: [MMIO] -> [MMIO]
618 */
619 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsMMIO, d);
620 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
621
622 PhysDst |= (RTGCUINTPTR)pu8Virt & PAGE_OFFSET_MASK;
623 PIOMMMIORANGEGC pMMIODst = iomMMIOGetRange(&pVM->iom.s, PhysDst);
624 if ( !pMMIODst
625 || !pMMIODst->pfnWriteCallback)
626 {
627 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
628 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
629 return VINF_IOM_HC_MMIO_READ_WRITE;
630 }
631
632 /* copy loop. */
633 while (cTransfers)
634 {
635 uint32_t u32Data;
636 rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
637 if (rc != VINF_SUCCESS)
638 break;
639 rc = iomGCMMIODoWrite(pVM, pMMIODst, PhysDst, &u32Data, cbSize);
640 if (rc != VINF_SUCCESS)
641 break;
642
643 Phys += offIncrement;
644 PhysDst += offIncrement;
645 pRegFrame->esi += offIncrement;
646 pRegFrame->edi += offIncrement;
647 cTransfers--;
648 }
649 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
650 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
651 }
652 else
653 {
654 /*
655 * Normal: [MMIO] -> [Mem]
656 */
657 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
658
659 /* Access verification first; we currently can't recover properly from traps inside this instruction */
660 rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)pu8Virt, cTransfers * cbSize, X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
661 if (rc != VINF_SUCCESS)
662 {
663 Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
664 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
665 return VINF_EM_RAW_EMULATE_INSTR;
666 }
667
668 /* copy loop. */
669 MMGCRamRegisterTrapHandler(pVM);
670 while (cTransfers)
671 {
672 uint32_t u32Data;
673 rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
674 if (rc != VINF_SUCCESS)
675 break;
676 rc = MMGCRamWriteNoTrapHandler(pu8Virt, &u32Data, cbSize);
677 if (rc != VINF_SUCCESS)
678 {
679 Log(("MMGCRamWriteNoTrapHandler %08X size=%d failed with %d\n", pu8Virt, cbSize, rc));
680 break;
681 }
682
683 pu8Virt += offIncrement;
684 Phys += offIncrement;
685 pRegFrame->esi += offIncrement;
686 pRegFrame->edi += offIncrement;
687 cTransfers--;
688 }
689 MMGCRamDeregisterTrapHandler(pVM);
690 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
691 }
692
693 /* Update ecx on exit. */
694 if (pCpu->prefix & PREFIX_REP)
695 pRegFrame->ecx = cTransfers;
696 }
697
698 /* work statistics. */
699 if (rc == VINF_SUCCESS)
700 {
701 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovs, a);
702 iomGCMMIOStatLength(pVM, cbSize);
703 }
704 return rc;
705}
706#endif /* IOMGC_MOVS_SUPPORT */
707
708
709
710/**
711 * [REP] STOSB
712 * [REP] STOSW
713 * [REP] STOSD
714 *
715 * Restricted implementation.
716 *
717 *
718 * @returns VBox status code.
719 *
720 * @param pVM The virtual machine (GC pointer ofcourse).
721 * @param pRegFrame Trap register frame.
722 * @param GCPhysFault The GC physical address corresponding to pvFault.
723 * @param pCpu Disassembler CPU state.
724 * @param pRange Pointer MMIO range.
725 */
726static int iomGCInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
727{
728 STAM_PROFILE_START(&pVM->iom.s.StatGCInstStos, a);
729
730 /*
731 * We do not support segment prefixes, REPNE or 16-bit addressing.
732 */
733 if ( pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE)
734 || (pCpu->addrmode != CPUMODE_32BIT))
735 return VINF_IOM_HC_MMIO_READ_WRITE;
736
737 /*
738 * Get bytes/words/dwords count to copy.
739 */
740 uint32_t cTransfers = 1;
741 if (pCpu->prefix & PREFIX_REP)
742 {
743 cTransfers = pRegFrame->ecx;
744 if (!cTransfers)
745 return VINF_SUCCESS;
746 }
747
748 /*
749 * Get data size.
750 */
751 unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
752 Assert(cbSize);
753 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
754
755#ifdef VBOX_WITH_STATISTICS
756 if (pVM->iom.s.cStosMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
757 pVM->iom.s.cStosMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
758#endif
759
760
761 RTGCPHYS Phys = GCPhysFault;
762 uint32_t u32Data = pRegFrame->eax;
763 int rc;
764 if (pRange->pfnFillCallback)
765 {
766 /*
767 * Use the fill callback.
768 */
769 /** @todo pfnFillCallback must return number of bytes successfully written!!! */
770 if (offIncrement > 0)
771 {
772 /* addr++ variant. */
773 rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, Phys, u32Data, cbSize, cTransfers);
774 if (rc == VINF_SUCCESS)
775 {
776 /* Update registers. */
777 pRegFrame->edi += cTransfers << SIZE2SHIFT(cbSize);
778 if (pCpu->prefix & PREFIX_REP)
779 pRegFrame->ecx = 0;
780 }
781 }
782 else
783 {
784 /* addr-- variant. */
785 rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, (Phys - (cTransfers - 1)) << SIZE2SHIFT(cbSize), u32Data, cbSize, cTransfers);
786 if (rc == VINF_SUCCESS)
787 {
788 /* Update registers. */
789 pRegFrame->edi -= cTransfers << SIZE2SHIFT(cbSize);
790 if (pCpu->prefix & PREFIX_REP)
791 pRegFrame->ecx = 0;
792 }
793 }
794 }
795 else
796 {
797 /*
798 * Use the write callback.
799 */
800 /* Check write callback. */
801 if (!pRange->pfnWriteCallback)
802 return VINF_IOM_HC_MMIO_WRITE;
803
804 /* fill loop. */
805 do
806 {
807 rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
808 if (rc != VINF_SUCCESS)
809 break;
810
811 Phys += offIncrement;
812 pRegFrame->edi += offIncrement;
813 cTransfers--;
814 } while (cTransfers);
815
816 /* Update ecx on exit. */
817 if (pCpu->prefix & PREFIX_REP)
818 pRegFrame->ecx = cTransfers;
819 }
820
821 /*
822 * Work statistics and return.
823 */
824 if (rc == VINF_SUCCESS)
825 {
826 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstStos, a);
827 iomGCMMIOStatLength(pVM, cbSize);
828 }
829 return rc;
830}
831
832
833/**
834 * [REP] LODSB
835 * [REP] LODSW
836 * [REP] LODSD
837 *
838 * Restricted implementation.
839 *
840 *
841 * @returns VBox status code.
842 *
843 * @param pVM The virtual machine (GC pointer ofcourse).
844 * @param pRegFrame Trap register frame.
845 * @param GCPhysFault The GC physical address corresponding to pvFault.
846 * @param pCpu Disassembler CPU state.
847 * @param pRange Pointer MMIO range.
848 */
849static int iomGCInterpretLODS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
850{
851 STAM_PROFILE_START(&pVM->iom.s.StatGCInstLods, a1);
852
853 /*
854 * We do not support segment prefixes, REP* or 16-bit addressing.
855 */
856 if ( (pCpu->prefix & (PREFIX_SEG | PREFIX_REP | PREFIX_REPNE))
857 || (pCpu->addrmode != CPUMODE_32BIT))
858 return VINF_IOM_HC_MMIO_READ_WRITE;
859
860 /* Check that we can handle it. */
861 if (!pRange->pfnReadCallback)
862 return VINF_IOM_HC_MMIO_READ;
863
864 /*
865 * Get data size.
866 */
867 unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param2);
868 Assert(cbSize);
869 int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
870
871 /*
872 * Perform read.
873 */
874 int rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &pRegFrame->eax, cbSize);
875 if (rc == VINF_SUCCESS)
876 pRegFrame->esi += offIncrement;
877
878 /*
879 * Work statistics and return.
880 */
881 if (rc == VINF_SUCCESS)
882 {
883 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstLods, a1);
884 iomGCMMIOStatLength(pVM, cbSize);
885 }
886 return rc;
887}
888
889
890/**
891 * CMP [MMIO], reg|imm
892 * CMP reg|imm, [MMIO]
893 *
894 * Restricted implementation.
895 *
896 *
897 * @returns VBox status code.
898 *
899 * @param pVM The virtual machine (GC pointer ofcourse).
900 * @param pRegFrame Trap register frame.
901 * @param GCPhysFault The GC physical address corresponding to pvFault.
902 * @param pCpu Disassembler CPU state.
903 * @param pRange Pointer MMIO range.
904 */
905static int iomGCInterpretCMP(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
906{
907 STAM_PROFILE_START(&pVM->iom.s.StatGCInstCmp, a1);
908
909 /* Check read callback. */
910 if (!pRange->pfnReadCallback)
911 return VINF_EM_RAW_GUEST_TRAP;
912
913 /*
914 * Get the operands.
915 */
916 unsigned cbSize = 0;
917 uint32_t uData1;
918 uint32_t uData2;
919 int rc;
920 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
921 /* cmp reg, [MMIO]. */
922 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
923 else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
924 /* cmp [MMIO], reg|imm. */
925 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
926 else
927 {
928 AssertMsgFailed(("Disassember CMP problem..\n"));
929 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
930 }
931
932 if (rc == VINF_SUCCESS)
933 {
934 /* Emulate CMP and update guest flags. */
935 uint32_t eflags = EMEmulateCmp(uData1, uData2, cbSize);
936 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
937 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
938
939 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstCmp, a1);
940 iomGCMMIOStatLength(pVM, cbSize);
941 }
942
943 return rc;
944}
945
946
947/**
948 * AND [MMIO], reg|imm
949 * AND reg, [MMIO]
950 *
951 * Restricted implementation.
952 *
953 *
954 * @returns VBox status code.
955 *
956 * @param pVM The virtual machine (GC pointer ofcourse).
957 * @param pRegFrame Trap register frame.
958 * @param GCPhysFault The GC physical address corresponding to pvFault.
959 * @param pCpu Disassembler CPU state.
960 * @param pRange Pointer MMIO range.
961 */
962static int iomGCInterpretAND(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
963{
964 STAM_PROFILE_START(&pVM->iom.s.StatGCInstAnd, a1);
965
966 /* Check read callback. */
967
968 unsigned cbSize = 0;
969 uint32_t uData1;
970 uint32_t uData2;
971 bool fAndWrite;
972 int rc;
973 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
974 {
975 /* and reg, [MMIO]. */
976 fAndWrite = false;
977 if (pRange->pfnReadCallback)
978 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
979 else
980 rc = VINF_IOM_HC_MMIO_READ;
981 }
982 else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
983 {
984 /* and [MMIO], reg|imm. */
985 fAndWrite = true;
986 if (pRange->pfnReadCallback && pRange->pfnWriteCallback)
987 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
988 else
989 rc = VINF_IOM_HC_MMIO_READ_WRITE;
990 }
991 else
992 {
993 AssertMsgFailed(("Disassember AND problem..\n"));
994 return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
995 }
996
997 if (rc == VINF_SUCCESS)
998 {
999 /* Emulate AND and update guest flags. */
1000 uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
1001 if (fAndWrite)
1002 /* Store result to MMIO. */
1003 rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
1004 else
1005 {
1006 /* Store result to register. */
1007 bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData1);
1008 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
1009 }
1010 if (rc == VINF_SUCCESS)
1011 {
1012 /* Update guest's eflags and finish. */
1013 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1014 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1015 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstAnd, a1);
1016 iomGCMMIOStatLength(pVM, cbSize);
1017 }
1018 }
1019
1020 return rc;
1021}
1022
1023
1024
1025/**
1026 * TEST [MMIO], reg|imm
1027 * TEST reg, [MMIO]
1028 *
1029 * Restricted implementation.
1030 *
1031 *
1032 * @returns VBox status code.
1033 *
1034 * @param pVM The virtual machine (GC pointer ofcourse).
1035 * @param pRegFrame Trap register frame.
1036 * @param GCPhysFault The GC physical address corresponding to pvFault.
1037 * @param pCpu Disassembler CPU state.
1038 * @param pRange Pointer MMIO range.
1039 */
1040static int iomGCInterpretTEST(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
1041{
1042 STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
1043
1044 /* Check read callback. */
1045
1046 unsigned cbSize = 0;
1047 uint32_t uData1;
1048 uint32_t uData2;
1049 int rc;
1050
1051 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
1052 {
1053 /* and test, [MMIO]. */
1054 if (pRange->pfnReadCallback)
1055 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
1056 else
1057 rc = VINF_IOM_HC_MMIO_READ;
1058 }
1059 else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
1060 {
1061 /* test [MMIO], reg|imm. */
1062 if (pRange->pfnReadCallback)
1063 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
1064 else
1065 rc = VINF_IOM_HC_MMIO_READ;
1066 }
1067 else
1068 {
1069 AssertMsgFailed(("Disassember TEST problem..\n"));
1070 return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
1071 }
1072
1073 if (rc == VINF_SUCCESS)
1074 {
1075 /* Emulate TEST (=AND without write back) and update guest EFLAGS. */
1076 uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
1077 pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
1078 | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
1079 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
1080 iomGCMMIOStatLength(pVM, cbSize);
1081 }
1082
1083 return rc;
1084}
1085
1086/**
1087 * XCHG [MMIO], reg
1088 * XCHG reg, [MMIO]
1089 *
1090 * Restricted implementation.
1091 *
1092 *
1093 * @returns VBox status code.
1094 *
1095 * @param pVM The virtual machine (GC pointer ofcourse).
1096 * @param pRegFrame Trap register frame.
1097 * @param GCPhysFault The GC physical address corresponding to pvFault.
1098 * @param pCpu Disassembler CPU state.
1099 * @param pRange Pointer MMIO range.
1100 */
1101static int iomGCInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
1102{
1103 STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
1104
1105 /* Check read callback. */
1106 unsigned cbSize = 0;
1107 uint32_t uData1;
1108 uint32_t uData2;
1109 int rc;
1110
1111 if (!pRange->pfnReadCallback || !pRange->pfnWriteCallback)
1112 {
1113 rc = VINF_IOM_HC_MMIO_READ;
1114 goto end;
1115 }
1116
1117 if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
1118 {
1119 /* xchg reg, [MMIO]. */
1120 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
1121 if (rc == VINF_SUCCESS)
1122 {
1123 /* Store result to MMIO. */
1124 rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
1125
1126 if (rc == VINF_SUCCESS)
1127 {
1128 /* Store result to register. */
1129 bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData2);
1130 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
1131 }
1132 else
1133 Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
1134 }
1135 else
1136 Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
1137 }
1138 else
1139 if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
1140 {
1141 /* xchg [MMIO], reg. */
1142 rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
1143 if (rc == VINF_SUCCESS)
1144 {
1145 /* Store result to MMIO. */
1146 rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData2, cbSize);
1147
1148 if (rc == VINF_SUCCESS)
1149 {
1150 /* Store result to register. */
1151 bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param2, pRegFrame, uData1);
1152 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
1153 }
1154 else
1155 Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
1156 }
1157 else
1158 Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
1159 }
1160 else
1161 {
1162 AssertMsgFailed(("Disassember XCHG problem..\n"));
1163 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
1164 goto end;
1165 }
1166
1167end:
1168 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
1169 return rc;
1170}
1171
1172
1173#ifdef IN_RING0
1174
1175/**
1176 * Read callback for disassembly function; supports reading bytes that cross a page boundary
1177 *
1178 * @returns VBox status code.
1179 * @param pSrc GC source pointer
1180 * @param pDest HC destination pointer
1181 * @param size Number of bytes to read
1182 * @param dwUserdata Callback specific user data (pCpu)
1183 *
1184 */
1185DECLCALLBACK(int32_t) iomReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, uint32_t size, RTHCUINTPTR dwUserdata)
1186{
1187 DISCPUSTATE *pCpu = (DISCPUSTATE *)dwUserdata;
1188 PVM pVM = (PVM)pCpu->dwUserData[0];
1189
1190 int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
1191 AssertRC(rc);
1192 return rc;
1193}
1194
1195inline bool iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
1196{
1197 return VBOX_SUCCESS(DISCoreOneEx(InstrGC, pCpu->mode, iomReadBytes, pVM, pCpu, pOpsize));
1198}
1199#else
1200inline bool iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
1201{
1202 return DISCoreOne(pCpu, InstrGC, pOpsize);
1203}
1204
1205#endif
1206
1207/**
1208 * \#PF Handler callback for MMIO ranges.
1209 * Note: we are on ring0 in Hypervisor and interrupts are disabled.
1210 *
1211 * @returns VBox status code (appropriate for GC return).
1212 * @param pVM VM Handle.
1213 * @param uErrorCode CPU Error code.
1214 * @param pRegFrame Trap register frame.
1215 * @param pvFault The fault address (cr2).
1216 * @param GCPhysFault The GC physical address corresponding to pvFault.
1217 * @param pvUser Pointer to the MMIO ring-3 range entry.
1218 */
1219IOMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1220{
1221 STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
1222 NOREF(pvUser); /** @todo implement pvUser usage! */
1223 Log3(("IOMMMIOHandler: GCPhys=%RGp uErr=%#x pvFault=%p eip=%RGv\n",
1224 GCPhysFault, uErrorCode, pvFault, pRegFrame->eip));
1225
1226 /*
1227 * Find the corresponding MMIO range.
1228 */
1229 CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysFault);
1230 if (!pRange)
1231 {
1232#ifdef VBOX_WITH_STATISTICS
1233 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
1234 if (pStats)
1235 {
1236 if (uErrorCode & X86_TRAP_PF_RW)
1237 STAM_COUNTER_INC(&pStats->WriteGCToR3);
1238 else
1239 STAM_COUNTER_INC(&pStats->ReadGCToR3);
1240 }
1241#endif
1242 PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhysFault);
1243 if (pRangeR3)
1244 {
1245 STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
1246 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
1247 return (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
1248 }
1249
1250 /*
1251 * Now, why are we here...
1252 */
1253 AssertMsgFailed(("Internal error! GCPhysFault=%x\n", GCPhysFault));
1254 return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
1255 }
1256
1257 /*
1258 * Convert CS:EIP to linear address and initialize the disassembler.
1259 */
1260 DISCPUSTATE cpu;
1261 cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
1262
1263 RTGCPTR pvCode;
1264 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)(cpu.mode == CPUMODE_32BIT ? pRegFrame->eip : pRegFrame->eip & 0xffff), &pvCode);
1265 if (VBOX_FAILURE(rc))
1266 {
1267 AssertMsgFailed(("Internal error! cs:eip=%04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
1268 return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
1269 }
1270
1271 /*
1272 * Disassemble the instruction and interprete it.
1273 */
1274 unsigned cbOp;
1275 if (iomDisCoreOne(pVM, &cpu, (RTGCUINTPTR)pvCode, &cbOp))
1276 {
1277 switch (cpu.pCurInstr->opcode)
1278 {
1279 case OP_MOV:
1280 case OP_MOVZX:
1281 case OP_MOVSX:
1282 {
1283 STAM_PROFILE_START(&pVM->iom.s.StatGCInstMov, b);
1284 if (uErrorCode & X86_TRAP_PF_RW)
1285 rc = iomGCInterpretMOVxXWrite(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
1286 else
1287 rc = iomGCInterpretMOVxXRead(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
1288 if (rc == VINF_SUCCESS)
1289 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMov, b);
1290 break;
1291 }
1292
1293
1294#ifdef IOMGC_MOVS_SUPPORT
1295 case OP_MOVSB:
1296 case OP_MOVSWD:
1297 rc = iomGCInterpretMOVS(pVM, uErrorCode, pRegFrame, GCPhysFault, &cpu, pRange);
1298 break;
1299#endif
1300
1301 case OP_STOSB:
1302 case OP_STOSWD:
1303 Assert(uErrorCode & X86_TRAP_PF_RW);
1304 rc = iomGCInterpretSTOS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1305 break;
1306
1307 case OP_LODSB:
1308 case OP_LODSWD:
1309 Assert(!(uErrorCode & X86_TRAP_PF_RW));
1310 rc = iomGCInterpretLODS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1311 break;
1312
1313
1314 case OP_CMP:
1315 Assert(!(uErrorCode & X86_TRAP_PF_RW));
1316 rc = iomGCInterpretCMP(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1317 break;
1318
1319 case OP_AND:
1320 rc = iomGCInterpretAND(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1321 break;
1322
1323 case OP_TEST:
1324 Assert(!(uErrorCode & X86_TRAP_PF_RW));
1325 rc = iomGCInterpretTEST(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1326 break;
1327
1328 case OP_XCHG:
1329 rc = iomGCInterpretXCHG(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
1330 break;
1331
1332
1333 /*
1334 * The instruction isn't supported. Hand it on to ring-3.
1335 */
1336 default:
1337 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOther);
1338 rc = (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
1339 break;
1340 }
1341 }
1342 else
1343 {
1344 AssertMsgFailed(("Disassembler freaked out!\n"));
1345 rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
1346 }
1347
1348 /*
1349 * On success advance EIP.
1350 */
1351 if (rc == VINF_SUCCESS)
1352 pRegFrame->eip += cbOp;
1353 else
1354 {
1355 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
1356#ifdef VBOX_WITH_STATISTICS
1357 switch (rc)
1358 {
1359 case VINF_IOM_HC_MMIO_READ:
1360 case VINF_IOM_HC_MMIO_WRITE:
1361 case VINF_IOM_HC_MMIO_READ_WRITE:
1362 {
1363 PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
1364 if (pStats)
1365 {
1366 if (uErrorCode & X86_TRAP_PF_RW)
1367 STAM_COUNTER_INC(&pStats->WriteGCToR3);
1368 else
1369 STAM_COUNTER_INC(&pStats->ReadGCToR3);
1370 }
1371 }
1372 break;
1373 }
1374#endif
1375 }
1376 STAM_PROFILE_STOP(&pVM->iom.s.StatGCMMIOHandler, a);
1377 return rc;
1378}
1379
1380
1381#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