forked from virtio-win/kvm-guest-drivers-windows
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvirtio_pci.h
392 lines (325 loc) · 15.7 KB
/
virtio_pci.h
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
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
/*
* Virtio PCI driver
*
* This module allows virtio devices to be used over a virtual PCI device.
* This can be used with QEMU based VMMs like KVM or Xen.
*
* Copyright IBM Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of IBM nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LINUX_VIRTIO_PCI_H
#define _LINUX_VIRTIO_PCI_H
#include "linux/types.h"
#include "linux/virtio_config.h"
#ifndef VIRTIO_PCI_NO_LEGACY
/* A 32-bit r/o bitmask of the features supported by the host */
#define VIRTIO_PCI_HOST_FEATURES 0
/* A 32-bit r/w bitmask of features activated by the guest */
#define VIRTIO_PCI_GUEST_FEATURES 4
/* A 32-bit r/w PFN for the currently selected queue */
#define VIRTIO_PCI_QUEUE_PFN 8
/* A 16-bit r/o queue size for the currently selected queue */
#define VIRTIO_PCI_QUEUE_NUM 12
/* A 16-bit r/w queue selector */
#define VIRTIO_PCI_QUEUE_SEL 14
/* A 16-bit r/w queue notifier */
#define VIRTIO_PCI_QUEUE_NOTIFY 16
/* An 8-bit device status register. */
#define VIRTIO_PCI_STATUS 18
/* An 8-bit r/o interrupt status register. Reading the value will return the
* current contents of the ISR and will also clear it. This is effectively
* a read-and-acknowledge. */
#define VIRTIO_PCI_ISR 19
/* MSI-X registers: only enabled if MSI-X is enabled. */
/* A 16-bit vector for configuration changes. */
#define VIRTIO_MSI_CONFIG_VECTOR 20
/* A 16-bit vector for selected queue notifications. */
#define VIRTIO_MSI_QUEUE_VECTOR 22
/* The remaining space is defined by each driver as the per-driver
* configuration space */
#define VIRTIO_PCI_CONFIG_OFF(msix_enabled) ((msix_enabled) ? 24 : 20)
/* Deprecated: please use VIRTIO_PCI_CONFIG_OFF instead */
#define VIRTIO_PCI_CONFIG(msix_enabled) VIRTIO_PCI_CONFIG_OFF(msix_enabled)
/* How many bits to shift physical queue address written to QUEUE_PFN.
* 12 is historical, and due to x86 page size. */
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
/* The alignment to use between consumer and producer parts of vring.
* x86 pagesize again. */
#define VIRTIO_PCI_VRING_ALIGN 4096
#endif /* VIRTIO_PCI_NO_LEGACY */
/* The bit of the ISR which indicates a device configuration change. */
#define VIRTIO_PCI_ISR_CONFIG 0x2
/* Vector value used to disable MSI for queue */
#define VIRTIO_MSI_NO_VECTOR 0xffff
/* IDs for different capabilities. Must all exist. */
/* Common configuration */
#define VIRTIO_PCI_CAP_COMMON_CFG 1
/* Notifications */
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
/* ISR access */
#define VIRTIO_PCI_CAP_ISR_CFG 3
/* Device specific configuration */
#define VIRTIO_PCI_CAP_DEVICE_CFG 4
/* PCI configuration access */
#define VIRTIO_PCI_CAP_PCI_CFG 5
/* This is the PCI capability header: */
struct virtio_pci_cap {
__u8 cap_vndr; /* Generic PCI field: PCI_CAPABILITY_ID_VENDOR_SPECIFIC */
__u8 cap_next; /* Generic PCI field: next ptr. */
__u8 cap_len; /* Generic PCI field: capability length */
__u8 cfg_type; /* Identifies the structure. */
__u8 bar; /* Where to find it. */
__u8 padding[3]; /* Pad to full dword. */
__le32 offset; /* Offset within bar. */
__le32 length; /* Length of the structure, in bytes. */
};
struct virtio_pci_notify_cap {
struct virtio_pci_cap cap;
__le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
};
/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
struct virtio_pci_common_cfg {
/* About the whole device. */
__le32 device_feature_select; /* read-write */
__le32 device_feature; /* read-only */
__le32 guest_feature_select; /* read-write */
__le32 guest_feature; /* read-write */
__le16 msix_config; /* read-write */
__le16 num_queues; /* read-only */
__u8 device_status; /* read-write */
__u8 config_generation; /* read-only */
/* About a specific virtqueue. */
__le16 queue_select; /* read-write */
__le16 queue_size; /* read-write, power of 2. */
__le16 queue_msix_vector; /* read-write */
__le16 queue_enable; /* read-write */
__le16 queue_notify_off; /* read-only */
__le32 queue_desc_lo; /* read-write */
__le32 queue_desc_hi; /* read-write */
__le32 queue_avail_lo; /* read-write */
__le32 queue_avail_hi; /* read-write */
__le32 queue_used_lo; /* read-write */
__le32 queue_used_hi; /* read-write */
};
#define MAX_QUEUES_PER_DEVICE_DEFAULT 8
typedef struct virtio_queue_info
{
/* the actual virtqueue */
struct virtqueue *vq;
/* the number of entries in the queue */
u16 num;
/* the virtual address of the ring queue */
void *queue;
} VirtIOQueueInfo;
typedef struct virtio_system_ops {
// device register access
u8 (*vdev_read_byte)(ULONG_PTR ulRegister);
u16 (*vdev_read_word)(ULONG_PTR ulRegister);
u32 (*vdev_read_dword)(ULONG_PTR ulRegister);
void (*vdev_write_byte)(ULONG_PTR ulRegister, u8 bValue);
void (*vdev_write_word)(ULONG_PTR ulRegister, u16 wValue);
void (*vdev_write_dword)(ULONG_PTR ulRegister, u32 ulValue);
// memory management
void *(*mem_alloc_contiguous_pages)(void *context, size_t size);
void (*mem_free_contiguous_pages)(void *context, void *virt);
ULONGLONG (*mem_get_physical_address)(void *context, void *virt);
void *(*mem_alloc_nonpaged_block)(void *context, size_t size);
void (*mem_free_nonpaged_block)(void *context, void *addr);
// PCI config space access
int (*pci_read_config_byte)(void *context, int where, u8 *bVal);
int (*pci_read_config_word)(void *context, int where, u16 *wVal);
int (*pci_read_config_dword)(void *context, int where, u32 *dwVal);
// PCI resource handling
size_t (*pci_get_resource_len)(void *context, int bar);
void *(*pci_map_address_range)(void *context, int bar, size_t offset, size_t maxlen);
// misc
u16 (*vdev_get_msix_vector)(void *context, int queue);
void (*vdev_sleep)(void *context, unsigned int msecs);
} VirtIOSystemOps;
struct virtio_device;
typedef struct virtio_device VirtIODevice;
struct virtio_device_ops
{
// read/write device config and read config generation counter
void (*get_config)(VirtIODevice *vdev, unsigned offset, void *buf, unsigned len);
void (*set_config)(VirtIODevice *vdev, unsigned offset, const void *buf, unsigned len);
u32 (*get_config_generation)(VirtIODevice *vdev);
// read/write device status byte and reset the device
u8 (*get_status)(VirtIODevice *vdev);
void (*set_status)(VirtIODevice *vdev, u8 status);
void (*reset)(VirtIODevice *vdev);
// get/set device feature bits
u64 (*get_features)(VirtIODevice *vdev);
NTSTATUS (*set_features)(VirtIODevice *vdev, u64 features);
// set config/queue MSI interrupt vector, returns the new vector
u16 (*set_config_vector)(VirtIODevice *vdev, u16 vector);
u16 (*set_queue_vector)(struct virtqueue *vq, u16 vector);
// query virtual queue size and memory requirements
NTSTATUS (*query_queue_alloc)(VirtIODevice *vdev,
unsigned index, unsigned short *pNumEntries,
unsigned long *pRingSize,
unsigned long *pHeapSize);
// allocate and initialize a queue
NTSTATUS (*setup_queue)(struct virtqueue **queue,
VirtIODevice *vdev, VirtIOQueueInfo *info,
unsigned idx, u16 msix_vec);
// tear down and deallocate a queue
void (*delete_queue)(VirtIOQueueInfo *info);
};
struct virtio_device
{
// the I/O port BAR of the PCI device (legacy virtio devices only)
ULONG_PTR addr;
// true if the device uses MSI interrupts
bool msix_used;
// true if the VIRTIO_RING_F_EVENT_IDX feature flag has been negotiated
bool event_suppression_enabled;
// true if the VIRTIO_F_RING_PACKED feature flag has been negotiated
bool packed_ring;
// internal device operations, implemented separately for legacy and modern
const struct virtio_device_ops *device;
// external callbacks implemented separately by different driver model drivers
const struct virtio_system_ops *system;
// opaque context value passed as first argument to virtio_system_ops callbacks
void *DeviceContext;
// the ISR status field, reading causes the device to de-assert an interrupt
volatile u8 *isr;
// modern virtio device capabilities and related state
volatile struct virtio_pci_common_cfg *common;
volatile unsigned char *config;
volatile unsigned char *notify_base;
int notify_map_cap;
u32 notify_offset_multiplier;
size_t config_len;
size_t notify_len;
// maximum number of virtqueues that fit in the memory block pointed to by info
ULONG maxQueues;
// points to inline_info if not more than MAX_QUEUES_PER_DEVICE_DEFAULT queues
// are used, or to an external allocation otherwise
VirtIOQueueInfo *info;
VirtIOQueueInfo inline_info[MAX_QUEUES_PER_DEVICE_DEFAULT];
};
/* Driver API: device init and shutdown
* DeviceContext is a driver defined opaque value which will be passed to driver
* supplied callbacks described in pSystemOps. pSystemOps must be non-NULL and all
* its fields must be non-NULL. msix_used is true if and only if the device is
* configured with MSI support.
*/
NTSTATUS virtio_device_initialize(VirtIODevice *vdev,
const VirtIOSystemOps *pSystemOps,
void *DeviceContext,
bool msix_used);
void virtio_device_shutdown(VirtIODevice *vdev);
/* Driver API: device status manipulation
* virtio_set_status should not be called by new drivers. Device status should only
* be getting its bits set with virtio_add_status and reset all back to 0 with
* virtio_device_reset. virtio_device_ready is a special version of virtio_add_status
* which adds the VIRTIO_CONFIG_S_DRIVER_OK status bit.
*/
u8 virtio_get_status(VirtIODevice *vdev);
void virtio_set_status(VirtIODevice *vdev, u8 status);
void virtio_add_status(VirtIODevice *vdev, u8 status);
void virtio_device_reset(VirtIODevice *vdev);
void virtio_device_ready(VirtIODevice *vdev);
/* Driver API: device feature bitmap manipulation
* Features passed to virtio_set_features should be a subset of features offered by
* the device as returned from virtio_get_features. virtio_set_features sets the
* VIRTIO_CONFIG_S_FEATURES_OK status bit if it is supported by the device.
*/
#define virtio_is_feature_enabled(FeaturesList, Feature) (!!((FeaturesList) & (1ULL << (Feature))))
#define virtio_feature_enable(FeaturesList, Feature) ((FeaturesList) |= (1ULL << (Feature)))
#define virtio_feature_disable(FeaturesList, Feature) ((FeaturesList) &= ~(1ULL << (Feature)))
u64 virtio_get_features(VirtIODevice *dev);
NTSTATUS virtio_set_features(VirtIODevice *vdev, u64 features);
/* Driver API: device configuration access
* Both virtio_get_config and virtio_set_config support arbitrary values of the len
* parameter. Config items of length 1, 2, and 4 are read/written using one access,
* length 8 is broken down to two 4 bytes accesses, and any other length is read or
* written byte by byte.
*/
void virtio_get_config(VirtIODevice *vdev, unsigned offset,
void *buf, unsigned len);
void virtio_set_config(VirtIODevice *vdev, unsigned offset,
void *buf, unsigned len);
/* Driver API: virtqueue setup
* virtio_reserve_queue_memory makes VirtioLib reserve memory for its virtqueue
* bookkeeping. Drivers should call this function if they intend to set up queues
* one by one with virtio_find_queue. virtio_find_queues (plural) internally takes
* care of the reservation and virtio_reserve_queue_memory need not be called.
* Note that in addition to queue interrupt vectors, virtio_find_queues also sets
* up the device config vector as a convenience.
* Drivers should treat the returned struct virtqueue pointers as opaque handles.
*/
NTSTATUS virtio_query_queue_allocation(VirtIODevice *vdev, unsigned index,
unsigned short *pNumEntries,
unsigned long *pRingSize,
unsigned long *pHeapSize);
NTSTATUS virtio_reserve_queue_memory(VirtIODevice *vdev, unsigned nvqs);
NTSTATUS virtio_find_queue(VirtIODevice *vdev, unsigned index,
struct virtqueue **vq);
NTSTATUS virtio_find_queues(VirtIODevice *vdev, unsigned nvqs,
struct virtqueue *vqs[]);
/* Driver API: virtqueue shutdown
* The device must be reset and re-initialized to re-setup queues after they have
* been deleted.
*/
void virtio_delete_queue(struct virtqueue *vq);
void virtio_delete_queues(VirtIODevice *vdev);
/* Driver API: virtqueue query and manipulation
* virtio_get_queue_descriptor_size
* is useful in situations where the driver has to prepare for the memory allocation
* performed by virtio_reserve_queue_memory beforehand.
*/
u32 virtio_get_queue_size(struct virtqueue *vq);
unsigned long virtio_get_indirect_page_capacity();
ULONG __inline virtio_get_queue_descriptor_size()
{
return sizeof(VirtIOQueueInfo);
}
/* Driver API: interrupt handling
* virtio_set_config_vector and virtio_set_queue_vector set the MSI vector used for
* device configuration interrupt and queue interrupt, respectively. The driver may
* choose to either return the vector from the vdev_get_msix_vector callback (called
* as part of queue setup) or call these functions later. Note that setting the vector
* may fail which is indicated by the return value of VIRTIO_MSI_NO_VECTOR.
* virtio_read_isr_status returns the value of the ISR status register, note that it
* is not idempotent, calling the function makes the device de-assert the interrupt.
*/
u16 virtio_set_config_vector(VirtIODevice *vdev, u16 vector);
u16 virtio_set_queue_vector(struct virtqueue *vq, u16 vector);
u8 virtio_read_isr_status(VirtIODevice *vdev);
/* Driver API: miscellaneous helpers
* virtio_get_bar_index returns the corresponding BAR index given its physical address.
* This tends to be useful to all drivers since Windows doesn't provide reliable BAR
* indices as part of resource enumeration. The function returns -1 on failure.
*/
int virtio_get_bar_index(PPCI_COMMON_HEADER pPCIHeader, PHYSICAL_ADDRESS BasePA);
#endif