~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/VMM/IOM.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: IOM.cpp $ */
2
 
/** @file
3
 
 * IOM - Input / Output Monitor.
4
 
 */
5
 
 
6
 
/*
7
 
 * Copyright (C) 2006-2007 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
 
 * dissassembler (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 IOMGCIOPortHandler (via EMInterpretPortIO).
36
 
 * IOMGCIOPortHandler 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 sligtly 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 IOMMMIOHandler while in ring-3 it's IOMR3MMIOHandler (althought in
45
 
 * ring-3 there can be alternative ways). IOMMMIOHandler will attempt to emulate
46
 
 * the instruction that is doing the access and pass the corresponding reads /
47
 
 * writes to the device.
48
 
 *
49
 
 * Emulating I/O port access is less complex and should be sligtly faster than
50
 
 * emulating MMIO, so in most cases we should encourage the OS to use port I/O.
51
 
 * Devices which are freqently accessed should register GC handlers to speed up
52
 
 * execution.
53
 
 *
54
 
 *
55
 
 * @section sec_iom_hwaccm     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
82
 
 * setup 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
 
 
91
 
 
92
 
/*******************************************************************************
93
 
*   Header Files                                                               *
94
 
*******************************************************************************/
95
 
#define LOG_GROUP LOG_GROUP_IOM
96
 
#include <VBox/iom.h>
97
 
#include <VBox/cpum.h>
98
 
#include <VBox/pgm.h>
99
 
#include <VBox/sup.h>
100
 
#include <VBox/mm.h>
101
 
#include <VBox/stam.h>
102
 
#include <VBox/dbgf.h>
103
 
#include <VBox/pdmapi.h>
104
 
#include <VBox/pdmdev.h>
105
 
#include "IOMInternal.h"
106
 
#include <VBox/vm.h>
107
 
 
108
 
#include <VBox/param.h>
109
 
#include <iprt/assert.h>
110
 
#include <iprt/alloc.h>
111
 
#include <iprt/string.h>
112
 
#include <VBox/log.h>
113
 
#include <VBox/err.h>
114
 
 
115
 
 
116
 
/*******************************************************************************
117
 
*   Internal Functions                                                         *
118
 
*******************************************************************************/
119
 
static void iomR3FlushCache(PVM pVM);
120
 
static DECLCALLBACK(int) iomR3RelocateIOPortCallback(PAVLROIOPORTNODECORE pNode, void *pvUser);
121
 
static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser);
122
 
static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
123
 
static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
124
 
static DECLCALLBACK(int) iomR3IOPortDummyIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
125
 
static DECLCALLBACK(int) iomR3IOPortDummyOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
126
 
static DECLCALLBACK(int) iomR3IOPortDummyInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb);
127
 
static DECLCALLBACK(int) iomR3IOPortDummyOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb);
128
 
 
129
 
#ifdef VBOX_WITH_STATISTICS
130
 
static const char *iomR3IOPortGetStandardName(RTIOPORT Port);
131
 
#endif
132
 
 
133
 
 
134
 
/**
135
 
 * Initializes the IOM.
136
 
 *
137
 
 * @returns VBox status code.
138
 
 * @param   pVM         The VM to operate on.
139
 
 */
140
 
VMMR3DECL(int) IOMR3Init(PVM pVM)
141
 
{
142
 
    LogFlow(("IOMR3Init:\n"));
143
 
 
144
 
    /*
145
 
     * Assert alignment and sizes.
146
 
     */
147
 
    AssertCompileMemberAlignment(VM, iom.s, 32);
148
 
    AssertCompile(sizeof(pVM->iom.s) <= sizeof(pVM->iom.padding));
149
 
    AssertCompileMemberAlignment(IOM, EmtLock, sizeof(uintptr_t));
150
 
 
151
 
    /*
152
 
     * Setup any fixed pointers and offsets.
153
 
     */
154
 
    pVM->iom.s.offVM = RT_OFFSETOF(VM, iom);
155
 
 
156
 
    /*
157
 
     * Initialize the REM critical section.
158
 
     */
159
 
    int rc = PDMR3CritSectInit(pVM, &pVM->iom.s.EmtLock, RT_SRC_POS, "IOM EMT Lock");
160
 
    AssertRCReturn(rc, rc);
161
 
 
162
 
    /*
163
 
     * Allocate the trees structure.
164
 
     */
165
 
    rc = MMHyperAlloc(pVM, sizeof(*pVM->iom.s.pTreesR3), 0, MM_TAG_IOM, (void **)&pVM->iom.s.pTreesR3);
166
 
    if (RT_SUCCESS(rc))
167
 
    {
168
 
        pVM->iom.s.pTreesRC = MMHyperR3ToRC(pVM, pVM->iom.s.pTreesR3);
169
 
        pVM->iom.s.pTreesR0 = MMHyperR3ToR0(pVM, pVM->iom.s.pTreesR3);
170
 
        pVM->iom.s.pfnMMIOHandlerRC = NIL_RTGCPTR;
171
 
        pVM->iom.s.pfnMMIOHandlerR0 = NIL_RTR0PTR;
172
 
 
173
 
        /*
174
 
         * Info.
175
 
         */
176
 
        DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IOPortInfo);
177
 
        DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MMIOInfo);
178
 
 
179
 
        /*
180
 
         * Statistics.
181
 
         */
182
 
        STAM_REG(pVM, &pVM->iom.s.StatRZMMIOHandler,      STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler",                      STAMUNIT_TICKS_PER_CALL, "Profiling of the IOMMMIOHandler() body, only success calls.");
183
 
        STAM_REG(pVM, &pVM->iom.s.StatRZMMIO1Byte,        STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access1",              STAMUNIT_OCCURENCES,     "MMIO access by 1 byte counter.");
184
 
        STAM_REG(pVM, &pVM->iom.s.StatRZMMIO2Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access2",              STAMUNIT_OCCURENCES,     "MMIO access by 2 bytes counter.");
185
 
        STAM_REG(pVM, &pVM->iom.s.StatRZMMIO4Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access4",              STAMUNIT_OCCURENCES,     "MMIO access by 4 bytes counter.");
186
 
        STAM_REG(pVM, &pVM->iom.s.StatRZMMIO8Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access8",              STAMUNIT_OCCURENCES,     "MMIO access by 8 bytes counter.");
187
 
        STAM_REG(pVM, &pVM->iom.s.StatRZMMIOFailures,     STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/MMIOFailures",         STAMUNIT_OCCURENCES,     "Number of times IOMMMIOHandler() didn't service the request.");
188
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstMov,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOV",             STAMUNIT_TICKS_PER_CALL, "Profiling of the MOV instruction emulation.");
189
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstCmp,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/CMP",             STAMUNIT_TICKS_PER_CALL, "Profiling of the CMP instruction emulation.");
190
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstAnd,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/AND",             STAMUNIT_TICKS_PER_CALL, "Profiling of the AND instruction emulation.");
191
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstOr,           STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/OR",              STAMUNIT_TICKS_PER_CALL, "Profiling of the OR instruction emulation.");
192
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstXor,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/XOR",             STAMUNIT_TICKS_PER_CALL, "Profiling of the XOR instruction emulation.");
193
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstBt,           STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/BT",              STAMUNIT_TICKS_PER_CALL, "Profiling of the BT instruction emulation.");
194
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstTest,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/TEST",            STAMUNIT_TICKS_PER_CALL, "Profiling of the TEST instruction emulation.");
195
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstXchg,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/XCHG",            STAMUNIT_TICKS_PER_CALL, "Profiling of the XCHG instruction emulation.");
196
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstStos,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/STOS",            STAMUNIT_TICKS_PER_CALL, "Profiling of the STOS instruction emulation.");
197
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstLods,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/LODS",            STAMUNIT_TICKS_PER_CALL, "Profiling of the LODS instruction emulation.");
198
 
#ifdef IOM_WITH_MOVS_SUPPORT
199
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstMovs,     STAMTYPE_PROFILE_ADV, "/IOM/RZ-MMIOHandler/Inst/MOVS",            STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation.");
200
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsToMMIO,   STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/ToMMIO",     STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - Mem2MMIO.");
201
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsFromMMIO, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/FromMMIO",   STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - MMIO2Mem.");
202
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsMMIO,     STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/MMIO2MMIO",  STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - MMIO2MMIO.");
203
 
#endif
204
 
        STAM_REG(pVM, &pVM->iom.s.StatRZInstOther,        STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Inst/Other",           STAMUNIT_OCCURENCES,     "Other instructions counter.");
205
 
        STAM_REG(pVM, &pVM->iom.s.StatR3MMIOHandler,      STAMTYPE_COUNTER, "/IOM/R3-MMIOHandler",                      STAMUNIT_OCCURENCES,     "Number of calls to IOMR3MMIOHandler.");
206
 
        STAM_REG(pVM, &pVM->iom.s.StatInstIn,             STAMTYPE_COUNTER, "/IOM/IOWork/In",                           STAMUNIT_OCCURENCES,     "Counter of any IN instructions.");
207
 
        STAM_REG(pVM, &pVM->iom.s.StatInstOut,            STAMTYPE_COUNTER, "/IOM/IOWork/Out",                          STAMUNIT_OCCURENCES,     "Counter of any OUT instructions.");
208
 
        STAM_REG(pVM, &pVM->iom.s.StatInstIns,            STAMTYPE_COUNTER, "/IOM/IOWork/Ins",                          STAMUNIT_OCCURENCES,     "Counter of any INS instructions.");
209
 
        STAM_REG(pVM, &pVM->iom.s.StatInstOuts,           STAMTYPE_COUNTER, "/IOM/IOWork/Outs",                         STAMUNIT_OCCURENCES,     "Counter of any OUTS instructions.");
210
 
    }
211
 
 
212
 
    /* Redundant, but just in case we change something in the future */
213
 
    iomR3FlushCache(pVM);
214
 
 
215
 
    LogFlow(("IOMR3Init: returns %Rrc\n", rc));
216
 
    return rc;
217
 
}
218
 
 
219
 
 
220
 
/**
221
 
 * Flushes the IOM port & statistics lookup cache
222
 
 *
223
 
 * @param   pVM     The VM.
224
 
 */
225
 
static void iomR3FlushCache(PVM pVM)
226
 
{
227
 
    iomLock(pVM);
228
 
    /*
229
 
     * Caching of port and statistics (saves some time in rep outs/ins instruction emulation)
230
 
     */
231
 
    pVM->iom.s.pRangeLastReadR0  = NIL_RTR0PTR;
232
 
    pVM->iom.s.pRangeLastWriteR0 = NIL_RTR0PTR;
233
 
    pVM->iom.s.pStatsLastReadR0  = NIL_RTR0PTR;
234
 
    pVM->iom.s.pStatsLastWriteR0 = NIL_RTR0PTR;
235
 
    pVM->iom.s.pMMIORangeLastR0  = NIL_RTR0PTR;
236
 
    pVM->iom.s.pMMIOStatsLastR0  = NIL_RTR0PTR;
237
 
 
238
 
    pVM->iom.s.pRangeLastReadR3  = NULL;
239
 
    pVM->iom.s.pRangeLastWriteR3 = NULL;
240
 
    pVM->iom.s.pStatsLastReadR3  = NULL;
241
 
    pVM->iom.s.pStatsLastWriteR3 = NULL;
242
 
    pVM->iom.s.pMMIORangeLastR3  = NULL;
243
 
    pVM->iom.s.pMMIOStatsLastR3  = NULL;
244
 
 
245
 
    pVM->iom.s.pRangeLastReadRC  = NIL_RTRCPTR;
246
 
    pVM->iom.s.pRangeLastWriteRC = NIL_RTRCPTR;
247
 
    pVM->iom.s.pStatsLastReadRC  = NIL_RTRCPTR;
248
 
    pVM->iom.s.pStatsLastWriteRC = NIL_RTRCPTR;
249
 
    pVM->iom.s.pMMIORangeLastRC  = NIL_RTRCPTR;
250
 
    pVM->iom.s.pMMIOStatsLastRC  = NIL_RTRCPTR;
251
 
 
252
 
    iomUnlock(pVM);
253
 
}
254
 
 
255
 
 
256
 
/**
257
 
 * The VM is being reset.
258
 
 *
259
 
 * @param   pVM     VM handle.
260
 
 */
261
 
VMMR3DECL(void) IOMR3Reset(PVM pVM)
262
 
{
263
 
    iomR3FlushCache(pVM);
264
 
}
265
 
 
266
 
 
267
 
/**
268
 
 * Applies relocations to data and code managed by this
269
 
 * component. This function will be called at init and
270
 
 * whenever the VMM need to relocate it self inside the GC.
271
 
 *
272
 
 * The IOM will update the addresses used by the switcher.
273
 
 *
274
 
 * @param   pVM     The VM.
275
 
 * @param   offDelta    Relocation delta relative to old location.
276
 
 */
277
 
VMMR3DECL(void) IOMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
278
 
{
279
 
    LogFlow(("IOMR3Relocate: offDelta=%d\n", offDelta));
280
 
 
281
 
    /*
282
 
     * Apply relocations to the GC callbacks.
283
 
     */
284
 
    pVM->iom.s.pTreesRC = MMHyperR3ToRC(pVM, pVM->iom.s.pTreesR3);
285
 
    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeRC, true, iomR3RelocateIOPortCallback, &offDelta);
286
 
    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesR3->MMIOTree,     true, iomR3RelocateMMIOCallback,   &offDelta);
287
 
 
288
 
    if (pVM->iom.s.pfnMMIOHandlerRC)
289
 
        pVM->iom.s.pfnMMIOHandlerRC += offDelta;
290
 
 
291
 
    /*
292
 
     * Apply relocations to the cached GC handlers
293
 
     */
294
 
    if (pVM->iom.s.pRangeLastReadRC)
295
 
        pVM->iom.s.pRangeLastReadRC  += offDelta;
296
 
    if (pVM->iom.s.pRangeLastWriteRC)
297
 
        pVM->iom.s.pRangeLastWriteRC += offDelta;
298
 
    if (pVM->iom.s.pStatsLastReadRC)
299
 
        pVM->iom.s.pStatsLastReadRC  += offDelta;
300
 
    if (pVM->iom.s.pStatsLastWriteRC)
301
 
        pVM->iom.s.pStatsLastWriteRC += offDelta;
302
 
    if (pVM->iom.s.pMMIORangeLastRC)
303
 
        pVM->iom.s.pMMIORangeLastRC  += offDelta;
304
 
    if (pVM->iom.s.pMMIOStatsLastRC)
305
 
        pVM->iom.s.pMMIOStatsLastRC  += offDelta;
306
 
}
307
 
 
308
 
 
309
 
/**
310
 
 * Callback function for relocating a I/O port range.
311
 
 *
312
 
 * @returns 0 (continue enum)
313
 
 * @param   pNode       Pointer to a IOMIOPORTRANGERC node.
314
 
 * @param   pvUser      Pointer to the offDelta. This is a pointer to the delta since we're
315
 
 *                      not certain the delta will fit in a void pointer for all possible configs.
316
 
 */
317
 
static DECLCALLBACK(int) iomR3RelocateIOPortCallback(PAVLROIOPORTNODECORE pNode, void *pvUser)
318
 
{
319
 
    PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode;
320
 
    RTGCINTPTR      offDelta = *(PRTGCINTPTR)pvUser;
321
 
 
322
 
    Assert(pRange->pDevIns);
323
 
    pRange->pDevIns                 += offDelta;
324
 
    if (pRange->pfnOutCallback)
325
 
        pRange->pfnOutCallback      += offDelta;
326
 
    if (pRange->pfnInCallback)
327
 
        pRange->pfnInCallback       += offDelta;
328
 
    if (pRange->pfnOutStrCallback)
329
 
        pRange->pfnOutStrCallback   += offDelta;
330
 
    if (pRange->pfnInStrCallback)
331
 
        pRange->pfnInStrCallback    += offDelta;
332
 
    if (pRange->pvUser > _64K)
333
 
        pRange->pvUser              += offDelta;
334
 
    return 0;
335
 
}
336
 
 
337
 
 
338
 
/**
339
 
 * Callback function for relocating a MMIO range.
340
 
 *
341
 
 * @returns 0 (continue enum)
342
 
 * @param   pNode       Pointer to a IOMMMIORANGE node.
343
 
 * @param   pvUser      Pointer to the offDelta. This is a pointer to the delta since we're
344
 
 *                      not certain the delta will fit in a void pointer for all possible configs.
345
 
 */
346
 
static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser)
347
 
{
348
 
    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;
349
 
    RTGCINTPTR    offDelta = *(PRTGCINTPTR)pvUser;
350
 
 
351
 
    if (pRange->pDevInsRC)
352
 
        pRange->pDevInsRC           += offDelta;
353
 
    if (pRange->pfnWriteCallbackRC)
354
 
        pRange->pfnWriteCallbackRC  += offDelta;
355
 
    if (pRange->pfnReadCallbackRC)
356
 
        pRange->pfnReadCallbackRC   += offDelta;
357
 
    if (pRange->pfnFillCallbackRC)
358
 
        pRange->pfnFillCallbackRC   += offDelta;
359
 
    if (pRange->pvUserRC > _64K)
360
 
        pRange->pvUserRC            += offDelta;
361
 
 
362
 
    return 0;
363
 
}
364
 
 
365
 
 
366
 
/**
367
 
 * Terminates the IOM.
368
 
 *
369
 
 * Termination means cleaning up and freeing all resources,
370
 
 * the VM it self is at this point powered off or suspended.
371
 
 *
372
 
 * @returns VBox status code.
373
 
 * @param   pVM         The VM to operate on.
374
 
 */
375
 
VMMR3DECL(int) IOMR3Term(PVM pVM)
376
 
{
377
 
    /*
378
 
     * IOM is not owning anything but automatically freed resources,
379
 
     * so there's nothing to do here.
380
 
     */
381
 
    return VINF_SUCCESS;
382
 
}
383
 
 
384
 
#ifdef VBOX_WITH_STATISTICS
385
 
 
386
 
/**
387
 
 * Create the statistics node for an I/O port.
388
 
 *
389
 
 * @returns Pointer to new stats node.
390
 
 *
391
 
 * @param   pVM         VM handle.
392
 
 * @param   Port        Port.
393
 
 * @param   pszDesc     Description.
394
 
 */
395
 
PIOMIOPORTSTATS iomR3IOPortStatsCreate(PVM pVM, RTIOPORT Port, const char *pszDesc)
396
 
{
397
 
    Assert(IOMIsLockOwner(pVM));
398
 
    /* check if it already exists. */
399
 
    PIOMIOPORTSTATS pPort = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.pTreesR3->IOPortStatTree, Port);
400
 
    if (pPort)
401
 
        return pPort;
402
 
 
403
 
    /* allocate stats node. */
404
 
    int rc = MMHyperAlloc(pVM, sizeof(*pPort), 0, MM_TAG_IOM_STATS, (void **)&pPort);
405
 
    AssertRC(rc);
406
 
    if (RT_SUCCESS(rc))
407
 
    {
408
 
        /* insert into the tree. */
409
 
        pPort->Core.Key = Port;
410
 
        if (RTAvloIOPortInsert(&pVM->iom.s.pTreesR3->IOPortStatTree, &pPort->Core))
411
 
        {
412
 
            /* put a name on common ports. */
413
 
            if (!pszDesc)
414
 
                pszDesc = iomR3IOPortGetStandardName(Port);
415
 
 
416
 
            /* register the statistics counters. */
417
 
            rc = STAMR3RegisterF(pVM, &pPort->InR3,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc,    "/IOM/Ports/%04x-In-R3", Port); AssertRC(rc);
418
 
            rc = STAMR3RegisterF(pVM, &pPort->OutR3,    STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc,    "/IOM/Ports/%04x-Out-R3", Port); AssertRC(rc);
419
 
            rc = STAMR3RegisterF(pVM, &pPort->InRZ,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc,    "/IOM/Ports/%04x-In-RZ", Port); AssertRC(rc);
420
 
            rc = STAMR3RegisterF(pVM, &pPort->OutRZ,    STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc,    "/IOM/Ports/%04x-Out-RZ", Port); AssertRC(rc);
421
 
            rc = STAMR3RegisterF(pVM, &pPort->InRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc,    "/IOM/Ports/%04x-In-RZtoR3", Port); AssertRC(rc);
422
 
            rc = STAMR3RegisterF(pVM, &pPort->OutRZToR3,STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc,    "/IOM/Ports/%04x-Out-RZtoR3", Port); AssertRC(rc);
423
 
 
424
 
            /* Profiling */
425
 
            rc = STAMR3RegisterF(pVM, &pPort->ProfInR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-In-R3/Prof", Port); AssertRC(rc);
426
 
            rc = STAMR3RegisterF(pVM, &pPort->ProfOutR3,STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-Out-R3/Prof", Port); AssertRC(rc);
427
 
            rc = STAMR3RegisterF(pVM, &pPort->ProfInRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-In-RZ/Prof", Port); AssertRC(rc);
428
 
            rc = STAMR3RegisterF(pVM, &pPort->ProfOutRZ,STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,"/IOM/Ports/%04x-Out-RZ/Prof", Port); AssertRC(rc);
429
 
 
430
 
            return pPort;
431
 
        }
432
 
        AssertMsgFailed(("what! Port=%d\n", Port));
433
 
        MMHyperFree(pVM, pPort);
434
 
    }
435
 
    return NULL;
436
 
}
437
 
 
438
 
 
439
 
/**
440
 
 * Create the statistics node for an MMIO address.
441
 
 *
442
 
 * @returns Pointer to new stats node.
443
 
 *
444
 
 * @param   pVM         VM handle.
445
 
 * @param   GCPhys      The address.
446
 
 * @param   pszDesc     Description.
447
 
 */
448
 
PIOMMMIOSTATS iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc)
449
 
{
450
 
    Assert(IOMIsLockOwner(pVM));
451
 
#ifdef DEBUG_sandervl
452
 
    AssertGCPhys32(GCPhys);
453
 
#endif
454
 
    /* check if it already exists. */
455
 
    PIOMMMIOSTATS pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pVM->iom.s.pTreesR3->MMIOStatTree, GCPhys);
456
 
    if (pStats)
457
 
        return pStats;
458
 
 
459
 
    /* allocate stats node. */
460
 
    int rc = MMHyperAlloc(pVM, sizeof(*pStats), 0, MM_TAG_IOM_STATS, (void **)&pStats);
461
 
    AssertRC(rc);
462
 
    if (RT_SUCCESS(rc))
463
 
    {
464
 
        /* insert into the tree. */
465
 
        pStats->Core.Key = GCPhys;
466
 
        if (RTAvloGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOStatTree, &pStats->Core))
467
 
        {
468
 
            rc = STAMR3RegisterF(pVM, &pStats->Accesses,    STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,     pszDesc, "/IOM/MMIO/%RGp",              GCPhys); AssertRC(rc);
469
 
            rc = STAMR3RegisterF(pVM, &pStats->ProfReadR3,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Read-R3",      GCPhys); AssertRC(rc);
470
 
            rc = STAMR3RegisterF(pVM, &pStats->ProfWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Write-R3",     GCPhys); AssertRC(rc);
471
 
            rc = STAMR3RegisterF(pVM, &pStats->ProfReadRZ,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Read-RZ",      GCPhys); AssertRC(rc);
472
 
            rc = STAMR3RegisterF(pVM, &pStats->ProfWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Write-RZ",     GCPhys); AssertRC(rc);
473
 
            rc = STAMR3RegisterF(pVM, &pStats->ReadRZToR3,  STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,     pszDesc, "/IOM/MMIO/%RGp/Read-RZtoR3",  GCPhys); AssertRC(rc);
474
 
            rc = STAMR3RegisterF(pVM, &pStats->WriteRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,     pszDesc, "/IOM/MMIO/%RGp/Write-RZtoR3", GCPhys); AssertRC(rc);
475
 
 
476
 
            return pStats;
477
 
        }
478
 
        AssertMsgFailed(("what! GCPhys=%RGp\n", GCPhys));
479
 
        MMHyperFree(pVM, pStats);
480
 
    }
481
 
    return NULL;
482
 
}
483
 
 
484
 
#endif /* VBOX_WITH_STATISTICS */
485
 
 
486
 
/**
487
 
 * Registers a I/O port ring-3 handler.
488
 
 *
489
 
 * This API is called by PDM on behalf of a device. Devices must first register
490
 
 * ring-3 ranges before any GC and R0 ranges can be registerd using IOMR3IOPortRegisterRC()
491
 
 * and IOMR3IOPortRegisterR0().
492
 
 *
493
 
 *
494
 
 * @returns VBox status code.
495
 
 *
496
 
 * @param   pVM                 VM handle.
497
 
 * @param   pDevIns             PDM device instance owning the port range.
498
 
 * @param   PortStart           First port number in the range.
499
 
 * @param   cPorts              Number of ports to register.
500
 
 * @param   pvUser              User argument for the callbacks.
501
 
 * @param   pfnOutCallback      Pointer to function which is gonna handle OUT operations in R3.
502
 
 * @param   pfnInCallback       Pointer to function which is gonna handle IN operations in R3.
503
 
 * @param   pfnOutStrCallback   Pointer to function which is gonna handle string OUT operations in R3.
504
 
 * @param   pfnInStrCallback    Pointer to function which is gonna handle string IN operations in R3.
505
 
 * @param   pszDesc             Pointer to description string. This must not be freed.
506
 
 */
507
 
VMMR3DECL(int) IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser,
508
 
                                     R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,
509
 
                                     R3PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, R3PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback, const char *pszDesc)
510
 
{
511
 
    LogFlow(("IOMR3IOPortRegisterR3: pDevIns=%p PortStart=%#x cPorts=%#x pvUser=%RHv pfnOutCallback=%#x pfnInCallback=%#x pfnOutStrCallback=%#x pfnInStrCallback=%#x pszDesc=%s\n",
512
 
             pDevIns, PortStart, cPorts, pvUser, pfnOutCallback, pfnInCallback, pfnOutStrCallback, pfnInStrCallback, pszDesc));
513
 
 
514
 
    /*
515
 
     * Validate input.
516
 
     */
517
 
    if (    (RTUINT)PortStart + cPorts <= (RTUINT)PortStart
518
 
        ||  (RTUINT)PortStart + cPorts > 0x10000)
519
 
    {
520
 
        AssertMsgFailed(("Invalid port range %#x-%#x (inclusive)! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
521
 
        return VERR_IOM_INVALID_IOPORT_RANGE;
522
 
    }
523
 
    if (!pfnOutCallback && !pfnInCallback)
524
 
    {
525
 
        AssertMsgFailed(("no handlers specfied for %#x-%#x (inclusive)! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
526
 
        return VERR_INVALID_PARAMETER;
527
 
    }
528
 
    if (!pfnOutCallback)
529
 
        pfnOutCallback = iomR3IOPortDummyOut;
530
 
    if (!pfnInCallback)
531
 
        pfnInCallback = iomR3IOPortDummyIn;
532
 
    if (!pfnOutStrCallback)
533
 
        pfnOutStrCallback = iomR3IOPortDummyOutStr;
534
 
    if (!pfnInStrCallback)
535
 
        pfnInStrCallback = iomR3IOPortDummyInStr;
536
 
 
537
 
    /* Flush the IO port lookup cache */
538
 
    iomR3FlushCache(pVM);
539
 
 
540
 
    /*
541
 
     * Allocate new range record and initialize it.
542
 
     */
543
 
    PIOMIOPORTRANGER3 pRange;
544
 
    int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
545
 
    if (RT_SUCCESS(rc))
546
 
    {
547
 
        pRange->Core.Key        = PortStart;
548
 
        pRange->Core.KeyLast    = PortStart + (cPorts - 1);
549
 
        pRange->Port            = PortStart;
550
 
        pRange->cPorts          = cPorts;
551
 
        pRange->pvUser          = pvUser;
552
 
        pRange->pDevIns         = pDevIns;
553
 
        pRange->pfnOutCallback  = pfnOutCallback;
554
 
        pRange->pfnInCallback   = pfnInCallback;
555
 
        pRange->pfnOutStrCallback = pfnOutStrCallback;
556
 
        pRange->pfnInStrCallback = pfnInStrCallback;
557
 
        pRange->pszDesc         = pszDesc;
558
 
 
559
 
        /*
560
 
         * Try Insert it.
561
 
         */
562
 
        iomLock(pVM);
563
 
        if (RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR3, &pRange->Core))
564
 
        {
565
 
            #ifdef VBOX_WITH_STATISTICS
566
 
            for (unsigned iPort = 0; iPort < cPorts; iPort++)
567
 
                iomR3IOPortStatsCreate(pVM, PortStart + iPort, pszDesc);
568
 
            #endif
569
 
            iomUnlock(pVM);
570
 
            return VINF_SUCCESS;
571
 
        }
572
 
        iomUnlock(pVM);
573
 
 
574
 
        /* conflict. */
575
 
        DBGFR3Info(pVM, "ioport", NULL, NULL);
576
 
        AssertMsgFailed(("Port range %#x-%#x (%s) conflicts with existing range(s)!\n", PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
577
 
        MMHyperFree(pVM, pRange);
578
 
        rc = VERR_IOM_IOPORT_RANGE_CONFLICT;
579
 
    }
580
 
 
581
 
    return rc;
582
 
}
583
 
 
584
 
 
585
 
/**
586
 
 * Registers a I/O port RC handler.
587
 
 *
588
 
 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges
589
 
 * using IOMIOPortRegisterR3() before calling this function.
590
 
 *
591
 
 *
592
 
 * @returns VBox status code.
593
 
 *
594
 
 * @param   pVM                 VM handle.
595
 
 * @param   pDevIns             PDM device instance owning the port range.
596
 
 * @param   PortStart           First port number in the range.
597
 
 * @param   cPorts              Number of ports to register.
598
 
 * @param   pvUser              User argument for the callbacks.
599
 
 * @param   pfnOutCallback      Pointer to function which is gonna handle OUT operations in GC.
600
 
 * @param   pfnInCallback       Pointer to function which is gonna handle IN operations in GC.
601
 
 * @param   pfnOutStrCallback   Pointer to function which is gonna handle string OUT operations in GC.
602
 
 * @param   pfnInStrCallback    Pointer to function which is gonna handle string IN operations in GC.
603
 
 * @param   pszDesc             Pointer to description string. This must not be freed.
604
 
 */
605
 
VMMR3DECL(int)  IOMR3IOPortRegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTRCPTR pvUser,
606
 
                                      RCPTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, RCPTRTYPE(PFNIOMIOPORTIN) pfnInCallback,
607
 
                                      RCPTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, RCPTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback, const char *pszDesc)
608
 
{
609
 
    LogFlow(("IOMR3IOPortRegisterRC: pDevIns=%p PortStart=%#x cPorts=%#x pvUser=%RRv pfnOutCallback=%RRv pfnInCallback=%RRv pfnOutStrCallback=%RRv  pfnInStrCallback=%RRv pszDesc=%s\n",
610
 
             pDevIns, PortStart, cPorts, pvUser, pfnOutCallback, pfnInCallback, pfnOutStrCallback, pfnInStrCallback, pszDesc));
611
 
 
612
 
    /*
613
 
     * Validate input.
614
 
     */
615
 
    if (    (RTUINT)PortStart + cPorts <= (RTUINT)PortStart
616
 
        ||  (RTUINT)PortStart + cPorts > 0x10000)
617
 
    {
618
 
        AssertMsgFailed(("Invalid port range %#x-%#x! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
619
 
        return VERR_IOM_INVALID_IOPORT_RANGE;
620
 
    }
621
 
    RTIOPORT PortLast = PortStart + (cPorts - 1);
622
 
    if (!pfnOutCallback && !pfnInCallback)
623
 
    {
624
 
        AssertMsgFailed(("Invalid port range %#x-%#x! No callbacks! (%s)\n", PortStart, PortLast, pszDesc));
625
 
        return VERR_INVALID_PARAMETER;
626
 
    }
627
 
 
628
 
    iomLock(pVM);
629
 
 
630
 
    /*
631
 
     * Validate that there are ring-3 ranges for the ports.
632
 
     */
633
 
    RTIOPORT Port = PortStart;
634
 
    while (Port <= PortLast && Port >= PortStart)
635
 
    {
636
 
        PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);
637
 
        if (!pRange)
638
 
        {
639
 
            AssertMsgFailed(("No R3! Port=#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
640
 
            iomUnlock(pVM);
641
 
            return VERR_IOM_NO_HC_IOPORT_RANGE;
642
 
        }
643
 
#ifndef IOM_NO_PDMINS_CHECKS
644
 
# ifndef IN_RC
645
 
        if (pRange->pDevIns != pDevIns)
646
 
# else
647
 
        if (pRange->pDevIns != MMHyperRCToCC(pVM, pDevIns))
648
 
# endif
649
 
        {
650
 
            AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
651
 
            iomUnlock(pVM);
652
 
            return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
653
 
        }
654
 
#endif
655
 
        Port = pRange->Core.KeyLast + 1;
656
 
    }
657
 
 
658
 
    /* Flush the IO port lookup cache */
659
 
    iomR3FlushCache(pVM);
660
 
 
661
 
    /*
662
 
     * Allocate new range record and initialize it.
663
 
     */
664
 
    PIOMIOPORTRANGERC pRange;
665
 
    int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
666
 
    if (RT_SUCCESS(rc))
667
 
    {
668
 
        pRange->Core.Key        = PortStart;
669
 
        pRange->Core.KeyLast    = PortLast;
670
 
        pRange->Port            = PortStart;
671
 
        pRange->cPorts          = cPorts;
672
 
        pRange->pvUser          = pvUser;
673
 
        pRange->pfnOutCallback  = pfnOutCallback;
674
 
        pRange->pfnInCallback   = pfnInCallback;
675
 
        pRange->pfnOutStrCallback = pfnOutStrCallback;
676
 
        pRange->pfnInStrCallback = pfnInStrCallback;
677
 
        pRange->pDevIns         = MMHyperCCToRC(pVM, pDevIns);
678
 
        pRange->pszDesc         = pszDesc;
679
 
 
680
 
        /*
681
 
         * Insert it.
682
 
         */
683
 
        if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeRC, &pRange->Core))
684
 
        {
685
 
            iomUnlock(pVM);
686
 
            return VINF_SUCCESS;
687
 
        }
688
 
 
689
 
        /* conflict. */
690
 
        AssertMsgFailed(("Port range %#x-%#x (%s) conflicts with existing range(s)!\n", PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
691
 
        MMHyperFree(pVM, pRange);
692
 
        rc = VERR_IOM_IOPORT_RANGE_CONFLICT;
693
 
    }
694
 
    iomUnlock(pVM);
695
 
    return rc;
696
 
}
697
 
 
698
 
 
699
 
/**
700
 
 * Registers a Port IO R0 handler.
701
 
 *
702
 
 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges
703
 
 * using IOMR3IOPortRegisterR3() before calling this function.
704
 
 *
705
 
 *
706
 
 * @returns VBox status code.
707
 
 *
708
 
 * @param   pVM                 VM handle.
709
 
 * @param   pDevIns             PDM device instance owning the port range.
710
 
 * @param   PortStart           First port number in the range.
711
 
 * @param   cPorts              Number of ports to register.
712
 
 * @param   pvUser              User argument for the callbacks.
713
 
 * @param   pfnOutCallback      Pointer to function which is gonna handle OUT operations in GC.
714
 
 * @param   pfnInCallback       Pointer to function which is gonna handle IN operations in GC.
715
 
 * @param   pfnOutStrCallback   Pointer to function which is gonna handle OUT operations in GC.
716
 
 * @param   pfnInStrCallback    Pointer to function which is gonna handle IN operations in GC.
717
 
 * @param   pszDesc             Pointer to description string. This must not be freed.
718
 
 */
719
 
VMMR3DECL(int)  IOMR3IOPortRegisterR0(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTR0PTR pvUser,
720
 
                                      R0PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R0PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,
721
 
                                      R0PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, R0PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback,
722
 
                                      const char *pszDesc)
723
 
{
724
 
    LogFlow(("IOMR3IOPortRegisterR0: pDevIns=%p PortStart=%#x cPorts=%#x pvUser=%RHv pfnOutCallback=%RHv pfnInCallback=%RHv pfnOutStrCallback=%RHv  pfnInStrCallback=%RHv pszDesc=%s\n",
725
 
             pDevIns, PortStart, cPorts, pvUser, pfnOutCallback, pfnInCallback, pfnOutStrCallback, pfnInStrCallback, pszDesc));
726
 
 
727
 
    /*
728
 
     * Validate input.
729
 
     */
730
 
    if (    (RTUINT)PortStart + cPorts <= (RTUINT)PortStart
731
 
        ||  (RTUINT)PortStart + cPorts > 0x10000)
732
 
    {
733
 
        AssertMsgFailed(("Invalid port range %#x-%#x! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
734
 
        return VERR_IOM_INVALID_IOPORT_RANGE;
735
 
    }
736
 
    RTIOPORT PortLast = PortStart + (cPorts - 1);
737
 
    if (!pfnOutCallback && !pfnInCallback)
738
 
    {
739
 
        AssertMsgFailed(("Invalid port range %#x-%#x! No callbacks! (%s)\n", PortStart, PortLast, pszDesc));
740
 
        return VERR_INVALID_PARAMETER;
741
 
    }
742
 
 
743
 
    iomLock(pVM);
744
 
    /*
745
 
     * Validate that there are ring-3 ranges for the ports.
746
 
     */
747
 
    RTIOPORT Port = PortStart;
748
 
    while (Port <= PortLast && Port >= PortStart)
749
 
    {
750
 
        PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);
751
 
        if (!pRange)
752
 
        {
753
 
            AssertMsgFailed(("No R3! Port=#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
754
 
            iomUnlock(pVM);
755
 
            return VERR_IOM_NO_HC_IOPORT_RANGE;
756
 
        }
757
 
#ifndef IOM_NO_PDMINS_CHECKS
758
 
# ifndef IN_RC
759
 
        if (pRange->pDevIns != pDevIns)
760
 
# else
761
 
        if (pRange->pDevIns != MMHyperRCToCC(pVM, pDevIns))
762
 
# endif
763
 
        {
764
 
            AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
765
 
            iomUnlock(pVM);
766
 
            return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
767
 
        }
768
 
#endif
769
 
        Port = pRange->Core.KeyLast + 1;
770
 
    }
771
 
 
772
 
    /* Flush the IO port lookup cache */
773
 
    iomR3FlushCache(pVM);
774
 
 
775
 
    /*
776
 
     * Allocate new range record and initialize it.
777
 
     */
778
 
    PIOMIOPORTRANGER0 pRange;
779
 
    int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
780
 
    if (RT_SUCCESS(rc))
781
 
    {
782
 
        pRange->Core.Key        = PortStart;
783
 
        pRange->Core.KeyLast    = PortLast;
784
 
        pRange->Port            = PortStart;
785
 
        pRange->cPorts          = cPorts;
786
 
        pRange->pvUser          = pvUser;
787
 
        pRange->pfnOutCallback  = pfnOutCallback;
788
 
        pRange->pfnInCallback   = pfnInCallback;
789
 
        pRange->pfnOutStrCallback = pfnOutStrCallback;
790
 
        pRange->pfnInStrCallback = pfnInStrCallback;
791
 
        pRange->pDevIns         = MMHyperR3ToR0(pVM, pDevIns);
792
 
        pRange->pszDesc         = pszDesc;
793
 
 
794
 
        /*
795
 
         * Insert it.
796
 
         */
797
 
        if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR0, &pRange->Core))
798
 
        {
799
 
            iomUnlock(pVM);
800
 
            return VINF_SUCCESS;
801
 
        }
802
 
 
803
 
        /* conflict. */
804
 
        AssertMsgFailed(("Port range %#x-%#x (%s) conflicts with existing range(s)!\n", PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
805
 
        MMHyperFree(pVM, pRange);
806
 
        rc = VERR_IOM_IOPORT_RANGE_CONFLICT;
807
 
    }
808
 
    iomUnlock(pVM);
809
 
    return rc;
810
 
}
811
 
 
812
 
 
813
 
/**
814
 
 * Deregisters a I/O Port range.
815
 
 *
816
 
 * The specified range must be registered using IOMR3IOPortRegister previous to
817
 
 * this call. The range does can be a smaller part of the range specified to
818
 
 * IOMR3IOPortRegister, but it can never be larger.
819
 
 *
820
 
 * This function will remove GC, R0 and R3 context port handlers for this range.
821
 
 *
822
 
 * @returns VBox status code.
823
 
 *
824
 
 * @param   pVM                 The virtual machine.
825
 
 * @param   pDevIns             The device instance associated with the range.
826
 
 * @param   PortStart           First port number in the range.
827
 
 * @param   cPorts              Number of ports to remove starting at PortStart.
828
 
 *
829
 
 * @remark  This function mainly for PCI PnP Config and will not do
830
 
 *          all the checks you might expect it to do.
831
 
 */
832
 
VMMR3DECL(int)  IOMR3IOPortDeregister(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts)
833
 
{
834
 
    LogFlow(("IOMR3IOPortDeregister: pDevIns=%p PortStart=%#x cPorts=%#x\n", pDevIns, PortStart, cPorts));
835
 
 
836
 
    /*
837
 
     * Validate input.
838
 
     */
839
 
    if (    (RTUINT)PortStart + cPorts < (RTUINT)PortStart
840
 
        ||  (RTUINT)PortStart + cPorts > 0x10000)
841
 
    {
842
 
        AssertMsgFailed(("Invalid port range %#x-%#x!\n", PortStart, (unsigned)PortStart + cPorts - 1));
843
 
        return VERR_IOM_INVALID_IOPORT_RANGE;
844
 
    }
845
 
 
846
 
    iomLock(pVM);
847
 
 
848
 
    /* Flush the IO port lookup cache */
849
 
    iomR3FlushCache(pVM);
850
 
 
851
 
    /*
852
 
     * Check ownership.
853
 
     */
854
 
    RTIOPORT PortLast = PortStart + (cPorts - 1);
855
 
    RTIOPORT Port = PortStart;
856
 
    while (Port <= PortLast && Port >= PortStart)
857
 
    {
858
 
        PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);
859
 
        if (pRange)
860
 
        {
861
 
            Assert(Port <= pRange->Core.KeyLast);
862
 
#ifndef IOM_NO_PDMINS_CHECKS
863
 
            if (pRange->pDevIns != pDevIns)
864
 
            {
865
 
                AssertMsgFailed(("Removal of ports in range %#x-%#x rejected because not owner of %#x-%#x (%s)\n",
866
 
                                 PortStart, PortLast, pRange->Core.Key, pRange->Core.KeyLast, pRange->pszDesc));
867
 
                iomUnlock(pVM);
868
 
                return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
869
 
            }
870
 
#endif /* !IOM_NO_PDMINS_CHECKS */
871
 
            Port = pRange->Core.KeyLast;
872
 
        }
873
 
        Port++;
874
 
    }
875
 
 
876
 
    /*
877
 
     * Remove any RC ranges first.
878
 
     */
879
 
    int     rc = VINF_SUCCESS;
880
 
    Port = PortStart;
881
 
    while (Port <= PortLast && Port >= PortStart)
882
 
    {
883
 
        /*
884
 
         * Try find range.
885
 
         */
886
 
        PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeRC, Port);
887
 
        if (pRange)
888
 
        {
889
 
            if (   pRange->Core.Key     == Port
890
 
                && pRange->Core.KeyLast <= PortLast)
891
 
            {
892
 
                /*
893
 
                 * Kick out the entire range.
894
 
                 */
895
 
                void *pv = RTAvlroIOPortRemove(&pVM->iom.s.pTreesR3->IOPortTreeRC, Port);
896
 
                Assert(pv == (void *)pRange); NOREF(pv);
897
 
                Port += pRange->cPorts;
898
 
                MMHyperFree(pVM, pRange);
899
 
            }
900
 
            else if (pRange->Core.Key == Port)
901
 
            {
902
 
                /*
903
 
                 * Cut of the head of the range, done.
904
 
                 */
905
 
                pRange->cPorts  -= Port - pRange->Port;
906
 
                pRange->Core.Key = Port;
907
 
                pRange->Port     = Port;
908
 
                break;
909
 
            }
910
 
            else if (pRange->Core.KeyLast <= PortLast)
911
 
            {
912
 
                /*
913
 
                 * Just cut of the tail.
914
 
                 */
915
 
                unsigned c = pRange->Core.KeyLast - Port + 1;
916
 
                pRange->Core.KeyLast -= c;
917
 
                pRange->cPorts -= c;
918
 
                Port += c;
919
 
            }
920
 
            else
921
 
            {
922
 
                /*
923
 
                 * Split the range, done.
924
 
                 */
925
 
                Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);
926
 
                /* create tail. */
927
 
                PIOMIOPORTRANGERC pRangeNew;
928
 
                int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);
929
 
                if (RT_FAILURE(rc2))
930
 
                {
931
 
                    iomUnlock(pVM);
932
 
                    return rc2;
933
 
                }
934
 
                *pRangeNew = *pRange;
935
 
                pRangeNew->Core.Key     = PortLast;
936
 
                pRangeNew->Port         = PortLast;
937
 
                pRangeNew->cPorts       = pRangeNew->Core.KeyLast - PortLast + 1;
938
 
 
939
 
                LogFlow(("IOMR3IOPortDeregister (rc): split the range; new %x\n", pRangeNew->Core.Key));
940
 
 
941
 
                /* adjust head */
942
 
                pRange->Core.KeyLast  = Port - 1;
943
 
                pRange->cPorts        = Port - pRange->Port;
944
 
 
945
 
                /* insert */
946
 
                if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeRC, &pRangeNew->Core))
947
 
                {
948
 
                    AssertMsgFailed(("This cannot happen!\n"));
949
 
                    MMHyperFree(pVM, pRangeNew);
950
 
                    rc = VERR_INTERNAL_ERROR;
951
 
                }
952
 
                break;
953
 
            }
954
 
        }
955
 
        else /* next port */
956
 
            Port++;
957
 
    } /* for all ports - RC. */
958
 
 
959
 
 
960
 
    /*
961
 
     * Remove any R0 ranges.
962
 
     */
963
 
    Port = PortStart;
964
 
    while (Port <= PortLast && Port >= PortStart)
965
 
    {
966
 
        /*
967
 
         * Try find range.
968
 
         */
969
 
        PIOMIOPORTRANGER0 pRange = (PIOMIOPORTRANGER0)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR0, Port);
970
 
        if (pRange)
971
 
        {
972
 
            if (   pRange->Core.Key     == Port
973
 
                && pRange->Core.KeyLast <= PortLast)
974
 
            {
975
 
                /*
976
 
                 * Kick out the entire range.
977
 
                 */
978
 
                void *pv = RTAvlroIOPortRemove(&pVM->iom.s.pTreesR3->IOPortTreeR0, Port);
979
 
                Assert(pv == (void *)pRange); NOREF(pv);
980
 
                Port += pRange->cPorts;
981
 
                MMHyperFree(pVM, pRange);
982
 
            }
983
 
            else if (pRange->Core.Key == Port)
984
 
            {
985
 
                /*
986
 
                 * Cut of the head of the range, done.
987
 
                 */
988
 
                pRange->cPorts  -= Port - pRange->Port;
989
 
                pRange->Core.Key = Port;
990
 
                pRange->Port     = Port;
991
 
                break;
992
 
            }
993
 
            else if (pRange->Core.KeyLast <= PortLast)
994
 
            {
995
 
                /*
996
 
                 * Just cut of the tail.
997
 
                 */
998
 
                unsigned c = pRange->Core.KeyLast - Port + 1;
999
 
                pRange->Core.KeyLast -= c;
1000
 
                pRange->cPorts -= c;
1001
 
                Port += c;
1002
 
            }
1003
 
            else
1004
 
            {
1005
 
                /*
1006
 
                 * Split the range, done.
1007
 
                 */
1008
 
                Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);
1009
 
                /* create tail. */
1010
 
                PIOMIOPORTRANGER0 pRangeNew;
1011
 
                int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);
1012
 
                if (RT_FAILURE(rc2))
1013
 
                {
1014
 
                    iomUnlock(pVM);
1015
 
                    return rc2;
1016
 
                }
1017
 
                *pRangeNew = *pRange;
1018
 
                pRangeNew->Core.Key     = PortLast;
1019
 
                pRangeNew->Port         = PortLast;
1020
 
                pRangeNew->cPorts       = pRangeNew->Core.KeyLast - PortLast + 1;
1021
 
 
1022
 
                LogFlow(("IOMR3IOPortDeregister (r0): split the range; new %x\n", pRangeNew->Core.Key));
1023
 
 
1024
 
                /* adjust head */
1025
 
                pRange->Core.KeyLast  = Port - 1;
1026
 
                pRange->cPorts        = Port - pRange->Port;
1027
 
 
1028
 
                /* insert */
1029
 
                if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR0, &pRangeNew->Core))
1030
 
                {
1031
 
                    AssertMsgFailed(("This cannot happen!\n"));
1032
 
                    MMHyperFree(pVM, pRangeNew);
1033
 
                    rc = VERR_INTERNAL_ERROR;
1034
 
                }
1035
 
                break;
1036
 
            }
1037
 
        }
1038
 
        else /* next port */
1039
 
            Port++;
1040
 
    } /* for all ports - R0. */
1041
 
 
1042
 
    /*
1043
 
     * And the same procedure for ring-3 ranges.
1044
 
     */
1045
 
    Port = PortStart;
1046
 
    while (Port <= PortLast && Port >= PortStart)
1047
 
    {
1048
 
        /*
1049
 
         * Try find range.
1050
 
         */
1051
 
        PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);
1052
 
        if (pRange)
1053
 
        {
1054
 
            if (   pRange->Core.Key     == Port
1055
 
                && pRange->Core.KeyLast <= PortLast)
1056
 
            {
1057
 
                /*
1058
 
                 * Kick out the entire range.
1059
 
                 */
1060
 
                void *pv = RTAvlroIOPortRemove(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);
1061
 
                Assert(pv == (void *)pRange); NOREF(pv);
1062
 
                Port += pRange->cPorts;
1063
 
                MMHyperFree(pVM, pRange);
1064
 
            }
1065
 
            else if (pRange->Core.Key == Port)
1066
 
            {
1067
 
                /*
1068
 
                 * Cut of the head of the range, done.
1069
 
                 */
1070
 
                pRange->cPorts  -= Port - pRange->Port;
1071
 
                pRange->Core.Key = Port;
1072
 
                pRange->Port     = Port;
1073
 
                break;
1074
 
            }
1075
 
            else if (pRange->Core.KeyLast <= PortLast)
1076
 
            {
1077
 
                /*
1078
 
                 * Just cut of the tail.
1079
 
                 */
1080
 
                unsigned c = pRange->Core.KeyLast - Port + 1;
1081
 
                pRange->Core.KeyLast -= c;
1082
 
                pRange->cPorts -= c;
1083
 
                Port += c;
1084
 
            }
1085
 
            else
1086
 
            {
1087
 
                /*
1088
 
                 * Split the range, done.
1089
 
                 */
1090
 
                Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);
1091
 
                /* create tail. */
1092
 
                PIOMIOPORTRANGER3 pRangeNew;
1093
 
                int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);
1094
 
                if (RT_FAILURE(rc2))
1095
 
                {
1096
 
                    iomUnlock(pVM);
1097
 
                    return rc2;
1098
 
                }
1099
 
                *pRangeNew = *pRange;
1100
 
                pRangeNew->Core.Key     = PortLast;
1101
 
                pRangeNew->Port         = PortLast;
1102
 
                pRangeNew->cPorts       = pRangeNew->Core.KeyLast - PortLast + 1;
1103
 
 
1104
 
                LogFlow(("IOMR3IOPortDeregister (r3): split the range; new %x\n", pRangeNew->Core.Key));
1105
 
 
1106
 
                /* adjust head */
1107
 
                pRange->Core.KeyLast  = Port - 1;
1108
 
                pRange->cPorts        = Port - pRange->Port;
1109
 
 
1110
 
                /* insert */
1111
 
                if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR3, &pRangeNew->Core))
1112
 
                {
1113
 
                    AssertMsgFailed(("This cannot happen!\n"));
1114
 
                    MMHyperFree(pVM, pRangeNew);
1115
 
                    rc = VERR_INTERNAL_ERROR;
1116
 
                }
1117
 
                break;
1118
 
            }
1119
 
        }
1120
 
        else /* next port */
1121
 
            Port++;
1122
 
    } /* for all ports - ring-3. */
1123
 
 
1124
 
    /* done */
1125
 
    iomUnlock(pVM);
1126
 
    return rc;
1127
 
}
1128
 
 
1129
 
 
1130
 
/**
1131
 
 * Dummy Port I/O Handler for IN operations.
1132
 
 *
1133
 
 * @returns VBox status code.
1134
 
 *
1135
 
 * @param   pDevIns     The device instance.
1136
 
 * @param   pvUser      User argument.
1137
 
 * @param   Port        Port number used for the IN operation.
1138
 
 * @param   pu32        Where to store the result.
1139
 
 * @param   cb          Number of bytes read.
1140
 
 */
1141
 
static DECLCALLBACK(int) iomR3IOPortDummyIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1142
 
{
1143
 
    switch (cb)
1144
 
    {
1145
 
        case 1: *pu32 = 0xff; break;
1146
 
        case 2: *pu32 = 0xffff; break;
1147
 
        case 4: *pu32 = UINT32_C(0xffffffff); break;
1148
 
        default:
1149
 
            AssertReleaseMsgFailed(("cb=%d\n", cb));
1150
 
            return VERR_INTERNAL_ERROR;
1151
 
    }
1152
 
    return VINF_SUCCESS;
1153
 
}
1154
 
 
1155
 
 
1156
 
/**
1157
 
 * Dummy Port I/O Handler for string IN operations.
1158
 
 *
1159
 
 * @returns VBox status code.
1160
 
 *
1161
 
 * @param   pDevIns     The device instance.
1162
 
 * @param   pvUser      User argument.
1163
 
 * @param   Port        Port number used for the string IN operation.
1164
 
 * @param   pGCPtrDst   Pointer to the destination buffer (GC, incremented appropriately).
1165
 
 * @param   pcTransfer  Pointer to the number of transfer units to read, on return remaining transfer units.
1166
 
 * @param   cb          Size of the transfer unit (1, 2 or 4 bytes).
1167
 
 */
1168
 
static DECLCALLBACK(int) iomR3IOPortDummyInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
1169
 
{
1170
 
    return VINF_SUCCESS;
1171
 
}
1172
 
 
1173
 
 
1174
 
/**
1175
 
 * Dummy Port I/O Handler for OUT operations.
1176
 
 *
1177
 
 * @returns VBox status code.
1178
 
 *
1179
 
 * @param   pDevIns     The device instance.
1180
 
 * @param   pvUser      User argument.
1181
 
 * @param   Port        Port number used for the OUT operation.
1182
 
 * @param   u32         The value to output.
1183
 
 * @param   cb          The value size in bytes.
1184
 
 */
1185
 
static DECLCALLBACK(int) iomR3IOPortDummyOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1186
 
{
1187
 
    return VINF_SUCCESS;
1188
 
}
1189
 
 
1190
 
 
1191
 
/**
1192
 
 * Dummy Port I/O Handler for string OUT operations.
1193
 
 *
1194
 
 * @returns VBox status code.
1195
 
 *
1196
 
 * @param   pDevIns     The device instance.
1197
 
 * @param   pvUser      User argument.
1198
 
 * @param   Port        Port number used for the string OUT operation.
1199
 
 * @param   pGCPtrSrc   Pointer to the source buffer (GC, incremented appropriately).
1200
 
 * @param   pcTransfer  Pointer to the number of transfer units to write, on return remaining transfer units.
1201
 
 * @param   cb          Size of the transfer unit (1, 2 or 4 bytes).
1202
 
 */
1203
 
static DECLCALLBACK(int) iomR3IOPortDummyOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
1204
 
{
1205
 
    return VINF_SUCCESS;
1206
 
}
1207
 
 
1208
 
 
1209
 
/**
1210
 
 * Display a single I/O port ring-3 range.
1211
 
 *
1212
 
 * @returns 0
1213
 
 * @param   pNode   Pointer to I/O port HC range.
1214
 
 * @param   pvUser  Pointer to info output callback structure.
1215
 
 */
1216
 
static DECLCALLBACK(int) iomR3IOPortInfoOneR3(PAVLROIOPORTNODECORE pNode, void *pvUser)
1217
 
{
1218
 
    PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)pNode;
1219
 
    PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
1220
 
    pHlp->pfnPrintf(pHlp,
1221
 
                    "%04x-%04x %p %p %p %p %s\n",
1222
 
                    pRange->Core.Key,
1223
 
                    pRange->Core.KeyLast,
1224
 
                    pRange->pDevIns,
1225
 
                    pRange->pfnInCallback,
1226
 
                    pRange->pfnOutCallback,
1227
 
                    pRange->pvUser,
1228
 
                    pRange->pszDesc);
1229
 
    return 0;
1230
 
}
1231
 
 
1232
 
 
1233
 
/**
1234
 
 * Display a single I/O port GC range.
1235
 
 *
1236
 
 * @returns 0
1237
 
 * @param   pNode   Pointer to IOPORT GC range.
1238
 
 * @param   pvUser  Pointer to info output callback structure.
1239
 
 */
1240
 
static DECLCALLBACK(int) iomR3IOPortInfoOneRC(PAVLROIOPORTNODECORE pNode, void *pvUser)
1241
 
{
1242
 
    PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode;
1243
 
    PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
1244
 
    pHlp->pfnPrintf(pHlp,
1245
 
                    "%04x-%04x %RRv %RRv %RRv %RRv %s\n",
1246
 
                    pRange->Core.Key,
1247
 
                    pRange->Core.KeyLast,
1248
 
                    pRange->pDevIns,
1249
 
                    pRange->pfnInCallback,
1250
 
                    pRange->pfnOutCallback,
1251
 
                    pRange->pvUser,
1252
 
                    pRange->pszDesc);
1253
 
    return 0;
1254
 
}
1255
 
 
1256
 
 
1257
 
/**
1258
 
 * Display all registered I/O port ranges.
1259
 
 *
1260
 
 * @param   pVM         VM Handle.
1261
 
 * @param   pHlp        The info helpers.
1262
 
 * @param   pszArgs     Arguments, ignored.
1263
 
 */
1264
 
static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1265
 
{
1266
 
    NOREF(pszArgs);
1267
 
    pHlp->pfnPrintf(pHlp,
1268
 
                    "I/O Port R3 ranges (pVM=%p)\n"
1269
 
                    "Range     %.*s %.*s %.*s %.*s Description\n",
1270
 
                    pVM,
1271
 
                    sizeof(RTHCPTR) * 2,      "pDevIns         ",
1272
 
                    sizeof(RTHCPTR) * 2,      "In              ",
1273
 
                    sizeof(RTHCPTR) * 2,      "Out             ",
1274
 
                    sizeof(RTHCPTR) * 2,      "pvUser          ");
1275
 
    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR3, true, iomR3IOPortInfoOneR3, (void *)pHlp);
1276
 
 
1277
 
    pHlp->pfnPrintf(pHlp,
1278
 
                    "I/O Port R0 ranges (pVM=%p)\n"
1279
 
                    "Range     %.*s %.*s %.*s %.*s Description\n",
1280
 
                    pVM,
1281
 
                    sizeof(RTHCPTR) * 2,      "pDevIns         ",
1282
 
                    sizeof(RTHCPTR) * 2,      "In              ",
1283
 
                    sizeof(RTHCPTR) * 2,      "Out             ",
1284
 
                    sizeof(RTHCPTR) * 2,      "pvUser          ");
1285
 
    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR0, true, iomR3IOPortInfoOneR3, (void *)pHlp);
1286
 
 
1287
 
    pHlp->pfnPrintf(pHlp,
1288
 
                    "I/O Port GC ranges (pVM=%p)\n"
1289
 
                    "Range     %.*s %.*s %.*s %.*s Description\n",
1290
 
                    pVM,
1291
 
                    sizeof(RTRCPTR) * 2,      "pDevIns         ",
1292
 
                    sizeof(RTRCPTR) * 2,      "In              ",
1293
 
                    sizeof(RTRCPTR) * 2,      "Out             ",
1294
 
                    sizeof(RTRCPTR) * 2,      "pvUser          ");
1295
 
    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeRC, true, iomR3IOPortInfoOneRC, (void *)pHlp);
1296
 
 
1297
 
    if (pVM->iom.s.pRangeLastReadRC)
1298
 
    {
1299
 
        PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)MMHyperRCToCC(pVM, pVM->iom.s.pRangeLastReadRC);
1300
 
        pHlp->pfnPrintf(pHlp, "RC Read  Ports: %#04x-%#04x %RRv %s\n",
1301
 
                        pRange->Port, pRange->Port + pRange->cPorts, pVM->iom.s.pRangeLastReadRC, pRange->pszDesc);
1302
 
    }
1303
 
    if (pVM->iom.s.pStatsLastReadRC)
1304
 
    {
1305
 
        PIOMIOPORTSTATS pRange = (PIOMIOPORTSTATS)MMHyperRCToCC(pVM, pVM->iom.s.pStatsLastReadRC);
1306
 
        pHlp->pfnPrintf(pHlp, "RC Read  Stats: %#04x %RRv\n",
1307
 
                        pRange->Core.Key, pVM->iom.s.pStatsLastReadRC);
1308
 
    }
1309
 
 
1310
 
    if (pVM->iom.s.pRangeLastWriteRC)
1311
 
    {
1312
 
        PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)MMHyperRCToCC(pVM, pVM->iom.s.pRangeLastWriteRC);
1313
 
        pHlp->pfnPrintf(pHlp, "RC Write Ports: %#04x-%#04x %RRv %s\n",
1314
 
                        pRange->Port, pRange->Port + pRange->cPorts, pVM->iom.s.pRangeLastWriteRC, pRange->pszDesc);
1315
 
    }
1316
 
    if (pVM->iom.s.pStatsLastWriteRC)
1317
 
    {
1318
 
        PIOMIOPORTSTATS pRange = (PIOMIOPORTSTATS)MMHyperRCToCC(pVM, pVM->iom.s.pStatsLastWriteRC);
1319
 
        pHlp->pfnPrintf(pHlp, "RC Write Stats: %#04x %RRv\n",
1320
 
                        pRange->Core.Key, pVM->iom.s.pStatsLastWriteRC);
1321
 
    }
1322
 
 
1323
 
    if (pVM->iom.s.pRangeLastReadR3)
1324
 
    {
1325
 
        PIOMIOPORTRANGER3 pRange = pVM->iom.s.pRangeLastReadR3;
1326
 
        pHlp->pfnPrintf(pHlp, "R3 Read  Ports: %#04x-%#04x %p %s\n",
1327
 
                        pRange->Port, pRange->Port + pRange->cPorts, pRange, pRange->pszDesc);
1328
 
    }
1329
 
    if (pVM->iom.s.pStatsLastReadR3)
1330
 
    {
1331
 
        PIOMIOPORTSTATS pRange = pVM->iom.s.pStatsLastReadR3;
1332
 
        pHlp->pfnPrintf(pHlp, "R3 Read  Stats: %#04x %p\n",
1333
 
                        pRange->Core.Key, pRange);
1334
 
    }
1335
 
 
1336
 
    if (pVM->iom.s.pRangeLastWriteR3)
1337
 
    {
1338
 
        PIOMIOPORTRANGER3 pRange = pVM->iom.s.pRangeLastWriteR3;
1339
 
        pHlp->pfnPrintf(pHlp, "R3 Write Ports: %#04x-%#04x %p %s\n",
1340
 
                        pRange->Port, pRange->Port + pRange->cPorts, pRange, pRange->pszDesc);
1341
 
    }
1342
 
    if (pVM->iom.s.pStatsLastWriteR3)
1343
 
    {
1344
 
        PIOMIOPORTSTATS pRange = pVM->iom.s.pStatsLastWriteR3;
1345
 
        pHlp->pfnPrintf(pHlp, "R3 Write Stats: %#04x %p\n",
1346
 
                        pRange->Core.Key, pRange);
1347
 
    }
1348
 
 
1349
 
    if (pVM->iom.s.pRangeLastReadR0)
1350
 
    {
1351
 
        PIOMIOPORTRANGER0 pRange = (PIOMIOPORTRANGER0)MMHyperR0ToCC(pVM, pVM->iom.s.pRangeLastReadR0);
1352
 
        pHlp->pfnPrintf(pHlp, "R0 Read  Ports: %#04x-%#04x %p %s\n",
1353
 
                        pRange->Port, pRange->Port + pRange->cPorts, pRange, pRange->pszDesc);
1354
 
    }
1355
 
    if (pVM->iom.s.pStatsLastReadR0)
1356
 
    {
1357
 
        PIOMIOPORTSTATS pRange = (PIOMIOPORTSTATS)MMHyperR0ToCC(pVM, pVM->iom.s.pStatsLastReadR0);
1358
 
        pHlp->pfnPrintf(pHlp, "R0 Read  Stats: %#04x %p\n",
1359
 
                        pRange->Core.Key, pRange);
1360
 
    }
1361
 
 
1362
 
    if (pVM->iom.s.pRangeLastWriteR0)
1363
 
    {
1364
 
        PIOMIOPORTRANGER0 pRange = (PIOMIOPORTRANGER0)MMHyperR0ToCC(pVM, pVM->iom.s.pRangeLastWriteR0);
1365
 
        pHlp->pfnPrintf(pHlp, "R0 Write Ports: %#04x-%#04x %p %s\n",
1366
 
                        pRange->Port, pRange->Port + pRange->cPorts, pRange, pRange->pszDesc);
1367
 
    }
1368
 
    if (pVM->iom.s.pStatsLastWriteR0)
1369
 
    {
1370
 
        PIOMIOPORTSTATS pRange = (PIOMIOPORTSTATS)MMHyperR0ToCC(pVM, pVM->iom.s.pStatsLastWriteR0);
1371
 
        pHlp->pfnPrintf(pHlp, "R0 Write Stats: %#04x %p\n",
1372
 
                        pRange->Core.Key, pRange);
1373
 
    }
1374
 
}
1375
 
 
1376
 
 
1377
 
/**
1378
 
 * Registers a Memory Mapped I/O R3 handler.
1379
 
 *
1380
 
 * This API is called by PDM on behalf of a device. Devices must register ring-3 ranges
1381
 
 * before any GC and R0 ranges can be registered using IOMR3MMIORegisterRC() and IOMR3MMIORegisterR0().
1382
 
 *
1383
 
 * @returns VBox status code.
1384
 
 *
1385
 
 * @param   pVM                 VM handle.
1386
 
 * @param   pDevIns             PDM device instance owning the MMIO range.
1387
 
 * @param   GCPhysStart         First physical address in the range.
1388
 
 * @param   cbRange             The size of the range (in bytes).
1389
 
 * @param   pvUser              User argument for the callbacks.
1390
 
 * @param   pfnWriteCallback    Pointer to function which is gonna handle Write operations.
1391
 
 * @param   pfnReadCallback     Pointer to function which is gonna handle Read operations.
1392
 
 * @param   pfnFillCallback     Pointer to function which is gonna handle Fill/memset operations.
1393
 
 * @param   pszDesc             Pointer to description string. This must not be freed.
1394
 
 */
1395
 
VMMR3DECL(int)  IOMR3MMIORegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange, RTHCPTR pvUser,
1396
 
                                    R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
1397
 
                                    R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback, const char *pszDesc)
1398
 
{
1399
 
    LogFlow(("IOMR3MMIORegisterR3: pDevIns=%p GCPhysStart=%RGp cbRange=%#x pvUser=%RHv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x pszDesc=%s\n",
1400
 
             pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback, pszDesc));
1401
 
    int rc;
1402
 
 
1403
 
    /*
1404
 
     * Validate input.
1405
 
     */
1406
 
    if (GCPhysStart + (cbRange - 1) < GCPhysStart)
1407
 
    {
1408
 
        AssertMsgFailed(("Wrapped! %RGp %#x bytes\n", GCPhysStart, cbRange));
1409
 
        return VERR_IOM_INVALID_MMIO_RANGE;
1410
 
    }
1411
 
    /** @todo implement per-device locks for MMIO access. */
1412
 
    AssertReturn(!pDevIns->pCritSectR3, VERR_INTERNAL_ERROR_2);
1413
 
 
1414
 
    /*
1415
 
     * Resolve the GC/R0 handler addresses lazily because of init order.
1416
 
     */
1417
 
    if (pVM->iom.s.pfnMMIOHandlerR0 == NIL_RTR0PTR)
1418
 
    {
1419
 
        rc = PDMR3LdrGetSymbolRCLazy(pVM, NULL, "IOMMMIOHandler", &pVM->iom.s.pfnMMIOHandlerRC);
1420
 
        AssertLogRelRCReturn(rc, rc);
1421
 
        rc = PDMR3LdrGetSymbolR0Lazy(pVM, NULL, "IOMMMIOHandler", &pVM->iom.s.pfnMMIOHandlerR0);
1422
 
        AssertLogRelRCReturn(rc, rc);
1423
 
    }
1424
 
 
1425
 
    /*
1426
 
     * For the 2nd+ instance, mangle the description string so it's unique.
1427
 
     * (PGM requires this.)
1428
 
     */
1429
 
    if (pDevIns->iInstance > 0) /** @todo Move to PDMDevHlp.cpp and use a string cache. */
1430
 
    {
1431
 
        pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_IOM, "%s [%u]", pszDesc, pDevIns->iInstance);
1432
 
        if (!pszDesc)
1433
 
            return VERR_NO_MEMORY;
1434
 
    }
1435
 
 
1436
 
 
1437
 
    /*
1438
 
     * Allocate new range record and initialize it.
1439
 
     */
1440
 
    PIOMMMIORANGE pRange;
1441
 
    rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
1442
 
    if (RT_SUCCESS(rc))
1443
 
    {
1444
 
        pRange->Core.Key            = GCPhysStart;
1445
 
        pRange->Core.KeyLast        = GCPhysStart + (cbRange - 1);
1446
 
        pRange->GCPhys              = GCPhysStart;
1447
 
        pRange->cb                  = cbRange;
1448
 
        pRange->pszDesc             = pszDesc;
1449
 
 
1450
 
        pRange->pvUserR3            = pvUser;
1451
 
        pRange->pDevInsR3           = pDevIns;
1452
 
        pRange->pfnReadCallbackR3   = pfnReadCallback;
1453
 
        pRange->pfnWriteCallbackR3  = pfnWriteCallback;
1454
 
        pRange->pfnFillCallbackR3   = pfnFillCallback;
1455
 
 
1456
 
        //pRange->pvUserR0            = NIL_RTR0PTR;
1457
 
        //pRange->pDevInsR0           = NIL_RTR0PTR;
1458
 
        //pRange->pfnReadCallbackR0   = NIL_RTR0PTR;
1459
 
        //pRange->pfnWriteCallbackR0  = NIL_RTR0PTR;
1460
 
        //pRange->pfnFillCallbackR0   = NIL_RTR0PTR;
1461
 
 
1462
 
        //pRange->pvUserRC            = NIL_RTRCPTR;
1463
 
        //pRange->pDevInsRC           = NIL_RTRCPTR;
1464
 
        //pRange->pfnReadCallbackRC   = NIL_RTRCPTR;
1465
 
        //pRange->pfnWriteCallbackRC  = NIL_RTRCPTR;
1466
 
        //pRange->pfnFillCallbackRC   = NIL_RTRCPTR;
1467
 
 
1468
 
        /*
1469
 
         * Try register it with PGM and then insert it into the tree.
1470
 
         */
1471
 
        iomLock(pVM);
1472
 
        iomR3FlushCache(pVM);
1473
 
        rc = PGMR3PhysMMIORegister(pVM, GCPhysStart, cbRange,
1474
 
                                   IOMR3MMIOHandler, pRange,
1475
 
                                   pVM->iom.s.pfnMMIOHandlerR0, MMHyperR3ToR0(pVM, pRange),
1476
 
                                   pVM->iom.s.pfnMMIOHandlerRC, MMHyperR3ToRC(pVM, pRange), pszDesc);
1477
 
        if (RT_SUCCESS(rc))
1478
 
        {
1479
 
            if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))
1480
 
            {
1481
 
                iomUnlock(pVM);
1482
 
                return VINF_SUCCESS;
1483
 
            }
1484
 
 
1485
 
            /* bail out */
1486
 
            iomUnlock(pVM);
1487
 
            DBGFR3Info(pVM, "mmio", NULL, NULL);
1488
 
            AssertMsgFailed(("This cannot happen!\n"));
1489
 
            rc = VERR_INTERNAL_ERROR;
1490
 
        }
1491
 
        else
1492
 
            iomUnlock(pVM);
1493
 
 
1494
 
        MMHyperFree(pVM, pRange);
1495
 
    }
1496
 
    if (pDevIns->iInstance > 0)
1497
 
        MMR3HeapFree((void *)pszDesc);
1498
 
    return rc;
1499
 
}
1500
 
 
1501
 
 
1502
 
/**
1503
 
 * Registers a Memory Mapped I/O RC handler range.
1504
 
 *
1505
 
 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges
1506
 
 * using IOMMMIORegisterR3() before calling this function.
1507
 
 *
1508
 
 *
1509
 
 * @returns VBox status code.
1510
 
 *
1511
 
 * @param   pVM                 VM handle.
1512
 
 * @param   pDevIns             PDM device instance owning the MMIO range.
1513
 
 * @param   GCPhysStart         First physical address in the range.
1514
 
 * @param   cbRange             The size of the range (in bytes).
1515
 
 * @param   pvUser              User argument for the callbacks.
1516
 
 * @param   pfnWriteCallback    Pointer to function which is gonna handle Write operations.
1517
 
 * @param   pfnReadCallback     Pointer to function which is gonna handle Read operations.
1518
 
 * @param   pfnFillCallback     Pointer to function which is gonna handle Fill/memset operations.
1519
 
 */
1520
 
VMMR3DECL(int)  IOMR3MMIORegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange, RTGCPTR pvUser,
1521
 
                                    RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, RCPTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
1522
 
                                    RCPTRTYPE(PFNIOMMMIOFILL) pfnFillCallback)
1523
 
{
1524
 
    LogFlow(("IOMR3MMIORegisterRC: pDevIns=%p GCPhysStart=%RGp cbRange=%#x pvUser=%RGv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x\n",
1525
 
             pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback));
1526
 
 
1527
 
    /*
1528
 
     * Validate input.
1529
 
     */
1530
 
    if (!pfnWriteCallback && !pfnReadCallback)
1531
 
    {
1532
 
        AssertMsgFailed(("No callbacks! %RGp LB%#x %s\n", GCPhysStart, cbRange));
1533
 
        return VERR_INVALID_PARAMETER;
1534
 
    }
1535
 
 
1536
 
    /*
1537
 
     * Find the MMIO range and check that the input matches.
1538
 
     */
1539
 
    iomLock(pVM);
1540
 
    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysStart);
1541
 
    AssertReturnStmt(pRange, iomUnlock(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1542
 
    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, iomUnlock(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
1543
 
    AssertReturnStmt(pRange->GCPhys == GCPhysStart, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
1544
 
    AssertReturnStmt(pRange->cb == cbRange, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
1545
 
 
1546
 
    pRange->pvUserRC          = pvUser;
1547
 
    pRange->pfnReadCallbackRC = pfnReadCallback;
1548
 
    pRange->pfnWriteCallbackRC= pfnWriteCallback;
1549
 
    pRange->pfnFillCallbackRC = pfnFillCallback;
1550
 
    pRange->pDevInsRC         = MMHyperCCToRC(pVM, pDevIns);
1551
 
    iomUnlock(pVM);
1552
 
 
1553
 
    return VINF_SUCCESS;
1554
 
}
1555
 
 
1556
 
 
1557
 
/**
1558
 
 * Registers a Memory Mapped I/O R0 handler range.
1559
 
 *
1560
 
 * This API is called by PDM on behalf of a device. Devices must first register ring-3 ranges
1561
 
 * using IOMMR3MIORegisterHC() before calling this function.
1562
 
 *
1563
 
 *
1564
 
 * @returns VBox status code.
1565
 
 *
1566
 
 * @param   pVM                 VM handle.
1567
 
 * @param   pDevIns             PDM device instance owning the MMIO range.
1568
 
 * @param   GCPhysStart         First physical address in the range.
1569
 
 * @param   cbRange             The size of the range (in bytes).
1570
 
 * @param   pvUser              User argument for the callbacks.
1571
 
 * @param   pfnWriteCallback    Pointer to function which is gonna handle Write operations.
1572
 
 * @param   pfnReadCallback     Pointer to function which is gonna handle Read operations.
1573
 
 * @param   pfnFillCallback     Pointer to function which is gonna handle Fill/memset operations.
1574
 
 */
1575
 
VMMR3DECL(int)  IOMR3MMIORegisterR0(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange, RTR0PTR pvUser,
1576
 
                                    R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback,
1577
 
                                    R0PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
1578
 
                                    R0PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback)
1579
 
{
1580
 
    LogFlow(("IOMR3MMIORegisterR0: pDevIns=%p GCPhysStart=%RGp cbRange=%#x pvUser=%RHv pfnWriteCallback=%#x pfnReadCallback=%#x pfnFillCallback=%#x\n",
1581
 
             pDevIns, GCPhysStart, cbRange, pvUser, pfnWriteCallback, pfnReadCallback, pfnFillCallback));
1582
 
 
1583
 
    /*
1584
 
     * Validate input.
1585
 
     */
1586
 
    if (!pfnWriteCallback && !pfnReadCallback)
1587
 
    {
1588
 
        AssertMsgFailed(("No callbacks! %RGp LB%#x %s\n", GCPhysStart, cbRange));
1589
 
        return VERR_INVALID_PARAMETER;
1590
 
    }
1591
 
 
1592
 
    /*
1593
 
     * Find the MMIO range and check that the input matches.
1594
 
     */
1595
 
    iomLock(pVM);
1596
 
    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysStart);
1597
 
    AssertReturnStmt(pRange, iomUnlock(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1598
 
    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, iomUnlock(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
1599
 
    AssertReturnStmt(pRange->GCPhys == GCPhysStart, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
1600
 
    AssertReturnStmt(pRange->cb == cbRange, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
1601
 
 
1602
 
    pRange->pvUserR0          = pvUser;
1603
 
    pRange->pfnReadCallbackR0 = pfnReadCallback;
1604
 
    pRange->pfnWriteCallbackR0= pfnWriteCallback;
1605
 
    pRange->pfnFillCallbackR0 = pfnFillCallback;
1606
 
    pRange->pDevInsR0         = MMHyperCCToR0(pVM, pDevIns);
1607
 
    iomUnlock(pVM);
1608
 
 
1609
 
    return VINF_SUCCESS;
1610
 
}
1611
 
 
1612
 
 
1613
 
/**
1614
 
 * Deregisters a Memory Mapped I/O handler range.
1615
 
 *
1616
 
 * Registered GC, R0, and R3 ranges are affected.
1617
 
 *
1618
 
 * @returns VBox status code.
1619
 
 *
1620
 
 * @param   pVM                 The virtual machine.
1621
 
 * @param   pDevIns             Device instance which the MMIO region is registered.
1622
 
 * @param   GCPhysStart         First physical address (GC) in the range.
1623
 
 * @param   cbRange             Number of bytes to deregister.
1624
 
 *
1625
 
 * @remark  This function mainly for PCI PnP Config and will not do
1626
 
 *          all the checks you might expect it to do.
1627
 
 */
1628
 
VMMR3DECL(int)  IOMR3MMIODeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange)
1629
 
{
1630
 
    LogFlow(("IOMR3MMIODeregister: pDevIns=%p GCPhysStart=%RGp cbRange=%#x\n", pDevIns, GCPhysStart, cbRange));
1631
 
 
1632
 
    /*
1633
 
     * Validate input.
1634
 
     */
1635
 
    RTGCPHYS GCPhysLast = GCPhysStart + (cbRange - 1);
1636
 
    if (GCPhysLast < GCPhysStart)
1637
 
    {
1638
 
        AssertMsgFailed(("Wrapped! %#x LB%#x\n", GCPhysStart, cbRange));
1639
 
        return VERR_IOM_INVALID_MMIO_RANGE;
1640
 
    }
1641
 
 
1642
 
    iomLock(pVM);
1643
 
 
1644
 
    /*
1645
 
     * Check ownership and such for the entire area.
1646
 
     */
1647
 
    RTGCPHYS GCPhys = GCPhysStart;
1648
 
    while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
1649
 
    {
1650
 
        PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
1651
 
        if (!pRange)
1652
 
        {
1653
 
            iomUnlock(pVM);
1654
 
            return VERR_IOM_MMIO_RANGE_NOT_FOUND;
1655
 
        }
1656
 
        AssertMsgReturnStmt(pRange->pDevInsR3 == pDevIns,
1657
 
                            ("Not owner! GCPhys=%RGp %RGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
1658
 
                            iomUnlock(pVM),
1659
 
                            VERR_IOM_NOT_MMIO_RANGE_OWNER);
1660
 
        AssertMsgReturnStmt(pRange->Core.KeyLast <= GCPhysLast,
1661
 
                            ("Incomplete R3 range! GCPhys=%RGp %RGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
1662
 
                            iomUnlock(pVM),
1663
 
                            VERR_IOM_INCOMPLETE_MMIO_RANGE);
1664
 
 
1665
 
        /* next */
1666
 
        Assert(GCPhys <= pRange->Core.KeyLast);
1667
 
        GCPhys = pRange->Core.KeyLast + 1;
1668
 
    }
1669
 
 
1670
 
    /*
1671
 
     * Do the actual removing of the MMIO ranges.
1672
 
     */
1673
 
    GCPhys = GCPhysStart;
1674
 
    while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
1675
 
    {
1676
 
        iomR3FlushCache(pVM);
1677
 
 
1678
 
        PIOMMMIORANGE pRange = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesR3->MMIOTree, GCPhys);
1679
 
        Assert(pRange);
1680
 
        Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);
1681
 
        iomUnlock(pVM);
1682
 
 
1683
 
        /* remove it from PGM */
1684
 
        int rc = PGMR3PhysMMIODeregister(pVM, GCPhys, pRange->cb);
1685
 
        AssertRC(rc);
1686
 
 
1687
 
        iomLock(pVM);
1688
 
 
1689
 
        /* advance and free. */
1690
 
        GCPhys = pRange->Core.KeyLast + 1;
1691
 
        if (pDevIns->iInstance > 0)
1692
 
            MMR3HeapFree((void *)pRange->pszDesc);
1693
 
        MMHyperFree(pVM, pRange);
1694
 
    }
1695
 
 
1696
 
    iomUnlock(pVM);
1697
 
    return VINF_SUCCESS;
1698
 
}
1699
 
 
1700
 
 
1701
 
/**
1702
 
 * For TM only!
1703
 
 *
1704
 
 * @returns Pointer to the critical section.
1705
 
 * @param   pVM                 The VM handle.
1706
 
 */
1707
 
VMMR3DECL(PPDMCRITSECT) IOMR3GetCritSect(PVM pVM)
1708
 
{
1709
 
    return &pVM->iom.s.EmtLock;
1710
 
}
1711
 
 
1712
 
 
1713
 
/**
1714
 
 * Display a single MMIO range.
1715
 
 *
1716
 
 * @returns 0
1717
 
 * @param   pNode   Pointer to MMIO R3 range.
1718
 
 * @param   pvUser  Pointer to info output callback structure.
1719
 
 */
1720
 
static DECLCALLBACK(int) iomR3MMIOInfoOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
1721
 
{
1722
 
    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;
1723
 
    PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
1724
 
    pHlp->pfnPrintf(pHlp,
1725
 
                    "%RGp-%RGp %RHv %RHv %RHv %RHv %RHv %s\n",
1726
 
                    pRange->Core.Key,
1727
 
                    pRange->Core.KeyLast,
1728
 
                    pRange->pDevInsR3,
1729
 
                    pRange->pfnReadCallbackR3,
1730
 
                    pRange->pfnWriteCallbackR3,
1731
 
                    pRange->pfnFillCallbackR3,
1732
 
                    pRange->pvUserR3,
1733
 
                    pRange->pszDesc);
1734
 
    pHlp->pfnPrintf(pHlp,
1735
 
                    "%*s %RHv %RHv %RHv %RHv %RHv\n",
1736
 
                    sizeof(RTGCPHYS) * 2 * 2 + 1, "R0",
1737
 
                    pRange->pDevInsR0,
1738
 
                    pRange->pfnReadCallbackR0,
1739
 
                    pRange->pfnWriteCallbackR0,
1740
 
                    pRange->pfnFillCallbackR0,
1741
 
                    pRange->pvUserR0);
1742
 
    pHlp->pfnPrintf(pHlp,
1743
 
                    "%*s %RRv %RRv %RRv %RRv %RRv\n",
1744
 
                    sizeof(RTGCPHYS) * 2 * 2 + 1, "RC",
1745
 
                    pRange->pDevInsRC,
1746
 
                    pRange->pfnReadCallbackRC,
1747
 
                    pRange->pfnWriteCallbackRC,
1748
 
                    pRange->pfnFillCallbackRC,
1749
 
                    pRange->pvUserRC);
1750
 
    return 0;
1751
 
}
1752
 
 
1753
 
 
1754
 
/**
1755
 
 * Display registered MMIO ranges to the log.
1756
 
 *
1757
 
 * @param   pVM         VM Handle.
1758
 
 * @param   pHlp        The info helpers.
1759
 
 * @param   pszArgs     Arguments, ignored.
1760
 
 */
1761
 
static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1762
 
{
1763
 
    NOREF(pszArgs);
1764
 
    pHlp->pfnPrintf(pHlp,
1765
 
                    "MMIO ranges (pVM=%p)\n"
1766
 
                    "%.*s %.*s %.*s %.*s %.*s %.*s %s\n",
1767
 
                    pVM,
1768
 
                    sizeof(RTGCPHYS) * 4 + 1, "GC Phys Range                    ",
1769
 
                    sizeof(RTHCPTR) * 2,      "pDevIns         ",
1770
 
                    sizeof(RTHCPTR) * 2,      "Read            ",
1771
 
                    sizeof(RTHCPTR) * 2,      "Write           ",
1772
 
                    sizeof(RTHCPTR) * 2,      "Fill            ",
1773
 
                    sizeof(RTHCPTR) * 2,      "pvUser          ",
1774
 
                                              "Description");
1775
 
    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesR3->MMIOTree, true, iomR3MMIOInfoOne, (void *)pHlp);
1776
 
}
1777
 
 
1778
 
 
1779
 
#ifdef VBOX_WITH_STATISTICS
1780
 
/**
1781
 
 * Tries to come up with the standard name for a port.
1782
 
 *
1783
 
 * @returns Pointer to readonly string if known.
1784
 
 * @returns NULL if unknown port number.
1785
 
 *
1786
 
 * @param   Port    The port to name.
1787
 
 */
1788
 
static const char *iomR3IOPortGetStandardName(RTIOPORT Port)
1789
 
{
1790
 
    switch (Port)
1791
 
    {
1792
 
        case 0x00: case 0x10: case 0x20: case 0x30: case 0x40: case 0x50:            case 0x70:
1793
 
        case 0x01: case 0x11: case 0x21: case 0x31: case 0x41: case 0x51: case 0x61: case 0x71:
1794
 
        case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: case 0x62: case 0x72:
1795
 
        case 0x03: case 0x13: case 0x23: case 0x33: case 0x43: case 0x53: case 0x63: case 0x73:
1796
 
        case 0x04: case 0x14: case 0x24: case 0x34: case 0x44: case 0x54:            case 0x74:
1797
 
        case 0x05: case 0x15: case 0x25: case 0x35: case 0x45: case 0x55: case 0x65: case 0x75:
1798
 
        case 0x06: case 0x16: case 0x26: case 0x36: case 0x46: case 0x56: case 0x66: case 0x76:
1799
 
        case 0x07: case 0x17: case 0x27: case 0x37: case 0x47: case 0x57: case 0x67: case 0x77:
1800
 
        case 0x08: case 0x18: case 0x28: case 0x38: case 0x48: case 0x58: case 0x68: case 0x78:
1801
 
        case 0x09: case 0x19: case 0x29: case 0x39: case 0x49: case 0x59: case 0x69: case 0x79:
1802
 
        case 0x0a: case 0x1a: case 0x2a: case 0x3a: case 0x4a: case 0x5a: case 0x6a: case 0x7a:
1803
 
        case 0x0b: case 0x1b: case 0x2b: case 0x3b: case 0x4b: case 0x5b: case 0x6b: case 0x7b:
1804
 
        case 0x0c: case 0x1c: case 0x2c: case 0x3c: case 0x4c: case 0x5c: case 0x6c: case 0x7c:
1805
 
        case 0x0d: case 0x1d: case 0x2d: case 0x3d: case 0x4d: case 0x5d: case 0x6d: case 0x7d:
1806
 
        case 0x0e: case 0x1e: case 0x2e: case 0x3e: case 0x4e: case 0x5e: case 0x6e: case 0x7e:
1807
 
        case 0x0f: case 0x1f: case 0x2f: case 0x3f: case 0x4f: case 0x5f: case 0x6f: case 0x7f:
1808
 
 
1809
 
        case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xc0: case 0xd0: case 0xe0: case 0xf0:
1810
 
        case 0x81: case 0x91: case 0xa1: case 0xb1: case 0xc1: case 0xd1: case 0xe1: case 0xf1:
1811
 
        case 0x82: case 0x92: case 0xa2: case 0xb2: case 0xc2: case 0xd2: case 0xe2: case 0xf2:
1812
 
        case 0x83: case 0x93: case 0xa3: case 0xb3: case 0xc3: case 0xd3: case 0xe3: case 0xf3:
1813
 
        case 0x84: case 0x94: case 0xa4: case 0xb4: case 0xc4: case 0xd4: case 0xe4: case 0xf4:
1814
 
        case 0x85: case 0x95: case 0xa5: case 0xb5: case 0xc5: case 0xd5: case 0xe5: case 0xf5:
1815
 
        case 0x86: case 0x96: case 0xa6: case 0xb6: case 0xc6: case 0xd6: case 0xe6: case 0xf6:
1816
 
        case 0x87: case 0x97: case 0xa7: case 0xb7: case 0xc7: case 0xd7: case 0xe7: case 0xf7:
1817
 
        case 0x88: case 0x98: case 0xa8: case 0xb8: case 0xc8: case 0xd8: case 0xe8: case 0xf8:
1818
 
        case 0x89: case 0x99: case 0xa9: case 0xb9: case 0xc9: case 0xd9: case 0xe9: case 0xf9:
1819
 
        case 0x8a: case 0x9a: case 0xaa: case 0xba: case 0xca: case 0xda: case 0xea: case 0xfa:
1820
 
        case 0x8b: case 0x9b: case 0xab: case 0xbb: case 0xcb: case 0xdb: case 0xeb: case 0xfb:
1821
 
        case 0x8c: case 0x9c: case 0xac: case 0xbc: case 0xcc: case 0xdc: case 0xec: case 0xfc:
1822
 
        case 0x8d: case 0x9d: case 0xad: case 0xbd: case 0xcd: case 0xdd: case 0xed: case 0xfd:
1823
 
        case 0x8e: case 0x9e: case 0xae: case 0xbe: case 0xce: case 0xde: case 0xee: case 0xfe:
1824
 
        case 0x8f: case 0x9f: case 0xaf: case 0xbf: case 0xcf: case 0xdf: case 0xef: case 0xff:
1825
 
            return "System Reserved";
1826
 
 
1827
 
        case 0x60:
1828
 
        case 0x64:
1829
 
            return "Keyboard & Mouse";
1830
 
 
1831
 
        case 0x378:
1832
 
        case 0x379:
1833
 
        case 0x37a:
1834
 
        case 0x37b:
1835
 
        case 0x37c:
1836
 
        case 0x37d:
1837
 
        case 0x37e:
1838
 
        case 0x37f:
1839
 
        case 0x3bc:
1840
 
        case 0x3bd:
1841
 
        case 0x3be:
1842
 
        case 0x3bf:
1843
 
        case 0x278:
1844
 
        case 0x279:
1845
 
        case 0x27a:
1846
 
        case 0x27b:
1847
 
        case 0x27c:
1848
 
        case 0x27d:
1849
 
        case 0x27e:
1850
 
        case 0x27f:
1851
 
            return "LPT1/2/3";
1852
 
 
1853
 
        case 0x3f8:
1854
 
        case 0x3f9:
1855
 
        case 0x3fa:
1856
 
        case 0x3fb:
1857
 
        case 0x3fc:
1858
 
        case 0x3fd:
1859
 
        case 0x3fe:
1860
 
        case 0x3ff:
1861
 
            return "COM1";
1862
 
 
1863
 
        case 0x2f8:
1864
 
        case 0x2f9:
1865
 
        case 0x2fa:
1866
 
        case 0x2fb:
1867
 
        case 0x2fc:
1868
 
        case 0x2fd:
1869
 
        case 0x2fe:
1870
 
        case 0x2ff:
1871
 
            return "COM2";
1872
 
 
1873
 
        case 0x3e8:
1874
 
        case 0x3e9:
1875
 
        case 0x3ea:
1876
 
        case 0x3eb:
1877
 
        case 0x3ec:
1878
 
        case 0x3ed:
1879
 
        case 0x3ee:
1880
 
        case 0x3ef:
1881
 
            return "COM3";
1882
 
 
1883
 
        case 0x2e8:
1884
 
        case 0x2e9:
1885
 
        case 0x2ea:
1886
 
        case 0x2eb:
1887
 
        case 0x2ec:
1888
 
        case 0x2ed:
1889
 
        case 0x2ee:
1890
 
        case 0x2ef:
1891
 
            return "COM4";
1892
 
 
1893
 
        case 0x200:
1894
 
        case 0x201:
1895
 
        case 0x202:
1896
 
        case 0x203:
1897
 
        case 0x204:
1898
 
        case 0x205:
1899
 
        case 0x206:
1900
 
        case 0x207:
1901
 
            return "Joystick";
1902
 
 
1903
 
        case 0x3f0:
1904
 
        case 0x3f1:
1905
 
        case 0x3f2:
1906
 
        case 0x3f3:
1907
 
        case 0x3f4:
1908
 
        case 0x3f5:
1909
 
        case 0x3f6:
1910
 
        case 0x3f7:
1911
 
            return "Floppy";
1912
 
 
1913
 
        case 0x1f0:
1914
 
        case 0x1f1:
1915
 
        case 0x1f2:
1916
 
        case 0x1f3:
1917
 
        case 0x1f4:
1918
 
        case 0x1f5:
1919
 
        case 0x1f6:
1920
 
        case 0x1f7:
1921
 
        //case 0x3f6:
1922
 
        //case 0x3f7:
1923
 
            return "IDE 1st";
1924
 
 
1925
 
        case 0x170:
1926
 
        case 0x171:
1927
 
        case 0x172:
1928
 
        case 0x173:
1929
 
        case 0x174:
1930
 
        case 0x175:
1931
 
        case 0x176:
1932
 
        case 0x177:
1933
 
        case 0x376:
1934
 
        case 0x377:
1935
 
            return "IDE 2nd";
1936
 
 
1937
 
        case 0x1e0:
1938
 
        case 0x1e1:
1939
 
        case 0x1e2:
1940
 
        case 0x1e3:
1941
 
        case 0x1e4:
1942
 
        case 0x1e5:
1943
 
        case 0x1e6:
1944
 
        case 0x1e7:
1945
 
        case 0x3e6:
1946
 
        case 0x3e7:
1947
 
            return "IDE 3rd";
1948
 
 
1949
 
        case 0x160:
1950
 
        case 0x161:
1951
 
        case 0x162:
1952
 
        case 0x163:
1953
 
        case 0x164:
1954
 
        case 0x165:
1955
 
        case 0x166:
1956
 
        case 0x167:
1957
 
        case 0x366:
1958
 
        case 0x367:
1959
 
            return "IDE 4th";
1960
 
 
1961
 
        case 0x130: case 0x140: case 0x150:
1962
 
        case 0x131: case 0x141: case 0x151:
1963
 
        case 0x132: case 0x142: case 0x152:
1964
 
        case 0x133: case 0x143: case 0x153:
1965
 
        case 0x134: case 0x144: case 0x154:
1966
 
        case 0x135: case 0x145: case 0x155:
1967
 
        case 0x136: case 0x146: case 0x156:
1968
 
        case 0x137: case 0x147: case 0x157:
1969
 
        case 0x138: case 0x148: case 0x158:
1970
 
        case 0x139: case 0x149: case 0x159:
1971
 
        case 0x13a: case 0x14a: case 0x15a:
1972
 
        case 0x13b: case 0x14b: case 0x15b:
1973
 
        case 0x13c: case 0x14c: case 0x15c:
1974
 
        case 0x13d: case 0x14d: case 0x15d:
1975
 
        case 0x13e: case 0x14e: case 0x15e:
1976
 
        case 0x13f: case 0x14f: case 0x15f:
1977
 
        case 0x220: case 0x230:
1978
 
        case 0x221: case 0x231:
1979
 
        case 0x222: case 0x232:
1980
 
        case 0x223: case 0x233:
1981
 
        case 0x224: case 0x234:
1982
 
        case 0x225: case 0x235:
1983
 
        case 0x226: case 0x236:
1984
 
        case 0x227: case 0x237:
1985
 
        case 0x228: case 0x238:
1986
 
        case 0x229: case 0x239:
1987
 
        case 0x22a: case 0x23a:
1988
 
        case 0x22b: case 0x23b:
1989
 
        case 0x22c: case 0x23c:
1990
 
        case 0x22d: case 0x23d:
1991
 
        case 0x22e: case 0x23e:
1992
 
        case 0x22f: case 0x23f:
1993
 
        case 0x330: case 0x340: case 0x350:
1994
 
        case 0x331: case 0x341: case 0x351:
1995
 
        case 0x332: case 0x342: case 0x352:
1996
 
        case 0x333: case 0x343: case 0x353:
1997
 
        case 0x334: case 0x344: case 0x354:
1998
 
        case 0x335: case 0x345: case 0x355:
1999
 
        case 0x336: case 0x346: case 0x356:
2000
 
        case 0x337: case 0x347: case 0x357:
2001
 
        case 0x338: case 0x348: case 0x358:
2002
 
        case 0x339: case 0x349: case 0x359:
2003
 
        case 0x33a: case 0x34a: case 0x35a:
2004
 
        case 0x33b: case 0x34b: case 0x35b:
2005
 
        case 0x33c: case 0x34c: case 0x35c:
2006
 
        case 0x33d: case 0x34d: case 0x35d:
2007
 
        case 0x33e: case 0x34e: case 0x35e:
2008
 
        case 0x33f: case 0x34f: case 0x35f:
2009
 
            return "SCSI (typically)";
2010
 
 
2011
 
        case 0x320:
2012
 
        case 0x321:
2013
 
        case 0x322:
2014
 
        case 0x323:
2015
 
        case 0x324:
2016
 
        case 0x325:
2017
 
        case 0x326:
2018
 
        case 0x327:
2019
 
            return "XT HD";
2020
 
 
2021
 
        case 0x3b0:
2022
 
        case 0x3b1:
2023
 
        case 0x3b2:
2024
 
        case 0x3b3:
2025
 
        case 0x3b4:
2026
 
        case 0x3b5:
2027
 
        case 0x3b6:
2028
 
        case 0x3b7:
2029
 
        case 0x3b8:
2030
 
        case 0x3b9:
2031
 
        case 0x3ba:
2032
 
        case 0x3bb:
2033
 
            return "VGA";
2034
 
 
2035
 
        case 0x3c0: case 0x3d0:
2036
 
        case 0x3c1: case 0x3d1:
2037
 
        case 0x3c2: case 0x3d2:
2038
 
        case 0x3c3: case 0x3d3:
2039
 
        case 0x3c4: case 0x3d4:
2040
 
        case 0x3c5: case 0x3d5:
2041
 
        case 0x3c6: case 0x3d6:
2042
 
        case 0x3c7: case 0x3d7:
2043
 
        case 0x3c8: case 0x3d8:
2044
 
        case 0x3c9: case 0x3d9:
2045
 
        case 0x3ca: case 0x3da:
2046
 
        case 0x3cb: case 0x3db:
2047
 
        case 0x3cc: case 0x3dc:
2048
 
        case 0x3cd: case 0x3dd:
2049
 
        case 0x3ce: case 0x3de:
2050
 
        case 0x3cf: case 0x3df:
2051
 
            return "VGA/EGA";
2052
 
 
2053
 
        case 0x240: case 0x260: case 0x280:
2054
 
        case 0x241: case 0x261: case 0x281:
2055
 
        case 0x242: case 0x262: case 0x282:
2056
 
        case 0x243: case 0x263: case 0x283:
2057
 
        case 0x244: case 0x264: case 0x284:
2058
 
        case 0x245: case 0x265: case 0x285:
2059
 
        case 0x246: case 0x266: case 0x286:
2060
 
        case 0x247: case 0x267: case 0x287:
2061
 
        case 0x248: case 0x268: case 0x288:
2062
 
        case 0x249: case 0x269: case 0x289:
2063
 
        case 0x24a: case 0x26a: case 0x28a:
2064
 
        case 0x24b: case 0x26b: case 0x28b:
2065
 
        case 0x24c: case 0x26c: case 0x28c:
2066
 
        case 0x24d: case 0x26d: case 0x28d:
2067
 
        case 0x24e: case 0x26e: case 0x28e:
2068
 
        case 0x24f: case 0x26f: case 0x28f:
2069
 
        case 0x300:
2070
 
        case 0x301:
2071
 
        case 0x388:
2072
 
        case 0x389:
2073
 
        case 0x38a:
2074
 
        case 0x38b:
2075
 
            return "Sound Card (typically)";
2076
 
 
2077
 
        default:
2078
 
            return NULL;
2079
 
    }
2080
 
}
2081
 
#endif /* VBOX_WITH_STATISTICS */
2082