VirtualBox

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

最後變更 在這個檔案從80824是 80679,由 vboxsync 提交於 6 年 前

IOM,PDM,RTC: Add port sub-descriptions for a range. Fixed bug in statistics collection causing all access to be attributed to the first port in the range. Rearranged the stats for new I/O ports. bugref:9218

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 39.1 KB
 
1/* $Id: IOMAll.cpp 80679 2019-09-09 18:26:59Z 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.alldomusa.eu.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 PFNIOMIOPORTIN 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 PFNIOMIOPORTINSTRING pfnInStrCallback = pRegEntry->pfnInStrCallback;
352 PFNIOMIOPORTIN 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 PFNIOMIOPORTOUT 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 PFNIOMIOPORTOUTSTRING pfnOutStrCallback = pRegEntry->pfnOutStrCallback;
895 PFNIOMIOPORTOUT 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
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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