blob: c2c6d854750c82013263c731aaff0d77db6e9a57 [file] [log] [blame]
Peter Maydell4b525302013-07-16 13:25:09 +01001/*
2 * Virtio MMIO bindings
3 *
4 * Copyright (c) 2011 Linaro Limited
5 *
6 * Author:
7 * Peter Maydell <peter.maydell@linaro.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21
Peter Maydell9b8bfe22016-01-26 18:17:07 +000022#include "qemu/osdep.h"
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +020023#include "standard-headers/linux/virtio_mmio.h"
Markus Armbruster64552b62019-08-12 07:23:42 +020024#include "hw/irq.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020025#include "hw/qdev-properties.h"
Peter Maydell4b525302013-07-16 13:25:09 +010026#include "hw/sysbus.h"
27#include "hw/virtio/virtio.h"
Markus Armbrusterca77ee22019-08-12 07:23:39 +020028#include "migration/qemu-file-types.h"
Peter Maydell4b525302013-07-16 13:25:09 +010029#include "qemu/host-utils.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020030#include "qemu/module.h"
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030031#include "sysemu/kvm.h"
Pavel Dovgalyuk3909c072021-05-17 16:06:28 +030032#include "sysemu/replay.h"
Sergio Lopezbca964b2019-09-26 15:02:22 +020033#include "hw/virtio/virtio-mmio.h"
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030034#include "qemu/error-report.h"
Boxuan Lida1804d2019-05-03 23:44:24 +080035#include "qemu/log.h"
36#include "trace.h"
Peter Maydell4b525302013-07-16 13:25:09 +010037
Paolo Bonzini8e93cef2016-10-21 22:48:08 +020038static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
Cornelia Huckc0971bc2016-06-10 11:04:13 +020039{
Pavel Dovgalyukb8893a32021-03-29 10:43:12 +030040 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
41
42 return (proxy->flags & VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD) != 0;
Cornelia Huckc0971bc2016-06-10 11:04:13 +020043}
44
45static int virtio_mmio_ioeventfd_assign(DeviceState *d,
46 EventNotifier *notifier,
47 int n, bool assign)
48{
49 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030050
51 if (assign) {
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +020052 memory_region_add_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUE_NOTIFY, 4,
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030053 true, n, notifier);
54 } else {
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +020055 memory_region_del_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUE_NOTIFY, 4,
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030056 true, n, notifier);
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030057 }
Cornelia Huckc0971bc2016-06-10 11:04:13 +020058 return 0;
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030059}
60
61static void virtio_mmio_start_ioeventfd(VirtIOMMIOProxy *proxy)
62{
Cornelia Huckc0971bc2016-06-10 11:04:13 +020063 virtio_bus_start_ioeventfd(&proxy->bus);
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030064}
65
66static void virtio_mmio_stop_ioeventfd(VirtIOMMIOProxy *proxy)
67{
Cornelia Huckc0971bc2016-06-10 11:04:13 +020068 virtio_bus_stop_ioeventfd(&proxy->bus);
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +030069}
70
Jean-Philippe Brucker351da832019-12-13 10:54:10 +010071static void virtio_mmio_soft_reset(VirtIOMMIOProxy *proxy)
72{
73 int i;
74
Paolo Bonzini26cfd672022-06-09 08:54:54 +020075 virtio_bus_reset(&proxy->bus);
Jean-Philippe Brucker351da832019-12-13 10:54:10 +010076
Paolo Bonzini26cfd672022-06-09 08:54:54 +020077 if (!proxy->legacy) {
78 for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
79 proxy->vqs[i].enabled = 0;
80 }
Jean-Philippe Brucker351da832019-12-13 10:54:10 +010081 }
82}
83
Peter Maydell4b525302013-07-16 13:25:09 +010084static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
85{
86 VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
Paolo Bonzini06d3dff2013-09-20 13:31:39 +020087 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
Peter Maydell4b525302013-07-16 13:25:09 +010088
Boxuan Lida1804d2019-05-03 23:44:24 +080089 trace_virtio_mmio_read(offset);
Peter Maydell4b525302013-07-16 13:25:09 +010090
91 if (!vdev) {
92 /* If no backend is present, we treat most registers as
93 * read-as-zero, except for the magic number, version and
94 * vendor ID. This is not strictly sanctioned by the virtio
95 * spec, but it allows us to provide transports with no backend
96 * plugged in which don't confuse Linux's virtio code: the
97 * probe won't complain about the bad magic number, but the
98 * device ID of zero means no backend will claim it.
99 */
100 switch (offset) {
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200101 case VIRTIO_MMIO_MAGIC_VALUE:
Peter Maydell4b525302013-07-16 13:25:09 +0100102 return VIRT_MAGIC;
103 case VIRTIO_MMIO_VERSION:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200104 if (proxy->legacy) {
105 return VIRT_VERSION_LEGACY;
106 } else {
107 return VIRT_VERSION;
108 }
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200109 case VIRTIO_MMIO_VENDOR_ID:
Peter Maydell4b525302013-07-16 13:25:09 +0100110 return VIRT_VENDOR;
111 default:
112 return 0;
113 }
114 }
115
116 if (offset >= VIRTIO_MMIO_CONFIG) {
117 offset -= VIRTIO_MMIO_CONFIG;
Laurent Vivier0ab8c022021-03-14 21:03:00 +0100118 if (proxy->legacy) {
119 switch (size) {
120 case 1:
121 return virtio_config_readb(vdev, offset);
122 case 2:
123 return virtio_config_readw(vdev, offset);
124 case 4:
125 return virtio_config_readl(vdev, offset);
126 default:
127 abort();
128 }
129 } else {
130 switch (size) {
131 case 1:
132 return virtio_config_modern_readb(vdev, offset);
133 case 2:
134 return virtio_config_modern_readw(vdev, offset);
135 case 4:
136 return virtio_config_modern_readl(vdev, offset);
137 default:
138 abort();
139 }
Peter Maydell4b525302013-07-16 13:25:09 +0100140 }
141 }
142 if (size != 4) {
Boxuan Lida1804d2019-05-03 23:44:24 +0800143 qemu_log_mask(LOG_GUEST_ERROR,
144 "%s: wrong size access to register!\n",
145 __func__);
Peter Maydell4b525302013-07-16 13:25:09 +0100146 return 0;
147 }
148 switch (offset) {
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200149 case VIRTIO_MMIO_MAGIC_VALUE:
Peter Maydell4b525302013-07-16 13:25:09 +0100150 return VIRT_MAGIC;
151 case VIRTIO_MMIO_VERSION:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200152 if (proxy->legacy) {
153 return VIRT_VERSION_LEGACY;
154 } else {
155 return VIRT_VERSION;
156 }
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200157 case VIRTIO_MMIO_DEVICE_ID:
Peter Maydell4b525302013-07-16 13:25:09 +0100158 return vdev->device_id;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200159 case VIRTIO_MMIO_VENDOR_ID:
Peter Maydell4b525302013-07-16 13:25:09 +0100160 return VIRT_VENDOR;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200161 case VIRTIO_MMIO_DEVICE_FEATURES:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200162 if (proxy->legacy) {
163 if (proxy->host_features_sel) {
164 return 0;
165 } else {
166 return vdev->host_features;
167 }
168 } else {
169 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
170 return (vdev->host_features & ~vdc->legacy_features)
171 >> (32 * proxy->host_features_sel);
Peter Maydell4b525302013-07-16 13:25:09 +0100172 }
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200173 case VIRTIO_MMIO_QUEUE_NUM_MAX:
Peter Maydellf7b803b2013-07-26 16:41:28 +0100174 if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
175 return 0;
176 }
Peter Maydell4b525302013-07-16 13:25:09 +0100177 return VIRTQUEUE_MAX_SIZE;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200178 case VIRTIO_MMIO_QUEUE_PFN:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200179 if (!proxy->legacy) {
180 qemu_log_mask(LOG_GUEST_ERROR,
181 "%s: read from legacy register (0x%"
182 HWADDR_PRIx ") in non-legacy mode\n",
183 __func__, offset);
184 return 0;
185 }
Peter Maydell4b525302013-07-16 13:25:09 +0100186 return virtio_queue_get_addr(vdev, vdev->queue_sel)
187 >> proxy->guest_page_shift;
Sergio Lopez44e687a2019-09-13 14:06:01 +0200188 case VIRTIO_MMIO_QUEUE_READY:
189 if (proxy->legacy) {
190 qemu_log_mask(LOG_GUEST_ERROR,
191 "%s: read from non-legacy register (0x%"
192 HWADDR_PRIx ") in legacy mode\n",
193 __func__, offset);
194 return 0;
195 }
196 return proxy->vqs[vdev->queue_sel].enabled;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200197 case VIRTIO_MMIO_INTERRUPT_STATUS:
Stefan Hajnoczid73415a2020-09-23 11:56:46 +0100198 return qatomic_read(&vdev->isr);
Peter Maydell4b525302013-07-16 13:25:09 +0100199 case VIRTIO_MMIO_STATUS:
200 return vdev->status;
Sergio Lopez44e687a2019-09-13 14:06:01 +0200201 case VIRTIO_MMIO_CONFIG_GENERATION:
202 if (proxy->legacy) {
203 qemu_log_mask(LOG_GUEST_ERROR,
204 "%s: read from non-legacy register (0x%"
205 HWADDR_PRIx ") in legacy mode\n",
206 __func__, offset);
207 return 0;
208 }
209 return vdev->generation;
Laurent Vivier2d9e7d42020-12-20 17:35:39 +0100210 case VIRTIO_MMIO_SHM_LEN_LOW:
211 case VIRTIO_MMIO_SHM_LEN_HIGH:
212 /*
213 * VIRTIO_MMIO_SHM_SEL is unimplemented
214 * according to the linux driver, if region length is -1
215 * the shared memory doesn't exist
216 */
217 return -1;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200218 case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
219 case VIRTIO_MMIO_DRIVER_FEATURES:
220 case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
221 case VIRTIO_MMIO_GUEST_PAGE_SIZE:
222 case VIRTIO_MMIO_QUEUE_SEL:
223 case VIRTIO_MMIO_QUEUE_NUM:
224 case VIRTIO_MMIO_QUEUE_ALIGN:
225 case VIRTIO_MMIO_QUEUE_NOTIFY:
226 case VIRTIO_MMIO_INTERRUPT_ACK:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200227 case VIRTIO_MMIO_QUEUE_DESC_LOW:
228 case VIRTIO_MMIO_QUEUE_DESC_HIGH:
229 case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
230 case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
231 case VIRTIO_MMIO_QUEUE_USED_LOW:
232 case VIRTIO_MMIO_QUEUE_USED_HIGH:
Boxuan Lida1804d2019-05-03 23:44:24 +0800233 qemu_log_mask(LOG_GUEST_ERROR,
Sergio Lopez44e687a2019-09-13 14:06:01 +0200234 "%s: read of write-only register (0x%" HWADDR_PRIx ")\n",
235 __func__, offset);
Peter Maydell4b525302013-07-16 13:25:09 +0100236 return 0;
237 default:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200238 qemu_log_mask(LOG_GUEST_ERROR,
239 "%s: bad register offset (0x%" HWADDR_PRIx ")\n",
240 __func__, offset);
Peter Maydell4b525302013-07-16 13:25:09 +0100241 return 0;
242 }
243 return 0;
244}
245
246static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
247 unsigned size)
248{
249 VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
Paolo Bonzini06d3dff2013-09-20 13:31:39 +0200250 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
Peter Maydell4b525302013-07-16 13:25:09 +0100251
Boxuan Lida1804d2019-05-03 23:44:24 +0800252 trace_virtio_mmio_write_offset(offset, value);
Peter Maydell4b525302013-07-16 13:25:09 +0100253
254 if (!vdev) {
255 /* If no backend is present, we just make all registers
256 * write-ignored. This allows us to provide transports with
257 * no backend plugged in.
258 */
259 return;
260 }
261
262 if (offset >= VIRTIO_MMIO_CONFIG) {
263 offset -= VIRTIO_MMIO_CONFIG;
Laurent Vivier0ab8c022021-03-14 21:03:00 +0100264 if (proxy->legacy) {
265 switch (size) {
266 case 1:
267 virtio_config_writeb(vdev, offset, value);
268 break;
269 case 2:
270 virtio_config_writew(vdev, offset, value);
271 break;
272 case 4:
273 virtio_config_writel(vdev, offset, value);
274 break;
275 default:
276 abort();
277 }
278 return;
279 } else {
280 switch (size) {
281 case 1:
282 virtio_config_modern_writeb(vdev, offset, value);
283 break;
284 case 2:
285 virtio_config_modern_writew(vdev, offset, value);
286 break;
287 case 4:
288 virtio_config_modern_writel(vdev, offset, value);
289 break;
290 default:
291 abort();
292 }
293 return;
Peter Maydell4b525302013-07-16 13:25:09 +0100294 }
Peter Maydell4b525302013-07-16 13:25:09 +0100295 }
296 if (size != 4) {
Boxuan Lida1804d2019-05-03 23:44:24 +0800297 qemu_log_mask(LOG_GUEST_ERROR,
298 "%s: wrong size access to register!\n",
299 __func__);
Peter Maydell4b525302013-07-16 13:25:09 +0100300 return;
301 }
302 switch (offset) {
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200303 case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200304 if (value) {
305 proxy->host_features_sel = 1;
306 } else {
307 proxy->host_features_sel = 0;
308 }
Peter Maydell4b525302013-07-16 13:25:09 +0100309 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200310 case VIRTIO_MMIO_DRIVER_FEATURES:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200311 if (proxy->legacy) {
312 if (proxy->guest_features_sel) {
313 qemu_log_mask(LOG_GUEST_ERROR,
314 "%s: attempt to write guest features with "
315 "guest_features_sel > 0 in legacy mode\n",
316 __func__);
317 } else {
318 virtio_set_features(vdev, value);
319 }
320 } else {
321 proxy->guest_features[proxy->guest_features_sel] = value;
Peter Maydell4b525302013-07-16 13:25:09 +0100322 }
323 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200324 case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200325 if (value) {
326 proxy->guest_features_sel = 1;
327 } else {
328 proxy->guest_features_sel = 0;
329 }
Peter Maydell4b525302013-07-16 13:25:09 +0100330 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200331 case VIRTIO_MMIO_GUEST_PAGE_SIZE:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200332 if (!proxy->legacy) {
333 qemu_log_mask(LOG_GUEST_ERROR,
334 "%s: write to legacy register (0x%"
335 HWADDR_PRIx ") in non-legacy mode\n",
336 __func__, offset);
337 return;
338 }
Peter Maydell4b525302013-07-16 13:25:09 +0100339 proxy->guest_page_shift = ctz32(value);
340 if (proxy->guest_page_shift > 31) {
341 proxy->guest_page_shift = 0;
342 }
Boxuan Lida1804d2019-05-03 23:44:24 +0800343 trace_virtio_mmio_guest_page(value, proxy->guest_page_shift);
Peter Maydell4b525302013-07-16 13:25:09 +0100344 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200345 case VIRTIO_MMIO_QUEUE_SEL:
Jason Wang87b3bd12015-05-29 14:15:31 +0800346 if (value < VIRTIO_QUEUE_MAX) {
Peter Maydell4b525302013-07-16 13:25:09 +0100347 vdev->queue_sel = value;
348 }
349 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200350 case VIRTIO_MMIO_QUEUE_NUM:
Boxuan Lida1804d2019-05-03 23:44:24 +0800351 trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
Denis Plotnikov1049f4c2019-12-24 11:14:46 +0300352 virtio_queue_set_num(vdev, vdev->queue_sel, value);
353
Sergio Lopez44e687a2019-09-13 14:06:01 +0200354 if (proxy->legacy) {
Sergio Lopez44e687a2019-09-13 14:06:01 +0200355 virtio_queue_update_rings(vdev, vdev->queue_sel);
356 } else {
Carlos Lópezf0d634e2023-03-17 01:27:51 +0100357 virtio_init_region_cache(vdev, vdev->queue_sel);
Sergio Lopez44e687a2019-09-13 14:06:01 +0200358 proxy->vqs[vdev->queue_sel].num = value;
359 }
Peter Maydell4b525302013-07-16 13:25:09 +0100360 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200361 case VIRTIO_MMIO_QUEUE_ALIGN:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200362 if (!proxy->legacy) {
363 qemu_log_mask(LOG_GUEST_ERROR,
364 "%s: write to legacy register (0x%"
365 HWADDR_PRIx ") in non-legacy mode\n",
366 __func__, offset);
367 return;
368 }
Peter Maydell4b525302013-07-16 13:25:09 +0100369 virtio_queue_set_align(vdev, vdev->queue_sel, value);
370 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200371 case VIRTIO_MMIO_QUEUE_PFN:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200372 if (!proxy->legacy) {
373 qemu_log_mask(LOG_GUEST_ERROR,
374 "%s: write to legacy register (0x%"
375 HWADDR_PRIx ") in non-legacy mode\n",
376 __func__, offset);
377 return;
378 }
Peter Maydell4b525302013-07-16 13:25:09 +0100379 if (value == 0) {
Paolo Bonzini26cfd672022-06-09 08:54:54 +0200380 virtio_mmio_soft_reset(proxy);
Peter Maydell4b525302013-07-16 13:25:09 +0100381 } else {
382 virtio_queue_set_addr(vdev, vdev->queue_sel,
383 value << proxy->guest_page_shift);
384 }
385 break;
Sergio Lopez44e687a2019-09-13 14:06:01 +0200386 case VIRTIO_MMIO_QUEUE_READY:
387 if (proxy->legacy) {
388 qemu_log_mask(LOG_GUEST_ERROR,
389 "%s: write to non-legacy register (0x%"
390 HWADDR_PRIx ") in legacy mode\n",
391 __func__, offset);
392 return;
393 }
394 if (value) {
395 virtio_queue_set_num(vdev, vdev->queue_sel,
396 proxy->vqs[vdev->queue_sel].num);
397 virtio_queue_set_rings(vdev, vdev->queue_sel,
398 ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
399 proxy->vqs[vdev->queue_sel].desc[0],
400 ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
401 proxy->vqs[vdev->queue_sel].avail[0],
402 ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
403 proxy->vqs[vdev->queue_sel].used[0]);
404 proxy->vqs[vdev->queue_sel].enabled = 1;
405 } else {
406 proxy->vqs[vdev->queue_sel].enabled = 0;
407 }
408 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200409 case VIRTIO_MMIO_QUEUE_NOTIFY:
Jason Wang87b3bd12015-05-29 14:15:31 +0800410 if (value < VIRTIO_QUEUE_MAX) {
Peter Maydell4b525302013-07-16 13:25:09 +0100411 virtio_queue_notify(vdev, value);
412 }
413 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200414 case VIRTIO_MMIO_INTERRUPT_ACK:
Stefan Hajnoczid73415a2020-09-23 11:56:46 +0100415 qatomic_and(&vdev->isr, ~value);
Peter Maydell4b525302013-07-16 13:25:09 +0100416 virtio_update_irq(vdev);
417 break;
418 case VIRTIO_MMIO_STATUS:
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300419 if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
420 virtio_mmio_stop_ioeventfd(proxy);
421 }
422
Sergio Lopez44e687a2019-09-13 14:06:01 +0200423 if (!proxy->legacy && (value & VIRTIO_CONFIG_S_FEATURES_OK)) {
424 virtio_set_features(vdev,
425 ((uint64_t)proxy->guest_features[1]) << 32 |
426 proxy->guest_features[0]);
427 }
428
Peter Maydell4b525302013-07-16 13:25:09 +0100429 virtio_set_status(vdev, value & 0xff);
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300430
431 if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
432 virtio_mmio_start_ioeventfd(proxy);
433 }
434
Peter Maydell4b525302013-07-16 13:25:09 +0100435 if (vdev->status == 0) {
Jean-Philippe Brucker351da832019-12-13 10:54:10 +0100436 virtio_mmio_soft_reset(proxy);
Peter Maydell4b525302013-07-16 13:25:09 +0100437 }
438 break;
Sergio Lopez44e687a2019-09-13 14:06:01 +0200439 case VIRTIO_MMIO_QUEUE_DESC_LOW:
440 if (proxy->legacy) {
441 qemu_log_mask(LOG_GUEST_ERROR,
442 "%s: write to non-legacy register (0x%"
443 HWADDR_PRIx ") in legacy mode\n",
444 __func__, offset);
445 return;
446 }
447 proxy->vqs[vdev->queue_sel].desc[0] = value;
448 break;
449 case VIRTIO_MMIO_QUEUE_DESC_HIGH:
450 if (proxy->legacy) {
451 qemu_log_mask(LOG_GUEST_ERROR,
452 "%s: write to non-legacy register (0x%"
453 HWADDR_PRIx ") in legacy mode\n",
454 __func__, offset);
455 return;
456 }
457 proxy->vqs[vdev->queue_sel].desc[1] = value;
458 break;
459 case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
460 if (proxy->legacy) {
461 qemu_log_mask(LOG_GUEST_ERROR,
462 "%s: write to non-legacy register (0x%"
463 HWADDR_PRIx ") in legacy mode\n",
464 __func__, offset);
465 return;
466 }
467 proxy->vqs[vdev->queue_sel].avail[0] = value;
468 break;
469 case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
470 if (proxy->legacy) {
471 qemu_log_mask(LOG_GUEST_ERROR,
472 "%s: write to non-legacy register (0x%"
473 HWADDR_PRIx ") in legacy mode\n",
474 __func__, offset);
475 return;
476 }
477 proxy->vqs[vdev->queue_sel].avail[1] = value;
478 break;
479 case VIRTIO_MMIO_QUEUE_USED_LOW:
480 if (proxy->legacy) {
481 qemu_log_mask(LOG_GUEST_ERROR,
482 "%s: write to non-legacy register (0x%"
483 HWADDR_PRIx ") in legacy mode\n",
484 __func__, offset);
485 return;
486 }
487 proxy->vqs[vdev->queue_sel].used[0] = value;
488 break;
489 case VIRTIO_MMIO_QUEUE_USED_HIGH:
490 if (proxy->legacy) {
491 qemu_log_mask(LOG_GUEST_ERROR,
492 "%s: write to non-legacy register (0x%"
493 HWADDR_PRIx ") in legacy mode\n",
494 __func__, offset);
495 return;
496 }
497 proxy->vqs[vdev->queue_sel].used[1] = value;
498 break;
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200499 case VIRTIO_MMIO_MAGIC_VALUE:
Peter Maydell4b525302013-07-16 13:25:09 +0100500 case VIRTIO_MMIO_VERSION:
Michael S. Tsirkin7e71da72017-01-13 00:14:55 +0200501 case VIRTIO_MMIO_DEVICE_ID:
502 case VIRTIO_MMIO_VENDOR_ID:
503 case VIRTIO_MMIO_DEVICE_FEATURES:
504 case VIRTIO_MMIO_QUEUE_NUM_MAX:
505 case VIRTIO_MMIO_INTERRUPT_STATUS:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200506 case VIRTIO_MMIO_CONFIG_GENERATION:
Boxuan Lida1804d2019-05-03 23:44:24 +0800507 qemu_log_mask(LOG_GUEST_ERROR,
Sergio Lopez44e687a2019-09-13 14:06:01 +0200508 "%s: write to read-only register (0x%" HWADDR_PRIx ")\n",
509 __func__, offset);
Peter Maydell4b525302013-07-16 13:25:09 +0100510 break;
511
512 default:
Sergio Lopez44e687a2019-09-13 14:06:01 +0200513 qemu_log_mask(LOG_GUEST_ERROR,
514 "%s: bad register offset (0x%" HWADDR_PRIx ")\n",
515 __func__, offset);
Peter Maydell4b525302013-07-16 13:25:09 +0100516 }
517}
518
Sergio Lopez44e687a2019-09-13 14:06:01 +0200519static const MemoryRegionOps virtio_legacy_mem_ops = {
520 .read = virtio_mmio_read,
521 .write = virtio_mmio_write,
522 .endianness = DEVICE_NATIVE_ENDIAN,
523};
524
Peter Maydell4b525302013-07-16 13:25:09 +0100525static const MemoryRegionOps virtio_mem_ops = {
526 .read = virtio_mmio_read,
527 .write = virtio_mmio_write,
Sergio Lopez44e687a2019-09-13 14:06:01 +0200528 .endianness = DEVICE_LITTLE_ENDIAN,
Peter Maydell4b525302013-07-16 13:25:09 +0100529};
530
531static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
532{
533 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
Paolo Bonzini06d3dff2013-09-20 13:31:39 +0200534 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
Peter Maydell4b525302013-07-16 13:25:09 +0100535 int level;
536
Paolo Bonzini06d3dff2013-09-20 13:31:39 +0200537 if (!vdev) {
Peter Maydell4b525302013-07-16 13:25:09 +0100538 return;
539 }
Stefan Hajnoczid73415a2020-09-23 11:56:46 +0100540 level = (qatomic_read(&vdev->isr) != 0);
Boxuan Lida1804d2019-05-03 23:44:24 +0800541 trace_virtio_mmio_setting_irq(level);
Peter Maydell4b525302013-07-16 13:25:09 +0100542 qemu_set_irq(proxy->irq, level);
543}
544
Peter Maydell4b525302013-07-16 13:25:09 +0100545static int virtio_mmio_load_config(DeviceState *opaque, QEMUFile *f)
546{
547 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
548
549 proxy->host_features_sel = qemu_get_be32(f);
550 proxy->guest_features_sel = qemu_get_be32(f);
551 proxy->guest_page_shift = qemu_get_be32(f);
552 return 0;
553}
554
555static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
556{
557 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
558
559 qemu_put_be32(f, proxy->host_features_sel);
560 qemu_put_be32(f, proxy->guest_features_sel);
561 qemu_put_be32(f, proxy->guest_page_shift);
562}
563
Sergio Lopez44e687a2019-09-13 14:06:01 +0200564static const VMStateDescription vmstate_virtio_mmio_queue_state = {
565 .name = "virtio_mmio/queue_state",
566 .version_id = 1,
567 .minimum_version_id = 1,
568 .fields = (VMStateField[]) {
569 VMSTATE_UINT16(num, VirtIOMMIOQueue),
570 VMSTATE_BOOL(enabled, VirtIOMMIOQueue),
571 VMSTATE_UINT32_ARRAY(desc, VirtIOMMIOQueue, 2),
572 VMSTATE_UINT32_ARRAY(avail, VirtIOMMIOQueue, 2),
573 VMSTATE_UINT32_ARRAY(used, VirtIOMMIOQueue, 2),
574 VMSTATE_END_OF_LIST()
575 }
576};
577
578static const VMStateDescription vmstate_virtio_mmio_state_sub = {
579 .name = "virtio_mmio/state",
580 .version_id = 1,
581 .minimum_version_id = 1,
582 .fields = (VMStateField[]) {
583 VMSTATE_UINT32_ARRAY(guest_features, VirtIOMMIOProxy, 2),
584 VMSTATE_STRUCT_ARRAY(vqs, VirtIOMMIOProxy, VIRTIO_QUEUE_MAX, 0,
585 vmstate_virtio_mmio_queue_state,
586 VirtIOMMIOQueue),
587 VMSTATE_END_OF_LIST()
588 }
589};
590
591static const VMStateDescription vmstate_virtio_mmio = {
592 .name = "virtio_mmio",
593 .version_id = 1,
594 .minimum_version_id = 1,
Sergio Lopez44e687a2019-09-13 14:06:01 +0200595 .fields = (VMStateField[]) {
596 VMSTATE_END_OF_LIST()
597 },
598 .subsections = (const VMStateDescription * []) {
599 &vmstate_virtio_mmio_state_sub,
600 NULL
601 }
602};
603
604static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
605{
606 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
607
608 vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL);
609}
610
611static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
612{
613 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
614
615 return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
616}
617
618static bool virtio_mmio_has_extra_state(DeviceState *opaque)
619{
620 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
621
622 return !proxy->legacy;
623}
624
Peter Maydell4b525302013-07-16 13:25:09 +0100625static void virtio_mmio_reset(DeviceState *d)
626{
627 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
Sergio Lopez44e687a2019-09-13 14:06:01 +0200628 int i;
Peter Maydell4b525302013-07-16 13:25:09 +0100629
Paolo Bonzini26cfd672022-06-09 08:54:54 +0200630 virtio_mmio_soft_reset(proxy);
631
Peter Maydell4b525302013-07-16 13:25:09 +0100632 proxy->host_features_sel = 0;
633 proxy->guest_features_sel = 0;
634 proxy->guest_page_shift = 0;
Sergio Lopez44e687a2019-09-13 14:06:01 +0200635
636 if (!proxy->legacy) {
637 proxy->guest_features[0] = proxy->guest_features[1] = 0;
638
639 for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
Sergio Lopez44e687a2019-09-13 14:06:01 +0200640 proxy->vqs[i].num = 0;
641 proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
642 proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
643 proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
644 }
645 }
Peter Maydell4b525302013-07-16 13:25:09 +0100646}
647
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300648static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
649 bool with_irqfd)
650{
651 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
652 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
653 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
654 VirtQueue *vq = virtio_get_queue(vdev, n);
655 EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
656
657 if (assign) {
658 int r = event_notifier_init(notifier, 0);
659 if (r < 0) {
660 return r;
661 }
662 virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
663 } else {
664 virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
665 event_notifier_cleanup(notifier);
666 }
667
Wei Huang2858bc62016-12-15 12:23:24 -0600668 if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) {
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300669 vdc->guest_notifier_mask(vdev, n, !assign);
670 }
671
672 return 0;
673}
Cindy Lucd336e82022-12-22 15:04:50 +0800674static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign,
675 bool with_irqfd)
676{
677 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
678 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
679 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
680 EventNotifier *notifier = virtio_config_get_guest_notifier(vdev);
681 int r = 0;
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300682
Cindy Lucd336e82022-12-22 15:04:50 +0800683 if (assign) {
684 r = event_notifier_init(notifier, 0);
685 if (r < 0) {
686 return r;
687 }
688 virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd);
689 } else {
690 virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd);
691 event_notifier_cleanup(notifier);
692 }
693 if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) {
694 vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign);
695 }
696 return r;
697}
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300698static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs,
699 bool assign)
700{
701 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
702 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
703 /* TODO: need to check if kvm-arm supports irqfd */
704 bool with_irqfd = false;
705 int r, n;
706
707 nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
708
709 for (n = 0; n < nvqs; n++) {
710 if (!virtio_queue_get_num(vdev, n)) {
711 break;
712 }
713
714 r = virtio_mmio_set_guest_notifier(d, n, assign, with_irqfd);
715 if (r < 0) {
716 goto assign_error;
717 }
718 }
Cindy Lucd336e82022-12-22 15:04:50 +0800719 r = virtio_mmio_set_config_guest_notifier(d, assign, with_irqfd);
720 if (r < 0) {
721 goto assign_error;
722 }
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300723
724 return 0;
725
726assign_error:
727 /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
728 assert(assign);
729 while (--n >= 0) {
730 virtio_mmio_set_guest_notifier(d, n, !assign, false);
731 }
732 return r;
733}
734
Sergio Lopez44e687a2019-09-13 14:06:01 +0200735static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
736{
737 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
738 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
739
740 if (!proxy->legacy) {
741 virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
742 }
743}
744
Peter Maydell4b525302013-07-16 13:25:09 +0100745/* virtio-mmio device */
746
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100747static Property virtio_mmio_properties[] = {
748 DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
749 format_transport_address, true),
Sergio Lopez44e687a2019-09-13 14:06:01 +0200750 DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true),
Pavel Dovgalyukb8893a32021-03-29 10:43:12 +0300751 DEFINE_PROP_BIT("ioeventfd", VirtIOMMIOProxy, flags,
752 VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT, true),
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100753 DEFINE_PROP_END_OF_LIST(),
754};
755
Peter Maydell4b525302013-07-16 13:25:09 +0100756static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
757{
758 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
759 SysBusDevice *sbd = SYS_BUS_DEVICE(d);
760
Peter Maydelld637e1d2021-09-23 13:11:51 +0100761 qbus_init(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS, d, NULL);
Peter Maydell4b525302013-07-16 13:25:09 +0100762 sysbus_init_irq(sbd, &proxy->irq);
Pavel Dovgalyukb8893a32021-03-29 10:43:12 +0300763
764 if (!kvm_eventfds_enabled()) {
765 proxy->flags &= ~VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD;
766 }
767
Pavel Dovgalyuk3909c072021-05-17 16:06:28 +0300768 /* fd-based ioevents can't be synchronized in record/replay */
769 if (replay_mode != REPLAY_MODE_NONE) {
770 proxy->flags &= ~VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD;
771 }
772
Sergio Lopez44e687a2019-09-13 14:06:01 +0200773 if (proxy->legacy) {
774 memory_region_init_io(&proxy->iomem, OBJECT(d),
775 &virtio_legacy_mem_ops, proxy,
776 TYPE_VIRTIO_MMIO, 0x200);
777 } else {
778 memory_region_init_io(&proxy->iomem, OBJECT(d),
779 &virtio_mem_ops, proxy,
780 TYPE_VIRTIO_MMIO, 0x200);
781 }
Peter Maydell4b525302013-07-16 13:25:09 +0100782 sysbus_init_mmio(sbd, &proxy->iomem);
783}
784
785static void virtio_mmio_class_init(ObjectClass *klass, void *data)
786{
787 DeviceClass *dc = DEVICE_CLASS(klass);
788
789 dc->realize = virtio_mmio_realizefn;
790 dc->reset = virtio_mmio_reset;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +0300791 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
Marc-André Lureau4f67d302020-01-10 19:30:32 +0400792 device_class_set_props(dc, virtio_mmio_properties);
Peter Maydell4b525302013-07-16 13:25:09 +0100793}
794
795static const TypeInfo virtio_mmio_info = {
796 .name = TYPE_VIRTIO_MMIO,
797 .parent = TYPE_SYS_BUS_DEVICE,
798 .instance_size = sizeof(VirtIOMMIOProxy),
799 .class_init = virtio_mmio_class_init,
800};
801
802/* virtio-mmio-bus. */
803
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100804static char *virtio_mmio_bus_get_dev_path(DeviceState *dev)
805{
806 BusState *virtio_mmio_bus;
807 VirtIOMMIOProxy *virtio_mmio_proxy;
808 char *proxy_path;
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100809 char *path;
schspa819b3492021-02-25 13:36:06 +0800810 MemoryRegionSection section;
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100811
812 virtio_mmio_bus = qdev_get_parent_bus(dev);
813 virtio_mmio_proxy = VIRTIO_MMIO(virtio_mmio_bus->parent);
814 proxy_path = qdev_get_dev_path(DEVICE(virtio_mmio_proxy));
815
816 /*
817 * If @format_transport_address is false, then we just perform the same as
818 * virtio_bus_get_dev_path(): we delegate the address formatting for the
819 * device on the virtio-mmio bus to the bus that the virtio-mmio proxy
820 * (i.e., the device that implements the virtio-mmio bus) resides on. In
821 * this case the base address of the virtio-mmio transport will be
822 * invisible.
823 */
824 if (!virtio_mmio_proxy->format_transport_address) {
825 return proxy_path;
826 }
827
828 /* Otherwise, we append the base address of the transport. */
schspa819b3492021-02-25 13:36:06 +0800829 section = memory_region_find(&virtio_mmio_proxy->iomem, 0, 0x200);
830 assert(section.mr);
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100831
832 if (proxy_path) {
Philippe Mathieu-Daudé883f2c52023-01-10 22:29:47 +0100833 path = g_strdup_printf("%s/virtio-mmio@" HWADDR_FMT_plx, proxy_path,
schspa819b3492021-02-25 13:36:06 +0800834 section.offset_within_address_space);
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100835 } else {
Philippe Mathieu-Daudé883f2c52023-01-10 22:29:47 +0100836 path = g_strdup_printf("virtio-mmio@" HWADDR_FMT_plx,
schspa819b3492021-02-25 13:36:06 +0800837 section.offset_within_address_space);
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100838 }
schspa819b3492021-02-25 13:36:06 +0800839 memory_region_unref(section.mr);
840
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100841 g_free(proxy_path);
842 return path;
843}
844
Cindy Lu7abba7c2021-11-09 10:37:44 +0800845static void virtio_mmio_vmstate_change(DeviceState *d, bool running)
846{
847 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
848
849 if (running) {
850 virtio_mmio_start_ioeventfd(proxy);
851 } else {
852 virtio_mmio_stop_ioeventfd(proxy);
853 }
854}
855
Peter Maydell4b525302013-07-16 13:25:09 +0100856static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
857{
858 BusClass *bus_class = BUS_CLASS(klass);
859 VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
860
861 k->notify = virtio_mmio_update_irq;
862 k->save_config = virtio_mmio_save_config;
863 k->load_config = virtio_mmio_load_config;
Sergio Lopez44e687a2019-09-13 14:06:01 +0200864 k->save_extra_state = virtio_mmio_save_extra_state;
865 k->load_extra_state = virtio_mmio_load_extra_state;
866 k->has_extra_state = virtio_mmio_has_extra_state;
Ying-Shiuan Pan434027b2015-05-12 11:10:50 +0300867 k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
Paolo Bonzini8e93cef2016-10-21 22:48:08 +0200868 k->ioeventfd_enabled = virtio_mmio_ioeventfd_enabled;
Cornelia Huckc0971bc2016-06-10 11:04:13 +0200869 k->ioeventfd_assign = virtio_mmio_ioeventfd_assign;
Sergio Lopez44e687a2019-09-13 14:06:01 +0200870 k->pre_plugged = virtio_mmio_pre_plugged;
Cindy Lu7abba7c2021-11-09 10:37:44 +0800871 k->vmstate_change = virtio_mmio_vmstate_change;
Peter Maydell4b525302013-07-16 13:25:09 +0100872 k->has_variable_vring_alignment = true;
873 bus_class->max_dev = 1;
Laszlo Ersekf58b39d2016-07-14 16:51:36 +0100874 bus_class->get_dev_path = virtio_mmio_bus_get_dev_path;
Peter Maydell4b525302013-07-16 13:25:09 +0100875}
876
877static const TypeInfo virtio_mmio_bus_info = {
878 .name = TYPE_VIRTIO_MMIO_BUS,
879 .parent = TYPE_VIRTIO_BUS,
880 .instance_size = sizeof(VirtioBusState),
881 .class_init = virtio_mmio_bus_class_init,
882};
883
884static void virtio_mmio_register_types(void)
885{
886 type_register_static(&virtio_mmio_bus_info);
887 type_register_static(&virtio_mmio_info);
888}
889
890type_init(virtio_mmio_register_types)