VirtualBox

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

Last change on this file since 81786 was 81383, checked in by vboxsync, 5 years ago

IOM: Split up the logging into two more groups, one for I/O ports and one for MMIO. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 39.2 KB
Line 
1/* $Id: IOMAll.cpp 81383 2019-10-19 23:58:44Z vboxsync $ */
2/** @file
3 * IOM - Input / Output Monitor - Any Context.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_IOM_IOPORT
23#include <VBox/vmm/iom.h>
24#include <VBox/vmm/mm.h>
25#include <VBox/param.h>
26#include "IOMInternal.h"
27#include <VBox/vmm/vmcc.h>
28#include <VBox/vmm/vmm.h>
29#include <VBox/vmm/selm.h>
30#include <VBox/vmm/trpm.h>
31#include <VBox/vmm/pdmdev.h>
32#include <VBox/vmm/pgm.h>
33#include <VBox/vmm/cpum.h>
34#include <VBox/err.h>
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/string.h>
38#include "IOMInline.h"
39
40
41/**
42 * Reads an I/O port register.
43 *
44 * @returns Strict VBox status code. Informational status codes other than the one documented
45 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
46 * @retval VINF_SUCCESS Success.
47 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
48 * status code must be passed on to EM.
49 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3. (R0/RC only)
50 *
51 * @param pVM The cross context VM structure.
52 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
53 * @param Port The port to read.
54 * @param pu32Value Where to store the value read.
55 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
56 */
57VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue)
58{
59 Assert(pVCpu->iom.s.PendingIOPortWrite.cbValue == 0);
60
61/** @todo should initialize *pu32Value here because it can happen that some
62 * handle is buggy and doesn't handle all cases. */
63
64 /* For lookups we need to share lock IOM. */
65 int rc2 = IOM_LOCK_SHARED(pVM);
66#ifndef IN_RING3
67 if (rc2 == VERR_SEM_BUSY)
68 return VINF_IOM_R3_IOPORT_READ;
69#endif
70 AssertRC(rc2);
71
72 /*
73 * Get the entry for the current context.
74 */
75 uint16_t offPort;
76 CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, Port, &offPort, &pVCpu->iom.s.idxIoPortLastRead);
77 if (pRegEntry)
78 {
79#ifdef VBOX_WITH_STATISTICS
80 PIOMIOPORTSTATSENTRY pStats = iomIoPortGetStats(pVM, pRegEntry, offPort);
81#endif
82
83 /*
84 * Found an entry, get the data so we can leave the IOM lock.
85 */
86 uint16_t const fFlags = pRegEntry->fFlags;
87 PFNIOMIOPORTNEWIN pfnInCallback = pRegEntry->pfnInCallback;
88 PPDMDEVINS pDevIns = pRegEntry->pDevIns;
89#ifndef IN_RING3
90 if ( pfnInCallback
91 && pDevIns
92 && pRegEntry->cPorts > 0)
93 { /* likely */ }
94 else
95 {
96 STAM_COUNTER_INC(&pStats->InRZToR3);
97 IOM_UNLOCK_SHARED(pVM);
98 return VINF_IOM_R3_IOPORT_READ;
99 }
100#endif
101 void *pvUser = pRegEntry->pvUser;
102 IOM_UNLOCK_SHARED(pVM);
103 AssertPtr(pDevIns);
104 AssertPtr(pfnInCallback);
105
106 /*
107 * Call the device.
108 */
109 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_READ);
110 if (rcStrict == VINF_SUCCESS)
111 {
112 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
113 rcStrict = pfnInCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? Port : offPort, pu32Value, (unsigned)cbValue);
114 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
115 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
116
117 if (rcStrict == VINF_SUCCESS)
118 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
119#ifndef IN_RING3
120 else if (rcStrict == VINF_IOM_R3_IOPORT_READ)
121 STAM_COUNTER_INC(&pStats->InRZToR3);
122#endif
123 else if (rcStrict == VERR_IOM_IOPORT_UNUSED)
124 {
125 /* make return value */
126 rcStrict = VINF_SUCCESS;
127 switch (cbValue)
128 {
129 case 1: *(uint8_t *)pu32Value = 0xff; break;
130 case 2: *(uint16_t *)pu32Value = 0xffff; break;
131 case 4: *(uint32_t *)pu32Value = UINT32_C(0xffffffff); break;
132 default:
133 AssertMsgFailedReturn(("Invalid I/O port size %d. Port=%d\n", cbValue, Port), VERR_IOM_INVALID_IOPORT_SIZE);
134 }
135 }
136 Log3(("IOMIOPortRead: Port=%RTiop *pu32=%08RX32 cb=%d rc=%Rrc\n", Port, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rcStrict)));
137 }
138 else
139 STAM_COUNTER_INC(&pStats->InRZToR3);
140 return rcStrict;
141 }
142
143 /*
144 * Old code
145 * Old code
146 * Old code
147 */
148
149#ifdef VBOX_WITH_STATISTICS
150 /*
151 * Get the statistics record.
152 */
153 PIOMIOPORTSTATS pStats = pVCpu->iom.s.CTX_SUFF(pStatsLastRead);
154 if (!pStats || pStats->Core.Key != Port)
155 {
156 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, Port);
157 if (pStats)
158 pVCpu->iom.s.CTX_SUFF(pStatsLastRead) = pStats;
159 }
160#endif
161
162 /*
163 * Get handler for current context.
164 */
165 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVCpu->iom.s.CTX_SUFF(pRangeLastRead);
166 if ( !pRange
167 || (unsigned)Port - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
168 {
169 pRange = iomIOPortGetRange(pVM, Port);
170 if (pRange)
171 pVCpu->iom.s.CTX_SUFF(pRangeLastRead) = pRange;
172 }
173 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
174 if (pRange)
175 {
176 /*
177 * Found a range, get the data in case we leave the IOM lock.
178 */
179 PFNIOMIOPORTIN pfnInCallback = pRange->pfnInCallback;
180#ifndef IN_RING3
181 if (pfnInCallback)
182 { /* likely */ }
183 else
184 {
185 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
186 IOM_UNLOCK_SHARED(pVM);
187 return VINF_IOM_R3_IOPORT_READ;
188 }
189#endif
190 void *pvUser = pRange->pvUser;
191 PPDMDEVINS pDevIns = pRange->pDevIns;
192 IOM_UNLOCK_SHARED(pVM);
193
194 /*
195 * Call the device.
196 */
197 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_READ);
198 if (rcStrict == VINF_SUCCESS)
199 { /* likely */ }
200 else
201 {
202 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
203 return rcStrict;
204 }
205#ifdef VBOX_WITH_STATISTICS
206 if (pStats)
207 {
208 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
209 rcStrict = pfnInCallback(pDevIns, pvUser, Port, pu32Value, (unsigned)cbValue);
210 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
211 }
212 else
213#endif
214 rcStrict = pfnInCallback(pDevIns, pvUser, Port, pu32Value, (unsigned)cbValue);
215 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
216
217#ifdef VBOX_WITH_STATISTICS
218 if (rcStrict == VINF_SUCCESS && pStats)
219 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
220# ifndef IN_RING3
221 else if (rcStrict == VINF_IOM_R3_IOPORT_READ && pStats)
222 STAM_COUNTER_INC(&pStats->InRZToR3);
223# endif
224#endif
225 if (rcStrict == VERR_IOM_IOPORT_UNUSED)
226 {
227 /* make return value */
228 rcStrict = VINF_SUCCESS;
229 switch (cbValue)
230 {
231 case 1: *(uint8_t *)pu32Value = 0xff; break;
232 case 2: *(uint16_t *)pu32Value = 0xffff; break;
233 case 4: *(uint32_t *)pu32Value = UINT32_C(0xffffffff); break;
234 default:
235 AssertMsgFailed(("Invalid I/O port size %d. Port=%d\n", cbValue, Port));
236 return VERR_IOM_INVALID_IOPORT_SIZE;
237 }
238 }
239 Log3(("IOMIOPortRead: Port=%RTiop *pu32=%08RX32 cb=%d rc=%Rrc\n", Port, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rcStrict)));
240 return rcStrict;
241 }
242
243#ifndef IN_RING3
244 /*
245 * Handler in ring-3?
246 */
247 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(pVM, Port);
248 if (pRangeR3)
249 {
250# ifdef VBOX_WITH_STATISTICS
251 if (pStats)
252 STAM_COUNTER_INC(&pStats->InRZToR3);
253# endif
254 IOM_UNLOCK_SHARED(pVM);
255 return VINF_IOM_R3_IOPORT_READ;
256 }
257#endif
258
259 /*
260 * Ok, no handler for this port.
261 */
262#ifdef VBOX_WITH_STATISTICS
263 if (pStats)
264 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
265#endif
266
267 /* make return value */
268 switch (cbValue)
269 {
270 case 1: *(uint8_t *)pu32Value = 0xff; break;
271 case 2: *(uint16_t *)pu32Value = 0xffff; break;
272 case 4: *(uint32_t *)pu32Value = UINT32_C(0xffffffff); break;
273 default:
274 AssertMsgFailed(("Invalid I/O port size %d. Port=%d\n", cbValue, Port));
275 IOM_UNLOCK_SHARED(pVM);
276 return VERR_IOM_INVALID_IOPORT_SIZE;
277 }
278 Log3(("IOMIOPortRead: Port=%RTiop *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", Port, *pu32Value, cbValue));
279 IOM_UNLOCK_SHARED(pVM);
280 return VINF_SUCCESS;
281}
282
283
284/**
285 * Reads the string buffer of an I/O port register.
286 *
287 * @returns Strict VBox status code. Informational status codes other than the one documented
288 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
289 * @retval VINF_SUCCESS Success or no string I/O callback in
290 * this context.
291 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
292 * status code must be passed on to EM.
293 * @retval VINF_IOM_R3_IOPORT_READ Defer the read to ring-3. (R0/RC only)
294 *
295 * @param pVM The cross context VM structure.
296 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
297 * @param uPort The port to read.
298 * @param pvDst Pointer to the destination buffer.
299 * @param pcTransfers Pointer to the number of transfer units to read, on return remaining transfer units.
300 * @param cb Size of the transfer unit (1, 2 or 4 bytes).
301 */
302VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortReadString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uPort,
303 void *pvDst, uint32_t *pcTransfers, unsigned cb)
304{
305 Assert(pVCpu->iom.s.PendingIOPortWrite.cbValue == 0);
306
307 /* For lookups we need to share lock IOM. */
308 int rc2 = IOM_LOCK_SHARED(pVM);
309#ifndef IN_RING3
310 if (rc2 == VERR_SEM_BUSY)
311 return VINF_IOM_R3_IOPORT_READ;
312#endif
313 AssertRC(rc2);
314
315 const uint32_t cRequestedTransfers = *pcTransfers;
316 Assert(cRequestedTransfers > 0);
317
318 /*
319 * Get the entry for the current context.
320 */
321 uint16_t offPort;
322 CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, uPort, &offPort, &pVCpu->iom.s.idxIoPortLastReadStr);
323 if (pRegEntry)
324 {
325#ifdef VBOX_WITH_STATISTICS
326 PIOMIOPORTSTATSENTRY pStats = iomIoPortGetStats(pVM, pRegEntry, offPort);
327#endif
328
329 /*
330 * Found an entry, get the data so we can leave the IOM lock.
331 */
332 uint16_t const fFlags = pRegEntry->fFlags;
333 PFNIOMIOPORTNEWINSTRING pfnInStrCallback = pRegEntry->pfnInStrCallback;
334 PFNIOMIOPORTNEWIN pfnInCallback = pRegEntry->pfnInCallback;
335 PPDMDEVINS pDevIns = pRegEntry->pDevIns;
336#ifndef IN_RING3
337 if ( pfnInCallback
338 && pDevIns
339 && pRegEntry->cPorts > 0)
340 { /* likely */ }
341 else
342 {
343 STAM_COUNTER_INC(&pStats->InRZToR3);
344 IOM_UNLOCK_SHARED(pVM);
345 return VINF_IOM_R3_IOPORT_READ;
346 }
347#endif
348 void *pvUser = pRegEntry->pvUser;
349 IOM_UNLOCK_SHARED(pVM);
350 AssertPtr(pDevIns);
351 AssertPtr(pfnInCallback);
352
353 /*
354 * Call the device.
355 */
356 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_READ);
357 if (rcStrict == VINF_SUCCESS)
358 {
359 /*
360 * First using the string I/O callback.
361 */
362 if (pfnInStrCallback)
363 {
364 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
365 rcStrict = pfnInStrCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort,
366 (uint8_t *)pvDst, pcTransfers, cb);
367 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
368 }
369
370 /*
371 * Then doing the single I/O fallback.
372 */
373 if ( *pcTransfers > 0
374 && rcStrict == VINF_SUCCESS)
375 {
376 pvDst = (uint8_t *)pvDst + (cRequestedTransfers - *pcTransfers) * cb;
377 do
378 {
379 uint32_t u32Value = 0;
380 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
381 rcStrict = pfnInCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort, &u32Value, cb);
382 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
383 if (rcStrict == VERR_IOM_IOPORT_UNUSED)
384 {
385 u32Value = UINT32_MAX;
386 rcStrict = VINF_SUCCESS;
387 }
388 if (IOM_SUCCESS(rcStrict))
389 {
390 switch (cb)
391 {
392 case 4: *(uint32_t *)pvDst = u32Value; pvDst = (uint8_t *)pvDst + 4; break;
393 case 2: *(uint16_t *)pvDst = (uint16_t)u32Value; pvDst = (uint8_t *)pvDst + 2; break;
394 case 1: *(uint8_t *)pvDst = (uint8_t )u32Value; pvDst = (uint8_t *)pvDst + 1; break;
395 default: AssertFailed();
396 }
397 *pcTransfers -= 1;
398 }
399 } while ( *pcTransfers > 0
400 && rcStrict == VINF_SUCCESS);
401 }
402 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
403
404#ifdef VBOX_WITH_STATISTICS
405 if (rcStrict == VINF_SUCCESS && pStats)
406 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
407# ifndef IN_RING3
408 else if (rcStrict == VINF_IOM_R3_IOPORT_READ && pStats)
409 STAM_COUNTER_INC(&pStats->InRZToR3);
410# endif
411#endif
412 Log3(("IOMIOPortReadStr: uPort=%RTiop pvDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=%Rrc\n",
413 uPort, pvDst, pcTransfers, cRequestedTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
414 }
415#ifndef IN_RING3
416 else
417 STAM_COUNTER_INC(&pStats->InRZToR3);
418#endif
419 return rcStrict;
420 }
421
422 /*
423 * Old code
424 * Old code
425 * Old code
426 */
427
428#ifdef VBOX_WITH_STATISTICS
429 /*
430 * Get the statistics record.
431 */
432 PIOMIOPORTSTATS pStats = pVCpu->iom.s.CTX_SUFF(pStatsLastRead);
433 if (!pStats || pStats->Core.Key != uPort)
434 {
435 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, uPort);
436 if (pStats)
437 pVCpu->iom.s.CTX_SUFF(pStatsLastRead) = pStats;
438 }
439#endif
440
441 /*
442 * Get handler for current context.
443 */
444 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVCpu->iom.s.CTX_SUFF(pRangeLastRead);
445 if ( !pRange
446 || (unsigned)uPort - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
447 {
448 pRange = iomIOPortGetRange(pVM, uPort);
449 if (pRange)
450 pVCpu->iom.s.CTX_SUFF(pRangeLastRead) = pRange;
451 }
452 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
453 if (pRange)
454 {
455 /*
456 * Found a range.
457 */
458 PFNIOMIOPORTINSTRING pfnInStrCallback = pRange->pfnInStrCallback;
459 PFNIOMIOPORTIN pfnInCallback = pRange->pfnInCallback;
460#ifndef IN_RING3
461 if (pfnInStrCallback || pfnInCallback)
462 { /* likely */ }
463 else
464 {
465 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
466 IOM_UNLOCK_SHARED(pVM);
467 return VINF_IOM_R3_IOPORT_READ;
468 }
469#endif
470 void *pvUser = pRange->pvUser;
471 PPDMDEVINS pDevIns = pRange->pDevIns;
472 IOM_UNLOCK_SHARED(pVM);
473
474 /*
475 * Call the device.
476 */
477 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_READ);
478 if (rcStrict == VINF_SUCCESS)
479 { /* likely */ }
480 else
481 {
482 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
483 return rcStrict;
484 }
485
486 /*
487 * First using the string I/O callback.
488 */
489 if (pfnInStrCallback)
490 {
491#ifdef VBOX_WITH_STATISTICS
492 if (pStats)
493 {
494 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
495 rcStrict = pfnInStrCallback(pDevIns, pvUser, uPort, (uint8_t *)pvDst, pcTransfers, cb);
496 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
497 }
498 else
499#endif
500 rcStrict = pfnInStrCallback(pDevIns, pvUser, uPort, (uint8_t *)pvDst, pcTransfers, cb);
501 }
502
503 /*
504 * Then doing the single I/O fallback.
505 */
506 if ( *pcTransfers > 0
507 && rcStrict == VINF_SUCCESS)
508 {
509 pvDst = (uint8_t *)pvDst + (cRequestedTransfers - *pcTransfers) * cb;
510 do
511 {
512 uint32_t u32Value = 0;
513#ifdef VBOX_WITH_STATISTICS
514 if (pStats)
515 {
516 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
517 rcStrict = pfnInCallback(pDevIns, pvUser, uPort, &u32Value, cb);
518 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
519 }
520 else
521#endif
522 rcStrict = pfnInCallback(pDevIns, pvUser, uPort, &u32Value, cb);
523 if (rcStrict == VERR_IOM_IOPORT_UNUSED)
524 {
525 u32Value = UINT32_MAX;
526 rcStrict = VINF_SUCCESS;
527 }
528 if (IOM_SUCCESS(rcStrict))
529 {
530 switch (cb)
531 {
532 case 4: *(uint32_t *)pvDst = u32Value; pvDst = (uint8_t *)pvDst + 4; break;
533 case 2: *(uint16_t *)pvDst = (uint16_t)u32Value; pvDst = (uint8_t *)pvDst + 2; break;
534 case 1: *(uint8_t *)pvDst = (uint8_t )u32Value; pvDst = (uint8_t *)pvDst + 1; break;
535 default: AssertFailed();
536 }
537 *pcTransfers -= 1;
538 }
539 } while ( *pcTransfers > 0
540 && rcStrict == VINF_SUCCESS);
541 }
542 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
543
544#ifdef VBOX_WITH_STATISTICS
545 if (rcStrict == VINF_SUCCESS && pStats)
546 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
547# ifndef IN_RING3
548 else if (rcStrict == VINF_IOM_R3_IOPORT_READ && pStats)
549 STAM_COUNTER_INC(&pStats->InRZToR3);
550# endif
551#endif
552 Log3(("IOMIOPortReadStr: uPort=%RTiop pvDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=%Rrc\n",
553 uPort, pvDst, pcTransfers, cRequestedTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
554 return rcStrict;
555 }
556
557#ifndef IN_RING3
558 /*
559 * Handler in ring-3?
560 */
561 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(pVM, uPort);
562 if (pRangeR3)
563 {
564# ifdef VBOX_WITH_STATISTICS
565 if (pStats)
566 STAM_COUNTER_INC(&pStats->InRZToR3);
567# endif
568 IOM_UNLOCK_SHARED(pVM);
569 return VINF_IOM_R3_IOPORT_READ;
570 }
571#endif
572
573 /*
574 * Ok, no handler for this port.
575 */
576 *pcTransfers = 0;
577 memset(pvDst, 0xff, cRequestedTransfers * cb);
578#ifdef VBOX_WITH_STATISTICS
579 if (pStats)
580 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
581#endif
582 Log3(("IOMIOPortReadStr: uPort=%RTiop (unused) pvDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
583 uPort, pvDst, pcTransfers, cRequestedTransfers, *pcTransfers, cb));
584 IOM_UNLOCK_SHARED(pVM);
585 return VINF_SUCCESS;
586}
587
588
589#ifndef IN_RING3
590/**
591 * Defers a pending I/O port write to ring-3.
592 *
593 * @returns VINF_IOM_R3_IOPORT_COMMIT_WRITE
594 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
595 * @param Port The port to write to.
596 * @param u32Value The value to write.
597 * @param cbValue The size of the value (1, 2, 4).
598 */
599static VBOXSTRICTRC iomIOPortRing3WritePending(PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
600{
601 Log5(("iomIOPortRing3WritePending: %#x LB %u -> %RTiop\n", u32Value, cbValue, Port));
602 AssertReturn(pVCpu->iom.s.PendingIOPortWrite.cbValue == 0, VERR_IOM_IOPORT_IPE_1);
603 pVCpu->iom.s.PendingIOPortWrite.IOPort = Port;
604 pVCpu->iom.s.PendingIOPortWrite.u32Value = u32Value;
605 pVCpu->iom.s.PendingIOPortWrite.cbValue = (uint32_t)cbValue;
606 VMCPU_FF_SET(pVCpu, VMCPU_FF_IOM);
607 return VINF_IOM_R3_IOPORT_COMMIT_WRITE;
608}
609#endif
610
611
612/**
613 * Writes to an I/O port register.
614 *
615 * @returns Strict VBox status code. Informational status codes other than the one documented
616 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
617 * @retval VINF_SUCCESS Success.
618 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
619 * status code must be passed on to EM.
620 * @retval VINF_IOM_R3_IOPORT_WRITE Defer the write to ring-3. (R0/RC only)
621 *
622 * @param pVM The cross context VM structure.
623 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
624 * @param Port The port to write to.
625 * @param u32Value The value to write.
626 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
627 */
628VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
629{
630#ifndef IN_RING3
631 Assert(pVCpu->iom.s.PendingIOPortWrite.cbValue == 0);
632#endif
633
634 /* For lookups we need to share lock IOM. */
635 int rc2 = IOM_LOCK_SHARED(pVM);
636#ifndef IN_RING3
637 if (rc2 == VERR_SEM_BUSY)
638 return iomIOPortRing3WritePending(pVCpu, Port, u32Value, cbValue);
639#endif
640 AssertRC(rc2);
641
642 /*
643 * Get the entry for the current context.
644 */
645 uint16_t offPort;
646 CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, Port, &offPort, &pVCpu->iom.s.idxIoPortLastWrite);
647 if (pRegEntry)
648 {
649#ifdef VBOX_WITH_STATISTICS
650 PIOMIOPORTSTATSENTRY pStats = iomIoPortGetStats(pVM, pRegEntry, offPort);
651#endif
652
653 /*
654 * Found an entry, get the data so we can leave the IOM lock.
655 */
656 uint16_t const fFlags = pRegEntry->fFlags;
657 PFNIOMIOPORTNEWOUT pfnOutCallback = pRegEntry->pfnOutCallback;
658 PPDMDEVINS pDevIns = pRegEntry->pDevIns;
659#ifndef IN_RING3
660 if ( pfnOutCallback
661 && pDevIns
662 && pRegEntry->cPorts > 0)
663 { /* likely */ }
664 else
665 {
666 IOM_UNLOCK_SHARED(pVM);
667 STAM_COUNTER_INC(&pStats->OutRZToR3);
668 return iomIOPortRing3WritePending(pVCpu, Port, u32Value, cbValue);
669 }
670#endif
671 void *pvUser = pRegEntry->pvUser;
672 IOM_UNLOCK_SHARED(pVM);
673 AssertPtr(pDevIns);
674 AssertPtr(pfnOutCallback);
675
676 /*
677 * Call the device.
678 */
679 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_WRITE);
680 if (rcStrict == VINF_SUCCESS)
681 {
682 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
683 rcStrict = pfnOutCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? Port : offPort, u32Value, (unsigned)cbValue);
684 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
685
686 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
687
688#ifdef VBOX_WITH_STATISTICS
689 if (rcStrict == VINF_SUCCESS)
690 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
691#endif
692 Log3(("IOMIOPortWrite: Port=%RTiop u32=%08RX32 cb=%d rc=%Rrc\n", Port, u32Value, cbValue, VBOXSTRICTRC_VAL(rcStrict)));
693 }
694#ifndef IN_RING3
695 if (rcStrict == VINF_IOM_R3_IOPORT_WRITE)
696 {
697 STAM_COUNTER_INC(&pStats->OutRZToR3);
698 return iomIOPortRing3WritePending(pVCpu, Port, u32Value, cbValue);
699 }
700#endif
701 return rcStrict;
702 }
703
704 /*
705 * Old code
706 * Old code
707 * Old code
708 */
709
710#ifdef VBOX_WITH_STATISTICS
711 /*
712 * Find the statistics record.
713 */
714 PIOMIOPORTSTATS pStats = pVCpu->iom.s.CTX_SUFF(pStatsLastWrite);
715 if (!pStats || pStats->Core.Key != Port)
716 {
717 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, Port);
718 if (pStats)
719 pVCpu->iom.s.CTX_SUFF(pStatsLastWrite) = pStats;
720 }
721#endif
722
723 /*
724 * Get handler for current context.
725 */
726 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVCpu->iom.s.CTX_SUFF(pRangeLastWrite);
727 if ( !pRange
728 || (unsigned)Port - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
729 {
730 pRange = iomIOPortGetRange(pVM, Port);
731 if (pRange)
732 pVCpu->iom.s.CTX_SUFF(pRangeLastWrite) = pRange;
733 }
734 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
735 if (pRange)
736 {
737 /*
738 * Found a range.
739 */
740 PFNIOMIOPORTOUT pfnOutCallback = pRange->pfnOutCallback;
741#ifndef IN_RING3
742 if (pfnOutCallback)
743 { /* likely */ }
744 else
745 {
746 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
747 IOM_UNLOCK_SHARED(pVM);
748 return iomIOPortRing3WritePending(pVCpu, Port, u32Value, cbValue);
749 }
750#endif
751 void *pvUser = pRange->pvUser;
752 PPDMDEVINS pDevIns = pRange->pDevIns;
753 IOM_UNLOCK_SHARED(pVM);
754
755 /*
756 * Call the device.
757 */
758 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_WRITE);
759 if (rcStrict == VINF_SUCCESS)
760 { /* likely */ }
761 else
762 {
763 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
764#ifndef IN_RING3
765 if (RT_LIKELY(rcStrict == VINF_IOM_R3_IOPORT_WRITE))
766 return iomIOPortRing3WritePending(pVCpu, Port, u32Value, cbValue);
767#endif
768 return rcStrict;
769 }
770#ifdef VBOX_WITH_STATISTICS
771 if (pStats)
772 {
773 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
774 rcStrict = pfnOutCallback(pDevIns, pvUser, Port, u32Value, (unsigned)cbValue);
775 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
776 }
777 else
778#endif
779 rcStrict = pfnOutCallback(pDevIns, pvUser, Port, u32Value, (unsigned)cbValue);
780 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
781
782#ifdef VBOX_WITH_STATISTICS
783 if (rcStrict == VINF_SUCCESS && pStats)
784 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
785# ifndef IN_RING3
786 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE && pStats)
787 STAM_COUNTER_INC(&pStats->OutRZToR3);
788# endif
789#endif
790 Log3(("IOMIOPortWrite: Port=%RTiop u32=%08RX32 cb=%d rc=%Rrc\n", Port, u32Value, cbValue, VBOXSTRICTRC_VAL(rcStrict)));
791#ifndef IN_RING3
792 if (rcStrict == VINF_IOM_R3_IOPORT_WRITE)
793 return iomIOPortRing3WritePending(pVCpu, Port, u32Value, cbValue);
794#endif
795 return rcStrict;
796 }
797
798#ifndef IN_RING3
799 /*
800 * Handler in ring-3?
801 */
802 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(pVM, Port);
803 if (pRangeR3)
804 {
805# ifdef VBOX_WITH_STATISTICS
806 if (pStats)
807 STAM_COUNTER_INC(&pStats->OutRZToR3);
808# endif
809 IOM_UNLOCK_SHARED(pVM);
810 return iomIOPortRing3WritePending(pVCpu, Port, u32Value, cbValue);
811 }
812#endif
813
814 /*
815 * Ok, no handler for that port.
816 */
817#ifdef VBOX_WITH_STATISTICS
818 /* statistics. */
819 if (pStats)
820 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
821#endif
822 Log3(("IOMIOPortWrite: Port=%RTiop u32=%08RX32 cb=%d nop\n", Port, u32Value, cbValue));
823 IOM_UNLOCK_SHARED(pVM);
824 return VINF_SUCCESS;
825}
826
827
828/**
829 * Writes the string buffer of an I/O port register.
830 *
831 * @returns Strict VBox status code. Informational status codes other than the one documented
832 * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
833 * @retval VINF_SUCCESS Success or no string I/O callback in
834 * this context.
835 * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
836 * status code must be passed on to EM.
837 * @retval VINF_IOM_R3_IOPORT_WRITE Defer the write to ring-3. (R0/RC only)
838 *
839 * @param pVM The cross context VM structure.
840 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
841 * @param uPort The port to write to.
842 * @param pvSrc The guest page to read from.
843 * @param pcTransfers Pointer to the number of transfer units to write, on
844 * return remaining transfer units.
845 * @param cb Size of the transfer unit (1, 2 or 4 bytes).
846 */
847VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortWriteString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uPort, void const *pvSrc,
848 uint32_t *pcTransfers, unsigned cb)
849{
850 Assert(pVCpu->iom.s.PendingIOPortWrite.cbValue == 0);
851 Assert(cb == 1 || cb == 2 || cb == 4);
852
853 /* Take the IOM lock before performing any device I/O. */
854 int rc2 = IOM_LOCK_SHARED(pVM);
855#ifndef IN_RING3
856 if (rc2 == VERR_SEM_BUSY)
857 return VINF_IOM_R3_IOPORT_WRITE;
858#endif
859 AssertRC(rc2);
860
861 const uint32_t cRequestedTransfers = *pcTransfers;
862 Assert(cRequestedTransfers > 0);
863
864 /*
865 * Get the entry for the current context.
866 */
867 uint16_t offPort;
868 CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, uPort, &offPort, &pVCpu->iom.s.idxIoPortLastWriteStr);
869 if (pRegEntry)
870 {
871#ifdef VBOX_WITH_STATISTICS
872 PIOMIOPORTSTATSENTRY pStats = iomIoPortGetStats(pVM, pRegEntry, offPort);
873#endif
874
875 /*
876 * Found an entry, get the data so we can leave the IOM lock.
877 */
878 uint16_t const fFlags = pRegEntry->fFlags;
879 PFNIOMIOPORTNEWOUTSTRING pfnOutStrCallback = pRegEntry->pfnOutStrCallback;
880 PFNIOMIOPORTNEWOUT pfnOutCallback = pRegEntry->pfnOutCallback;
881 PPDMDEVINS pDevIns = pRegEntry->pDevIns;
882#ifndef IN_RING3
883 if ( pfnOutCallback
884 && pDevIns
885 && pRegEntry->cPorts > 0)
886 { /* likely */ }
887 else
888 {
889 IOM_UNLOCK_SHARED(pVM);
890 STAM_COUNTER_INC(&pStats->OutRZToR3);
891 return VINF_IOM_R3_IOPORT_WRITE;
892 }
893#endif
894 void *pvUser = pRegEntry->pvUser;
895 IOM_UNLOCK_SHARED(pVM);
896 AssertPtr(pDevIns);
897 AssertPtr(pfnOutCallback);
898
899 /*
900 * Call the device.
901 */
902 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_WRITE);
903 if (rcStrict == VINF_SUCCESS)
904 {
905 /*
906 * First using string I/O if possible.
907 */
908 if (pfnOutStrCallback)
909 {
910 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
911 rcStrict = pfnOutStrCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort,
912 (uint8_t const *)pvSrc, pcTransfers, cb);
913 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
914 }
915
916 /*
917 * Then doing the single I/O fallback.
918 */
919 if ( *pcTransfers > 0
920 && rcStrict == VINF_SUCCESS)
921 {
922 pvSrc = (uint8_t *)pvSrc + (cRequestedTransfers - *pcTransfers) * cb;
923 do
924 {
925 uint32_t u32Value;
926 switch (cb)
927 {
928 case 4: u32Value = *(uint32_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 4; break;
929 case 2: u32Value = *(uint16_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 2; break;
930 case 1: u32Value = *(uint8_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 1; break;
931 default: AssertFailed(); u32Value = UINT32_MAX;
932 }
933 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
934 rcStrict = pfnOutCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort, u32Value, cb);
935 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
936 if (IOM_SUCCESS(rcStrict))
937 *pcTransfers -= 1;
938 } while ( *pcTransfers > 0
939 && rcStrict == VINF_SUCCESS);
940 }
941
942 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
943
944#ifdef VBOX_WITH_STATISTICS
945 if (rcStrict == VINF_SUCCESS)
946 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
947# ifndef IN_RING3
948 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE)
949 STAM_COUNTER_INC(&pStats->OutRZToR3);
950# endif
951#endif
952 Log3(("IOMIOPortWriteStr: uPort=%RTiop pvSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rcStrict=%Rrc\n",
953 uPort, pvSrc, pcTransfers, cRequestedTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
954 }
955#ifndef IN_RING3
956 else
957 STAM_COUNTER_INC(&pStats->OutRZToR3);
958#endif
959 return rcStrict;
960 }
961
962 /*
963 * Old code.
964 * Old code.
965 * Old code.
966 */
967
968#ifdef VBOX_WITH_STATISTICS
969 /*
970 * Get the statistics record.
971 */
972 PIOMIOPORTSTATS pStats = pVCpu->iom.s.CTX_SUFF(pStatsLastWrite);
973 if (!pStats || pStats->Core.Key != uPort)
974 {
975 pStats = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortStatTree, uPort);
976 if (pStats)
977 pVCpu->iom.s.CTX_SUFF(pStatsLastWrite) = pStats;
978 }
979#endif
980
981 /*
982 * Get handler for current context.
983 */
984 CTX_SUFF(PIOMIOPORTRANGE) pRange = pVCpu->iom.s.CTX_SUFF(pRangeLastWrite);
985 if ( !pRange
986 || (unsigned)uPort - (unsigned)pRange->Port >= (unsigned)pRange->cPorts)
987 {
988 pRange = iomIOPortGetRange(pVM, uPort);
989 if (pRange)
990 pVCpu->iom.s.CTX_SUFF(pRangeLastWrite) = pRange;
991 }
992 MMHYPER_RC_ASSERT_RCPTR(pVM, pRange);
993 if (pRange)
994 {
995 /*
996 * Found a range.
997 */
998 PFNIOMIOPORTOUTSTRING pfnOutStrCallback = pRange->pfnOutStrCallback;
999 PFNIOMIOPORTOUT pfnOutCallback = pRange->pfnOutCallback;
1000#ifndef IN_RING3
1001 if (pfnOutStrCallback || pfnOutCallback)
1002 { /* likely */ }
1003 else
1004 {
1005 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
1006 IOM_UNLOCK_SHARED(pVM);
1007 return VINF_IOM_R3_IOPORT_WRITE;
1008 }
1009#endif
1010 void *pvUser = pRange->pvUser;
1011 PPDMDEVINS pDevIns = pRange->pDevIns;
1012 IOM_UNLOCK_SHARED(pVM);
1013
1014 /*
1015 * Call the device.
1016 */
1017 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_WRITE);
1018 if (rcStrict == VINF_SUCCESS)
1019 { /* likely */ }
1020 else
1021 {
1022 STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
1023 return rcStrict;
1024 }
1025
1026 /*
1027 * First using string I/O if possible.
1028 */
1029 if (pfnOutStrCallback)
1030 {
1031#ifdef VBOX_WITH_STATISTICS
1032 if (pStats)
1033 {
1034 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
1035 rcStrict = pfnOutStrCallback(pDevIns, pvUser, uPort, (uint8_t const *)pvSrc, pcTransfers, cb);
1036 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
1037 }
1038 else
1039#endif
1040 rcStrict = pfnOutStrCallback(pDevIns, pvUser, uPort, (uint8_t const *)pvSrc, pcTransfers, cb);
1041 }
1042
1043 /*
1044 * Then doing the single I/O fallback.
1045 */
1046 if ( *pcTransfers > 0
1047 && rcStrict == VINF_SUCCESS)
1048 {
1049 pvSrc = (uint8_t *)pvSrc + (cRequestedTransfers - *pcTransfers) * cb;
1050 do
1051 {
1052 uint32_t u32Value;
1053 switch (cb)
1054 {
1055 case 4: u32Value = *(uint32_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 4; break;
1056 case 2: u32Value = *(uint16_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 2; break;
1057 case 1: u32Value = *(uint8_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 1; break;
1058 default: AssertFailed(); u32Value = UINT32_MAX;
1059 }
1060#ifdef VBOX_WITH_STATISTICS
1061 if (pStats)
1062 {
1063 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
1064 rcStrict = pfnOutCallback(pDevIns, pvUser, uPort, u32Value, cb);
1065 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
1066 }
1067 else
1068#endif
1069 rcStrict = pfnOutCallback(pDevIns, pvUser, uPort, u32Value, cb);
1070 if (IOM_SUCCESS(rcStrict))
1071 *pcTransfers -= 1;
1072 } while ( *pcTransfers > 0
1073 && rcStrict == VINF_SUCCESS);
1074 }
1075
1076 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
1077
1078#ifdef VBOX_WITH_STATISTICS
1079 if (rcStrict == VINF_SUCCESS && pStats)
1080 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
1081# ifndef IN_RING3
1082 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE && pStats)
1083 STAM_COUNTER_INC(&pStats->OutRZToR3);
1084# endif
1085#endif
1086 Log3(("IOMIOPortWriteStr: uPort=%RTiop pvSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rcStrict=%Rrc\n",
1087 uPort, pvSrc, pcTransfers, cRequestedTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
1088 return rcStrict;
1089 }
1090
1091#ifndef IN_RING3
1092 /*
1093 * Handler in ring-3?
1094 */
1095 PIOMIOPORTRANGER3 pRangeR3 = iomIOPortGetRangeR3(pVM, uPort);
1096 if (pRangeR3)
1097 {
1098# ifdef VBOX_WITH_STATISTICS
1099 if (pStats)
1100 STAM_COUNTER_INC(&pStats->OutRZToR3);
1101# endif
1102 IOM_UNLOCK_SHARED(pVM);
1103 return VINF_IOM_R3_IOPORT_WRITE;
1104 }
1105#endif
1106
1107 /*
1108 * Ok, no handler for this port.
1109 */
1110 *pcTransfers = 0;
1111#ifdef VBOX_WITH_STATISTICS
1112 if (pStats)
1113 STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
1114#endif
1115 Log3(("IOMIOPortWriteStr: uPort=%RTiop (unused) pvSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
1116 uPort, pvSrc, pcTransfers, cRequestedTransfers, *pcTransfers, cb));
1117 IOM_UNLOCK_SHARED(pVM);
1118 return VINF_SUCCESS;
1119}
1120
1121
1122/**
1123 * Fress an MMIO range after the reference counter has become zero.
1124 *
1125 * @param pVM The cross context VM structure.
1126 * @param pRange The range to free.
1127 */
1128void iomMmioFreeRange(PVMCC pVM, PIOMMMIORANGE pRange)
1129{
1130 MMHyperFree(pVM, pRange);
1131}
1132
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