]> Git Repo - qemu.git/blame - hw/virtio/virtio-mmio.c
memory-device: simplify Makefile.objs conditions
[qemu.git] / hw / virtio / virtio-mmio.c
CommitLineData
4b52530b
PM
1/*
2 * Virtio MMIO bindings
3 *
4 * Copyright (c) 2011 Linaro Limited
5 *
6 * Author:
7 * Peter Maydell <[email protected]>
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
9b8bfe21 22#include "qemu/osdep.h"
7e71da7f 23#include "standard-headers/linux/virtio_mmio.h"
64552b6b 24#include "hw/irq.h"
a27bd6c7 25#include "hw/qdev-properties.h"
4b52530b
PM
26#include "hw/sysbus.h"
27#include "hw/virtio/virtio.h"
ca77ee28 28#include "migration/qemu-file-types.h"
4b52530b 29#include "qemu/host-utils.h"
0b8fa32f 30#include "qemu/module.h"
434027ba 31#include "sysemu/kvm.h"
4b52530b 32#include "hw/virtio/virtio-bus.h"
434027ba 33#include "qemu/error-report.h"
da1804d1
BL
34#include "qemu/log.h"
35#include "trace.h"
4b52530b
PM
36
37/* QOM macros */
38/* virtio-mmio-bus */
39#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus"
40#define VIRTIO_MMIO_BUS(obj) \
41 OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS)
42#define VIRTIO_MMIO_BUS_GET_CLASS(obj) \
43 OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS)
44#define VIRTIO_MMIO_BUS_CLASS(klass) \
45 OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS)
46
47/* virtio-mmio */
48#define TYPE_VIRTIO_MMIO "virtio-mmio"
49#define VIRTIO_MMIO(obj) \
50 OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
51
4b52530b 52#define VIRT_MAGIC 0x74726976 /* 'virt' */
44e687a4
SL
53#define VIRT_VERSION 2
54#define VIRT_VERSION_LEGACY 1
4b52530b
PM
55#define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
56
44e687a4
SL
57typedef struct VirtIOMMIOQueue {
58 uint16_t num;
59 bool enabled;
60 uint32_t desc[2];
61 uint32_t avail[2];
62 uint32_t used[2];
63} VirtIOMMIOQueue;
64
4b52530b
PM
65typedef struct {
66 /* Generic */
67 SysBusDevice parent_obj;
68 MemoryRegion iomem;
69 qemu_irq irq;
44e687a4 70 bool legacy;
4b52530b
PM
71 /* Guest accessible state needing migration and reset */
72 uint32_t host_features_sel;
73 uint32_t guest_features_sel;
74 uint32_t guest_page_shift;
75 /* virtio-bus */
76 VirtioBusState bus;
f58b39d2 77 bool format_transport_address;
44e687a4
SL
78 /* Fields only used for non-legacy (v2) devices */
79 uint32_t guest_features[2];
80 VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
4b52530b
PM
81} VirtIOMMIOProxy;
82
8e93cef1 83static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
c0971bcb 84{
8e93cef1 85 return kvm_eventfds_enabled();
434027ba
YSP
86}
87
c0971bcb
CH
88static int virtio_mmio_ioeventfd_assign(DeviceState *d,
89 EventNotifier *notifier,
90 int n, bool assign)
434027ba 91{
c0971bcb 92 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
434027ba 93
c0971bcb 94 if (assign) {
7e71da7f 95 memory_region_add_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUE_NOTIFY, 4,
c0971bcb
CH
96 true, n, notifier);
97 } else {
7e71da7f 98 memory_region_del_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUE_NOTIFY, 4,
c0971bcb 99 true, n, notifier);
434027ba 100 }
c0971bcb
CH
101 return 0;
102}
434027ba 103
c0971bcb
CH
104static void virtio_mmio_start_ioeventfd(VirtIOMMIOProxy *proxy)
105{
106 virtio_bus_start_ioeventfd(&proxy->bus);
107}
434027ba 108
c0971bcb
CH
109static void virtio_mmio_stop_ioeventfd(VirtIOMMIOProxy *proxy)
110{
111 virtio_bus_stop_ioeventfd(&proxy->bus);
434027ba
YSP
112}
113
4b52530b
PM
114static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
115{
116 VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
06d3dff0 117 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
4b52530b 118
da1804d1 119 trace_virtio_mmio_read(offset);
4b52530b
PM
120
121 if (!vdev) {
122 /* If no backend is present, we treat most registers as
123 * read-as-zero, except for the magic number, version and
124 * vendor ID. This is not strictly sanctioned by the virtio
125 * spec, but it allows us to provide transports with no backend
126 * plugged in which don't confuse Linux's virtio code: the
127 * probe won't complain about the bad magic number, but the
128 * device ID of zero means no backend will claim it.
129 */
130 switch (offset) {
7e71da7f 131 case VIRTIO_MMIO_MAGIC_VALUE:
4b52530b
PM
132 return VIRT_MAGIC;
133 case VIRTIO_MMIO_VERSION:
44e687a4
SL
134 if (proxy->legacy) {
135 return VIRT_VERSION_LEGACY;
136 } else {
137 return VIRT_VERSION;
138 }
7e71da7f 139 case VIRTIO_MMIO_VENDOR_ID:
4b52530b
PM
140 return VIRT_VENDOR;
141 default:
142 return 0;
143 }
144 }
145
146 if (offset >= VIRTIO_MMIO_CONFIG) {
147 offset -= VIRTIO_MMIO_CONFIG;
148 switch (size) {
149 case 1:
150 return virtio_config_readb(vdev, offset);
151 case 2:
152 return virtio_config_readw(vdev, offset);
153 case 4:
154 return virtio_config_readl(vdev, offset);
155 default:
156 abort();
157 }
158 }
159 if (size != 4) {
da1804d1
BL
160 qemu_log_mask(LOG_GUEST_ERROR,
161 "%s: wrong size access to register!\n",
162 __func__);
4b52530b
PM
163 return 0;
164 }
165 switch (offset) {
7e71da7f 166 case VIRTIO_MMIO_MAGIC_VALUE:
4b52530b
PM
167 return VIRT_MAGIC;
168 case VIRTIO_MMIO_VERSION:
44e687a4
SL
169 if (proxy->legacy) {
170 return VIRT_VERSION_LEGACY;
171 } else {
172 return VIRT_VERSION;
173 }
7e71da7f 174 case VIRTIO_MMIO_DEVICE_ID:
4b52530b 175 return vdev->device_id;
7e71da7f 176 case VIRTIO_MMIO_VENDOR_ID:
4b52530b 177 return VIRT_VENDOR;
7e71da7f 178 case VIRTIO_MMIO_DEVICE_FEATURES:
44e687a4
SL
179 if (proxy->legacy) {
180 if (proxy->host_features_sel) {
181 return 0;
182 } else {
183 return vdev->host_features;
184 }
185 } else {
186 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
187 return (vdev->host_features & ~vdc->legacy_features)
188 >> (32 * proxy->host_features_sel);
4b52530b 189 }
7e71da7f 190 case VIRTIO_MMIO_QUEUE_NUM_MAX:
f7b803b3
PM
191 if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
192 return 0;
193 }
4b52530b 194 return VIRTQUEUE_MAX_SIZE;
7e71da7f 195 case VIRTIO_MMIO_QUEUE_PFN:
44e687a4
SL
196 if (!proxy->legacy) {
197 qemu_log_mask(LOG_GUEST_ERROR,
198 "%s: read from legacy register (0x%"
199 HWADDR_PRIx ") in non-legacy mode\n",
200 __func__, offset);
201 return 0;
202 }
4b52530b
PM
203 return virtio_queue_get_addr(vdev, vdev->queue_sel)
204 >> proxy->guest_page_shift;
44e687a4
SL
205 case VIRTIO_MMIO_QUEUE_READY:
206 if (proxy->legacy) {
207 qemu_log_mask(LOG_GUEST_ERROR,
208 "%s: read from non-legacy register (0x%"
209 HWADDR_PRIx ") in legacy mode\n",
210 __func__, offset);
211 return 0;
212 }
213 return proxy->vqs[vdev->queue_sel].enabled;
7e71da7f 214 case VIRTIO_MMIO_INTERRUPT_STATUS:
0687c37c 215 return atomic_read(&vdev->isr);
4b52530b
PM
216 case VIRTIO_MMIO_STATUS:
217 return vdev->status;
44e687a4
SL
218 case VIRTIO_MMIO_CONFIG_GENERATION:
219 if (proxy->legacy) {
220 qemu_log_mask(LOG_GUEST_ERROR,
221 "%s: read from non-legacy register (0x%"
222 HWADDR_PRIx ") in legacy mode\n",
223 __func__, offset);
224 return 0;
225 }
226 return vdev->generation;
7e71da7f
MT
227 case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
228 case VIRTIO_MMIO_DRIVER_FEATURES:
229 case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
230 case VIRTIO_MMIO_GUEST_PAGE_SIZE:
231 case VIRTIO_MMIO_QUEUE_SEL:
232 case VIRTIO_MMIO_QUEUE_NUM:
233 case VIRTIO_MMIO_QUEUE_ALIGN:
234 case VIRTIO_MMIO_QUEUE_NOTIFY:
235 case VIRTIO_MMIO_INTERRUPT_ACK:
44e687a4
SL
236 case VIRTIO_MMIO_QUEUE_DESC_LOW:
237 case VIRTIO_MMIO_QUEUE_DESC_HIGH:
238 case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
239 case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
240 case VIRTIO_MMIO_QUEUE_USED_LOW:
241 case VIRTIO_MMIO_QUEUE_USED_HIGH:
da1804d1 242 qemu_log_mask(LOG_GUEST_ERROR,
44e687a4
SL
243 "%s: read of write-only register (0x%" HWADDR_PRIx ")\n",
244 __func__, offset);
4b52530b
PM
245 return 0;
246 default:
44e687a4
SL
247 qemu_log_mask(LOG_GUEST_ERROR,
248 "%s: bad register offset (0x%" HWADDR_PRIx ")\n",
249 __func__, offset);
4b52530b
PM
250 return 0;
251 }
252 return 0;
253}
254
255static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
256 unsigned size)
257{
258 VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
06d3dff0 259 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
4b52530b 260
da1804d1 261 trace_virtio_mmio_write_offset(offset, value);
4b52530b
PM
262
263 if (!vdev) {
264 /* If no backend is present, we just make all registers
265 * write-ignored. This allows us to provide transports with
266 * no backend plugged in.
267 */
268 return;
269 }
270
271 if (offset >= VIRTIO_MMIO_CONFIG) {
272 offset -= VIRTIO_MMIO_CONFIG;
273 switch (size) {
274 case 1:
275 virtio_config_writeb(vdev, offset, value);
276 break;
277 case 2:
278 virtio_config_writew(vdev, offset, value);
279 break;
280 case 4:
281 virtio_config_writel(vdev, offset, value);
282 break;
283 default:
284 abort();
285 }
286 return;
287 }
288 if (size != 4) {
da1804d1
BL
289 qemu_log_mask(LOG_GUEST_ERROR,
290 "%s: wrong size access to register!\n",
291 __func__);
4b52530b
PM
292 return;
293 }
294 switch (offset) {
7e71da7f 295 case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
44e687a4
SL
296 if (value) {
297 proxy->host_features_sel = 1;
298 } else {
299 proxy->host_features_sel = 0;
300 }
4b52530b 301 break;
7e71da7f 302 case VIRTIO_MMIO_DRIVER_FEATURES:
44e687a4
SL
303 if (proxy->legacy) {
304 if (proxy->guest_features_sel) {
305 qemu_log_mask(LOG_GUEST_ERROR,
306 "%s: attempt to write guest features with "
307 "guest_features_sel > 0 in legacy mode\n",
308 __func__);
309 } else {
310 virtio_set_features(vdev, value);
311 }
312 } else {
313 proxy->guest_features[proxy->guest_features_sel] = value;
4b52530b
PM
314 }
315 break;
7e71da7f 316 case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
44e687a4
SL
317 if (value) {
318 proxy->guest_features_sel = 1;
319 } else {
320 proxy->guest_features_sel = 0;
321 }
4b52530b 322 break;
7e71da7f 323 case VIRTIO_MMIO_GUEST_PAGE_SIZE:
44e687a4
SL
324 if (!proxy->legacy) {
325 qemu_log_mask(LOG_GUEST_ERROR,
326 "%s: write to legacy register (0x%"
327 HWADDR_PRIx ") in non-legacy mode\n",
328 __func__, offset);
329 return;
330 }
4b52530b
PM
331 proxy->guest_page_shift = ctz32(value);
332 if (proxy->guest_page_shift > 31) {
333 proxy->guest_page_shift = 0;
334 }
da1804d1 335 trace_virtio_mmio_guest_page(value, proxy->guest_page_shift);
4b52530b 336 break;
7e71da7f 337 case VIRTIO_MMIO_QUEUE_SEL:
87b3bd1c 338 if (value < VIRTIO_QUEUE_MAX) {
4b52530b
PM
339 vdev->queue_sel = value;
340 }
341 break;
7e71da7f 342 case VIRTIO_MMIO_QUEUE_NUM:
da1804d1 343 trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
44e687a4
SL
344 if (proxy->legacy) {
345 virtio_queue_set_num(vdev, vdev->queue_sel, value);
346 virtio_queue_update_rings(vdev, vdev->queue_sel);
347 } else {
348 proxy->vqs[vdev->queue_sel].num = value;
349 }
4b52530b 350 break;
7e71da7f 351 case VIRTIO_MMIO_QUEUE_ALIGN:
44e687a4
SL
352 if (!proxy->legacy) {
353 qemu_log_mask(LOG_GUEST_ERROR,
354 "%s: write to legacy register (0x%"
355 HWADDR_PRIx ") in non-legacy mode\n",
356 __func__, offset);
357 return;
358 }
4b52530b
PM
359 virtio_queue_set_align(vdev, vdev->queue_sel, value);
360 break;
7e71da7f 361 case VIRTIO_MMIO_QUEUE_PFN:
44e687a4
SL
362 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 }
4b52530b
PM
369 if (value == 0) {
370 virtio_reset(vdev);
371 } else {
372 virtio_queue_set_addr(vdev, vdev->queue_sel,
373 value << proxy->guest_page_shift);
374 }
375 break;
44e687a4
SL
376 case VIRTIO_MMIO_QUEUE_READY:
377 if (proxy->legacy) {
378 qemu_log_mask(LOG_GUEST_ERROR,
379 "%s: write to non-legacy register (0x%"
380 HWADDR_PRIx ") in legacy mode\n",
381 __func__, offset);
382 return;
383 }
384 if (value) {
385 virtio_queue_set_num(vdev, vdev->queue_sel,
386 proxy->vqs[vdev->queue_sel].num);
387 virtio_queue_set_rings(vdev, vdev->queue_sel,
388 ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
389 proxy->vqs[vdev->queue_sel].desc[0],
390 ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
391 proxy->vqs[vdev->queue_sel].avail[0],
392 ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
393 proxy->vqs[vdev->queue_sel].used[0]);
394 proxy->vqs[vdev->queue_sel].enabled = 1;
395 } else {
396 proxy->vqs[vdev->queue_sel].enabled = 0;
397 }
398 break;
7e71da7f 399 case VIRTIO_MMIO_QUEUE_NOTIFY:
87b3bd1c 400 if (value < VIRTIO_QUEUE_MAX) {
4b52530b
PM
401 virtio_queue_notify(vdev, value);
402 }
403 break;
7e71da7f 404 case VIRTIO_MMIO_INTERRUPT_ACK:
0687c37c 405 atomic_and(&vdev->isr, ~value);
4b52530b
PM
406 virtio_update_irq(vdev);
407 break;
408 case VIRTIO_MMIO_STATUS:
434027ba
YSP
409 if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
410 virtio_mmio_stop_ioeventfd(proxy);
411 }
412
44e687a4
SL
413 if (!proxy->legacy && (value & VIRTIO_CONFIG_S_FEATURES_OK)) {
414 virtio_set_features(vdev,
415 ((uint64_t)proxy->guest_features[1]) << 32 |
416 proxy->guest_features[0]);
417 }
418
4b52530b 419 virtio_set_status(vdev, value & 0xff);
434027ba
YSP
420
421 if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
422 virtio_mmio_start_ioeventfd(proxy);
423 }
424
4b52530b
PM
425 if (vdev->status == 0) {
426 virtio_reset(vdev);
427 }
428 break;
44e687a4
SL
429 case VIRTIO_MMIO_QUEUE_DESC_LOW:
430 if (proxy->legacy) {
431 qemu_log_mask(LOG_GUEST_ERROR,
432 "%s: write to non-legacy register (0x%"
433 HWADDR_PRIx ") in legacy mode\n",
434 __func__, offset);
435 return;
436 }
437 proxy->vqs[vdev->queue_sel].desc[0] = value;
438 break;
439 case VIRTIO_MMIO_QUEUE_DESC_HIGH:
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[1] = value;
448 break;
449 case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
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].avail[0] = value;
458 break;
459 case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
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[1] = value;
468 break;
469 case VIRTIO_MMIO_QUEUE_USED_LOW:
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].used[0] = value;
478 break;
479 case VIRTIO_MMIO_QUEUE_USED_HIGH:
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[1] = value;
488 break;
7e71da7f 489 case VIRTIO_MMIO_MAGIC_VALUE:
4b52530b 490 case VIRTIO_MMIO_VERSION:
7e71da7f
MT
491 case VIRTIO_MMIO_DEVICE_ID:
492 case VIRTIO_MMIO_VENDOR_ID:
493 case VIRTIO_MMIO_DEVICE_FEATURES:
494 case VIRTIO_MMIO_QUEUE_NUM_MAX:
495 case VIRTIO_MMIO_INTERRUPT_STATUS:
44e687a4 496 case VIRTIO_MMIO_CONFIG_GENERATION:
da1804d1 497 qemu_log_mask(LOG_GUEST_ERROR,
44e687a4
SL
498 "%s: write to read-only register (0x%" HWADDR_PRIx ")\n",
499 __func__, offset);
4b52530b
PM
500 break;
501
502 default:
44e687a4
SL
503 qemu_log_mask(LOG_GUEST_ERROR,
504 "%s: bad register offset (0x%" HWADDR_PRIx ")\n",
505 __func__, offset);
4b52530b
PM
506 }
507}
508
44e687a4 509static const MemoryRegionOps virtio_legacy_mem_ops = {
4b52530b
PM
510 .read = virtio_mmio_read,
511 .write = virtio_mmio_write,
512 .endianness = DEVICE_NATIVE_ENDIAN,
513};
514
44e687a4
SL
515static const MemoryRegionOps virtio_mem_ops = {
516 .read = virtio_mmio_read,
517 .write = virtio_mmio_write,
518 .endianness = DEVICE_LITTLE_ENDIAN,
519};
520
4b52530b
PM
521static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
522{
523 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
06d3dff0 524 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
4b52530b
PM
525 int level;
526
06d3dff0 527 if (!vdev) {
4b52530b
PM
528 return;
529 }
0687c37c 530 level = (atomic_read(&vdev->isr) != 0);
da1804d1 531 trace_virtio_mmio_setting_irq(level);
4b52530b
PM
532 qemu_set_irq(proxy->irq, level);
533}
534
4b52530b
PM
535static int virtio_mmio_load_config(DeviceState *opaque, QEMUFile *f)
536{
537 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
538
539 proxy->host_features_sel = qemu_get_be32(f);
540 proxy->guest_features_sel = qemu_get_be32(f);
541 proxy->guest_page_shift = qemu_get_be32(f);
542 return 0;
543}
544
545static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
546{
547 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
548
549 qemu_put_be32(f, proxy->host_features_sel);
550 qemu_put_be32(f, proxy->guest_features_sel);
551 qemu_put_be32(f, proxy->guest_page_shift);
552}
553
44e687a4
SL
554static const VMStateDescription vmstate_virtio_mmio_queue_state = {
555 .name = "virtio_mmio/queue_state",
556 .version_id = 1,
557 .minimum_version_id = 1,
558 .fields = (VMStateField[]) {
559 VMSTATE_UINT16(num, VirtIOMMIOQueue),
560 VMSTATE_BOOL(enabled, VirtIOMMIOQueue),
561 VMSTATE_UINT32_ARRAY(desc, VirtIOMMIOQueue, 2),
562 VMSTATE_UINT32_ARRAY(avail, VirtIOMMIOQueue, 2),
563 VMSTATE_UINT32_ARRAY(used, VirtIOMMIOQueue, 2),
564 VMSTATE_END_OF_LIST()
565 }
566};
567
568static const VMStateDescription vmstate_virtio_mmio_state_sub = {
569 .name = "virtio_mmio/state",
570 .version_id = 1,
571 .minimum_version_id = 1,
572 .fields = (VMStateField[]) {
573 VMSTATE_UINT32_ARRAY(guest_features, VirtIOMMIOProxy, 2),
574 VMSTATE_STRUCT_ARRAY(vqs, VirtIOMMIOProxy, VIRTIO_QUEUE_MAX, 0,
575 vmstate_virtio_mmio_queue_state,
576 VirtIOMMIOQueue),
577 VMSTATE_END_OF_LIST()
578 }
579};
580
581static const VMStateDescription vmstate_virtio_mmio = {
582 .name = "virtio_mmio",
583 .version_id = 1,
584 .minimum_version_id = 1,
585 .minimum_version_id_old = 1,
586 .fields = (VMStateField[]) {
587 VMSTATE_END_OF_LIST()
588 },
589 .subsections = (const VMStateDescription * []) {
590 &vmstate_virtio_mmio_state_sub,
591 NULL
592 }
593};
594
595static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
596{
597 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
598
599 vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL);
600}
601
602static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
603{
604 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
605
606 return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
607}
608
609static bool virtio_mmio_has_extra_state(DeviceState *opaque)
610{
611 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
612
613 return !proxy->legacy;
614}
615
4b52530b
PM
616static void virtio_mmio_reset(DeviceState *d)
617{
618 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
44e687a4 619 int i;
4b52530b 620
434027ba 621 virtio_mmio_stop_ioeventfd(proxy);
4b52530b
PM
622 virtio_bus_reset(&proxy->bus);
623 proxy->host_features_sel = 0;
624 proxy->guest_features_sel = 0;
625 proxy->guest_page_shift = 0;
44e687a4
SL
626
627 if (!proxy->legacy) {
628 proxy->guest_features[0] = proxy->guest_features[1] = 0;
629
630 for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
631 proxy->vqs[i].enabled = 0;
632 proxy->vqs[i].num = 0;
633 proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
634 proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
635 proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
636 }
637 }
4b52530b
PM
638}
639
434027ba
YSP
640static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
641 bool with_irqfd)
642{
643 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
644 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
645 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
646 VirtQueue *vq = virtio_get_queue(vdev, n);
647 EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
648
649 if (assign) {
650 int r = event_notifier_init(notifier, 0);
651 if (r < 0) {
652 return r;
653 }
654 virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
655 } else {
656 virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
657 event_notifier_cleanup(notifier);
658 }
659
2858bc68 660 if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) {
434027ba
YSP
661 vdc->guest_notifier_mask(vdev, n, !assign);
662 }
663
664 return 0;
665}
666
667static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs,
668 bool assign)
669{
670 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
671 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
672 /* TODO: need to check if kvm-arm supports irqfd */
673 bool with_irqfd = false;
674 int r, n;
675
676 nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
677
678 for (n = 0; n < nvqs; n++) {
679 if (!virtio_queue_get_num(vdev, n)) {
680 break;
681 }
682
683 r = virtio_mmio_set_guest_notifier(d, n, assign, with_irqfd);
684 if (r < 0) {
685 goto assign_error;
686 }
687 }
688
689 return 0;
690
691assign_error:
692 /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
693 assert(assign);
694 while (--n >= 0) {
695 virtio_mmio_set_guest_notifier(d, n, !assign, false);
696 }
697 return r;
698}
699
44e687a4
SL
700static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
701{
702 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
703 VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
704
705 if (!proxy->legacy) {
706 virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
707 }
708}
709
4b52530b
PM
710/* virtio-mmio device */
711
f58b39d2
LE
712static Property virtio_mmio_properties[] = {
713 DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
714 format_transport_address, true),
44e687a4 715 DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true),
f58b39d2
LE
716 DEFINE_PROP_END_OF_LIST(),
717};
718
4b52530b
PM
719static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
720{
721 VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
722 SysBusDevice *sbd = SYS_BUS_DEVICE(d);
723
2f4f6035
IM
724 qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS,
725 d, NULL);
4b52530b 726 sysbus_init_irq(sbd, &proxy->irq);
44e687a4
SL
727 if (proxy->legacy) {
728 memory_region_init_io(&proxy->iomem, OBJECT(d),
729 &virtio_legacy_mem_ops, proxy,
730 TYPE_VIRTIO_MMIO, 0x200);
731 } else {
732 memory_region_init_io(&proxy->iomem, OBJECT(d),
733 &virtio_mem_ops, proxy,
734 TYPE_VIRTIO_MMIO, 0x200);
735 }
4b52530b
PM
736 sysbus_init_mmio(sbd, &proxy->iomem);
737}
738
739static void virtio_mmio_class_init(ObjectClass *klass, void *data)
740{
741 DeviceClass *dc = DEVICE_CLASS(klass);
742
743 dc->realize = virtio_mmio_realizefn;
744 dc->reset = virtio_mmio_reset;
125ee0ed 745 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
f58b39d2 746 dc->props = virtio_mmio_properties;
4b52530b
PM
747}
748
749static const TypeInfo virtio_mmio_info = {
750 .name = TYPE_VIRTIO_MMIO,
751 .parent = TYPE_SYS_BUS_DEVICE,
752 .instance_size = sizeof(VirtIOMMIOProxy),
753 .class_init = virtio_mmio_class_init,
754};
755
756/* virtio-mmio-bus. */
757
f58b39d2
LE
758static char *virtio_mmio_bus_get_dev_path(DeviceState *dev)
759{
760 BusState *virtio_mmio_bus;
761 VirtIOMMIOProxy *virtio_mmio_proxy;
762 char *proxy_path;
763 SysBusDevice *proxy_sbd;
764 char *path;
765
766 virtio_mmio_bus = qdev_get_parent_bus(dev);
767 virtio_mmio_proxy = VIRTIO_MMIO(virtio_mmio_bus->parent);
768 proxy_path = qdev_get_dev_path(DEVICE(virtio_mmio_proxy));
769
770 /*
771 * If @format_transport_address is false, then we just perform the same as
772 * virtio_bus_get_dev_path(): we delegate the address formatting for the
773 * device on the virtio-mmio bus to the bus that the virtio-mmio proxy
774 * (i.e., the device that implements the virtio-mmio bus) resides on. In
775 * this case the base address of the virtio-mmio transport will be
776 * invisible.
777 */
778 if (!virtio_mmio_proxy->format_transport_address) {
779 return proxy_path;
780 }
781
782 /* Otherwise, we append the base address of the transport. */
783 proxy_sbd = SYS_BUS_DEVICE(virtio_mmio_proxy);
784 assert(proxy_sbd->num_mmio == 1);
785 assert(proxy_sbd->mmio[0].memory == &virtio_mmio_proxy->iomem);
786
787 if (proxy_path) {
788 path = g_strdup_printf("%s/virtio-mmio@" TARGET_FMT_plx, proxy_path,
789 proxy_sbd->mmio[0].addr);
790 } else {
791 path = g_strdup_printf("virtio-mmio@" TARGET_FMT_plx,
792 proxy_sbd->mmio[0].addr);
793 }
794 g_free(proxy_path);
795 return path;
796}
797
4b52530b
PM
798static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
799{
800 BusClass *bus_class = BUS_CLASS(klass);
801 VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
802
803 k->notify = virtio_mmio_update_irq;
804 k->save_config = virtio_mmio_save_config;
805 k->load_config = virtio_mmio_load_config;
44e687a4
SL
806 k->save_extra_state = virtio_mmio_save_extra_state;
807 k->load_extra_state = virtio_mmio_load_extra_state;
808 k->has_extra_state = virtio_mmio_has_extra_state;
434027ba 809 k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
8e93cef1 810 k->ioeventfd_enabled = virtio_mmio_ioeventfd_enabled;
c0971bcb 811 k->ioeventfd_assign = virtio_mmio_ioeventfd_assign;
44e687a4 812 k->pre_plugged = virtio_mmio_pre_plugged;
4b52530b
PM
813 k->has_variable_vring_alignment = true;
814 bus_class->max_dev = 1;
f58b39d2 815 bus_class->get_dev_path = virtio_mmio_bus_get_dev_path;
4b52530b
PM
816}
817
818static const TypeInfo virtio_mmio_bus_info = {
819 .name = TYPE_VIRTIO_MMIO_BUS,
820 .parent = TYPE_VIRTIO_BUS,
821 .instance_size = sizeof(VirtioBusState),
822 .class_init = virtio_mmio_bus_class_init,
823};
824
825static void virtio_mmio_register_types(void)
826{
827 type_register_static(&virtio_mmio_bus_info);
828 type_register_static(&virtio_mmio_info);
829}
830
831type_init(virtio_mmio_register_types)
This page took 0.405665 seconds and 4 git commands to generate.