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
|
/* $Id: Virtio.h $ */
/** @file
* Virtio.h - Virtio Declarations
*/
/*
* Copyright (C) 2009-2019 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#ifndef VBOX_INCLUDED_SRC_VirtIO_Virtio_h
#define VBOX_INCLUDED_SRC_VirtIO_Virtio_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <iprt/ctype.h>
/** @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 0x01000000
#define VPCI_F_ANY_LAYOUT 0x08000000
#define VPCI_F_RING_INDIRECT_DESC 0x10000000
#define VPCI_F_RING_EVENT_IDX 0x20000000
#define VPCI_F_BAD_FEATURE 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;
/**
* Queue callback (consumer?).
*
* @param pvState Pointer to the VirtIO PCI core state, VPCISTATE.
* @param pQueue Pointer to the queue structure.
*/
typedef DECLCALLBACK(void) FNVPCIQUEUECALLBACK(void *pvState, struct VQueue *pQueue);
/** Pointer to a VQUEUE callback function. */
typedef FNVPCIQUEUECALLBACK *PFNVPCIQUEUECALLBACK;
typedef struct VQueue
{
VRING VRing;
uint16_t uNextAvailIndex;
uint16_t uNextUsedIndex;
uint32_t uPageNumber;
R3PTRTYPE(PFNVPCIQUEUECALLBACK) pfnCallback;
R3PTRTYPE(const char *) pcszName;
} VQUEUE;
typedef VQUEUE *PVQUEUE;
typedef struct VQueueElemSeg
{
RTGCPHYS addr;
void *pv;
uint32_t cb;
} VQUEUESEG;
typedef struct VQueueElem
{
uint32_t uIndex;
uint32_t nIn;
uint32_t nOut;
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 (/common) state of the VirtIO PCI device
*
* @implements PDMILEDPORTS
*/
typedef struct VPCIState_st
{
PDMCRITSECT cs; /**< Critical section - what is it protecting? */
/* Read-only part, never changes after initialization. */
char szInstance[8]; /**< Instance name, e.g. VNet#1. */
#if HC_ARCH_BITS != 64
uint32_t padding1;
#endif
/** Status LUN: Base interface. */
PDMIBASE IBase;
/** Status LUN: LED port interface. */
PDMILEDPORTS ILeds;
/** Status LUN: LED connector (peer). */
R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3. */
PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0. */
PPDMDEVINSRC pDevInsRC; /**< Device instance - RC. */
#if HC_ARCH_BITS == 64
uint32_t padding2;
#endif
/** TODO */
PDMPCIDEV pciDevice;
/** Base port of I/O space region. */
RTIOPORT IOPortBase;
/* 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. */
#if HC_ARCH_BITS != 64
uint32_t padding3;
#endif
uint32_t nQueues; /**< Actual number of queues used. */
VQUEUE Queues[VIRTIO_MAX_NQUEUES];
#if defined(VBOX_WITH_STATISTICS)
STAMPROFILEADV StatIOReadR3;
STAMPROFILEADV StatIOReadR0;
STAMPROFILEADV StatIOReadRC;
STAMPROFILEADV StatIOWriteR3;
STAMPROFILEADV StatIOWriteR0;
STAMPROFILEADV StatIOWriteRC;
STAMCOUNTER StatIntsRaised;
STAMCOUNTER StatIntsSkipped;
STAMPROFILE StatCsR3;
STAMPROFILE StatCsR0;
STAMPROFILE StatCsRC;
#endif /* VBOX_WITH_STATISTICS */
} VPCISTATE;
/** Pointer to the core (/common) state of a VirtIO PCI device. */
typedef VPCISTATE *PVPCISTATE;
typedef DECLCALLBACK(uint32_t) FNGETHOSTFEATURES(void *pvState);
typedef FNGETHOSTFEATURES *PFNGETHOSTFEATURES;
/** @name VirtIO port I/O callbacks.
* @{ */
typedef struct VPCIIOCALLBACKS
{
DECLCALLBACKMEMBER(uint32_t, pfnGetHostFeatures)(void *pvState);
DECLCALLBACKMEMBER(uint32_t, pfnGetHostMinimalFeatures)(void *pvState);
DECLCALLBACKMEMBER(void, pfnSetHostFeatures)(void *pvState, uint32_t fFeatures);
DECLCALLBACKMEMBER(int, pfnGetConfig)(void *pvState, uint32_t offCfg, uint32_t cb, void *pvData);
DECLCALLBACKMEMBER(int, pfnSetConfig)(void *pvState, uint32_t offCfg, uint32_t cb, void *pvData);
DECLCALLBACKMEMBER(int, pfnReset)(void *pvState);
DECLCALLBACKMEMBER(void, pfnReady)(void *pvState);
} VPCIIOCALLBACKS;
/** Pointer to a const VirtIO port I/O callback structure. */
typedef const VPCIIOCALLBACKS *PCVPCIIOCALLBACKS;
/** @} */
int vpciRaiseInterrupt(VPCISTATE *pState, int rcBusy, uint8_t u8IntCause);
int vpciIOPortIn(PPDMDEVINS pDevIns,
void *pvUser,
RTIOPORT port,
uint32_t *pu32,
unsigned cb,
PCVPCIIOCALLBACKS pCallbacks);
int vpciIOPortOut(PPDMDEVINS pDevIns,
void *pvUser,
RTIOPORT port,
uint32_t u32,
unsigned cb,
PCVPCIIOCALLBACKS pCallbacks);
void vpciSetWriteLed(PVPCISTATE pState, bool fOn);
void vpciSetReadLed(PVPCISTATE pState, bool fOn);
int vpciSaveExec(PVPCISTATE pState, PSSMHANDLE pSSM);
int vpciLoadExec(PVPCISTATE pState, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t nQueues);
int vpciConstruct(PPDMDEVINS pDevIns, VPCISTATE *pState, int iInstance, const char *pcszNameFmt,
uint16_t uDeviceId, uint16_t uClass, uint32_t nQueues);
int vpciDestruct(VPCISTATE* pState);
void vpciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta);
void vpciReset(PVPCISTATE pState);
void *vpciQueryInterface(struct PDMIBASE *pInterface, const char *pszIID);
PVQUEUE vpciAddQueue(VPCISTATE* pState, unsigned uSize, PFNVPCIQUEUECALLBACK pfnCallback, const char *pcszName);
#define VPCI_CS
DECLINLINE(int) vpciCsEnter(VPCISTATE *pState, int rcBusy)
{
#ifdef VPCI_CS
STAM_PROFILE_START(&pState->CTX_SUFF(StatCs), a);
int rc = PDMCritSectEnter(&pState->cs, rcBusy);
STAM_PROFILE_STOP(&pState->CTX_SUFF(StatCs), a);
return rc;
#else
return VINF_SUCCESS;
#endif
}
DECLINLINE(void) vpciCsLeave(VPCISTATE *pState)
{
#ifdef VPCI_CS
PDMCritSectLeave(&pState->cs);
#endif
}
void vringSetNotification(PVPCISTATE pState, PVRING pVRing, bool fEnabled);
DECLINLINE(uint16_t) vringReadAvailIndex(PVPCISTATE pState, PVRING pVRing)
{
uint16_t tmp;
PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
pVRing->addrAvail + RT_UOFFSETOF(VRINGAVAIL, uNextFreeIndex),
&tmp, sizeof(tmp));
return tmp;
}
bool vqueueSkip(PVPCISTATE pState, PVQUEUE pQueue);
bool vqueueGet(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true);
void vqueuePut(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t uLen, uint32_t uReserved = 0);
void vqueueNotify(PVPCISTATE pState, PVQUEUE pQueue);
void vqueueSync(PVPCISTATE pState, PVQUEUE pQueue);
DECLINLINE(bool) vqueuePeek(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem)
{
return vqueueGet(pState, pQueue, pElem, /* fRemove */ false);
}
DECLINLINE(bool) vqueueIsReady(PVPCISTATE pState, PVQUEUE pQueue)
{
NOREF(pState);
return !!pQueue->VRing.addrAvail;
}
DECLINLINE(bool) vqueueIsEmpty(PVPCISTATE pState, PVQUEUE pQueue)
{
return (vringReadAvailIndex(pState, &pQueue->VRing) == pQueue->uNextAvailIndex);
}
#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_h */
|