VirtualBox

source: vbox/trunk/src/VBox/VMM/include/IOMInline.h@ 80651

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

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.0 KB
Line 
1/* $Id: IOMInline.h 80641 2019-09-06 20:09:16Z vboxsync $ */
2/** @file
3 * IOM - Inlined functions.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VMM_INCLUDED_SRC_include_IOMInline_h
19#define VMM_INCLUDED_SRC_include_IOMInline_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include <iprt/errcore.h>
25
26/** @addtogroup grp_iom_int Internals
27 * @internal
28 * @{
29 */
30
31
32/**
33 * Gets the I/O port entry for the specified I/O port in the current context.
34 *
35 * @returns Pointer to I/O port entry.
36 * @returns NULL if no port registered.
37 *
38 * @param pVM The cross context VM structure.
39 * @param Port The I/O port lookup.
40 * @param pidxLastHint Pointer to IOMCPU::idxIoPortLastRead or
41 * IOMCPU::idxIoPortLastWrite.
42 *
43 * @note In ring-0 it is possible to get an uninitialized entry (pDevIns is
44 * NULL, cPorts is 0), in which case there should be ring-3 handlers
45 * for the entry. Use IOMIOPORTENTRYR0::idxSelf to get the ring-3
46 * entry.
47 */
48DECLINLINE(CTX_SUFF(PIOMIOPORTENTRY)) iomIoPortGetEntry(PVMCC pVM, RTIOPORT uPort, uint16_t *pidxLastHint)
49{
50 Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
51
52#ifdef IN_RING0
53 uint32_t iEnd = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iomr0.s.cIoPortAlloc);
54 PIOMIOPORTLOOKUPENTRY paLookup = pVM->iomr0.s.paIoPortLookup;
55#else
56 uint32_t iEnd = pVM->iom.s.cIoPortLookupEntries;
57 PIOMIOPORTLOOKUPENTRY paLookup = pVM->iom.s.paIoPortLookup;
58#endif
59 if (iEnd > 0)
60 {
61 uint32_t iFirst = 0;
62 uint32_t i = *pidxLastHint;
63 if (i < iEnd)
64 { /* likely */ }
65 else
66 i = iEnd / 2;
67 for (;;)
68 {
69 PIOMIOPORTLOOKUPENTRY pCur = &paLookup[i];
70 if (pCur->uFirstPort > uPort)
71 {
72 if (i > iFirst)
73 iEnd = i;
74 else
75 return NULL;
76 }
77 else if (pCur->uLastPort < uPort)
78 {
79 i += 1;
80 if (i < iEnd)
81 iFirst = i;
82 else
83 return NULL;
84 }
85 else
86 {
87 *pidxLastHint = (uint16_t)i;
88
89 /*
90 * Translate the 'idx' member into a pointer.
91 */
92 size_t const idx = pCur->idx;
93#ifdef IN_RING0
94 AssertMsg(idx < pVM->iom.s.cIoPortRegs && idx < pVM->iomr0.s.cIoPortAlloc,
95 ("%#zx vs %#x/%x (port %#x)\n", idx, pVM->iom.s.cIoPortRegs, pVM->iomr0.s.cIoPortMax, uPort));
96 if (idx < pVM->iomr0.s.cIoPortAlloc)
97 return &pVM->iomr0.s.paIoPortRegs[idx];
98#else
99 if (idx < pVM->iom.s.cIoPortRegs)
100 return &pVM->iom.s.paIoPortRegs[idx];
101 AssertMsgFailed(("%#zx vs %#x (port %#x)\n", idx, pVM->iom.s.cIoPortRegs, uPort));
102#endif
103 break;
104 }
105
106 i = iFirst + (iEnd - iFirst) / 2;
107 }
108 }
109 return NULL;
110}
111
112
113#ifdef VBOX_WITH_STATISTICS
114/**
115 * Gets the I/O port statistics entry .
116 *
117 * @returns Pointer to stats. Instead of NULL, a pointer to IoPortDummyStats is
118 * returned, so the caller does not need to check for NULL.
119 *
120 * @param pVM The cross context VM structure.
121 * @param pRegEntry The I/O port entry to get stats for.
122 */
123DECLINLINE(PIOMIOPORTSTATSENTRY) iomIoPortGetStats(PVMCC pVM, CTX_SUFF(PIOMIOPORTENTRY) pRegEntry)
124{
125 size_t idxStats = pRegEntry->idxStats;
126# ifdef IN_RING0
127 if (idxStats < pVM->iomr0.s.cIoPortStatsAllocation)
128 return &pVM->iomr0.s.paIoPortStats[idxStats];
129# else
130 if (idxStats < pVM->iom.s.cIoPortStats)
131 return &pVM->iom.s.paIoPortStats[idxStats];
132# endif
133 return &pVM->iom.s.IoPortDummyStats;
134}
135#endif
136
137
138/**
139 * Gets the I/O port range for the specified I/O port in the current context.
140 *
141 * @returns Pointer to I/O port range.
142 * @returns NULL if no port registered.
143 *
144 * @param pVM The cross context VM structure.
145 * @param Port The I/O port lookup.
146 */
147DECLINLINE(CTX_SUFF(PIOMIOPORTRANGE)) iomIOPortGetRange(PVM pVM, RTIOPORT Port)
148{
149 Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
150 return (CTX_SUFF(PIOMIOPORTRANGE))RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->CTX_SUFF(IOPortTree), Port);
151}
152
153
154/**
155 * Gets the I/O port range for the specified I/O port in the HC.
156 *
157 * @returns Pointer to I/O port range.
158 * @returns NULL if no port registered.
159 *
160 * @param pVM The cross context VM structure.
161 * @param Port The I/O port to lookup.
162 */
163DECLINLINE(PIOMIOPORTRANGER3) iomIOPortGetRangeR3(PVM pVM, RTIOPORT Port)
164{
165 Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
166 return (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);
167}
168
169
170/**
171 * Gets the MMIO range for the specified physical address in the current context.
172 *
173 * @returns Pointer to MMIO range.
174 * @returns NULL if address not in a MMIO range.
175 *
176 * @param pVM The cross context VM structure.
177 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
178 * @param GCPhys Physical address to lookup.
179 */
180DECLINLINE(PIOMMMIORANGE) iomMmioGetRange(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
181{
182 Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
183 PIOMMMIORANGE pRange = pVCpu->iom.s.CTX_SUFF(pMMIORangeLast);
184 if ( !pRange
185 || GCPhys - pRange->GCPhys >= pRange->cb)
186 pVCpu->iom.s.CTX_SUFF(pMMIORangeLast) = pRange
187 = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->MMIOTree, GCPhys);
188 return pRange;
189}
190
191/**
192 * Retain a MMIO range.
193 *
194 * @param pRange The range to release.
195 */
196DECLINLINE(void) iomMmioRetainRange(PIOMMMIORANGE pRange)
197{
198 uint32_t cRefs = ASMAtomicIncU32(&pRange->cRefs);
199 Assert(cRefs > 1);
200 Assert(cRefs < _1M);
201 NOREF(cRefs);
202}
203
204
205/**
206 * Gets the referenced MMIO range for the specified physical address in the
207 * current context.
208 *
209 * @returns Pointer to MMIO range.
210 * @returns NULL if address not in a MMIO range.
211 *
212 * @param pVM The cross context VM structure.
213 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
214 * @param GCPhys Physical address to lookup.
215 */
216DECLINLINE(PIOMMMIORANGE) iomMmioGetRangeWithRef(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
217{
218 int rc = IOM_LOCK_SHARED_EX(pVM, VINF_SUCCESS);
219 AssertRCReturn(rc, NULL);
220
221 PIOMMMIORANGE pRange = pVCpu->iom.s.CTX_SUFF(pMMIORangeLast);
222 if ( !pRange
223 || GCPhys - pRange->GCPhys >= pRange->cb)
224 pVCpu->iom.s.CTX_SUFF(pMMIORangeLast) = pRange
225 = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->MMIOTree, GCPhys);
226 if (pRange)
227 iomMmioRetainRange(pRange);
228
229 IOM_UNLOCK_SHARED(pVM);
230 return pRange;
231}
232
233
234/**
235 * Releases a MMIO range.
236 *
237 * @param pVM The cross context VM structure.
238 * @param pRange The range to release.
239 */
240DECLINLINE(void) iomMmioReleaseRange(PVMCC pVM, PIOMMMIORANGE pRange)
241{
242 uint32_t cRefs = ASMAtomicDecU32(&pRange->cRefs);
243 if (!cRefs)
244 iomMmioFreeRange(pVM, pRange);
245}
246
247
248#ifdef VBOX_STRICT
249/**
250 * Gets the MMIO range for the specified physical address in the current context.
251 *
252 * @returns Pointer to MMIO range.
253 * @returns NULL if address not in a MMIO range.
254 *
255 * @param pVM The cross context VM structure.
256 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
257 * @param GCPhys Physical address to lookup.
258 */
259DECLINLINE(PIOMMMIORANGE) iomMMIOGetRangeUnsafe(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
260{
261 PIOMMMIORANGE pRange = pVCpu->iom.s.CTX_SUFF(pMMIORangeLast);
262 if ( !pRange
263 || GCPhys - pRange->GCPhys >= pRange->cb)
264 pVCpu->iom.s.CTX_SUFF(pMMIORangeLast) = pRange
265 = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->MMIOTree, GCPhys);
266 return pRange;
267}
268#endif /* VBOX_STRICT */
269
270
271#ifdef VBOX_WITH_STATISTICS
272/**
273 * Gets the MMIO statistics record.
274 *
275 * In ring-3 this will lazily create missing records, while in GC/R0 the caller has to
276 * return the appropriate status to defer the operation to ring-3.
277 *
278 * @returns Pointer to MMIO stats.
279 * @returns NULL if not found (R0/GC), or out of memory (R3).
280 *
281 * @param pVM The cross context VM structure.
282 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
283 * @param GCPhys Physical address to lookup.
284 * @param pRange The MMIO range.
285 *
286 * @remarks The caller holds the IOM critical section with shared access prior
287 * to calling this method. Upon return, the lock has been released!
288 * This is ugly, but it's a necessary evil since we cannot upgrade read
289 * locks to write locks and the whole purpose here is calling
290 * iomR3MMIOStatsCreate.
291 */
292DECLINLINE(PIOMMMIOSTATS) iomMmioGetStats(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, PIOMMMIORANGE pRange)
293{
294 Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
295
296 /* For large ranges, we'll put everything on the first byte. */
297 if (pRange->cb > PAGE_SIZE)
298 GCPhys = pRange->GCPhys;
299
300 PIOMMMIOSTATS pStats = pVCpu->iom.s.CTX_SUFF(pMMIOStatsLast);
301 if ( !pStats
302 || pStats->Core.Key != GCPhys)
303 {
304 pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pVM->iom.s.CTX_SUFF(pTrees)->MmioStatTree, GCPhys);
305# ifdef IN_RING3
306 if (!pStats)
307 {
308 IOM_UNLOCK_SHARED(pVM);
309 return iomR3MMIOStatsCreate(pVM, GCPhys, pRange->pszDesc);
310 }
311# endif
312 }
313
314 IOM_UNLOCK_SHARED(pVM);
315 return pStats;
316}
317#endif /* VBOX_WITH_STATISTICS */
318
319
320/** @} */
321
322#endif /* !VMM_INCLUDED_SRC_include_IOMInline_h */
323
Note: See TracBrowser for help on using the repository browser.

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