VirtualBox

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

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

IOM: New I/O port registration code. bugref:9218

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

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