VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMGC/IOMGC.cpp@ 2009

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

Use new disassembler functions. Remove obsolete tables.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.1 KB
Line 
1/* $Id: IOMGC.cpp 1936 2007-04-04 15:06:13Z 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
48/** @def IOMGC_MOVS_SUPPORT
49 * Define IOMGC_MOVS_SUPPORT for movsb/w/d support in GC.
50 */
51#define IOMGC_MOVS_SUPPORT
52
53
54/*******************************************************************************
55* Internal Functions *
56*******************************************************************************/
57#if 0
58static bool iomGCCalcParamEA(PDISCPUSTATE pCpu, POP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, void **ppAddr);
59#endif
60static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam);
61static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize);
62static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t u32Data);
63
64
65/*******************************************************************************
66* Global Variables *
67*******************************************************************************/
68
69/**
70 * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
71 */
72static const unsigned g_aSize2Shift[] =
73{
74 ~0, /* 0 - invalid */
75 0, /* *1 == 2^0 */
76 1, /* *2 == 2^1 */
77 ~0, /* 3 - invalid */
78 2, /* *4 == 2^2 */
79 ~0, /* 5 - invalid */
80 ~0, /* 6 - invalid */
81 ~0, /* 7 - invalid */
82 3 /* *8 == 2^3 */
83};
84
85/**
86 * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
87 */
88#define SIZE2SHIFT(cb) (g_aSize2Shift[cb])
89
90
91#if 0
92/**
93 * Calculates effective address (offset from current segment register) for
94 * instruction parameter, i.e. [eax + esi*4 + 1234h] -> virtual address.
95 *
96 * @returns true on success.
97 * @param pCpu Pointer to current disassembler context.
98 * @param pParam Pointer to parameter of instruction to calc EA.
99 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
100 * @param ppAddr Where to store result address.
101 */
102static bool iomGCCalcParamEA(PDISCPUSTATE pCpu, POP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, void **ppAddr)
103{
104 uint8_t *pAddr = 0;
105
106 if (pCpu->addrmode == CPUMODE_32BIT)
107 {
108 /* 32-bit addressing. */
109 if (pParam->flags & USE_BASE)
110 pAddr += ACCESS_REG32(pRegFrame, pParam->base.reg_gen32);
111 if (pParam->flags & USE_INDEX)
112 {
113 unsigned i = ACCESS_REG32(pRegFrame, pParam->index.reg_gen);
114 if (pParam->flags & USE_SCALE)
115 i *= pParam->scale;
116 pAddr += i;
117 }
118 if (pParam->flags & USE_DISPLACEMENT8)
119 pAddr += pParam->disp8;
120 else
121 if (pParam->flags & USE_DISPLACEMENT16)
122 pAddr += pParam->disp16;
123 else
124 if (pParam->flags & USE_DISPLACEMENT32)
125 pAddr += pParam->disp32;
126
127 if (pParam->flags & (USE_BASE | USE_INDEX | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
128 {
129 /* EA present in parameter. */
130 *ppAddr = pAddr;
131 return true;
132 }
133 }
134 else
135 {
136 /* 16-bit addressing. */
137 if (pParam->flags & USE_BASE)
138 pAddr += ACCESS_REG16(pRegFrame, pParam->base.reg_gen16);
139 if (pParam->flags & USE_INDEX)
140 pAddr += ACCESS_REG16(pRegFrame, pParam->index.reg_gen);
141 if (pParam->flags & USE_DISPLACEMENT8)
142 pAddr += pParam->disp8;
143 else
144 if (pParam->flags & USE_DISPLACEMENT16)
145 pAddr += pParam->disp16;
146
147 if (pParam->flags & (USE_BASE | USE_INDEX | USE_DISPLACEMENT8 | USE_DISPLACEMENT16))
148 {
149 /* EA present in parameter. */
150 *ppAddr = pAddr;
151 return true;
152 }
153 }
154
155 /* Error exit. */
156 return false;
157}
158#endif
159
160/**
161 * Calculates the size of register parameter.
162 *
163 * @returns 1, 2, 4 on success.
164 * @returns 0 if non-register parameter.
165 * @param pCpu Pointer to current disassembler context.
166 * @param pParam Pointer to parameter of instruction to proccess.
167 */
168static unsigned iomGCGetRegSize(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam)
169{
170 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))
171 return 0;
172
173 if (pParam->flags & USE_REG_GEN32)
174 return 4;
175
176 if (pParam->flags & USE_REG_GEN16)
177 return 2;
178
179 if (pParam->flags & USE_REG_GEN8)
180 return 1;
181
182 if (pParam->flags & USE_REG_SEG)
183 return 2;
184 return 0;
185}
186
187/**
188 * Returns the contents of register or immediate data of instruction's parameter.
189 *
190 * @returns true on success.
191 *
192 * @param pCpu Pointer to current disassembler context.
193 * @param pParam Pointer to parameter of instruction to proccess.
194 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
195 * @param pu32Data Where to store retrieved data.
196 * @param pcbSize Where to store the size of data (1, 2, 4).
197 */
198static bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize)
199{
200 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
201 {
202 *pcbSize = 0;
203 *pu32Data = 0;
204 return false;
205 }
206
207 if (pParam->flags & USE_REG_GEN32)
208 {
209 *pcbSize = 4;
210 DISFetchReg32(pRegFrame, pParam->base.reg_gen32, pu32Data);
211 return true;
212 }
213
214 if (pParam->flags & USE_REG_GEN16)
215 {
216 *pcbSize = 2;
217 DISFetchReg16(pRegFrame, pParam->base.reg_gen16, (uint16_t *)pu32Data);
218 return true;
219 }
220
221 if (pParam->flags & USE_REG_GEN8)
222 {
223 *pcbSize = 1;
224 DISFetchReg8(pRegFrame, pParam->base.reg_gen8, (uint8_t *)pu32Data);
225 return true;
226 }
227
228 if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_SX8))
229 {
230 *pcbSize = 4;
231 *pu32Data = (uint32_t)pParam->parval;
232 return true;
233 }
234
235 if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_SX8))
236 {
237 *pcbSize = 2;
238 *pu32Data = (uint16_t)pParam->parval;
239 return true;
240 }
241
242 if (pParam->flags & USE_IMMEDIATE8)
243 {
244 *pcbSize = 1;
245 *pu32Data = (uint8_t)pParam->parval;
246 return true;
247 }
248
249 if (pParam->flags & USE_REG_SEG)
250 {
251 *pcbSize = 2;
252 DISFetchRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL *)pu32Data);
253 return true;
254 } /* Else - error. */
255
256 *pcbSize = 0;
257 *pu32Data = 0;
258 return false;
259}
260
261
262/**
263 * Saves data to 8/16/32 general purpose or segment register defined by
264 * instruction's parameter.
265 *
266 * @returns true on success.
267 * @param pCpu Pointer to current disassembler context.
268 * @param pParam Pointer to parameter of instruction to proccess.
269 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
270 * @param u32Data 8/16/32 bit data to store.
271 */
272static bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, unsigned u32Data)
273{
274 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))
275 {
276 return false;
277 }
278
279 if (pParam->flags & USE_REG_GEN32)
280 {
281 DISWriteReg32(pRegFrame, pParam->base.reg_gen32, u32Data);
282 return true;
283 }
284
285 if (pParam->flags & USE_REG_GEN16)
286 {
287 DISWriteReg16(pRegFrame, pParam->base.reg_gen16, (uint16_t)u32Data);
288 return true;
289 }
290
291 if (pParam->flags & USE_REG_GEN8)
292 {
293 DISWriteReg8(pRegFrame, pParam->base.reg_gen8, (uint8_t)u32Data);
294 return true;
295 }
296
297 if (pParam->flags & USE_REG_SEG)
298 {
299 DISWriteRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL)u32Data);
300 return true;
301 }
302
303 /* Else - error. */
304 return false;
305}
306
307
308/*
309 * Internal - statistics only.
310 */
311inline void iomGCMMIOStatLength(PVM pVM, unsigned cb)
312{
313#ifdef VBOX_WITH_STATISTICS
314 switch (cb)
315 {
316 case 1:
317 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO1Byte);
318 break;
319 case 2:
320 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO2Bytes);
321 break;
322 case 4:
323 STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO4Bytes);
324 break;
325 default:
326 /* No way. */
327 AssertMsgFailed(("Invalid data length %d\n", cb));
328 break;
329 }
330#else
331 NOREF(pVM); NOREF(cb);
332#endif
333}
334
335
336/**
337 * IN <AL|AX|EAX>, <DX|imm16>
338 *
339 * @returns VBox status code.
340 *
341 * @param pVM The virtual machine (GC pointer ofcourse).
342 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
343 * @param pCpu Disassembler CPU state.
344 */
345IOMDECL(int) IOMInterpretIN(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
346{
347#ifdef VBOX_WITH_STATISTICS
348 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIn);
349#endif
350
351 /*
352 * Get port number from second parameter.
353 * And get the register size from the first parameter.
354 */
355 uint32_t uPort = 0;
356 unsigned cbSize = 0;
357 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uPort, &cbSize);
358 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
359
360 cbSize = iomGCGetRegSize(pCpu, &pCpu->param1);
361 Assert(cbSize > 0);
362 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
363 if (rc == VINF_SUCCESS)
364 {
365 /*
366 * Attemp to read the port.
367 */
368 uint32_t u32Data = ~0U;
369 rc = IOMIOPortRead(pVM, uPort, &u32Data, cbSize);
370 if (rc == VINF_SUCCESS)
371 {
372 /*
373 * Store the result in the AL|AX|EAX register.
374 */
375 fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data);
376 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
377 }
378 }
379 return rc;
380}
381
382
383/**
384 * OUT <DX|imm16>, <AL|AX|EAX>
385 *
386 * @returns VBox status code.
387 *
388 * @param pVM The virtual machine (GC pointer ofcourse).
389 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
390 * @param pCpu Disassembler CPU state.
391 */
392IOMDECL(int) IOMInterpretOUT(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
393{
394#ifdef VBOX_WITH_STATISTICS
395 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOut);
396#endif
397
398 /*
399 * Get port number from first parameter.
400 * And get the register size and value from the second parameter.
401 */
402 uint32_t uPort = 0;
403 unsigned cbSize = 0;
404 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
405 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
406
407 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
408 if (rc == VINF_SUCCESS)
409 {
410 uint32_t u32Data = 0;
411 fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u32Data, &cbSize);
412 AssertMsg(fRc, ("Failed to get reg value!\n")); NOREF(fRc);
413
414 /*
415 * Attemp to write to the port.
416 */
417 rc = IOMIOPortWrite(pVM, uPort, u32Data, cbSize);
418 }
419 return rc;
420}
421
422
423/**
424 * [REP*] INSB/INSW/INSD
425 * ES:EDI,DX[,ECX]
426 *
427 * @returns VBox status code.
428 *
429 * @param pVM The virtual machine (GC pointer ofcourse).
430 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
431 * @param pCpu Disassembler CPU state.
432 */
433IOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
434{
435#ifdef VBOX_WITH_STATISTICS
436 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);
437#endif
438
439 /*
440 * We do not support REPNE, 16-bit addressing or decrementing destination
441 * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
442 */
443 if ( pCpu->prefix & PREFIX_REPNE
444 || (pCpu->addrmode != CPUMODE_32BIT)
445 || pRegFrame->eflags.Bits.u1DF)
446 return VINF_IOM_HC_IOPORT_READ;
447
448 /*
449 * Get port number directly from the register (no need to bother the
450 * disassembler). And get the I/O register size from the opcode / prefix.
451 */
452 uint32_t uPort = pRegFrame->edx & 0xffff;
453 unsigned cbSize = 0;
454 if (pCpu->pCurInstr->opcode == OP_INSB)
455 cbSize = 1;
456 else
457 cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
458
459 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
460 if (rc == VINF_SUCCESS)
461 {
462 /*
463 * Get bytes/words/dwords count to transfer.
464 */
465 RTGCUINTREG cTransfers = 1;
466 if (pCpu->prefix & PREFIX_REP)
467 {
468 cTransfers = pRegFrame->ecx;
469 if (!cTransfers)
470 return VINF_SUCCESS;
471 }
472
473 /* Convert destination address es:edi. */
474 RTGCPTR GCPtrDst;
475 rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi,
476 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
477 &GCPtrDst, NULL);
478 if (VBOX_FAILURE(rc))
479 {
480 Log(("INS destination address conversion failed -> fallback, rc=%d\n", rc));
481 return VINF_IOM_HC_IOPORT_READ;
482 }
483
484 /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
485 uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
486
487 rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrDst, cTransfers * cbSize,
488 X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
489 if (rc != VINF_SUCCESS)
490 {
491 Log(("INS will generate a trap -> fallback, rc=%d\n", rc));
492 return VINF_IOM_HC_IOPORT_READ;
493 }
494
495 Log(("IOMGC: rep ins%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
496 MMGCRamRegisterTrapHandler(pVM);
497
498 /* If the device supports string transfers, ask it to do as
499 * much as it wants. The rest is done with single-word transfers. */
500 const RTGCUINTREG cTransfersOrg = cTransfers;
501 rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbSize);
502 AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
503 pRegFrame->edi += (cTransfersOrg - cTransfers) * cbSize;
504
505 while (cTransfers && rc == VINF_SUCCESS)
506 {
507 uint32_t u32Value;
508 rc = IOMIOPortRead(pVM, uPort, &u32Value, cbSize);
509 if (rc == VINF_IOM_HC_IOPORT_READ || VBOX_FAILURE(rc))
510 break;
511 int rc2 = MMGCRamWriteNoTrapHandler(GCPtrDst, &u32Value, cbSize);
512 Assert(rc2 == VINF_SUCCESS); NOREF(rc2);
513 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbSize);
514 pRegFrame->edi += cbSize;
515 cTransfers--;
516 }
517 MMGCRamDeregisterTrapHandler(pVM);
518
519 /* Update ecx on exit. */
520 if (pCpu->prefix & PREFIX_REP)
521 pRegFrame->ecx = cTransfers;
522 }
523 return rc;
524}
525
526
527/**
528 * [REP*] OUTSB/OUTSW/OUTSD
529 * DS:ESI,DX[,ECX]
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 */
537IOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
538{
539#ifdef VBOX_WITH_STATISTICS
540 STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);
541#endif
542
543 /*
544 * We do not support segment prefixes, REPNE, 16-bit addressing or
545 * decrementing source pointer.
546 */
547 if ( pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE)
548 || (pCpu->addrmode != CPUMODE_32BIT)
549 || pRegFrame->eflags.Bits.u1DF)
550 return VINF_IOM_HC_IOPORT_WRITE;
551
552 /*
553 * Get port number from the first parameter.
554 * And get the I/O register size from the opcode / prefix.
555 */
556 uint32_t uPort = 0;
557 unsigned cbSize = 0;
558 bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
559 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
560 if (pCpu->pCurInstr->opcode == OP_OUTSB)
561 cbSize = 1;
562 else
563 cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
564
565 int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
566 if (rc == VINF_SUCCESS)
567 {
568 /*
569 * Get bytes/words/dwords count to transfer.
570 */
571 RTGCUINTREG cTransfers = 1;
572 if (pCpu->prefix & PREFIX_REP)
573 {
574 cTransfers = pRegFrame->ecx;
575 if (!cTransfers)
576 return VINF_SUCCESS;
577 }
578
579 /* Convert source address ds:esi. */
580 RTGCPTR GCPtrSrc;
581 rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi,
582 SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
583 &GCPtrSrc, NULL);
584 if (VBOX_FAILURE(rc))
585 {
586 Log(("OUTS source address conversion failed -> fallback, rc=%d\n", rc));
587 return VINF_IOM_HC_IOPORT_WRITE;
588 }
589
590 /* Access verification first; we currently can't recover properly from traps inside this instruction */
591 uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
592 rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbSize,
593 (cpl == 3) ? X86_PTE_US : 0);
594 if (rc != VINF_SUCCESS)
595 {
596 Log(("OUTS will generate a trap -> fallback, rc=%d\n", rc));
597 return VINF_IOM_HC_IOPORT_WRITE;
598 }
599
600 Log(("IOMGC: rep outs%d port %#x count %d\n", cbSize * 8, uPort, cTransfers));
601 MMGCRamRegisterTrapHandler(pVM);
602
603 /*
604 * If the device supports string transfers, ask it to do as
605 * much as it wants. The rest is done with single-word transfers.
606 */
607 const RTGCUINTREG cTransfersOrg = cTransfers;
608 rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbSize);
609 AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
610 pRegFrame->esi += (cTransfersOrg - cTransfers) * cbSize;
611
612 while (cTransfers && rc == VINF_SUCCESS)
613 {
614 uint32_t u32Value;
615 rc = MMGCRamReadNoTrapHandler(&u32Value, GCPtrSrc, cbSize);
616 if (rc != VINF_SUCCESS)
617 break;
618 rc = IOMIOPortWrite(pVM, uPort, u32Value, cbSize);
619 if (rc == VINF_IOM_HC_IOPORT_WRITE)
620 break;
621 GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbSize);
622 pRegFrame->esi += cbSize;
623 cTransfers--;
624 }
625
626 MMGCRamDeregisterTrapHandler(pVM);
627
628 /* Update ecx on exit. */
629 if (pCpu->prefix & PREFIX_REP)
630 pRegFrame->ecx = cTransfers;
631 }
632 return rc;
633}
634
635
636/**
637 * Attempts to service an IN/OUT instruction.
638 *
639 * The \#GP trap handler in GC will call this function if the opcode causing the
640 * trap is a in or out type instruction.
641 *
642 * @returns VBox status code.
643 *
644 * @param pVM The virtual machine (GC pointer ofcourse).
645 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
646 * @param pCpu Disassembler CPU state.
647 */
648IOMGCDECL(int) IOMGCIOPortHandler(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
649{
650 switch (pCpu->pCurInstr->opcode)
651 {
652 case OP_IN:
653 return IOMInterpretIN(pVM, pRegFrame, pCpu);
654
655 case OP_OUT:
656 return IOMInterpretOUT(pVM, pRegFrame, pCpu);
657
658 case OP_INSB:
659 case OP_INSWD:
660 return IOMInterpretINS(pVM, pRegFrame, pCpu);
661
662 case OP_OUTSB:
663 case OP_OUTSWD:
664 return IOMInterpretOUTS(pVM, pRegFrame, pCpu);
665
666 /*
667 * The opcode wasn't know to us, freak out.
668 */
669 default:
670 AssertMsgFailed(("Unknown I/O port access opcode %d.\n", pCpu->pCurInstr->opcode));
671 return VERR_INTERNAL_ERROR;
672 }
673}
674
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