VirtualBox

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

Last change on this file since 81341 was 81333, checked in by vboxsync, 5 years ago

IOM: More MMIO stuff, almost there now... bugref:9218

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette