VirtualBox

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

Last change on this file since 27778 was 26944, checked in by vboxsync, 15 years ago

PDM,IOM,TM: Added an optional per-device critsect for avoiding the global IOM lock. Only port I/O and timer callbacks use it, cannot yet be used with MMIO callbacks (will assert and fail).

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