From b8f5cfd6824ee7122e714ffc7e893432dd7beae5 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 24 Jun 2014 23:04:44 -0300 Subject: pc: Move q35 compat props to PC_COMPAT_* For each compat property on PC_Q35_COMPAT_*, there are only two possibilities: * If the device is never instantiated when using a machine other than pc-q35, then the compat property can be safely added to PC_COMPAT_*; * If the device can be instantiated when using a machine other than pc-q35, that means the other machines also need the compat property to be set. That means we don't need separate PC_Q35_COMPAT_* macros at all, today. The hpet.hpet-intcap case is interesting: piix and q35 do have something that emulates different defaults, but the machine-specific default is applied _after_ compat_props are applied, by simply checking if the property is zero (which is the real default on the hpet code). The hpet.hpet-intcap=0x4 compat property can (should?) be applied to piix too, because 0x4 was the default on both piix and q35 before the hpet-intcap property was introduced. Now, if one day we change the default HPET intcap on one of the PC machine-types again, we may want to introduce PC_{Q35,I440FX}_COMPAT macros. But while we don't need that, we can keep the code simple. Signed-off-by: Eduardo Habkost Cc: Liu Ping Fan Cc: Peter Maydell Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_q35.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 155db99f63..36b6ab0bce 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -361,7 +361,7 @@ static QEMUMachine pc_q35_machine_v2_0 = { .name = "pc-q35-2.0", .init = pc_q35_init_2_0, .compat_props = (GlobalProperty[]) { - PC_Q35_COMPAT_2_0, + PC_COMPAT_2_0, { /* end of list */ } }, }; @@ -373,7 +373,7 @@ static QEMUMachine pc_q35_machine_v1_7 = { .name = "pc-q35-1.7", .init = pc_q35_init_1_7, .compat_props = (GlobalProperty[]) { - PC_Q35_COMPAT_1_7, + PC_COMPAT_1_7, { /* end of list */ } }, }; @@ -385,7 +385,7 @@ static QEMUMachine pc_q35_machine_v1_6 = { .name = "pc-q35-1.6", .init = pc_q35_init_1_6, .compat_props = (GlobalProperty[]) { - PC_Q35_COMPAT_1_6, + PC_COMPAT_1_6, { /* end of list */ } }, }; @@ -395,7 +395,7 @@ static QEMUMachine pc_q35_machine_v1_5 = { .name = "pc-q35-1.5", .init = pc_q35_init_1_5, .compat_props = (GlobalProperty[]) { - PC_Q35_COMPAT_1_5, + PC_COMPAT_1_5, { /* end of list */ } }, }; @@ -409,7 +409,7 @@ static QEMUMachine pc_q35_machine_v1_4 = { .name = "pc-q35-1.4", .init = pc_q35_init_1_4, .compat_props = (GlobalProperty[]) { - PC_Q35_COMPAT_1_4, + PC_COMPAT_1_4, { /* end of list */ } }, }; -- cgit v1.2.3-55-g7522 From f2ae8abf1fa003e7ec6ee22cc3871924422a01d0 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Tue, 24 Jun 2014 18:55:11 -0300 Subject: mc146818rtc: add rtc-reset-reinjection QMP command It is necessary to reset RTC interrupt reinjection backlog if guest time is synchronized via a different mechanism, such as QGA's guest-set-time command. Failing to do so causes both corrections to be applied (summed), resulting in an incorrect guest time. Signed-off-by: Marcelo Tosatti Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/timer/mc146818rtc.c | 18 ++++++++++++++++++ monitor.c | 7 +++++++ qapi-schema.json | 12 ++++++++++++ qmp-commands.hx | 23 +++++++++++++++++++++++ 4 files changed, 60 insertions(+) (limited to 'hw') diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 05002bf9d6..307732c744 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -27,6 +27,7 @@ #include "hw/timer/mc146818rtc.h" #include "qapi/visitor.h" #include "qapi-event.h" +#include "qmp-commands.h" #ifdef TARGET_I386 #include "hw/i386/apic.h" @@ -85,6 +86,7 @@ typedef struct RTCState { Notifier clock_reset_notifier; LostTickPolicy lost_tick_policy; Notifier suspend_notifier; + QLIST_ENTRY(RTCState) link; } RTCState; static void rtc_set_time(RTCState *s); @@ -523,6 +525,20 @@ static void rtc_get_time(RTCState *s, struct tm *tm) rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900; } +static QLIST_HEAD(, RTCState) rtc_devices = + QLIST_HEAD_INITIALIZER(rtc_devices); + +#ifdef TARGET_I386 +void qmp_rtc_reset_reinjection(Error **errp) +{ + RTCState *s; + + QLIST_FOREACH(s, &rtc_devices, link) { + s->irq_coalesced = 0; + } +} +#endif + static void rtc_set_time(RTCState *s) { struct tm tm; @@ -911,6 +927,8 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) } else { isa_init_irq(isadev, &s->irq, RTC_ISA_IRQ); } + QLIST_INSERT_HEAD(&rtc_devices, s, link); + return isadev; } diff --git a/monitor.c b/monitor.c index 5718d0b60a..799131bd01 100644 --- a/monitor.c +++ b/monitor.c @@ -5441,3 +5441,10 @@ QemuOptsList qemu_mon_opts = { { /* end of list */ } }, }; + +#ifndef TARGET_I386 +void qmp_rtc_reset_reinjection(Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection"); +} +#endif diff --git a/qapi-schema.json b/qapi-schema.json index a83befc05b..b11aad2068 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3468,3 +3468,15 @@ ## { 'enum': 'GuestPanicAction', 'data': [ 'pause' ] } + +## +# @rtc-reset-reinjection +# +# This command will reset the RTC interrupt reinjection backlog. +# Can be used if another mechanism to synchronize guest time +# is in effect, for example QEMU guest agent's guest-set-time +# command. +# +# Since: 2.1 +## +{ 'command': 'rtc-reset-reinjection' } diff --git a/qmp-commands.hx b/qmp-commands.hx index 65218bc147..1ea18b22a3 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -3675,3 +3675,26 @@ Example: { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0} ]} EQMP + +#if defined TARGET_I386 + { + .name = "rtc-reset-reinjection", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_rtc_reset_reinjection, + }, +#endif + +SQMP +rtc-reset-reinjection +--------------------- + +Reset the RTC interrupt reinjection backlog. + +Arguments: None. + +Example: + +-> { "execute": "rtc-reset-reinjection" } +<- { "return": {} } + +EQMP -- cgit v1.2.3-55-g7522 From 5f8632d3c3d7bc5ef24166ba7cf90fcfb2adbf7d Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Wed, 25 Jun 2014 16:19:07 -0400 Subject: pc: make isapc and pc-0.10 to pc-0.13 have 1.7.0 memory layout QEMU 2.0 changed memory layout for isapc and pc-0.10 to pc-0.13. This prevents migration from QEMU 1.7.0 for these machine types when -m 3.5G is specified. Paolo Bonzini asked that: smbios_legacy_mode = true; has_reserved_memory = false; option_rom_has_mr = true; rom_file_has_mr = false; also be done. Cc: qemu-stable@nongnu.org Cc: Paolo Bonzini Signed-off-by: Don Slutz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Fixes: https://bugs.launchpad.net/qemu/+bug/1334307 Tested-by: "Slutz, Donald Christopher" --- hw/i386/pc_piix.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'hw') diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 47546b72ae..2dccb3401b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -392,6 +392,11 @@ static void pc_init_pci_no_kvmclock(MachineState *machine) has_pci_info = false; has_acpi_build = false; smbios_defaults = false; + gigabyte_align = false; + smbios_legacy_mode = true; + has_reserved_memory = false; + option_rom_has_mr = true; + rom_file_has_mr = false; x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); enable_compat_apic_id_mode(); pc_init1(machine, 1, 0); @@ -402,6 +407,11 @@ static void pc_init_isa(MachineState *machine) has_pci_info = false; has_acpi_build = false; smbios_defaults = false; + gigabyte_align = false; + smbios_legacy_mode = true; + has_reserved_memory = false; + option_rom_has_mr = true; + rom_file_has_mr = false; if (!machine->cpu_model) { machine->cpu_model = "486"; } -- cgit v1.2.3-55-g7522 From 2f5732e9648fcddc8759a8fd25c0b41a38352be6 Mon Sep 17 00:00:00 2001 From: Dr. David Alan Gilbert Date: Fri, 27 Jun 2014 20:02:48 +0100 Subject: Allow mismatched virtio config-len Commit 'virtio: validate config_len on load' restricted config_len loaded from the wire to match the config_len that the device had. Unfortunately, there are cases where this isn't true, the one we found it on was the wce addition in virtio-blk. Allow mismatched config-lengths: *) If the version on the wire is shorter then fine *) If the version on the wire is longer, load what we have space for and skip the rest. (This is mst@redhat.com's rework of what I originally posted) Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index a3082d569d..c1d538c5f3 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -926,12 +926,18 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) return -1; } config_len = qemu_get_be32(f); - if (config_len != vdev->config_len) { - error_report("Unexpected config length 0x%x. Expected 0x%zx", - config_len, vdev->config_len); - return -1; + + /* + * There are cases where the incoming config can be bigger or smaller + * than what we have; so load what we have space for, and skip + * any excess that's in the stream. + */ + qemu_get_buffer(f, vdev->config, MIN(config_len, vdev->config_len)); + + while (config_len > vdev->config_len) { + qemu_get_byte(f); + config_len--; } - qemu_get_buffer(f, vdev->config, vdev->config_len); num = qemu_get_be32(f); -- cgit v1.2.3-55-g7522 From 3fd74b84076488ae44ba5f3cfed22ff056c5199c Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 26 Jun 2014 23:01:32 +0200 Subject: vhost-user: fix regions provied with VHOST_USER_SET_MEM_TABLE message Old code was affected by memory gaps which resulted in buffer pointers pointing to address outside of the mapped regions. Here we are introducing following changes: - new function qemu_get_ram_block_host_ptr() returns host pointer to the ram block, it is needed to calculate offset of specific region in the host memory - new field mmap_offset is added to the VhostUserMemoryRegion. It contains offset where specific region starts in the mapped memory. As there is stil no wider adoption of vhost-user agreement was made that we will not bump version number due to this change - other fileds in VhostUserMemoryRegion struct are not changed, as they are all needed for usermode app implementation - region data is not taken from ram_list.blocks anymore, instead we use region data which is alredy calculated for use in vhost-net - Now multiple regions can have same FD and user applicaton can call mmap() multiple times with the same FD but with different offset (user needs to take care for offset page alignment) Signed-off-by: Damjan Marion Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Signed-off-by: Damjan Marion --- docs/specs/vhost-user.txt | 7 ++++--- exec.c | 7 +++++++ hw/virtio/vhost-user.c | 23 ++++++++++++++--------- include/exec/ram_addr.h | 1 + 4 files changed, 26 insertions(+), 12 deletions(-) (limited to 'hw') diff --git a/docs/specs/vhost-user.txt b/docs/specs/vhost-user.txt index 2641390244..6abb6977ff 100644 --- a/docs/specs/vhost-user.txt +++ b/docs/specs/vhost-user.txt @@ -78,13 +78,14 @@ Depending on the request type, payload can be: Padding: 32-bit A region is: - --------------------------------------- - | guest address | size | user address | - --------------------------------------- + ----------------------------------------------------- + | guest address | size | user address | mmap offset | + ----------------------------------------------------- Guest address: a 64-bit guest address of the region Size: a 64-bit size User address: a 64-bit user address + mmmap offset: 64-bit offset where region starts in the mapped memory In QEMU the vhost-user message is implemented with the following struct: diff --git a/exec.c b/exec.c index c8494051a6..a94c5832f4 100644 --- a/exec.c +++ b/exec.c @@ -1456,6 +1456,13 @@ int qemu_get_ram_fd(ram_addr_t addr) return block->fd; } +void *qemu_get_ram_block_host_ptr(ram_addr_t addr) +{ + RAMBlock *block = qemu_get_ram_block(addr); + + return block->host; +} + /* Return a host pointer to ram allocated with qemu_ram_alloc. With the exception of the softmmu code in this file, this should only be used for local memory (e.g. video ram) that the device owns, diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 0df6a936a0..38e580642f 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -14,6 +14,7 @@ #include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/sockets.h" +#include "exec/ram_addr.h" #include #include @@ -47,6 +48,7 @@ typedef struct VhostUserMemoryRegion { uint64_t guest_phys_addr; uint64_t memory_size; uint64_t userspace_addr; + uint64_t mmap_offset; } VhostUserMemoryRegion; typedef struct VhostUserMemory { @@ -183,10 +185,10 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, { VhostUserMsg msg; VhostUserRequest msg_request; - RAMBlock *block = 0; struct vhost_vring_file *file = 0; int need_reply = 0; int fds[VHOST_MEMORY_MAX_NREGIONS]; + int i, fd; size_t fd_num = 0; assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); @@ -212,14 +214,17 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, break; case VHOST_SET_MEM_TABLE: - QTAILQ_FOREACH(block, &ram_list.blocks, next) - { - if (block->fd > 0) { - msg.memory.regions[fd_num].userspace_addr = - (uintptr_t) block->host; - msg.memory.regions[fd_num].memory_size = block->length; - msg.memory.regions[fd_num].guest_phys_addr = block->offset; - fds[fd_num++] = block->fd; + for (i = 0; i < dev->mem->nregions; ++i) { + struct vhost_memory_region *reg = dev->mem->regions + i; + fd = qemu_get_ram_fd(reg->guest_phys_addr); + if (fd > 0) { + msg.memory.regions[fd_num].userspace_addr = reg->userspace_addr; + msg.memory.regions[fd_num].memory_size = reg->memory_size; + msg.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr; + msg.memory.regions[fd_num].mmap_offset = reg->userspace_addr - + (uintptr_t) qemu_get_ram_block_host_ptr(reg->guest_phys_addr); + assert(fd_num < VHOST_MEMORY_MAX_NREGIONS); + fds[fd_num++] = fd; } } diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 55ca67681f..e9eb831ee3 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -29,6 +29,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr); ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr); int qemu_get_ram_fd(ram_addr_t addr); +void *qemu_get_ram_block_host_ptr(ram_addr_t addr); void *qemu_get_ram_ptr(ram_addr_t addr); void qemu_ram_free(ram_addr_t addr); void qemu_ram_free_from_ptr(ram_addr_t addr); -- cgit v1.2.3-55-g7522 From 032a74a1c0fcdd5fd1c69e56126b4c857ee36611 Mon Sep 17 00:00:00 2001 From: Cédric Le Goater Date: Tue, 24 Jun 2014 19:11:32 +0200 Subject: virtio-net: byteswap virtio-net header TCP connectivity fails when the guest has a different endianness. The packets are silently dropped on the host by the tap backend when they are read from user space because the endianness of the virtio-net header is in the wrong order. These lines may appear in the guest console: [ 454.709327] skbuff: bad partial csum: csum=8704/4096 len=74 [ 455.702554] skbuff: bad partial csum: csum=8704/4096 len=74 The issue that got first spotted with a ppc64le PowerKVM guest, but it also exists for the less common case of a x86_64 guest run by a big-endian ppc64 TCG hypervisor. Signed-off-by: Cédric Le Goater [ Ported from PowerKVM, Greg Kurz ] Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'hw') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index e51d753cee..ea1a081993 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -875,6 +875,14 @@ static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) return 1; } +static void virtio_net_hdr_swap(struct virtio_net_hdr *hdr) +{ + tswap16s(&hdr->hdr_len); + tswap16s(&hdr->gso_size); + tswap16s(&hdr->csum_start); + tswap16s(&hdr->csum_offset); +} + /* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so * it never finds out that the packets don't have valid checksums. This * causes dhclient to get upset. Fedora's carried a patch for ages to @@ -910,6 +918,7 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, void *wbuf = (void *)buf; work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, size - n->host_hdr_len); + virtio_net_hdr_swap(wbuf); iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); } else { struct virtio_net_hdr hdr = { @@ -1118,6 +1127,14 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) exit(1); } + if (n->has_vnet_hdr) { + if (out_sg[0].iov_len < n->guest_hdr_len) { + error_report("virtio-net header incorrect"); + exit(1); + } + virtio_net_hdr_swap((void *) out_sg[0].iov_base); + } + /* * If host wants to see the guest header as is, we can * pass it on unchanged. Otherwise, copy just the parts -- cgit v1.2.3-55-g7522 From e38e943a1fa20d04deb1899be19b12aadec7a585 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 24 Jun 2014 19:13:50 +0200 Subject: virtio-serial: don't migrate the config space The device configuration is set at realize time and never changes. It should not be migrated as it is done today. For the sake of compatibility, let's just skip them at load time. Signed-off-by: Alexander Graf [ added missing casts to uint16_t *, added From, SoB and commit message, Greg Kurz ] Reviewed-by: Michael S. Tsirkin Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'hw') diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index a2958ff02f..e2174b10bb 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -663,6 +663,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) uint32_t max_nr_ports, nr_active_ports, ports_map; unsigned int i; int ret; + uint32_t tmp; if (version_id > 3) { return -EINVAL; @@ -678,17 +679,12 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) return 0; } - /* The config space */ - qemu_get_be16s(f, &s->config.cols); - qemu_get_be16s(f, &s->config.rows); - - qemu_get_be32s(f, &max_nr_ports); - tswap32s(&max_nr_ports); - if (max_nr_ports > tswap32(s->config.max_nr_ports)) { - /* Source could have had more ports than us. Fail migration. */ - return -EINVAL; - } + /* Unused */ + qemu_get_be16s(f, (uint16_t *) &tmp); + qemu_get_be16s(f, (uint16_t *) &tmp); + qemu_get_be32s(f, &tmp); + max_nr_ports = tswap32(s->config.max_nr_ports); for (i = 0; i < (max_nr_ports + 31) / 32; i++) { qemu_get_be32s(f, &ports_map); -- cgit v1.2.3-55-g7522 From 1b5fc0dea469976fcbf6dc2e8f2637a2154af2fb Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:15:31 +0200 Subject: virtio: introduce device specific migration calls In order to migrate virtio subsections, they should be streamed after the device itself. We need the device specific code to be called from the common migration code to achieve this. This patch introduces load and save methods for this purpose. Suggested-by: Andreas Färber Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 2 +- hw/char/virtio-serial-bus.c | 2 +- hw/net/virtio-net.c | 2 +- hw/scsi/virtio-scsi.c | 2 +- hw/virtio/virtio-balloon.c | 2 +- hw/virtio/virtio-rng.c | 2 +- hw/virtio/virtio.c | 13 ++++++++++++- include/hw/virtio/virtio.h | 4 +++- 8 files changed, 21 insertions(+), 8 deletions(-) (limited to 'hw') diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index a222e3f9a4..5e2693a568 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -635,7 +635,7 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) if (version_id != 2) return -EINVAL; - ret = virtio_load(vdev, f); + ret = virtio_load(vdev, f, version_id); if (ret) { return ret; } diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index e2174b10bb..f919ec2440 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -670,7 +670,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) } /* The virtio device */ - ret = virtio_load(VIRTIO_DEVICE(s), f); + ret = virtio_load(VIRTIO_DEVICE(s), f, version_id); if (ret) { return ret; } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index ea1a081993..acfe91ccb6 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1362,7 +1362,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; - ret = virtio_load(vdev, f); + ret = virtio_load(vdev, f, version_id); if (ret) { return ret; } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 8c8c9d1f61..6b4fd6f625 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -549,7 +549,7 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) VirtIODevice *vdev = VIRTIO_DEVICE(opaque); int ret; - ret = virtio_load(vdev, f); + ret = virtio_load(vdev, f, version_id); if (ret) { return ret; } diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 2a2e58a297..165592e1d7 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -343,7 +343,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) if (version_id != 1) return -EINVAL; - ret = virtio_load(vdev, f); + ret = virtio_load(vdev, f, version_id); if (ret) { return ret; } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index b6ab3610cb..025de81345 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -113,7 +113,7 @@ static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) if (version_id != 1) { return -EINVAL; } - virtio_load(vdev, f); + virtio_load(vdev, f, version_id); /* We may have an element ready but couldn't process it due to a quota * limit. Make sure to try again after live migration when the quota may diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index c1d538c5f3..7f9ac5e0b9 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -843,6 +843,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) { BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); int i; if (k->save_config) { @@ -877,6 +878,10 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) k->save_queue(qbus->parent, i, f); } } + + if (vdc->save != NULL) { + vdc->save(vdev, f); + } } int virtio_set_features(VirtIODevice *vdev, uint32_t val) @@ -895,7 +900,7 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val) return bad ? -1 : 0; } -int virtio_load(VirtIODevice *vdev, QEMUFile *f) +int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) { int i, ret; int32_t config_len; @@ -904,6 +909,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) uint32_t supported_features; BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); if (k->load_config) { ret = k->load_config(qbus->parent, f); @@ -983,6 +989,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) } virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); + + if (vdc->load != NULL) { + return vdc->load(vdev, f, version_id); + } + return 0; } diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 3e54e90aad..3505ce511e 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -150,6 +150,8 @@ typedef struct VirtioDeviceClass { * must mask in frontend instead. */ void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); + void (*save)(VirtIODevice *vdev, QEMUFile *f); + int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id); } VirtioDeviceClass; void virtio_init(VirtIODevice *vdev, const char *name, @@ -184,7 +186,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_save(VirtIODevice *vdev, QEMUFile *f); -int virtio_load(VirtIODevice *vdev, QEMUFile *f); +int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id); void virtio_notify_config(VirtIODevice *vdev); -- cgit v1.2.3-55-g7522 From 037dab2fe8877f0513417ba7613a93c456962da9 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:19:03 +0200 Subject: virtio-net: implement per-device migration calls Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index acfe91ccb6..eead70e5a8 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1314,7 +1314,6 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) static void virtio_net_save(QEMUFile *f, void *opaque) { - int i; VirtIONet *n = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(n); @@ -1322,6 +1321,12 @@ static void virtio_net_save(QEMUFile *f, void *opaque) * it might keep writing to memory. */ assert(!n->vhost_started); virtio_save(vdev, f); +} + +static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) +{ + VirtIONet *n = VIRTIO_NET(vdev); + int i; qemu_put_buffer(f, n->mac, ETH_ALEN); qemu_put_be32(f, n->vqs[0].tx_waiting); @@ -1357,15 +1362,18 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(n); - int ret, i, link_down; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; - ret = virtio_load(vdev, f, version_id); - if (ret) { - return ret; - } + return virtio_load(vdev, f, version_id); +} + +static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, + int version_id) +{ + VirtIONet *n = VIRTIO_NET(vdev); + int i, link_down; qemu_get_buffer(f, n->mac, ETH_ALEN); n->vqs[0].tx_waiting = qemu_get_be32(f); @@ -1711,6 +1719,8 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->set_status = virtio_net_set_status; vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; + vdc->load = virtio_net_load_device; + vdc->save = virtio_net_save_device; } static const TypeInfo virtio_net_info = { -- cgit v1.2.3-55-g7522 From b2b295a74a17ec8b2eec166cbc65b65307a97ee2 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:19:23 +0200 Subject: virtio-blk: implement per-device migration calls Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'hw') diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 5e2693a568..b06af8c208 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -611,12 +611,16 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) static void virtio_blk_save(QEMUFile *f, void *opaque) { - VirtIOBlock *s = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(s); - VirtIOBlockReq *req = s->rq; + VirtIODevice *vdev = VIRTIO_DEVICE(opaque); virtio_save(vdev, f); +} +static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f) +{ + VirtIOBlock *s = VIRTIO_BLK(vdev); + VirtIOBlockReq *req = s->rq; + while (req) { qemu_put_sbyte(f, 1); qemu_put_buffer(f, (unsigned char *)req->elem, @@ -630,15 +634,17 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(s); - int ret; if (version_id != 2) return -EINVAL; - ret = virtio_load(vdev, f, version_id); - if (ret) { - return ret; - } + return virtio_load(vdev, f, version_id); +} + +static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, + int version_id) +{ + VirtIOBlock *s = VIRTIO_BLK(vdev); while (qemu_get_sbyte(f)) { VirtIOBlockReq *req = virtio_blk_alloc_request(s); @@ -799,6 +805,8 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data) vdc->get_features = virtio_blk_get_features; vdc->set_status = virtio_blk_set_status; vdc->reset = virtio_blk_reset; + vdc->save = virtio_blk_save_device; + vdc->load = virtio_blk_load_device; } static const TypeInfo virtio_device_info = { -- cgit v1.2.3-55-g7522 From 13c6855ab06b910a3a320b0e8f2b5f7ae8e2f351 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:19:48 +0200 Subject: virtio-serial: implement per-device migration calls Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'hw') diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index f919ec2440..b8af1b18cd 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -514,14 +514,17 @@ static void vser_reset(VirtIODevice *vdev) static void virtio_serial_save(QEMUFile *f, void *opaque) { - VirtIOSerial *s = VIRTIO_SERIAL(opaque); + /* The virtio device */ + virtio_save(VIRTIO_DEVICE(opaque), f); +} + +static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) +{ + VirtIOSerial *s = VIRTIO_SERIAL(vdev); VirtIOSerialPort *port; uint32_t nr_active_ports; unsigned int i, max_nr_ports; - /* The virtio device */ - virtio_save(VIRTIO_DEVICE(s), f); - /* The config space */ qemu_put_be16s(f, &s->config.cols); qemu_put_be16s(f, &s->config.rows); @@ -659,21 +662,22 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id, static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) { - VirtIOSerial *s = VIRTIO_SERIAL(opaque); - uint32_t max_nr_ports, nr_active_ports, ports_map; - unsigned int i; - int ret; - uint32_t tmp; - if (version_id > 3) { return -EINVAL; } /* The virtio device */ - ret = virtio_load(VIRTIO_DEVICE(s), f, version_id); - if (ret) { - return ret; - } + return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); +} + +static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, + int version_id) +{ + VirtIOSerial *s = VIRTIO_SERIAL(vdev); + uint32_t max_nr_ports, nr_active_ports, ports_map; + unsigned int i; + int ret; + uint32_t tmp; if (version_id < 2) { return 0; @@ -1015,6 +1019,8 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) vdc->get_config = get_config; vdc->set_status = set_status; vdc->reset = vser_reset; + vdc->save = virtio_serial_save_device; + vdc->load = virtio_serial_load_device; } static const TypeInfo virtio_device_info = { -- cgit v1.2.3-55-g7522 From 9ea2511c8542b875e89ab73d18480d42d6129a8c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:20:08 +0200 Subject: virtio-balloon: implement per-device migration calls Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 165592e1d7..e0ed5eee03 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -325,10 +325,12 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target) static void virtio_balloon_save(QEMUFile *f, void *opaque) { - VirtIOBalloon *s = VIRTIO_BALLOON(opaque); - VirtIODevice *vdev = VIRTIO_DEVICE(s); + virtio_save(VIRTIO_DEVICE(opaque), f); +} - virtio_save(vdev, f); +static void virtio_balloon_save_device(VirtIODevice *vdev, QEMUFile *f) +{ + VirtIOBalloon *s = VIRTIO_BALLOON(vdev); qemu_put_be32(f, s->num_pages); qemu_put_be32(f, s->actual); @@ -336,17 +338,16 @@ static void virtio_balloon_save(QEMUFile *f, void *opaque) static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) { - VirtIOBalloon *s = VIRTIO_BALLOON(opaque); - VirtIODevice *vdev = VIRTIO_DEVICE(s); - int ret; - if (version_id != 1) return -EINVAL; - ret = virtio_load(vdev, f, version_id); - if (ret) { - return ret; - } + return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); +} + +static int virtio_balloon_load_device(VirtIODevice *vdev, QEMUFile *f, + int version_id) +{ + VirtIOBalloon *s = VIRTIO_BALLOON(vdev); s->num_pages = qemu_get_be32(f); s->actual = qemu_get_be32(f); @@ -416,6 +417,8 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data) vdc->get_config = virtio_balloon_get_config; vdc->set_config = virtio_balloon_set_config; vdc->get_features = virtio_balloon_get_features; + vdc->save = virtio_balloon_save_device; + vdc->load = virtio_balloon_load_device; } static const TypeInfo virtio_balloon_info = { -- cgit v1.2.3-55-g7522 From 3902d49e13c2428bd6381cfdf183103ca4477c1f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:20:23 +0200 Subject: virtio-rng: implement per-device migration calls While we are here, we also check virtio_load() return value. Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-rng.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 025de81345..1356aca8d6 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -107,19 +107,20 @@ static void virtio_rng_save(QEMUFile *f, void *opaque) static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) { - VirtIORNG *vrng = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(vrng); - if (version_id != 1) { return -EINVAL; } - virtio_load(vdev, f, version_id); + return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); +} +static int virtio_rng_load_device(VirtIODevice *vdev, QEMUFile *f, + int version_id) +{ /* We may have an element ready but couldn't process it due to a quota * limit. Make sure to try again after live migration when the quota may * have been reset. */ - virtio_rng_process(vrng); + virtio_rng_process(VIRTIO_RNG(vdev)); return 0; } @@ -219,6 +220,7 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) vdc->realize = virtio_rng_device_realize; vdc->unrealize = virtio_rng_device_unrealize; vdc->get_features = get_features; + vdc->load = virtio_rng_load_device; } static void virtio_rng_initfn(Object *obj) -- cgit v1.2.3-55-g7522 From 6b321a3df55de42ad349870a8793e33a69f9d1a3 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:22:30 +0200 Subject: virtio: add subsections to the migration stream There is a need to add some more fields to VirtIODevice that should be migrated (broken status, endianness). The problem is that we do not want to break compatibility while adding a new feature... This issue has been addressed in the generic VMState code with the use of optional subsections. As a *temporary* alternative to port the whole virtio migration code to VMState, this patch mimics a similar subsectionning ability for virtio, using the VMState code. Since each virtio device is streamed in its own section, the idea is to stream subsections between the end of the device section and the start of the next sections. This allows an older QEMU to complain and exit when fed with subsections: Unknown savevm section type 5 load of migration failed Suggested-by: Alexander Graf Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 7f9ac5e0b9..7b317ce279 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -19,6 +19,7 @@ #include "hw/virtio/virtio.h" #include "qemu/atomic.h" #include "hw/virtio/virtio-bus.h" +#include "migration/migration.h" /* * The alignment to use between consumer and producer parts of vring. @@ -839,6 +840,16 @@ void virtio_notify_config(VirtIODevice *vdev) virtio_notify_vector(vdev, vdev->config_vector); } +static const VMStateDescription vmstate_virtio = { + .name = "virtio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + void virtio_save(VirtIODevice *vdev, QEMUFile *f) { BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); @@ -882,6 +893,9 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) if (vdc->save != NULL) { vdc->save(vdev, f); } + + /* Subsections */ + vmstate_save_state(f, &vmstate_virtio, vdev); } int virtio_set_features(VirtIODevice *vdev, uint32_t val) @@ -991,10 +1005,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); if (vdc->load != NULL) { - return vdc->load(vdev, f, version_id); + ret = vdc->load(vdev, f, version_id); + if (ret) { + return ret; + } } - return 0; + return vmstate_load_state(f, &vmstate_virtio, vdev, 1); } void virtio_cleanup(VirtIODevice *vdev) -- cgit v1.2.3-55-g7522 From 98ed8ecfc9dd9e22e4251251492f062dde32c3c4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:26:29 +0200 Subject: exec: introduce target_words_bigendian() helper We currently have a virtio_is_big_endian() helper that provides the target endianness to the virtio code. As of today, the helper returns a fixed compile-time value. Of course, this will have to change if we want to support target endianness changes at run-time. Let's move the TARGET_WORDS_BIGENDIAN bits out to a new helper and have virtio_is_big_endian() implemented on top of it. This patch doesn't change any functionality. Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- exec.c | 8 ++------ hw/virtio/virtio-pci.c | 3 --- include/hw/virtio/virtio.h | 6 ++++++ 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/exec.c b/exec.c index a94c5832f4..18d6c35942 100644 --- a/exec.c +++ b/exec.c @@ -2759,14 +2759,12 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, } #endif -#if !defined(CONFIG_USER_ONLY) - /* * A helper function for the _utterly broken_ virtio device model to find out if * it's running on a big endian machine. Don't do this at home kids! */ -bool virtio_is_big_endian(void); -bool virtio_is_big_endian(void) +bool target_words_bigendian(void); +bool target_words_bigendian(void) { #if defined(TARGET_WORDS_BIGENDIAN) return true; @@ -2775,8 +2773,6 @@ bool virtio_is_big_endian(void) #endif } -#endif - #ifndef CONFIG_USER_ONLY bool cpu_physical_memory_is_io(hwaddr phys_addr) { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 57e1e6141e..e11f759e94 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -89,9 +89,6 @@ /* Flags track per-device state like workarounds for quirks in older guests. */ #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0) -/* HACK for virtio to determine if it's running a big endian guest */ -bool virtio_is_big_endian(void); - static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, VirtIOPCIProxy *dev); diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 3505ce511e..9000ee2f50 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -255,4 +255,10 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, bool set_handler); void virtio_queue_notify_vq(VirtQueue *vq); void virtio_irq(VirtQueue *vq); + +bool target_words_bigendian(void); +static inline bool virtio_is_big_endian(void) +{ + return target_words_bigendian(); +} #endif -- cgit v1.2.3-55-g7522 From 616a655219a92ae7cf5d6a7862e6489c6282009e Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:38:54 +0200 Subject: virtio: add endian-ambivalent support to VirtIODevice Some CPU families can dynamically change their endianness. This means we can have little endian ppc or big endian arm guests for example. This has an impact on legacy virtio data structures since they are target endian. We hence introduce a new property to track the endianness of each virtio device. It is reasonnably assumed that endianness won't change while the device is in use : we hence capture the device endianness when it gets reset. We migrate this property in a subsection, after the device descriptor. This means the load code must not rely on it until it is restored. As a consequence, the vring sanity checks had to be moved after the call to vmstate_load_state(). We enforce paranoia by poisoning the property at the begining of virtio_load(). Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 8 ++-- hw/virtio/virtio.c | 99 ++++++++++++++++++++++++++++++++++++++++------ include/hw/virtio/virtio.h | 13 ++++-- 3 files changed, 101 insertions(+), 19 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index e11f759e94..317324f23d 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -406,13 +406,13 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, break; case 2: val = virtio_config_readw(vdev, addr); - if (virtio_is_big_endian()) { + if (virtio_is_big_endian(vdev)) { val = bswap16(val); } break; case 4: val = virtio_config_readl(vdev, addr); - if (virtio_is_big_endian()) { + if (virtio_is_big_endian(vdev)) { val = bswap32(val); } break; @@ -440,13 +440,13 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr, virtio_config_writeb(vdev, addr, val); break; case 2: - if (virtio_is_big_endian()) { + if (virtio_is_big_endian(vdev)) { val = bswap16(val); } virtio_config_writew(vdev, addr, val); break; case 4: - if (virtio_is_big_endian()) { + if (virtio_is_big_endian(vdev)) { val = bswap32(val); } virtio_config_writel(vdev, addr, val); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 7b317ce279..a0676e06af 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -545,6 +545,27 @@ void virtio_set_status(VirtIODevice *vdev, uint8_t val) vdev->status = val; } +bool target_words_bigendian(void); +static enum virtio_device_endian virtio_default_endian(void) +{ + if (target_words_bigendian()) { + return VIRTIO_DEVICE_ENDIAN_BIG; + } else { + return VIRTIO_DEVICE_ENDIAN_LITTLE; + } +} + +static enum virtio_device_endian virtio_current_cpu_endian(void) +{ + CPUClass *cc = CPU_GET_CLASS(current_cpu); + + if (cc->virtio_is_big_endian(current_cpu)) { + return VIRTIO_DEVICE_ENDIAN_BIG; + } else { + return VIRTIO_DEVICE_ENDIAN_LITTLE; + } +} + void virtio_reset(void *opaque) { VirtIODevice *vdev = opaque; @@ -552,6 +573,13 @@ void virtio_reset(void *opaque) int i; virtio_set_status(vdev, 0); + if (current_cpu) { + /* Guest initiated reset */ + vdev->device_endian = virtio_current_cpu_endian(); + } else { + /* System reset */ + vdev->device_endian = virtio_default_endian(); + } if (k->reset) { k->reset(vdev); @@ -840,6 +868,24 @@ void virtio_notify_config(VirtIODevice *vdev) virtio_notify_vector(vdev, vdev->config_vector); } +static bool virtio_device_endian_needed(void *opaque) +{ + VirtIODevice *vdev = opaque; + + assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); + return vdev->device_endian != virtio_default_endian(); +} + +static const VMStateDescription vmstate_virtio_device_endian = { + .name = "virtio/device_endian", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(device_endian, VirtIODevice), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_virtio = { .name = "virtio", .version_id = 1, @@ -847,6 +893,13 @@ static const VMStateDescription vmstate_virtio = { .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &vmstate_virtio_device_endian, + .needed = &virtio_device_endian_needed + }, + { 0 } } }; @@ -925,6 +978,12 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + /* + * We poison the endianness to ensure it does not get used before + * subsections have been loaded. + */ + vdev->device_endian = VIRTIO_DEVICE_ENDIAN_UNKNOWN; + if (k->load_config) { ret = k->load_config(qbus->parent, f); if (ret) @@ -977,18 +1036,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) vdev->vq[i].notification = true; if (vdev->vq[i].pa) { - uint16_t nheads; virtqueue_init(&vdev->vq[i]); - nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx; - /* Check it isn't doing very strange things with descriptor numbers. */ - if (nheads > vdev->vq[i].vring.num) { - error_report("VQ %d size 0x%x Guest index 0x%x " - "inconsistent with Host index 0x%x: delta 0x%x", - i, vdev->vq[i].vring.num, - vring_avail_idx(&vdev->vq[i]), - vdev->vq[i].last_avail_idx, nheads); - return -1; - } } else if (vdev->vq[i].last_avail_idx) { error_report("VQ %d address 0x0 " "inconsistent with Host index 0x%x", @@ -1011,7 +1059,33 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) } } - return vmstate_load_state(f, &vmstate_virtio, vdev, 1); + /* Subsections */ + ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1); + if (ret) { + return ret; + } + + if (vdev->device_endian == VIRTIO_DEVICE_ENDIAN_UNKNOWN) { + vdev->device_endian = virtio_default_endian(); + } + + for (i = 0; i < num; i++) { + if (vdev->vq[i].pa) { + uint16_t nheads; + nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx; + /* Check it isn't doing strange things with descriptor numbers. */ + if (nheads > vdev->vq[i].vring.num) { + error_report("VQ %d size 0x%x Guest index 0x%x " + "inconsistent with Host index 0x%x: delta 0x%x", + i, vdev->vq[i].vring.num, + vring_avail_idx(&vdev->vq[i]), + vdev->vq[i].last_avail_idx, nheads); + return -1; + } + } + } + + return 0; } void virtio_cleanup(VirtIODevice *vdev) @@ -1068,6 +1142,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, } vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, vdev); + vdev->device_endian = virtio_default_endian(); } hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 9000ee2f50..a60104ca24 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -104,6 +104,12 @@ typedef struct VirtQueueElement #define VIRTIO_DEVICE(obj) \ OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE) +enum virtio_device_endian { + VIRTIO_DEVICE_ENDIAN_UNKNOWN, + VIRTIO_DEVICE_ENDIAN_LITTLE, + VIRTIO_DEVICE_ENDIAN_BIG, +}; + struct VirtIODevice { DeviceState parent_obj; @@ -121,6 +127,7 @@ struct VirtIODevice bool vm_running; VMChangeStateEntry *vmstate; char *bus_name; + uint8_t device_endian; }; typedef struct VirtioDeviceClass { @@ -256,9 +263,9 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, void virtio_queue_notify_vq(VirtQueue *vq); void virtio_irq(VirtQueue *vq); -bool target_words_bigendian(void); -static inline bool virtio_is_big_endian(void) +static inline bool virtio_is_big_endian(VirtIODevice *vdev) { - return target_words_bigendian(); + assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); + return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; } #endif -- cgit v1.2.3-55-g7522 From cee3ca002855f87b78aaa7769efeb90321757e49 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Jun 2014 19:40:16 +0200 Subject: virtio: allow byte swapping for vring Quoting original text from Rusty: "This is based on a simpler patch by Anthony Liguouri". Signed-off-by: Rusty Russell [ add VirtIODevice * argument to most helpers, Greg Kurz ] Signed-off-by: Greg Kurz Reviewed-by: Thomas Huth Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 89 +++++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 41 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index a0676e06af..5c981801f3 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -20,6 +20,7 @@ #include "qemu/atomic.h" #include "hw/virtio/virtio-bus.h" #include "migration/migration.h" +#include "hw/virtio/virtio-access.h" /* * The alignment to use between consumer and producer parts of vring. @@ -102,53 +103,56 @@ static void virtqueue_init(VirtQueue *vq) vq->vring.align); } -static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i) +static inline uint64_t vring_desc_addr(VirtIODevice *vdev, hwaddr desc_pa, + int i) { hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr); - return ldq_phys(&address_space_memory, pa); + return virtio_ldq_phys(vdev, pa); } -static inline uint32_t vring_desc_len(hwaddr desc_pa, int i) +static inline uint32_t vring_desc_len(VirtIODevice *vdev, hwaddr desc_pa, int i) { hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len); - return ldl_phys(&address_space_memory, pa); + return virtio_ldl_phys(vdev, pa); } -static inline uint16_t vring_desc_flags(hwaddr desc_pa, int i) +static inline uint16_t vring_desc_flags(VirtIODevice *vdev, hwaddr desc_pa, + int i) { hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags); - return lduw_phys(&address_space_memory, pa); + return virtio_lduw_phys(vdev, pa); } -static inline uint16_t vring_desc_next(hwaddr desc_pa, int i) +static inline uint16_t vring_desc_next(VirtIODevice *vdev, hwaddr desc_pa, + int i) { hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next); - return lduw_phys(&address_space_memory, pa); + return virtio_lduw_phys(vdev, pa); } static inline uint16_t vring_avail_flags(VirtQueue *vq) { hwaddr pa; pa = vq->vring.avail + offsetof(VRingAvail, flags); - return lduw_phys(&address_space_memory, pa); + return virtio_lduw_phys(vq->vdev, pa); } static inline uint16_t vring_avail_idx(VirtQueue *vq) { hwaddr pa; pa = vq->vring.avail + offsetof(VRingAvail, idx); - return lduw_phys(&address_space_memory, pa); + return virtio_lduw_phys(vq->vdev, pa); } static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) { hwaddr pa; pa = vq->vring.avail + offsetof(VRingAvail, ring[i]); - return lduw_phys(&address_space_memory, pa); + return virtio_lduw_phys(vq->vdev, pa); } static inline uint16_t vring_used_event(VirtQueue *vq) @@ -160,44 +164,44 @@ static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val) { hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, ring[i].id); - stl_phys(&address_space_memory, pa, val); + virtio_stl_phys(vq->vdev, pa, val); } static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val) { hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, ring[i].len); - stl_phys(&address_space_memory, pa, val); + virtio_stl_phys(vq->vdev, pa, val); } static uint16_t vring_used_idx(VirtQueue *vq) { hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, idx); - return lduw_phys(&address_space_memory, pa); + return virtio_lduw_phys(vq->vdev, pa); } static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) { hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, idx); - stw_phys(&address_space_memory, pa, val); + virtio_stw_phys(vq->vdev, pa, val); } static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) { + VirtIODevice *vdev = vq->vdev; hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, flags); - stw_phys(&address_space_memory, - pa, lduw_phys(&address_space_memory, pa) | mask); + virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) | mask); } static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) { + VirtIODevice *vdev = vq->vdev; hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, flags); - stw_phys(&address_space_memory, - pa, lduw_phys(&address_space_memory, pa) & ~mask); + virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) & ~mask); } static inline void vring_avail_event(VirtQueue *vq, uint16_t val) @@ -207,7 +211,7 @@ static inline void vring_avail_event(VirtQueue *vq, uint16_t val) return; } pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]); - stw_phys(&address_space_memory, pa, val); + virtio_stw_phys(vq->vdev, pa, val); } void virtio_queue_set_notification(VirtQueue *vq, int enable) @@ -324,17 +328,18 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) return head; } -static unsigned virtqueue_next_desc(hwaddr desc_pa, +static unsigned virtqueue_next_desc(VirtIODevice *vdev, hwaddr desc_pa, unsigned int i, unsigned int max) { unsigned int next; /* If this descriptor says it doesn't chain, we're done. */ - if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT)) + if (!(vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_NEXT)) { return max; + } /* Check they're not leading us off end of descriptors. */ - next = vring_desc_next(desc_pa, i); + next = vring_desc_next(vdev, desc_pa, i); /* Make sure compiler knows to grab that: we don't want it changing! */ smp_wmb(); @@ -357,6 +362,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, total_bufs = in_total = out_total = 0; while (virtqueue_num_heads(vq, idx)) { + VirtIODevice *vdev = vq->vdev; unsigned int max, num_bufs, indirect = 0; hwaddr desc_pa; int i; @@ -366,8 +372,8 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, i = virtqueue_get_head(vq, idx++); desc_pa = vq->vring.desc; - if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { - if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { + if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) { + if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) { error_report("Invalid size for indirect buffer table"); exit(1); } @@ -380,8 +386,8 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, /* loop over the indirect descriptor table */ indirect = 1; - max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc); - desc_pa = vring_desc_addr(desc_pa, i); + max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc); + desc_pa = vring_desc_addr(vdev, desc_pa, i); num_bufs = i = 0; } @@ -392,15 +398,15 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, exit(1); } - if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { - in_total += vring_desc_len(desc_pa, i); + if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) { + in_total += vring_desc_len(vdev, desc_pa, i); } else { - out_total += vring_desc_len(desc_pa, i); + out_total += vring_desc_len(vdev, desc_pa, i); } if (in_total >= max_in_bytes && out_total >= max_out_bytes) { goto done; } - } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); + } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max); if (!indirect) total_bufs = num_bufs; @@ -451,6 +457,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) { unsigned int i, head, max; hwaddr desc_pa = vq->vring.desc; + VirtIODevice *vdev = vq->vdev; if (!virtqueue_num_heads(vq, vq->last_avail_idx)) return 0; @@ -461,19 +468,19 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) max = vq->vring.num; i = head = virtqueue_get_head(vq, vq->last_avail_idx++); - if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { + if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { vring_avail_event(vq, vring_avail_idx(vq)); } - if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { - if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { + if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) { + if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) { error_report("Invalid size for indirect buffer table"); exit(1); } /* loop over the indirect descriptor table */ - max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc); - desc_pa = vring_desc_addr(desc_pa, i); + max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc); + desc_pa = vring_desc_addr(vdev, desc_pa, i); i = 0; } @@ -481,30 +488,30 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) do { struct iovec *sg; - if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { + if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) { if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) { error_report("Too many write descriptors in indirect table"); exit(1); } - elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i); + elem->in_addr[elem->in_num] = vring_desc_addr(vdev, desc_pa, i); sg = &elem->in_sg[elem->in_num++]; } else { if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) { error_report("Too many read descriptors in indirect table"); exit(1); } - elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i); + elem->out_addr[elem->out_num] = vring_desc_addr(vdev, desc_pa, i); sg = &elem->out_sg[elem->out_num++]; } - sg->iov_len = vring_desc_len(desc_pa, i); + sg->iov_len = vring_desc_len(vdev, desc_pa, i); /* If we've got too many, that implies a descriptor loop. */ if ((elem->in_num + elem->out_num) > max) { error_report("Looped descriptor"); exit(1); } - } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); + } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max); /* Now map what we have collected */ virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1); -- cgit v1.2.3-55-g7522 From 1399c60d70a261acbeb65f614a00eab2dbf4237b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Jun 2014 19:42:54 +0200 Subject: virtio-net: use virtio wrappers to access headers Signed-off-by: Rusty Russell Reviewed-by: Anthony Liguori [ pass VirtIODevice * to memory accessors, converted new tswap locations to virtio_tswap, Greg Kurz ] Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'hw') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index eead70e5a8..268eff9df8 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -23,6 +23,7 @@ #include "hw/virtio/virtio-bus.h" #include "qapi/qmp/qjson.h" #include "qapi-event.h" +#include "hw/virtio/virtio-access.h" #define VIRTIO_NET_VM_VERSION 11 @@ -72,8 +73,8 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_config netcfg; - stw_p(&netcfg.status, n->status); - stw_p(&netcfg.max_virtqueue_pairs, n->max_queues); + virtio_stw_p(vdev, &netcfg.status, n->status); + virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues); memcpy(netcfg.mac, n->mac, ETH_ALEN); memcpy(config, &netcfg, n->config_size); } @@ -604,6 +605,7 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd, static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, struct iovec *iov, unsigned int iov_cnt) { + VirtIODevice *vdev = VIRTIO_DEVICE(n); struct virtio_net_ctrl_mac mac_data; size_t s; NetClientState *nc = qemu_get_queue(n->nic); @@ -632,7 +634,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, sizeof(mac_data.entries)); - mac_data.entries = ldl_p(&mac_data.entries); + mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries); if (s != sizeof(mac_data.entries)) { goto error; } @@ -659,7 +661,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, sizeof(mac_data.entries)); - mac_data.entries = ldl_p(&mac_data.entries); + mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries); if (s != sizeof(mac_data.entries)) { goto error; } @@ -699,12 +701,13 @@ error: static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, struct iovec *iov, unsigned int iov_cnt) { + VirtIODevice *vdev = VIRTIO_DEVICE(n); uint16_t vid; size_t s; NetClientState *nc = qemu_get_queue(n->nic); s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid)); - vid = lduw_p(&vid); + vid = virtio_lduw_p(vdev, &vid); if (s != sizeof(vid)) { return VIRTIO_NET_ERR; } @@ -758,7 +761,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; } - queues = lduw_p(&mq.virtqueue_pairs); + queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs); if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || @@ -875,12 +878,12 @@ static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) return 1; } -static void virtio_net_hdr_swap(struct virtio_net_hdr *hdr) +static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr) { - tswap16s(&hdr->hdr_len); - tswap16s(&hdr->gso_size); - tswap16s(&hdr->csum_start); - tswap16s(&hdr->csum_offset); + virtio_tswap16s(vdev, &hdr->hdr_len); + virtio_tswap16s(vdev, &hdr->gso_size); + virtio_tswap16s(vdev, &hdr->csum_start); + virtio_tswap16s(vdev, &hdr->csum_offset); } /* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so @@ -918,7 +921,7 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, void *wbuf = (void *)buf; work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, size - n->host_hdr_len); - virtio_net_hdr_swap(wbuf); + virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); } else { struct virtio_net_hdr hdr = { @@ -1068,7 +1071,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t } if (mhdr_cnt) { - stw_p(&mhdr.num_buffers, i); + virtio_stw_p(vdev, &mhdr.num_buffers, i); iov_from_buf(mhdr_sg, mhdr_cnt, 0, &mhdr.num_buffers, sizeof mhdr.num_buffers); @@ -1132,7 +1135,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) error_report("virtio-net header incorrect"); exit(1); } - virtio_net_hdr_swap((void *) out_sg[0].iov_base); + virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base); } /* -- cgit v1.2.3-55-g7522 From 8609d2a87aff1e4b45fa96f7373d9f8e07951deb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Jun 2014 19:43:22 +0200 Subject: virtio-balloon: use virtio wrappers to access page frame numbers Signed-off-by: Rusty Russell Reviewed-by: Anthony Liguori [ pass VirtIODevice * to memory accessors, Greg Kurz ] Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index e0ed5eee03..2c30b3d8bd 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -31,6 +31,7 @@ #endif #include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" static void balloon_page(void *addr, int deflate) { @@ -206,8 +207,9 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) { ram_addr_t pa; ram_addr_t addr; + int p = virtio_ldl_p(vdev, &pfn); - pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT; + pa = (ram_addr_t) p << VIRTIO_BALLOON_PFN_SHIFT; offset += 4; /* FIXME: remove get_system_memory(), but how? */ @@ -248,8 +250,8 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat)) == sizeof(stat)) { - uint16_t tag = tswap16(stat.tag); - uint64_t val = tswap64(stat.val); + uint16_t tag = virtio_tswap16(vdev, stat.tag); + uint64_t val = virtio_tswap64(vdev, stat.val); offset += sizeof(stat); if (tag < VIRTIO_BALLOON_S_NR) -- cgit v1.2.3-55-g7522 From 783d189725d937f8ed9dae68c7e35b6afa0691da Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Jun 2014 19:43:44 +0200 Subject: virtio-blk: use virtio wrappers to access headers Note that st*_raw and ld*_raw are effectively replaced by st*_p and ld*_p. Signed-off-by: Rusty Russell Reviewed-by: Anthony Liguori [ pass VirtIODevice * to memory accessors, Greg Kurz ] Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'hw') diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index b06af8c208..e59ebc962d 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -27,6 +27,7 @@ # include #endif #include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s) { @@ -88,7 +89,8 @@ static void virtio_blk_rw_complete(void *opaque, int ret) trace_virtio_blk_rw_complete(req, ret); if (ret) { - bool is_read = !(ldl_p(&req->out.type) & VIRTIO_BLK_T_OUT); + int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type); + bool is_read = !(p & VIRTIO_BLK_T_OUT); if (virtio_blk_handle_rw_error(req, -ret, is_read)) return; } @@ -130,6 +132,8 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk, { int status = VIRTIO_BLK_S_OK; struct virtio_scsi_inhdr *scsi = NULL; + VirtIODevice *vdev = VIRTIO_DEVICE(blk); + #ifdef __linux__ int i; struct sg_io_hdr hdr; @@ -224,12 +228,12 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk, hdr.status = CHECK_CONDITION; } - stl_p(&scsi->errors, - hdr.status | (hdr.msg_status << 8) | - (hdr.host_status << 16) | (hdr.driver_status << 24)); - stl_p(&scsi->residual, hdr.resid); - stl_p(&scsi->sense_len, hdr.sb_len_wr); - stl_p(&scsi->data_len, hdr.dxfer_len); + virtio_stl_p(vdev, &scsi->errors, + hdr.status | (hdr.msg_status << 8) | + (hdr.host_status << 16) | (hdr.driver_status << 24)); + virtio_stl_p(vdev, &scsi->residual, hdr.resid); + virtio_stl_p(vdev, &scsi->sense_len, hdr.sb_len_wr); + virtio_stl_p(vdev, &scsi->data_len, hdr.dxfer_len); return status; #else @@ -239,7 +243,7 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk, fail: /* Just put anything nonzero so that the ioctl fails in the guest. */ if (scsi) { - stl_p(&scsi->errors, 255); + virtio_stl_p(vdev, &scsi->errors, 255); } return status; } @@ -289,7 +293,7 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb) BlockRequest *blkreq; uint64_t sector; - sector = ldq_p(&req->out.sector); + sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector); bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE); @@ -323,7 +327,7 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req) { uint64_t sector; - sector = ldq_p(&req->out.sector); + sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector); bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ); @@ -374,7 +378,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) - sizeof(struct virtio_blk_inhdr); iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); - type = ldl_p(&req->out.type); + type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type); if (type & VIRTIO_BLK_T_FLUSH) { virtio_blk_handle_flush(req, mrb); @@ -504,12 +508,12 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) bdrv_get_geometry(s->bs, &capacity); memset(&blkcfg, 0, sizeof(blkcfg)); - stq_p(&blkcfg.capacity, capacity); - stl_p(&blkcfg.seg_max, 128 - 2); - stw_p(&blkcfg.cylinders, s->conf->cyls); - stl_p(&blkcfg.blk_size, blk_size); - stw_p(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); - stw_p(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); + virtio_stq_p(vdev, &blkcfg.capacity, capacity); + virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2); + virtio_stw_p(vdev, &blkcfg.cylinders, s->conf->cyls); + virtio_stl_p(vdev, &blkcfg.blk_size, blk_size); + virtio_stw_p(vdev, &blkcfg.min_io_size, s->conf->min_io_size / blk_size); + virtio_stw_p(vdev, &blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); blkcfg.heads = s->conf->heads; /* * We must ensure that the block device capacity is a multiple of -- cgit v1.2.3-55-g7522 From 8c085dbe6d1e3fb3f18cdd05e67980a529a3ba4a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Jun 2014 19:48:53 +0200 Subject: virtio-scsi: use virtio wrappers to access headers Note that st*_raw and ld*_raw are effectively replaced by st*_p and ld*_p. Signed-off-by: Rusty Russell Reviewed-by: Anthony Liguori [ pass VirtIODevice * to memory accessors, converted new tswap locations to virtio_tswap, Greg Kurz ] Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6b4fd6f625..04ecfa7e9a 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -19,6 +19,7 @@ #include #include #include +#include "hw/virtio/virtio-access.h" typedef struct VirtIOSCSIReq { VirtIOSCSI *dev; @@ -235,7 +236,7 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ req->resp.tmf.response = VIRTIO_SCSI_S_OK; - tswap32s(&req->req.tmf.subtype); + virtio_tswap32s(VIRTIO_DEVICE(s), &req->req.tmf.subtype); switch (req->req.tmf.subtype) { case VIRTIO_SCSI_T_TMF_ABORT_TASK: case VIRTIO_SCSI_T_TMF_QUERY_TASK: @@ -346,7 +347,7 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) continue; } - tswap32s(&req->req.tmf.type); + virtio_tswap32s(vdev, &req->req.tmf.type); if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) { if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), sizeof(VirtIOSCSICtrlTMFResp)) < 0) { @@ -384,6 +385,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, VirtIOSCSIReq *req = r->hba_private; uint8_t sense[SCSI_SENSE_BUF_SIZE]; uint32_t sense_len; + VirtIODevice *vdev = VIRTIO_DEVICE(req->dev); if (r->io_canceled) { return; @@ -392,14 +394,14 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, req->resp.cmd.response = VIRTIO_SCSI_S_OK; req->resp.cmd.status = status; if (req->resp.cmd.status == GOOD) { - req->resp.cmd.resid = tswap32(resid); + req->resp.cmd.resid = virtio_tswap32(vdev, resid); } else { req->resp.cmd.resid = 0; sense_len = scsi_req_get_sense(r, sense, sizeof(sense)); sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd)); qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd), &req->resp, sense_len); - req->resp.cmd.sense_len = tswap32(sense_len); + req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len); } virtio_scsi_complete_cmd_req(req); } @@ -487,16 +489,16 @@ static void virtio_scsi_get_config(VirtIODevice *vdev, VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev); - stl_p(&scsiconf->num_queues, s->conf.num_queues); - stl_p(&scsiconf->seg_max, 128 - 2); - stl_p(&scsiconf->max_sectors, s->conf.max_sectors); - stl_p(&scsiconf->cmd_per_lun, s->conf.cmd_per_lun); - stl_p(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent)); - stl_p(&scsiconf->sense_size, s->sense_size); - stl_p(&scsiconf->cdb_size, s->cdb_size); - stw_p(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); - stw_p(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); - stl_p(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN); + virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues); + virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2); + virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors); + virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun); + virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent)); + virtio_stl_p(vdev, &scsiconf->sense_size, s->sense_size); + virtio_stl_p(vdev, &scsiconf->cdb_size, s->cdb_size); + virtio_stw_p(vdev, &scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); + virtio_stw_p(vdev, &scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); + virtio_stl_p(vdev, &scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN); } static void virtio_scsi_set_config(VirtIODevice *vdev, @@ -505,14 +507,14 @@ static void virtio_scsi_set_config(VirtIODevice *vdev, VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - if ((uint32_t) ldl_p(&scsiconf->sense_size) >= 65536 || - (uint32_t) ldl_p(&scsiconf->cdb_size) >= 256) { + if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) >= 65536 || + (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) >= 256) { error_report("bad data written to virtio-scsi configuration space"); exit(1); } - vs->sense_size = ldl_p(&scsiconf->sense_size); - vs->cdb_size = ldl_p(&scsiconf->cdb_size); + vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size); + vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size); } static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, -- cgit v1.2.3-55-g7522 From e0ab7fac65dc75573d3f02105c80981be4f49c2d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Jun 2014 19:49:31 +0200 Subject: virtio-serial-bus: use virtio wrappers to access headers We also fix max_nr_ports at reset time as the device endianness may have changed. Signed-off-by: Rusty Russell Reviewed-by: Anthony Liguori [ pass VirtIODevice * to memory accessors, fix max_nr_ports at reset time, Greg Kurz ] Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 46 ++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) (limited to 'hw') diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index b8af1b18cd..07bebc03ac 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -24,6 +24,7 @@ #include "hw/sysbus.h" #include "trace.h" #include "hw/virtio/virtio-serial.h" +#include "hw/virtio/virtio-access.h" static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id) { @@ -183,11 +184,12 @@ static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len) static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id, uint16_t event, uint16_t value) { + VirtIODevice *vdev = VIRTIO_DEVICE(vser); struct virtio_console_control cpkt; - stl_p(&cpkt.id, port_id); - stw_p(&cpkt.event, event); - stw_p(&cpkt.value, value); + virtio_stl_p(vdev, &cpkt.id, port_id); + virtio_stw_p(vdev, &cpkt.event, event); + virtio_stw_p(vdev, &cpkt.value, value); trace_virtio_serial_send_control_event(port_id, event, value); return send_control_msg(vser, &cpkt, sizeof(cpkt)); @@ -278,6 +280,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle) /* Guest wants to notify us of some event */ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) { + VirtIODevice *vdev = VIRTIO_DEVICE(vser); struct VirtIOSerialPort *port; VirtIOSerialPortClass *vsc; struct virtio_console_control cpkt, *gcpkt; @@ -291,8 +294,8 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) return; } - cpkt.event = lduw_p(&gcpkt->event); - cpkt.value = lduw_p(&gcpkt->value); + cpkt.event = virtio_lduw_p(vdev, &gcpkt->event); + cpkt.value = virtio_lduw_p(vdev, &gcpkt->value); trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value); @@ -312,10 +315,10 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) return; } - port = find_port_by_id(vser, ldl_p(&gcpkt->id)); + port = find_port_by_id(vser, virtio_ldl_p(vdev, &gcpkt->id)); if (!port) { error_report("virtio-serial-bus: Unexpected port id %u for device %s", - ldl_p(&gcpkt->id), vser->bus.qbus.name); + virtio_ldl_p(vdev, &gcpkt->id), vser->bus.qbus.name); return; } @@ -342,9 +345,9 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) } if (port->name) { - stl_p(&cpkt.id, port->id); - stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME); - stw_p(&cpkt.value, 1); + virtio_stl_p(vdev, &cpkt.id, port->id); + virtio_stw_p(vdev, &cpkt.event, VIRTIO_CONSOLE_PORT_NAME); + virtio_stw_p(vdev, &cpkt.value, 1); buffer_len = sizeof(cpkt) + strlen(port->name) + 1; buffer = g_malloc(buffer_len); @@ -510,6 +513,10 @@ static void vser_reset(VirtIODevice *vdev) vser = VIRTIO_SERIAL(vdev); guest_reset(vser); + + /* In case we have switched endianness */ + vser->config.max_nr_ports = + virtio_tswap32(vdev, vser->serial.max_virtserial_ports); } static void virtio_serial_save(QEMUFile *f, void *opaque) @@ -532,7 +539,7 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) qemu_put_be32s(f, &s->config.max_nr_ports); /* The ports map */ - max_nr_ports = tswap32(s->config.max_nr_ports); + max_nr_ports = virtio_tswap32(vdev, s->config.max_nr_ports); for (i = 0; i < (max_nr_ports + 31) / 32; i++) { qemu_put_be32s(f, &s->ports_map[i]); } @@ -688,6 +695,12 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, qemu_get_be16s(f, (uint16_t *) &tmp); qemu_get_be32s(f, &tmp); + /* Note: this is the only location where we use tswap32() instead of + * virtio_tswap32() because: + * - virtio_tswap32() only makes sense when the device is fully restored + * - the target endianness that was used to populate s->config is + * necessarly the default one + */ max_nr_ports = tswap32(s->config.max_nr_ports); for (i = 0; i < (max_nr_ports + 31) / 32; i++) { qemu_get_be32s(f, &ports_map); @@ -751,9 +764,10 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) /* This function is only used if a port id is not provided by the user */ static uint32_t find_free_port_id(VirtIOSerial *vser) { + VirtIODevice *vdev = VIRTIO_DEVICE(vser); unsigned int i, max_nr_ports; - max_nr_ports = tswap32(vser->config.max_nr_ports); + max_nr_ports = virtio_tswap32(vdev, vser->config.max_nr_ports); for (i = 0; i < (max_nr_ports + 31) / 32; i++) { uint32_t map, bit; @@ -806,6 +820,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev)); + VirtIODevice *vdev = VIRTIO_DEVICE(bus->vser); int max_nr_ports; bool plugging_port0; Error *err = NULL; @@ -841,7 +856,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) } } - max_nr_ports = tswap32(port->vser->config.max_nr_ports); + max_nr_ports = virtio_tswap32(vdev, port->vser->config.max_nr_ports); if (port->id >= max_nr_ports) { error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, " "max. allowed: %u", max_nr_ports - 1); @@ -863,7 +878,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) add_port(port->vser, port->id); /* Send an update to the guest about this new port added */ - virtio_notify_config(VIRTIO_DEVICE(port->vser)); + virtio_notify_config(vdev); } static void virtser_port_device_unrealize(DeviceState *dev, Error **errp) @@ -942,7 +957,8 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output); } - vser->config.max_nr_ports = tswap32(vser->serial.max_virtserial_ports); + vser->config.max_nr_ports = + virtio_tswap32(vdev, vser->serial.max_virtserial_ports); vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32) * sizeof(vser->ports_map[0])); /* -- cgit v1.2.3-55-g7522 From d64ccb91adda46197702ec3a8b6d9c85c03b3c80 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:49:49 +0200 Subject: virtio-9p: use virtio wrappers to access headers Note that st*_raw and ld*_raw are effectively replaced by st*_p and ld*_p. Signed-off-by: Greg Kurz Reviewed-by: Alexander Graf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 653762af1a..2572747629 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -19,6 +19,7 @@ #include "fsdev/qemu-fsdev.h" #include "virtio-9p-xattr.h" #include "virtio-9p-coth.h" +#include "hw/virtio/virtio-access.h" static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features) { @@ -34,7 +35,7 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) len = strlen(s->tag); cfg = g_malloc0(sizeof(struct virtio_9p_config) + len); - stw_p(&cfg->tag_len, len); + virtio_stw_p(vdev, &cfg->tag_len, len); /* We don't copy the terminating null to config space */ memcpy(cfg->tag, s->tag, len); memcpy(config, cfg, s->config_size); -- cgit v1.2.3-55-g7522 From 371df9f5e0f175a1d8f2e9f2e86cf65f952b1c56 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 24 Jun 2014 19:55:03 +0200 Subject: vhost-net: disable when cross-endian As of today, vhost assumes guest and host have the same endianness. This is definitely not compatible with modern PPC64 and ARM that can change endianness at runtime. Let's disable vhost-net and print an error message when we detect such a case: qemu-system-ppc64: vhost-net does not support cross-endian qemu-system-ppc64: unable to start vhost net: 38: falling back on userspace virtio This way users can continue to run VMs without changing their setup and have a chance to know that performance will be impacted. Suggested-by: Michael S. Tsirkin Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/vhost_net.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'hw') diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 7ac7c21bdb..f87c79824b 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -275,6 +275,19 @@ static void vhost_net_stop_one(struct vhost_net *net, vhost_dev_disable_notifiers(&net->dev, dev); } +static bool vhost_net_device_endian_ok(VirtIODevice *vdev) +{ +#ifdef TARGET_IS_BIENDIAN +#ifdef HOST_WORDS_BIGENDIAN + return virtio_is_big_endian(vdev); +#else + return !virtio_is_big_endian(vdev); +#endif +#else + return true; +#endif +} + int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, int total_queues) { @@ -283,6 +296,12 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); int r, i = 0; + if (!vhost_net_device_endian_ok(dev)) { + error_report("vhost-net does not support cross-endian"); + r = -ENOSYS; + goto err; + } + if (!k->set_guest_notifiers) { error_report("binding does not support guest notifiers"); r = -ENOSYS; -- cgit v1.2.3-55-g7522