VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/IOM.cpp@ 82311

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

IOM,PDMDevHlp: Kicked out the old I/O port code. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 49.4 KB
Line 
1/* $Id: IOM.cpp 82311 2019-12-01 01:45:02Z vboxsync $ */
2/** @file
3 * IOM - Input / Output Monitor.
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/** @page pg_iom IOM - The Input / Output Monitor
20 *
21 * The input/output monitor will handle I/O exceptions routing them to the
22 * appropriate device. It implements an API to register and deregister virtual
23 * I/0 port handlers and memory mapped I/O handlers. A handler is PDM devices
24 * and a set of callback functions.
25 *
26 * @see grp_iom
27 *
28 *
29 * @section sec_iom_rawmode Raw-Mode
30 *
31 * In raw-mode I/O port access is trapped (\#GP(0)) by ensuring that the actual
32 * IOPL is 0 regardless of what the guest IOPL is. The \#GP handler use the
33 * disassembler (DIS) to figure which instruction caused it (there are a number
34 * of instructions in addition to the I/O ones) and if it's an I/O port access
35 * it will hand it to IOMRCIOPortHandler (via EMInterpretPortIO).
36 * IOMRCIOPortHandler will lookup the port in the AVL tree of registered
37 * handlers. If found, the handler will be called otherwise default action is
38 * taken. (Default action is to write into the void and read all set bits.)
39 *
40 * Memory Mapped I/O (MMIO) is implemented as a slightly special case of PGM
41 * access handlers. An MMIO range is registered with IOM which then registers it
42 * with the PGM access handler sub-system. The access handler catches all
43 * access and will be called in the context of a \#PF handler. In RC and R0 this
44 * handler is iomMmioPfHandler while in ring-3 it's iomR3MmioHandler (although
45 * in ring-3 there can be alternative ways). iomMmioPfHandler will attempt to
46 * emulate the instruction that is doing the access and pass the corresponding
47 * reads / writes to the device.
48 *
49 * Emulating I/O port access is less complex and should be slightly faster than
50 * emulating MMIO, so in most cases we should encourage the OS to use port I/O.
51 * Devices which are frequently accessed should register GC handlers to speed up
52 * execution.
53 *
54 *
55 * @section sec_iom_hm Hardware Assisted Virtualization Mode
56 *
57 * When running in hardware assisted virtualization mode we'll be doing much the
58 * same things as in raw-mode. The main difference is that we're running in the
59 * host ring-0 context and that we don't get faults (\#GP(0) and \#PG) but
60 * exits.
61 *
62 *
63 * @section sec_iom_rem Recompiled Execution Mode
64 *
65 * When running in the recompiler things are different. I/O port access is
66 * handled by calling IOMIOPortRead and IOMIOPortWrite directly. While MMIO can
67 * be handled in one of two ways. The normal way is that we have a registered a
68 * special RAM range with the recompiler and in the three callbacks (for byte,
69 * word and dword access) we call IOMMMIORead and IOMMMIOWrite directly. The
70 * alternative ways that the physical memory access which goes via PGM will take
71 * care of it by calling iomR3MmioHandler via the PGM access handler machinery
72 * - this shouldn't happen but it is an alternative...
73 *
74 *
75 * @section sec_iom_other Other Accesses
76 *
77 * I/O ports aren't really exposed in any other way, unless you count the
78 * instruction interpreter in EM, but that's just what we're doing in the
79 * raw-mode \#GP(0) case really. Now, it's possible to call IOMIOPortRead and
80 * IOMIOPortWrite directly to talk to a device, but this is really bad behavior
81 * and should only be done as temporary hacks (the PC BIOS device used to setup
82 * the CMOS this way back in the dark ages).
83 *
84 * MMIO has similar direct routes as the I/O ports and these shouldn't be used
85 * for the same reasons and with the same restrictions. OTOH since MMIO is
86 * mapped into the physical memory address space, it can be accessed in a number
87 * of ways thru PGM.
88 *
89 *
90 * @section sec_iom_logging Logging Levels
91 *
92 * Following assignments:
93 * - Level 5 is used for defering I/O port and MMIO writes to ring-3.
94 *
95 */
96
97/** @todo MMIO - simplifying the device end.
98 * - Add a return status for doing DBGFSTOP on access where there are no known
99 * registers.
100 * -
101 *
102 * */
103
104
105/*********************************************************************************************************************************
106* Header Files *
107*********************************************************************************************************************************/
108#define LOG_GROUP LOG_GROUP_IOM
109#include <VBox/vmm/iom.h>
110#include <VBox/vmm/cpum.h>
111#include <VBox/vmm/pgm.h>
112#include <VBox/sup.h>
113#include <VBox/vmm/hm.h>
114#include <VBox/vmm/mm.h>
115#include <VBox/vmm/stam.h>
116#include <VBox/vmm/dbgf.h>
117#include <VBox/vmm/pdmapi.h>
118#include <VBox/vmm/pdmdev.h>
119#include "IOMInternal.h"
120#include <VBox/vmm/vm.h>
121
122#include <VBox/param.h>
123#include <iprt/assert.h>
124#include <iprt/alloc.h>
125#include <iprt/string.h>
126#include <VBox/log.h>
127#include <VBox/err.h>
128
129#include "IOMInline.h"
130
131
132/*********************************************************************************************************************************
133* Internal Functions *
134*********************************************************************************************************************************/
135static void iomR3FlushCache(PVM pVM);
136
137#ifdef VBOX_WITH_STATISTICS
138static const char *iomR3IOPortGetStandardName(RTIOPORT Port);
139#endif
140
141
142/**
143 * Initializes the IOM.
144 *
145 * @returns VBox status code.
146 * @param pVM The cross context VM structure.
147 */
148VMMR3_INT_DECL(int) IOMR3Init(PVM pVM)
149{
150 LogFlow(("IOMR3Init:\n"));
151
152 /*
153 * Assert alignment and sizes.
154 */
155 AssertCompileMemberAlignment(VM, iom.s, 32);
156 AssertCompile(sizeof(pVM->iom.s) <= sizeof(pVM->iom.padding));
157 AssertCompileMemberAlignment(IOM, CritSect, sizeof(uintptr_t));
158
159 /*
160 * Initialize the REM critical section.
161 */
162#ifdef IOM_WITH_CRIT_SECT_RW
163 int rc = PDMR3CritSectRwInit(pVM, &pVM->iom.s.CritSect, RT_SRC_POS, "IOM Lock");
164#else
165 int rc = PDMR3CritSectInit(pVM, &pVM->iom.s.CritSect, RT_SRC_POS, "IOM Lock");
166#endif
167 AssertRCReturn(rc, rc);
168
169 /*
170 * Allocate the trees structure.
171 */
172 rc = MMHyperAlloc(pVM, sizeof(*pVM->iom.s.pTreesR3), 0, MM_TAG_IOM, (void **)&pVM->iom.s.pTreesR3);
173 AssertRCReturn(rc, rc);
174 pVM->iom.s.pTreesR0 = MMHyperR3ToR0(pVM, pVM->iom.s.pTreesR3);
175
176 /*
177 * Register the MMIO access handler type.
178 */
179 rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_MMIO,
180 iomMmioHandler,
181 NULL, "iomMmioHandler", "iomMmioPfHandler",
182 NULL, "iomMmioHandler", "iomMmioPfHandler",
183 "MMIO", &pVM->iom.s.hMmioHandlerType);
184 AssertRCReturn(rc, rc);
185
186 rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_MMIO,
187 iomMmioHandlerNew,
188 NULL, "iomMmioHandlerNew", "iomMmioPfHandlerNew",
189 NULL, "iomMmioHandlerNew", "iomMmioPfHandlerNew",
190 "MMIO New", &pVM->iom.s.hNewMmioHandlerType);
191 AssertRCReturn(rc, rc);
192
193 /*
194 * Info.
195 */
196 DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IoPortInfo);
197 DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MmioInfo);
198
199 /*
200 * Statistics.
201 */
202 STAM_REG(pVM, &pVM->iom.s.StatIoPortCommits, STAMTYPE_COUNTER, "/IOM/IoPortCommits", STAMUNIT_OCCURENCES, "Number of ring-3 I/O port commits.");
203
204 STAM_REL_REG(pVM, &pVM->iom.s.StatMMIOStaleMappings, STAMTYPE_PROFILE, "/IOM/MMIOStaleMappings", STAMUNIT_TICKS_PER_CALL, "Number of times iomMmioHandlerNew got a call for a remapped range at the old mapping.");
205 STAM_REG(pVM, &pVM->iom.s.StatRZMMIOHandler, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler", STAMUNIT_TICKS_PER_CALL, "Profiling of the iomMmioPfHandler() body, only success calls.");
206 STAM_REG(pVM, &pVM->iom.s.StatRZMMIOReadsToR3, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/ReadsToR3", STAMUNIT_OCCURENCES, "Number of read deferred to ring-3.");
207 STAM_REG(pVM, &pVM->iom.s.StatRZMMIOWritesToR3, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/WritesToR3", STAMUNIT_OCCURENCES, "Number of writes deferred to ring-3.");
208 STAM_REG(pVM, &pVM->iom.s.StatRZMMIOCommitsToR3, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/CommitsToR3", STAMUNIT_OCCURENCES, "Number of commits deferred to ring-3.");
209 STAM_REG(pVM, &pVM->iom.s.StatRZMMIODevLockContention, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/DevLockContention", STAMUNIT_OCCURENCES, "Number of device lock contention force return to ring-3.");
210 STAM_REG(pVM, &pVM->iom.s.StatR3MMIOHandler, STAMTYPE_COUNTER, "/IOM/R3-MMIOHandler", STAMUNIT_OCCURENCES, "Number of calls to iomMmioHandler.");
211
212 STAM_REG(pVM, &pVM->iom.s.StatMmioHandlerR3, STAMTYPE_COUNTER, "/IOM/OldMmioHandlerR3", STAMUNIT_OCCURENCES, "Number of calls to old iomMmioHandler from ring-3.");
213 STAM_REG(pVM, &pVM->iom.s.StatMmioHandlerR0, STAMTYPE_COUNTER, "/IOM/OldMmioHandlerR0", STAMUNIT_OCCURENCES, "Number of calls to old iomMmioHandler from ring-0.");
214
215 STAM_REG(pVM, &pVM->iom.s.StatMmioHandlerNewR3, STAMTYPE_COUNTER, "/IOM/MmioHandlerNewR3", STAMUNIT_OCCURENCES, "Number of calls to iomMmioHandlerNew from ring-3.");
216 STAM_REG(pVM, &pVM->iom.s.StatMmioHandlerNewR0, STAMTYPE_COUNTER, "/IOM/MmioHandlerNewR0", STAMUNIT_OCCURENCES, "Number of calls to iomMmioHandlerNew from ring-0.");
217 STAM_REG(pVM, &pVM->iom.s.StatMmioPfHandlerNew, STAMTYPE_COUNTER, "/IOM/MmioPfHandlerNew", STAMUNIT_OCCURENCES, "Number of calls to iomMmioPfHandlerNew.");
218 STAM_REG(pVM, &pVM->iom.s.StatMmioPhysHandlerNew, STAMTYPE_COUNTER, "/IOM/MmioPhysHandlerNew", STAMUNIT_OCCURENCES, "Number of calls to IOMR0MmioPhysHandler.");
219 STAM_REG(pVM, &pVM->iom.s.StatMmioCommitsDirect, STAMTYPE_COUNTER, "/IOM/MmioCommitsDirect", STAMUNIT_OCCURENCES, "Number of ring-3 MMIO commits direct to handler via handle hint.");
220 STAM_REG(pVM, &pVM->iom.s.StatMmioCommitsPgm, STAMTYPE_COUNTER, "/IOM/MmioCommitsPgm", STAMUNIT_OCCURENCES, "Number of ring-3 MMIO commits via PGM.");
221
222 /* Redundant, but just in case we change something in the future */
223 iomR3FlushCache(pVM);
224
225 LogFlow(("IOMR3Init: returns VINF_SUCCESS\n"));
226 return VINF_SUCCESS;
227}
228
229
230/**
231 * Called when a VM initialization stage is completed.
232 *
233 * @returns VBox status code.
234 * @param pVM The cross context VM structure.
235 * @param enmWhat The initialization state that was completed.
236 */
237VMMR3_INT_DECL(int) IOMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
238{
239#ifdef VBOX_WITH_STATISTICS
240 if (enmWhat == VMINITCOMPLETED_RING0)
241 {
242 /*
243 * Synchronize the ring-3 I/O port and MMIO statistics indices into the
244 * ring-0 tables to simplify ring-0 code. This also make sure that any
245 * later calls to grow the statistics tables will fail.
246 */
247 int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_SYNC_STATS_INDICES, 0, NULL);
248 AssertLogRelRCReturn(rc, rc);
249
250 /*
251 * Register I/O port and MMIO stats now that we're done registering MMIO
252 * regions and won't grow the table again.
253 */
254 for (uint32_t i = 0; i < pVM->iom.s.cIoPortRegs; i++)
255 {
256 PIOMIOPORTENTRYR3 pRegEntry = &pVM->iom.s.paIoPortRegs[i];
257 if ( pRegEntry->fMapped
258 && pRegEntry->idxStats != UINT16_MAX)
259 iomR3IoPortRegStats(pVM, pRegEntry);
260 }
261
262 for (uint32_t i = 0; i < pVM->iom.s.cMmioRegs; i++)
263 {
264 PIOMMMIOENTRYR3 pRegEntry = &pVM->iom.s.paMmioRegs[i];
265 if ( pRegEntry->fMapped
266 && pRegEntry->idxStats != UINT16_MAX)
267 iomR3MmioRegStats(pVM, pRegEntry);
268 }
269 }
270#else
271 RT_NOREF(pVM, enmWhat);
272#endif
273 return VINF_SUCCESS;
274}
275
276
277/**
278 * Flushes the IOM port & statistics lookup cache
279 *
280 * @param pVM The cross context VM structure.
281 */
282static void iomR3FlushCache(PVM pVM)
283{
284 /*
285 * Since all relevant (1) cache use requires at least read access to the
286 * critical section, we can exclude all other EMTs by grabbing exclusive
287 * access to the critical section and then safely update the caches of
288 * other EMTs.
289 * (1) The irrelvant access not holding the lock is in assertion code.
290 */
291 IOM_LOCK_EXCL(pVM);
292 VMCPUID idCpu = pVM->cCpus;
293 while (idCpu-- > 0)
294 {
295 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
296 pVCpu->iom.s.pMMIORangeLastR0 = NIL_RTR0PTR;
297 pVCpu->iom.s.pMMIOStatsLastR0 = NIL_RTR0PTR;
298
299 pVCpu->iom.s.pMMIORangeLastR3 = NULL;
300 pVCpu->iom.s.pMMIOStatsLastR3 = NULL;
301 }
302
303 IOM_UNLOCK_EXCL(pVM);
304}
305
306
307/**
308 * The VM is being reset.
309 *
310 * @param pVM The cross context VM structure.
311 */
312VMMR3_INT_DECL(void) IOMR3Reset(PVM pVM)
313{
314 iomR3FlushCache(pVM);
315}
316
317
318/**
319 * Applies relocations to data and code managed by this
320 * component. This function will be called at init and
321 * whenever the VMM need to relocate it self inside the GC.
322 *
323 * The IOM will update the addresses used by the switcher.
324 *
325 * @param pVM The cross context VM structure.
326 * @param offDelta Relocation delta relative to old location.
327 */
328VMMR3_INT_DECL(void) IOMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
329{
330 RT_NOREF(pVM, offDelta);
331}
332
333/**
334 * Terminates the IOM.
335 *
336 * Termination means cleaning up and freeing all resources,
337 * the VM it self is at this point powered off or suspended.
338 *
339 * @returns VBox status code.
340 * @param pVM The cross context VM structure.
341 */
342VMMR3_INT_DECL(int) IOMR3Term(PVM pVM)
343{
344 /*
345 * IOM is not owning anything but automatically freed resources,
346 * so there's nothing to do here.
347 */
348 NOREF(pVM);
349 return VINF_SUCCESS;
350}
351
352
353#ifdef VBOX_WITH_STATISTICS
354
355/**
356 * Create the statistics node for an MMIO address.
357 *
358 * @returns Pointer to new stats node.
359 *
360 * @param pVM The cross context VM structure.
361 * @param GCPhys The address.
362 * @param pszDesc Description.
363 */
364PIOMMMIOSTATS iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc)
365{
366 IOM_LOCK_EXCL(pVM);
367
368 /* check if it already exists. */
369 PIOMMMIOSTATS pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pVM->iom.s.pTreesR3->MmioStatTree, GCPhys);
370 if (pStats)
371 {
372 IOM_UNLOCK_EXCL(pVM);
373 return pStats;
374 }
375
376 /* allocate stats node. */
377 int rc = MMHyperAlloc(pVM, sizeof(*pStats), 0, MM_TAG_IOM_STATS, (void **)&pStats);
378 AssertRC(rc);
379 if (RT_SUCCESS(rc))
380 {
381 /* insert into the tree. */
382 pStats->Core.Key = GCPhys;
383 if (RTAvloGCPhysInsert(&pVM->iom.s.pTreesR3->MmioStatTree, &pStats->Core))
384 {
385 IOM_UNLOCK_EXCL(pVM);
386
387 rc = STAMR3RegisterF(pVM, &pStats->Accesses, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp", GCPhys); AssertRC(rc);
388 rc = STAMR3RegisterF(pVM, &pStats->ProfReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Read-R3", GCPhys); AssertRC(rc);
389 rc = STAMR3RegisterF(pVM, &pStats->ProfWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Write-R3", GCPhys); AssertRC(rc);
390 rc = STAMR3RegisterF(pVM, &pStats->ProfReadRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Read-RZ", GCPhys); AssertRC(rc);
391 rc = STAMR3RegisterF(pVM, &pStats->ProfWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Write-RZ", GCPhys); AssertRC(rc);
392 rc = STAMR3RegisterF(pVM, &pStats->ReadRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp/Read-RZtoR3", GCPhys); AssertRC(rc);
393 rc = STAMR3RegisterF(pVM, &pStats->WriteRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp/Write-RZtoR3", GCPhys); AssertRC(rc);
394
395 return pStats;
396 }
397 AssertMsgFailed(("what! GCPhys=%RGp\n", GCPhys));
398 MMHyperFree(pVM, pStats);
399 }
400 IOM_UNLOCK_EXCL(pVM);
401 return NULL;
402}
403
404#endif /* VBOX_WITH_STATISTICS */
405
406/**
407 * Registers a Memory Mapped I/O R3 handler.
408 *
409 * This API is called by PDM on behalf of a device. Devices must register ring-3 ranges
410 * before any GC and R0 ranges can be registered using IOMR3MMIORegisterRC() and IOMR3MMIORegisterR0().
411 *
412 * @returns VBox status code.
413 *
414 * @param pVM The cross context VM structure.
415 * @param pDevIns PDM device instance owning the MMIO range.
416 * @param GCPhysStart First physical address in the range.
417 * @param cbRange The size of the range (in bytes).
418 * @param pvUser User argument for the callbacks.
419 * @param pfnWriteCallback Pointer to function which is gonna handle Write operations.
420 * @param pfnReadCallback Pointer to function which is gonna handle Read operations.
421 * @param pfnFillCallback Pointer to function which is gonna handle Fill/memset operations.
422 * @param fFlags Flags, see IOMMMIO_FLAGS_XXX.
423 * @param pszDesc Pointer to description string. This must not be freed.
424 */
425VMMR3_INT_DECL(int)
426IOMR3MmioRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTHCPTR pvUser,
427 R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
428 R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback, uint32_t fFlags, const char *pszDesc)
429{
430 LogFlow(("IOMR3MmioRegisterR3: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp pvUser=%RHv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x fFlags=%#x pszDesc=%s\n",
431 pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback, fFlags, pszDesc));
432 int rc;
433
434 /*
435 * Validate input.
436 */
437 AssertMsgReturn(GCPhysStart + (cbRange - 1) >= GCPhysStart,("Wrapped! %RGp LB %RGp\n", GCPhysStart, cbRange),
438 VERR_IOM_INVALID_MMIO_RANGE);
439 AssertMsgReturn( !(fFlags & ~(IOMMMIO_FLAGS_VALID_MASK & ~IOMMMIO_FLAGS_ABS))
440 && (fFlags & IOMMMIO_FLAGS_READ_MODE) <= IOMMMIO_FLAGS_READ_DWORD_QWORD
441 && (fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
442 ("%#x\n", fFlags),
443 VERR_INVALID_PARAMETER);
444
445 /*
446 * Allocate new range record and initialize it.
447 */
448 PIOMMMIORANGE pRange;
449 rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
450 if (RT_SUCCESS(rc))
451 {
452 pRange->Core.Key = GCPhysStart;
453 pRange->Core.KeyLast = GCPhysStart + (cbRange - 1);
454 pRange->GCPhys = GCPhysStart;
455 pRange->cb = cbRange;
456 pRange->cRefs = 1; /* The tree reference. */
457 pRange->pszDesc = pszDesc;
458
459 //pRange->pvUserR0 = NIL_RTR0PTR;
460 //pRange->pDevInsR0 = NIL_RTR0PTR;
461 //pRange->pfnReadCallbackR0 = NIL_RTR0PTR;
462 //pRange->pfnWriteCallbackR0 = NIL_RTR0PTR;
463 //pRange->pfnFillCallbackR0 = NIL_RTR0PTR;
464
465 //pRange->pvUserRC = NIL_RTRCPTR;
466 //pRange->pDevInsRC = NIL_RTRCPTR;
467 //pRange->pfnReadCallbackRC = NIL_RTRCPTR;
468 //pRange->pfnWriteCallbackRC = NIL_RTRCPTR;
469 //pRange->pfnFillCallbackRC = NIL_RTRCPTR;
470
471 pRange->fFlags = fFlags;
472
473 pRange->pvUserR3 = pvUser;
474 pRange->pDevInsR3 = pDevIns;
475 pRange->pfnReadCallbackR3 = pfnReadCallback;
476 pRange->pfnWriteCallbackR3 = pfnWriteCallback;
477 pRange->pfnFillCallbackR3 = pfnFillCallback;
478
479 /*
480 * Try register it with PGM and then insert it into the tree.
481 */
482 rc = PGMR3PhysMMIORegister(pVM, GCPhysStart, cbRange, pVM->iom.s.hMmioHandlerType,
483 pRange, MMHyperR3ToR0(pVM, pRange), MMHyperR3ToRC(pVM, pRange), pszDesc);
484 if (RT_SUCCESS(rc))
485 {
486 IOM_LOCK_EXCL(pVM);
487 if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))
488 {
489 iomR3FlushCache(pVM);
490 IOM_UNLOCK_EXCL(pVM);
491 return VINF_SUCCESS;
492 }
493
494 /* bail out */
495 IOM_UNLOCK_EXCL(pVM);
496 DBGFR3Info(pVM->pUVM, "mmio", NULL, NULL);
497 AssertMsgFailed(("This cannot happen!\n"));
498 rc = VERR_IOM_IOPORT_IPE_3;
499 }
500
501 MMHyperFree(pVM, pRange);
502 }
503 if (pDevIns->iInstance > 0)
504 MMR3HeapFree((void *)pszDesc);
505 return rc;
506}
507
508
509#if 0
510/**
511 * Registers a Memory Mapped I/O RC handler range.
512 *
513 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges
514 * using IOMMMIORegisterR3() before calling this function.
515 *
516 *
517 * @returns VBox status code.
518 *
519 * @param pVM The cross context VM structure.
520 * @param pDevIns PDM device instance owning the MMIO range.
521 * @param GCPhysStart First physical address in the range.
522 * @param cbRange The size of the range (in bytes).
523 * @param pvUser User argument for the callbacks.
524 * @param pfnWriteCallback Pointer to function which is gonna handle Write operations.
525 * @param pfnReadCallback Pointer to function which is gonna handle Read operations.
526 * @param pfnFillCallback Pointer to function which is gonna handle Fill/memset operations.
527 * @thread EMT
528 */
529VMMR3_INT_DECL(int)
530IOMR3MmioRegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTGCPTR pvUser,
531 RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, RCPTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
532 RCPTRTYPE(PFNIOMMMIOFILL) pfnFillCallback)
533{
534 LogFlow(("IOMR3MmioRegisterRC: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp pvUser=%RGv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x\n",
535 pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback));
536 AssertReturn(VM_IS_RAW_MODE_ENABLED(pVM), VERR_IOM_HM_IPE);
537
538 /*
539 * Validate input.
540 */
541 if (!pfnWriteCallback && !pfnReadCallback)
542 {
543 AssertMsgFailed(("No callbacks! %RGp LB %RGp\n", GCPhysStart, cbRange));
544 return VERR_INVALID_PARAMETER;
545 }
546 PVMCPU pVCpu = VMMGetCpu(pVM); Assert(pVCpu);
547
548 /*
549 * Find the MMIO range and check that the input matches.
550 */
551 IOM_LOCK_EXCL(pVM);
552 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysStart);
553 AssertReturnStmt(pRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
554 AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK_EXCL(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
555 AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
556 AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
557
558 pRange->pvUserRC = pvUser;
559 pRange->pfnReadCallbackRC = pfnReadCallback;
560 pRange->pfnWriteCallbackRC= pfnWriteCallback;
561 pRange->pfnFillCallbackRC = pfnFillCallback;
562 pRange->pDevInsRC = pDevIns->pDevInsForRC;
563 IOM_UNLOCK_EXCL(pVM);
564
565 return VINF_SUCCESS;
566}
567#endif
568
569
570/**
571 * Registers a Memory Mapped I/O R0 handler range.
572 *
573 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges
574 * using IOMMR3MIORegisterHC() before calling this function.
575 *
576 *
577 * @returns VBox status code.
578 *
579 * @param pVM The cross context VM structure.
580 * @param pDevIns PDM device instance owning the MMIO range.
581 * @param GCPhysStart First physical address in the range.
582 * @param cbRange The size of the range (in bytes).
583 * @param pvUser User argument for the callbacks.
584 * @param pfnWriteCallback Pointer to function which is gonna handle Write operations.
585 * @param pfnReadCallback Pointer to function which is gonna handle Read operations.
586 * @param pfnFillCallback Pointer to function which is gonna handle Fill/memset operations.
587 * @thread EMT
588 */
589VMMR3_INT_DECL(int)
590IOMR3MmioRegisterR0(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTR0PTR pvUser,
591 R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback,
592 R0PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
593 R0PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback)
594{
595 LogFlow(("IOMR3MmioRegisterR0: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp pvUser=%RHv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x\n",
596 pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback));
597
598 /*
599 * Validate input.
600 */
601 if (!pfnWriteCallback && !pfnReadCallback)
602 {
603 AssertMsgFailed(("No callbacks! %RGp LB %RGp\n", GCPhysStart, cbRange));
604 return VERR_INVALID_PARAMETER;
605 }
606 PVMCPU pVCpu = VMMGetCpu(pVM); Assert(pVCpu);
607
608 /*
609 * Find the MMIO range and check that the input matches.
610 */
611 IOM_LOCK_EXCL(pVM);
612 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysStart);
613 AssertReturnStmt(pRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
614 AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK_EXCL(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
615 AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
616 AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
617
618 pRange->pvUserR0 = pvUser;
619 pRange->pfnReadCallbackR0 = pfnReadCallback;
620 pRange->pfnWriteCallbackR0= pfnWriteCallback;
621 pRange->pfnFillCallbackR0 = pfnFillCallback;
622 pRange->pDevInsR0 = pDevIns->pDevInsR0RemoveMe;
623 IOM_UNLOCK_EXCL(pVM);
624
625 return VINF_SUCCESS;
626}
627
628
629/**
630 * Deregisters a Memory Mapped I/O handler range.
631 *
632 * Registered GC, R0, and R3 ranges are affected.
633 *
634 * @returns VBox status code.
635 *
636 * @param pVM The cross context VM structure.
637 * @param pDevIns Device instance which the MMIO region is registered.
638 * @param GCPhysStart First physical address (GC) in the range.
639 * @param cbRange Number of bytes to deregister.
640 *
641 * @remark This function mainly for PCI PnP Config and will not do
642 * all the checks you might expect it to do.
643 */
644VMMR3_INT_DECL(int) IOMR3MmioDeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange)
645{
646 LogFlow(("IOMR3MmioDeregister: pDevIns=%p GCPhysStart=%RGp cbRange=%RGp\n", pDevIns, GCPhysStart, cbRange));
647
648 /*
649 * Validate input.
650 */
651 RTGCPHYS GCPhysLast = GCPhysStart + (cbRange - 1);
652 if (GCPhysLast < GCPhysStart)
653 {
654 AssertMsgFailed(("Wrapped! %#x LB %RGp\n", GCPhysStart, cbRange));
655 return VERR_IOM_INVALID_MMIO_RANGE;
656 }
657 PVMCPU pVCpu = VMMGetCpu(pVM); Assert(pVCpu);
658
659 IOM_LOCK_EXCL(pVM);
660
661 /*
662 * Check ownership and such for the entire area.
663 */
664 RTGCPHYS GCPhys = GCPhysStart;
665 while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
666 {
667 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
668 if (!pRange)
669 {
670 IOM_UNLOCK_EXCL(pVM);
671 return VERR_IOM_MMIO_RANGE_NOT_FOUND;
672 }
673 AssertMsgReturnStmt(pRange->pDevInsR3 == pDevIns,
674 ("Not owner! GCPhys=%RGp %RGp LB %RGp %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
675 IOM_UNLOCK_EXCL(pVM),
676 VERR_IOM_NOT_MMIO_RANGE_OWNER);
677 AssertMsgReturnStmt(pRange->Core.KeyLast <= GCPhysLast,
678 ("Incomplete R3 range! GCPhys=%RGp %RGp LB %RGp %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
679 IOM_UNLOCK_EXCL(pVM),
680 VERR_IOM_INCOMPLETE_MMIO_RANGE);
681
682 /* next */
683 Assert(GCPhys <= pRange->Core.KeyLast);
684 GCPhys = pRange->Core.KeyLast + 1;
685 }
686
687 /*
688 * Do the actual removing of the MMIO ranges.
689 */
690 GCPhys = GCPhysStart;
691 while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
692 {
693 iomR3FlushCache(pVM);
694
695 PIOMMMIORANGE pRange = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesR3->MMIOTree, GCPhys);
696 Assert(pRange);
697 Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);
698 IOM_UNLOCK_EXCL(pVM); /* Lock order fun. */
699
700 /* remove it from PGM */
701 int rc = PGMR3PhysMMIODeregister(pVM, GCPhys, pRange->cb);
702 AssertRC(rc);
703
704 IOM_LOCK_EXCL(pVM);
705
706 /* advance and free. */
707 GCPhys = pRange->Core.KeyLast + 1;
708 if (pDevIns->iInstance > 0)
709 {
710 void *pvDesc = ASMAtomicXchgPtr((void * volatile *)&pRange->pszDesc, NULL);
711 MMR3HeapFree(pvDesc);
712 }
713 iomMmioReleaseRange(pVM, pRange);
714 }
715
716 IOM_UNLOCK_EXCL(pVM);
717 return VINF_SUCCESS;
718}
719
720
721/**
722 * Notfication from PGM that the pre-registered MMIO region has been mapped into
723 * user address space.
724 *
725 * @returns VBox status code.
726 * @param pVM Pointer to the cross context VM structure.
727 * @param pvUser The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.
728 * @param GCPhys The mapping address.
729 * @remarks Called while owning the PGM lock.
730 */
731VMMR3_INT_DECL(int) IOMR3MmioExNotifyMapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys)
732{
733 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
734 AssertReturn(pRange->GCPhys == NIL_RTGCPHYS, VERR_IOM_MMIO_IPE_1);
735
736 IOM_LOCK_EXCL(pVM);
737 Assert(pRange->GCPhys == NIL_RTGCPHYS);
738 pRange->GCPhys = GCPhys;
739 pRange->Core.Key = GCPhys;
740 pRange->Core.KeyLast = GCPhys + pRange->cb - 1;
741 if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))
742 {
743 iomR3FlushCache(pVM);
744 IOM_UNLOCK_EXCL(pVM);
745 return VINF_SUCCESS;
746 }
747 IOM_UNLOCK_EXCL(pVM);
748
749 AssertLogRelMsgFailed(("RTAvlroGCPhysInsert failed on %RGp..%RGp - %s\n", pRange->Core.Key, pRange->Core.KeyLast, pRange->pszDesc));
750 pRange->GCPhys = NIL_RTGCPHYS;
751 pRange->Core.Key = NIL_RTGCPHYS;
752 pRange->Core.KeyLast = NIL_RTGCPHYS;
753 return VERR_IOM_MMIO_IPE_2;
754}
755
756
757/**
758 * Notfication from PGM that the pre-registered MMIO region has been unmapped
759 * from user address space.
760 *
761 * @param pVM Pointer to the cross context VM structure.
762 * @param pvUser The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.
763 * @param GCPhys The mapping address.
764 * @remarks Called while owning the PGM lock.
765 */
766VMMR3_INT_DECL(void) IOMR3MmioExNotifyUnmapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys)
767{
768 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
769 AssertLogRelReturnVoid(pRange->GCPhys == GCPhys);
770
771 IOM_LOCK_EXCL(pVM);
772 Assert(pRange->GCPhys == GCPhys);
773 PIOMMMIORANGE pRemoved = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesR3->MMIOTree, GCPhys);
774 if (pRemoved == pRange)
775 {
776 pRange->GCPhys = NIL_RTGCPHYS;
777 pRange->Core.Key = NIL_RTGCPHYS;
778 pRange->Core.KeyLast = NIL_RTGCPHYS;
779 iomR3FlushCache(pVM);
780 IOM_UNLOCK_EXCL(pVM);
781 }
782 else
783 {
784 if (pRemoved)
785 RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRemoved->Core);
786 IOM_UNLOCK_EXCL(pVM);
787 AssertLogRelMsgFailed(("RTAvlroGCPhysRemove returned %p instead of %p for %RGp (%s)\n",
788 pRemoved, pRange, GCPhys, pRange->pszDesc));
789 }
790}
791
792
793/**
794 * Notfication from PGM that the pre-registered MMIO region has been mapped into
795 * user address space.
796 *
797 * @param pVM Pointer to the cross context VM structure.
798 * @param pvUser The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.
799 * @remarks Called while owning the PGM lock.
800 */
801VMMR3_INT_DECL(void) IOMR3MmioExNotifyDeregistered(PVM pVM, void *pvUser)
802{
803 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
804 AssertLogRelReturnVoid(pRange->GCPhys == NIL_RTGCPHYS);
805 iomMmioReleaseRange(pVM, pRange);
806}
807
808
809/**
810 * Handles the unlikely and probably fatal merge cases.
811 *
812 * @returns Merged status code.
813 * @param rcStrict Current EM status code.
814 * @param rcStrictCommit The IOM I/O or MMIO write commit status to merge
815 * with @a rcStrict.
816 * @param rcIom For logging purposes only.
817 * @param pVCpu The cross context virtual CPU structure of the
818 * calling EMT. For logging purposes.
819 */
820DECL_NO_INLINE(static, VBOXSTRICTRC) iomR3MergeStatusSlow(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit,
821 int rcIom, PVMCPU pVCpu)
822{
823 if (RT_FAILURE_NP(rcStrict))
824 return rcStrict;
825
826 if (RT_FAILURE_NP(rcStrictCommit))
827 return rcStrictCommit;
828
829 if (rcStrict == rcStrictCommit)
830 return rcStrictCommit;
831
832 AssertLogRelMsgFailed(("rcStrictCommit=%Rrc rcStrict=%Rrc IOPort={%#06x<-%#xx/%u} MMIO={%RGp<-%.*Rhxs} (rcIom=%Rrc)\n",
833 VBOXSTRICTRC_VAL(rcStrictCommit), VBOXSTRICTRC_VAL(rcStrict),
834 pVCpu->iom.s.PendingIOPortWrite.IOPort,
835 pVCpu->iom.s.PendingIOPortWrite.u32Value, pVCpu->iom.s.PendingIOPortWrite.cbValue,
836 pVCpu->iom.s.PendingMmioWrite.GCPhys,
837 pVCpu->iom.s.PendingMmioWrite.cbValue, &pVCpu->iom.s.PendingMmioWrite.abValue[0], rcIom));
838 return VERR_IOM_FF_STATUS_IPE;
839}
840
841
842/**
843 * Helper for IOMR3ProcessForceFlag.
844 *
845 * @returns Merged status code.
846 * @param rcStrict Current EM status code.
847 * @param rcStrictCommit The IOM I/O or MMIO write commit status to merge
848 * with @a rcStrict.
849 * @param rcIom Either VINF_IOM_R3_IOPORT_COMMIT_WRITE or
850 * VINF_IOM_R3_MMIO_COMMIT_WRITE.
851 * @param pVCpu The cross context virtual CPU structure of the
852 * calling EMT.
853 */
854DECLINLINE(VBOXSTRICTRC) iomR3MergeStatus(VBOXSTRICTRC rcStrict, VBOXSTRICTRC rcStrictCommit, int rcIom, PVMCPU pVCpu)
855{
856 /* Simple. */
857 if (RT_LIKELY(rcStrict == rcIom || rcStrict == VINF_EM_RAW_TO_R3 || rcStrict == VINF_SUCCESS))
858 return rcStrictCommit;
859
860 if (RT_LIKELY(rcStrictCommit == VINF_SUCCESS))
861 return rcStrict;
862
863 /* EM scheduling status codes. */
864 if (RT_LIKELY( rcStrict >= VINF_EM_FIRST
865 && rcStrict <= VINF_EM_LAST))
866 {
867 if (RT_LIKELY( rcStrictCommit >= VINF_EM_FIRST
868 && rcStrictCommit <= VINF_EM_LAST))
869 return rcStrict < rcStrictCommit ? rcStrict : rcStrictCommit;
870 }
871
872 /* Unlikely */
873 return iomR3MergeStatusSlow(rcStrict, rcStrictCommit, rcIom, pVCpu);
874}
875
876
877/**
878 * Called by force-flag handling code when VMCPU_FF_IOM is set.
879 *
880 * @returns Merge between @a rcStrict and what the commit operation returned.
881 * @param pVM The cross context VM structure.
882 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
883 * @param rcStrict The status code returned by ring-0 or raw-mode.
884 * @thread EMT(pVCpu)
885 *
886 * @remarks The VMCPU_FF_IOM flag is handled before the status codes by EM, so
887 * we're very likely to see @a rcStrict set to
888 * VINF_IOM_R3_IOPORT_COMMIT_WRITE and VINF_IOM_R3_MMIO_COMMIT_WRITE
889 * here.
890 */
891VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict)
892{
893 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_IOM);
894 Assert(pVCpu->iom.s.PendingIOPortWrite.cbValue || pVCpu->iom.s.PendingMmioWrite.cbValue);
895
896 if (pVCpu->iom.s.PendingIOPortWrite.cbValue)
897 {
898 Log5(("IOM: Dispatching pending I/O port write: %#x LB %u -> %RTiop\n", pVCpu->iom.s.PendingIOPortWrite.u32Value,
899 pVCpu->iom.s.PendingIOPortWrite.cbValue, pVCpu->iom.s.PendingIOPortWrite.IOPort));
900 STAM_COUNTER_INC(&pVM->iom.s.StatIoPortCommits);
901 VBOXSTRICTRC rcStrictCommit = IOMIOPortWrite(pVM, pVCpu, pVCpu->iom.s.PendingIOPortWrite.IOPort,
902 pVCpu->iom.s.PendingIOPortWrite.u32Value,
903 pVCpu->iom.s.PendingIOPortWrite.cbValue);
904 pVCpu->iom.s.PendingIOPortWrite.cbValue = 0;
905 rcStrict = iomR3MergeStatus(rcStrict, rcStrictCommit, VINF_IOM_R3_IOPORT_COMMIT_WRITE, pVCpu);
906 }
907
908
909 if (pVCpu->iom.s.PendingMmioWrite.cbValue)
910 {
911 Log5(("IOM: Dispatching pending MMIO write: %RGp LB %#x\n",
912 pVCpu->iom.s.PendingMmioWrite.GCPhys, pVCpu->iom.s.PendingMmioWrite.cbValue));
913
914 /* Use new MMIO handle hint and bypass PGM if it still looks right. */
915 size_t idxMmioRegionHint = pVCpu->iom.s.PendingMmioWrite.idxMmioRegionHint;
916 if (idxMmioRegionHint < pVM->iom.s.cMmioRegs)
917 {
918 PIOMMMIOENTRYR3 pRegEntry = &pVM->iom.s.paMmioRegs[idxMmioRegionHint];
919 RTGCPHYS const GCPhysMapping = pRegEntry->GCPhysMapping;
920 RTGCPHYS const offRegion = pVCpu->iom.s.PendingMmioWrite.GCPhys - GCPhysMapping;
921 if (offRegion < pRegEntry->cbRegion && GCPhysMapping != NIL_RTGCPHYS)
922 {
923 STAM_COUNTER_INC(&pVM->iom.s.StatMmioCommitsDirect);
924 VBOXSTRICTRC rcStrictCommit = iomR3MmioCommitWorker(pVM, pVCpu, pRegEntry, offRegion);
925 pVCpu->iom.s.PendingMmioWrite.cbValue = 0;
926 return iomR3MergeStatus(rcStrict, rcStrictCommit, VINF_IOM_R3_MMIO_COMMIT_WRITE, pVCpu);
927 }
928 }
929
930 /* Fall back on PGM. */
931 STAM_COUNTER_INC(&pVM->iom.s.StatMmioCommitsPgm);
932 VBOXSTRICTRC rcStrictCommit = PGMPhysWrite(pVM, pVCpu->iom.s.PendingMmioWrite.GCPhys,
933 pVCpu->iom.s.PendingMmioWrite.abValue, pVCpu->iom.s.PendingMmioWrite.cbValue,
934 PGMACCESSORIGIN_IOM);
935 pVCpu->iom.s.PendingMmioWrite.cbValue = 0;
936 rcStrict = iomR3MergeStatus(rcStrict, rcStrictCommit, VINF_IOM_R3_MMIO_COMMIT_WRITE, pVCpu);
937 }
938
939 return rcStrict;
940}
941
942
943/**
944 * Notification from DBGF that the number of active I/O port or MMIO
945 * breakpoints has change.
946 *
947 * For performance reasons, IOM will only call DBGF before doing I/O and MMIO
948 * accesses where there are armed breakpoints.
949 *
950 * @param pVM The cross context VM structure.
951 * @param fPortIo True if there are armed I/O port breakpoints.
952 * @param fMmio True if there are armed MMIO breakpoints.
953 */
954VMMR3_INT_DECL(void) IOMR3NotifyBreakpointCountChange(PVM pVM, bool fPortIo, bool fMmio)
955{
956 /** @todo I/O breakpoints. */
957 RT_NOREF3(pVM, fPortIo, fMmio);
958}
959
960
961/**
962 * Notification from DBGF that an event has been enabled or disabled.
963 *
964 * For performance reasons, IOM may cache the state of events it implements.
965 *
966 * @param pVM The cross context VM structure.
967 * @param enmEvent The event.
968 * @param fEnabled The new state.
969 */
970VMMR3_INT_DECL(void) IOMR3NotifyDebugEventChange(PVM pVM, DBGFEVENT enmEvent, bool fEnabled)
971{
972 /** @todo IOM debug events. */
973 RT_NOREF3(pVM, enmEvent, fEnabled);
974}
975
976
977#ifdef VBOX_WITH_STATISTICS
978/**
979 * Tries to come up with the standard name for a port.
980 *
981 * @returns Pointer to readonly string if known.
982 * @returns NULL if unknown port number.
983 *
984 * @param Port The port to name.
985 */
986static const char *iomR3IOPortGetStandardName(RTIOPORT Port)
987{
988 switch (Port)
989 {
990 case 0x00: case 0x10: case 0x20: case 0x30: case 0x40: case 0x50: case 0x70:
991 case 0x01: case 0x11: case 0x21: case 0x31: case 0x41: case 0x51: case 0x61: case 0x71:
992 case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: case 0x62: case 0x72:
993 case 0x03: case 0x13: case 0x23: case 0x33: case 0x43: case 0x53: case 0x63: case 0x73:
994 case 0x04: case 0x14: case 0x24: case 0x34: case 0x44: case 0x54: case 0x74:
995 case 0x05: case 0x15: case 0x25: case 0x35: case 0x45: case 0x55: case 0x65: case 0x75:
996 case 0x06: case 0x16: case 0x26: case 0x36: case 0x46: case 0x56: case 0x66: case 0x76:
997 case 0x07: case 0x17: case 0x27: case 0x37: case 0x47: case 0x57: case 0x67: case 0x77:
998 case 0x08: case 0x18: case 0x28: case 0x38: case 0x48: case 0x58: case 0x68: case 0x78:
999 case 0x09: case 0x19: case 0x29: case 0x39: case 0x49: case 0x59: case 0x69: case 0x79:
1000 case 0x0a: case 0x1a: case 0x2a: case 0x3a: case 0x4a: case 0x5a: case 0x6a: case 0x7a:
1001 case 0x0b: case 0x1b: case 0x2b: case 0x3b: case 0x4b: case 0x5b: case 0x6b: case 0x7b:
1002 case 0x0c: case 0x1c: case 0x2c: case 0x3c: case 0x4c: case 0x5c: case 0x6c: case 0x7c:
1003 case 0x0d: case 0x1d: case 0x2d: case 0x3d: case 0x4d: case 0x5d: case 0x6d: case 0x7d:
1004 case 0x0e: case 0x1e: case 0x2e: case 0x3e: case 0x4e: case 0x5e: case 0x6e: case 0x7e:
1005 case 0x0f: case 0x1f: case 0x2f: case 0x3f: case 0x4f: case 0x5f: case 0x6f: case 0x7f:
1006
1007 case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xc0: case 0xd0: case 0xe0: case 0xf0:
1008 case 0x81: case 0x91: case 0xa1: case 0xb1: case 0xc1: case 0xd1: case 0xe1: case 0xf1:
1009 case 0x82: case 0x92: case 0xa2: case 0xb2: case 0xc2: case 0xd2: case 0xe2: case 0xf2:
1010 case 0x83: case 0x93: case 0xa3: case 0xb3: case 0xc3: case 0xd3: case 0xe3: case 0xf3:
1011 case 0x84: case 0x94: case 0xa4: case 0xb4: case 0xc4: case 0xd4: case 0xe4: case 0xf4:
1012 case 0x85: case 0x95: case 0xa5: case 0xb5: case 0xc5: case 0xd5: case 0xe5: case 0xf5:
1013 case 0x86: case 0x96: case 0xa6: case 0xb6: case 0xc6: case 0xd6: case 0xe6: case 0xf6:
1014 case 0x87: case 0x97: case 0xa7: case 0xb7: case 0xc7: case 0xd7: case 0xe7: case 0xf7:
1015 case 0x88: case 0x98: case 0xa8: case 0xb8: case 0xc8: case 0xd8: case 0xe8: case 0xf8:
1016 case 0x89: case 0x99: case 0xa9: case 0xb9: case 0xc9: case 0xd9: case 0xe9: case 0xf9:
1017 case 0x8a: case 0x9a: case 0xaa: case 0xba: case 0xca: case 0xda: case 0xea: case 0xfa:
1018 case 0x8b: case 0x9b: case 0xab: case 0xbb: case 0xcb: case 0xdb: case 0xeb: case 0xfb:
1019 case 0x8c: case 0x9c: case 0xac: case 0xbc: case 0xcc: case 0xdc: case 0xec: case 0xfc:
1020 case 0x8d: case 0x9d: case 0xad: case 0xbd: case 0xcd: case 0xdd: case 0xed: case 0xfd:
1021 case 0x8e: case 0x9e: case 0xae: case 0xbe: case 0xce: case 0xde: case 0xee: case 0xfe:
1022 case 0x8f: case 0x9f: case 0xaf: case 0xbf: case 0xcf: case 0xdf: case 0xef: case 0xff:
1023 return "System Reserved";
1024
1025 case 0x60:
1026 case 0x64:
1027 return "Keyboard & Mouse";
1028
1029 case 0x378:
1030 case 0x379:
1031 case 0x37a:
1032 case 0x37b:
1033 case 0x37c:
1034 case 0x37d:
1035 case 0x37e:
1036 case 0x37f:
1037 case 0x3bc:
1038 case 0x3bd:
1039 case 0x3be:
1040 case 0x3bf:
1041 case 0x278:
1042 case 0x279:
1043 case 0x27a:
1044 case 0x27b:
1045 case 0x27c:
1046 case 0x27d:
1047 case 0x27e:
1048 case 0x27f:
1049 return "LPT1/2/3";
1050
1051 case 0x3f8:
1052 case 0x3f9:
1053 case 0x3fa:
1054 case 0x3fb:
1055 case 0x3fc:
1056 case 0x3fd:
1057 case 0x3fe:
1058 case 0x3ff:
1059 return "COM1";
1060
1061 case 0x2f8:
1062 case 0x2f9:
1063 case 0x2fa:
1064 case 0x2fb:
1065 case 0x2fc:
1066 case 0x2fd:
1067 case 0x2fe:
1068 case 0x2ff:
1069 return "COM2";
1070
1071 case 0x3e8:
1072 case 0x3e9:
1073 case 0x3ea:
1074 case 0x3eb:
1075 case 0x3ec:
1076 case 0x3ed:
1077 case 0x3ee:
1078 case 0x3ef:
1079 return "COM3";
1080
1081 case 0x2e8:
1082 case 0x2e9:
1083 case 0x2ea:
1084 case 0x2eb:
1085 case 0x2ec:
1086 case 0x2ed:
1087 case 0x2ee:
1088 case 0x2ef:
1089 return "COM4";
1090
1091 case 0x200:
1092 case 0x201:
1093 case 0x202:
1094 case 0x203:
1095 case 0x204:
1096 case 0x205:
1097 case 0x206:
1098 case 0x207:
1099 return "Joystick";
1100
1101 case 0x3f0:
1102 case 0x3f1:
1103 case 0x3f2:
1104 case 0x3f3:
1105 case 0x3f4:
1106 case 0x3f5:
1107 case 0x3f6:
1108 case 0x3f7:
1109 return "Floppy";
1110
1111 case 0x1f0:
1112 case 0x1f1:
1113 case 0x1f2:
1114 case 0x1f3:
1115 case 0x1f4:
1116 case 0x1f5:
1117 case 0x1f6:
1118 case 0x1f7:
1119 //case 0x3f6:
1120 //case 0x3f7:
1121 return "IDE 1st";
1122
1123 case 0x170:
1124 case 0x171:
1125 case 0x172:
1126 case 0x173:
1127 case 0x174:
1128 case 0x175:
1129 case 0x176:
1130 case 0x177:
1131 case 0x376:
1132 case 0x377:
1133 return "IDE 2nd";
1134
1135 case 0x1e0:
1136 case 0x1e1:
1137 case 0x1e2:
1138 case 0x1e3:
1139 case 0x1e4:
1140 case 0x1e5:
1141 case 0x1e6:
1142 case 0x1e7:
1143 case 0x3e6:
1144 case 0x3e7:
1145 return "IDE 3rd";
1146
1147 case 0x160:
1148 case 0x161:
1149 case 0x162:
1150 case 0x163:
1151 case 0x164:
1152 case 0x165:
1153 case 0x166:
1154 case 0x167:
1155 case 0x366:
1156 case 0x367:
1157 return "IDE 4th";
1158
1159 case 0x130: case 0x140: case 0x150:
1160 case 0x131: case 0x141: case 0x151:
1161 case 0x132: case 0x142: case 0x152:
1162 case 0x133: case 0x143: case 0x153:
1163 case 0x134: case 0x144: case 0x154:
1164 case 0x135: case 0x145: case 0x155:
1165 case 0x136: case 0x146: case 0x156:
1166 case 0x137: case 0x147: case 0x157:
1167 case 0x138: case 0x148: case 0x158:
1168 case 0x139: case 0x149: case 0x159:
1169 case 0x13a: case 0x14a: case 0x15a:
1170 case 0x13b: case 0x14b: case 0x15b:
1171 case 0x13c: case 0x14c: case 0x15c:
1172 case 0x13d: case 0x14d: case 0x15d:
1173 case 0x13e: case 0x14e: case 0x15e:
1174 case 0x13f: case 0x14f: case 0x15f:
1175 case 0x220: case 0x230:
1176 case 0x221: case 0x231:
1177 case 0x222: case 0x232:
1178 case 0x223: case 0x233:
1179 case 0x224: case 0x234:
1180 case 0x225: case 0x235:
1181 case 0x226: case 0x236:
1182 case 0x227: case 0x237:
1183 case 0x228: case 0x238:
1184 case 0x229: case 0x239:
1185 case 0x22a: case 0x23a:
1186 case 0x22b: case 0x23b:
1187 case 0x22c: case 0x23c:
1188 case 0x22d: case 0x23d:
1189 case 0x22e: case 0x23e:
1190 case 0x22f: case 0x23f:
1191 case 0x330: case 0x340: case 0x350:
1192 case 0x331: case 0x341: case 0x351:
1193 case 0x332: case 0x342: case 0x352:
1194 case 0x333: case 0x343: case 0x353:
1195 case 0x334: case 0x344: case 0x354:
1196 case 0x335: case 0x345: case 0x355:
1197 case 0x336: case 0x346: case 0x356:
1198 case 0x337: case 0x347: case 0x357:
1199 case 0x338: case 0x348: case 0x358:
1200 case 0x339: case 0x349: case 0x359:
1201 case 0x33a: case 0x34a: case 0x35a:
1202 case 0x33b: case 0x34b: case 0x35b:
1203 case 0x33c: case 0x34c: case 0x35c:
1204 case 0x33d: case 0x34d: case 0x35d:
1205 case 0x33e: case 0x34e: case 0x35e:
1206 case 0x33f: case 0x34f: case 0x35f:
1207 return "SCSI (typically)";
1208
1209 case 0x320:
1210 case 0x321:
1211 case 0x322:
1212 case 0x323:
1213 case 0x324:
1214 case 0x325:
1215 case 0x326:
1216 case 0x327:
1217 return "XT HD";
1218
1219 case 0x3b0:
1220 case 0x3b1:
1221 case 0x3b2:
1222 case 0x3b3:
1223 case 0x3b4:
1224 case 0x3b5:
1225 case 0x3b6:
1226 case 0x3b7:
1227 case 0x3b8:
1228 case 0x3b9:
1229 case 0x3ba:
1230 case 0x3bb:
1231 return "VGA";
1232
1233 case 0x3c0: case 0x3d0:
1234 case 0x3c1: case 0x3d1:
1235 case 0x3c2: case 0x3d2:
1236 case 0x3c3: case 0x3d3:
1237 case 0x3c4: case 0x3d4:
1238 case 0x3c5: case 0x3d5:
1239 case 0x3c6: case 0x3d6:
1240 case 0x3c7: case 0x3d7:
1241 case 0x3c8: case 0x3d8:
1242 case 0x3c9: case 0x3d9:
1243 case 0x3ca: case 0x3da:
1244 case 0x3cb: case 0x3db:
1245 case 0x3cc: case 0x3dc:
1246 case 0x3cd: case 0x3dd:
1247 case 0x3ce: case 0x3de:
1248 case 0x3cf: case 0x3df:
1249 return "VGA/EGA";
1250
1251 case 0x240: case 0x260: case 0x280:
1252 case 0x241: case 0x261: case 0x281:
1253 case 0x242: case 0x262: case 0x282:
1254 case 0x243: case 0x263: case 0x283:
1255 case 0x244: case 0x264: case 0x284:
1256 case 0x245: case 0x265: case 0x285:
1257 case 0x246: case 0x266: case 0x286:
1258 case 0x247: case 0x267: case 0x287:
1259 case 0x248: case 0x268: case 0x288:
1260 case 0x249: case 0x269: case 0x289:
1261 case 0x24a: case 0x26a: case 0x28a:
1262 case 0x24b: case 0x26b: case 0x28b:
1263 case 0x24c: case 0x26c: case 0x28c:
1264 case 0x24d: case 0x26d: case 0x28d:
1265 case 0x24e: case 0x26e: case 0x28e:
1266 case 0x24f: case 0x26f: case 0x28f:
1267 case 0x300:
1268 case 0x301:
1269 case 0x388:
1270 case 0x389:
1271 case 0x38a:
1272 case 0x38b:
1273 return "Sound Card (typically)";
1274
1275 default:
1276 return NULL;
1277 }
1278}
1279#endif /* VBOX_WITH_STATISTICS */
1280
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