1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
|
/* $Id: Virtio.h $ */
/** @file
* Virtio.h - Virtio Declarations
*/
/*
* Copyright (C) 2009-2022 Oracle and/or its affiliates.
*
* This file is part of VirtualBox base platform packages, as
* available from https://www.virtualbox.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, in version 3 of the
* License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses>.
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#ifndef VBOX_INCLUDED_SRC_VirtIO_Virtio_h
#define VBOX_INCLUDED_SRC_VirtIO_Virtio_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <iprt/types.h>
/** Pointer to the core shared state of a VirtIO PCI device */
typedef struct VPCISTATE *PVPCISTATE;
/** Pointer to the core ring-3 state of a VirtIO PCI device */
typedef struct VPCISTATER3 *PVPCISTATER3;
/** Pointer to the core ring-0 state of a VirtIO PCI device */
typedef struct VPCISTATER0 *PVPCISTATER0;
/** Pointer to the core raw-mode state of a VirtIO PCI device */
typedef struct VPCISTATERC *PVPCISTATERC;
/** Pointer to the core current context state of a VirtIO PCI device */
typedef CTX_SUFF(PVPCISTATE) PVPCISTATECC;
/** The core current context state of a VirtIO PCI device */
typedef struct CTX_SUFF(VPCISTATE) VPCISTATECC;
/** @name Saved state versions.
* The saved state version is changed if either common or any of specific
* parts are changed. That is, it is perfectly possible that the version
* of saved vnet state will increase as a result of change in vblk structure
* for example.
*/
#define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1
#define VIRTIO_SAVEDSTATE_VERSION 2
/** @} */
#define DEVICE_PCI_VENDOR_ID 0x1AF4
#define DEVICE_PCI_BASE_ID 0x1000
#define DEVICE_PCI_SUBSYSTEM_VENDOR_ID 0x1AF4
#define DEVICE_PCI_SUBSYSTEM_BASE_ID 1
#define VIRTIO_MAX_NQUEUES 3
#define VPCI_HOST_FEATURES 0x0
#define VPCI_GUEST_FEATURES 0x4
#define VPCI_QUEUE_PFN 0x8
#define VPCI_QUEUE_NUM 0xC
#define VPCI_QUEUE_SEL 0xE
#define VPCI_QUEUE_NOTIFY 0x10
#define VPCI_STATUS 0x12
#define VPCI_ISR 0x13
#define VPCI_CONFIG 0x14
#define VPCI_ISR_QUEUE 0x1
#define VPCI_ISR_CONFIG 0x3
#define VPCI_STATUS_ACK 0x01
#define VPCI_STATUS_DRV 0x02
#define VPCI_STATUS_DRV_OK 0x04
#define VPCI_STATUS_FAILED 0x80
#define VPCI_F_NOTIFY_ON_EMPTY UINT32_C(0x01000000)
#define VPCI_F_ANY_LAYOUT UINT32_C(0x08000000)
#define VPCI_F_RING_INDIRECT_DESC UINT32_C(0x10000000)
#define VPCI_F_RING_EVENT_IDX UINT32_C(0x20000000)
#define VPCI_F_BAD_FEATURE UINT32_C(0x40000000)
#define VRINGDESC_MAX_SIZE (2 * 1024 * 1024)
#define VRINGDESC_F_NEXT 0x01
#define VRINGDESC_F_WRITE 0x02
#define VRINGDESC_F_INDIRECT 0x04
typedef struct VRINGDESC
{
uint64_t u64Addr;
uint32_t uLen;
uint16_t u16Flags;
uint16_t u16Next;
} VRINGDESC;
typedef VRINGDESC *PVRINGDESC;
#define VRINGAVAIL_F_NO_INTERRUPT 0x01
typedef struct VRINGAVAIL
{
uint16_t uFlags;
uint16_t uNextFreeIndex;
uint16_t auRing[1];
} VRINGAVAIL;
typedef struct VRINGUSEDELEM
{
uint32_t uId;
uint32_t uLen;
} VRINGUSEDELEM;
#define VRINGUSED_F_NO_NOTIFY 0x01
typedef struct VRingUsed
{
uint16_t uFlags;
uint16_t uIndex;
VRINGUSEDELEM aRing[1];
} VRINGUSED;
typedef VRINGUSED *PVRINGUSED;
#define VRING_MAX_SIZE 1024
typedef struct VRING
{
uint16_t uSize;
uint16_t padding[3];
RTGCPHYS addrDescriptors;
RTGCPHYS addrAvail;
RTGCPHYS addrUsed;
} VRING;
typedef VRING *PVRING;
typedef struct VQUEUE
{
VRING VRing;
uint16_t uNextAvailIndex;
uint16_t uNextUsedIndex;
uint32_t uPageNumber;
char szName[16];
} VQUEUE;
typedef VQUEUE *PVQUEUE;
/**
* Queue callback (consumer?).
*
* @param pDevIns The device instance.
* @param pQueue Pointer to the queue structure.
*/
typedef DECLCALLBACKTYPE(void, FNVPCIQUEUECALLBACK,(PPDMDEVINS pDevIns, PVQUEUE pQueue));
/** Pointer to a VQUEUE callback function. */
typedef FNVPCIQUEUECALLBACK *PFNVPCIQUEUECALLBACK;
typedef struct VQUEUER3
{
R3PTRTYPE(PFNVPCIQUEUECALLBACK) pfnCallback;
} VQUEUER3;
typedef VQUEUER3 *PVQUEUER3;
typedef struct VQUEUESEG
{
RTGCPHYS addr;
void *pv;
uint32_t cb;
} VQUEUESEG;
typedef struct VQUEUEELEM
{
uint32_t uIndex;
uint32_t cIn;
uint32_t cOut;
VQUEUESEG aSegsIn[VRING_MAX_SIZE];
VQUEUESEG aSegsOut[VRING_MAX_SIZE];
} VQUEUEELEM;
typedef VQUEUEELEM *PVQUEUEELEM;
enum VirtioDeviceType
{
VIRTIO_NET_ID = 0,
VIRTIO_BLK_ID = 1,
VIRTIO_32BIT_HACK = 0x7fffffff
};
/**
* The core shared state of a VirtIO PCI device
*/
typedef struct VPCISTATE
{
PDMCRITSECT cs; /**< Critical section - what is it protecting? */
/** Read-only part, never changes after initialization. */
char szInstance[8]; /**< Instance name, e.g. VNet#1. */
/* Read/write part, protected with critical section. */
/** Status LED. */
PDMLED led;
uint32_t uGuestFeatures;
uint16_t uQueueSelector; /**< An index in aQueues array. */
uint8_t uStatus; /**< Device Status (bits are device-specific). */
uint8_t uISR; /**< Interrupt Status Register. */
/** Number of queues actually used. */
uint32_t cQueues;
uint32_t u32Padding;
/** Shared queue data. */
VQUEUE Queues[VIRTIO_MAX_NQUEUES];
STAMCOUNTER StatIntsRaised;
STAMCOUNTER StatIntsSkipped;
#ifdef VBOX_WITH_STATISTICS
STAMPROFILEADV StatIOReadR3;
STAMPROFILEADV StatIOReadR0;
STAMPROFILEADV StatIOReadRC;
STAMPROFILEADV StatIOWriteR3;
STAMPROFILEADV StatIOWriteR0;
STAMPROFILEADV StatIOWriteRC;
#endif
} VPCISTATE;
/**
* The core ring-3 state of a VirtIO PCI device
*
* @implements PDMILEDPORTS
*/
typedef struct VPCISTATER3
{
/** Status LUN: Base interface. */
PDMIBASE IBase;
/** Status LUN: LED port interface. */
PDMILEDPORTS ILeds;
/** Status LUN: LED connector (peer). */
R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
/** Pointer to the shared state. */
R3PTRTYPE(PVPCISTATE) pShared;
/** Ring-3 per-queue data. */
VQUEUER3 Queues[VIRTIO_MAX_NQUEUES];
} VPCISTATER3;
/**
* The core ring-0 state of a VirtIO PCI device
*/
typedef struct VPCISTATER0
{
uint64_t uUnused;
} VPCISTATER0;
/**
* The core raw-mode state of a VirtIO PCI device
*/
typedef struct VPCISTATERC
{
uint64_t uUnused;
} VPCISTATERC;
/** @name VirtIO port I/O callbacks.
* @{ */
typedef struct VPCIIOCALLBACKS
{
DECLCALLBACKMEMBER(uint32_t, pfnGetHostFeatures,(PVPCISTATE pVPciState));
DECLCALLBACKMEMBER(uint32_t, pfnGetHostMinimalFeatures,(PVPCISTATE pVPciState));
DECLCALLBACKMEMBER(void, pfnSetHostFeatures,(PVPCISTATE pVPciState, uint32_t fFeatures));
DECLCALLBACKMEMBER(int, pfnGetConfig,(PVPCISTATE pVPciState, uint32_t offCfg, uint32_t cb, void *pvData));
DECLCALLBACKMEMBER(int, pfnSetConfig,(PVPCISTATE pVPciState, uint32_t offCfg, uint32_t cb, void *pvData));
DECLCALLBACKMEMBER(int, pfnReset,(PPDMDEVINS pDevIns));
DECLCALLBACKMEMBER(void, pfnReady,(PPDMDEVINS pDevIns));
} VPCIIOCALLBACKS;
/** Pointer to a const VirtIO port I/O callback structure. */
typedef const VPCIIOCALLBACKS *PCVPCIIOCALLBACKS;
/** @} */
int vpciR3Init(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVPCISTATECC pThisCC, uint16_t uDeviceId, uint16_t uClass, uint32_t cQueues);
int vpciRZInit(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVPCISTATECC pThisCC);
int vpciR3Term(PPDMDEVINS pDevIns, PVPCISTATE pThis);
PVQUEUE vpciR3AddQueue(PVPCISTATE pThis, PVPCISTATECC pThisCC, unsigned uSize, PFNVPCIQUEUECALLBACK pfnCallback, const char *pcszName);
void *vpciR3QueryInterface(PVPCISTATECC pThisCC, const char *pszIID);
void vpciR3SetWriteLed(PVPCISTATE pThis, bool fOn);
void vpciR3SetReadLed(PVPCISTATE pThis, bool fOn);
int vpciR3SaveExec(PPDMDEVINS pDevIns, PCPDMDEVHLPR3 pHlp, PVPCISTATE pThis, PSSMHANDLE pSSM);
int vpciR3LoadExec(PPDMDEVINS pDevIns, PCPDMDEVHLPR3 pHlp, PVPCISTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t cQueues);
void vpciR3DumpStateWorker(PVPCISTATE pThis, PCDBGFINFOHLP pHlp);
void vpciReset(PPDMDEVINS pDevIns, PVPCISTATE pThis);
int vpciRaiseInterrupt(PPDMDEVINS pDevIns, PVPCISTATE pThis, int rcBusy, uint8_t u8IntCause);
int vpciIOPortIn(PPDMDEVINS pDevIns, PVPCISTATE pThis, RTIOPORT offPort,
uint32_t *pu32, unsigned cb,PCVPCIIOCALLBACKS pCallbacks);
int vpciIOPortOut(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVPCISTATECC pThisCC, RTIOPORT offPort,
uint32_t u32, unsigned cb, PCVPCIIOCALLBACKS pCallbacks);
#define VPCI_CS
#ifdef VPCI_CS
# define VPCI_R3_CS_ENTER_RETURN_VOID(a_pDevIns, a_pThis) do { \
int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &(a_pThis)->cs, VERR_IGNORED); \
PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &(a_pThis)->cs, rcLock); \
} while (0)
#else
# define VPCI_R3_CS_ENTER_RETURN_VOID(a_pDevIns, a_pThis) do { } while (0)
#endif
DECLINLINE(int) vpciCsEnter(PPDMDEVINS pDevIns, PVPCISTATE pThis, int rcBusy)
{
#ifdef VPCI_CS
return PDMDevHlpCritSectEnter(pDevIns, &pThis->cs, rcBusy);
#else
RT_NOREF(pDevIns, pThis, rcBusy);
return VINF_SUCCESS;
#endif
}
DECLINLINE(void) vpciCsLeave(PPDMDEVINS pDevIns, PVPCISTATE pThis)
{
#ifdef VPCI_CS
PDMDevHlpCritSectLeave(pDevIns, &pThis->cs);
#endif
}
void vringSetNotification(PPDMDEVINS pDevIns, PVRING pVRing, bool fEnabled);
DECLINLINE(uint16_t) vringReadAvailIndex(PPDMDEVINS pDevIns, PVRING pVRing)
{
uint16_t idx = 0;
PDMDevHlpPhysRead(pDevIns, pVRing->addrAvail + RT_UOFFSETOF(VRINGAVAIL, uNextFreeIndex), &idx, sizeof(idx));
return idx;
}
bool vqueueSkip(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue);
bool vqueueGet(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true);
void vqueuePut(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t uLen, uint32_t uReserved = 0);
void vqueueSync(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue);
DECLINLINE(bool) vqueuePeek(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue, PVQUEUEELEM pElem)
{
return vqueueGet(pDevIns, pThis, pQueue, pElem, /* fRemove */ false);
}
DECLINLINE(bool) vqueueIsReady(PVQUEUE pQueue)
{
return !!pQueue->VRing.addrAvail;
}
DECLINLINE(bool) vqueueIsEmpty(PPDMDEVINS pDevIns, PVQUEUE pQueue)
{
return vringReadAvailIndex(pDevIns, &pQueue->VRing) == pQueue->uNextAvailIndex;
}
#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_h */
|