Skip to content

Commit 81d0c2a

Browse files
CopilotBernardXiong
andcommitted
[virtio] Add modern VirtIO (v1.2.0) support with backward compatibility
- Updated Kconfig to support both legacy and modern versions - Added version field to virtio_device structure - Implemented 64-bit feature negotiation for modern virtio - Updated queue initialization for modern virtio (separate desc/driver/device areas) - Added FEATURES_OK check for modern virtio - Updated all device drivers (blk, net, console, gpu, input) to use new APIs - Updated BSP drivers to accept both version 1 (legacy) and version 2 (modern) Co-authored-by: BernardXiong <[email protected]>
1 parent e12ae42 commit 81d0c2a

File tree

10 files changed

+240
-34
lines changed

10 files changed

+240
-34
lines changed

bsp/qemu-virt64-aarch64/drivers/drv_virtio.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,17 @@ int rt_virtio_devices_init(void)
7474
mmio_config = (struct virtio_mmio_config *)mmio_base;
7575

7676
if (mmio_config->magic != VIRTIO_MAGIC_VALUE ||
77-
mmio_config->version != RT_USING_VIRTIO_VERSION ||
7877
mmio_config->vendor_id != VIRTIO_VENDOR_ID)
7978
{
8079
continue;
8180
}
8281

82+
/* Support both legacy (0x1) and modern (0x2) versions */
83+
if (mmio_config->version != 1 && mmio_config->version != 2)
84+
{
85+
continue;
86+
}
87+
8388
init_handler = virtio_device_init_handlers[mmio_config->device_id];
8489

8590
if (init_handler != RT_NULL)

bsp/qemu-virt64-riscv/driver/drv_virtio.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,17 @@ int rt_virtio_devices_init(void)
8080
mmio_config = (struct virtio_mmio_config *)mmio_base;
8181

8282
if (mmio_config->magic != VIRTIO_MAGIC_VALUE ||
83-
mmio_config->version != RT_USING_VIRTIO_VERSION ||
8483
mmio_config->vendor_id != VIRTIO_VENDOR_ID)
8584
{
8685
continue;
8786
}
8887

88+
/* Support both legacy (0x1) and modern (0x2) versions */
89+
if (mmio_config->version != 1 && mmio_config->version != 2)
90+
{
91+
continue;
92+
}
93+
8994
init_handler = virtio_device_init_handlers[mmio_config->device_id];
9095

9196
if (init_handler != RT_NULL)

components/drivers/virtio/Kconfig

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,20 @@ menuconfig RT_USING_VIRTIO
55
if RT_USING_VIRTIO
66
choice RT_USING_VIRTIO_VERSION
77
prompt "VirtIO Version"
8-
default RT_USING_VIRTIO10
9-
10-
config RT_USING_VIRTIO10
11-
bool "VirtIO v1.0"
8+
default RT_USING_VIRTIO_LEGACY
9+
10+
config RT_USING_VIRTIO_LEGACY
11+
bool "VirtIO Legacy (v0.95)"
12+
help
13+
Support for VirtIO legacy interface (version 0x1).
14+
This is the older version compatible with most existing QEMU versions.
15+
16+
config RT_USING_VIRTIO_MODERN
17+
bool "VirtIO Modern (v1.0+)"
18+
help
19+
Support for VirtIO modern interface (version 0x2).
20+
This version supports VirtIO 1.0, 1.1, and 1.2 specifications.
21+
Requires QEMU 2.4+ or compatible hypervisor.
1222
endchoice
1323

1424
config RT_USING_VIRTIO_MMIO_ALIGN

components/drivers/virtio/virtio.c

Lines changed: 122 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,27 @@ void virtio_status_driver_ok(struct virtio_device *dev)
3838
{
3939
_virtio_dev_check(dev);
4040

41-
dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK;
41+
if (dev->version == 1)
42+
{
43+
/* Legacy virtio */
44+
dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK;
45+
}
46+
else
47+
{
48+
/* Modern virtio: set FEATURES_OK and verify it */
49+
dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK;
50+
51+
/* Verify that device accepted the features */
52+
if (!(dev->mmio_config->status & VIRTIO_STATUS_FEATURES_OK))
53+
{
54+
/* Device doesn't support our feature subset */
55+
dev->mmio_config->status |= VIRTIO_STATUS_FAILED;
56+
return;
57+
}
58+
59+
/* Now set DRIVER_OK */
60+
dev->mmio_config->status |= VIRTIO_STATUS_DRIVER_OK;
61+
}
4262
}
4363

4464
void virtio_interrupt_ack(struct virtio_device *dev)
@@ -59,7 +79,66 @@ rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit)
5979
{
6080
_virtio_dev_check(dev);
6181

62-
return !!(dev->mmio_config->device_features & (1UL << feature_bit));
82+
if (dev->version == 1)
83+
{
84+
/* Legacy: 32-bit feature bits only */
85+
return !!(dev->mmio_config->device_features & (1UL << feature_bit));
86+
}
87+
else
88+
{
89+
/* Modern: Use 64-bit feature access */
90+
rt_uint64_t features = virtio_get_features(dev);
91+
return !!(features & (1ULL << feature_bit));
92+
}
93+
}
94+
95+
rt_uint64_t virtio_get_features(struct virtio_device *dev)
96+
{
97+
rt_uint64_t features = 0;
98+
99+
_virtio_dev_check(dev);
100+
101+
if (dev->version == 1)
102+
{
103+
/* Legacy: only lower 32 bits */
104+
features = dev->mmio_config->device_features;
105+
}
106+
else
107+
{
108+
/* Modern: read both 32-bit halves */
109+
dev->mmio_config->device_features_sel = 0;
110+
features = dev->mmio_config->device_features;
111+
112+
dev->mmio_config->device_features_sel = 1;
113+
features |= ((rt_uint64_t)dev->mmio_config->device_features) << 32;
114+
}
115+
116+
return features;
117+
}
118+
119+
void virtio_set_features(struct virtio_device *dev, rt_uint64_t features)
120+
{
121+
_virtio_dev_check(dev);
122+
123+
if (dev->version == 1)
124+
{
125+
/* Legacy: only lower 32 bits */
126+
dev->mmio_config->driver_features = (rt_uint32_t)features;
127+
}
128+
else
129+
{
130+
/* Modern: write both 32-bit halves */
131+
dev->mmio_config->driver_features_sel = 0;
132+
dev->mmio_config->driver_features = (rt_uint32_t)features;
133+
134+
dev->mmio_config->driver_features_sel = 1;
135+
dev->mmio_config->driver_features = (rt_uint32_t)(features >> 32);
136+
}
137+
}
138+
139+
rt_bool_t virtio_has_feature_64(struct virtio_device *dev, rt_uint64_t features, rt_uint32_t feature_bit)
140+
{
141+
return !!(features & (1ULL << feature_bit));
63142
}
64143

65144
rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num)
@@ -93,6 +172,7 @@ rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, r
93172
void *pages;
94173
rt_size_t pages_total_size;
95174
struct virtq *queue;
175+
rt_uint64_t desc_addr, avail_addr, used_addr;
96176

97177
_virtio_dev_check(dev);
98178

@@ -123,18 +203,44 @@ rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, r
123203

124204
rt_memset(pages, 0, pages_total_size);
125205

126-
dev->mmio_config->guest_page_size = VIRTIO_PAGE_SIZE;
206+
/* Set queue selector */
127207
dev->mmio_config->queue_sel = queue_index;
128208
dev->mmio_config->queue_num = ring_size;
129-
dev->mmio_config->queue_align = VIRTIO_PAGE_SIZE;
130-
dev->mmio_config->queue_pfn = VIRTIO_VA2PA(pages) >> VIRTIO_PAGE_SHIFT;
131209

210+
/* Calculate queue area addresses */
132211
queue->num = ring_size;
133212
queue->desc = (struct virtq_desc *)((rt_ubase_t)pages);
134213
queue->avail = (struct virtq_avail *)(((rt_ubase_t)pages) + VIRTQ_DESC_TOTAL_SIZE(ring_size));
135214
queue->used = (struct virtq_used *)VIRTIO_PAGE_ALIGN(
136215
(rt_ubase_t)&queue->avail->ring[ring_size] + VIRTQ_AVAIL_RES_SIZE);
137216

217+
desc_addr = VIRTIO_VA2PA(queue->desc);
218+
avail_addr = VIRTIO_VA2PA(queue->avail);
219+
used_addr = VIRTIO_VA2PA(queue->used);
220+
221+
if (dev->version == 1)
222+
{
223+
/* Legacy virtio: use queue_pfn */
224+
dev->mmio_config->guest_page_size = VIRTIO_PAGE_SIZE;
225+
dev->mmio_config->queue_align = VIRTIO_PAGE_SIZE;
226+
dev->mmio_config->queue_pfn = desc_addr >> VIRTIO_PAGE_SHIFT;
227+
}
228+
else
229+
{
230+
/* Modern virtio: use separate descriptor/driver/device registers */
231+
dev->mmio_config->queue_desc_low = (rt_uint32_t)desc_addr;
232+
dev->mmio_config->queue_desc_high = (rt_uint32_t)(desc_addr >> 32);
233+
234+
dev->mmio_config->queue_driver_low = (rt_uint32_t)avail_addr;
235+
dev->mmio_config->queue_driver_high = (rt_uint32_t)(avail_addr >> 32);
236+
237+
dev->mmio_config->queue_device_low = (rt_uint32_t)used_addr;
238+
dev->mmio_config->queue_device_high = (rt_uint32_t)(used_addr >> 32);
239+
240+
/* Enable the queue */
241+
dev->mmio_config->queue_ready = 1;
242+
}
243+
138244
queue->used_idx = 0;
139245

140246
/* All descriptors start out unused */
@@ -165,7 +271,17 @@ void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index)
165271
rt_free_align((void *)queue->desc);
166272

167273
dev->mmio_config->queue_sel = queue_index;
168-
dev->mmio_config->queue_pfn = RT_NULL;
274+
275+
if (dev->version == 1)
276+
{
277+
/* Legacy virtio */
278+
dev->mmio_config->queue_pfn = 0;
279+
}
280+
else
281+
{
282+
/* Modern virtio */
283+
dev->mmio_config->queue_ready = 0;
284+
}
169285

170286
queue->num = 0;
171287
queue->desc = RT_NULL;

components/drivers/virtio/virtio.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,13 @@
2424
#error "Please set RT_NAME_MAX to at lest 16"
2525
#endif
2626

27-
#ifdef RT_USING_VIRTIO10
28-
#define RT_USING_VIRTIO_VERSION 0x1
27+
/* VirtIO version configuration */
28+
#ifdef RT_USING_VIRTIO_LEGACY
29+
#define RT_USING_VIRTIO_VERSION 0x1 /* Legacy interface */
30+
#elif defined(RT_USING_VIRTIO_MODERN)
31+
#define RT_USING_VIRTIO_VERSION 0x2 /* Modern interface (1.0+) */
32+
#else
33+
#define RT_USING_VIRTIO_VERSION 0x1 /* Default to legacy */
2934
#endif
3035

3136
#include <virtio_mmio.h>
@@ -111,6 +116,7 @@ enum
111116
struct virtio_device
112117
{
113118
rt_uint32_t irq;
119+
rt_uint32_t version; /* VirtIO version from MMIO config */
114120

115121
struct virtq *queues;
116122
rt_size_t queues_num;
@@ -136,6 +142,11 @@ void virtio_status_driver_ok(struct virtio_device *dev);
136142
void virtio_interrupt_ack(struct virtio_device *dev);
137143
rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit);
138144

145+
/* Modern VirtIO feature negotiation (64-bit features) */
146+
rt_uint64_t virtio_get_features(struct virtio_device *dev);
147+
void virtio_set_features(struct virtio_device *dev, rt_uint64_t features);
148+
rt_bool_t virtio_has_feature_64(struct virtio_device *dev, rt_uint64_t features, rt_uint32_t feature_bit);
149+
139150
rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num);
140151
void virtio_queues_free(struct virtio_device *dev);
141152
rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size);

components/drivers/virtio/virtio_blk.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
178178
char dev_name[RT_NAME_MAX];
179179
struct virtio_device *virtio_dev;
180180
struct virtio_blk_device *virtio_blk_dev;
181+
rt_uint64_t device_features, driver_features;
181182

182183
virtio_blk_dev = rt_malloc(sizeof(struct virtio_blk_device));
183184

@@ -189,6 +190,7 @@ rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
189190
virtio_dev = &virtio_blk_dev->virtio_dev;
190191
virtio_dev->irq = irq;
191192
virtio_dev->mmio_base = mmio_base;
193+
virtio_dev->version = virtio_dev->mmio_config->version;
192194

193195
virtio_blk_dev->config = (struct virtio_blk_config *)virtio_dev->mmio_config->config;
194196

@@ -200,14 +202,23 @@ rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
200202
virtio_status_acknowledge_driver(virtio_dev);
201203

202204
/* Negotiate features */
203-
virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
204-
(1 << VIRTIO_BLK_F_RO) |
205-
(1 << VIRTIO_BLK_F_MQ) |
206-
(1 << VIRTIO_BLK_F_SCSI) |
207-
(1 << VIRTIO_BLK_F_CONFIG_WCE) |
208-
(1 << VIRTIO_F_ANY_LAYOUT) |
209-
(1 << VIRTIO_F_RING_EVENT_IDX) |
210-
(1 << VIRTIO_F_RING_INDIRECT_DESC));
205+
device_features = virtio_get_features(virtio_dev);
206+
driver_features = device_features & ~(
207+
(1ULL << VIRTIO_BLK_F_RO) |
208+
(1ULL << VIRTIO_BLK_F_MQ) |
209+
(1ULL << VIRTIO_BLK_F_SCSI) |
210+
(1ULL << VIRTIO_BLK_F_CONFIG_WCE) |
211+
(1ULL << VIRTIO_F_ANY_LAYOUT) |
212+
(1ULL << VIRTIO_F_RING_EVENT_IDX) |
213+
(1ULL << VIRTIO_F_RING_INDIRECT_DESC));
214+
215+
/* For modern virtio, we must support VERSION_1 */
216+
if (virtio_dev->version == 2)
217+
{
218+
driver_features |= (1ULL << VIRTIO_F_VERSION_1);
219+
}
220+
221+
virtio_set_features(virtio_dev, driver_features);
211222

212223
/* Tell device that feature negotiation is complete and we're completely ready */
213224
virtio_status_driver_ok(virtio_dev);

components/drivers/virtio/virtio_console.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
674674
char dev_name[RT_NAME_MAX];
675675
struct virtio_device *virtio_dev;
676676
struct virtio_console_device *virtio_console_dev;
677+
rt_uint64_t device_features, driver_features;
677678

678679
RT_ASSERT(RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR > 0);
679680

@@ -687,6 +688,7 @@ rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
687688
virtio_dev = &virtio_console_dev->virtio_dev;
688689
virtio_dev->irq = irq;
689690
virtio_dev->mmio_base = mmio_base;
691+
virtio_dev->version = virtio_dev->mmio_config->version;
690692

691693
virtio_console_dev->config = (struct virtio_console_config *)virtio_dev->mmio_config->config;
692694

@@ -697,9 +699,19 @@ rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
697699
virtio_reset_device(virtio_dev);
698700
virtio_status_acknowledge_driver(virtio_dev);
699701

700-
virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
701-
(1 << VIRTIO_F_RING_EVENT_IDX) |
702-
(1 << VIRTIO_F_RING_INDIRECT_DESC));
702+
/* Negotiate features */
703+
device_features = virtio_get_features(virtio_dev);
704+
driver_features = device_features & ~(
705+
(1ULL << VIRTIO_F_RING_EVENT_IDX) |
706+
(1ULL << VIRTIO_F_RING_INDIRECT_DESC));
707+
708+
/* For modern virtio, we must support VERSION_1 */
709+
if (virtio_dev->version == 2)
710+
{
711+
driver_features |= (1ULL << VIRTIO_F_VERSION_1);
712+
}
713+
714+
virtio_set_features(virtio_dev, driver_features);
703715

704716
virtio_status_driver_ok(virtio_dev);
705717

components/drivers/virtio/virtio_gpu.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,7 @@ rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
850850
char dev_name[RT_NAME_MAX];
851851
struct virtio_device *virtio_dev;
852852
struct virtio_gpu_device *virtio_gpu_dev;
853+
rt_uint64_t device_features, driver_features;
853854

854855
virtio_gpu_dev = rt_malloc(sizeof(struct virtio_gpu_device));
855856

@@ -861,6 +862,7 @@ rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
861862
virtio_dev = &virtio_gpu_dev->virtio_dev;
862863
virtio_dev->irq = irq;
863864
virtio_dev->mmio_base = mmio_base;
865+
virtio_dev->version = virtio_dev->mmio_config->version;
864866

865867
virtio_gpu_dev->pmode_id = VIRTIO_GPU_INVALID_PMODE_ID;
866868
virtio_gpu_dev->display_resource_id = 0;
@@ -877,9 +879,19 @@ rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
877879
virtio_reset_device(virtio_dev);
878880
virtio_status_acknowledge_driver(virtio_dev);
879881

880-
virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
881-
(1 << VIRTIO_F_RING_EVENT_IDX) |
882-
(1 << VIRTIO_F_RING_INDIRECT_DESC));
882+
/* Negotiate features */
883+
device_features = virtio_get_features(virtio_dev);
884+
driver_features = device_features & ~(
885+
(1ULL << VIRTIO_F_RING_EVENT_IDX) |
886+
(1ULL << VIRTIO_F_RING_INDIRECT_DESC));
887+
888+
/* For modern virtio, we must support VERSION_1 */
889+
if (virtio_dev->version == 2)
890+
{
891+
driver_features |= (1ULL << VIRTIO_F_VERSION_1);
892+
}
893+
894+
virtio_set_features(virtio_dev, driver_features);
883895

884896
virtio_status_driver_ok(virtio_dev);
885897

0 commit comments

Comments
 (0)