VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IOMAll.cpp@ 37387

Last change on this file since 37387 was 36794, checked in by vboxsync, 14 years ago

IEM: Verify I/O port read and writes as well as MMIO accesses. Implemented some more instructions, getting thru the BIOS now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 38.5 KB
Line 
1/* $Id: IOMAll.cpp 36794 2011-04-21 15:02:34Z vboxsync $ */
2/** @file
3 * IOM - Input / Output Monitor - Any Context.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_IOM
22#include <VBox/vmm/iom.h>
23#include <VBox/vmm/mm.h>
24#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
25# include <VBox/vmm/iem.h>
26#endif
27#include <VBox/param.h>
28#include "IOMInternal.h"
29#include <VBox/vmm/vm.h>
30#include <VBox/vmm/vmm.h>
31#include <VBox/vmm/selm.h>
32#include <VBox/vmm/trpm.h>
33#include <VBox/vmm/pdmdev.h>
34#include <VBox/vmm/pgm.h>
35#include <VBox/vmm/cpum.h>
36#include <VBox/err.h>
37#include <VBox/log.h>
38#include <iprt/assert.h>
39
40
41
42/**
43 * Try take the EMT/IOM lock, wait in ring-3 return VERR_SEM_BUSY in R0/RC.
44 *
45 * @retval VINF_SUCCESS on success (always in ring-3).
46 * @retval VERR_SEM_BUSY in RC and R0 if the semaphore is busy.
47 *
48 * @param pVM VM handle.
49 */
50int iomLock(PVM pVM)
51{
52 Assert(pVM->cCpus == 1 || !PGMIsLockOwner(pVM));
53 int rc = PDMCritSectEnter(&pVM->iom.s.EmtLock, VERR_SEM_BUSY);
54 return rc;
55}
56
57
58/**
59 * Try take the EMT/IOM lock, no waiting.
60 *
61 * @retval VINF_SUCCESS on success.
62 * @retval VERR_SEM_BUSY if busy.
63 *
64 * @param pVM VM handle.
65 */
66int iomTryLock(PVM pVM)
67{
68 int rc = PDMCritSectTryEnter(&pVM->iom.s.EmtLock);
69 return rc;
70}
71
72
73/**
74 * Release EMT/IOM lock.
75 *
76 * @param pVM VM handle.
77 */
78void iomUnlock(PVM pVM)
79{
80 PDMCritSectLeave(&pVM->iom.s.EmtLock);
81}
82
83
84/**
85 * Check if this VCPU currently owns the IOM lock.
86 *
87 * @returns bool owner/not owner
88 * @param pVM The VM to operate on.
89 */
90VMMDECL(bool) IOMIsLockOwner(PVM pVM)
91{
92 return PDMCritSectIsOwner(&pVM->iom.s.EmtLock);
93}
94
95/**
96 * Returns the contents of register or immediate data of instruction's parameter.
97 *
98 * @returns true on success.
99 *
100 * @todo Get rid of this code. Use DISQueryParamVal instead
101 *
102 * @param pCpu Pointer to current disassembler context.
103 * @param pParam Pointer to parameter of instruction to process.
104 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
105 * @param pu64Data Where to store retrieved data.
106 * @param pcbSize Where to store the size of data (1, 2, 4, 8).
107 */
108bool iomGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint64_t *pu64Data, unsigned *pcbSize)
109{
110 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
111 {
112 *pcbSize = 0;
113 *pu64Data = 0;
114 return false;
115 }
116
117 /* divide and conquer */
118 if (pParam->flags & (USE_REG_GEN64 | USE_REG_GEN32 | USE_REG_GEN16 | USE_REG_GEN8))
119 {
120 if (pParam->flags & USE_REG_GEN32)
121 {
122 *pcbSize = 4;
123 DISFetchReg32(pRegFrame, pParam->base.reg_gen, (uint32_t *)pu64Data);
124 return true;
125 }
126
127 if (pParam->flags & USE_REG_GEN16)
128 {
129 *pcbSize = 2;
130 DISFetchReg16(pRegFrame, pParam->base.reg_gen, (uint16_t *)pu64Data);
131 return true;
132 }
133
134 if (pParam->flags & USE_REG_GEN8)
135 {
136 *pcbSize = 1;
137 DISFetchReg8(pRegFrame, pParam->base.reg_gen, (uint8_t *)pu64Data);
138 return true;
139 }
140
141 Assert(pParam->flags & USE_REG_GEN64);
142 *pcbSize = 8;
143 DISFetchReg64(pRegFrame, pParam->base.reg_gen, pu64Data);
144 return true;
145 }
146 else
147 {
148 if (pParam->flags & (USE_IMMEDIATE64 | USE_IMMEDIATE64_SX8))
149 {
150 *pcbSize = 8;
151 *pu64Data = pParam->parval;
152 return true;
153 }
154
155 if (pParam->flags & (USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8))
156 {
157 *pcbSize = 4;
158 *pu64Data = (uint32_t)pParam->parval;
159 return true;
160 }
161
162 if (pParam->flags & (USE_IMMEDIATE16 | USE_IMMEDIATE16_SX8))
163 {
164 *pcbSize = 2;
165 *pu64Data = (uint16_t)pParam->parval;
166 return true;
167 }
168
169 if (pParam->flags & USE_IMMEDIATE8)
170 {
171 *pcbSize = 1;
172 *pu64Data = (uint8_t)pParam->parval;
173 return true;
174 }
175
176 if (pParam->flags & USE_REG_SEG)
177 {
178 *pcbSize = 2;
179 DISFetchRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL *)pu64Data);
180 return true;
181 } /* Else - error. */
182
183 AssertFailed();
184 *pcbSize = 0;
185 *pu64Data = 0;
186 return false;
187 }
188}
189
190
191/**
192 * Saves data to 8/16/32 general purpose or segment register defined by
193 * instruction's parameter.
194 *
195 * @returns true on success.
196 * @param pCpu Pointer to current disassembler context.
197 * @param pParam Pointer to parameter of instruction to process.
198 * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
199 * @param u64Data 8/16/32/64 bit data to store.
200 */
201bool iomSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint64_t u64Data)
202{
203 if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8 | USE_IMMEDIATE16_SX8))
204 {
205 return false;
206 }
207
208 if (pParam->flags & USE_REG_GEN32)
209 {
210 DISWriteReg32(pRegFrame, pParam->base.reg_gen, (uint32_t)u64Data);
211 return true;
212 }
213
214 if (pParam->flags & USE_REG_GEN64)
215 {
216 DISWriteReg64(pRegFrame, pParam->base.reg_gen, u64Data);
217 return true;
218 }
219
220 if (pParam->flags & USE_REG_GEN16)
221 {
222 DISWriteReg16(pRegFrame, pParam->base.reg_gen, (uint16_t)u64Data);
223 return true;
224 }
225
226 if (pParam->flags & USE_REG_GEN8)
227 {
228 DISWriteReg8(pRegFrame, pParam->base.reg_gen, (uint8_t)u64Data);
229 return true;
230 }
231
232 if (pParam->flags & USE_REG_SEG)
233 {
234 DISWriteRegSeg(pRegFrame, pParam->base.reg_seg, (RTSEL)u64Data);
235 return true;
236 }
237
238 /* Else - error. */
239 return false;
240}
241
242
243//#undef LOG_GROUP
244//#define LOG_GROUP LOG_GROUP_IOM_IOPORT
245
246/**
247 * Reads an I/O port register.
248 *
249 * @returns Strict VBox status code. Informational status codes other than the one documented
250 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
251 * @retval VINF_SUCCESS Success.
252 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
253 * status code must be passed on to EM.
254 * @retval VINF_IOM_HC_IOPORT_READ Defer the read to ring-3. (R0/GC only)
255 *
256 * @param pVM VM handle.
257 * @param Port The port to read.
258 * @param pu32Value Where to store the value read.
259 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
260 */
261VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVM pVM, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue)
262{
263 /* Take the IOM lock before performing any device I/O. */
264 int rc2 = iomLock(pVM);
265#ifndef IN_RING3
266 if (rc2 == VERR_SEM_BUSY)
267 return VINF_IOM_HC_IOPORT_READ;
268#endif
269 AssertRC(rc2);
270#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
271 IEMNotifyIOPortRead(pVM, Port, cbValue);
272#endif
273
274#ifdef VBOX_WITH_STATISTICS
275 /*
276 * Get the statistics record.
277 */
278 PIOMIOPORTSTATS pStats = pVM->iom.s.CTX_SUFF(pStatsLastRead);
279 if (!pStats || pStats->Core.Key != Port)
280 {
281 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, Port);
282 if (pStats)
283 pVM->iom.s.CTX_SUFF(pStatsLastRead) = pStats;
284 }
285#endif
286
287 /*
288 * Get handler for current context.
289 */
290 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVM->iom.s.CTX_SUFF(pRangeLastRead);
291 if ( !pRange
292 || (unsigned)Port - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
293 {
294 pRange = iomIOPortGetRange(&pVM->iom.s, Port);
295 if (pRange)
296 pVM->iom.s.CTX_SUFF(pRangeLastRead) = pRange;
297 }
298 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
299 if (pRange)
300 {
301 /*
302 * Found a range, get the data in case we leave the IOM lock.
303 */
304 PFNIOMIOPORTIN pfnInCallback = pRange->pfnInCallback;
305#ifndef IN_RING3
306 if (!pfnInCallback)
307 {
308 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
309 iomUnlock(pVM);
310 return VINF_IOM_HC_IOPORT_READ;
311 }
312#endif
313 void *pvUser = pRange->pvUser;
314 PPDMDEVINS pDevIns = pRange->pDevIns;
315 PPDMCRITSECT pCritSect = pDevIns->CTX_SUFF(pCritSect);
316
317 /*
318 * Call the device - 4 variations.
319 */
320 VBOXSTRICTRC rcStrict;
321 if (pCritSect)
322 {
323 iomUnlock(pVM);
324 rcStrict = PDMCritSectEnter(pCritSect, VINF_IOM_HC_IOPORT_READ);
325 if (rcStrict != VINF_SUCCESS)
326 {
327 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
328 return rcStrict;
329 }
330#ifdef VBOX_WITH_STATISTICS
331 if (pStats)
332 {
333 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
334 rcStrict = pfnInCallback(pDevIns, pvUser, Port, pu32Value, (unsigned)cbValue);
335 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
336 }
337 else
338#endif
339 rcStrict = pfnInCallback(pDevIns, pvUser, Port, pu32Value, (unsigned)cbValue);
340 PDMCritSectLeave(pCritSect);
341 }
342 else
343 {
344#ifdef VBOX_WITH_STATISTICS
345 if (pStats)
346 {
347 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
348 rcStrict = pfnInCallback(pDevIns, pvUser, Port, pu32Value, (unsigned)cbValue);
349 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
350 }
351 else
352#endif
353 rcStrict = pfnInCallback(pDevIns, pvUser, Port, pu32Value, (unsigned)cbValue);
354 }
355#ifdef VBOX_WITH_STATISTICS
356 if (rcStrict == VINF_SUCCESS && pStats)
357 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
358# ifndef IN_RING3
359 else if (rcStrict == VINF_IOM_HC_IOPORT_READ && pStats)
360 STAM_COUNTER_INC(&pStats->InRZToR3);
361# endif
362#endif
363 if (rcStrict == VERR_IOM_IOPORT_UNUSED)
364 {
365 /* make return value */
366 rcStrict = VINF_SUCCESS;
367 switch (cbValue)
368 {
369 case 1: *(uint8_t *)pu32Value = 0xff; break;
370 case 2: *(uint16_t *)pu32Value = 0xffff; break;
371 case 4: *(uint32_t *)pu32Value = UINT32_C(0xffffffff); break;
372 default:
373 AssertMsgFailed(("Invalid I/O port size %d. Port=%d\n", cbValue, Port));
374 if (!pCritSect)
375 iomUnlock(pVM);
376 return VERR_IOM_INVALID_IOPORT_SIZE;
377 }
378 }
379 Log3(("IOMIOPortRead: Port=%RTiop *pu32=%08RX32 cb=%d rc=%Rrc\n", Port, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rcStrict)));
380 if (!pCritSect)
381 iomUnlock(pVM);
382 return rcStrict;
383 }
384
385#ifndef IN_RING3
386 /*
387 * Handler in ring-3?
388 */
389 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(&pVM->iom.s, Port);
390 if (pRangeR3)
391 {
392# ifdef VBOX_WITH_STATISTICS
393 if (pStats)
394 STAM_COUNTER_INC(&pStats->InRZToR3);
395# endif
396 iomUnlock(pVM);
397 return VINF_IOM_HC_IOPORT_READ;
398 }
399#endif
400
401 /*
402 * Ok, no handler for this port.
403 */
404#ifdef VBOX_WITH_STATISTICS
405 if (pStats)
406 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
407 else
408 {
409# ifndef IN_RING3
410 /* Ring-3 will have to create the statistics record. */
411 iomUnlock(pVM);
412 return VINF_IOM_HC_IOPORT_READ;
413# else
414 pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
415 if (pStats)
416 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
417# endif
418 }
419#endif
420
421 /* make return value */
422 switch (cbValue)
423 {
424 case 1: *(uint8_t *)pu32Value = 0xff; break;
425 case 2: *(uint16_t *)pu32Value = 0xffff; break;
426 case 4: *(uint32_t *)pu32Value = UINT32_C(0xffffffff); break;
427 default:
428 AssertMsgFailed(("Invalid I/O port size %d. Port=%d\n", cbValue, Port));
429 iomUnlock(pVM);
430 return VERR_IOM_INVALID_IOPORT_SIZE;
431 }
432 Log3(("IOMIOPortRead: Port=%RTiop *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", Port, *pu32Value, cbValue));
433 iomUnlock(pVM);
434 return VINF_SUCCESS;
435}
436
437
438/**
439 * Reads the string buffer of an I/O port register.
440 *
441 * @returns Strict VBox status code. Informational status codes other than the one documented
442 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
443 * @retval VINF_SUCCESS Success.
444 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
445 * status code must be passed on to EM.
446 * @retval VINF_IOM_HC_IOPORT_READ Defer the read to ring-3. (R0/GC only)
447 *
448 * @param pVM VM handle.
449 * @param Port The port to read.
450 * @param pGCPtrDst Pointer to the destination buffer (GC, incremented appropriately).
451 * @param pcTransfers Pointer to the number of transfer units to read, on return remaining transfer units.
452 * @param cb Size of the transfer unit (1, 2 or 4 bytes).
453 */
454VMMDECL(VBOXSTRICTRC) IOMIOPortReadString(PVM pVM, RTIOPORT Port, PRTGCPTR pGCPtrDst, PRTGCUINTREG pcTransfers, unsigned cb)
455{
456 /* Take the IOM lock before performing any device I/O. */
457 int rc2 = iomLock(pVM);
458#ifndef IN_RING3
459 if (rc2 == VERR_SEM_BUSY)
460 return VINF_IOM_HC_IOPORT_READ;
461#endif
462 AssertRC(rc2);
463#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
464 IEMNotifyIOPortReadString(pVM, Port, *pGCPtrDst, *pcTransfers, cb);
465#endif
466
467#ifdef LOG_ENABLED
468 const RTGCUINTREG cTransfers = *pcTransfers;
469#endif
470#ifdef VBOX_WITH_STATISTICS
471 /*
472 * Get the statistics record.
473 */
474 PIOMIOPORTSTATS pStats = pVM->iom.s.CTX_SUFF(pStatsLastRead);
475 if (!pStats || pStats->Core.Key != Port)
476 {
477 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, Port);
478 if (pStats)
479 pVM->iom.s.CTX_SUFF(pStatsLastRead) = pStats;
480 }
481#endif
482
483 /*
484 * Get handler for current context.
485 */
486 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVM->iom.s.CTX_SUFF(pRangeLastRead);
487 if ( !pRange
488 || (unsigned)Port - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
489 {
490 pRange = iomIOPortGetRange(&pVM->iom.s, Port);
491 if (pRange)
492 pVM->iom.s.CTX_SUFF(pRangeLastRead) = pRange;
493 }
494 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
495 if (pRange)
496 {
497 /*
498 * Found a range.
499 */
500 PFNIOMIOPORTINSTRING pfnInStrCallback = pRange->pfnInStrCallback;
501#ifndef IN_RING3
502 if (!pfnInStrCallback)
503 {
504 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
505 iomUnlock(pVM);
506 return VINF_IOM_HC_IOPORT_READ;
507 }
508#endif
509 void *pvUser = pRange->pvUser;
510 PPDMDEVINS pDevIns = pRange->pDevIns;
511 PPDMCRITSECT pCritSect = pDevIns->CTX_SUFF(pCritSect);
512
513 /*
514 * Call the device - 4 variations.
515 */
516 VBOXSTRICTRC rcStrict;
517 if (pCritSect)
518 {
519 iomUnlock(pVM);
520 rcStrict = PDMCritSectEnter(pCritSect, VINF_IOM_HC_IOPORT_READ);
521 if (rcStrict != VINF_SUCCESS)
522 {
523 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
524 return rcStrict;
525 }
526#ifdef VBOX_WITH_STATISTICS
527 if (pStats)
528 {
529 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
530 rcStrict = pfnInStrCallback(pDevIns, pvUser, Port, pGCPtrDst, pcTransfers, cb);
531 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
532 }
533 else
534#endif
535 rcStrict = pfnInStrCallback(pDevIns, pvUser, Port, pGCPtrDst, pcTransfers, cb);
536 PDMCritSectLeave(pCritSect);
537 }
538 else
539 {
540#ifdef VBOX_WITH_STATISTICS
541 if (pStats)
542 {
543 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
544 rcStrict = pfnInStrCallback(pDevIns, pvUser, Port, pGCPtrDst, pcTransfers, cb);
545 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
546 }
547 else
548#endif
549 rcStrict = pfnInStrCallback(pDevIns, pvUser, Port, pGCPtrDst, pcTransfers, cb);
550 }
551
552#ifdef VBOX_WITH_STATISTICS
553 if (rcStrict == VINF_SUCCESS && pStats)
554 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
555# ifndef IN_RING3
556 else if (rcStrict == VINF_IOM_HC_IOPORT_READ && pStats)
557 STAM_COUNTER_INC(&pStats->InRZToR3);
558# endif
559#endif
560 Log3(("IOMIOPortReadStr: Port=%RTiop pGCPtrDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=%Rrc\n",
561 Port, pGCPtrDst, pcTransfers, cTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
562 if (!pCritSect)
563 iomUnlock(pVM);
564 return rcStrict;
565 }
566
567#ifndef IN_RING3
568 /*
569 * Handler in ring-3?
570 */
571 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(&pVM->iom.s, Port);
572 if (pRangeR3)
573 {
574# ifdef VBOX_WITH_STATISTICS
575 if (pStats)
576 STAM_COUNTER_INC(&pStats->InRZToR3);
577# endif
578 iomUnlock(pVM);
579 return VINF_IOM_HC_IOPORT_READ;
580 }
581#endif
582
583 /*
584 * Ok, no handler for this port.
585 */
586#ifdef VBOX_WITH_STATISTICS
587 if (pStats)
588 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
589 else
590 {
591# ifndef IN_RING3
592 /* Ring-3 will have to create the statistics record. */
593 iomUnlock(pVM);
594 return VINF_IOM_HC_IOPORT_READ;
595# else
596 pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
597 if (pStats)
598 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
599# endif
600 }
601#endif
602
603 Log3(("IOMIOPortReadStr: Port=%RTiop pGCPtrDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
604 Port, pGCPtrDst, pcTransfers, cTransfers, *pcTransfers, cb));
605 iomUnlock(pVM);
606 return VINF_SUCCESS;
607}
608
609
610/**
611 * Writes to an I/O port register.
612 *
613 * @returns Strict VBox status code. Informational status codes other than the one documented
614 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
615 * @retval VINF_SUCCESS Success.
616 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
617 * status code must be passed on to EM.
618 * @retval VINF_IOM_HC_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
619 *
620 * @param pVM VM handle.
621 * @param Port The port to write to.
622 * @param u32Value The value to write.
623 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
624 */
625VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVM pVM, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
626{
627 /* Take the IOM lock before performing any device I/O. */
628 int rc2 = iomLock(pVM);
629#ifndef IN_RING3
630 if (rc2 == VERR_SEM_BUSY)
631 return VINF_IOM_HC_IOPORT_WRITE;
632#endif
633 AssertRC(rc2);
634#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
635 IEMNotifyIOPortWrite(pVM, Port, u32Value, cbValue);
636#endif
637
638/** @todo bird: When I get time, I'll remove the RC/R0 trees and link the RC/R0
639 * entries to the ring-3 node. */
640#ifdef VBOX_WITH_STATISTICS
641 /*
642 * Find the statistics record.
643 */
644 PIOMIOPORTSTATS pStats = pVM->iom.s.CTX_SUFF(pStatsLastWrite);
645 if (!pStats || pStats->Core.Key != Port)
646 {
647 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, Port);
648 if (pStats)
649 pVM->iom.s.CTX_SUFF(pStatsLastWrite) = pStats;
650 }
651#endif
652
653 /*
654 * Get handler for current context.
655 */
656 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVM->iom.s.CTX_SUFF(pRangeLastWrite);
657 if ( !pRange
658 || (unsigned)Port - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
659 {
660 pRange = iomIOPortGetRange(&pVM->iom.s, Port);
661 if (pRange)
662 pVM->iom.s.CTX_SUFF(pRangeLastWrite) = pRange;
663 }
664 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
665 if (pRange)
666 {
667 /*
668 * Found a range.
669 */
670 PFNIOMIOPORTOUT pfnOutCallback = pRange->pfnOutCallback;
671#ifndef IN_RING3
672 if (!pfnOutCallback)
673 {
674 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
675 iomUnlock(pVM);
676 return VINF_IOM_HC_IOPORT_WRITE;
677 }
678#endif
679 void *pvUser = pRange->pvUser;
680 PPDMDEVINS pDevIns = pRange->pDevIns;
681 PPDMCRITSECT pCritSect = pDevIns->CTX_SUFF(pCritSect);
682
683 /*
684 * Call the device - 4 variations.
685 */
686 VBOXSTRICTRC rcStrict;
687 if (pCritSect)
688 {
689 iomUnlock(pVM);
690 rcStrict = PDMCritSectEnter(pCritSect, VINF_IOM_HC_IOPORT_WRITE);
691 if (rcStrict != VINF_SUCCESS)
692 {
693 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
694 return rcStrict;
695 }
696#ifdef VBOX_WITH_STATISTICS
697 if (pStats)
698 {
699 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
700 rcStrict = pfnOutCallback(pDevIns, pvUser, Port, u32Value, (unsigned)cbValue);
701 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
702 }
703 else
704#endif
705 rcStrict = pfnOutCallback(pDevIns, pvUser, Port, u32Value, (unsigned)cbValue);
706 PDMCritSectLeave(pCritSect);
707 }
708 else
709 {
710#ifdef VBOX_WITH_STATISTICS
711 if (pStats)
712 {
713 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
714 rcStrict = pfnOutCallback(pDevIns, pvUser, Port, u32Value, (unsigned)cbValue);
715 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
716 }
717 else
718#endif
719 rcStrict = pfnOutCallback(pDevIns, pvUser, Port, u32Value, (unsigned)cbValue);
720 }
721
722#ifdef VBOX_WITH_STATISTICS
723 if (rcStrict == VINF_SUCCESS && pStats)
724 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
725# ifndef IN_RING3
726 else if (rcStrict == VINF_IOM_HC_IOPORT_WRITE && pStats)
727 STAM_COUNTER_INC(&pStats->OutRZToR3);
728# endif
729#endif
730 Log3(("IOMIOPortWrite: Port=%RTiop u32=%08RX32 cb=%d rc=%Rrc\n", Port, u32Value, cbValue, VBOXSTRICTRC_VAL(rcStrict)));
731 if (!pCritSect)
732 iomUnlock(pVM);
733 return rcStrict;
734 }
735
736#ifndef IN_RING3
737 /*
738 * Handler in ring-3?
739 */
740 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(&pVM->iom.s, Port);
741 if (pRangeR3)
742 {
743# ifdef VBOX_WITH_STATISTICS
744 if (pStats)
745 STAM_COUNTER_INC(&pStats->OutRZToR3);
746# endif
747 iomUnlock(pVM);
748 return VINF_IOM_HC_IOPORT_WRITE;
749 }
750#endif
751
752 /*
753 * Ok, no handler for that port.
754 */
755#ifdef VBOX_WITH_STATISTICS
756 /* statistics. */
757 if (pStats)
758 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
759 else
760 {
761# ifndef IN_RING3
762 /* R3 will have to create the statistics record. */
763 iomUnlock(pVM);
764 return VINF_IOM_HC_IOPORT_WRITE;
765# else
766 pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
767 if (pStats)
768 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
769# endif
770 }
771#endif
772 Log3(("IOMIOPortWrite: Port=%RTiop u32=%08RX32 cb=%d nop\n", Port, u32Value, cbValue));
773 iomUnlock(pVM);
774 return VINF_SUCCESS;
775}
776
777
778/**
779 * Writes the string buffer of an I/O port register.
780 *
781 * @returns Strict VBox status code. Informational status codes other than the one documented
782 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
783 * @retval VINF_SUCCESS Success.
784 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
785 * status code must be passed on to EM.
786 * @retval VINF_IOM_HC_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
787 *
788 * @param pVM VM handle.
789 * @param Port The port to write.
790 * @param pGCPtrSrc Pointer to the source buffer (GC, incremented appropriately).
791 * @param pcTransfers Pointer to the number of transfer units to write, on return remaining transfer units.
792 * @param cb Size of the transfer unit (1, 2 or 4 bytes).
793 * */
794VMMDECL(VBOXSTRICTRC) IOMIOPortWriteString(PVM pVM, RTIOPORT Port, PRTGCPTR pGCPtrSrc, PRTGCUINTREG pcTransfers, unsigned cb)
795{
796 /* Take the IOM lock before performing any device I/O. */
797 int rc2 = iomLock(pVM);
798#ifndef IN_RING3
799 if (rc2 == VERR_SEM_BUSY)
800 return VINF_IOM_HC_IOPORT_WRITE;
801#endif
802 AssertRC(rc2);
803#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
804 IEMNotifyIOPortWriteString(pVM, Port, *pGCPtrSrc, *pcTransfers, cb);
805#endif
806
807#ifdef LOG_ENABLED
808 const RTGCUINTREG cTransfers = *pcTransfers;
809#endif
810#ifdef VBOX_WITH_STATISTICS
811 /*
812 * Get the statistics record.
813 */
814 PIOMIOPORTSTATS pStats = pVM->iom.s.CTX_SUFF(pStatsLastWrite);
815 if (!pStats || pStats->Core.Key != Port)
816 {
817 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, Port);
818 if (pStats)
819 pVM->iom.s.CTX_SUFF(pStatsLastWrite) = pStats;
820 }
821#endif
822
823 /*
824 * Get handler for current context.
825 */
826 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVM->iom.s.CTX_SUFF(pRangeLastWrite);
827 if ( !pRange
828 || (unsigned)Port - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
829 {
830 pRange = iomIOPortGetRange(&pVM->iom.s, Port);
831 if (pRange)
832 pVM->iom.s.CTX_SUFF(pRangeLastWrite) = pRange;
833 }
834 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
835 if (pRange)
836 {
837 /*
838 * Found a range.
839 */
840 PFNIOMIOPORTOUTSTRING pfnOutStrCallback = pRange->pfnOutStrCallback;
841#ifndef IN_RING3
842 if (!pfnOutStrCallback)
843 {
844 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
845 iomUnlock(pVM);
846 return VINF_IOM_HC_IOPORT_WRITE;
847 }
848#endif
849 void *pvUser = pRange->pvUser;
850 PPDMDEVINS pDevIns = pRange->pDevIns;
851 PPDMCRITSECT pCritSect = pDevIns->CTX_SUFF(pCritSect);
852
853 /*
854 * Call the device - 4 variations.
855 */
856 VBOXSTRICTRC rcStrict;
857 if (pCritSect)
858 {
859 iomUnlock(pVM);
860 rcStrict = PDMCritSectEnter(pCritSect, VINF_IOM_HC_IOPORT_WRITE);
861 if (rcStrict != VINF_SUCCESS)
862 {
863 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
864 return rcStrict;
865 }
866#ifdef VBOX_WITH_STATISTICS
867 if (pStats)
868 {
869 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
870 rcStrict = pfnOutStrCallback(pDevIns, pvUser, Port, pGCPtrSrc, pcTransfers, cb);
871 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
872 }
873 else
874#endif
875 rcStrict = pfnOutStrCallback(pDevIns, pvUser, Port, pGCPtrSrc, pcTransfers, cb);
876 PDMCritSectLeave(pCritSect);
877 }
878 else
879 {
880#ifdef VBOX_WITH_STATISTICS
881 if (pStats)
882 {
883 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
884 rcStrict = pfnOutStrCallback(pDevIns, pvUser, Port, pGCPtrSrc, pcTransfers, cb);
885 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
886 }
887 else
888#endif
889 rcStrict = pfnOutStrCallback(pDevIns, pvUser, Port, pGCPtrSrc, pcTransfers, cb);
890 }
891
892#ifdef VBOX_WITH_STATISTICS
893 if (rcStrict == VINF_SUCCESS && pStats)
894 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
895# ifndef IN_RING3
896 else if (rcStrict == VINF_IOM_HC_IOPORT_WRITE && pStats)
897 STAM_COUNTER_INC(&pStats->OutRZToR3);
898# endif
899#endif
900 Log3(("IOMIOPortWriteStr: Port=%RTiop pGCPtrSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rcStrict=%Rrc\n",
901 Port, pGCPtrSrc, pcTransfers, cTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
902 if (!pCritSect)
903 iomUnlock(pVM);
904 return rcStrict;
905 }
906
907#ifndef IN_RING3
908 /*
909 * Handler in ring-3?
910 */
911 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(&pVM->iom.s, Port);
912 if (pRangeR3)
913 {
914# ifdef VBOX_WITH_STATISTICS
915 if (pStats)
916 STAM_COUNTER_INC(&pStats->OutRZToR3);
917# endif
918 iomUnlock(pVM);
919 return VINF_IOM_HC_IOPORT_WRITE;
920 }
921#endif
922
923 /*
924 * Ok, no handler for this port.
925 */
926#ifdef VBOX_WITH_STATISTICS
927 if (pStats)
928 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
929 else
930 {
931# ifndef IN_RING3
932 /* Ring-3 will have to create the statistics record. */
933 iomUnlock(pVM);
934 return VINF_IOM_HC_IOPORT_WRITE;
935# else
936 pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
937 if (pStats)
938 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
939# endif
940 }
941#endif
942
943 Log3(("IOMIOPortWriteStr: Port=%RTiop pGCPtrSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
944 Port, pGCPtrSrc, pcTransfers, cTransfers, *pcTransfers, cb));
945 iomUnlock(pVM);
946 return VINF_SUCCESS;
947}
948
949
950/**
951 * Checks that the operation is allowed according to the IOPL
952 * level and I/O bitmap.
953 *
954 * @returns Strict VBox status code. Informational status codes other than the one documented
955 * here are to be treated as internal failure.
956 * @retval VINF_SUCCESS Success.
957 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
958 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
959 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
960 *
961 * @param pVM VM handle.
962 * @param pCtxCore Pointer to register frame.
963 * @param Port The I/O port number.
964 * @param cb The access size.
965 */
966VMMDECL(VBOXSTRICTRC) IOMInterpretCheckPortIOAccess(PVM pVM, PCPUMCTXCORE pCtxCore, RTIOPORT Port, unsigned cb)
967{
968 PVMCPU pVCpu = VMMGetCpu(pVM);
969
970 /*
971 * If this isn't ring-0, we have to check for I/O privileges.
972 */
973 uint32_t efl = CPUMRawGetEFlags(pVCpu, pCtxCore);
974 uint32_t cpl = CPUMGetGuestCPL(pVCpu, pCtxCore);
975
976 if ( ( cpl > 0
977 && X86_EFL_GET_IOPL(efl) < cpl)
978 || pCtxCore->eflags.Bits.u1VM /* IOPL is ignored in V86 mode; always check TSS bitmap */
979 )
980 {
981 /*
982 * Get TSS location and check if there can be a I/O bitmap.
983 */
984 RTGCUINTPTR GCPtrTss;
985 RTGCUINTPTR cbTss;
986 bool fCanHaveIOBitmap;
987 int rc2 = SELMGetTSSInfo(pVM, pVCpu, &GCPtrTss, &cbTss, &fCanHaveIOBitmap);
988 if (RT_FAILURE(rc2))
989 {
990 Log(("iomInterpretCheckPortIOAccess: Port=%RTiop cb=%d %Rrc -> #GP(0)\n", Port, cb, rc2));
991 return TRPMRaiseXcptErr(pVCpu, pCtxCore, X86_XCPT_GP, 0);
992 }
993
994 if ( !fCanHaveIOBitmap
995 || cbTss <= sizeof(VBOXTSS)) /** @todo r=bird: Should this really include the interrupt redirection bitmap? */
996 {
997 Log(("iomInterpretCheckPortIOAccess: Port=%RTiop cb=%d cbTss=%#x fCanHaveIOBitmap=%RTbool -> #GP(0)\n",
998 Port, cb, cbTss, fCanHaveIOBitmap));
999 return TRPMRaiseXcptErr(pVCpu, pCtxCore, X86_XCPT_GP, 0);
1000 }
1001
1002 /*
1003 * Fetch the I/O bitmap offset.
1004 */
1005 uint16_t offIOPB;
1006 VBOXSTRICTRC rcStrict = PGMPhysInterpretedRead(pVCpu, pCtxCore, &offIOPB, GCPtrTss + RT_OFFSETOF(VBOXTSS, offIoBitmap), sizeof(offIOPB));
1007 if (rcStrict != VINF_SUCCESS)
1008 {
1009 Log(("iomInterpretCheckPortIOAccess: Port=%RTiop cb=%d GCPtrTss=%RGv %Rrc\n",
1010 Port, cb, GCPtrTss, VBOXSTRICTRC_VAL(rcStrict)));
1011 return rcStrict;
1012 }
1013
1014 /*
1015 * Check the limit and read the two bitmap bytes.
1016 */
1017 uint32_t offTss = offIOPB + (Port >> 3);
1018 if (offTss + 1 >= cbTss)
1019 {
1020 Log(("iomInterpretCheckPortIOAccess: Port=%RTiop cb=%d offTss=%#x cbTss=%#x -> #GP(0)\n",
1021 Port, cb, offTss, cbTss));
1022 return TRPMRaiseXcptErr(pVCpu, pCtxCore, X86_XCPT_GP, 0);
1023 }
1024 uint16_t u16;
1025 rcStrict = PGMPhysInterpretedRead(pVCpu, pCtxCore, &u16, GCPtrTss + offTss, sizeof(u16));
1026 if (rcStrict != VINF_SUCCESS)
1027 {
1028 Log(("iomInterpretCheckPortIOAccess: Port=%RTiop cb=%d GCPtrTss=%RGv offTss=%#x -> %Rrc\n",
1029 Port, cb, GCPtrTss, offTss, VBOXSTRICTRC_VAL(rcStrict)));
1030 return rcStrict;
1031 }
1032
1033 /*
1034 * All the bits must be clear.
1035 */
1036 if ((u16 >> (Port & 7)) & ((1 << cb) - 1))
1037 {
1038 Log(("iomInterpretCheckPortIOAccess: Port=%RTiop cb=%d u16=%#x -> #GP(0)\n",
1039 Port, cb, u16, offTss));
1040 return TRPMRaiseXcptErr(pVCpu, pCtxCore, X86_XCPT_GP, 0);
1041 }
1042 LogFlow(("iomInterpretCheckPortIOAccess: Port=%RTiop cb=%d offTss=%#x cbTss=%#x u16=%#x -> OK\n",
1043 Port, cb, u16, offTss, cbTss));
1044 }
1045 return VINF_SUCCESS;
1046}
1047
1048
1049/**
1050 * IN <AL|AX|EAX>, <DX|imm16>
1051 *
1052 * @returns Strict VBox status code. Informational status codes other than the one documented
1053 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
1054 * @retval VINF_SUCCESS Success.
1055 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
1056 * status code must be passed on to EM.
1057 * @retval VINF_IOM_HC_IOPORT_READ Defer the read to ring-3. (R0/GC only)
1058 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
1059 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
1060 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
1061 *
1062 * @param pVM The virtual machine (GC pointer of course).
1063 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
1064 * @param pCpu Disassembler CPU state.
1065 */
1066VMMDECL(VBOXSTRICTRC) IOMInterpretIN(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
1067{
1068#ifdef IN_RC
1069 STAM_COUNTER_INC(&pVM->iom.s.StatInstIn);
1070#endif
1071
1072 /*
1073 * Get port number from second parameter.
1074 * And get the register size from the first parameter.
1075 */
1076 uint64_t uPort = 0;
1077 unsigned cbSize = 0;
1078 bool fRc = iomGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uPort, &cbSize);
1079 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
1080
1081 cbSize = DISGetParamSize(pCpu, &pCpu->param1);
1082 Assert(cbSize > 0);
1083 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
1084 if (rcStrict == VINF_SUCCESS)
1085 {
1086 /*
1087 * Attempt to read the port.
1088 */
1089 uint32_t u32Data = UINT32_C(0xffffffff);
1090 rcStrict = IOMIOPortRead(pVM, uPort, &u32Data, cbSize);
1091 if (IOM_SUCCESS(rcStrict))
1092 {
1093 /*
1094 * Store the result in the AL|AX|EAX register.
1095 */
1096 fRc = iomSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data);
1097 AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
1098 }
1099 else
1100 AssertMsg(rcStrict == VINF_IOM_HC_IOPORT_READ || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
1101 }
1102 else
1103 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
1104
1105 return rcStrict;
1106}
1107
1108
1109/**
1110 * OUT <DX|imm16>, <AL|AX|EAX>
1111 *
1112 * @returns Strict VBox status code. Informational status codes other than the one documented
1113 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
1114 * @retval VINF_SUCCESS Success.
1115 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
1116 * status code must be passed on to EM.
1117 * @retval VINF_IOM_HC_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
1118 * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
1119 * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
1120 * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
1121 *
1122 * @param pVM The virtual machine (GC pointer of course).
1123 * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
1124 * @param pCpu Disassembler CPU state.
1125 */
1126VMMDECL(VBOXSTRICTRC) IOMInterpretOUT(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
1127{
1128#ifdef IN_RC
1129 STAM_COUNTER_INC(&pVM->iom.s.StatInstOut);
1130#endif
1131
1132 /*
1133 * Get port number from first parameter.
1134 * And get the register size and value from the second parameter.
1135 */
1136 uint64_t uPort = 0;
1137 unsigned cbSize = 0;
1138 bool fRc = iomGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
1139 AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
1140
1141 VBOXSTRICTRC rcStrict = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
1142 if (rcStrict == VINF_SUCCESS)
1143 {
1144 uint64_t u64Data = 0;
1145 fRc = iomGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u64Data, &cbSize);
1146 AssertMsg(fRc, ("Failed to get reg value!\n")); NOREF(fRc);
1147
1148 /*
1149 * Attempt to write to the port.
1150 */
1151 rcStrict = IOMIOPortWrite(pVM, uPort, u64Data, cbSize);
1152 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IOM_HC_IOPORT_WRITE || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST) || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
1153 }
1154 else
1155 AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
1156 return rcStrict;
1157}
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