3
* IOM - Input / Output Monitor.
7
* Copyright (C) 2006-2007 Oracle Corporation
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.
19
/** @page pg_iom IOM - The Input / Output Monitor
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.
29
* @section sec_iom_rawmode Raw-Mode
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.)
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.
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
55
* @section sec_iom_hwaccm Hardware Assisted Virtualization Mode
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
63
* @section sec_iom_rem Recompiled Execution Mode
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...
75
* @section sec_iom_other Other Accesses
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).
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
92
/*******************************************************************************
94
*******************************************************************************/
95
#define LOG_GROUP LOG_GROUP_IOM
97
#include <VBox/cpum.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"
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>
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);
129
#ifdef VBOX_WITH_STATISTICS
130
static const char *iomR3IOPortGetStandardName(RTIOPORT Port);
135
* Initializes the IOM.
137
* @returns VBox status code.
138
* @param pVM The VM to operate on.
140
VMMR3DECL(int) IOMR3Init(PVM pVM)
142
LogFlow(("IOMR3Init:\n"));
145
* Assert alignment and sizes.
147
AssertCompileMemberAlignment(VM, iom.s, 32);
148
AssertCompile(sizeof(pVM->iom.s) <= sizeof(pVM->iom.padding));
149
AssertCompileMemberAlignment(IOM, EmtLock, sizeof(uintptr_t));
152
* Setup any fixed pointers and offsets.
154
pVM->iom.s.offVM = RT_OFFSETOF(VM, iom);
157
* Initialize the REM critical section.
159
int rc = PDMR3CritSectInit(pVM, &pVM->iom.s.EmtLock, RT_SRC_POS, "IOM EMT Lock");
160
AssertRCReturn(rc, rc);
163
* Allocate the trees structure.
165
rc = MMHyperAlloc(pVM, sizeof(*pVM->iom.s.pTreesR3), 0, MM_TAG_IOM, (void **)&pVM->iom.s.pTreesR3);
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;
176
DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IOPortInfo);
177
DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MMIOInfo);
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.");
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.");
212
/* Redundant, but just in case we change something in the future */
213
iomR3FlushCache(pVM);
215
LogFlow(("IOMR3Init: returns %Rrc\n", rc));
221
* Flushes the IOM port & statistics lookup cache
225
static void iomR3FlushCache(PVM pVM)
229
* Caching of port and statistics (saves some time in rep outs/ins instruction emulation)
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;
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;
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;
257
* The VM is being reset.
259
* @param pVM VM handle.
261
VMMR3DECL(void) IOMR3Reset(PVM pVM)
263
iomR3FlushCache(pVM);
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.
272
* The IOM will update the addresses used by the switcher.
275
* @param offDelta Relocation delta relative to old location.
277
VMMR3DECL(void) IOMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
279
LogFlow(("IOMR3Relocate: offDelta=%d\n", offDelta));
282
* Apply relocations to the GC callbacks.
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);
288
if (pVM->iom.s.pfnMMIOHandlerRC)
289
pVM->iom.s.pfnMMIOHandlerRC += offDelta;
292
* Apply relocations to the cached GC handlers
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;
310
* Callback function for relocating a I/O port range.
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.
317
static DECLCALLBACK(int) iomR3RelocateIOPortCallback(PAVLROIOPORTNODECORE pNode, void *pvUser)
319
PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode;
320
RTGCINTPTR offDelta = *(PRTGCINTPTR)pvUser;
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;
339
* Callback function for relocating a MMIO range.
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.
346
static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser)
348
PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;
349
RTGCINTPTR offDelta = *(PRTGCINTPTR)pvUser;
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;
367
* Terminates the IOM.
369
* Termination means cleaning up and freeing all resources,
370
* the VM it self is at this point powered off or suspended.
372
* @returns VBox status code.
373
* @param pVM The VM to operate on.
375
VMMR3DECL(int) IOMR3Term(PVM pVM)
378
* IOM is not owning anything but automatically freed resources,
379
* so there's nothing to do here.
384
#ifdef VBOX_WITH_STATISTICS
387
* Create the statistics node for an I/O port.
389
* @returns Pointer to new stats node.
391
* @param pVM VM handle.
393
* @param pszDesc Description.
395
PIOMIOPORTSTATS iomR3IOPortStatsCreate(PVM pVM, RTIOPORT Port, const char *pszDesc)
397
Assert(IOMIsLockOwner(pVM));
398
/* check if it already exists. */
399
PIOMIOPORTSTATS pPort = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.pTreesR3->IOPortStatTree, Port);
403
/* allocate stats node. */
404
int rc = MMHyperAlloc(pVM, sizeof(*pPort), 0, MM_TAG_IOM_STATS, (void **)&pPort);
408
/* insert into the tree. */
409
pPort->Core.Key = Port;
410
if (RTAvloIOPortInsert(&pVM->iom.s.pTreesR3->IOPortStatTree, &pPort->Core))
412
/* put a name on common ports. */
414
pszDesc = iomR3IOPortGetStandardName(Port);
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);
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);
432
AssertMsgFailed(("what! Port=%d\n", Port));
433
MMHyperFree(pVM, pPort);
440
* Create the statistics node for an MMIO address.
442
* @returns Pointer to new stats node.
444
* @param pVM VM handle.
445
* @param GCPhys The address.
446
* @param pszDesc Description.
448
PIOMMMIOSTATS iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc)
450
Assert(IOMIsLockOwner(pVM));
451
#ifdef DEBUG_sandervl
452
AssertGCPhys32(GCPhys);
454
/* check if it already exists. */
455
PIOMMMIOSTATS pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pVM->iom.s.pTreesR3->MMIOStatTree, GCPhys);
459
/* allocate stats node. */
460
int rc = MMHyperAlloc(pVM, sizeof(*pStats), 0, MM_TAG_IOM_STATS, (void **)&pStats);
464
/* insert into the tree. */
465
pStats->Core.Key = GCPhys;
466
if (RTAvloGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOStatTree, &pStats->Core))
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);
478
AssertMsgFailed(("what! GCPhys=%RGp\n", GCPhys));
479
MMHyperFree(pVM, pStats);
484
#endif /* VBOX_WITH_STATISTICS */
487
* Registers a I/O port ring-3 handler.
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().
494
* @returns VBox status code.
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.
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)
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));
517
if ( (RTUINT)PortStart + cPorts <= (RTUINT)PortStart
518
|| (RTUINT)PortStart + cPorts > 0x10000)
520
AssertMsgFailed(("Invalid port range %#x-%#x (inclusive)! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
521
return VERR_IOM_INVALID_IOPORT_RANGE;
523
if (!pfnOutCallback && !pfnInCallback)
525
AssertMsgFailed(("no handlers specfied for %#x-%#x (inclusive)! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
526
return VERR_INVALID_PARAMETER;
529
pfnOutCallback = iomR3IOPortDummyOut;
531
pfnInCallback = iomR3IOPortDummyIn;
532
if (!pfnOutStrCallback)
533
pfnOutStrCallback = iomR3IOPortDummyOutStr;
534
if (!pfnInStrCallback)
535
pfnInStrCallback = iomR3IOPortDummyInStr;
537
/* Flush the IO port lookup cache */
538
iomR3FlushCache(pVM);
541
* Allocate new range record and initialize it.
543
PIOMIOPORTRANGER3 pRange;
544
int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
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;
563
if (RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR3, &pRange->Core))
565
#ifdef VBOX_WITH_STATISTICS
566
for (unsigned iPort = 0; iPort < cPorts; iPort++)
567
iomR3IOPortStatsCreate(pVM, PortStart + iPort, pszDesc);
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;
586
* Registers a I/O port RC handler.
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.
592
* @returns VBox status code.
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.
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)
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));
615
if ( (RTUINT)PortStart + cPorts <= (RTUINT)PortStart
616
|| (RTUINT)PortStart + cPorts > 0x10000)
618
AssertMsgFailed(("Invalid port range %#x-%#x! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
619
return VERR_IOM_INVALID_IOPORT_RANGE;
621
RTIOPORT PortLast = PortStart + (cPorts - 1);
622
if (!pfnOutCallback && !pfnInCallback)
624
AssertMsgFailed(("Invalid port range %#x-%#x! No callbacks! (%s)\n", PortStart, PortLast, pszDesc));
625
return VERR_INVALID_PARAMETER;
631
* Validate that there are ring-3 ranges for the ports.
633
RTIOPORT Port = PortStart;
634
while (Port <= PortLast && Port >= PortStart)
636
PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);
639
AssertMsgFailed(("No R3! Port=#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
641
return VERR_IOM_NO_HC_IOPORT_RANGE;
643
#ifndef IOM_NO_PDMINS_CHECKS
645
if (pRange->pDevIns != pDevIns)
647
if (pRange->pDevIns != MMHyperRCToCC(pVM, pDevIns))
650
AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
652
return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
655
Port = pRange->Core.KeyLast + 1;
658
/* Flush the IO port lookup cache */
659
iomR3FlushCache(pVM);
662
* Allocate new range record and initialize it.
664
PIOMIOPORTRANGERC pRange;
665
int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
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;
683
if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeRC, &pRange->Core))
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;
700
* Registers a Port IO R0 handler.
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.
706
* @returns VBox status code.
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.
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,
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));
730
if ( (RTUINT)PortStart + cPorts <= (RTUINT)PortStart
731
|| (RTUINT)PortStart + cPorts > 0x10000)
733
AssertMsgFailed(("Invalid port range %#x-%#x! (%s)\n", PortStart, (RTUINT)PortStart + (cPorts - 1), pszDesc));
734
return VERR_IOM_INVALID_IOPORT_RANGE;
736
RTIOPORT PortLast = PortStart + (cPorts - 1);
737
if (!pfnOutCallback && !pfnInCallback)
739
AssertMsgFailed(("Invalid port range %#x-%#x! No callbacks! (%s)\n", PortStart, PortLast, pszDesc));
740
return VERR_INVALID_PARAMETER;
745
* Validate that there are ring-3 ranges for the ports.
747
RTIOPORT Port = PortStart;
748
while (Port <= PortLast && Port >= PortStart)
750
PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);
753
AssertMsgFailed(("No R3! Port=#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
755
return VERR_IOM_NO_HC_IOPORT_RANGE;
757
#ifndef IOM_NO_PDMINS_CHECKS
759
if (pRange->pDevIns != pDevIns)
761
if (pRange->pDevIns != MMHyperRCToCC(pVM, pDevIns))
764
AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
766
return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
769
Port = pRange->Core.KeyLast + 1;
772
/* Flush the IO port lookup cache */
773
iomR3FlushCache(pVM);
776
* Allocate new range record and initialize it.
778
PIOMIOPORTRANGER0 pRange;
779
int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
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;
797
if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR0, &pRange->Core))
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;
814
* Deregisters a I/O Port range.
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.
820
* This function will remove GC, R0 and R3 context port handlers for this range.
822
* @returns VBox status code.
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.
829
* @remark This function mainly for PCI PnP Config and will not do
830
* all the checks you might expect it to do.
832
VMMR3DECL(int) IOMR3IOPortDeregister(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts)
834
LogFlow(("IOMR3IOPortDeregister: pDevIns=%p PortStart=%#x cPorts=%#x\n", pDevIns, PortStart, cPorts));
839
if ( (RTUINT)PortStart + cPorts < (RTUINT)PortStart
840
|| (RTUINT)PortStart + cPorts > 0x10000)
842
AssertMsgFailed(("Invalid port range %#x-%#x!\n", PortStart, (unsigned)PortStart + cPorts - 1));
843
return VERR_IOM_INVALID_IOPORT_RANGE;
848
/* Flush the IO port lookup cache */
849
iomR3FlushCache(pVM);
854
RTIOPORT PortLast = PortStart + (cPorts - 1);
855
RTIOPORT Port = PortStart;
856
while (Port <= PortLast && Port >= PortStart)
858
PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);
861
Assert(Port <= pRange->Core.KeyLast);
862
#ifndef IOM_NO_PDMINS_CHECKS
863
if (pRange->pDevIns != pDevIns)
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));
868
return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
870
#endif /* !IOM_NO_PDMINS_CHECKS */
871
Port = pRange->Core.KeyLast;
877
* Remove any RC ranges first.
879
int rc = VINF_SUCCESS;
881
while (Port <= PortLast && Port >= PortStart)
886
PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeRC, Port);
889
if ( pRange->Core.Key == Port
890
&& pRange->Core.KeyLast <= PortLast)
893
* Kick out the entire range.
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);
900
else if (pRange->Core.Key == Port)
903
* Cut of the head of the range, done.
905
pRange->cPorts -= Port - pRange->Port;
906
pRange->Core.Key = Port;
910
else if (pRange->Core.KeyLast <= PortLast)
913
* Just cut of the tail.
915
unsigned c = pRange->Core.KeyLast - Port + 1;
916
pRange->Core.KeyLast -= c;
923
* Split the range, done.
925
Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);
927
PIOMIOPORTRANGERC pRangeNew;
928
int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);
934
*pRangeNew = *pRange;
935
pRangeNew->Core.Key = PortLast;
936
pRangeNew->Port = PortLast;
937
pRangeNew->cPorts = pRangeNew->Core.KeyLast - PortLast + 1;
939
LogFlow(("IOMR3IOPortDeregister (rc): split the range; new %x\n", pRangeNew->Core.Key));
942
pRange->Core.KeyLast = Port - 1;
943
pRange->cPorts = Port - pRange->Port;
946
if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeRC, &pRangeNew->Core))
948
AssertMsgFailed(("This cannot happen!\n"));
949
MMHyperFree(pVM, pRangeNew);
950
rc = VERR_INTERNAL_ERROR;
957
} /* for all ports - RC. */
961
* Remove any R0 ranges.
964
while (Port <= PortLast && Port >= PortStart)
969
PIOMIOPORTRANGER0 pRange = (PIOMIOPORTRANGER0)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR0, Port);
972
if ( pRange->Core.Key == Port
973
&& pRange->Core.KeyLast <= PortLast)
976
* Kick out the entire range.
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);
983
else if (pRange->Core.Key == Port)
986
* Cut of the head of the range, done.
988
pRange->cPorts -= Port - pRange->Port;
989
pRange->Core.Key = Port;
993
else if (pRange->Core.KeyLast <= PortLast)
996
* Just cut of the tail.
998
unsigned c = pRange->Core.KeyLast - Port + 1;
999
pRange->Core.KeyLast -= c;
1000
pRange->cPorts -= c;
1006
* Split the range, done.
1008
Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);
1010
PIOMIOPORTRANGER0 pRangeNew;
1011
int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);
1012
if (RT_FAILURE(rc2))
1017
*pRangeNew = *pRange;
1018
pRangeNew->Core.Key = PortLast;
1019
pRangeNew->Port = PortLast;
1020
pRangeNew->cPorts = pRangeNew->Core.KeyLast - PortLast + 1;
1022
LogFlow(("IOMR3IOPortDeregister (r0): split the range; new %x\n", pRangeNew->Core.Key));
1025
pRange->Core.KeyLast = Port - 1;
1026
pRange->cPorts = Port - pRange->Port;
1029
if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR0, &pRangeNew->Core))
1031
AssertMsgFailed(("This cannot happen!\n"));
1032
MMHyperFree(pVM, pRangeNew);
1033
rc = VERR_INTERNAL_ERROR;
1038
else /* next port */
1040
} /* for all ports - R0. */
1043
* And the same procedure for ring-3 ranges.
1046
while (Port <= PortLast && Port >= PortStart)
1051
PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.pTreesR3->IOPortTreeR3, Port);
1054
if ( pRange->Core.Key == Port
1055
&& pRange->Core.KeyLast <= PortLast)
1058
* Kick out the entire range.
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);
1065
else if (pRange->Core.Key == Port)
1068
* Cut of the head of the range, done.
1070
pRange->cPorts -= Port - pRange->Port;
1071
pRange->Core.Key = Port;
1072
pRange->Port = Port;
1075
else if (pRange->Core.KeyLast <= PortLast)
1078
* Just cut of the tail.
1080
unsigned c = pRange->Core.KeyLast - Port + 1;
1081
pRange->Core.KeyLast -= c;
1082
pRange->cPorts -= c;
1088
* Split the range, done.
1090
Assert(pRange->Core.KeyLast > PortLast && pRange->Core.Key < Port);
1092
PIOMIOPORTRANGER3 pRangeNew;
1093
int rc2 = MMHyperAlloc(pVM, sizeof(*pRangeNew), 0, MM_TAG_IOM, (void **)&pRangeNew);
1094
if (RT_FAILURE(rc2))
1099
*pRangeNew = *pRange;
1100
pRangeNew->Core.Key = PortLast;
1101
pRangeNew->Port = PortLast;
1102
pRangeNew->cPorts = pRangeNew->Core.KeyLast - PortLast + 1;
1104
LogFlow(("IOMR3IOPortDeregister (r3): split the range; new %x\n", pRangeNew->Core.Key));
1107
pRange->Core.KeyLast = Port - 1;
1108
pRange->cPorts = Port - pRange->Port;
1111
if (!RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR3, &pRangeNew->Core))
1113
AssertMsgFailed(("This cannot happen!\n"));
1114
MMHyperFree(pVM, pRangeNew);
1115
rc = VERR_INTERNAL_ERROR;
1120
else /* next port */
1122
} /* for all ports - ring-3. */
1131
* Dummy Port I/O Handler for IN operations.
1133
* @returns VBox status code.
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.
1141
static DECLCALLBACK(int) iomR3IOPortDummyIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1145
case 1: *pu32 = 0xff; break;
1146
case 2: *pu32 = 0xffff; break;
1147
case 4: *pu32 = UINT32_C(0xffffffff); break;
1149
AssertReleaseMsgFailed(("cb=%d\n", cb));
1150
return VERR_INTERNAL_ERROR;
1152
return VINF_SUCCESS;
1157
* Dummy Port I/O Handler for string IN operations.
1159
* @returns VBox status code.
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).
1168
static DECLCALLBACK(int) iomR3IOPortDummyInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
1170
return VINF_SUCCESS;
1175
* Dummy Port I/O Handler for OUT operations.
1177
* @returns VBox status code.
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.
1185
static DECLCALLBACK(int) iomR3IOPortDummyOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1187
return VINF_SUCCESS;
1192
* Dummy Port I/O Handler for string OUT operations.
1194
* @returns VBox status code.
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).
1203
static DECLCALLBACK(int) iomR3IOPortDummyOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
1205
return VINF_SUCCESS;
1210
* Display a single I/O port ring-3 range.
1213
* @param pNode Pointer to I/O port HC range.
1214
* @param pvUser Pointer to info output callback structure.
1216
static DECLCALLBACK(int) iomR3IOPortInfoOneR3(PAVLROIOPORTNODECORE pNode, void *pvUser)
1218
PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)pNode;
1219
PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
1220
pHlp->pfnPrintf(pHlp,
1221
"%04x-%04x %p %p %p %p %s\n",
1223
pRange->Core.KeyLast,
1225
pRange->pfnInCallback,
1226
pRange->pfnOutCallback,
1234
* Display a single I/O port GC range.
1237
* @param pNode Pointer to IOPORT GC range.
1238
* @param pvUser Pointer to info output callback structure.
1240
static DECLCALLBACK(int) iomR3IOPortInfoOneRC(PAVLROIOPORTNODECORE pNode, void *pvUser)
1242
PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode;
1243
PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
1244
pHlp->pfnPrintf(pHlp,
1245
"%04x-%04x %RRv %RRv %RRv %RRv %s\n",
1247
pRange->Core.KeyLast,
1249
pRange->pfnInCallback,
1250
pRange->pfnOutCallback,
1258
* Display all registered I/O port ranges.
1260
* @param pVM VM Handle.
1261
* @param pHlp The info helpers.
1262
* @param pszArgs Arguments, ignored.
1264
static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1267
pHlp->pfnPrintf(pHlp,
1268
"I/O Port R3 ranges (pVM=%p)\n"
1269
"Range %.*s %.*s %.*s %.*s Description\n",
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);
1277
pHlp->pfnPrintf(pHlp,
1278
"I/O Port R0 ranges (pVM=%p)\n"
1279
"Range %.*s %.*s %.*s %.*s Description\n",
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);
1287
pHlp->pfnPrintf(pHlp,
1288
"I/O Port GC ranges (pVM=%p)\n"
1289
"Range %.*s %.*s %.*s %.*s Description\n",
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);
1297
if (pVM->iom.s.pRangeLastReadRC)
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);
1303
if (pVM->iom.s.pStatsLastReadRC)
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);
1310
if (pVM->iom.s.pRangeLastWriteRC)
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);
1316
if (pVM->iom.s.pStatsLastWriteRC)
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);
1323
if (pVM->iom.s.pRangeLastReadR3)
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);
1329
if (pVM->iom.s.pStatsLastReadR3)
1331
PIOMIOPORTSTATS pRange = pVM->iom.s.pStatsLastReadR3;
1332
pHlp->pfnPrintf(pHlp, "R3 Read Stats: %#04x %p\n",
1333
pRange->Core.Key, pRange);
1336
if (pVM->iom.s.pRangeLastWriteR3)
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);
1342
if (pVM->iom.s.pStatsLastWriteR3)
1344
PIOMIOPORTSTATS pRange = pVM->iom.s.pStatsLastWriteR3;
1345
pHlp->pfnPrintf(pHlp, "R3 Write Stats: %#04x %p\n",
1346
pRange->Core.Key, pRange);
1349
if (pVM->iom.s.pRangeLastReadR0)
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);
1355
if (pVM->iom.s.pStatsLastReadR0)
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);
1362
if (pVM->iom.s.pRangeLastWriteR0)
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);
1368
if (pVM->iom.s.pStatsLastWriteR0)
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);
1378
* Registers a Memory Mapped I/O R3 handler.
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().
1383
* @returns VBox status code.
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.
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)
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));
1406
if (GCPhysStart + (cbRange - 1) < GCPhysStart)
1408
AssertMsgFailed(("Wrapped! %RGp %#x bytes\n", GCPhysStart, cbRange));
1409
return VERR_IOM_INVALID_MMIO_RANGE;
1411
/** @todo implement per-device locks for MMIO access. */
1412
AssertReturn(!pDevIns->pCritSectR3, VERR_INTERNAL_ERROR_2);
1415
* Resolve the GC/R0 handler addresses lazily because of init order.
1417
if (pVM->iom.s.pfnMMIOHandlerR0 == NIL_RTR0PTR)
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);
1426
* For the 2nd+ instance, mangle the description string so it's unique.
1427
* (PGM requires this.)
1429
if (pDevIns->iInstance > 0) /** @todo Move to PDMDevHlp.cpp and use a string cache. */
1431
pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_IOM, "%s [%u]", pszDesc, pDevIns->iInstance);
1433
return VERR_NO_MEMORY;
1438
* Allocate new range record and initialize it.
1440
PIOMMMIORANGE pRange;
1441
rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
1444
pRange->Core.Key = GCPhysStart;
1445
pRange->Core.KeyLast = GCPhysStart + (cbRange - 1);
1446
pRange->GCPhys = GCPhysStart;
1447
pRange->cb = cbRange;
1448
pRange->pszDesc = pszDesc;
1450
pRange->pvUserR3 = pvUser;
1451
pRange->pDevInsR3 = pDevIns;
1452
pRange->pfnReadCallbackR3 = pfnReadCallback;
1453
pRange->pfnWriteCallbackR3 = pfnWriteCallback;
1454
pRange->pfnFillCallbackR3 = pfnFillCallback;
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;
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;
1469
* Try register it with PGM and then insert it into the tree.
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);
1479
if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))
1482
return VINF_SUCCESS;
1487
DBGFR3Info(pVM, "mmio", NULL, NULL);
1488
AssertMsgFailed(("This cannot happen!\n"));
1489
rc = VERR_INTERNAL_ERROR;
1494
MMHyperFree(pVM, pRange);
1496
if (pDevIns->iInstance > 0)
1497
MMR3HeapFree((void *)pszDesc);
1503
* Registers a Memory Mapped I/O RC handler range.
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.
1509
* @returns VBox status code.
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.
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)
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));
1530
if (!pfnWriteCallback && !pfnReadCallback)
1532
AssertMsgFailed(("No callbacks! %RGp LB%#x %s\n", GCPhysStart, cbRange));
1533
return VERR_INVALID_PARAMETER;
1537
* Find the MMIO range and check that the input matches.
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);
1546
pRange->pvUserRC = pvUser;
1547
pRange->pfnReadCallbackRC = pfnReadCallback;
1548
pRange->pfnWriteCallbackRC= pfnWriteCallback;
1549
pRange->pfnFillCallbackRC = pfnFillCallback;
1550
pRange->pDevInsRC = MMHyperCCToRC(pVM, pDevIns);
1553
return VINF_SUCCESS;
1558
* Registers a Memory Mapped I/O R0 handler range.
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.
1564
* @returns VBox status code.
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.
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)
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));
1586
if (!pfnWriteCallback && !pfnReadCallback)
1588
AssertMsgFailed(("No callbacks! %RGp LB%#x %s\n", GCPhysStart, cbRange));
1589
return VERR_INVALID_PARAMETER;
1593
* Find the MMIO range and check that the input matches.
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);
1602
pRange->pvUserR0 = pvUser;
1603
pRange->pfnReadCallbackR0 = pfnReadCallback;
1604
pRange->pfnWriteCallbackR0= pfnWriteCallback;
1605
pRange->pfnFillCallbackR0 = pfnFillCallback;
1606
pRange->pDevInsR0 = MMHyperCCToR0(pVM, pDevIns);
1609
return VINF_SUCCESS;
1614
* Deregisters a Memory Mapped I/O handler range.
1616
* Registered GC, R0, and R3 ranges are affected.
1618
* @returns VBox status code.
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.
1625
* @remark This function mainly for PCI PnP Config and will not do
1626
* all the checks you might expect it to do.
1628
VMMR3DECL(int) IOMR3MMIODeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange)
1630
LogFlow(("IOMR3MMIODeregister: pDevIns=%p GCPhysStart=%RGp cbRange=%#x\n", pDevIns, GCPhysStart, cbRange));
1635
RTGCPHYS GCPhysLast = GCPhysStart + (cbRange - 1);
1636
if (GCPhysLast < GCPhysStart)
1638
AssertMsgFailed(("Wrapped! %#x LB%#x\n", GCPhysStart, cbRange));
1639
return VERR_IOM_INVALID_MMIO_RANGE;
1645
* Check ownership and such for the entire area.
1647
RTGCPHYS GCPhys = GCPhysStart;
1648
while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
1650
PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
1654
return VERR_IOM_MMIO_RANGE_NOT_FOUND;
1656
AssertMsgReturnStmt(pRange->pDevInsR3 == pDevIns,
1657
("Not owner! GCPhys=%RGp %RGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
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),
1663
VERR_IOM_INCOMPLETE_MMIO_RANGE);
1666
Assert(GCPhys <= pRange->Core.KeyLast);
1667
GCPhys = pRange->Core.KeyLast + 1;
1671
* Do the actual removing of the MMIO ranges.
1673
GCPhys = GCPhysStart;
1674
while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
1676
iomR3FlushCache(pVM);
1678
PIOMMMIORANGE pRange = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesR3->MMIOTree, GCPhys);
1680
Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);
1683
/* remove it from PGM */
1684
int rc = PGMR3PhysMMIODeregister(pVM, GCPhys, pRange->cb);
1689
/* advance and free. */
1690
GCPhys = pRange->Core.KeyLast + 1;
1691
if (pDevIns->iInstance > 0)
1692
MMR3HeapFree((void *)pRange->pszDesc);
1693
MMHyperFree(pVM, pRange);
1697
return VINF_SUCCESS;
1704
* @returns Pointer to the critical section.
1705
* @param pVM The VM handle.
1707
VMMR3DECL(PPDMCRITSECT) IOMR3GetCritSect(PVM pVM)
1709
return &pVM->iom.s.EmtLock;
1714
* Display a single MMIO range.
1717
* @param pNode Pointer to MMIO R3 range.
1718
* @param pvUser Pointer to info output callback structure.
1720
static DECLCALLBACK(int) iomR3MMIOInfoOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
1722
PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;
1723
PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
1724
pHlp->pfnPrintf(pHlp,
1725
"%RGp-%RGp %RHv %RHv %RHv %RHv %RHv %s\n",
1727
pRange->Core.KeyLast,
1729
pRange->pfnReadCallbackR3,
1730
pRange->pfnWriteCallbackR3,
1731
pRange->pfnFillCallbackR3,
1734
pHlp->pfnPrintf(pHlp,
1735
"%*s %RHv %RHv %RHv %RHv %RHv\n",
1736
sizeof(RTGCPHYS) * 2 * 2 + 1, "R0",
1738
pRange->pfnReadCallbackR0,
1739
pRange->pfnWriteCallbackR0,
1740
pRange->pfnFillCallbackR0,
1742
pHlp->pfnPrintf(pHlp,
1743
"%*s %RRv %RRv %RRv %RRv %RRv\n",
1744
sizeof(RTGCPHYS) * 2 * 2 + 1, "RC",
1746
pRange->pfnReadCallbackRC,
1747
pRange->pfnWriteCallbackRC,
1748
pRange->pfnFillCallbackRC,
1755
* Display registered MMIO ranges to the log.
1757
* @param pVM VM Handle.
1758
* @param pHlp The info helpers.
1759
* @param pszArgs Arguments, ignored.
1761
static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1764
pHlp->pfnPrintf(pHlp,
1765
"MMIO ranges (pVM=%p)\n"
1766
"%.*s %.*s %.*s %.*s %.*s %.*s %s\n",
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 ",
1775
RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesR3->MMIOTree, true, iomR3MMIOInfoOne, (void *)pHlp);
1779
#ifdef VBOX_WITH_STATISTICS
1781
* Tries to come up with the standard name for a port.
1783
* @returns Pointer to readonly string if known.
1784
* @returns NULL if unknown port number.
1786
* @param Port The port to name.
1788
static const char *iomR3IOPortGetStandardName(RTIOPORT Port)
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:
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";
1829
return "Keyboard & Mouse";
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)";
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:
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:
2075
return "Sound Card (typically)";
2081
#endif /* VBOX_WITH_STATISTICS */