VirtualBox

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

Last change on this file since 81071 was 80960, checked in by vboxsync, 5 years ago

IOM,PDM,DevPCI,DevPciIch9,RTC: Fixes to the I/O port lookup table insertion code. Converted (mostly) the two PCI buses to the new PDM device style. The ICH9 variant wasn't actually dropping the default critsect, it turned out. Changed the new I/O port callbacks to return VBOXSTRICTRC rather than plain int. bugref:9218

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

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