summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/VirtIO/Virtio.h
blob: 492f5944ebea1fd5ee823f10a0685517fe65651f (plain)
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 */