VirtualBox

source: vbox/trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp@ 82180

最後變更 在這個檔案從82180是 82151,由 vboxsync 提交於 5 年 前

Storage/DevVirtioSCSI.cpp: Did some work on virtio async event subscription logic. Fixed medium eject detection. Added one more layer of mallocs to virtual address S/G buffer handling to prevent stack out of scope errors undetected by the Sanitizer.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 79.8 KB
 
1/* $Id: Virtio_1_0.cpp 82151 2019-11-25 04:14:32Z vboxsync $ */
2/** @file
3 * Virtio_1_0 - Virtio Common (PCI, feature & config mgt, queue mgt & proxy, notification mgt)
4 */
5
6/*
7 * Copyright (C) 2009-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_VIRTIO
23
24#include <VBox/log.h>
25#include <VBox/msi.h>
26#include <VBox/AssertGuest.h>
27#include <iprt/param.h>
28#include <iprt/assert.h>
29#include <iprt/uuid.h>
30#include <iprt/mem.h>
31#include <iprt/assert.h>
32#include <iprt/sg.h>
33#include <iprt/string.h>
34#include <VBox/vmm/pdmdev.h>
35#include "Virtio_1_0.h"
36
37
38/*********************************************************************************************************************************
39* Defined Constants And Macros *
40*********************************************************************************************************************************/
41#define INSTANCE(a_pVirtio) ((a_pVirtio)->szInstance)
42#define QUEUE_NAME(a_pVirtio, a_idxQueue) ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName)
43#define IS_DRIVER_OK(a_pVirtio) ((a_pVirtio)->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
44
45/**
46 * This macro returns true if the @a a_offAccess and access length (@a
47 * a_cbAccess) are within the range of the mapped capability struct described by
48 * @a a_LocCapData.
49 *
50 * @param[in] a_offAccess The offset into the MMIO bar of the access.
51 * @param[in] a_cbAccess The access size.
52 * @param[out] a_offIntraVar The variable to return the intra-capability
53 * offset into. ASSUMES this is uint32_t.
54 * @param[in] a_LocCapData The capability location info.
55 */
56#define MATCHES_VIRTIO_CAP_STRUCT(a_offAccess, a_cbAccess, a_offIntraVar, a_LocCapData) \
57 ( ((a_offIntraVar) = (uint32_t)((a_offAccess) - (a_LocCapData).offMmio)) < (uint32_t)(a_LocCapData).cbMmio \
58 && (a_offIntraVar) + (uint32_t)(a_cbAccess) <= (uint32_t)(a_LocCapData).cbMmio )
59
60
61/** Marks the start of the virtio saved state (just for sanity). */
62#define VIRTIO_SAVEDSTATE_MARKER UINT64_C(0x1133557799bbddff)
63/** The current saved state version for the virtio core. */
64#define VIRTIO_SAVEDSTATE_VERSION UINT32_C(1)
65
66
67/*********************************************************************************************************************************
68* Structures and Typedefs *
69*********************************************************************************************************************************/
70/**
71 * virtq related structs
72 * (struct names follow VirtIO 1.0 spec, typedef use VBox style)
73 */
74typedef struct virtq_desc
75{
76 uint64_t GCPhysBuf; /**< addr GC Phys. address of buffer */
77 uint32_t cb; /**< len Buffer length */
78 uint16_t fFlags; /**< flags Buffer specific flags */
79 uint16_t uDescIdxNext; /**< next Idx set if VIRTIO_DESC_F_NEXT */
80} VIRTQ_DESC_T, *PVIRTQ_DESC_T;
81
82typedef struct virtq_avail
83{
84 uint16_t fFlags; /**< flags avail ring drv to dev flags */
85 uint16_t uIdx; /**< idx Index of next free ring slot */
86 uint16_t auRing[RT_FLEXIBLE_ARRAY]; /**< ring Ring: avail drv to dev bufs */
87 /* uint16_t uUsedEventIdx; - used_event (if VIRTQ_USED_F_EVENT_IDX) */
88} VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
89
90typedef struct virtq_used_elem
91{
92 uint32_t uDescIdx; /**< idx Start of used desc chain */
93 uint32_t cbElem; /**< len Total len of used desc chain */
94} VIRTQ_USED_ELEM_T;
95
96typedef struct virt_used
97{
98 uint16_t fFlags; /**< flags used ring host-to-guest flags */
99 uint16_t uIdx; /**< idx Index of next ring slot */
100 VIRTQ_USED_ELEM_T aRing[RT_FLEXIBLE_ARRAY]; /**< ring Ring: used dev to drv bufs */
101 /* uint16_t uAvailEventIdx; - avail_event if (VIRTQ_USED_F_EVENT_IDX) */
102} VIRTQ_USED_T, *PVIRTQ_USED_T;
103
104
105const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState)
106{
107 switch (enmState)
108 {
109 case kvirtIoVmStateChangedReset: return "VM RESET";
110 case kvirtIoVmStateChangedSuspend: return "VM SUSPEND";
111 case kvirtIoVmStateChangedPowerOff: return "VM POWER OFF";
112 case kvirtIoVmStateChangedResume: return "VM RESUME";
113 default: return "<BAD ENUM>";
114 }
115}
116
117/* Internal Functions */
118
119static void virtioNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fForce);
120static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec, bool fForce);
121
122/** @name Internal queue operations
123 * @{ */
124
125#if 0 /* unused */
126DECLINLINE(int) virtqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld)
127{
128 return (uint16_t)(uDescIdxNew - uEventIdx - 1) < (uint16_t)(uDescIdxNew - uDescIdxOld);
129}
130#endif
131
132/**
133 * Accessor for virtq descriptor
134 */
135DECLINLINE(void) virtioReadDesc(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue,
136 uint32_t idxDesc, PVIRTQ_DESC_T pDesc)
137{
138 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
139 uint16_t const cQueueItems = RT_MAX(pVirtio->uQueueSize[idxQueue], 1); /* Make sure to avoid div-by-zero. */
140 PDMDevHlpPCIPhysRead(pDevIns,
141 pVirtio->aGCPhysQueueDesc[idxQueue] + sizeof(VIRTQ_DESC_T) * (idxDesc % cQueueItems),
142 pDesc, sizeof(VIRTQ_DESC_T));
143}
144
145/**
146 * Accessors for virtq avail ring
147 */
148DECLINLINE(uint16_t) virtioReadAvailDescIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint32_t availIdx)
149{
150 uint16_t uDescIdx;
151 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
152 uint16_t const cQueueItems = RT_MAX(pVirtio->uQueueSize[idxQueue], 1); /* Make sure to avoid div-by-zero. */
153 PDMDevHlpPCIPhysRead(pDevIns,
154 pVirtio->aGCPhysQueueAvail[idxQueue]
155 + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % cQueueItems]),
156 &uDescIdx, sizeof(uDescIdx));
157 return uDescIdx;
158}
159
160DECLINLINE(uint16_t) virtioReadAvailRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
161{
162 uint16_t uIdx = 0;
163 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
164 PDMDevHlpPCIPhysRead(pDevIns,
165 pVirtio->aGCPhysQueueAvail[idxQueue] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
166 &uIdx, sizeof(uIdx));
167 return uIdx;
168}
169
170DECLINLINE(bool) virtqIsEmpty(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
171{
172 return virtioReadAvailRingIdx(pDevIns, pVirtio, idxQueue) == pVirtio->virtqState[idxQueue].uAvailIdx;
173}
174
175#if 0 /* unused - Will be used when VIRTIO_F_EVENT_IDX optional feature is implemented, VirtIO 1.0, 2.4.7 */
176DECLINLINE(uint16_t) virtioReadAvailFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
177{
178 uint16_t fFlags;
179 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
180 PDMDevHlpPCIPhysRead(pDevIns,
181 pVirtio->aGCPhysQueueAvail[idxQueue] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
182 &fFlags, sizeof(fFlags));
183 return fFlags;
184}
185#endif
186
187DECLINLINE(uint16_t) virtioReadAvailUsedEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
188{
189 uint16_t uUsedEventIdx;
190 /* VirtIO 1.0 uUsedEventIdx (used_event) immediately follows ring */
191 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
192 PDMDevHlpPCIPhysRead(pDevIns,
193 pVirtio->aGCPhysQueueAvail[idxQueue] + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uQueueSize[idxQueue]]),
194 &uUsedEventIdx, sizeof(uUsedEventIdx));
195 return uUsedEventIdx;
196}
197/** @} */
198
199/** @name Accessors for virtq used ring
200 * @{
201 */
202DECLINLINE(void) virtioWriteUsedElem(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue,
203 uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen)
204{
205 VIRTQ_USED_ELEM_T elem = { uDescIdx, uLen };
206 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
207 uint16_t const cQueueItems = RT_MAX(pVirtio->uQueueSize[idxQueue], 1); /* Make sure to avoid div-by-zero. */
208 PDMDevHlpPCIPhysWrite(pDevIns,
209 pVirtio->aGCPhysQueueUsed[idxQueue] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[usedIdx % cQueueItems]),
210 &elem, sizeof(elem));
211}
212
213DECLINLINE(void) virtioWriteUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint16_t uIdx)
214{
215 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
216 PDMDevHlpPCIPhysWrite(pDevIns,
217 pVirtio->aGCPhysQueueUsed[idxQueue] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
218 &uIdx, sizeof(uIdx));
219}
220
221#ifdef LOG_ENABLED
222DECLINLINE(uint16_t) virtioReadUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
223{
224 uint16_t uIdx = 0;
225 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
226 PDMDevHlpPCIPhysRead(pDevIns,
227 pVirtio->aGCPhysQueueUsed[idxQueue] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
228 &uIdx, sizeof(uIdx));
229 return uIdx;
230}
231#endif
232
233DECLINLINE(uint16_t) virtioReadUsedFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
234{
235 uint16_t fFlags = 0;
236 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
237 PDMDevHlpPCIPhysRead(pDevIns,
238 pVirtio->aGCPhysQueueUsed[idxQueue] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
239 &fFlags, sizeof(fFlags));
240 return fFlags;
241}
242
243#if 0 /* unused - This may eventually be used to set no-notify for the ring as an optimization */
244DECLINLINE(void) virtioWriteUsedFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint32_t fFlags)
245{
246 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
247 RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
248 PDMDevHlpPCIPhysWrite(pDevIns,
249 pVirtio->aGCPhysQueueUsed[idxQueue] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
250 &fFlags, sizeof(fFlags));
251}
252#endif
253
254#if 0 /* unused - *May* be used when VIRTIO_F_EVENT_IDX optional feature is implemented VirtIO 1.0, 2.4.9.2*/
255DECLINLINE(void) virtioWriteUsedAvailEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint32_t uAvailEventIdx)
256{
257 /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */
258 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
259 PDMDevHlpPCIPhysWrite(pDevIns,
260 pVirtio->aGCPhysQueueUsed[idxQueue] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtio->uQueueSize[idxQueue]]),
261 &uAvailEventIdx, sizeof(uAvailEventIdx));
262}
263#endif
264
265/** @} */
266
267void virtioCoreSgBufInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs)
268{
269 AssertPtr(pGcSgBuf);
270 Assert( (cSegs > 0 && VALID_PTR(paSegs)) || (!cSegs && !paSegs));
271 Assert(cSegs < (~(unsigned)0 >> 1));
272
273 pGcSgBuf->paSegs = paSegs;
274 pGcSgBuf->cSegs = (unsigned)cSegs;
275 pGcSgBuf->idxSeg = 0;
276 if (cSegs && paSegs)
277 {
278 pGcSgBuf->pGcSegCur = paSegs[0].pGcSeg;
279 pGcSgBuf->cbSegLeft = paSegs[0].cbSeg;
280 }
281 else
282 {
283 pGcSgBuf->pGcSegCur = 0;
284 pGcSgBuf->cbSegLeft = 0;
285 }
286}
287
288static RTGCPHYS virtioCoreSgBufGet(PVIRTIOSGBUF pGcSgBuf, size_t *pcbData)
289{
290 size_t cbData;
291 RTGCPHYS pGcBuf;
292
293 /* Check that the S/G buffer has memory left. */
294 if (RT_LIKELY(pGcSgBuf->idxSeg < pGcSgBuf->cSegs && pGcSgBuf->cbSegLeft))
295 { /* likely */ }
296 else
297 {
298 *pcbData = 0;
299 return 0;
300 }
301
302 AssertMsg( pGcSgBuf->cbSegLeft <= 128 * _1M
303 && (RTGCPHYS)pGcSgBuf->pGcSegCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg
304 && (RTGCPHYS)pGcSgBuf->pGcSegCur + pGcSgBuf->cbSegLeft <=
305 (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg,
306 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf->pGcSegCur=%p pGcSgBuf->cbSegLeft=%zd "
307 "pGcSgBuf->paSegs[%d].pGcSeg=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n",
308 pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf->pGcSegCur, pGcSgBuf->cbSegLeft,
309 pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg, pGcSgBuf->idxSeg,
310 pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg));
311
312 cbData = RT_MIN(*pcbData, pGcSgBuf->cbSegLeft);
313 pGcBuf = pGcSgBuf->pGcSegCur;
314 pGcSgBuf->cbSegLeft -= cbData;
315 if (!pGcSgBuf->cbSegLeft)
316 {
317 pGcSgBuf->idxSeg++;
318
319 if (pGcSgBuf->idxSeg < pGcSgBuf->cSegs)
320 {
321 pGcSgBuf->pGcSegCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg;
322 pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg;
323 }
324 *pcbData = cbData;
325 }
326 else
327 pGcSgBuf->pGcSegCur = pGcSgBuf->pGcSegCur + cbData;
328
329 return pGcBuf;
330}
331
332void virtioCoreSgBufReset(PVIRTIOSGBUF pGcSgBuf)
333{
334 AssertPtrReturnVoid(pGcSgBuf);
335
336 pGcSgBuf->idxSeg = 0;
337 if (pGcSgBuf->cSegs)
338 {
339 pGcSgBuf->pGcSegCur = pGcSgBuf->paSegs[0].pGcSeg;
340 pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[0].cbSeg;
341 }
342 else
343 {
344 pGcSgBuf->pGcSegCur = 0;
345 pGcSgBuf->cbSegLeft = 0;
346 }
347}
348
349RTGCPHYS virtioCoreSgBufAdvance(PVIRTIOSGBUF pGcSgBuf, size_t cbAdvance)
350{
351 AssertReturn(pGcSgBuf, 0);
352
353 size_t cbLeft = cbAdvance;
354 while (cbLeft)
355 {
356 size_t cbThisAdvance = cbLeft;
357 virtioCoreSgBufGet(pGcSgBuf, &cbThisAdvance);
358 if (!cbThisAdvance)
359 break;
360
361 cbLeft -= cbThisAdvance;
362 }
363 return cbAdvance - cbLeft;
364}
365
366RTGCPHYS virtioCoreSgBufGetNextSegment(PVIRTIOSGBUF pGcSgBuf, size_t *pcbSeg)
367{
368 AssertReturn(pGcSgBuf, 0);
369 AssertPtrReturn(pcbSeg, 0);
370
371 if (!*pcbSeg)
372 *pcbSeg = pGcSgBuf->cbSegLeft;
373
374 return virtioCoreSgBufGet(pGcSgBuf, pcbSeg);
375}
376
377#ifdef LOG_ENABLED
378
379/**
380 * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to
381 * control enabling of logging efficiently.
382 *
383 * @param pv pointer to buffer to dump contents of
384 * @param cb count of characters to dump from buffer
385 * @param uBase base address of per-row address prefixing of hex output
386 * @param pszTitle Optional title. If present displays title that lists
387 * provided text with value of cb to indicate size next to it.
388 */
389void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle)
390{
391 if (pszTitle)
392 Log(("%s [%d bytes]:\n", pszTitle, cb));
393 for (uint32_t row = 0; row < RT_MAX(1, (cb / 16) + 1) && row * 16 < cb; row++)
394 {
395 Log(("%04x: ", row * 16 + uBase)); /* line address */
396 for (uint8_t col = 0; col < 16; col++)
397 {
398 uint32_t idx = row * 16 + col;
399 if (idx >= cb)
400 Log(("-- %s", (col + 1) % 8 ? "" : " "));
401 else
402 Log(("%02x %s", pv[idx], (col + 1) % 8 ? "" : " "));
403 }
404 for (uint32_t idx = row * 16; idx < row * 16 + 16; idx++)
405 Log(("%c", (idx >= cb) ? ' ' : (pv[idx] >= 0x20 && pv[idx] <= 0x7e ? pv[idx] : '.')));
406 Log(("\n"));
407 }
408 Log(("\n"));
409 RT_NOREF2(uBase, pv);
410}
411
412#endif /* LOG_ENABLED */
413
414/**
415 * Log memory-mapped I/O input or output value.
416 *
417 * This is designed to be invoked by macros that can make contextual assumptions
418 * (e.g. implicitly derive MACRO parameters from the invoking function). It is exposed
419 * for the VirtIO client doing the device-specific implementation in order to log in a
420 * similar fashion accesses to the device-specific MMIO configuration structure. Macros
421 * that leverage this function are found in virtioCommonCfgAccessed() and can be
422 * used as an example of how to use this effectively for the device-specific
423 * code.
424 *
425 * @param pszFunc To avoid displaying this function's name via __FUNCTION__ or LogFunc()
426 * @param pszMember Name of struct member
427 * @param pv pointer to value
428 * @param cb size of value
429 * @param uOffset offset into member where value starts
430 * @param fWrite True if write I/O
431 * @param fHasIndex True if the member is indexed
432 * @param idx The index if fHasIndex
433 */
434void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
435 const void *pv, uint32_t cb, uint32_t uOffset, int fWrite,
436 int fHasIndex, uint32_t idx)
437{
438 if (!LogIs6Enabled())
439 return;
440
441 char szIdx[16];
442 if (fHasIndex)
443 RTStrPrintf(szIdx, sizeof(szIdx), "[%d]", idx);
444 else
445 szIdx[0] = '\0';
446
447 if (cb == 1 || cb == 2 || cb == 4 || cb == 8)
448 {
449 char szDepiction[64];
450 size_t cchDepiction;
451 if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */
452 cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s[%d:%d]",
453 pszMember, szIdx, uOffset, uOffset + cb - 1);
454 else
455 cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s", pszMember, szIdx);
456
457 /* padding */
458 if (cchDepiction < 30)
459 szDepiction[cchDepiction++] = ' ';
460 while (cchDepiction < 30)
461 szDepiction[cchDepiction++] = '.';
462 szDepiction[cchDepiction] = '\0';
463
464 RTUINT64U uValue;
465 uValue.u = 0;
466 memcpy(uValue.au8, pv, cb);
467 Log6(("%s: Guest %s %s %#0*RX64\n",
468 pszFunc, fWrite ? "wrote" : "read ", szDepiction, 2 + cb * 2, uValue.u));
469 }
470 else /* odd number or oversized access, ... log inline hex-dump style */
471 {
472 Log6(("%s: Guest %s %s%s[%d:%d]: %.*Rhxs\n",
473 pszFunc, fWrite ? "wrote" : "read ", pszMember,
474 szIdx, uOffset, uOffset + cb, cb, pv));
475 }
476 RT_NOREF2(fWrite, pszFunc);
477}
478
479
480/**
481 * Makes the MMIO-mapped Virtio uDeviceStatus registers non-cryptic
482 */
483DECLINLINE(void) virtioLogDeviceStatus(uint8_t bStatus)
484{
485 if (bStatus == 0)
486 Log6(("RESET"));
487 else
488 {
489 int primed = 0;
490 if (bStatus & VIRTIO_STATUS_ACKNOWLEDGE)
491 Log6(("%sACKNOWLEDGE", primed++ ? "" : ""));
492 if (bStatus & VIRTIO_STATUS_DRIVER)
493 Log6(("%sDRIVER", primed++ ? " | " : ""));
494 if (bStatus & VIRTIO_STATUS_FEATURES_OK)
495 Log6(("%sFEATURES_OK", primed++ ? " | " : ""));
496 if (bStatus & VIRTIO_STATUS_DRIVER_OK)
497 Log6(("%sDRIVER_OK", primed++ ? " | " : ""));
498 if (bStatus & VIRTIO_STATUS_FAILED)
499 Log6(("%sFAILED", primed++ ? " | " : ""));
500 if (bStatus & VIRTIO_STATUS_DEVICE_NEEDS_RESET)
501 Log6(("%sNEEDS_RESET", primed++ ? " | " : ""));
502 (void)primed;
503 }
504}
505
506#ifdef IN_RING3
507/**
508 * Allocate client context for client to work with VirtIO-provided with queue
509 *
510 * @param pVirtio Pointer to the shared virtio state.
511 * @param idxQueue Queue number
512 * @param pcszName Name to give queue
513 *
514 * @returns VBox status code.
515 */
516int virtioCoreR3QueueAttach(PVIRTIOCORE pVirtio, uint16_t idxQueue, const char *pcszName)
517{
518 LogFunc(("%s\n", pcszName));
519 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
520 pVirtq->uAvailIdx = 0;
521 pVirtq->uUsedIdx = 0;
522 pVirtq->fEventThresholdReached = false;
523 RTStrCopy(pVirtq->szVirtqName, sizeof(pVirtq->szVirtqName), pcszName);
524 return VINF_SUCCESS;
525}
526#endif /* IN_RING3 */
527
528/**
529 * See API comments in header file for description
530 */
531int virtioQueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue)
532{
533 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
534 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
535
536 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[idxQueue],
537 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
538
539 if (virtioCoreQueueIsEmpty(pVirtio->pDevIns, pVirtio, idxQueue))
540 return VERR_NOT_AVAILABLE;
541
542 Log2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx));
543 pVirtq->uAvailIdx++;
544
545 return VINF_SUCCESS;
546}
547
548/**
549 * Check if the associated queue is empty
550 *
551 * @param pDevIns The device instance (for reading).
552 * @param pVirtio Pointer to the shared virtio state.
553 * @param idxQueue Queue number
554 *
555 * @retval true Queue is empty or unavailable.
556 * @retval false Queue is available and has entries
557 */
558bool virtioCoreQueueIsEmpty(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
559{
560 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
561 return virtqIsEmpty(pDevIns, pVirtio, idxQueue);
562 return true;
563}
564
565#ifdef IN_RING3
566
567
568int virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue,
569 uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain)
570{
571 AssertReturn(ppDescChain, VERR_INVALID_PARAMETER);
572
573 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
574
575 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
576
577 PVIRTIOSGSEG paSegsIn = (PVIRTIOSGSEG)RTMemAlloc(VIRTQ_MAX_SIZE * sizeof(VIRTIOSGSEG));
578 AssertReturn(paSegsIn, VERR_NO_MEMORY);
579
580 PVIRTIOSGSEG paSegsOut = (PVIRTIOSGSEG)RTMemAlloc(VIRTQ_MAX_SIZE * sizeof(VIRTIOSGSEG));
581 AssertReturn(paSegsOut, VERR_NO_MEMORY);
582
583 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[idxQueue],
584 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
585
586 uint16_t uDescIdx = uHeadIdx;
587
588 Log3Func(("%s DESC CHAIN: (head) desc_idx=%u\n", pVirtq->szVirtqName, uHeadIdx));
589 RT_NOREF(pVirtq);
590
591 VIRTQ_DESC_T desc;
592
593 uint32_t cbIn = 0, cbOut = 0, cSegsIn = 0, cSegsOut = 0;
594
595 do
596 {
597 PVIRTIOSGSEG pSeg;
598
599 /*
600 * Malicious guests may go beyond paSegsIn or paSegsOut boundaries by linking
601 * several descriptors into a loop. Since there is no legitimate way to get a sequences of
602 * linked descriptors exceeding the total number of descriptors in the ring (see @bugref{8620}),
603 * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
604 */
605 if (cSegsIn + cSegsOut >= VIRTQ_MAX_SIZE)
606 {
607 static volatile uint32_t s_cMessages = 0;
608 static volatile uint32_t s_cThreshold = 1;
609 if (ASMAtomicIncU32(&s_cMessages) == ASMAtomicReadU32(&s_cThreshold))
610 {
611 LogRelMax(64, ("Too many linked descriptors; check if the guest arranges descriptors in a loop.\n"));
612 if (ASMAtomicReadU32(&s_cMessages) != 1)
613 LogRelMax(64, ("(the above error has occured %u times so far)\n", ASMAtomicReadU32(&s_cMessages)));
614 ASMAtomicWriteU32(&s_cThreshold, ASMAtomicReadU32(&s_cThreshold) * 10);
615 }
616 break;
617 }
618 RT_UNTRUSTED_VALIDATED_FENCE();
619
620 virtioReadDesc(pDevIns, pVirtio, idxQueue, uDescIdx, &desc);
621
622 if (desc.fFlags & VIRTQ_DESC_F_WRITE)
623 {
624 Log3Func(("%s IN desc_idx=%u seg=%u addr=%RGp cb=%u\n", QUEUE_NAME(pVirtio, idxQueue), uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
625 cbIn += desc.cb;
626 pSeg = &(paSegsIn[cSegsIn++]);
627 }
628 else
629 {
630 Log3Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", QUEUE_NAME(pVirtio, idxQueue), uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb));
631 cbOut += desc.cb;
632 pSeg = &(paSegsOut[cSegsOut++]);
633 }
634
635 pSeg->pGcSeg = desc.GCPhysBuf;
636 pSeg->cbSeg = desc.cb;
637
638 uDescIdx = desc.uDescIdxNext;
639 } while (desc.fFlags & VIRTQ_DESC_F_NEXT);
640
641 PVIRTIOSGBUF pSgPhysIn = (PVIRTIOSGBUF)RTMemAllocZ(sizeof(VIRTIOSGBUF));
642 AssertReturn(pSgPhysIn, VERR_NO_MEMORY);
643
644 virtioCoreSgBufInit(pSgPhysIn, paSegsIn, cSegsIn);
645
646 PVIRTIOSGBUF pSgPhysOut = (PVIRTIOSGBUF)RTMemAllocZ(sizeof(VIRTIOSGBUF));
647 AssertReturn(pSgPhysOut, VERR_NO_MEMORY);
648
649 virtioCoreSgBufInit(pSgPhysOut, paSegsOut, cSegsOut);
650
651 PVIRTIO_DESC_CHAIN_T pDescChain = (PVIRTIO_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTIO_DESC_CHAIN_T));
652 AssertReturn(pDescChain, VERR_NO_MEMORY);
653
654 pDescChain->uHeadIdx = uHeadIdx;
655 pDescChain->cbPhysSend = cbOut;
656 pDescChain->pSgPhysSend = pSgPhysOut;
657 pDescChain->cbPhysReturn = cbIn;
658 pDescChain->pSgPhysReturn = pSgPhysIn;
659 *ppDescChain = pDescChain;
660
661 Log3Func(("%s -- segs OUT: %u (%u bytes) IN: %u (%u bytes) --\n", pVirtq->szVirtqName, cSegsOut, cbOut, cSegsIn, cbIn));
662
663 return VINF_SUCCESS;
664}
665
666/**
667 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor
668 * chain into its OUT (to device) and IN to guest components.
669 *
670 * Additionally it converts the OUT desc chain data to a contiguous virtual
671 * memory buffer for easy consumption by the caller. The caller must return the
672 * descriptor chain pointer via virtioCoreR3QueuePut() and then call virtioCoreQueueSync()
673 * at some point to return the data to the guest and complete the transaction.
674 *
675 * @param pDevIns The device instance.
676 * @param pVirtio Pointer to the shared virtio state.
677 * @param idxQueue Queue number
678 * @param fRemove flags whether to remove desc chain from queue (false = peek)
679 * @param ppDescChain Address to store pointer to descriptor chain that contains the
680 * pre-processed transaction information pulled from the virtq.
681 *
682 * @returns VBox status code:
683 * @retval VINF_SUCCESS Success
684 * @retval VERR_INVALID_STATE VirtIO not in ready state (asserted).
685 * @retval VERR_NOT_AVAILABLE If the queue is empty.
686 */
687int virtioCoreR3QueueGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue,
688 PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove)
689{
690 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
691
692 if (virtqIsEmpty(pDevIns, pVirtio, idxQueue))
693 return VERR_NOT_AVAILABLE;
694
695 uint16_t uHeadIdx = virtioReadAvailDescIdx(pDevIns, pVirtio, idxQueue, pVirtq->uAvailIdx);
696
697 if (fRemove)
698 pVirtq->uAvailIdx++;
699
700 int rc = virtioCoreR3DescChainGet(pDevIns, pVirtio, idxQueue, uHeadIdx, ppDescChain);
701 return rc;
702}
703
704/**
705 * Returns data to the guest to complete a transaction initiated by virtQueueGet().
706 *
707 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments
708 * and a pointer to the descriptor chain context originally derived from the pulled
709 * queue entry, and this function will write the virtual memory s/g buffer into the
710 * guest's physical memory free the descriptor chain. The caller handles the freeing
711 * (as needed) of the virtual memory buffer.
712 *
713 * @note This does a write-ahead to the used ring of the guest's queue. The data
714 * written won't be seen by the guest until the next call to virtioCoreQueueSync()
715 *
716 *
717 * @param pDevIns The device instance (for reading).
718 * @param pVirtio Pointer to the shared virtio state.
719 * @param idxQueue Queue number
720 *
721 * @param pSgVirtReturn Points toscatter-gather buffer of virtual memory
722 * segments the caller is returning to the guest.
723 *
724 * @param pDescChain This contains the context of the scatter-gather
725 * buffer originally pulled from the queue.
726 *
727 * @param fFence If true, put up copy fence (memory barrier) after
728 * copying to guest phys. mem.
729 *
730 * @returns VBox status code.
731 * @retval VINF_SUCCESS Success
732 * @retval VERR_INVALID_STATE VirtIO not in ready state
733 * @retval VERR_NOT_AVAILABLE Queue is empty
734 */
735int virtioCoreR3QueuePut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn,
736 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence)
737{
738 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
739 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
740 PVIRTIOSGBUF pSgPhysReturn = pDescChain->pSgPhysReturn;
741
742 AssertMsgReturn(IS_DRIVER_OK(pVirtio) /*&& pVirtio->uQueueEnable[idxQueue]*/,
743 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
744
745 Log3Func(("Copying client data to %s, desc chain (head desc_idx %d)\n",
746 QUEUE_NAME(pVirtio, idxQueue), virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue)));
747
748 /*
749 * Copy s/g buf (virtual memory) to guest phys mem (IN direction). This virtual memory
750 * block will be small (fixed portion of response header + sense buffer area or
751 * control commands or error return values)... The bulk of req data xfers to phys mem
752 * is handled by client */
753
754 size_t cbCopy = 0;
755 size_t cbRemain = RTSgBufCalcTotalLength(pSgVirtReturn);
756 virtioCoreSgBufReset(pSgPhysReturn); /* Reset ptr because req data may have already been written */
757 while (cbRemain)
758 {
759 PVIRTIOSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg];
760 uint64_t dstSgStart = (uint64_t)paSeg->pGcSeg;
761 uint64_t dstSgLen = (uint64_t)paSeg->cbSeg;
762 uint64_t dstSgCur = (uint64_t)pSgPhysReturn->pGcSegCur;
763 cbCopy = RT_MIN((uint64_t)pSgVirtReturn->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart));
764 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->pGcSegCur, pSgVirtReturn->pvSegCur, cbCopy);
765 RTSgBufAdvance(pSgVirtReturn, cbCopy);
766 virtioCoreSgBufAdvance(pSgPhysReturn, cbCopy);
767 cbRemain -= cbCopy;
768 }
769
770 if (fFence)
771 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); /* needed? */
772
773 /* If this write-ahead crosses threshold where the driver wants to get an event flag it */
774 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
775 if (pVirtq->uUsedIdx == virtioReadAvailUsedEvent(pDevIns, pVirtio, idxQueue))
776 pVirtq->fEventThresholdReached = true;
777
778 Assert(!(cbCopy >> 32));
779
780 /*
781 * Place used buffer's descriptor in used ring but don't update used ring's slot index.
782 * That will be done with a subsequent client call to virtioCoreQueueSync() */
783 virtioWriteUsedElem(pDevIns, pVirtio, idxQueue, pVirtq->uUsedIdx++, pDescChain->uHeadIdx, (uint32_t)cbCopy);
784
785 Log2Func((".... Copied %zu bytes to %u byte buffer, residual=%zu\n",
786 cbCopy, pDescChain->cbPhysReturn, pDescChain->cbPhysReturn - cbCopy));
787
788 Log6Func(("Write ahead used_idx=%u, %s used_idx=%u\n",
789 pVirtq->uUsedIdx, QUEUE_NAME(pVirtio, idxQueue), virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue)));
790
791 RTMemFree((void *)pDescChain->pSgPhysSend->paSegs);
792 RTMemFree(pDescChain->pSgPhysSend);
793 RTMemFree((void *)pSgPhysReturn->paSegs);
794 RTMemFree(pSgPhysReturn);
795 RTMemFree(pDescChain);
796
797 return VINF_SUCCESS;
798}
799
800#endif /* IN_RING3 */
801
802/**
803 * Updates the indicated virtq's "used ring" descriptor index to match the
804 * current write-head index, thus exposing the data added to the used ring by all
805 * virtioCoreR3QueuePut() calls since the last sync. This should be called after one or
806 * more virtioCoreR3QueuePut() calls to inform the guest driver there is data in the queue.
807 * Explicit notifications (e.g. interrupt or MSI-X) will be sent to the guest,
808 * depending on VirtIO features negotiated and conditions, otherwise the guest
809 * will detect the update by polling. (see VirtIO 1.0
810 * specification, Section 2.4 "Virtqueues").
811 *
812 * @param pDevIns The device instance.
813 * @param pVirtio Pointer to the shared virtio state.
814 * @param idxQueue Queue number
815 *
816 * @returns VBox status code.
817 * @retval VINF_SUCCESS Success
818 * @retval VERR_INVALID_STATE VirtIO not in ready state
819 */
820int virtioCoreQueueSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
821{
822 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
823 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
824
825 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[idxQueue],
826 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
827
828 Log6Func(("Updating %s used_idx from %u to %u\n",
829 QUEUE_NAME(pVirtio, idxQueue), virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue), pVirtq->uUsedIdx));
830
831 virtioWriteUsedRingIdx(pDevIns, pVirtio, idxQueue, pVirtq->uUsedIdx);
832 virtioNotifyGuestDriver(pDevIns, pVirtio, idxQueue, false);
833
834 return VINF_SUCCESS;
835}
836
837#ifdef IN_RING3
838/**
839 */
840static void virtioR3QueueNotified(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint16_t idxQueue, uint16_t uNotifyIdx)
841{
842 /* See VirtIO 1.0, section 4.1.5.2 It implies that idxQueue and uNotifyIdx should match.
843 * Disregarding this notification may cause throughput to stop, however there's no way to know
844 * which was queue was intended for wake-up if the two parameters disagree. */
845
846 AssertMsg(uNotifyIdx == idxQueue,
847 ("Guest kicked virtq %d's notify addr w/non-corresponding virtq idx %d\n",
848 idxQueue, uNotifyIdx));
849 RT_NOREF(uNotifyIdx);
850
851 AssertReturnVoid(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
852 Log6Func(("%s\n", pVirtio->virtqState[idxQueue].szVirtqName));
853
854 /* Inform client */
855 pVirtioCC->pfnQueueNotified(pVirtio, pVirtioCC, idxQueue);
856}
857#endif /* IN_RING3 */
858
859/**
860 * Trigger MSI-X or INT# interrupt to notify guest of data added to used ring of
861 * the specified virtq, depending on the interrupt configuration of the device
862 * and depending on negotiated and realtime constraints flagged by the guest driver.
863 *
864 * See VirtIO 1.0 specification (section 2.4.7).
865 *
866 * @param pDevIns The device instance.
867 * @param pVirtio Pointer to the shared virtio state.
868 * @param idxQueue Queue to check for guest interrupt handling preference
869 * @param fForce Overrides idxQueue, forcing notification regardless of driver's
870 * notification preferences. This is a safeguard to prevent
871 * stalls upon resuming the VM. VirtIO 1.0 specification Section 4.1.5.5
872 * indicates spurious interrupts are harmless to guest driver's state,
873 * as they only cause the guest driver to [re]scan queues for work to do.
874 */
875static void virtioNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fForce)
876{
877
878 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
879 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
880
881 AssertMsgReturnVoid(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"));
882 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
883 {
884 if (pVirtq->fEventThresholdReached)
885 {
886 virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uQueueMsixVector[idxQueue], fForce);
887 pVirtq->fEventThresholdReached = false;
888 return;
889 }
890 Log6Func(("...skipping interrupt: VIRTIO_F_EVENT_IDX set but threshold not reached\n"));
891 }
892 else
893 {
894 /** If guest driver hasn't suppressed interrupts, interrupt */
895 if (fForce || !(virtioReadUsedFlags(pDevIns, pVirtio, idxQueue) & VIRTQ_AVAIL_F_NO_INTERRUPT))
896 {
897 virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uQueueMsixVector[idxQueue], fForce);
898 return;
899 }
900 Log6Func(("...skipping interrupt. Guest flagged VIRTQ_AVAIL_F_NO_INTERRUPT for queue\n"));
901 }
902}
903
904/**
905 * Raise interrupt or MSI-X
906 *
907 * @param pDevIns The device instance.
908 * @param pVirtio Pointer to the shared virtio state.
909 * @param uCause Interrupt cause bit mask to set in PCI ISR port.
910 * @param uVec MSI-X vector, if enabled
911 * @param uForce True of out-of-band
912 */
913static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixVector, bool fForce)
914{
915 if (fForce)
916 Log6Func(("reason: resumed after suspend\n"));
917 else
918 if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
919 Log6Func(("reason: buffer added to 'used' ring.\n"));
920 else
921 if (uCause == VIRTIO_ISR_DEVICE_CONFIG)
922 Log6Func(("reason: device config change\n"));
923
924 if (!pVirtio->fMsiSupport)
925 {
926 pVirtio->uISR |= uCause;
927 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
928 }
929 else if (uMsixVector != VIRTIO_MSI_NO_VECTOR)
930 PDMDevHlpPCISetIrq(pDevIns, uMsixVector, 1);
931 return VINF_SUCCESS;
932}
933
934/**
935 * Lower interrupt (Called when guest reads ISR and when resetting)
936 *
937 * @param pDevIns The device instance.
938 */
939static void virtioLowerInterrupt(PPDMDEVINS pDevIns, uint16_t uMsixVector)
940{
941 PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
942 if (!pVirtio->fMsiSupport)
943 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
944 else if (uMsixVector != VIRTIO_MSI_NO_VECTOR)
945 PDMDevHlpPCISetIrq(pDevIns, pVirtio->uMsixConfig, PDM_IRQ_LEVEL_LOW);
946}
947
948static void virtioResetQueue(PVIRTIOCORE pVirtio, uint16_t idxQueue)
949{
950 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
951 PVIRTQSTATE pVirtQ = &pVirtio->virtqState[idxQueue];
952 pVirtQ->uAvailIdx = 0;
953 pVirtQ->uUsedIdx = 0;
954 pVirtio->uQueueEnable[idxQueue] = false;
955 pVirtio->uQueueSize[idxQueue] = VIRTQ_MAX_SIZE;
956 pVirtio->uQueueNotifyOff[idxQueue] = idxQueue;
957 pVirtio->uQueueMsixVector[idxQueue] = idxQueue + 2;
958
959 if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */
960 pVirtio->uQueueMsixVector[idxQueue] = VIRTIO_MSI_NO_VECTOR;
961
962 virtioLowerInterrupt(pVirtio->pDevIns, pVirtio->uQueueMsixVector[idxQueue]);
963}
964
965static void virtioResetDevice(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio)
966{
967 Log2Func(("\n"));
968 pVirtio->uDeviceFeaturesSelect = 0;
969 pVirtio->uDriverFeaturesSelect = 0;
970 pVirtio->uConfigGeneration = 0;
971 pVirtio->uDeviceStatus = 0;
972 pVirtio->uISR = 0;
973
974 if (!pVirtio->fMsiSupport)
975 virtioLowerInterrupt(pDevIns, 0);
976 else
977 {
978 virtioLowerInterrupt(pDevIns, pVirtio->uMsixConfig);
979 for (int i = 0; i < VIRTQ_MAX_CNT; i++)
980 {
981 virtioLowerInterrupt(pDevIns, pVirtio->uQueueMsixVector[i]);
982 pVirtio->uQueueMsixVector[i];
983 }
984 }
985
986 if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */
987 pVirtio->uMsixConfig = VIRTIO_MSI_NO_VECTOR;
988
989 for (uint16_t idxQueue = 0; idxQueue < VIRTQ_MAX_CNT; idxQueue++)
990 virtioResetQueue(pVirtio, idxQueue);
991}
992
993/**
994 * Initiate orderly reset procedure. This is an exposed API for clients that might need it.
995 * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)
996 */
997void virtioCoreResetAll(PVIRTIOCORE pVirtio)
998{
999 LogFunc(("\n"));
1000 pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
1001 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
1002 {
1003 pVirtio->fGenUpdatePending = true;
1004 virtioKick(pVirtio->pDevIns, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false /* fForce */);
1005 }
1006}
1007
1008#ifdef IN_RING3
1009/**
1010 * Invoked by this implementation when guest driver resets the device.
1011 * The driver itself will not until the device has read the status change.
1012 */
1013static void virtioGuestR3WasReset(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC)
1014{
1015 LogFunc(("Guest reset the device\n"));
1016
1017 /* Let the client know */
1018 pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, 0);
1019 virtioResetDevice(pDevIns, pVirtio);
1020}
1021#endif /* IN_RING3 */
1022
1023/**
1024 * Handle accesses to Common Configuration capability
1025 *
1026 * @returns VBox status code
1027 *
1028 * @param pDevIns The device instance.
1029 * @param pVirtio Pointer to the shared virtio state.
1030 * @param pVirtioCC Pointer to the current context virtio state.
1031 * @param fWrite Set if write access, clear if read access.
1032 * @param offCfg The common configuration capability offset.
1033 * @param cb Number of bytes to read or write
1034 * @param pv Pointer to location to write to or read from
1035 */
1036static int virtioCommonCfgAccessed(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC,
1037 int fWrite, uint32_t offCfg, unsigned cb, void *pv)
1038{
1039/**
1040 * This macro resolves to boolean true if the implied parameters, offCfg and cb,
1041 * match the field offset and size of a field in the Common Cfg struct, (or if
1042 * it is a 64-bit field, if it accesses either 32-bit part as a 32-bit access)
1043 * This is mandated by section 4.1.3.1 of the VirtIO 1.0 specification)
1044 *
1045 * @param member Member of VIRTIO_PCI_COMMON_CFG_T
1046 * @param offCfg Implied parameter: Offset into VIRTIO_PCI_COMMON_CFG_T
1047 * @param cb Implied parameter: Number of bytes to access
1048 * @result true or false
1049 */
1050#define MATCH_COMMON_CFG(member) \
1051 ( ( RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member) == 8 \
1052 && ( offCfg == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \
1053 || offCfg == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) + sizeof(uint32_t)) \
1054 && cb == sizeof(uint32_t)) \
1055 || ( offCfg == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \
1056 && cb == RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member)) )
1057
1058#ifdef LOG_ENABLED
1059# define LOG_COMMON_CFG_ACCESS(member, a_offIntra) \
1060 virtioCoreLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
1061 pv, cb, a_offIntra, fWrite, false, 0);
1062# define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, a_offIntra) \
1063 virtioCoreLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
1064 pv, cb, a_offIntra, fWrite, true, idx);
1065#else
1066# define LOG_COMMON_CFG_ACCESS(member, a_offIntra) do { } while (0)
1067# define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, a_offIntra) do { } while (0)
1068#endif
1069
1070#define COMMON_CFG_ACCESSOR(member) \
1071 do \
1072 { \
1073 uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
1074 if (fWrite) \
1075 memcpy((char *)&pVirtio->member + offIntra, (const char *)pv, cb); \
1076 else \
1077 memcpy(pv, (const char *)&pVirtio->member + offIntra, cb); \
1078 LOG_COMMON_CFG_ACCESS(member, offIntra); \
1079 } while(0)
1080
1081#define COMMON_CFG_ACCESSOR_INDEXED(member, idx) \
1082 do \
1083 { \
1084 uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
1085 if (fWrite) \
1086 memcpy((char *)&pVirtio->member[idx] + offIntra, pv, cb); \
1087 else \
1088 memcpy(pv, (const char *)&pVirtio->member[idx] + offIntra, cb); \
1089 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, offIntra); \
1090 } while(0)
1091
1092#define COMMON_CFG_ACCESSOR_READONLY(member) \
1093 do \
1094 { \
1095 uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
1096 if (fWrite) \
1097 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \
1098 else \
1099 { \
1100 memcpy(pv, (const char *)&pVirtio->member + offIntra, cb); \
1101 LOG_COMMON_CFG_ACCESS(member, offIntra); \
1102 } \
1103 } while(0)
1104
1105#define COMMON_CFG_ACCESSOR_INDEXED_READONLY(member, idx) \
1106 do \
1107 { \
1108 uint32_t offIntra = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
1109 if (fWrite) \
1110 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s[%d]\n", #member, idx)); \
1111 else \
1112 { \
1113 memcpy(pv, (char const *)&pVirtio->member[idx] + offIntra, cb); \
1114 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, offIntra); \
1115 } \
1116 } while(0)
1117
1118
1119 int rc = VINF_SUCCESS;
1120 uint64_t val;
1121 if (MATCH_COMMON_CFG(uDeviceFeatures))
1122 {
1123 if (fWrite) /* Guest WRITE pCommonCfg>uDeviceFeatures */
1124 {
1125 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.device_feature\n"));
1126 return VINF_SUCCESS;
1127 }
1128 else /* Guest READ pCommonCfg->uDeviceFeatures */
1129 {
1130 switch (pVirtio->uDeviceFeaturesSelect)
1131 {
1132 case 0:
1133 val = pVirtio->uDeviceFeatures & UINT32_C(0xffffffff);
1134 memcpy(pv, &val, cb);
1135 LOG_COMMON_CFG_ACCESS(uDeviceFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures));
1136 break;
1137 case 1:
1138 val = pVirtio->uDeviceFeatures >> 32;
1139 memcpy(pv, &val, cb);
1140 LOG_COMMON_CFG_ACCESS(uDeviceFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures) + 4);
1141 break;
1142 default:
1143 LogFunc(("Guest read uDeviceFeatures with out of range selector (%#x), returning 0\n",
1144 pVirtio->uDeviceFeaturesSelect));
1145 return VINF_IOM_MMIO_UNUSED_00;
1146 }
1147 }
1148 }
1149 else if (MATCH_COMMON_CFG(uDriverFeatures))
1150 {
1151 if (fWrite) /* Guest WRITE pCommonCfg->udriverFeatures */
1152 {
1153 switch (pVirtio->uDriverFeaturesSelect)
1154 {
1155 case 0:
1156 memcpy(&pVirtio->uDriverFeatures, pv, cb);
1157 LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures));
1158 break;
1159 case 1:
1160 memcpy((char *)&pVirtio->uDriverFeatures + sizeof(uint32_t), pv, cb);
1161 LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures) + 4);
1162 break;
1163 default:
1164 LogFunc(("Guest wrote uDriverFeatures with out of range selector (%#x), returning 0\n",
1165 pVirtio->uDriverFeaturesSelect));
1166 return VINF_SUCCESS;
1167 }
1168 }
1169 else /* Guest READ pCommonCfg->udriverFeatures */
1170 {
1171 switch (pVirtio->uDriverFeaturesSelect)
1172 {
1173 case 0:
1174 val = pVirtio->uDriverFeatures & 0xffffffff;
1175 memcpy(pv, &val, cb);
1176 LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures));
1177 break;
1178 case 1:
1179 val = (pVirtio->uDriverFeatures >> 32) & 0xffffffff;
1180 memcpy(pv, &val, cb);
1181 LOG_COMMON_CFG_ACCESS(uDriverFeatures, offCfg - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures) + 4);
1182 break;
1183 default:
1184 LogFunc(("Guest read uDriverFeatures with out of range selector (%#x), returning 0\n",
1185 pVirtio->uDriverFeaturesSelect));
1186 return VINF_IOM_MMIO_UNUSED_00;
1187 }
1188 }
1189 }
1190 else if (MATCH_COMMON_CFG(uNumQueues))
1191 {
1192 if (fWrite)
1193 {
1194 Log2Func(("Guest attempted to write readonly virtio_pci_common_cfg.num_queues\n"));
1195 return VINF_SUCCESS;
1196 }
1197 else
1198 {
1199 *(uint16_t *)pv = VIRTQ_MAX_CNT;
1200 LOG_COMMON_CFG_ACCESS(uNumQueues, 0);
1201 }
1202 }
1203 else if (MATCH_COMMON_CFG(uDeviceStatus))
1204 {
1205 if (fWrite) /* Guest WRITE pCommonCfg->uDeviceStatus */
1206 {
1207 uint8_t const fNewStatus = *(uint8_t *)pv;
1208 Log6Func(("Guest wrote uDeviceStatus (%#x, was %#x, change #%x) ................ (",
1209 fNewStatus, pVirtio->uDeviceStatus, fNewStatus ^ pVirtio->uDeviceStatus));
1210 virtioLogDeviceStatus(fNewStatus);
1211 Log6((")\n"));
1212
1213 /* If the status changed or we were reset, we need to go to ring-3 as
1214 it requires notifying the parent device. */
1215 bool const fStatusChanged = (fNewStatus & VIRTIO_STATUS_DRIVER_OK)
1216 != (pVirtio->uPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
1217#ifndef IN_RING3
1218 if (fStatusChanged || fNewStatus == 0)
1219 {
1220 Log6Func(("=>ring3\n"));
1221 return VINF_IOM_R3_MMIO_WRITE;
1222 }
1223#endif
1224 pVirtio->uDeviceStatus = fNewStatus;
1225
1226#ifdef IN_RING3
1227 /*
1228 * Notify client only if status actually changed from last time and when we're reset.
1229 */
1230 if (pVirtio->uDeviceStatus == 0)
1231 virtioGuestR3WasReset(pDevIns, pVirtio, pVirtioCC);
1232 if (fStatusChanged)
1233 pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, fNewStatus & VIRTIO_STATUS_DRIVER_OK);
1234#endif
1235 /*
1236 * Save the current status for the next write so we can see what changed.
1237 */
1238 pVirtio->uPrevDeviceStatus = pVirtio->uDeviceStatus;
1239 }
1240 else /* Guest READ pCommonCfg->uDeviceStatus */
1241 {
1242 Log6Func(("Guest read uDeviceStatus ................ ("));
1243 *(uint8_t *)pv = pVirtio->uDeviceStatus;
1244 virtioLogDeviceStatus(pVirtio->uDeviceStatus);
1245 Log6((")\n"));
1246 }
1247 }
1248 else
1249 if (MATCH_COMMON_CFG(uMsixConfig))
1250 COMMON_CFG_ACCESSOR(uMsixConfig);
1251 else
1252 if (MATCH_COMMON_CFG(uDeviceFeaturesSelect))
1253 COMMON_CFG_ACCESSOR(uDeviceFeaturesSelect);
1254 else
1255 if (MATCH_COMMON_CFG(uDriverFeaturesSelect))
1256 COMMON_CFG_ACCESSOR(uDriverFeaturesSelect);
1257 else
1258 if (MATCH_COMMON_CFG(uConfigGeneration))
1259 COMMON_CFG_ACCESSOR_READONLY(uConfigGeneration);
1260 else
1261 if (MATCH_COMMON_CFG(uQueueSelect))
1262 COMMON_CFG_ACCESSOR(uQueueSelect);
1263 else
1264 if (MATCH_COMMON_CFG(uQueueSize))
1265 COMMON_CFG_ACCESSOR_INDEXED(uQueueSize, pVirtio->uQueueSelect);
1266 else
1267 if (MATCH_COMMON_CFG(uQueueMsixVector))
1268 COMMON_CFG_ACCESSOR_INDEXED(uQueueMsixVector, pVirtio->uQueueSelect);
1269 else
1270 if (MATCH_COMMON_CFG(uQueueEnable))
1271 COMMON_CFG_ACCESSOR_INDEXED(uQueueEnable, pVirtio->uQueueSelect);
1272 else
1273 if (MATCH_COMMON_CFG(uQueueNotifyOff))
1274 COMMON_CFG_ACCESSOR_INDEXED_READONLY(uQueueNotifyOff, pVirtio->uQueueSelect);
1275 else
1276 if (MATCH_COMMON_CFG(aGCPhysQueueDesc))
1277 COMMON_CFG_ACCESSOR_INDEXED(aGCPhysQueueDesc, pVirtio->uQueueSelect);
1278 else
1279 if (MATCH_COMMON_CFG(aGCPhysQueueAvail))
1280 COMMON_CFG_ACCESSOR_INDEXED(aGCPhysQueueAvail, pVirtio->uQueueSelect);
1281 else
1282 if (MATCH_COMMON_CFG(aGCPhysQueueUsed))
1283 COMMON_CFG_ACCESSOR_INDEXED(aGCPhysQueueUsed, pVirtio->uQueueSelect);
1284 else
1285 {
1286 Log2Func(("Bad guest %s access to virtio_pci_common_cfg: offCfg=%#x (%d), cb=%d\n",
1287 fWrite ? "write" : "read ", offCfg, offCfg, cb));
1288 return fWrite ? VINF_SUCCESS : VINF_IOM_MMIO_UNUSED_00;
1289 }
1290
1291#undef COMMON_CFG_ACCESSOR_READONLY
1292#undef COMMON_CFG_ACCESSOR_INDEXED_READONLY
1293#undef COMMON_CFG_ACCESSOR_INDEXED
1294#undef COMMON_CFG_ACCESSOR
1295#undef LOG_COMMON_CFG_ACCESS_INDEXED
1296#undef LOG_COMMON_CFG_ACCESS
1297#undef MATCH_COMMON_CFG
1298#ifndef IN_RING3
1299 RT_NOREF(pDevIns, pVirtioCC);
1300#endif
1301 return rc;
1302}
1303
1304/**
1305 * @callback_method_impl{FNIOMMMIONEWREAD,
1306 * Memory mapped I/O Handler for PCI Capabilities read operations.}
1307 *
1308 * This MMIO handler specifically supports the VIRTIO_PCI_CAP_PCI_CFG capability defined
1309 * in the VirtIO 1.0 specification, section 4.1.4.7, and as such is limited to cb == 1, cb == 2, or cb==4 type reads.
1310 *
1311 */
1312static DECLCALLBACK(VBOXSTRICTRC) virtioMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1313{
1314 PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
1315 PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
1316 AssertReturn(cb == 1 || cb == 2 || cb == 4, VERR_INVALID_PARAMETER);
1317 Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser);
1318
1319 uint32_t offIntra;
1320 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocDeviceCap))
1321 {
1322#ifdef IN_RING3
1323 /*
1324 * Callback to client to manage device-specific configuration.
1325 */
1326 VBOXSTRICTRC rcStrict = pVirtioCC->pfnDevCapRead(pDevIns, offIntra, pv, cb);
1327
1328 /*
1329 * Additionally, anytime any part of the device-specific configuration (which our client maintains)
1330 * is READ it needs to be checked to see if it changed since the last time any part was read, in
1331 * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1)
1332 */
1333 bool fDevSpecificFieldChanged = !!memcmp(pVirtioCC->pbDevSpecificCfg + offIntra,
1334 pVirtioCC->pbPrevDevSpecificCfg + offIntra,
1335 RT_MIN(cb, pVirtioCC->cbDevSpecificCfg - offIntra));
1336
1337 memcpy(pVirtioCC->pbPrevDevSpecificCfg, pVirtioCC->pbDevSpecificCfg, pVirtioCC->cbDevSpecificCfg);
1338
1339 if (pVirtio->fGenUpdatePending || fDevSpecificFieldChanged)
1340 {
1341 ++pVirtio->uConfigGeneration;
1342 Log6Func(("Bumped cfg. generation to %d because %s%s\n",
1343 pVirtio->uConfigGeneration,
1344 fDevSpecificFieldChanged ? "<dev cfg changed> " : "",
1345 pVirtio->fGenUpdatePending ? "<update was pending>" : ""));
1346 pVirtio->fGenUpdatePending = false;
1347 }
1348
1349 if (pVirtio->fMsiSupport)
1350 PDMDevHlpPCISetIrq(pDevIns, pVirtio->uMsixConfig, PDM_IRQ_LEVEL_LOW);
1351
1352 return rcStrict;
1353#else
1354 return VINF_IOM_R3_MMIO_READ;
1355#endif
1356 }
1357
1358 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocCommonCfgCap))
1359 return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, false /* fWrite */, offIntra, cb, pv);
1360
1361 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocIsrCap) && cb == sizeof(uint8_t))
1362 {
1363 *(uint8_t *)pv = pVirtio->uISR;
1364 Log6Func(("Read and clear ISR\n"));
1365 pVirtio->uISR = 0; /* VirtIO specification requires reads of ISR to clear it */
1366 virtioLowerInterrupt(pDevIns, 0);
1367 return VINF_SUCCESS;
1368 }
1369
1370 ASSERT_GUEST_MSG_FAILED(("Bad read access to mapped capabilities region: off=%RGp cb=%u\n", off, cb));
1371 return VINF_IOM_MMIO_UNUSED_00;
1372}
1373
1374/**
1375 * @callback_method_impl{FNIOMMMIONEWREAD,
1376 * Memory mapped I/O Handler for PCI Capabilities write operations.}
1377 *
1378 * This MMIO handler specifically supports the VIRTIO_PCI_CAP_PCI_CFG capability defined
1379 * in the VirtIO 1.0 specification, section 4.1.4.7, and as such is limited to cb == 1, cb == 2, or cb==4 type writes.
1380 */
1381static DECLCALLBACK(VBOXSTRICTRC) virtioMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1382{
1383 PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
1384 PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
1385
1386 AssertReturn(cb == 1 || cb == 2 || cb == 4, VERR_INVALID_PARAMETER);
1387
1388 Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser);
1389
1390 uint32_t offIntra;
1391 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocDeviceCap))
1392 {
1393#ifdef IN_RING3
1394 /*
1395 * Pass this MMIO write access back to the client to handle
1396 */
1397 return pVirtioCC->pfnDevCapWrite(pDevIns, offIntra, pv, cb);
1398#else
1399 return VINF_IOM_R3_MMIO_WRITE;
1400#endif
1401 }
1402
1403 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocCommonCfgCap))
1404 return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, true /* fWrite */, offIntra, cb, (void *)pv);
1405
1406 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocIsrCap) && cb == sizeof(uint8_t))
1407 {
1408 pVirtio->uISR = *(uint8_t *)pv;
1409 Log6Func(("Setting uISR = 0x%02x (virtq interrupt: %d, dev confg interrupt: %d)\n",
1410 pVirtio->uISR & 0xff,
1411 pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
1412 RT_BOOL(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG)));
1413 return VINF_SUCCESS;
1414 }
1415
1416 /* This *should* be guest driver dropping index of a new descriptor in avail ring */
1417 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocNotifyCap) && cb == sizeof(uint16_t))
1418 {
1419#ifdef IN_RING3
1420 virtioR3QueueNotified(pVirtio, pVirtioCC, offIntra / VIRTIO_NOTIFY_OFFSET_MULTIPLIER, *(uint16_t *)pv);
1421 return VINF_SUCCESS;
1422#else
1423 return VINF_IOM_R3_MMIO_WRITE;
1424#endif
1425 }
1426
1427 ASSERT_GUEST_MSG_FAILED(("Bad write access to mapped capabilities region: off=%RGp pv=%#p{%.*Rhxs} cb=%u\n", off, pv, cb, pv, cb));
1428 return VINF_SUCCESS;
1429}
1430
1431#ifdef IN_RING3
1432
1433/**
1434 * @callback_method_impl{FNPCICONFIGREAD}
1435 */
1436static DECLCALLBACK(VBOXSTRICTRC) virtioR3PciConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
1437 uint32_t uAddress, unsigned cb, uint32_t *pu32Value)
1438{
1439 PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
1440 PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
1441 RT_NOREF(pPciDev);
1442
1443 LogFlowFunc(("pDevIns=%p pPciDev=%p uAddress=%#x cb=%u pu32Value=%p\n",
1444 pDevIns, pPciDev, uAddress, cb, pu32Value));
1445 if (uAddress == pVirtio->uPciCfgDataOff)
1446 {
1447 /*
1448 * VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability
1449 * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
1450 * (the virtio_pci_cfg_cap capability), and access data items.
1451 */
1452 uint32_t uLength = pVirtioCC->pPciCfgCap->pciCap.uLength;
1453 uint32_t uOffset = pVirtioCC->pPciCfgCap->pciCap.uOffset;
1454 uint8_t uBar = pVirtioCC->pPciCfgCap->pciCap.uBar;
1455
1456 if ( (uLength != 1 && uLength != 2 && uLength != 4)
1457 || cb != uLength
1458 || uBar != VIRTIO_REGION_PCI_CAP)
1459 {
1460 ASSERT_GUEST_MSG_FAILED(("Guest read virtio_pci_cfg_cap.pci_cfg_data using mismatching config. Ignoring\n"));
1461 *pu32Value = UINT32_MAX;
1462 return VINF_SUCCESS;
1463 }
1464
1465 VBOXSTRICTRC rcStrict = virtioMmioRead(pDevIns, pVirtio, uOffset, pu32Value, cb);
1466 Log2Func(("virtio: Guest read virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%d, length=%d, result=%d -> %Rrc\n",
1467 uBar, uOffset, uLength, *pu32Value, VBOXSTRICTRC_VAL(rcStrict)));
1468 return rcStrict;
1469 }
1470 return VINF_PDM_PCI_DO_DEFAULT;
1471}
1472
1473/**
1474 * @callback_method_impl{FNPCICONFIGWRITE}
1475 */
1476static DECLCALLBACK(VBOXSTRICTRC) virtioR3PciConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
1477 uint32_t uAddress, unsigned cb, uint32_t u32Value)
1478{
1479 PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
1480 PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
1481 RT_NOREF(pPciDev);
1482
1483 LogFlowFunc(("pDevIns=%p pPciDev=%p uAddress=%#x cb=%u u32Value=%#x\n", pDevIns, pPciDev, uAddress, cb, u32Value));
1484 if (uAddress == pVirtio->uPciCfgDataOff)
1485 {
1486 /* VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability
1487 * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
1488 * (the virtio_pci_cfg_cap capability), and access data items. */
1489
1490 uint32_t uLength = pVirtioCC->pPciCfgCap->pciCap.uLength;
1491 uint32_t uOffset = pVirtioCC->pPciCfgCap->pciCap.uOffset;
1492 uint8_t uBar = pVirtioCC->pPciCfgCap->pciCap.uBar;
1493
1494 if ( (uLength != 1 && uLength != 2 && uLength != 4)
1495 || cb != uLength
1496 || uBar != VIRTIO_REGION_PCI_CAP)
1497 {
1498 ASSERT_GUEST_MSG_FAILED(("Guest write virtio_pci_cfg_cap.pci_cfg_data using mismatching config. Ignoring\n"));
1499 return VINF_SUCCESS;
1500 }
1501
1502 VBOXSTRICTRC rcStrict = virtioMmioWrite(pDevIns, pVirtio, uOffset, &u32Value, cb);
1503 Log2Func(("Guest wrote virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%x, length=%x, value=%d -> %Rrc\n",
1504 uBar, uOffset, uLength, u32Value, VBOXSTRICTRC_VAL(rcStrict)));
1505 return rcStrict;
1506 }
1507 return VINF_PDM_PCI_DO_DEFAULT;
1508}
1509
1510
1511/*********************************************************************************************************************************
1512* Saved state. *
1513*********************************************************************************************************************************/
1514
1515/**
1516 * Called from the FNSSMDEVSAVEEXEC function of the device.
1517 *
1518 * @param pVirtio Pointer to the shared virtio state.
1519 * @param pHlp The ring-3 device helpers.
1520 * @param pSSM The saved state handle.
1521 * @returns VBox status code.
1522 */
1523int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
1524{
1525 LogFunc(("\n"));
1526 pHlp->pfnSSMPutU64(pSSM, VIRTIO_SAVEDSTATE_MARKER);
1527 pHlp->pfnSSMPutU32(pSSM, VIRTIO_SAVEDSTATE_VERSION);
1528
1529 pHlp->pfnSSMPutBool(pSSM, pVirtio->fGenUpdatePending);
1530 pHlp->pfnSSMPutU8(pSSM, pVirtio->uDeviceStatus);
1531 pHlp->pfnSSMPutU8(pSSM, pVirtio->uConfigGeneration);
1532 pHlp->pfnSSMPutU8(pSSM, pVirtio->uPciCfgDataOff);
1533 pHlp->pfnSSMPutU8(pSSM, pVirtio->uISR);
1534 pHlp->pfnSSMPutU16(pSSM, pVirtio->uQueueSelect);
1535 pHlp->pfnSSMPutU32(pSSM, pVirtio->uDeviceFeaturesSelect);
1536 pHlp->pfnSSMPutU32(pSSM, pVirtio->uDriverFeaturesSelect);
1537 pHlp->pfnSSMPutU64(pSSM, pVirtio->uDriverFeatures);
1538
1539 for (uint32_t i = 0; i < VIRTQ_MAX_CNT; i++)
1540 {
1541 pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueDesc[i]);
1542 pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueAvail[i]);
1543 pHlp->pfnSSMPutGCPhys64(pSSM, pVirtio->aGCPhysQueueUsed[i]);
1544 pHlp->pfnSSMPutU16(pSSM, pVirtio->uQueueNotifyOff[i]);
1545 pHlp->pfnSSMPutU16(pSSM, pVirtio->uQueueMsixVector[i]);
1546 pHlp->pfnSSMPutU16(pSSM, pVirtio->uQueueEnable[i]);
1547 pHlp->pfnSSMPutU16(pSSM, pVirtio->uQueueSize[i]);
1548 pHlp->pfnSSMPutU16(pSSM, pVirtio->virtqState[i].uAvailIdx);
1549 pHlp->pfnSSMPutU16(pSSM, pVirtio->virtqState[i].uUsedIdx);
1550 int rc = pHlp->pfnSSMPutMem(pSSM, pVirtio->virtqState[i].szVirtqName, 32);
1551 AssertRCReturn(rc, rc);
1552 }
1553
1554 return VINF_SUCCESS;
1555}
1556
1557/**
1558 * Called from the FNSSMDEVLOADEXEC function of the device.
1559 *
1560 * @param pVirtio Pointer to the shared virtio state.
1561 * @param pHlp The ring-3 device helpers.
1562 * @param pSSM The saved state handle.
1563 * @returns VBox status code.
1564 */
1565int virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
1566{
1567 LogFunc(("\n"));
1568 /*
1569 * Check the marker and (embedded) version number.
1570 */
1571 uint64_t uMarker = 0;
1572 int rc = pHlp->pfnSSMGetU64(pSSM, &uMarker);
1573 AssertRCReturn(rc, rc);
1574 if (uMarker != VIRTIO_SAVEDSTATE_MARKER)
1575 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
1576 N_("Expected marker value %#RX64 found %#RX64 instead"),
1577 VIRTIO_SAVEDSTATE_MARKER, uMarker);
1578 uint32_t uVersion = 0;
1579 rc = pHlp->pfnSSMGetU32(pSSM, &uVersion);
1580 AssertRCReturn(rc, rc);
1581 if (uVersion != VIRTIO_SAVEDSTATE_VERSION)
1582 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
1583 N_("Unsupported virtio version: %u"), uVersion);
1584 /*
1585 * Load the state.
1586 */
1587 pHlp->pfnSSMGetBool(pSSM, &pVirtio->fGenUpdatePending);
1588 pHlp->pfnSSMGetU8(pSSM, &pVirtio->uDeviceStatus);
1589 pHlp->pfnSSMGetU8(pSSM, &pVirtio->uConfigGeneration);
1590 pHlp->pfnSSMGetU8(pSSM, &pVirtio->uPciCfgDataOff);
1591 pHlp->pfnSSMGetU8(pSSM, &pVirtio->uISR);
1592 pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueSelect);
1593 pHlp->pfnSSMGetU32(pSSM, &pVirtio->uDeviceFeaturesSelect);
1594 pHlp->pfnSSMGetU32(pSSM, &pVirtio->uDriverFeaturesSelect);
1595 pHlp->pfnSSMGetU64(pSSM, &pVirtio->uDriverFeatures);
1596
1597 for (uint32_t i = 0; i < VIRTQ_MAX_CNT; i++)
1598 {
1599 pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueDesc[i]);
1600 pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueAvail[i]);
1601 pHlp->pfnSSMGetGCPhys64(pSSM, &pVirtio->aGCPhysQueueUsed[i]);
1602 pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueNotifyOff[i]);
1603 pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueMsixVector[i]);
1604 pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueEnable[i]);
1605 pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueSize[i]);
1606 pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[i].uAvailIdx);
1607 pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[i].uUsedIdx);
1608 rc = pHlp->pfnSSMGetMem(pSSM, pVirtio->virtqState[i].szVirtqName,
1609 sizeof(pVirtio->virtqState[i].szVirtqName));
1610 AssertRCReturn(rc, rc);
1611 }
1612
1613 return VINF_SUCCESS;
1614}
1615
1616
1617/*********************************************************************************************************************************
1618* Device Level *
1619*********************************************************************************************************************************/
1620
1621/**
1622 * This must be called by the client to handle VM state changes
1623 * after the client takes care of its device-specific tasks for the state change.
1624 * (i.e. Reset, suspend, power-off, resume)
1625 *
1626 * @param pDevIns The device instance.
1627 * @param pVirtio Pointer to the shared virtio state.
1628 */
1629void virtioCoreR3VmStateChanged(PVIRTIOCORE pVirtio, VIRTIOVMSTATECHANGED enmState)
1630{
1631 LogFunc(("State changing to %s\n",
1632 virtioCoreGetStateChangeText(enmState)));
1633
1634 switch(enmState)
1635 {
1636 case kvirtIoVmStateChangedReset:
1637 virtioCoreResetAll(pVirtio);
1638 break;
1639 case kvirtIoVmStateChangedSuspend:
1640 break;
1641 case kvirtIoVmStateChangedPowerOff:
1642 break;
1643 case kvirtIoVmStateChangedResume:
1644 virtioNotifyGuestDriver(pVirtio->pDevIns, pVirtio, 0 /* idxQueue */, true /* fForce */);
1645 break;
1646 default:
1647 LogRelFunc(("Bad enum value"));
1648 return;
1649 }
1650}
1651
1652/**
1653 * This should be called from PDMDEVREGR3::pfnDestruct.
1654 *
1655 * @param pDevIns The device instance.
1656 * @param pVirtio Pointer to the shared virtio state.
1657 * @param pVirtioCC Pointer to the ring-3 virtio state.
1658 */
1659void virtioCoreR3Term(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC)
1660{
1661 if (pVirtioCC->pbPrevDevSpecificCfg)
1662 {
1663 RTMemFree(pVirtioCC->pbPrevDevSpecificCfg);
1664 pVirtioCC->pbPrevDevSpecificCfg = NULL;
1665 }
1666 RT_NOREF(pDevIns, pVirtio);
1667}
1668
1669
1670/**
1671 * Setup PCI device controller and Virtio state
1672 *
1673 * This should be called from PDMDEVREGR3::pfnConstruct.
1674 *
1675 * @param pDevIns The device instance.
1676 * @param pVirtio Pointer to the shared virtio state. This
1677 * must be the first member in the shared
1678 * device instance data!
1679 * @param pVirtioCC Pointer to the ring-3 virtio state. This
1680 * must be the first member in the ring-3
1681 * device instance data!
1682 * @param pPciParams Values to populate industry standard PCI Configuration Space data structure
1683 * @param pcszInstance Device instance name (format-specifier)
1684 * @param fDevSpecificFeatures VirtIO device-specific features offered by
1685 * client
1686 * @param cbDevSpecificCfg Size of virtio_pci_device_cap device-specific struct
1687 * @param pvDevSpecificCfg Address of client's dev-specific
1688 * configuration struct.
1689 */
1690int virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, PVIRTIOPCIPARAMS pPciParams,
1691 const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg)
1692{
1693 /*
1694 * The pVirtio state must be the first member of the shared device instance
1695 * data, otherwise we cannot get our bearings in the PCI configuration callbacks.
1696 */
1697 AssertLogRelReturn(pVirtio == PDMINS_2_DATA(pDevIns, PVIRTIOCORE), VERR_STATE_CHANGED);
1698 AssertLogRelReturn(pVirtioCC == PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC), VERR_STATE_CHANGED);
1699
1700 pVirtio->pDevIns = pDevIns;
1701
1702 /*
1703 * Caller must initialize these.
1704 */
1705 AssertReturn(pVirtioCC->pfnStatusChanged, VERR_INVALID_POINTER);
1706 AssertReturn(pVirtioCC->pfnQueueNotified, VERR_INVALID_POINTER);
1707 AssertReturn(pVirtioCC->pfnDevCapRead, VERR_INVALID_POINTER);
1708 AssertReturn(pVirtioCC->pfnDevCapWrite, VERR_INVALID_POINTER);
1709
1710#if 0 /* Until pdmR3DvHlp_PCISetIrq() impl is fixed and Assert that limits vec to 0 is removed */
1711# ifdef VBOX_WITH_MSI_DEVICES
1712 pVirtio->fMsiSupport = true;
1713# endif
1714#endif
1715
1716 /*
1717 * The host features offered include both device-specific features
1718 * and reserved feature bits (device independent)
1719 */
1720 pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1
1721 | VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED
1722 | fDevSpecificFeatures;
1723
1724 RTStrCopy(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszInstance);
1725
1726 pVirtio->uDeviceStatus = 0;
1727 pVirtioCC->cbDevSpecificCfg = cbDevSpecificCfg;
1728 pVirtioCC->pbDevSpecificCfg = (uint8_t *)pvDevSpecificCfg;
1729 pVirtioCC->pbPrevDevSpecificCfg = (uint8_t *)RTMemDup(pvDevSpecificCfg, cbDevSpecificCfg);
1730 AssertLogRelReturn(pVirtioCC->pbPrevDevSpecificCfg, VERR_NO_MEMORY);
1731
1732 /* Set PCI config registers (assume 32-bit mode) */
1733 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
1734 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
1735
1736 PDMPciDevSetRevisionId(pPciDev, DEVICE_PCI_REVISION_ID_VIRTIO);
1737 PDMPciDevSetVendorId(pPciDev, DEVICE_PCI_VENDOR_ID_VIRTIO);
1738 PDMPciDevSetSubSystemVendorId(pPciDev, DEVICE_PCI_VENDOR_ID_VIRTIO);
1739 PDMPciDevSetDeviceId(pPciDev, pPciParams->uDeviceId);
1740 PDMPciDevSetClassBase(pPciDev, pPciParams->uClassBase);
1741 PDMPciDevSetClassSub(pPciDev, pPciParams->uClassSub);
1742 PDMPciDevSetClassProg(pPciDev, pPciParams->uClassProg);
1743 PDMPciDevSetSubSystemId(pPciDev, pPciParams->uSubsystemId);
1744 PDMPciDevSetInterruptLine(pPciDev, pPciParams->uInterruptLine);
1745 PDMPciDevSetInterruptPin(pPciDev, pPciParams->uInterruptPin);
1746
1747 /* Register PCI device */
1748 int rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
1749 if (RT_FAILURE(rc))
1750 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register PCI Device")); /* can we put params in this error? */
1751
1752 rc = PDMDevHlpPCIInterceptConfigAccesses(pDevIns, pPciDev, virtioR3PciConfigRead, virtioR3PciConfigWrite);
1753 AssertRCReturn(rc, rc);
1754
1755
1756 /* Construct & map PCI vendor-specific capabilities for virtio host negotiation with guest driver */
1757
1758 /* The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T)
1759 * as a mandatory but suboptimal alternative interface to host device capabilities, facilitating
1760 * access the memory of any BAR. If the guest uses it (the VirtIO driver on Linux doesn't),
1761 * Unlike Common, Notify, ISR and Device capabilities, it is accessed directly via PCI Config region.
1762 * therefore does not contribute to the capabilities region (BAR) the other capabilities use.
1763 */
1764#define CFG_ADDR_2_IDX(addr) ((uint8_t)(((uintptr_t)(addr) - (uintptr_t)&pPciDev->abConfig[0])))
1765#define SET_PCI_CAP_LOC(a_pPciDev, a_pCfg, a_LocCap, a_uMmioLengthAlign) \
1766 do { \
1767 (a_LocCap).offMmio = (a_pCfg)->uOffset; \
1768 (a_LocCap).cbMmio = RT_ALIGN_T((a_pCfg)->uLength, a_uMmioLengthAlign, uint16_t); \
1769 (a_LocCap).offPci = (uint16_t)(uintptr_t)((uint8_t *)(a_pCfg) - &(a_pPciDev)->abConfig[0]); \
1770 (a_LocCap).cbPci = (a_pCfg)->uCapLen; \
1771 } while (0)
1772
1773 PVIRTIO_PCI_CAP_T pCfg;
1774 uint32_t cbRegion = 0;
1775
1776 /* Common capability (VirtIO 1.0 spec, section 4.1.4.3) */
1777 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[0x40];
1778 pCfg->uCfgType = VIRTIO_PCI_CAP_COMMON_CFG;
1779 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
1780 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T);
1781 pCfg->uCapNext = CFG_ADDR_2_IDX(pCfg) + pCfg->uCapLen;
1782 pCfg->uBar = VIRTIO_REGION_PCI_CAP;
1783 pCfg->uOffset = RT_ALIGN_32(0, 4); /* reminder, in case someone changes offset */
1784 pCfg->uLength = sizeof(VIRTIO_PCI_COMMON_CFG_T);
1785 cbRegion += pCfg->uLength;
1786 SET_PCI_CAP_LOC(pPciDev, pCfg, pVirtio->LocCommonCfgCap, 2);
1787 pVirtioCC->pCommonCfgCap = pCfg;
1788
1789 /*
1790 * Notify capability (VirtIO 1.0 spec, section 4.1.4.4). Note: uLength is based the choice
1791 * of this implementation that each queue's uQueueNotifyOff is set equal to (QueueSelect) ordinal
1792 * value of the queue
1793 */
1794 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext];
1795 pCfg->uCfgType = VIRTIO_PCI_CAP_NOTIFY_CFG;
1796 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
1797 pCfg->uCapLen = sizeof(VIRTIO_PCI_NOTIFY_CAP_T);
1798 pCfg->uCapNext = CFG_ADDR_2_IDX(pCfg) + pCfg->uCapLen;
1799 pCfg->uBar = VIRTIO_REGION_PCI_CAP;
1800 pCfg->uOffset = pVirtioCC->pCommonCfgCap->uOffset + pVirtioCC->pCommonCfgCap->uLength;
1801 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 4);
1802
1803
1804 pCfg->uLength = VIRTQ_MAX_CNT * VIRTIO_NOTIFY_OFFSET_MULTIPLIER + 2; /* will change in VirtIO 1.1 */
1805 cbRegion += pCfg->uLength;
1806 SET_PCI_CAP_LOC(pPciDev, pCfg, pVirtio->LocNotifyCap, 1);
1807 pVirtioCC->pNotifyCap = (PVIRTIO_PCI_NOTIFY_CAP_T)pCfg;
1808 pVirtioCC->pNotifyCap->uNotifyOffMultiplier = VIRTIO_NOTIFY_OFFSET_MULTIPLIER;
1809
1810 /* ISR capability (VirtIO 1.0 spec, section 4.1.4.5)
1811 *
1812 * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. Example/diagram
1813 * of spec shows it as a 32-bit field with upper bits 'reserved'
1814 * Will take spec words more literally than the diagram for now.
1815 */
1816 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext];
1817 pCfg->uCfgType = VIRTIO_PCI_CAP_ISR_CFG;
1818 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
1819 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T);
1820 pCfg->uCapNext = CFG_ADDR_2_IDX(pCfg) + pCfg->uCapLen;
1821 pCfg->uBar = VIRTIO_REGION_PCI_CAP;
1822 pCfg->uOffset = pVirtioCC->pNotifyCap->pciCap.uOffset + pVirtioCC->pNotifyCap->pciCap.uLength;
1823 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 4);
1824 pCfg->uLength = sizeof(uint8_t);
1825 cbRegion += pCfg->uLength;
1826 SET_PCI_CAP_LOC(pPciDev, pCfg, pVirtio->LocIsrCap, 4);
1827 pVirtioCC->pIsrCap = pCfg;
1828
1829 /* PCI Cfg capability (VirtIO 1.0 spec, section 4.1.4.7)
1830 * This capability doesn't get page-MMIO mapped. Instead uBar, uOffset and uLength are intercepted
1831 * by trapping PCI configuration I/O and get modulated by consumers to locate fetch and read/write
1832 * values from any region. NOTE: The linux driver not only doesn't use this feature, it will not
1833 * even list it as present if uLength isn't non-zero and also 4-byte-aligned as the linux driver is
1834 * initializing.
1835 */
1836 pVirtio->uPciCfgDataOff = pCfg->uCapNext + RT_OFFSETOF(VIRTIO_PCI_CFG_CAP_T, uPciCfgData);
1837 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext];
1838 pCfg->uCfgType = VIRTIO_PCI_CAP_PCI_CFG;
1839 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
1840 pCfg->uCapLen = sizeof(VIRTIO_PCI_CFG_CAP_T);
1841 pCfg->uCapNext = (pVirtio->fMsiSupport || pVirtioCC->pbDevSpecificCfg) ? CFG_ADDR_2_IDX(pCfg) + pCfg->uCapLen : 0;
1842 pCfg->uBar = 0;
1843 pCfg->uOffset = 0;
1844 pCfg->uLength = 0;
1845 cbRegion += pCfg->uLength;
1846 SET_PCI_CAP_LOC(pPciDev, pCfg, pVirtio->LocPciCfgCap, 1);
1847 pVirtioCC->pPciCfgCap = (PVIRTIO_PCI_CFG_CAP_T)pCfg;
1848
1849 if (pVirtioCC->pbDevSpecificCfg)
1850 {
1851 /* Following capability (via VirtIO 1.0, section 4.1.4.6). Client defines the
1852 * device-specific config fields struct and passes size to this constructor */
1853 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext];
1854 pCfg->uCfgType = VIRTIO_PCI_CAP_DEVICE_CFG;
1855 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
1856 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T);
1857 pCfg->uCapNext = pVirtio->fMsiSupport ? CFG_ADDR_2_IDX(pCfg) + pCfg->uCapLen : 0;
1858 pCfg->uBar = VIRTIO_REGION_PCI_CAP;
1859 pCfg->uOffset = pVirtioCC->pIsrCap->uOffset + pVirtioCC->pIsrCap->uLength;
1860 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 4);
1861 pCfg->uLength = cbDevSpecificCfg;
1862 cbRegion += pCfg->uLength;
1863 SET_PCI_CAP_LOC(pPciDev, pCfg, pVirtio->LocDeviceCap, 4);
1864 pVirtioCC->pDeviceCap = pCfg;
1865 }
1866 else
1867 Assert(pVirtio->LocDeviceCap.cbMmio == 0 && pVirtio->LocDeviceCap.cbPci == 0);
1868
1869 if (pVirtio->fMsiSupport)
1870 {
1871 PDMMSIREG aMsiReg;
1872 RT_ZERO(aMsiReg);
1873 aMsiReg.iMsixCapOffset = pCfg->uCapNext;
1874 aMsiReg.iMsixNextOffset = 0;
1875 aMsiReg.iMsixBar = VIRTIO_REGION_MSIX_CAP;
1876 aMsiReg.cMsixVectors = VBOX_MSIX_MAX_ENTRIES;
1877 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg); /* see MsixR3init() */
1878 if (RT_FAILURE(rc))
1879 {
1880 /* See PDMDevHlp.cpp:pdmR3DevHlp_PCIRegisterMsi */
1881 LogFunc(("Failed to configure MSI-X (%Rrc). Reverting to INTx\n", rc));
1882 pVirtio->fMsiSupport = false;
1883 }
1884 else
1885 Log2Func(("Using MSI-X for guest driver notification\n"));
1886 }
1887 else
1888 LogFunc(("MSI-X not available for VBox, using INTx notification\n"));
1889
1890 /* Set offset to first capability and enable PCI dev capabilities */
1891 PDMPciDevSetCapabilityList(pPciDev, 0x40);
1892 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST);
1893
1894 /* Linux drivers/virtio/virtio_pci_modern.c tries to map at least a page for the
1895 * 'unknown' device-specific capability without querying the capability to figure
1896 * out size, so pad with an extra page
1897 */
1898 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + PAGE_SIZE, PAGE_SIZE),
1899 PCI_ADDRESS_SPACE_MEM, virtioMmioWrite, virtioMmioRead, pVirtio,
1900 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, "virtio-scsi MMIO",
1901 &pVirtio->hMmioPciCap);
1902 AssertLogRelRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register PCI Capabilities address space")));
1903
1904 return rc;
1905}
1906
1907#else /* !IN_RING3 */
1908
1909/**
1910 * Sets up the core ring-0/raw-mode virtio bits.
1911 *
1912 * @returns VBox status code.
1913 * @param pDevIns The device instance.
1914 * @param pVirtio Pointer to the shared virtio state. This must be the first
1915 * member in the shared device instance data!
1916 * @param pVirtioCC Pointer to the current context virtio state. This must be the
1917 * first member in the currenct context's device instance data!
1918 */
1919int virtioCoreRZInit(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC)
1920{
1921 AssertLogRelReturn(pVirtio == PDMINS_2_DATA(pDevIns, PVIRTIOCORE), VERR_STATE_CHANGED);
1922 AssertLogRelReturn(pVirtioCC == PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC), VERR_STATE_CHANGED);
1923
1924 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pVirtio->hMmioPciCap, virtioMmioWrite, virtioMmioRead, pVirtio);
1925 AssertRCReturn(rc, rc);
1926 return rc;
1927}
1928
1929#endif /* !IN_RING3 */
1930
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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