VirtualBox

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

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

string.h & stdio.h + header cleanups.

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