VirtualBox

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

Last change on this file since 30045 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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