1 | /* $Id: Virtio_1_0_impl.h 81122 2019-10-07 08:54:00Z vboxsync $ $Revision: 81122 $ $Date: 2019-10-07 08:54:00 +0000 (Mon, 07 Oct 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 | */
|
---|
73 | typedef 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 | */
|
---|
89 | typedef 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 | */
|
---|
102 | typedef 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 |
|
---|
125 | typedef 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 |
|
---|
131 | typedef 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 | */
|
---|
142 | typedef struct VIRTIOSTATE
|
---|
143 | {
|
---|
144 | char szInstance[16]; /**< Instance name, e.g. "VIRTIOSCSI0" */
|
---|
145 | void * pClientContext; /**< Client callback returned on callbacks */
|
---|
146 |
|
---|
147 | PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3 */
|
---|
148 | PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0 */
|
---|
149 | PPDMDEVINSRC pDevInsRC; /**< Device instance - RC */
|
---|
150 |
|
---|
151 | RTGCPHYS pGcPhysPciCapBase; /**< Pointer to MMIO mapped capability data */
|
---|
152 | RTGCPHYS pGcPhysCommonCfg; /**< Pointer to MMIO mapped capability data */
|
---|
153 | RTGCPHYS pGcPhysNotifyCap; /**< Pointer to MMIO mapped capability data */
|
---|
154 | RTGCPHYS pGcPhysIsrCap; /**< Pointer to MMIO mapped capability data */
|
---|
155 | RTGCPHYS pGcPhysDeviceCap; /**< Pointer to MMIO mapped capability data */
|
---|
156 |
|
---|
157 | RTGCPHYS pGcPhysQueueDesc[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q desc structs GUEST */
|
---|
158 | RTGCPHYS pGcPhysQueueAvail[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q avail structs GUEST */
|
---|
159 | RTGCPHYS pGcPhysQueueUsed[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q used structs GUEST */
|
---|
160 | uint16_t uQueueNotifyOff[VIRTQ_MAX_CNT]; /**< (MMIO) per-Q notify offset HOST */
|
---|
161 | uint16_t uQueueMsixVector[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue vector for MSI-X GUEST */
|
---|
162 | uint16_t uQueueEnable[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue enable GUEST */
|
---|
163 | uint16_t uQueueSize[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue size HOST/GUEST */
|
---|
164 | uint16_t uQueueSelect; /**< (MMIO) queue selector GUEST */
|
---|
165 | uint16_t padding;
|
---|
166 | uint64_t uDeviceFeatures; /**< (MMIO) Host features offered HOST */
|
---|
167 | uint64_t uDriverFeatures; /**< (MMIO) Host features accepted GUEST */
|
---|
168 | uint32_t uDeviceFeaturesSelect; /**< (MMIO) hi/lo select uDeviceFeatures GUEST */
|
---|
169 | uint32_t uDriverFeaturesSelect; /**< (MMIO) hi/lo select uDriverFeatures GUEST */
|
---|
170 | uint32_t uMsixConfig; /**< (MMIO) MSI-X vector GUEST */
|
---|
171 | uint32_t uNumQueues; /**< (MMIO) Actual number of queues GUEST */
|
---|
172 | uint8_t uDeviceStatus; /**< (MMIO) Device Status GUEST */
|
---|
173 | uint8_t uPrevDeviceStatus; /**< (MMIO) Prev Device Status GUEST */
|
---|
174 | uint8_t uConfigGeneration; /**< (MMIO) Device config sequencer HOST */
|
---|
175 |
|
---|
176 | VIRTQSTATE virtqState[VIRTQ_MAX_CNT]; /**< Local impl-specific queue context */
|
---|
177 | VIRTIOCALLBACKS virtioCallbacks; /**< Callback vectors to client */
|
---|
178 |
|
---|
179 | PVIRTIO_PCI_CFG_CAP_T pPciCfgCap; /**< Pointer to struct in configuration area */
|
---|
180 | PVIRTIO_PCI_NOTIFY_CAP_T pNotifyCap; /**< Pointer to struct in configuration area */
|
---|
181 | PVIRTIO_PCI_CAP_T pCommonCfgCap; /**< Pointer to struct in configuration area */
|
---|
182 | PVIRTIO_PCI_CAP_T pIsrCap; /**< Pointer to struct in configuration area */
|
---|
183 | PVIRTIO_PCI_CAP_T pDeviceCap; /**< Pointer to struct in configuration area */
|
---|
184 |
|
---|
185 | uint32_t cbDevSpecificCfg; /**< Size of client's dev-specific config data */
|
---|
186 | void *pDevSpecificCfg; /**< Pointer to client's struct */
|
---|
187 | void *pPrevDevSpecificCfg; /**< Previous read dev-specific cfg of client */
|
---|
188 | bool fGenUpdatePending; /**< If set, update cfg gen after driver reads */
|
---|
189 | uint8_t uPciCfgDataOff;
|
---|
190 | uint8_t uISR; /**< Interrupt Status Register. */
|
---|
191 | uint8_t fMsiSupport;
|
---|
192 |
|
---|
193 | } VIRTIOSTATE, *PVIRTIOSTATE;
|
---|
194 |
|
---|
195 | /** virtq related flags */
|
---|
196 | #define VIRTQ_DESC_F_NEXT 1 /**< Indicates this descriptor chains to next */
|
---|
197 | #define VIRTQ_DESC_F_WRITE 2 /**< Marks buffer as write-only (default ro) */
|
---|
198 | #define VIRTQ_DESC_F_INDIRECT 4 /**< Buffer is list of buffer descriptors */
|
---|
199 |
|
---|
200 | #define VIRTQ_USED_F_NO_NOTIFY 1 /**< Dev to Drv: Don't notify when buf added */
|
---|
201 | #define VIRTQ_AVAIL_F_NO_INTERRUPT 1 /**< Drv to Dev: Don't notify when buf eaten */
|
---|
202 |
|
---|
203 | /**
|
---|
204 | * virtq related structs
|
---|
205 | * (struct names follow VirtIO 1.0 spec, typedef use VBox style)
|
---|
206 | */
|
---|
207 | typedef struct virtq_desc
|
---|
208 | {
|
---|
209 | uint64_t pGcPhysBuf; /**< addr GC Phys. address of buffer */
|
---|
210 | uint32_t cb; /**< len Buffer length */
|
---|
211 | uint16_t fFlags; /**< flags Buffer specific flags */
|
---|
212 | uint16_t uDescIdxNext; /**< next Idx set if VIRTIO_DESC_F_NEXT */
|
---|
213 | } VIRTQ_DESC_T, *PVIRTQ_DESC_T;
|
---|
214 |
|
---|
215 | typedef struct virtq_avail
|
---|
216 | {
|
---|
217 | uint16_t fFlags; /**< flags avail ring drv to dev flags */
|
---|
218 | uint16_t uIdx; /**< idx Index of next free ring slot */
|
---|
219 | uint16_t auRing[1]; /**< ring Ring: avail drv to dev bufs */
|
---|
220 | uint16_t uUsedEventIdx; /**< used_event (if VIRTQ_USED_F_EVENT_IDX) */
|
---|
221 | } VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
|
---|
222 |
|
---|
223 | typedef struct virtq_used_elem
|
---|
224 | {
|
---|
225 | uint32_t uDescIdx; /**< idx Start of used desc chain */
|
---|
226 | uint32_t cbElem; /**< len Total len of used desc chain */
|
---|
227 | } VIRTQ_USED_ELEM_T;
|
---|
228 |
|
---|
229 | typedef struct virt_used
|
---|
230 | {
|
---|
231 | uint16_t fFlags; /**< flags used ring host-to-guest flags */
|
---|
232 | uint16_t uIdx; /**< idx Index of next ring slot */
|
---|
233 | VIRTQ_USED_ELEM_T auRing[1]; /**< ring Ring: used dev to drv bufs */
|
---|
234 | uint16_t uAvailEventIdx; /**< avail_event if (VIRTQ_USED_F_EVENT_IDX) */
|
---|
235 | } VIRTQ_USED_T, *PVIRTQ_USED_T;
|
---|
236 |
|
---|
237 | /**
|
---|
238 | * This macro returns true if the implied parameter GCPhysAddr address and access length are
|
---|
239 | * within the range of the mapped capability struct specified with the explicit parameters.
|
---|
240 | *
|
---|
241 | * Actual Parameters:
|
---|
242 | * @oaram pPhysCapStruct - [input] Pointer to MMIO mapped capability struct
|
---|
243 | * @param pCfgCap - [input] Pointer to capability in PCI configuration area
|
---|
244 | * @param fMatched - [output] True if GCPhysAddr is within the physically mapped capability.
|
---|
245 | *
|
---|
246 | * Implied parameters:
|
---|
247 | * @param GCPhysAddr - [input, implied] Physical address accessed (via MMIO callback)
|
---|
248 | * @param cb - [input, implied] Number of bytes to access
|
---|
249 | */
|
---|
250 | #define MATCH_VIRTIO_CAP_STRUCT(pGcPhysCapData, pCfgCap, fMatched) \
|
---|
251 | bool fMatched = false; \
|
---|
252 | if (pGcPhysCapData && pCfgCap && GCPhysAddr >= (RTGCPHYS)pGcPhysCapData \
|
---|
253 | && GCPhysAddr < ((RTGCPHYS)pGcPhysCapData + ((PVIRTIO_PCI_CAP_T)pCfgCap)->uLength) \
|
---|
254 | && cb <= ((PVIRTIO_PCI_CAP_T)pCfgCap)->uLength) \
|
---|
255 | fMatched = true;
|
---|
256 |
|
---|
257 | /**
|
---|
258 | * This macro resolves to boolean true if the implied parameters, uOffset and cb, match the field
|
---|
259 | * offset and size of a field in the Common Cfg struct, (or if it is a 64-bit field, if it accesses
|
---|
260 | * either 32-bit part as a 32-bit access)
|
---|
261 | * This is mandated by section 4.1.3.1 of the VirtIO 1.0 specification)
|
---|
262 | *
|
---|
263 | * @param member - Member of VIRTIO_PCI_COMMON_CFG_T
|
---|
264 | * @param uOffset - Implied parameter: Offset into VIRTIO_PCI_COMMON_CFG_T
|
---|
265 | * @param cb - Implied parameter: Number of bytes to access
|
---|
266 | * @result - true or false
|
---|
267 | */
|
---|
268 | #define MATCH_COMMON_CFG(member) \
|
---|
269 | (RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member) == 8 \
|
---|
270 | && ( uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \
|
---|
271 | || uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) + sizeof(uint32_t)) \
|
---|
272 | && cb == sizeof(uint32_t)) \
|
---|
273 | || (uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \
|
---|
274 | && cb == RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member))
|
---|
275 |
|
---|
276 | #define LOG_COMMON_CFG_ACCESS(member) \
|
---|
277 | virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
|
---|
278 | pv, cb, uIntraOff, fWrite, false, 0);
|
---|
279 |
|
---|
280 | #define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx) \
|
---|
281 | virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
|
---|
282 | pv, cb, uIntraOff, fWrite, true, idx);
|
---|
283 |
|
---|
284 | #define COMMON_CFG_ACCESSOR(member) \
|
---|
285 | do \
|
---|
286 | { \
|
---|
287 | uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
|
---|
288 | if (fWrite) \
|
---|
289 | memcpy(((char *)&pVirtio->member) + uIntraOff, (const char *)pv, cb); \
|
---|
290 | else \
|
---|
291 | memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
|
---|
292 | LOG_COMMON_CFG_ACCESS(member); \
|
---|
293 | } while(0)
|
---|
294 |
|
---|
295 | #define COMMON_CFG_ACCESSOR_INDEXED(member, idx) \
|
---|
296 | do \
|
---|
297 | { \
|
---|
298 | uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
|
---|
299 | if (fWrite) \
|
---|
300 | memcpy(((char *)(pVirtio->member + idx)) + uIntraOff, (const char *)pv, cb); \
|
---|
301 | else \
|
---|
302 | memcpy((char *)pv, (const char *)(((char *)(pVirtio->member + idx)) + uIntraOff), cb); \
|
---|
303 | LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
|
---|
304 | } while(0)
|
---|
305 |
|
---|
306 | #define COMMON_CFG_ACCESSOR_READONLY(member) \
|
---|
307 | do \
|
---|
308 | { \
|
---|
309 | uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
|
---|
310 | if (fWrite) \
|
---|
311 | LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \
|
---|
312 | else \
|
---|
313 | { \
|
---|
314 | memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
|
---|
315 | LOG_COMMON_CFG_ACCESS(member); \
|
---|
316 | } \
|
---|
317 | } while(0)
|
---|
318 |
|
---|
319 | #define COMMON_CFG_ACCESSOR_INDEXED_READONLY(member, idx) \
|
---|
320 | do \
|
---|
321 | { \
|
---|
322 | uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
|
---|
323 | if (fWrite) \
|
---|
324 | LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s[%d]\n", #member, idx)); \
|
---|
325 | else \
|
---|
326 | { \
|
---|
327 | memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + uIntraOff, cb); \
|
---|
328 | LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
|
---|
329 | } \
|
---|
330 | } while(0)
|
---|
331 |
|
---|
332 | #define DRIVER_OK(pVirtio) (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
|
---|
333 |
|
---|
334 | /**
|
---|
335 | * Internal queue operations
|
---|
336 | */
|
---|
337 |
|
---|
338 | static int virtqIsEventNeeded (uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
|
---|
339 | static bool virtqIsEmpty (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
340 | static void virtioReadDesc (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc);
|
---|
341 | static uint16_t virtioReadAvailDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx);
|
---|
342 | static uint16_t virtioReadAvailRingIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
343 | static uint16_t virtioReadAvailFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
344 | static uint16_t virtioReadAvailUsedEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
345 | static void virtioWriteUsedElem (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen);
|
---|
346 | static void virtioWriteUsedRingIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uDescIdx);
|
---|
347 | static uint16_t virtioReadUsedRingIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
348 | static uint16_t virtioReadUsedFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
349 | static void virtioWriteUsedFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags);
|
---|
350 | static uint16_t virtioReadUsedAvailEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
351 | static void virtioWriteUsedAvailEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uAvailEventIdx);
|
---|
352 |
|
---|
353 |
|
---|
354 | DECLINLINE(int) virtqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld)
|
---|
355 | {
|
---|
356 | return (uint16_t)(uDescIdxNew - uEventIdx - 1) < (uint16_t)(uDescIdxNew - uDescIdxOld);
|
---|
357 | }
|
---|
358 |
|
---|
359 | DECLINLINE(bool) virtqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx)
|
---|
360 | {
|
---|
361 | return virtioReadAvailRingIdx(pVirtio, qIdx) == pVirtio->virtqState[qIdx].uAvailIdx;
|
---|
362 | }
|
---|
363 |
|
---|
364 | /**
|
---|
365 | * Accessor for virtq descriptor
|
---|
366 | */
|
---|
367 | DECLINLINE(void) virtioReadDesc(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc)
|
---|
368 | {
|
---|
369 | //Log(("%s virtioQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQ, idx));
|
---|
370 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
371 | PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
|
---|
372 | pVirtio->pGcPhysQueueDesc[qIdx]
|
---|
373 | + sizeof(VIRTQ_DESC_T) * (uDescIdx % pVirtio->uQueueSize[qIdx]),
|
---|
374 | pDesc, sizeof(VIRTQ_DESC_T));
|
---|
375 | }
|
---|
376 |
|
---|
377 | /**
|
---|
378 | * Accessors for virtq avail ring
|
---|
379 | */
|
---|
380 | DECLINLINE(uint16_t) virtioReadAvailDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx)
|
---|
381 | {
|
---|
382 | uint16_t uDescIdx;
|
---|
383 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
384 | PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
|
---|
385 | pVirtio->pGcPhysQueueAvail[qIdx]
|
---|
386 | + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % pVirtio->uQueueSize[qIdx]]),
|
---|
387 | &uDescIdx, sizeof(uDescIdx));
|
---|
388 | return uDescIdx;
|
---|
389 | }
|
---|
390 |
|
---|
391 | DECLINLINE(uint16_t) virtioReadAvailRingIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx)
|
---|
392 | {
|
---|
393 | uint16_t uIdx = 0;
|
---|
394 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
395 | PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
|
---|
396 | pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
|
---|
397 | &uIdx, sizeof(uIdx));
|
---|
398 | return uIdx;
|
---|
399 | }
|
---|
400 |
|
---|
401 | DECLINLINE(uint16_t) virtioReadAvailFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx)
|
---|
402 | {
|
---|
403 | uint16_t fFlags;
|
---|
404 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
405 | PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
|
---|
406 | pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
|
---|
407 | &fFlags, sizeof(fFlags));
|
---|
408 | return fFlags;
|
---|
409 | }
|
---|
410 |
|
---|
411 | DECLINLINE(uint16_t) virtioReadAvailUsedEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx)
|
---|
412 | {
|
---|
413 | uint16_t uUsedEventIdx;
|
---|
414 | /** VirtIO 1.0 uUsedEventIdx (used_event) immediately follows ring */
|
---|
415 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
416 | PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
|
---|
417 | pVirtio->pGcPhysQueueAvail[qIdx]
|
---|
418 | + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uQueueSize[qIdx]]),
|
---|
419 | &uUsedEventIdx, sizeof(uUsedEventIdx));
|
---|
420 | return uUsedEventIdx;
|
---|
421 | }
|
---|
422 |
|
---|
423 | /**
|
---|
424 | * Accessors for virtq used ring
|
---|
425 | */
|
---|
426 | DECLINLINE(void) virtioWriteUsedElem(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen)
|
---|
427 | {
|
---|
428 | VIRTQ_USED_ELEM_T elem = { uDescIdx, uLen };
|
---|
429 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
430 | PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
|
---|
431 | pVirtio->pGcPhysQueueUsed[qIdx]
|
---|
432 | + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[usedIdx % pVirtio->uQueueSize[qIdx]]),
|
---|
433 | &elem, sizeof(elem));
|
---|
434 | }
|
---|
435 |
|
---|
436 | DECLINLINE(void) virtioWriteUsedRingIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uIdx)
|
---|
437 | {
|
---|
438 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
439 | PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
|
---|
440 | pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
|
---|
441 | &uIdx, sizeof(uIdx));
|
---|
442 | }
|
---|
443 |
|
---|
444 | DECLINLINE(uint16_t)virtioReadUsedRingIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx)
|
---|
445 | {
|
---|
446 | uint16_t uIdx;
|
---|
447 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
448 | PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
|
---|
449 | pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
|
---|
450 | &uIdx, sizeof(uIdx));
|
---|
451 | return uIdx;
|
---|
452 | }
|
---|
453 |
|
---|
454 | DECLINLINE(uint16_t) virtioReadUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx)
|
---|
455 | {
|
---|
456 | uint16_t fFlags;
|
---|
457 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
458 | PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
|
---|
459 | pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
|
---|
460 | &fFlags, sizeof(fFlags));
|
---|
461 | return fFlags;
|
---|
462 | }
|
---|
463 |
|
---|
464 | DECLINLINE(void) virtioWriteUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags)
|
---|
465 | {
|
---|
466 | AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
|
---|
467 | PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
|
---|
468 | pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
|
---|
469 | &fFlags, sizeof(fFlags));
|
---|
470 | }
|
---|
471 |
|
---|
472 | DECLINLINE(uint16_t) virtioReadUsedAvailEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx)
|
---|
473 | {
|
---|
474 | uint16_t uAvailEventIdx;
|
---|
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 |
|
---|
484 | DECLINLINE(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 */
|
---|
497 | DECLINLINE(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 |
|
---|
520 | static int virtioCommonCfgAccessed (PVIRTIOSTATE pVirtio, int fWrite, off_t uOffset, unsigned cb, void const *pv);
|
---|
521 | static void virtioResetQueue (PVIRTIOSTATE pVirtio, uint16_t qIdx);
|
---|
522 | static void virtioNotifyGuestDriver (PVIRTIOSTATE pVirtio, uint16_t qIdx, bool fForce);
|
---|
523 | static int virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uVec, bool fForce);
|
---|
524 | static void virtioQueueNotified (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx);
|
---|
525 | static void virtioGuestResetted (PVIRTIOSTATE pVirtio);
|
---|
526 |
|
---|
527 | static DECLCALLBACK(int) virtioR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
|
---|
528 | static DECLCALLBACK(int) virtioR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
|
---|
529 | static DECLCALLBACK(int) virtioR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
|
---|
530 | static DECLCALLBACK(int) virtioR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass);
|
---|
531 |
|
---|
532 | #endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h */
|
---|