VirtualBox

source: vbox/trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h@ 81634

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

DevVirtioScsi,Virtio_1_0: A quick and superficial review of DevVirtioScsi. bugref:9218 bugref:9440

DevVirtioScsi.cpp:

  • Changed a bunch of 'virtioScsi' prefixes to 'virtioScsiR3' to prepare for ring-0 enabling of the code.
  • VIRTIO_IN_DIRECTION -> VIRTIO_IS_IN_DIRECTION because predicates should have a verb in them. Ditto for VIRTIO_OUT_DIRECTION.
  • Avoid the 'u' prefix when possible, e.g. s/uOffset/offConfig/, s/uIntraOffset/offIntra/, s/uSenseLen/cbSenseLen/, s/uAsyncTypesMask/fAsyncTypesMask/, ++.
  • The macros MATCH_SCSI_CONFIG, LOG_ACCESSOR, SCSI_CONFIG_ACCESSOR and SCSI_CONFIG_ACCESSOR_READONLY are local to virtioScsiCfgAccessed() and should be defined inside given the amount of non-parameters they access.
  • The unnecessary/compulsory initialization of variables, like 'rc' in virtioScsiDevCapRead and virtioScsiDevCapWrite, drives me nuts. It looks like there is code missing that would require 'rc' to be initialized.
  • Better if the 'pv' parameter to virtioScsiCfgAccessed is 'void *' rather than 'const void *'. Saves a lot of confusing casting inside the function.
  • virtioScsiDevCapRead/FNVIRTIODEVCAPREAD should not take a 'const' 'pv' parameter, that's just wrong.
  • Marking VIRTIOSCSI::szInstance and szQueueNames as 'const' doesn't buy us anything other than some confusing casts in the constructor. (szQueueNames should actually be aszQueueNames as it's an array of strings.)
  • SUBSCRIBABLE_EVENTS is missing vital parentheses, messing up the test in VIRTIOSCSI_T_AN_SUBSCRIBE (harmless, as logging only). See also MATCH_SCSI_CONFIG (also harmless). Parentheses around expression like that should be an automatic habit.
  • SUBSCRIBABLE_EVENTS is using '&' instead of '|', making the value zero.
  • The VIRTIOSCSIREQ::pbSense allocation must be zeroed (use the 'Z' allocator variant) to make sure the guest never see any old heap data. (The whole sense buffer is returned in virtioScsiR3IoReqFinish, rather than just the valid length.)
  • In case of VIRTIOSCSIREQ::pbSense allocation failure, pReq and pVirtqReq must be freed too.
  • Inconsistent parameter indention (when parameter list spills onto a new line). My preference is aligning to opening parenthesis. (E.g. 2nd RTStrPrintf in virtioScsiConstruct().)
  • Inconsistent identation of multiline macros (VIRTIOSCSI_HOST_SCSI_FEATURES_ALL vs VIRTIO_[IS_]IN_DIRECTION).
  • A couple of missing/incorrect indentations.
  • No need to split lines for VIRTIOCALLBACKS (just get used to about 130 columns wide sources).
  • Some unnecessary casts (RTStrPrintf((char *)pThis->szInstance,...), SCSI_CONFIG_ACCESSOR*, (size_t)pReq->cbSense[Alloc], ++).
  • Some unnecessary parentheses (SCSI_CONFIG_ACCESSOR*, ++).
  • VIRTIOSCSI_T_EVENTS_MISSED should use UINT32_C to be on the safe side.
  • There are three uses of LogIs2Enabled() that seem to need RT_NOREF, and the latter including several unnecessary variables. Put the whole block inside #ifdef LOG_ENABLED and dropping the expansive RT_NOREF.
  • Five 'sizeof(aReqSegs) / sizeof(RTSGSEG)' that would more easily be written 'RT_ELEMENTS(aReqSegs)'.
  • There shall be a space between 'switch' and the parenthesis.
  • VIRTIOSCSI_EVENT_T::uVirtioLun is a byte array and should be called 'abVirtioLun'. Ditto REQ_CMD_HDR_T::uVirtioLun, VIRTIOSCSI_CTRL_TMF_T::uScsiLun, VIRTIOSCSI_CTRL_AN_T::uScsiLun.
  • VIRTIOSCSIREQ::uSenseLen is easily confused with the 'cbSense' member, best to change the latter to 'cbSenseAlloc' (done) and then the former to 'cbSense' (not done).
  • REQ_CMD_HDR should be typedef 'REQ_CMD_HDR_T', as you're not consequentially using 'struct ...'). Ditto REQ_CMD_PI
  • pragma pack(1) is not needed on REQ_CMD_PI_T and REQ_RESP_HDR_T, so keep them out of it. Recomment using AssertCompileSize on structures like this.
  • struct, union and enum tags are either omitted or the same as the typedef name.
  • A few same-line doxygen comments missing the '<' markers and a couple the 2nd '*'.
  • Try keep the same-line doxygen comments aligned at a tab (4+) and avoid having them slide sideways in the next strcture or define block.
  • The WORKER structure is a bit too generic, renamed it VIRTIOSCSIWORKER. Arrays are plural, so s/aWorker/aWorkers/ too.
  • When casting an integer to a pointer you must go thru uintptr_t or intptr_t, not uint64_t like in the PDMDevHlpThreadCreate call, as type size matters some compilers.
  • Try avoid having Log statement gobble up unnecessary virtual space (a few lines as possible), as they are just noise making it hard to get an idea what's going on.
  • Always scope switch cases with variables in them (e.g virtioScsiSendEvent).
  • ++

Virtio_1_0*: A few preliminary changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.2 KB
Line 
1/* $Id: Virtio_1_0_impl.h 81634 2019-11-04 01:58:52Z vboxsync $ $Revision: 81634 $ $Date: 2019-11-04 01:58:52 +0000 (Mon, 04 Nov 2019) $ $Author: vboxsync $ */
2/** @file
3 * Virtio_1_0_impl.h - Virtio Declarations
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.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 VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h
19#define VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include "Virtio_1_0.h"
25
26/** @name Saved state versions.
27 * The saved state version is changed if either common or any of specific
28 * parts are changed. That is, it is perfectly possible that the version
29 * of saved vnet state will increase as a result of change in vblk structure
30 * for example.
31 */
32#define VIRTIO_SAVEDSTATE_VERSION 1
33/** @} */
34
35#define VIRTIO_F_VERSION_1 RT_BIT_64(32) /**< Required feature bit for 1.0 devices */
36
37#define VIRTIO_F_INDIRECT_DESC RT_BIT_64(28) /**< Allow descs to point to list of descs */
38#define VIRTIO_F_EVENT_IDX RT_BIT_64(29) /**< Allow notification disable for n elems */
39#define VIRTIO_F_RING_INDIRECT_DESC RT_BIT_64(28) /**< Doc bug: Goes under two names in spec */
40#define VIRTIO_F_RING_EVENT_IDX RT_BIT_64(29) /**< Doc bug: Goes under two names in spec */
41
42#define VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED ( 0 ) /**< TBD: Add VIRTIO_F_INDIRECT_DESC */
43
44#define VIRTIO_ISR_VIRTQ_INTERRUPT RT_BIT_32(0) /**< Virtq interrupt bit of ISR register */
45#define VIRTIO_ISR_DEVICE_CONFIG RT_BIT_32(1) /**< Device configuration changed bit of ISR */
46#define DEVICE_PCI_VENDOR_ID_VIRTIO 0x1AF4 /**< Guest driver locates dev via (mandatory) */
47#define DEVICE_PCI_REVISION_ID_VIRTIO 1 /**< VirtIO 1.0 non-transitional drivers >= 1 */
48
49/** Reserved (*negotiated*) Feature Bits (e.g. device independent features, VirtIO 1.0 spec,section 6) */
50
51#define VIRTIO_MSI_NO_VECTOR 0xffff /**< Vector value to disable MSI for queue */
52
53/** Device Status field constants (from Virtio 1.0 spec) */
54#define VIRTIO_STATUS_ACKNOWLEDGE 0x01 /**< Guest driver: Located this VirtIO device */
55#define VIRTIO_STATUS_DRIVER 0x02 /**< Guest driver: Can drive this VirtIO dev. */
56#define VIRTIO_STATUS_DRIVER_OK 0x04 /**< Guest driver: Driver set-up and ready */
57#define VIRTIO_STATUS_FEATURES_OK 0x08 /**< Guest driver: Feature negotiation done */
58#define VIRTIO_STATUS_FAILED 0x80 /**< Guest driver: Fatal error, gave up */
59#define VIRTIO_STATUS_DEVICE_NEEDS_RESET 0x40 /**< Device experienced unrecoverable error */
60
61/** @def Virtio Device PCI Capabilities type codes */
62#define VIRTIO_PCI_CAP_COMMON_CFG 1 /**< Common configuration PCI capability ID */
63#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 /**< Notification area PCI capability ID */
64#define VIRTIO_PCI_CAP_ISR_CFG 3 /**< ISR PCI capability id */
65#define VIRTIO_PCI_CAP_DEVICE_CFG 4 /**< Device-specific PCI cfg capability ID */
66#define VIRTIO_PCI_CAP_PCI_CFG 5 /**< PCI CFG capability ID */
67
68#define VIRTIO_PCI_CAP_ID_VENDOR 0x09 /**< Vendor-specific PCI CFG Device Cap. ID */
69
70/**
71 * The following is the PCI capability struct common to all VirtIO capability types
72 */
73typedef struct virtio_pci_cap
74{
75 /* All little-endian */
76 uint8_t uCapVndr; /**< Generic PCI field: PCI_CAP_ID_VNDR */
77 uint8_t uCapNext; /**< Generic PCI field: next ptr. */
78 uint8_t uCapLen; /**< Generic PCI field: capability length */
79 uint8_t uCfgType; /**< Identifies the structure. */
80 uint8_t uBar; /**< Where to find it. */
81 uint8_t uPadding[3]; /**< Pad to full dword. */
82 uint32_t uOffset; /**< Offset within bar. (L.E.) */
83 uint32_t uLength; /**< Length of struct, in bytes. (L.E.) */
84} VIRTIO_PCI_CAP_T, *PVIRTIO_PCI_CAP_T;
85
86/**
87 * Local implementation's usage context of a queue (e.g. not part of VirtIO specification)
88 */
89typedef struct VIRTQSTATE
90{
91 const char szVirtqName[32]; /**< Dev-specific name of queue */
92 uint16_t uAvailIdx; /**< Consumer's position in avail ring */
93 uint16_t uUsedIdx; /**< Consumer's position in used ring */
94 bool fEventThresholdReached; /**< Don't lose track while queueing ahead */
95} VIRTQSTATE, *PVIRTQSTATE;
96
97/**
98 * VirtIO 1.0 Capabilities' related MMIO-mapped structs:
99 *
100 * Note: virtio_pci_device_cap is dev-specific, implemented by client. Definition unknown here.
101 */
102typedef struct virtio_pci_common_cfg
103{
104 /* Per device fields */
105 uint32_t uDeviceFeaturesSelect; /**< RW (driver selects device features) */
106 uint32_t uDeviceFeatures; /**< RO (device reports features to driver) */
107 uint32_t uDriverFeaturesSelect; /**< RW (driver selects driver features) */
108 uint32_t uDriverFeatures; /**< RW (driver-accepted device features) */
109 uint16_t uMsixConfig; /**< RW (driver sets MSI-X config vector) */
110 uint16_t uNumQueues; /**< RO (device specifies max queues) */
111 uint8_t uDeviceStatus; /**< RW (driver writes device status, 0=reset) */
112 uint8_t uConfigGeneration; /**< RO (device changes when changing configs) */
113
114 /* Per virtqueue fields (as determined by uQueueSelect) */
115 uint16_t uQueueSelect; /**< RW (selects queue focus for these fields) */
116 uint16_t uQueueSize; /**< RW (queue size, 0 - 2^n) */
117 uint16_t uQueueMsixVector; /**< RW (driver selects MSI-X queue vector) */
118 uint16_t uQueueEnable; /**< RW (driver controls usability of queue) */
119 uint16_t uQueueNotifyOff; /**< RO (offset uto virtqueue; see spec) */
120 uint64_t pGcPhysQueueDesc; /**< RW (driver writes desc table phys addr) */
121 uint64_t pGcPhysQueueAvail; /**< RW (driver writes avail ring phys addr) */
122 uint64_t pGcPhysQueueUsed; /**< RW (driver writes used ring phys addr) */
123} VIRTIO_PCI_COMMON_CFG_T, *PVIRTIO_PCI_COMMON_CFG_T;
124
125typedef struct virtio_pci_notify_cap
126{
127 struct virtio_pci_cap pciCap; /**< Notification MMIO mapping capability */
128 uint32_t uNotifyOffMultiplier; /**< notify_off_multiplier */
129} VIRTIO_PCI_NOTIFY_CAP_T, *PVIRTIO_PCI_NOTIFY_CAP_T;
130
131typedef struct virtio_pci_cfg_cap
132{
133 struct virtio_pci_cap pciCap; /**< Cap. defines the BAR/off/len to access */
134 uint8_t uPciCfgData[4]; /**< I/O buf for above cap. */
135} VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T;
136
137/**
138 * The core (/common) state of the VirtIO PCI device
139 *
140 * @implements PDMILEDPORTS
141 */
142typedef struct VIRTIOSTATE
143{
144 char szInstance[16]; /**< Instance name, e.g. "VIRTIOSCSI0" */
145 R3PTRTYPE(void *) pClientContext; /**< Client callback returned on callbacks */
146
147 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3 */
148
149 RTGCPHYS pGcPhysPciCapBase; /**< Pointer to MMIO mapped capability data */
150 RTGCPHYS pGcPhysCommonCfg; /**< Pointer to MMIO mapped capability data */
151 RTGCPHYS pGcPhysNotifyCap; /**< Pointer to MMIO mapped capability data */
152 RTGCPHYS pGcPhysIsrCap; /**< Pointer to MMIO mapped capability data */
153 RTGCPHYS pGcPhysDeviceCap; /**< Pointer to MMIO mapped capability data */
154
155 RTGCPHYS pGcPhysQueueDesc[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q desc structs GUEST */
156 RTGCPHYS pGcPhysQueueAvail[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q avail structs GUEST */
157 RTGCPHYS pGcPhysQueueUsed[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q used structs GUEST */
158 uint16_t uQueueNotifyOff[VIRTQ_MAX_CNT]; /**< (MMIO) per-Q notify offset HOST */
159 uint16_t uQueueMsixVector[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue vector for MSI-X GUEST */
160 uint16_t uQueueEnable[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue enable GUEST */
161 uint16_t uQueueSize[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue size HOST/GUEST */
162 uint16_t uQueueSelect; /**< (MMIO) queue selector GUEST */
163 uint16_t padding;
164 uint64_t uDeviceFeatures; /**< (MMIO) Host features offered HOST */
165 uint64_t uDriverFeatures; /**< (MMIO) Host features accepted GUEST */
166 uint32_t uDeviceFeaturesSelect; /**< (MMIO) hi/lo select uDeviceFeatures GUEST */
167 uint32_t uDriverFeaturesSelect; /**< (MMIO) hi/lo select uDriverFeatures GUEST */
168 uint32_t uMsixConfig; /**< (MMIO) MSI-X vector GUEST */
169 uint32_t uNumQueues; /**< (MMIO) Actual number of queues GUEST */
170 uint8_t uDeviceStatus; /**< (MMIO) Device Status GUEST */
171 uint8_t uPrevDeviceStatus; /**< (MMIO) Prev Device Status GUEST */
172 uint8_t uConfigGeneration; /**< (MMIO) Device config sequencer HOST */
173
174 VIRTQSTATE virtqState[VIRTQ_MAX_CNT]; /**< Local impl-specific queue context */
175 VIRTIOCALLBACKS virtioCallbacks; /**< Callback vectors to client */
176
177 PVIRTIO_PCI_CFG_CAP_T pPciCfgCap; /**< Pointer to struct in configuration area */
178 PVIRTIO_PCI_NOTIFY_CAP_T pNotifyCap; /**< Pointer to struct in configuration area */
179 PVIRTIO_PCI_CAP_T pCommonCfgCap; /**< Pointer to struct in configuration area */
180 PVIRTIO_PCI_CAP_T pIsrCap; /**< Pointer to struct in configuration area */
181 PVIRTIO_PCI_CAP_T pDeviceCap; /**< Pointer to struct in configuration area */
182
183 uint32_t cbDevSpecificCfg; /**< Size of client's dev-specific config data */
184 void *pDevSpecificCfg; /**< Pointer to client's struct */
185 void *pPrevDevSpecificCfg; /**< Previous read dev-specific cfg of client */
186 bool fGenUpdatePending; /**< If set, update cfg gen after driver reads */
187 uint8_t uPciCfgDataOff;
188 uint8_t uISR; /**< Interrupt Status Register. */
189 uint8_t fMsiSupport;
190
191} VIRTIOSTATE, *PVIRTIOSTATE;
192
193/** virtq related flags */
194#define VIRTQ_DESC_F_NEXT 1 /**< Indicates this descriptor chains to next */
195#define VIRTQ_DESC_F_WRITE 2 /**< Marks buffer as write-only (default ro) */
196#define VIRTQ_DESC_F_INDIRECT 4 /**< Buffer is list of buffer descriptors */
197
198#define VIRTQ_USED_F_NO_NOTIFY 1 /**< Dev to Drv: Don't notify when buf added */
199#define VIRTQ_AVAIL_F_NO_INTERRUPT 1 /**< Drv to Dev: Don't notify when buf eaten */
200
201/**
202 * virtq related structs
203 * (struct names follow VirtIO 1.0 spec, typedef use VBox style)
204 */
205typedef struct virtq_desc
206{
207 uint64_t pGcPhysBuf; /**< addr GC Phys. address of buffer */
208 uint32_t cb; /**< len Buffer length */
209 uint16_t fFlags; /**< flags Buffer specific flags */
210 uint16_t uDescIdxNext; /**< next Idx set if VIRTIO_DESC_F_NEXT */
211} VIRTQ_DESC_T, *PVIRTQ_DESC_T;
212
213typedef struct virtq_avail
214{
215 uint16_t fFlags; /**< flags avail ring drv to dev flags */
216 uint16_t uIdx; /**< idx Index of next free ring slot */
217 uint16_t auRing[1]; /**< ring Ring: avail drv to dev bufs */
218 uint16_t uUsedEventIdx; /**< used_event (if VIRTQ_USED_F_EVENT_IDX) */
219} VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
220
221typedef struct virtq_used_elem
222{
223 uint32_t uDescIdx; /**< idx Start of used desc chain */
224 uint32_t cbElem; /**< len Total len of used desc chain */
225} VIRTQ_USED_ELEM_T;
226
227typedef struct virt_used
228{
229 uint16_t fFlags; /**< flags used ring host-to-guest flags */
230 uint16_t uIdx; /**< idx Index of next ring slot */
231 VIRTQ_USED_ELEM_T auRing[1]; /**< ring Ring: used dev to drv bufs */
232 uint16_t uAvailEventIdx; /**< avail_event if (VIRTQ_USED_F_EVENT_IDX) */
233} VIRTQ_USED_T, *PVIRTQ_USED_T;
234
235/**
236* This macro returns true if the implied parameter GCPhysAddr address and access length are
237* within the range of the mapped capability struct specified with the explicit parameters.
238*
239* Actual Parameters:
240* @oaram pPhysCapStruct - [input] Pointer to MMIO mapped capability struct
241* @param pCfgCap - [input] Pointer to capability in PCI configuration area
242* @param fMatched - [output] True if GCPhysAddr is within the physically mapped capability.
243*
244* Implied parameters:
245* @param GCPhysAddr - [input, implied] Physical address accessed (via MMIO callback)
246* @param cb - [input, implied] Number of bytes to access
247*/
248#define MATCH_VIRTIO_CAP_STRUCT(pGcPhysCapData, pCfgCap, fMatched) \
249 bool fMatched = false; \
250 if (pGcPhysCapData && pCfgCap && GCPhysAddr >= (RTGCPHYS)pGcPhysCapData \
251 && GCPhysAddr < ((RTGCPHYS)pGcPhysCapData + ((PVIRTIO_PCI_CAP_T)pCfgCap)->uLength) \
252 && cb <= ((PVIRTIO_PCI_CAP_T)pCfgCap)->uLength) \
253 fMatched = true;
254
255/**
256 * This macro resolves to boolean true if the implied parameters, uOffset and cb, match the field
257 * offset and size of a field in the Common Cfg struct, (or if it is a 64-bit field, if it accesses
258 * either 32-bit part as a 32-bit access)
259 * This is mandated by section 4.1.3.1 of the VirtIO 1.0 specification)
260 *
261 * @param member - Member of VIRTIO_PCI_COMMON_CFG_T
262 * @param uOffset - Implied parameter: Offset into VIRTIO_PCI_COMMON_CFG_T
263 * @param cb - Implied parameter: Number of bytes to access
264 * @result - true or false
265 */
266#define MATCH_COMMON_CFG(member) \
267 (RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member) == 8 \
268 && ( uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \
269 || uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) + sizeof(uint32_t)) \
270 && cb == sizeof(uint32_t)) \
271 || (uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \
272 && cb == RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member))
273
274#define LOG_COMMON_CFG_ACCESS(member) \
275 virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
276 pv, cb, uIntraOff, fWrite, false, 0);
277
278#define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx) \
279 virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
280 pv, cb, uIntraOff, fWrite, true, idx);
281
282#define COMMON_CFG_ACCESSOR(member) \
283 do \
284 { \
285 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
286 if (fWrite) \
287 memcpy(((char *)&pVirtio->member) + uIntraOff, (const char *)pv, cb); \
288 else \
289 memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
290 LOG_COMMON_CFG_ACCESS(member); \
291 } while(0)
292
293#define COMMON_CFG_ACCESSOR_INDEXED(member, idx) \
294 do \
295 { \
296 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
297 if (fWrite) \
298 memcpy(((char *)(pVirtio->member + idx)) + uIntraOff, (const char *)pv, cb); \
299 else \
300 memcpy((char *)pv, (const char *)(((char *)(pVirtio->member + idx)) + uIntraOff), cb); \
301 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
302 } while(0)
303
304#define COMMON_CFG_ACCESSOR_READONLY(member) \
305 do \
306 { \
307 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
308 if (fWrite) \
309 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \
310 else \
311 { \
312 memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
313 LOG_COMMON_CFG_ACCESS(member); \
314 } \
315 } while(0)
316
317#define COMMON_CFG_ACCESSOR_INDEXED_READONLY(member, idx) \
318 do \
319 { \
320 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
321 if (fWrite) \
322 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s[%d]\n", #member, idx)); \
323 else \
324 { \
325 memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + uIntraOff, cb); \
326 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
327 } \
328 } while(0)
329
330#define DRIVER_OK(pVirtio) (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
331
332/**
333 * Internal queue operations
334 */
335
336static int virtqIsEventNeeded (uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
337static bool virtqIsEmpty (PVIRTIOSTATE pVirtio, uint16_t qIdx);
338static void virtioReadDesc (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc);
339static uint16_t virtioReadAvailDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx);
340static uint16_t virtioReadAvailRingIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx);
341static uint16_t virtioReadAvailFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx);
342static uint16_t virtioReadAvailUsedEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx);
343static void virtioWriteUsedElem (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen);
344static void virtioWriteUsedRingIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uDescIdx);
345static uint16_t virtioReadUsedRingIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx);
346static uint16_t virtioReadUsedFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx);
347static void virtioWriteUsedFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags);
348static uint16_t virtioReadUsedAvailEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx);
349static void virtioWriteUsedAvailEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uAvailEventIdx);
350
351
352DECLINLINE(int) virtqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld)
353{
354 return (uint16_t)(uDescIdxNew - uEventIdx - 1) < (uint16_t)(uDescIdxNew - uDescIdxOld);
355}
356
357DECLINLINE(bool) virtqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx)
358{
359 return virtioReadAvailRingIdx(pVirtio, qIdx) == pVirtio->virtqState[qIdx].uAvailIdx;
360}
361
362/**
363 * Accessor for virtq descriptor
364 */
365DECLINLINE(void) virtioReadDesc(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc)
366{
367 //Log(("%s virtioQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQ, idx));
368 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
369 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
370 pVirtio->pGcPhysQueueDesc[qIdx]
371 + sizeof(VIRTQ_DESC_T) * (uDescIdx % pVirtio->uQueueSize[qIdx]),
372 pDesc, sizeof(VIRTQ_DESC_T));
373}
374
375/**
376 * Accessors for virtq avail ring
377 */
378DECLINLINE(uint16_t) virtioReadAvailDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx)
379{
380 uint16_t uDescIdx;
381 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
382 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
383 pVirtio->pGcPhysQueueAvail[qIdx]
384 + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % pVirtio->uQueueSize[qIdx]]),
385 &uDescIdx, sizeof(uDescIdx));
386 return uDescIdx;
387}
388
389DECLINLINE(uint16_t) virtioReadAvailRingIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx)
390{
391 uint16_t uIdx = 0;
392 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
393 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
394 pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
395 &uIdx, sizeof(uIdx));
396 return uIdx;
397}
398
399DECLINLINE(uint16_t) virtioReadAvailFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx)
400{
401 uint16_t fFlags;
402 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
403 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
404 pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
405 &fFlags, sizeof(fFlags));
406 return fFlags;
407}
408
409DECLINLINE(uint16_t) virtioReadAvailUsedEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx)
410{
411 uint16_t uUsedEventIdx;
412 /** VirtIO 1.0 uUsedEventIdx (used_event) immediately follows ring */
413 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
414 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
415 pVirtio->pGcPhysQueueAvail[qIdx]
416 + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uQueueSize[qIdx]]),
417 &uUsedEventIdx, sizeof(uUsedEventIdx));
418 return uUsedEventIdx;
419}
420
421/**
422 * Accessors for virtq used ring
423 */
424DECLINLINE(void) virtioWriteUsedElem(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen)
425{
426 VIRTQ_USED_ELEM_T elem = { uDescIdx, uLen };
427 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
428 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
429 pVirtio->pGcPhysQueueUsed[qIdx]
430 + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[usedIdx % pVirtio->uQueueSize[qIdx]]),
431 &elem, sizeof(elem));
432}
433
434DECLINLINE(void) virtioWriteUsedRingIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uIdx)
435{
436 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
437 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
438 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
439 &uIdx, sizeof(uIdx));
440}
441
442DECLINLINE(uint16_t)virtioReadUsedRingIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx)
443{
444 uint16_t uIdx;
445 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
446 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
447 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
448 &uIdx, sizeof(uIdx));
449 return uIdx;
450}
451
452DECLINLINE(uint16_t) virtioReadUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx)
453{
454 uint16_t fFlags;
455 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
456 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
457 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
458 &fFlags, sizeof(fFlags));
459 return fFlags;
460}
461
462DECLINLINE(void) virtioWriteUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags)
463{
464 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
465 RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
466 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
467 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
468 &fFlags, sizeof(fFlags));
469}
470
471DECLINLINE(uint16_t) virtioReadUsedAvailEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx)
472{
473 uint16_t uAvailEventIdx;
474 RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
475 /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */
476 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
477 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
478 pVirtio->pGcPhysQueueUsed[qIdx]
479 + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[pVirtio->uQueueSize[qIdx]]),
480 &uAvailEventIdx, sizeof(uAvailEventIdx));
481 return uAvailEventIdx;
482}
483
484DECLINLINE(void) virtioWriteUsedAvailEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uAvailEventIdx)
485{
486 /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */
487 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
488 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
489 pVirtio->pGcPhysQueueUsed[qIdx]
490 + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[pVirtio->uQueueSize[qIdx]]),
491 &uAvailEventIdx, sizeof(uAvailEventIdx));
492}
493
494
495/**
496 * Makes the MMIO-mapped Virtio uDeviceStatus registers non-cryptic */
497DECLINLINE(void) virtioLogDeviceStatus( uint8_t status)
498{
499 if (status == 0)
500 Log6(("RESET"));
501 else
502 {
503 int primed = 0;
504 if (status & VIRTIO_STATUS_ACKNOWLEDGE)
505 Log6(("%sACKNOWLEDGE", primed++ ? "" : ""));
506 if (status & VIRTIO_STATUS_DRIVER)
507 Log6(("%sDRIVER", primed++ ? " | " : ""));
508 if (status & VIRTIO_STATUS_FEATURES_OK)
509 Log6(("%sFEATURES_OK", primed++ ? " | " : ""));
510 if (status & VIRTIO_STATUS_DRIVER_OK)
511 Log6(("%sDRIVER_OK", primed++ ? " | " : ""));
512 if (status & VIRTIO_STATUS_FAILED)
513 Log6(("%sFAILED", primed++ ? " | " : ""));
514 if (status & VIRTIO_STATUS_DEVICE_NEEDS_RESET)
515 Log6(("%sNEEDS_RESET", primed++ ? " | " : ""));
516 (void)primed;
517 }
518}
519
520static int virtioCommonCfgAccessed (PVIRTIOSTATE pVirtio, int fWrite, off_t uOffset, unsigned cb, void const *pv);
521static void virtioResetQueue (PVIRTIOSTATE pVirtio, uint16_t qIdx);
522static void virtioNotifyGuestDriver (PVIRTIOSTATE pVirtio, uint16_t qIdx, bool fForce);
523static int virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uVec, bool fForce);
524static void virtioQueueNotified (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx);
525static void virtioGuestResetted (PVIRTIOSTATE pVirtio);
526
527static DECLCALLBACK(int) virtioR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
528static DECLCALLBACK(int) virtioR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
529static DECLCALLBACK(int) virtioR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
530static DECLCALLBACK(int) virtioR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass);
531
532#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h */
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