diff options
122 files changed, 2628 insertions, 1133 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index ef2ec58a94..7df088259b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1005,6 +1005,14 @@ S: Supported F: hw/vfio/* F: include/hw/vfio/ +vfio-ccw +M: Cornelia Huck <cornelia.huck@de.ibm.com> +S: Supported +F: hw/vfio/ccw.c +F: hw/s390x/s390-ccw.c +F: include/hw/s390x/s390-ccw.h +T: git git://github.com/cohuck/qemu.git s390-next + vhost M: Michael S. Tsirkin <mst@redhat.com> S: Supported diff --git a/Makefile.target b/Makefile.target index 465a633367..ce8dfe44a8 100644 --- a/Makefile.target +++ b/Makefile.target @@ -146,7 +146,7 @@ obj-$(CONFIG_KVM) += kvm-all.o obj-y += memory.o cputlb.o obj-y += memory_mapping.o obj-y += dump.o -obj-y += migration/ram.o migration/savevm.o +obj-y += migration/ram.o LIBS := $(libs_softmmu) $(LIBS) # Hardware support diff --git a/arch_init.c b/arch_init.c index 0810116144..a0b8ed6167 100644 --- a/arch_init.c +++ b/arch_init.c @@ -27,7 +27,7 @@ #include "sysemu/sysemu.h" #include "sysemu/arch_init.h" #include "hw/pci/pci.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qmp-commands.h" @@ -85,130 +85,6 @@ int graphic_depth = 32; const uint32_t arch_type = QEMU_ARCH; -struct soundhw { - const char *name; - const char *descr; - int enabled; - int isa; - union { - int (*init_isa) (ISABus *bus); - int (*init_pci) (PCIBus *bus); - } init; -}; - -static struct soundhw soundhw[9]; -static int soundhw_count; - -void isa_register_soundhw(const char *name, const char *descr, - int (*init_isa)(ISABus *bus)) -{ - assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); - soundhw[soundhw_count].name = name; - soundhw[soundhw_count].descr = descr; - soundhw[soundhw_count].isa = 1; - soundhw[soundhw_count].init.init_isa = init_isa; - soundhw_count++; -} - -void pci_register_soundhw(const char *name, const char *descr, - int (*init_pci)(PCIBus *bus)) -{ - assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); - soundhw[soundhw_count].name = name; - soundhw[soundhw_count].descr = descr; - soundhw[soundhw_count].isa = 0; - soundhw[soundhw_count].init.init_pci = init_pci; - soundhw_count++; -} - -void select_soundhw(const char *optarg) -{ - struct soundhw *c; - - if (is_help_option(optarg)) { - show_valid_cards: - - if (soundhw_count) { - printf("Valid sound card names (comma separated):\n"); - for (c = soundhw; c->name; ++c) { - printf ("%-11s %s\n", c->name, c->descr); - } - printf("\n-soundhw all will enable all of the above\n"); - } else { - printf("Machine has no user-selectable audio hardware " - "(it may or may not have always-present audio hardware).\n"); - } - exit(!is_help_option(optarg)); - } - else { - size_t l; - const char *p; - char *e; - int bad_card = 0; - - if (!strcmp(optarg, "all")) { - for (c = soundhw; c->name; ++c) { - c->enabled = 1; - } - return; - } - - p = optarg; - while (*p) { - e = strchr(p, ','); - l = !e ? strlen(p) : (size_t) (e - p); - - for (c = soundhw; c->name; ++c) { - if (!strncmp(c->name, p, l) && !c->name[l]) { - c->enabled = 1; - break; - } - } - - if (!c->name) { - if (l > 80) { - error_report("Unknown sound card name (too big to show)"); - } - else { - error_report("Unknown sound card name `%.*s'", - (int) l, p); - } - bad_card = 1; - } - p += l + (e != NULL); - } - - if (bad_card) { - goto show_valid_cards; - } - } -} - -void audio_init(void) -{ - struct soundhw *c; - ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL); - PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL); - - for (c = soundhw; c->name; ++c) { - if (c->enabled) { - if (c->isa) { - if (!isa_bus) { - error_report("ISA bus not available for %s", c->name); - exit(1); - } - c->init.init_isa(isa_bus); - } else { - if (!pci_bus) { - error_report("PCI bus not available for %s", c->name); - exit(1); - } - c->init.init_pci(pci_bus); - } - } - } -} - int kvm_available(void) { #ifdef CONFIG_KVM diff --git a/block/qed.c b/block/qed.c index fd76817cbb..8d899fd479 100644 --- a/block/qed.c +++ b/block/qed.c @@ -19,7 +19,6 @@ #include "trace.h" #include "qed.h" #include "qapi/qmp/qerror.h" -#include "migration/migration.h" #include "sysemu/block-backend.h" static const AIOCBInfo qed_aiocb_info = { diff --git a/configure b/configure index 139638e922..1a5ee4b909 100755 --- a/configure +++ b/configure @@ -316,6 +316,7 @@ vte="" virglrenderer="" tpm="yes" libssh2="" +live_block_migration="yes" numa="" tcmalloc="no" jemalloc="no" @@ -1169,6 +1170,10 @@ for opt do ;; --enable-libssh2) libssh2="yes" ;; + --disable-live-block-migration) live_block_migration="no" + ;; + --enable-live-block-migration) live_block_migration="yes" + ;; --disable-numa) numa="no" ;; --enable-numa) numa="yes" @@ -1401,6 +1406,7 @@ disabled with --disable-FEATURE, default is enabled if available: libnfs nfs support smartcard smartcard support (libcacard) libusb libusb (for usb passthrough) + live-block-migration Block migration in the main migration stream usb-redir usb network redirection support lzo support of lzo compression library snappy support of snappy compression library @@ -5216,6 +5222,7 @@ echo "TPM support $tpm" echo "libssh2 support $libssh2" echo "TPM passthrough $tpm_passthrough" echo "QOM debugging $qom_cast_debug" +echo "Live block migration $live_block_migration" echo "lzo support $lzo" echo "snappy support $snappy" echo "bzip2 support $bzip2" @@ -5782,6 +5789,10 @@ if test "$libssh2" = "yes" ; then echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak fi +if test "$live_block_migration" = "yes" ; then + echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak +fi + # USB host support if test "$libusb" = "yes"; then echo "HOST_USB=libusb legacy" >> $config_host_mak diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index 9615a48f80..18aed56fc0 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -5,4 +5,5 @@ CONFIG_SCLPCONSOLE=y CONFIG_TERMINAL3270=y CONFIG_S390_FLIC=y CONFIG_S390_FLIC_KVM=$(CONFIG_KVM) +CONFIG_VFIO_CCW=$(CONFIG_LINUX) CONFIG_WDT_DIAG288=y diff --git a/exec.c b/exec.c index 96e3ac98e1..ff16f04f2b 100644 --- a/exec.c +++ b/exec.c @@ -24,6 +24,7 @@ #include "qemu/cutils.h" #include "cpu.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "tcg.h" #include "hw/qdev-core.h" #if !defined(CONFIG_USER_ONLY) @@ -3443,6 +3444,15 @@ size_t qemu_target_page_size(void) return TARGET_PAGE_SIZE; } +int qemu_target_page_bits(void) +{ + return TARGET_PAGE_BITS; +} + +int qemu_target_page_bits_min(void) +{ + return TARGET_PAGE_BITS_MIN; +} #endif /* diff --git a/hmp-commands.hx b/hmp-commands.hx index 0aca984261..baeac47a72 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1296,7 +1296,7 @@ ETEXI .name = "host_net_add", .args_type = "device:s,opts:s?", .params = "tap|user|socket|vde|netmap|bridge|vhost-user|dump [options]", - .help = "add host VLAN client", + .help = "add host VLAN client (deprecated, use netdev_add instead)", .cmd = hmp_host_net_add, .command_completion = host_net_add_completion, }, @@ -1304,14 +1304,14 @@ ETEXI STEXI @item host_net_add @findex host_net_add -Add host VLAN client. +Add host VLAN client. Deprecated, please use @code{netdev_add} instead. ETEXI { .name = "host_net_remove", .args_type = "vlan_id:i,device:s", .params = "vlan_id name", - .help = "remove host VLAN client", + .help = "remove host VLAN client (deprecated, use netdev_del instead)", .cmd = hmp_host_net_remove, .command_completion = host_net_remove_completion, }, @@ -1319,7 +1319,7 @@ ETEXI STEXI @item host_net_remove @findex host_net_remove -Remove host VLAN client. +Remove host VLAN client. Deprecated, please use @code{netdev_del} instead. ETEXI { diff --git a/hmp.c b/hmp.c index 3dceaf809b..20f5daba5e 100644 --- a/hmp.c +++ b/hmp.c @@ -29,6 +29,7 @@ #include "monitor/qdev.h" #include "qapi/opts-visitor.h" #include "qapi/qmp/qerror.h" +#include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" #include "qapi/util.h" #include "qapi-visit.h" @@ -326,6 +327,10 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: %" PRId64 "\n", MigrationParameter_lookup[MIGRATION_PARAMETER_X_CHECKPOINT_DELAY], params->x_checkpoint_delay); + assert(params->has_block_incremental); + monitor_printf(mon, "%s: %s\n", + MigrationParameter_lookup[MIGRATION_PARAMETER_BLOCK_INCREMENTAL], + params->block_incremental ? "on" : "off"); } qapi_free_MigrationParameters(params); @@ -1524,8 +1529,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) { const char *param = qdict_get_str(qdict, "parameter"); const char *valuestr = qdict_get_str(qdict, "value"); + Visitor *v = string_input_visitor_new(valuestr); uint64_t valuebw = 0; - long valueint = 0; + int64_t valueint = 0; + bool valuebool = false; Error *err = NULL; bool use_int_value = false; int i, ret; @@ -1580,12 +1587,19 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p.has_x_checkpoint_delay = true; use_int_value = true; break; + case MIGRATION_PARAMETER_BLOCK_INCREMENTAL: + p.has_block_incremental = true; + visit_type_bool(v, param, &valuebool, &err); + if (err) { + goto cleanup; + } + p.block_incremental = valuebool; + break; } if (use_int_value) { - if (qemu_strtol(valuestr, NULL, 10, &valueint) < 0) { - error_setg(&err, "Unable to parse '%s' as an int", - valuestr); + visit_type_int(v, param, &valueint, &err); + if (err) { goto cleanup; } /* Set all integers; only one has_FOO will be set, and @@ -1609,6 +1623,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) } cleanup: + visit_free(v); if (err) { error_report_err(err); } diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs index bb6f07a91e..63db383709 100644 --- a/hw/audio/Makefile.objs +++ b/hw/audio/Makefile.objs @@ -14,3 +14,5 @@ common-obj-$(CONFIG_PL041) += pl041.o lm4549.o common-obj-$(CONFIG_CS4231) += cs4231.o common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o + +common-obj-y += soundhw.o diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index c30657501c..959c786261 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "hw/pci/pci.h" #include "sysemu/dma.h" diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 09b8248cda..c6e0f10c16 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hw.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "hw/isa/isa.h" diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 3ecd0582bf..096e8e98d7 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "hw/isa/isa.h" #include "hw/qdev.h" diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index fe64c1ac37..dd7c23d185 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -28,7 +28,7 @@ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "hw/pci/pci.h" #include "sysemu/dma.h" diff --git a/hw/audio/gus.c b/hw/audio/gus.c index ec103a4db9..3e864cd36d 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hw.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "hw/isa/isa.h" #include "gusemu.h" diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 2c497eb174..06acc98f7b 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -22,7 +22,7 @@ #include "hw/pci/pci.h" #include "hw/pci/msi.h" #include "qemu/timer.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "intel-hda.h" #include "intel-hda-defs.h" #include "sysemu/dma.h" diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 9b99358d87..f643b122bb 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -26,7 +26,7 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/isa/isa.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "qemu/timer.h" #include "hw/timer/i8254.h" diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 6b4427f242..6ab2f6f89a 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/audio/audio.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "hw/isa/isa.h" #include "hw/qdev.h" diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c new file mode 100644 index 0000000000..e698909d34 --- /dev/null +++ b/hw/audio/soundhw.c @@ -0,0 +1,156 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/help_option.h" +#include "qemu/error-report.h" +#include "qom/object.h" +#include "hw/isa/isa.h" +#include "hw/pci/pci.h" +#include "hw/audio/soundhw.h" + +struct soundhw { + const char *name; + const char *descr; + int enabled; + int isa; + union { + int (*init_isa) (ISABus *bus); + int (*init_pci) (PCIBus *bus); + } init; +}; + +static struct soundhw soundhw[9]; +static int soundhw_count; + +void isa_register_soundhw(const char *name, const char *descr, + int (*init_isa)(ISABus *bus)) +{ + assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); + soundhw[soundhw_count].name = name; + soundhw[soundhw_count].descr = descr; + soundhw[soundhw_count].isa = 1; + soundhw[soundhw_count].init.init_isa = init_isa; + soundhw_count++; +} + +void pci_register_soundhw(const char *name, const char *descr, + int (*init_pci)(PCIBus *bus)) +{ + assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); + soundhw[soundhw_count].name = name; + soundhw[soundhw_count].descr = descr; + soundhw[soundhw_count].isa = 0; + soundhw[soundhw_count].init.init_pci = init_pci; + soundhw_count++; +} + +void select_soundhw(const char *optarg) +{ + struct soundhw *c; + + if (is_help_option(optarg)) { + show_valid_cards: + + if (soundhw_count) { + printf("Valid sound card names (comma separated):\n"); + for (c = soundhw; c->name; ++c) { + printf ("%-11s %s\n", c->name, c->descr); + } + printf("\n-soundhw all will enable all of the above\n"); + } else { + printf("Machine has no user-selectable audio hardware " + "(it may or may not have always-present audio hardware).\n"); + } + exit(!is_help_option(optarg)); + } + else { + size_t l; + const char *p; + char *e; + int bad_card = 0; + + if (!strcmp(optarg, "all")) { + for (c = soundhw; c->name; ++c) { + c->enabled = 1; + } + return; + } + + p = optarg; + while (*p) { + e = strchr(p, ','); + l = !e ? strlen(p) : (size_t) (e - p); + + for (c = soundhw; c->name; ++c) { + if (!strncmp(c->name, p, l) && !c->name[l]) { + c->enabled = 1; + break; + } + } + + if (!c->name) { + if (l > 80) { + error_report("Unknown sound card name (too big to show)"); + } + else { + error_report("Unknown sound card name `%.*s'", + (int) l, p); + } + bad_card = 1; + } + p += l + (e != NULL); + } + + if (bad_card) { + goto show_valid_cards; + } + } +} + +void soundhw_init(void) +{ + struct soundhw *c; + ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL); + PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL); + + for (c = soundhw; c->name; ++c) { + if (c->enabled) { + if (c->isa) { + if (!isa_bus) { + error_report("ISA bus not available for %s", c->name); + exit(1); + } + c->init.init_isa(isa_bus); + } else { + if (!pci_bus) { + error_report("PCI bus not available for %s", c->name); + exit(1); + } + c->init.init_pci(pci_bus); + } + } + } +} + diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index f243203844..1523ef39e1 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -46,7 +46,6 @@ #include "hw/ide/ahci.h" #include "hw/usb.h" #include "qemu/error-report.h" -#include "migration/migration.h" #include "sysemu/numa.h" /* ICH9 AHCI has 6 ports */ diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 28c5be1506..81405640f0 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -2454,14 +2454,20 @@ e1000e_set_ics(E1000ECore *core, int index, uint32_t val) static void e1000e_set_icr(E1000ECore *core, int index, uint32_t val) { + uint32_t icr = 0; if ((core->mac[ICR] & E1000_ICR_ASSERTED) && (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { trace_e1000e_irq_icr_process_iame(); e1000e_clear_ims_bits(core, core->mac[IAM]); } - trace_e1000e_irq_icr_write(val, core->mac[ICR], core->mac[ICR] & ~val); - core->mac[ICR] &= ~val; + icr = core->mac[ICR] & ~val; + /* Windows driver expects that the "receive overrun" bit and other + * ones to be cleared when the "Other" bit (#24) is cleared. + */ + icr = (val & E1000_ICR_OTHER) ? (icr & ~E1000_ICR_OTHER_CAUSES) : icr; + trace_e1000e_irq_icr_write(val, core->mac[ICR], icr); + core->mac[ICR] = icr; e1000e_update_interrupt_state(core); } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 7d091c9259..98bd683f31 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1522,9 +1522,12 @@ static void virtio_net_del_queue(VirtIONet *n, int index) if (q->tx_timer) { timer_del(q->tx_timer); timer_free(q->tx_timer); + q->tx_timer = NULL; } else { qemu_bh_delete(q->tx_bh); + q->tx_bh = NULL; } + q->tx_waiting = 0; virtio_del_queue(vdev, index * 2 + 1); } diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 961230c569..d16646c95d 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -36,6 +36,7 @@ #include "hw/pci/pci_host.h" #include "hw/ppc/ppc.h" #include "hw/boards.h" +#include "hw/audio/soundhw.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "hw/ide.h" @@ -782,7 +783,7 @@ static void ibm_40p_init(MachineState *machine) &cmos_checksum); /* initialize audio subsystem */ - audio_init(); + soundhw_init(); /* add some more devices */ if (defaults_enabled()) { diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index a7a5b412e4..6e6eee4e90 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -98,9 +98,13 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp) EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev); CcwDevice *cdev = CCW_DEVICE(ds); CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev); - SubchDev *sch = css_create_virtual_sch(cdev->devno, errp); + DeviceState *parent = DEVICE(cdev); + BusState *qbus = qdev_get_parent_bus(parent); + VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); + SubchDev *sch; Error *err = NULL; + sch = css_create_sch(cdev->devno, true, cbus->squash_mcss, errp); if (!sch) { return; } diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 36bd4b1645..a8e5575a8a 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -14,3 +14,4 @@ obj-y += ccw-device.o obj-y += s390-pci-bus.o s390-pci-inst.o obj-y += s390-skeys.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o +obj-y += s390-ccw.o diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index b54ac01d37..823747fcd7 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -17,6 +17,7 @@ #include "hw/s390x/css.h" #include "ccw-device.h" #include "hw/s390x/css-bridge.h" +#include "cpu.h" /* * Invoke device-specific unplug handler, disable the subchannel @@ -103,6 +104,7 @@ VirtualCssBus *virtual_css_bus_init(void) /* Create bus on bridge device */ bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); cbus = VIRTUAL_CSS_BUS(bus); + cbus->squash_mcss = s390_get_squash_mcss(); /* Enable hotplugging */ qbus_set_hotplug_handler(bus, dev, &error_abort); diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 15c4f4b249..1e2f26b65a 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -13,6 +13,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/qdev.h" +#include "qemu/error-report.h" #include "qemu/bitops.h" #include "exec/address-spaces.h" #include "cpu.h" @@ -258,7 +259,7 @@ uint16_t css_build_subchannel_id(SubchDev *sch) return css_do_build_subchannel_id(sch->cssid, sch->ssid); } -static void css_inject_io_interrupt(SubchDev *sch) +void css_inject_io_interrupt(SubchDev *sch) { uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; @@ -523,7 +524,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, return ret; } -static void sch_handle_start_func(SubchDev *sch, ORB *orb) +static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb) { PMCW *p = &sch->curr_status.pmcw; @@ -625,13 +626,58 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) } +static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb) +{ + + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + int ret; + + if (!(s->ctrl & SCSW_ACTL_SUSP)) { + assert(orb != NULL); + p->intparm = orb->intparm; + } + + /* + * Only support prefetch enable mode. + * Only support 64bit addressing idal. + */ + if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) || + !(orb->ctrl0 & ORB_CTRL0_MASK_C64)) { + return -EINVAL; + } + + ret = s390_ccw_cmd_request(orb, s, sch->driver_data); + switch (ret) { + /* Currently we don't update control block and just return the cc code. */ + case 0: + break; + case -EBUSY: + break; + case -ENODEV: + break; + case -EACCES: + /* Let's reflect an inaccessible host device by cc 3. */ + ret = -ENODEV; + break; + default: + /* + * All other return codes will trigger a program check, + * or set cc to 1. + */ + break; + }; + + return ret; +} + /* * On real machines, this would run asynchronously to the main vcpus. * We might want to make some parts of the ssch handling (interpreting * read/writes) asynchronous later on if we start supporting more than * our current very simple devices. */ -static void do_subchannel_work(SubchDev *sch, ORB *orb) +int do_subchannel_work_virtual(SubchDev *sch, ORB *orb) { SCSW *s = &sch->curr_status.scsw; @@ -642,12 +688,45 @@ static void do_subchannel_work(SubchDev *sch, ORB *orb) sch_handle_halt_func(sch); } else if (s->ctrl & SCSW_FCTL_START_FUNC) { /* Triggered by both ssch and rsch. */ - sch_handle_start_func(sch, orb); + sch_handle_start_func_virtual(sch, orb); } else { /* Cannot happen. */ - return; + return 0; } css_inject_io_interrupt(sch); + return 0; +} + +int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb) +{ + int ret; + SCSW *s = &sch->curr_status.scsw; + + if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) { + /* TODO: Clear handling */ + sch_handle_clear_func(sch); + ret = 0; + } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { + /* TODO: Halt handling */ + sch_handle_halt_func(sch); + ret = 0; + } else if (s->ctrl & SCSW_FCTL_START_FUNC) { + ret = sch_handle_start_func_passthrough(sch, orb); + } else { + /* Cannot happen. */ + return -ENODEV; + } + + return ret; +} + +static int do_subchannel_work(SubchDev *sch, ORB *orb) +{ + if (sch->do_subchannel_work) { + return sch->do_subchannel_work(sch, orb); + } else { + return -EINVAL; + } } static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) @@ -670,7 +749,7 @@ static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) dest->chars = cpu_to_be32(src->chars); } -static void copy_scsw_to_guest(SCSW *dest, const SCSW *src) +void copy_scsw_to_guest(SCSW *dest, const SCSW *src) { dest->flags = cpu_to_be16(src->flags); dest->ctrl = cpu_to_be16(src->ctrl); @@ -966,8 +1045,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb) s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); s->flags &= ~SCSW_FLAGS_MASK_PNO; - do_subchannel_work(sch, orb); - ret = 0; + ret = do_subchannel_work(sch, orb); out: return ret; @@ -1326,7 +1404,8 @@ unsigned int css_find_free_chpid(uint8_t cssid) return MAX_CHPID + 1; } -static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) +static int css_add_chpid(uint8_t cssid, uint8_t chpid, uint8_t type, + bool is_virt) { CssImage *css; @@ -1340,7 +1419,7 @@ static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) } css->chpids[chpid].in_use = 1; css->chpids[chpid].type = type; - css->chpids[chpid].is_virtual = 1; + css->chpids[chpid].is_virtual = is_virt; css_generate_chp_crws(cssid, chpid); @@ -1364,7 +1443,7 @@ void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type) p->pam = 0x80; p->chpid[0] = chpid; if (!css->chpids[chpid].in_use) { - css_add_virtual_chpid(sch->cssid, chpid, type); + css_add_chpid(sch->cssid, chpid, type, true); } memset(s, 0, sizeof(SCSW)); @@ -1946,28 +2025,59 @@ PropertyInfo css_devid_ro_propinfo = { .get = get_css_devid, }; -SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp) +SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, + Error **errp) { uint16_t schid = 0; SubchDev *sch; if (bus_id.valid) { - /* Enforce use of virtual cssid. */ - if (bus_id.cssid != VIRTUAL_CSSID) { - error_setg(errp, "cssid %hhx not valid for virtual devices", - bus_id.cssid); + if (is_virtual != (bus_id.cssid == VIRTUAL_CSSID)) { + error_setg(errp, "cssid %hhx not valid for %s devices", + bus_id.cssid, + (is_virtual ? "virtual" : "non-virtual")); return NULL; } + } + + if (bus_id.valid) { + if (squash_mcss) { + bus_id.cssid = channel_subsys.default_cssid; + } else if (!channel_subsys.css[bus_id.cssid]) { + css_create_css_image(bus_id.cssid, false); + } + if (!css_find_free_subch_for_devno(bus_id.cssid, bus_id.ssid, bus_id.devid, &schid, errp)) { return NULL; } - } else { - bus_id.cssid = VIRTUAL_CSSID; + } else if (squash_mcss || is_virtual) { + bus_id.cssid = channel_subsys.default_cssid; + if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, &bus_id.devid, &schid, errp)) { return NULL; } + } else { + for (bus_id.cssid = 0; bus_id.cssid < MAX_CSSID; ++bus_id.cssid) { + if (bus_id.cssid == VIRTUAL_CSSID) { + continue; + } + + if (!channel_subsys.css[bus_id.cssid]) { + css_create_css_image(bus_id.cssid, false); + } + + if (css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, + &bus_id.devid, &schid, + NULL)) { + break; + } + if (bus_id.cssid == MAX_CSSID) { + error_setg(errp, "Virtual channel subsystem is full!"); + return NULL; + } + } } sch = g_malloc0(sizeof(*sch)); @@ -1978,3 +2088,147 @@ SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp) css_subch_assign(sch->cssid, sch->ssid, schid, sch->devno, sch); return sch; } + +static int css_sch_get_chpids(SubchDev *sch, CssDevId *dev_id) +{ + char *fid_path; + FILE *fd; + uint32_t chpid[8]; + int i; + PMCW *p = &sch->curr_status.pmcw; + + fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/chpids", + dev_id->cssid, dev_id->ssid, dev_id->devid); + fd = fopen(fid_path, "r"); + if (fd == NULL) { + error_report("%s: open %s failed", __func__, fid_path); + g_free(fid_path); + return -EINVAL; + } + + if (fscanf(fd, "%x %x %x %x %x %x %x %x", + &chpid[0], &chpid[1], &chpid[2], &chpid[3], + &chpid[4], &chpid[5], &chpid[6], &chpid[7]) != 8) { + fclose(fd); + g_free(fid_path); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(p->chpid); i++) { + p->chpid[i] = chpid[i]; + } + + fclose(fd); + g_free(fid_path); + + return 0; +} + +static int css_sch_get_path_masks(SubchDev *sch, CssDevId *dev_id) +{ + char *fid_path; + FILE *fd; + uint32_t pim, pam, pom; + PMCW *p = &sch->curr_status.pmcw; + + fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/pimpampom", + dev_id->cssid, dev_id->ssid, dev_id->devid); + fd = fopen(fid_path, "r"); + if (fd == NULL) { + error_report("%s: open %s failed", __func__, fid_path); + g_free(fid_path); + return -EINVAL; + } + + if (fscanf(fd, "%x %x %x", &pim, &pam, &pom) != 3) { + fclose(fd); + g_free(fid_path); + return -EINVAL; + } + + p->pim = pim; + p->pam = pam; + p->pom = pom; + fclose(fd); + g_free(fid_path); + + return 0; +} + +static int css_sch_get_chpid_type(uint8_t chpid, uint32_t *type, + CssDevId *dev_id) +{ + char *fid_path; + FILE *fd; + + fid_path = g_strdup_printf("/sys/devices/css%x/chp0.%02x/type", + dev_id->cssid, chpid); + fd = fopen(fid_path, "r"); + if (fd == NULL) { + error_report("%s: open %s failed", __func__, fid_path); + g_free(fid_path); + return -EINVAL; + } + + if (fscanf(fd, "%x", type) != 1) { + fclose(fd); + g_free(fid_path); + return -EINVAL; + } + + fclose(fd); + g_free(fid_path); + + return 0; +} + +/* + * We currently retrieve the real device information from sysfs to build the + * guest subchannel information block without considering the migration feature. + * We need to revisit this problem when we want to add migration support. + */ +int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id) +{ + CssImage *css = channel_subsys.css[sch->cssid]; + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + uint32_t type; + int i, ret; + + assert(css != NULL); + memset(p, 0, sizeof(PMCW)); + p->flags |= PMCW_FLAGS_MASK_DNV; + /* We are dealing with I/O subchannels only. */ + p->devno = sch->devno; + + /* Grab path mask from sysfs. */ + ret = css_sch_get_path_masks(sch, dev_id); + if (ret) { + return ret; + } + + /* Grab chpids from sysfs. */ + ret = css_sch_get_chpids(sch, dev_id); + if (ret) { + return ret; + } + + /* Build chpid type. */ + for (i = 0; i < ARRAY_SIZE(p->chpid); i++) { + if (p->chpid[i] && !css->chpids[p->chpid[i]].in_use) { + ret = css_sch_get_chpid_type(p->chpid[i], &type, dev_id); + if (ret) { + return ret; + } + css_add_chpid(sch->cssid, p->chpid[i], type, false); + } + } + + memset(s, 0, sizeof(SCSW)); + sch->curr_status.mba = 0; + for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) { + sch->curr_status.mda[i] = 0; + } + + return 0; +} diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c new file mode 100644 index 0000000000..8614dda6f8 --- /dev/null +++ b/hw/s390x/s390-ccw.c @@ -0,0 +1,153 @@ +/* + * s390 CCW Assignment Support + * + * Copyright 2017 IBM Corp + * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> + * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> + * Pierre Morel <pmorel@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 + * or (at your option) any later version. See the COPYING file in the + * top-level directory. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "libgen.h" +#include "hw/s390x/css.h" +#include "hw/s390x/css-bridge.h" +#include "hw/s390x/s390-ccw.h" + +int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data) +{ + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(data); + + if (cdc->handle_request) { + return cdc->handle_request(orb, scsw, data); + } else { + return -ENOSYS; + } +} + +static void s390_ccw_get_dev_info(S390CCWDevice *cdev, + char *sysfsdev, + Error **errp) +{ + unsigned int cssid, ssid, devid; + char dev_path[PATH_MAX] = {0}, *tmp; + + if (!sysfsdev) { + error_setg(errp, "No host device provided"); + error_append_hint(errp, + "Use -device vfio-ccw,sysfsdev=PATH_TO_DEVICE\n"); + return; + } + + if (!realpath(sysfsdev, dev_path)) { + error_setg_errno(errp, errno, "Host device '%s' not found", sysfsdev); + return; + } + + cdev->mdevid = g_strdup(basename(dev_path)); + + tmp = basename(dirname(dev_path)); + if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) { + error_setg_errno(errp, errno, "Failed to read %s", tmp); + return; + } + + cdev->hostid.cssid = cssid; + cdev->hostid.ssid = ssid; + cdev->hostid.devid = devid; + cdev->hostid.valid = true; +} + +static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp) +{ + CcwDevice *ccw_dev = CCW_DEVICE(cdev); + CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev); + DeviceState *parent = DEVICE(ccw_dev); + BusState *qbus = qdev_get_parent_bus(parent); + VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); + SubchDev *sch; + int ret; + Error *err = NULL; + + s390_ccw_get_dev_info(cdev, sysfsdev, &err); + if (err) { + goto out_err_propagate; + } + + sch = css_create_sch(ccw_dev->devno, false, cbus->squash_mcss, &err); + if (!sch) { + goto out_mdevid_free; + } + sch->driver_data = cdev; + sch->do_subchannel_work = do_subchannel_work_passthrough; + + ccw_dev->sch = sch; + ret = css_sch_build_schib(sch, &cdev->hostid); + if (ret) { + error_setg_errno(&err, -ret, "%s: Failed to build initial schib", + __func__); + goto out_err; + } + + ck->realize(ccw_dev, &err); + if (err) { + goto out_err; + } + + css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, + parent->hotplugged, 1); + return; + +out_err: + css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); + ccw_dev->sch = NULL; + g_free(sch); +out_mdevid_free: + g_free(cdev->mdevid); +out_err_propagate: + error_propagate(errp, err); +} + +static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp) +{ + CcwDevice *ccw_dev = CCW_DEVICE(cdev); + SubchDev *sch = ccw_dev->sch; + + if (sch) { + css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); + g_free(sch); + ccw_dev->sch = NULL; + } + + g_free(cdev->mdevid); +} + +static void s390_ccw_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); + + dc->bus_type = TYPE_VIRTUAL_CSS_BUS; + cdc->realize = s390_ccw_realize; + cdc->unrealize = s390_ccw_unrealize; +} + +static const TypeInfo s390_ccw_info = { + .name = TYPE_S390_CCW, + .parent = TYPE_CCW_DEVICE, + .instance_size = sizeof(S390CCWDevice), + .class_size = sizeof(S390CCWDeviceClass), + .class_init = s390_ccw_class_init, + .abstract = true, +}; + +static void register_s390_ccw_type(void) +{ + type_register_static(&s390_ccw_info); +} + +type_init(register_s390_ccw_type) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index fdd4384ff0..c9021f2fa9 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -136,10 +136,15 @@ static void ccw_init(MachineState *machine) kvm_s390_enable_css_support(s390_cpu_addr2state(0)); } /* - * Create virtual css and set it as default so that non mcss-e - * enabled guests only see virtio devices. + * Non mcss-e enabled guests only see the devices from the default + * css, which is determined by the value of the squash_mcss property. + * Note: we must not squash non virtual devices to css 0xFE. */ - ret = css_create_css_image(VIRTUAL_CSSID, true); + if (css_bus->squash_mcss) { + ret = css_create_css_image(0, true); + } else { + ret = css_create_css_image(VIRTUAL_CSSID, true); + } assert(ret == 0); /* Create VirtIO network adapters */ @@ -303,6 +308,20 @@ static void machine_set_loadparm(Object *obj, const char *val, Error **errp) ms->loadparm[i] = ' '; /* pad right with spaces */ } } +static inline bool machine_get_squash_mcss(Object *obj, Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + return ms->s390_squash_mcss; +} + +static inline void machine_set_squash_mcss(Object *obj, bool value, + Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + ms->s390_squash_mcss = value; +} static inline void s390_machine_initfn(Object *obj) { @@ -328,6 +347,13 @@ static inline void s390_machine_initfn(Object *obj) " to upper case) to pass to machine loader, boot manager," " and guest kernel", NULL); + object_property_add_bool(obj, "s390-squash-mcss", + machine_get_squash_mcss, + machine_set_squash_mcss, NULL); + object_property_set_description(obj, "s390-squash-mcss", + "enable/disable squashing subchannels into the default css", + NULL); + object_property_set_bool(obj, false, "s390-squash-mcss", NULL); } static const TypeInfo ccw_machine_info = { diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e7167e3d05..e6a6f74be3 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -680,9 +680,13 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); CcwDevice *ccw_dev = CCW_DEVICE(dev); CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev); - SubchDev *sch = css_create_virtual_sch(ccw_dev->devno, errp); + DeviceState *parent = DEVICE(ccw_dev); + BusState *qbus = qdev_get_parent_bus(parent); + VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); + SubchDev *sch; Error *err = NULL; + sch = css_create_sch(ccw_dev->devno, true, cbus->squash_mcss, errp); if (!sch) { return; } @@ -697,6 +701,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) sch->disable_cb = virtio_sch_disable_cb; sch->id.reserved = 0xff; sch->id.cu_type = VIRTIO_CCW_CU_TYPE; + sch->do_subchannel_work = do_subchannel_work_virtual; ccw_dev->sch = sch; dev->indicators = NULL; dev->revision = -1; diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs index 05e7fbb93f..c3ab9097f1 100644 --- a/hw/vfio/Makefile.objs +++ b/hw/vfio/Makefile.objs @@ -1,6 +1,7 @@ ifeq ($(CONFIG_LINUX), y) obj-$(CONFIG_SOFTMMU) += common.o obj-$(CONFIG_PCI) += pci.o pci-quirks.o +obj-$(CONFIG_VFIO_CCW) += ccw.o obj-$(CONFIG_SOFTMMU) += platform.o obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o obj-$(CONFIG_VFIO_AMD_XGBE) += amd-xgbe.o diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c new file mode 100644 index 0000000000..12d0262336 --- /dev/null +++ b/hw/vfio/ccw.c @@ -0,0 +1,434 @@ +/* + * vfio based subchannel assignment support + * + * Copyright 2017 IBM Corp. + * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> + * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> + * Pierre Morel <pmorel@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or(at + * your option) any version. See the COPYING file in the top-level + * directory. + */ + +#include <linux/vfio.h> +#include <linux/vfio_ccw.h> +#include <sys/ioctl.h> + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "hw/vfio/vfio.h" +#include "hw/vfio/vfio-common.h" +#include "hw/s390x/s390-ccw.h" +#include "hw/s390x/ccw-device.h" +#include "qemu/error-report.h" + +#define TYPE_VFIO_CCW "vfio-ccw" +typedef struct VFIOCCWDevice { + S390CCWDevice cdev; + VFIODevice vdev; + uint64_t io_region_size; + uint64_t io_region_offset; + struct ccw_io_region *io_region; + EventNotifier io_notifier; +} VFIOCCWDevice; + +static void vfio_ccw_compute_needs_reset(VFIODevice *vdev) +{ + vdev->needs_reset = false; +} + +/* + * We don't need vfio_hot_reset_multi and vfio_eoi operations for + * vfio_ccw device now. + */ +struct VFIODeviceOps vfio_ccw_ops = { + .vfio_compute_needs_reset = vfio_ccw_compute_needs_reset, +}; + +static int vfio_ccw_handle_request(ORB *orb, SCSW *scsw, void *data) +{ + S390CCWDevice *cdev = data; + VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); + struct ccw_io_region *region = vcdev->io_region; + int ret; + + QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB)); + QEMU_BUILD_BUG_ON(sizeof(region->scsw_area) != sizeof(SCSW)); + QEMU_BUILD_BUG_ON(sizeof(region->irb_area) != sizeof(IRB)); + + memset(region, 0, sizeof(*region)); + + memcpy(region->orb_area, orb, sizeof(ORB)); + memcpy(region->scsw_area, scsw, sizeof(SCSW)); + +again: + ret = pwrite(vcdev->vdev.fd, region, + vcdev->io_region_size, vcdev->io_region_offset); + if (ret != vcdev->io_region_size) { + if (errno == EAGAIN) { + goto again; + } + error_report("vfio-ccw: wirte I/O region failed with errno=%d", errno); + return -errno; + } + + return region->ret_code; +} + +static void vfio_ccw_reset(DeviceState *dev) +{ + CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev); + S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev); + VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); + + ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET); +} + +static void vfio_ccw_io_notifier_handler(void *opaque) +{ + VFIOCCWDevice *vcdev = opaque; + struct ccw_io_region *region = vcdev->io_region; + S390CCWDevice *cdev = S390_CCW_DEVICE(vcdev); + CcwDevice *ccw_dev = CCW_DEVICE(cdev); + SubchDev *sch = ccw_dev->sch; + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + IRB irb; + int size; + + if (!event_notifier_test_and_clear(&vcdev->io_notifier)) { + return; + } + + size = pread(vcdev->vdev.fd, region, vcdev->io_region_size, + vcdev->io_region_offset); + if (size == -1) { + switch (errno) { + case ENODEV: + /* Generate a deferred cc 3 condition. */ + s->flags |= SCSW_FLAGS_MASK_CC; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND); + goto read_err; + case EFAULT: + /* Memory problem, generate channel data check. */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->cstat = SCSW_CSTAT_DATA_CHECK; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + goto read_err; + default: + /* Error, generate channel program check. */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->cstat = SCSW_CSTAT_PROG_CHECK; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + goto read_err; + } + } else if (size != vcdev->io_region_size) { + /* Information transfer error, generate channel-control check. */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->cstat = SCSW_CSTAT_CHN_CTRL_CHK; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + goto read_err; + } + + memcpy(&irb, region->irb_area, sizeof(IRB)); + + /* Update control block via irb. */ + copy_scsw_to_guest(s, &irb.scsw); + + /* If a uint check is pending, copy sense data. */ + if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) && + (p->chars & PMCW_CHARS_MASK_CSENSE)) { + memcpy(sch->sense_data, irb.ecw, sizeof(irb.ecw)); + } + +read_err: + css_inject_io_interrupt(sch); +} + +static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp) +{ + VFIODevice *vdev = &vcdev->vdev; + struct vfio_irq_info *irq_info; + struct vfio_irq_set *irq_set; + size_t argsz; + int32_t *pfd; + + if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) { + error_setg(errp, "vfio: unexpected number of io irqs %u", + vdev->num_irqs); + return; + } + + argsz = sizeof(*irq_set); + irq_info = g_malloc0(argsz); + irq_info->index = VFIO_CCW_IO_IRQ_INDEX; + irq_info->argsz = argsz; + if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, + irq_info) < 0 || irq_info->count < 1) { + error_setg_errno(errp, errno, "vfio: Error getting irq info"); + goto out_free_info; + } + + if (event_notifier_init(&vcdev->io_notifier, 0)) { + error_setg_errno(errp, errno, + "vfio: Unable to init event notifier for IO"); + goto out_free_info; + } + + argsz = sizeof(*irq_set) + sizeof(*pfd); + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_CCW_IO_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *) &irq_set->data; + + *pfd = event_notifier_get_fd(&vcdev->io_notifier); + qemu_set_fd_handler(*pfd, vfio_ccw_io_notifier_handler, NULL, vcdev); + if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + error_setg(errp, "vfio: Failed to set up io notification"); + qemu_set_fd_handler(*pfd, NULL, NULL, vcdev); + event_notifier_cleanup(&vcdev->io_notifier); + } + + g_free(irq_set); + +out_free_info: + g_free(irq_info); +} + +static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice *vcdev) +{ + struct vfio_irq_set *irq_set; + size_t argsz; + int32_t *pfd; + + argsz = sizeof(*irq_set) + sizeof(*pfd); + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_CCW_IO_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *) &irq_set->data; + *pfd = -1; + + if (ioctl(vcdev->vdev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + error_report("vfio: Failed to de-assign device io fd: %m"); + } + + qemu_set_fd_handler(event_notifier_get_fd(&vcdev->io_notifier), + NULL, NULL, vcdev); + event_notifier_cleanup(&vcdev->io_notifier); + + g_free(irq_set); +} + +static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) +{ + VFIODevice *vdev = &vcdev->vdev; + struct vfio_region_info *info; + int ret; + + /* Sanity check device */ + if (!(vdev->flags & VFIO_DEVICE_FLAGS_CCW)) { + error_setg(errp, "vfio: Um, this isn't a vfio-ccw device"); + return; + } + + if (vdev->num_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) { + error_setg(errp, "vfio: Unexpected number of the I/O region %u", + vdev->num_regions); + return; + } + + ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info); + if (ret) { + error_setg_errno(errp, -ret, "vfio: Error getting config info"); + return; + } + + vcdev->io_region_size = info->size; + if (sizeof(*vcdev->io_region) != vcdev->io_region_size) { + error_setg(errp, "vfio: Unexpected size of the I/O region"); + g_free(info); + return; + } + + vcdev->io_region_offset = info->offset; + vcdev->io_region = g_malloc0(info->size); + + g_free(info); +} + +static void vfio_ccw_put_region(VFIOCCWDevice *vcdev) +{ + g_free(vcdev->io_region); +} + +static void vfio_put_device(VFIOCCWDevice *vcdev) +{ + g_free(vcdev->vdev.name); + vfio_put_base_device(&vcdev->vdev); +} + +static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp) +{ + char *tmp, group_path[PATH_MAX]; + ssize_t len; + int groupid; + + tmp = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/%s/iommu_group", + cdev->hostid.cssid, cdev->hostid.ssid, + cdev->hostid.devid, cdev->mdevid); + len = readlink(tmp, group_path, sizeof(group_path)); + g_free(tmp); + + if (len <= 0 || len >= sizeof(group_path)) { + error_setg(errp, "vfio: no iommu_group found"); + return NULL; + } + + group_path[len] = 0; + + if (sscanf(basename(group_path), "%d", &groupid) != 1) { + error_setg(errp, "vfio: failed to read %s", group_path); + return NULL; + } + + return vfio_get_group(groupid, &address_space_memory, errp); +} + +static void vfio_ccw_realize(DeviceState *dev, Error **errp) +{ + VFIODevice *vbasedev; + VFIOGroup *group; + CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev); + S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev); + VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); + Error *err = NULL; + + /* Call the class init function for subchannel. */ + if (cdc->realize) { + cdc->realize(cdev, vcdev->vdev.sysfsdev, &err); + if (err) { + goto out_err_propagate; + } + } + + group = vfio_ccw_get_group(cdev, &err); + if (!group) { + goto out_group_err; + } + + vcdev->vdev.ops = &vfio_ccw_ops; + vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW; + vcdev->vdev.name = g_strdup_printf("%x.%x.%04x", cdev->hostid.cssid, + cdev->hostid.ssid, cdev->hostid.devid); + QLIST_FOREACH(vbasedev, &group->device_list, next) { + if (strcmp(vbasedev->name, vcdev->vdev.name) == 0) { + error_setg(&err, "vfio: subchannel %s has already been attached", + vcdev->vdev.name); + goto out_device_err; + } + } + + if (vfio_get_device(group, cdev->mdevid, &vcdev->vdev, &err)) { + goto out_device_err; + } + + vfio_ccw_get_region(vcdev, &err); + if (err) { + goto out_region_err; + } + + vfio_ccw_register_io_notifier(vcdev, &err); + if (err) { + goto out_notifier_err; + } + + return; + +out_notifier_err: + vfio_ccw_put_region(vcdev); +out_region_err: + vfio_put_device(vcdev); +out_device_err: + vfio_put_group(group); +out_group_err: + if (cdc->unrealize) { + cdc->unrealize(cdev, NULL); + } +out_err_propagate: + error_propagate(errp, err); +} + +static void vfio_ccw_unrealize(DeviceState *dev, Error **errp) +{ + CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev); + S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev); + VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); + VFIOGroup *group = vcdev->vdev.group; + + vfio_ccw_unregister_io_notifier(vcdev); + vfio_ccw_put_region(vcdev); + vfio_put_device(vcdev); + vfio_put_group(group); + + if (cdc->unrealize) { + cdc->unrealize(cdev, errp); + } +} + +static Property vfio_ccw_properties[] = { + DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vfio_ccw_vmstate = { + .name = TYPE_VFIO_CCW, + .unmigratable = 1, +}; + +static void vfio_ccw_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); + + dc->props = vfio_ccw_properties; + dc->vmsd = &vfio_ccw_vmstate; + dc->desc = "VFIO-based subchannel assignment"; + dc->realize = vfio_ccw_realize; + dc->unrealize = vfio_ccw_unrealize; + dc->reset = vfio_ccw_reset; + + cdc->handle_request = vfio_ccw_handle_request; +} + +static const TypeInfo vfio_ccw_info = { + .name = TYPE_VFIO_CCW, + .parent = TYPE_S390_CCW, + .instance_size = sizeof(VFIOCCWDevice), + .class_init = vfio_ccw_class_init, +}; + +static void register_vfio_ccw_type(void) +{ + type_register_static(&vfio_ccw_info); +} + +type_init(register_vfio_ccw_type) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 32a95a8c69..b87a176770 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -17,7 +17,6 @@ #include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/sockets.h" -#include "migration/migration.h" #include <sys/ioctl.h> #include <sys/socket.h> diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index b4815629e1..49e0022533 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -17,7 +17,6 @@ #include "qapi/error.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" -#include "migration/migration.h" #include "qemu/error-report.h" #include "hw/virtio/vhost-vsock.h" #include "qemu/iov.h" diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 890b4d7eb7..f99d99fd78 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -21,7 +21,6 @@ #include "hw/virtio/virtio.h" #include "qemu/atomic.h" #include "hw/virtio/virtio-bus.h" -#include "migration/migration.h" #include "hw/virtio/virtio-access.h" #include "sysemu/dma.h" diff --git a/include/exec/target_page.h b/include/exec/target_page.h new file mode 100644 index 0000000000..96726c36a4 --- /dev/null +++ b/include/exec/target_page.h @@ -0,0 +1,21 @@ +/* + * Target page sizes and friends for non target files + * + * Copyright (c) 2017 Red Hat Inc + * + * Authors: + * David Alan Gilbert <dgilbert@redhat.com> + * Juan Quintela <quintela@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef EXEC_TARGET_PAGE_H +#define EXEC_TARGET_PAGE_H + +size_t qemu_target_page_size(void); +int qemu_target_page_bits(void); +int qemu_target_page_bits_min(void); + +#endif diff --git a/include/hw/audio/audio.h b/include/hw/audio/soundhw.h index 55d40f71bf..119f7d78d5 100644 --- a/include/hw/audio/audio.h +++ b/include/hw/audio/soundhw.h @@ -7,4 +7,7 @@ void isa_register_soundhw(const char *name, const char *descr, void pci_register_soundhw(const char *name, const char *descr, int (*init_pci)(PCIBus *bus)); +void soundhw_init(void); +void select_soundhw(const char *optarg); + #endif diff --git a/include/hw/hw.h b/include/hw/hw.h index e22d4ce5fa..af9eae11c5 100644 --- a/include/hw/hw.h +++ b/include/hw/hw.h @@ -11,6 +11,7 @@ #include "exec/memory.h" #include "hw/irq.h" #include "migration/vmstate.h" +#include "migration/qemu-file.h" #include "qemu/module.h" #include "sysemu/reset.h" diff --git a/include/hw/s390x/css-bridge.h b/include/hw/s390x/css-bridge.h index 5a0203be5f..cf0860432a 100644 --- a/include/hw/s390x/css-bridge.h +++ b/include/hw/s390x/css-bridge.h @@ -28,6 +28,7 @@ typedef struct VirtualCssBridge { /* virtual css bus type */ typedef struct VirtualCssBus { BusState parent_obj; + bool squash_mcss; } VirtualCssBus; #define TYPE_VIRTUAL_CSS_BUS "virtual-css-bus" diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index e61fa74d9b..596a2f2ef3 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -91,10 +91,29 @@ struct SubchDev { /* transport-provided data: */ int (*ccw_cb) (SubchDev *, CCW1); void (*disable_cb)(SubchDev *); + int (*do_subchannel_work) (SubchDev *, ORB *); SenseId id; void *driver_data; }; +/* + * Identify a device within the channel subsystem. + * Note that this can be used to identify either the subchannel or + * the attached I/O device, as there's always one I/O device per + * subchannel. + */ +typedef struct CssDevId { + uint8_t cssid; + uint8_t ssid; + uint16_t devid; + bool valid; +} CssDevId; + +extern PropertyInfo css_devid_propinfo; + +#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId) + typedef struct IndAddr { hwaddr addr; uint64_t map; @@ -116,8 +135,11 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno, SubchDev *sch); void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type); +int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id); unsigned int css_find_free_chpid(uint8_t cssid); uint16_t css_build_subchannel_id(SubchDev *sch); +void copy_scsw_to_guest(SCSW *dest, const SCSW *src); +void css_inject_io_interrupt(SubchDev *sch); void css_reset(void); void css_reset_sch(SubchDev *sch); void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid); @@ -127,6 +149,9 @@ void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); void css_generate_css_crws(uint8_t cssid); void css_clear_sei_pending(void); void css_adapter_interrupt(uint8_t isc); +int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data); +int do_subchannel_work_virtual(SubchDev *sub, ORB *orb); +int do_subchannel_work_passthrough(SubchDev *sub, ORB *orb); typedef enum { CSS_IO_ADAPTER_VIRTIO = 0, @@ -164,23 +189,6 @@ int css_do_rsch(SubchDev *sch); int css_do_rchp(uint8_t cssid, uint8_t chpid); bool css_present(uint8_t cssid); #endif -/* - * Identify a device within the channel subsystem. - * Note that this can be used to identify either the subchannel or - * the attached I/O device, as there's always one I/O device per - * subchannel. - */ -typedef struct CssDevId { - uint8_t cssid; - uint8_t ssid; - uint16_t devid; - bool valid; -} CssDevId; - -extern PropertyInfo css_devid_propinfo; - -#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId) extern PropertyInfo css_devid_ro_propinfo; @@ -190,16 +198,25 @@ extern PropertyInfo css_devid_ro_propinfo; /** * Create a subchannel for the given bus id. * - * If @p bus_id is valid, verify that it uses the virtual channel - * subsystem id and is not already in use, and find a free subchannel - * id for it. If @p bus_id is not valid, find a free subchannel id and - * device number across all subchannel sets. If either of the former - * actions succeed, allocate a subchannel structure, initialise it - * with the bus id, subchannel id and device number, register it with - * the CSS and return it. Otherwise return NULL. + * If @p bus_id is valid, and @p squash_mcss is true, verify that it is + * not already in use in the default css, and find a free devno from the + * default css image for it. + * If @p bus_id is valid, and @p squash_mcss is false, verify that it is + * not already in use, and find a free devno for it. + * If @p bus_id is not valid, and if either @p squash_mcss or @p is_virtual + * is true, find a free subchannel id and device number across all + * subchannel sets from the default css image. + * If @p bus_id is not valid, and if both @p squash_mcss and @p is_virtual + * are false, find a non-full css image and find a free subchannel id and + * device number across all subchannel sets from it. + * + * If either of the former actions succeed, allocate a subchannel structure, + * initialise it with the bus id, subchannel id and device number, register + * it with the CSS and return it. Otherwise return NULL. * * The caller becomes owner of the returned subchannel structure and * is responsible for unregistering and freeing it. */ -SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp); +SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, + Error **errp); #endif diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h new file mode 100644 index 0000000000..9f45cf1347 --- /dev/null +++ b/include/hw/s390x/s390-ccw.h @@ -0,0 +1,39 @@ +/* + * s390 CCW Assignment Support + * + * Copyright 2017 IBM Corp. + * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> + * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef HW_S390_CCW_H +#define HW_S390_CCW_H + +#include "hw/s390x/ccw-device.h" + +#define TYPE_S390_CCW "s390-ccw" +#define S390_CCW_DEVICE(obj) \ + OBJECT_CHECK(S390CCWDevice, (obj), TYPE_S390_CCW) +#define S390_CCW_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(S390CCWDeviceClass, (klass), TYPE_S390_CCW) +#define S390_CCW_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(S390CCWDeviceClass, (obj), TYPE_S390_CCW) + +typedef struct S390CCWDevice { + CcwDevice parent_obj; + CssDevId hostid; + char *mdevid; +} S390CCWDevice; + +typedef struct S390CCWDeviceClass { + CCWDeviceClass parent_class; + void (*realize)(S390CCWDevice *dev, char *sysfsdev, Error **errp); + void (*unrealize)(S390CCWDevice *dev, Error **errp); + int (*handle_request) (ORB *, SCSW *, void *); +} S390CCWDeviceClass; + +#endif diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 7b8a3e4d74..3027555f6d 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -29,6 +29,7 @@ typedef struct S390CcwMachineState { bool aes_key_wrap; bool dea_key_wrap; uint8_t loadparm[8]; + bool s390_squash_mcss; } S390CcwMachineState; typedef struct S390CcwMachineClass { diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index c582de18c9..9521013d52 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -45,6 +45,7 @@ enum { VFIO_DEVICE_TYPE_PCI = 0, VFIO_DEVICE_TYPE_PLATFORM = 1, + VFIO_DEVICE_TYPE_CCW = 2, }; typedef struct VFIOMmap { diff --git a/include/migration/block.h b/include/migration/block.h index 41a1ac8f79..28cff53a23 100644 --- a/include/migration/block.h +++ b/include/migration/block.h @@ -14,10 +14,34 @@ #ifndef MIGRATION_BLOCK_H #define MIGRATION_BLOCK_H +#ifdef CONFIG_LIVE_BLOCK_MIGRATION void blk_mig_init(void); int blk_mig_active(void); uint64_t blk_mig_bytes_transferred(void); uint64_t blk_mig_bytes_remaining(void); uint64_t blk_mig_bytes_total(void); +#else +static inline void blk_mig_init(void) { } +static inline int blk_mig_active(void) +{ + return false; +} +static inline uint64_t blk_mig_bytes_transferred(void) +{ + return 0; +} + +static inline uint64_t blk_mig_bytes_remaining(void) +{ + return 0; +} + +static inline uint64_t blk_mig_bytes_total(void) +{ + return 0; +} +#endif /* CONFIG_LIVE_BLOCK_MIGRATION */ + +void migrate_set_block_enabled(bool value, Error **errp); #endif /* MIGRATION_BLOCK_H */ diff --git a/include/migration/colo.h b/include/migration/colo.h index 2bbff9e6c2..ba0bb6e6d5 100644 --- a/include/migration/colo.h +++ b/include/migration/colo.h @@ -14,7 +14,6 @@ #define QEMU_COLO_H #include "qemu-common.h" -#include "migration/migration.h" #include "qemu/coroutine_int.h" #include "qemu/thread.h" #include "qemu/main-loop.h" diff --git a/include/migration/migration.h b/include/migration/migration.h index 49ec5015e5..0e807b63b8 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -18,7 +18,7 @@ #include "qemu-common.h" #include "qemu/thread.h" #include "qemu/notify.h" -#include "migration/vmstate.h" +#include "io/channel.h" #include "qapi-types.h" #include "exec/cpu-common.h" #include "qemu/coroutine_int.h" @@ -38,11 +38,6 @@ #define QEMU_VM_COMMAND 0x08 #define QEMU_VM_SECTION_FOOTER 0x7e -struct MigrationParams { - bool blk; - bool shared; -}; - /* Messages sent on the return path from destination to source */ enum mig_rp_message_type { MIG_RP_MSG_INVALID = 0, /* Must be 0 */ @@ -110,12 +105,10 @@ struct MigrationState QEMUBH *cleanup_bh; QEMUFile *to_dst_file; - /* New style params from 'migrate-set-parameters' */ + /* params from 'migrate-set-parameters' */ MigrationParameters parameters; int state; - /* Old style params from 'migrate' command */ - MigrationParams params; /* State related to return path */ struct { @@ -153,6 +146,9 @@ struct MigrationState /* The last error that occurred */ Error *error; + /* Do we have to clean up -b/-i from old migrate parameters */ + /* This feature is deprecated and will be removed */ + bool must_remove_block_options; }; void migrate_set_state(int *state, int old_state, int new_state); @@ -161,17 +157,10 @@ void migration_fd_process_incoming(QEMUFile *f); void qemu_start_incoming_migration(const char *uri, Error **errp); -void migration_channel_process_incoming(MigrationState *s, - QIOChannel *ioc); - void migration_tls_channel_process_incoming(MigrationState *s, QIOChannel *ioc, Error **errp); -void migration_channel_connect(MigrationState *s, - QIOChannel *ioc, - const char *hostname); - void migration_tls_channel_connect(MigrationState *s, QIOChannel *ioc, const char *hostname, @@ -205,7 +194,7 @@ void migrate_fd_connect(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); -MigrationState *migrate_init(const MigrationParams *params); +MigrationState *migrate_init(void); bool migration_is_blocked(Error **errp); bool migration_in_setup(MigrationState *); bool migration_is_idle(void); @@ -255,16 +244,15 @@ bool migrate_zero_blocks(void); bool migrate_auto_converge(void); -int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen, - uint8_t *dst, int dlen); -int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen); - int migrate_use_xbzrle(void); int64_t migrate_xbzrle_cache_size(void); bool migrate_colo_enabled(void); int64_t xbzrle_cache_resize(int64_t new_size); +bool migrate_use_block(void); +bool migrate_use_block_incremental(void); + bool migrate_use_compression(void); int migrate_compress_level(void); int migrate_compress_threads(void); diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 0cd648a733..b5ac800258 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -27,8 +27,6 @@ #include "qemu-common.h" #include "exec/cpu-common.h" -#include "io/channel.h" - /* Read a chunk of data from a file at the given position. The pos argument * can be ignored if the file is only be used for streaming. The number of @@ -119,8 +117,6 @@ typedef struct QEMUFileHooks { } QEMUFileHooks; QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops); -QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc); -QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc); void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks); int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 848965963a..f97411d31f 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -27,9 +27,6 @@ #ifndef QEMU_VMSTATE_H #define QEMU_VMSTATE_H -#ifndef CONFIG_USER_ONLY -#include "migration/qemu-file.h" -#endif #include "migration/qjson.h" typedef void SaveStateHandler(QEMUFile *f, void *opaque); @@ -37,7 +34,6 @@ typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); typedef struct SaveVMHandlers { /* This runs inside the iothread lock. */ - void (*set_params)(const MigrationParams *params, void * opaque); SaveStateHandler *save_state; void (*cleanup)(void *opaque); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 7d8505730c..33a6aa18e3 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -49,7 +49,6 @@ typedef struct MemoryRegion MemoryRegion; typedef struct MemoryRegionCache MemoryRegionCache; typedef struct MemoryRegionSection MemoryRegionSection; typedef struct MigrationIncomingState MigrationIncomingState; -typedef struct MigrationParams MigrationParams; typedef struct MigrationState MigrationState; typedef struct Monitor Monitor; typedef struct MonitorDef MonitorDef; diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h index eca9a2ca22..d0c6e0a079 100644 --- a/include/standard-headers/asm-x86/hyperv.h +++ b/include/standard-headers/asm-x86/hyperv.h @@ -124,7 +124,7 @@ * Recommend using hypercall for address space switches rather * than MOV to CR3 instruction */ -#define HV_X64_MWAIT_RECOMMENDED (1 << 0) +#define HV_X64_AS_SWITCH_RECOMMENDED (1 << 0) /* Recommend using hypercall for local TLB flushes rather * than INVLPG or MOV to CR3 instructions */ #define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED (1 << 1) @@ -148,6 +148,11 @@ #define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5) /* + * Virtual APIC support + */ +#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9) + +/* * Crash notification flag. */ #define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63) diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h index c8b3338375..29d463af37 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -641,6 +641,7 @@ * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) */ #define KEY_DATA 0x277 +#define KEY_ONSCREEN_KEYBOARD 0x278 #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h index b472b8530c..666e201ddb 100644 --- a/include/standard-headers/linux/input.h +++ b/include/standard-headers/linux/input.h @@ -58,9 +58,14 @@ struct input_id { * Note that input core does not clamp reported values to the * [minimum, maximum] limits, such task is left to userspace. * - * Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in - * units per millimeter (units/mm), resolution for rotational axes - * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian. + * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z) + * is reported in units per millimeter (units/mm), resolution + * for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported + * in units per radian. + * When INPUT_PROP_ACCELEROMETER is set the resolution changes. + * The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in + * in units per g (units/g) and in units per degree per second + * (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ). */ struct input_absinfo { int32_t value; diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index 634c9c44ed..d56bb00510 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -114,7 +114,7 @@ #define PCI_SUBSYSTEM_ID 0x2e #define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ #define PCI_ROM_ADDRESS_ENABLE 0x01 -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) +#define PCI_ROM_ADDRESS_MASK (~0x7ffU) #define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ @@ -630,6 +630,7 @@ #define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ #define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ #define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */ +#define PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */ #define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */ #define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */ #define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 2bf16b203c..8751c468ed 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -28,8 +28,6 @@ enum { extern const uint32_t arch_type; -void select_soundhw(const char *optarg); -void audio_init(void); int kvm_available(void); int xen_available(void); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 83c1ceb33e..ed8fe3bf34 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -67,7 +67,6 @@ int qemu_reset_requested_get(void); void qemu_system_killed(int signal, pid_t pid); void qemu_system_reset(bool report); void qemu_system_guest_panicked(GuestPanicInformation *info); -size_t qemu_target_page_size(void); void qemu_add_exit_notifier(Notifier *notify); void qemu_remove_exit_notifier(Notifier *notify); @@ -102,8 +101,7 @@ enum qemu_vm_cmd { #define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24) bool qemu_savevm_state_blocked(Error **errp); -void qemu_savevm_state_begin(QEMUFile *f, - const MigrationParams *params); +void qemu_savevm_state_begin(QEMUFile *f); void qemu_savevm_state_header(QEMUFile *f); int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy); void qemu_savevm_state_cleanup(void); diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h index 1101d55d2f..7258a00225 100644 --- a/linux-headers/asm-arm/kvm.h +++ b/linux-headers/asm-arm/kvm.h @@ -27,6 +27,8 @@ #define __KVM_HAVE_IRQ_LINE #define __KVM_HAVE_READONLY_MEM +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + #define KVM_REG_SIZE(id) \ (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) @@ -114,6 +116,8 @@ struct kvm_debug_exit_arch { }; struct kvm_sync_regs { + /* Used with KVM_CAP_ARM_USER_IRQ */ + __u64 device_irq_level; }; struct kvm_arch_memory_slot { @@ -192,13 +196,17 @@ struct kvm_arch_memory_slot { #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 +#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff #define VGIC_LEVEL_INFO_LINE_LEVEL 0 -#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 +#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 +#define KVM_DEV_ARM_ITS_SAVE_TABLES 1 +#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 +#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 /* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 diff --git a/linux-headers/asm-arm/unistd-common.h b/linux-headers/asm-arm/unistd-common.h index 13a74afd02..8d5ceaee1a 100644 --- a/linux-headers/asm-arm/unistd-common.h +++ b/linux-headers/asm-arm/unistd-common.h @@ -353,5 +353,6 @@ #define __NR_pkey_mprotect (__NR_SYSCALL_BASE + 394) #define __NR_pkey_alloc (__NR_SYSCALL_BASE + 395) #define __NR_pkey_free (__NR_SYSCALL_BASE + 396) +#define __NR_statx (__NR_SYSCALL_BASE + 397) #endif /* _ASM_ARM_UNISTD_COMMON_H */ diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 651ec30040..31bb1dd924 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -39,6 +39,8 @@ #define __KVM_HAVE_IRQ_LINE #define __KVM_HAVE_READONLY_MEM +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + #define KVM_REG_SIZE(id) \ (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) @@ -143,6 +145,8 @@ struct kvm_debug_exit_arch { #define KVM_GUESTDBG_USE_HW (1 << 17) struct kvm_sync_regs { + /* Used with KVM_CAP_ARM_USER_IRQ */ + __u64 device_irq_level; }; struct kvm_arch_memory_slot { @@ -212,13 +216,17 @@ struct kvm_arch_memory_slot { #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 +#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff #define VGIC_LEVEL_INFO_LINE_LEVEL 0 -#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 +#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 +#define KVM_DEV_ARM_ITS_SAVE_TABLES 1 +#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 +#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 /* Device Control API on vcpu fd */ #define KVM_ARM_VCPU_PMU_V3_CTRL 0 diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 4edbe4bb0e..07fbeb9278 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -29,6 +29,9 @@ #define __KVM_HAVE_IRQ_LINE #define __KVM_HAVE_GUEST_DEBUG +/* Not always available, but if it is, this is the correct offset. */ +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + struct kvm_regs { __u64 pc; __u64 cr; diff --git a/linux-headers/asm-powerpc/unistd.h b/linux-headers/asm-powerpc/unistd.h index 598043c7b6..a1786340e9 100644 --- a/linux-headers/asm-powerpc/unistd.h +++ b/linux-headers/asm-powerpc/unistd.h @@ -393,5 +393,6 @@ #define __NR_preadv2 380 #define __NR_pwritev2 381 #define __NR_kexec_file_load 382 +#define __NR_statx 383 #endif /* _ASM_POWERPC_UNISTD_H_ */ diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h index ac63ca630b..243f195776 100644 --- a/linux-headers/asm-s390/kvm.h +++ b/linux-headers/asm-s390/kvm.h @@ -26,6 +26,8 @@ #define KVM_DEV_FLIC_ADAPTER_REGISTER 6 #define KVM_DEV_FLIC_ADAPTER_MODIFY 7 #define KVM_DEV_FLIC_CLEAR_IO_IRQ 8 +#define KVM_DEV_FLIC_AISM 9 +#define KVM_DEV_FLIC_AIRQ_INJECT 10 /* * We can have up to 4*64k pending subchannels + 8 adapter interrupts, * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. @@ -41,7 +43,14 @@ struct kvm_s390_io_adapter { __u8 isc; __u8 maskable; __u8 swap; - __u8 pad; + __u8 flags; +}; + +#define KVM_S390_ADAPTER_SUPPRESSIBLE 0x01 + +struct kvm_s390_ais_req { + __u8 isc; + __u16 mode; }; #define KVM_S390_IO_ADAPTER_MASK 1 @@ -110,6 +119,7 @@ struct kvm_s390_vm_cpu_machine { #define KVM_S390_VM_CPU_FEAT_CMMA 10 #define KVM_S390_VM_CPU_FEAT_PFMFI 11 #define KVM_S390_VM_CPU_FEAT_SIGPIF 12 +#define KVM_S390_VM_CPU_FEAT_KSS 13 struct kvm_s390_vm_cpu_feat { __u64 feat[16]; }; @@ -131,7 +141,8 @@ struct kvm_s390_vm_cpu_subfunc { __u8 kmo[16]; /* with MSA4 */ __u8 pcc[16]; /* with MSA4 */ __u8 ppno[16]; /* with MSA5 */ - __u8 reserved[1824]; + __u8 kma[16]; /* with MSA8 */ + __u8 reserved[1808]; }; /* kvm attributes for crypto */ @@ -197,6 +208,10 @@ struct kvm_guest_debug_arch { #define KVM_SYNC_VRS (1UL << 6) #define KVM_SYNC_RICCB (1UL << 7) #define KVM_SYNC_FPRS (1UL << 8) +#define KVM_SYNC_GSCB (1UL << 9) +/* length and alignment of the sdnx as a power of two */ +#define SDNXC 8 +#define SDNXL (1UL << SDNXC) /* definition of registers in kvm_run */ struct kvm_sync_regs { __u64 prefix; /* prefix register */ @@ -217,8 +232,16 @@ struct kvm_sync_regs { }; __u8 reserved[512]; /* for future vector expansion */ __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ - __u8 padding[52]; /* riccb needs to be 64byte aligned */ + __u8 padding1[52]; /* riccb needs to be 64byte aligned */ __u8 riccb[64]; /* runtime instrumentation controls block */ + __u8 padding2[192]; /* sdnx needs to be 256byte aligned */ + union { + __u8 sdnx[SDNXL]; /* state description annex */ + struct { + __u64 reserved1[2]; + __u64 gscb[4]; + }; + }; }; #define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1) diff --git a/linux-headers/asm-s390/unistd.h b/linux-headers/asm-s390/unistd.h index 8a404fd3a1..65e7e59dbb 100644 --- a/linux-headers/asm-s390/unistd.h +++ b/linux-headers/asm-s390/unistd.h @@ -313,7 +313,9 @@ #define __NR_copy_file_range 375 #define __NR_preadv2 376 #define __NR_pwritev2 377 -#define NR_syscalls 378 +#define __NR_s390_guarded_storage 378 +#define __NR_statx 379 +#define NR_syscalls 380 /* * There are some system calls that are not present on 64 bit, some diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 739c0c5940..c2824d02ba 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -9,6 +9,9 @@ #include <linux/types.h> #include <linux/ioctl.h> +#define KVM_PIO_PAGE_OFFSET 1 +#define KVM_COALESCED_MMIO_PAGE_OFFSET 2 + #define DE_VECTOR 0 #define DB_VECTOR 1 #define BP_VECTOR 3 diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h index d45ea28e15..8a206df454 100644 --- a/linux-headers/asm-x86/unistd_32.h +++ b/linux-headers/asm-x86/unistd_32.h @@ -380,5 +380,7 @@ #define __NR_pkey_mprotect 380 #define __NR_pkey_alloc 381 #define __NR_pkey_free 382 +#define __NR_statx 383 +#define __NR_arch_prctl 384 #endif /* _ASM_X86_UNISTD_32_H */ diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h index e22db9171e..336c2e4aaa 100644 --- a/linux-headers/asm-x86/unistd_64.h +++ b/linux-headers/asm-x86/unistd_64.h @@ -333,5 +333,6 @@ #define __NR_pkey_mprotect 329 #define __NR_pkey_alloc 330 #define __NR_pkey_free 331 +#define __NR_statx 332 #endif /* _ASM_X86_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h index 84e58b202d..cb98a52998 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -286,6 +286,7 @@ #define __NR_pkey_mprotect (__X32_SYSCALL_BIT + 329) #define __NR_pkey_alloc (__X32_SYSCALL_BIT + 330) #define __NR_pkey_free (__X32_SYSCALL_BIT + 331) +#define __NR_statx (__X32_SYSCALL_BIT + 332) #define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512) #define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513) #define __NR_ioctl (__X32_SYSCALL_BIT + 514) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 4e082a81b4..d2892da172 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -702,6 +702,10 @@ struct kvm_ppc_resize_hpt { #define KVM_VM_PPC_HV 1 #define KVM_VM_PPC_PR 2 +/* on MIPS, 0 forces trap & emulate, 1 forces VZ ASE */ +#define KVM_VM_MIPS_TE 0 +#define KVM_VM_MIPS_VZ 1 + #define KVM_S390_SIE_PAGE_OFFSET 1 /* @@ -883,6 +887,14 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PPC_MMU_RADIX 134 #define KVM_CAP_PPC_MMU_HASH_V3 135 #define KVM_CAP_IMMEDIATE_EXIT 136 +#define KVM_CAP_MIPS_VZ 137 +#define KVM_CAP_MIPS_TE 138 +#define KVM_CAP_MIPS_64BIT 139 +#define KVM_CAP_S390_GS 140 +#define KVM_CAP_S390_AIS 141 +#define KVM_CAP_SPAPR_TCE_VFIO 142 +#define KVM_CAP_X86_GUEST_MWAIT 143 +#define KVM_CAP_ARM_USER_IRQ 144 #ifdef KVM_CAP_IRQ_ROUTING @@ -1087,6 +1099,7 @@ struct kvm_device_attr { #define KVM_DEV_VFIO_GROUP 1 #define KVM_DEV_VFIO_GROUP_ADD 1 #define KVM_DEV_VFIO_GROUP_DEL 2 +#define KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE 3 enum kvm_device_type { KVM_DEV_TYPE_FSL_MPIC_20 = 1, @@ -1108,6 +1121,11 @@ enum kvm_device_type { KVM_DEV_TYPE_MAX, }; +struct kvm_vfio_spapr_tce { + __s32 groupfd; + __s32 tablefd; +}; + /* * ioctls for VM fds */ @@ -1354,4 +1372,11 @@ struct kvm_assigned_msix_entry { #define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) +/* Available with KVM_CAP_ARM_USER_IRQ */ + +/* Bits for run->s.regs.device_irq_level */ +#define KVM_ARM_DEV_EL1_VTIMER (1 << 0) +#define KVM_ARM_DEV_EL1_PTIMER (1 << 1) +#define KVM_ARM_DEV_PMU (1 << 2) + #endif /* __LINUX_KVM_H */ diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index 2ed5dc3775..9701772497 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -20,7 +20,8 @@ #define UFFD_API ((__u64)0xAA) #define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \ UFFD_FEATURE_EVENT_REMAP | \ - UFFD_FEATURE_EVENT_MADVDONTNEED | \ + UFFD_FEATURE_EVENT_REMOVE | \ + UFFD_FEATURE_EVENT_UNMAP | \ UFFD_FEATURE_MISSING_HUGETLBFS | \ UFFD_FEATURE_MISSING_SHMEM) #define UFFD_API_IOCTLS \ @@ -92,7 +93,7 @@ struct uffd_msg { struct { __u64 start; __u64 end; - } madv_dn; + } remove; struct { /* unused reserved fields */ @@ -109,7 +110,8 @@ struct uffd_msg { #define UFFD_EVENT_PAGEFAULT 0x12 #define UFFD_EVENT_FORK 0x13 #define UFFD_EVENT_REMAP 0x14 -#define UFFD_EVENT_MADVDONTNEED 0x15 +#define UFFD_EVENT_REMOVE 0x15 +#define UFFD_EVENT_UNMAP 0x16 /* flags for UFFD_EVENT_PAGEFAULT */ #define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ @@ -155,9 +157,10 @@ struct uffdio_api { #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) #define UFFD_FEATURE_EVENT_FORK (1<<1) #define UFFD_FEATURE_EVENT_REMAP (1<<2) -#define UFFD_FEATURE_EVENT_MADVDONTNEED (1<<3) +#define UFFD_FEATURE_EVENT_REMOVE (1<<3) #define UFFD_FEATURE_MISSING_HUGETLBFS (1<<4) #define UFFD_FEATURE_MISSING_SHMEM (1<<5) +#define UFFD_FEATURE_EVENT_UNMAP (1<<6) __u64 features; __u64 ioctls; diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 531cb2eda9..4e7ab4c52a 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -198,6 +198,7 @@ struct vfio_device_info { #define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */ #define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */ #define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */ +#define VFIO_DEVICE_FLAGS_CCW (1 << 4) /* vfio-ccw device */ __u32 num_regions; /* Max region index + 1 */ __u32 num_irqs; /* Max IRQ index + 1 */ }; @@ -212,6 +213,7 @@ struct vfio_device_info { #define VFIO_DEVICE_API_PCI_STRING "vfio-pci" #define VFIO_DEVICE_API_PLATFORM_STRING "vfio-platform" #define VFIO_DEVICE_API_AMBA_STRING "vfio-amba" +#define VFIO_DEVICE_API_CCW_STRING "vfio-ccw" /** * VFIO_DEVICE_GET_REGION_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 8, @@ -446,6 +448,22 @@ enum { VFIO_PCI_NUM_IRQS }; +/* + * The vfio-ccw bus driver makes use of the following fixed region and + * IRQ index mapping. Unimplemented regions return a size of zero. + * Unimplemented IRQ types return a count of zero. + */ + +enum { + VFIO_CCW_CONFIG_REGION_INDEX, + VFIO_CCW_NUM_REGIONS +}; + +enum { + VFIO_CCW_IO_IRQ_INDEX, + VFIO_CCW_NUM_IRQS +}; + /** * VFIO_DEVICE_GET_PCI_HOT_RESET_INFO - _IORW(VFIO_TYPE, VFIO_BASE + 12, * struct vfio_pci_hot_reset_info) diff --git a/linux-headers/linux/vfio_ccw.h b/linux-headers/linux/vfio_ccw.h new file mode 100644 index 0000000000..3a565511ab --- /dev/null +++ b/linux-headers/linux/vfio_ccw.h @@ -0,0 +1,24 @@ +/* + * Interfaces for vfio-ccw + * + * Copyright IBM Corp. 2017 + * + * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> + */ + +#ifndef _VFIO_CCW_H_ +#define _VFIO_CCW_H_ + +#include <linux/types.h> + +struct ccw_io_region { +#define ORB_AREA_SIZE 12 + __u8 orb_area[ORB_AREA_SIZE]; +#define SCSW_AREA_SIZE 12 + __u8 scsw_area[SCSW_AREA_SIZE]; +#define IRB_AREA_SIZE 96 + __u8 irb_area[IRB_AREA_SIZE]; + __u32 ret_code; +} __attribute__((packed)); + +#endif diff --git a/migration/Makefile.objs b/migration/Makefile.objs index c1920b6fc0..90f8c1f177 100644 --- a/migration/Makefile.objs +++ b/migration/Makefile.objs @@ -1,7 +1,7 @@ common-obj-y += migration.o socket.o fd.o exec.o -common-obj-y += tls.o +common-obj-y += tls.o channel.o savevm.o common-obj-y += colo-comm.o colo.o colo-failover.o -common-obj-y += vmstate.o page_cache.o +common-obj-y += vmstate.o vmstate-types.o page_cache.o common-obj-y += qemu-file.o common-obj-y += qemu-file-channel.o common-obj-y += xbzrle.o postcopy-ram.o @@ -9,5 +9,5 @@ common-obj-y += qjson.o common-obj-$(CONFIG_RDMA) += rdma.o -common-obj-y += block.o +common-obj-$(CONFIG_LIVE_BLOCK_MIGRATION) += block.o diff --git a/migration/block.c b/migration/block.c index 060087fa32..13f90d3f17 100644 --- a/migration/block.c +++ b/migration/block.c @@ -26,6 +26,8 @@ #include "migration/block.h" #include "migration/migration.h" #include "sysemu/blockdev.h" +#include "migration/qemu-file.h" +#include "migration/vmstate.h" #include "sysemu/block-backend.h" #define BLOCK_SIZE (1 << 20) @@ -94,9 +96,6 @@ typedef struct BlkMigBlock { } BlkMigBlock; typedef struct BlkMigState { - /* Written during setup phase. Can be read without a lock. */ - int blk_enable; - int shared_base; QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list; int64_t total_sector_sum; bool zero_blocks; @@ -425,7 +424,7 @@ static int init_blk_migration(QEMUFile *f) bmds->bulk_completed = 0; bmds->total_sectors = sectors; bmds->completed_sectors = 0; - bmds->shared_base = block_mig_state.shared_base; + bmds->shared_base = migrate_use_block_incremental(); assert(i < num_bs); bmds_bs[i].bmds = bmds; @@ -994,22 +993,12 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void block_set_params(const MigrationParams *params, void *opaque) -{ - block_mig_state.blk_enable = params->blk; - block_mig_state.shared_base = params->shared; - - /* shared base means that blk_enable = 1 */ - block_mig_state.blk_enable |= params->shared; -} - static bool block_is_active(void *opaque) { - return block_mig_state.blk_enable == 1; + return migrate_use_block(); } static SaveVMHandlers savevm_block_handlers = { - .set_params = block_set_params, .save_live_setup = block_save_setup, .save_live_iterate = block_save_iterate, .save_live_complete_precopy = block_save_complete, diff --git a/migration/channel.c b/migration/channel.c new file mode 100644 index 0000000000..2e78905cc7 --- /dev/null +++ b/migration/channel.c @@ -0,0 +1,67 @@ +/* + * QEMU live migration channel operations + * + * Copyright Red Hat, Inc. 2016 + * + * Authors: + * Daniel P. Berrange <berrange@redhat.com> + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "channel.h" +#include "migration/migration.h" +#include "qemu-file-channel.h" +#include "trace.h" +#include "qapi/error.h" +#include "io/channel-tls.h" + +void migration_channel_process_incoming(MigrationState *s, + QIOChannel *ioc) +{ + trace_migration_set_incoming_channel( + ioc, object_get_typename(OBJECT(ioc))); + + if (s->parameters.tls_creds && + *s->parameters.tls_creds && + !object_dynamic_cast(OBJECT(ioc), + TYPE_QIO_CHANNEL_TLS)) { + Error *local_err = NULL; + migration_tls_channel_process_incoming(s, ioc, &local_err); + if (local_err) { + error_report_err(local_err); + } + } else { + QEMUFile *f = qemu_fopen_channel_input(ioc); + migration_fd_process_incoming(f); + } +} + + +void migration_channel_connect(MigrationState *s, + QIOChannel *ioc, + const char *hostname) +{ + trace_migration_set_outgoing_channel( + ioc, object_get_typename(OBJECT(ioc)), hostname); + + if (s->parameters.tls_creds && + *s->parameters.tls_creds && + !object_dynamic_cast(OBJECT(ioc), + TYPE_QIO_CHANNEL_TLS)) { + Error *local_err = NULL; + migration_tls_channel_connect(s, ioc, hostname, &local_err); + if (local_err) { + migrate_fd_error(s, local_err); + error_free(local_err); + } + } else { + QEMUFile *f = qemu_fopen_channel_output(ioc); + + s->to_dst_file = f; + + migrate_fd_connect(s); + } +} diff --git a/migration/channel.h b/migration/channel.h new file mode 100644 index 0000000000..2e0a7e33cc --- /dev/null +++ b/migration/channel.h @@ -0,0 +1,27 @@ +/* + * QEMU live migration channel operations + * + * Copyright Red Hat, Inc. 2016 + * + * Authors: + * Daniel P. Berrange <berrange@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef QEMU_MIGRATION_CHANNEL_H +#define QEMU_MIGRATION_CHANNEL_H + +#include "io/channel.h" + +void migration_channel_process_incoming(MigrationState *s, + QIOChannel *ioc); + +void migration_channel_connect(MigrationState *s, + QIOChannel *ioc, + const char *hostname); +#endif diff --git a/migration/colo-comm.c b/migration/colo-comm.c index 20b60ec384..8bfdf6825a 100644 --- a/migration/colo-comm.c +++ b/migration/colo-comm.c @@ -12,7 +12,9 @@ */ #include "qemu/osdep.h" -#include <migration/colo.h> +#include "migration/migration.h" +#include "migration/colo.h" +#include "migration/vmstate.h" #include "trace.h" typedef struct { diff --git a/migration/colo.c b/migration/colo.c index 963c80256d..929b31c50c 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -13,7 +13,11 @@ #include "qemu/osdep.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" +#include "qemu-file-channel.h" +#include "migration/migration.h" +#include "migration/qemu-file.h" #include "migration/colo.h" +#include "migration/block.h" #include "io/channel-buffer.h" #include "trace.h" #include "qemu/error-report.h" @@ -345,10 +349,9 @@ static int colo_do_checkpoint_transaction(MigrationState *s, } /* Disable block migration */ - s->params.blk = 0; - s->params.shared = 0; + migrate_set_block_enabled(false, &local_err); qemu_savevm_state_header(fb); - qemu_savevm_state_begin(fb, &s->params); + qemu_savevm_state_begin(fb); qemu_mutex_lock_iothread(); qemu_savevm_state_complete_precopy(fb, false); qemu_mutex_unlock_iothread(); diff --git a/migration/exec.c b/migration/exec.c index aba9089466..57a93355d1 100644 --- a/migration/exec.c +++ b/migration/exec.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" +#include "channel.h" #include "migration/migration.h" #include "io/channel-command.h" #include "trace.h" diff --git a/migration/fd.c b/migration/fd.c index 58cb51a9e6..05e0a5cca8 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -17,6 +17,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" +#include "channel.h" #include "migration/migration.h" #include "monitor/monitor.h" #include "io/channel-util.h" diff --git a/migration/migration.c b/migration/migration.c index 0304c013f3..ad29e53400 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -19,7 +19,9 @@ #include "qemu/main-loop.h" #include "migration/blocker.h" #include "migration/migration.h" +#include "qemu-file-channel.h" #include "migration/qemu-file.h" +#include "migration/vmstate.h" #include "sysemu/sysemu.h" #include "block/block.h" #include "qapi/qmp/qerror.h" @@ -35,6 +37,7 @@ #include "qom/cpu.h" #include "exec/memory.h" #include "exec/address-spaces.h" +#include "exec/target_page.h" #include "io/channel-buffer.h" #include "io/channel-tls.h" #include "migration/colo.h" @@ -444,56 +447,6 @@ void migration_fd_process_incoming(QEMUFile *f) qemu_coroutine_enter(co); } - -void migration_channel_process_incoming(MigrationState *s, - QIOChannel *ioc) -{ - trace_migration_set_incoming_channel( - ioc, object_get_typename(OBJECT(ioc))); - - if (s->parameters.tls_creds && - *s->parameters.tls_creds && - !object_dynamic_cast(OBJECT(ioc), - TYPE_QIO_CHANNEL_TLS)) { - Error *local_err = NULL; - migration_tls_channel_process_incoming(s, ioc, &local_err); - if (local_err) { - error_report_err(local_err); - } - } else { - QEMUFile *f = qemu_fopen_channel_input(ioc); - migration_fd_process_incoming(f); - } -} - - -void migration_channel_connect(MigrationState *s, - QIOChannel *ioc, - const char *hostname) -{ - trace_migration_set_outgoing_channel( - ioc, object_get_typename(OBJECT(ioc)), hostname); - - if (s->parameters.tls_creds && - *s->parameters.tls_creds && - !object_dynamic_cast(OBJECT(ioc), - TYPE_QIO_CHANNEL_TLS)) { - Error *local_err = NULL; - migration_tls_channel_connect(s, ioc, hostname, &local_err); - if (local_err) { - migrate_fd_error(s, local_err); - error_free(local_err); - } - } else { - QEMUFile *f = qemu_fopen_channel_output(ioc); - - s->to_dst_file = f; - - migrate_fd_connect(s); - } -} - - /* * Send a message on the return channel back to the source * of the migration. @@ -547,6 +500,11 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp) caps = NULL; /* silence compiler warning */ for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { +#ifndef CONFIG_LIVE_BLOCK_MIGRATION + if (i == MIGRATION_CAPABILITY_BLOCK) { + continue; + } +#endif if (i == MIGRATION_CAPABILITY_X_COLO && !colo_supported()) { continue; } @@ -592,6 +550,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->downtime_limit = s->parameters.downtime_limit; params->has_x_checkpoint_delay = true; params->x_checkpoint_delay = s->parameters.x_checkpoint_delay; + params->has_block_incremental = true; + params->block_incremental = s->parameters.block_incremental; return params; } @@ -761,6 +721,15 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, } for (cap = params; cap; cap = cap->next) { +#ifndef CONFIG_LIVE_BLOCK_MIGRATION + if (cap->value->capability == MIGRATION_CAPABILITY_BLOCK + && cap->value->state) { + error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) " + "block migration"); + error_append_hint(errp, "Use drive_mirror+NBD instead.\n"); + continue; + } +#endif if (cap->value->capability == MIGRATION_CAPABILITY_X_COLO) { if (!colo_supported()) { error_setg(errp, "COLO is not currently supported, please" @@ -900,6 +869,9 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp) colo_checkpoint_notify(s); } } + if (params->has_block_incremental) { + s->parameters.block_incremental = params->block_incremental; + } } @@ -935,6 +907,33 @@ void migrate_set_state(int *state, int old_state, int new_state) } } +void migrate_set_block_enabled(bool value, Error **errp) +{ + MigrationCapabilityStatusList *cap; + + cap = g_new0(MigrationCapabilityStatusList, 1); + cap->value = g_new0(MigrationCapabilityStatus, 1); + cap->value->capability = MIGRATION_CAPABILITY_BLOCK; + cap->value->state = value; + qmp_migrate_set_capabilities(cap, errp); + qapi_free_MigrationCapabilityStatusList(cap); +} + +static void migrate_set_block_incremental(MigrationState *s, bool value) +{ + s->parameters.block_incremental = value; +} + +static void block_cleanup_parameters(MigrationState *s) +{ + if (s->must_remove_block_options) { + /* setting to false can never fail */ + migrate_set_block_enabled(false, &error_abort); + migrate_set_block_incremental(s, false); + s->must_remove_block_options = false; + } +} + static void migrate_fd_cleanup(void *opaque) { MigrationState *s = opaque; @@ -967,6 +966,7 @@ static void migrate_fd_cleanup(void *opaque) } notifier_list_notify(&migration_state_notifiers, s); + block_cleanup_parameters(s); } void migrate_fd_error(MigrationState *s, const Error *error) @@ -979,6 +979,7 @@ void migrate_fd_error(MigrationState *s, const Error *error) s->error = error_copy(error); } notifier_list_notify(&migration_state_notifiers, s); + block_cleanup_parameters(s); } static void migrate_fd_cancel(MigrationState *s) @@ -1020,6 +1021,7 @@ static void migrate_fd_cancel(MigrationState *s) s->block_inactive = false; } } + block_cleanup_parameters(s); } void add_migration_state_change_notifier(Notifier *notify) @@ -1083,7 +1085,7 @@ bool migration_is_idle(void) return false; } -MigrationState *migrate_init(const MigrationParams *params) +MigrationState *migrate_init(void) { MigrationState *s = migrate_get_current(); @@ -1097,7 +1099,6 @@ MigrationState *migrate_init(const MigrationParams *params) s->cleanup_bh = 0; s->to_dst_file = NULL; s->state = MIGRATION_STATUS_NONE; - s->params = *params; s->rp_state.from_dst_file = NULL; s->rp_state.error = false; s->mbps = 0.0; @@ -1186,12 +1187,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, { Error *local_err = NULL; MigrationState *s = migrate_get_current(); - MigrationParams params; const char *p; - params.blk = has_blk && blk; - params.shared = has_inc && inc; - if (migration_is_setup_or_active(s->state) || s->state == MIGRATION_STATUS_CANCELLING || s->state == MIGRATION_STATUS_COLO) { @@ -1207,7 +1204,25 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, return; } - s = migrate_init(¶ms); + if ((has_blk && blk) || (has_inc && inc)) { + if (migrate_use_block() || migrate_use_block_incremental()) { + error_setg(errp, "Command options are incompatible with " + "current migration capabilities"); + return; + } + migrate_set_block_enabled(true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + s->must_remove_block_options = true; + } + + if (has_inc && inc) { + migrate_set_block_incremental(s, true); + } + + s = migrate_init(); if (strstart(uri, "tcp:", &p)) { tcp_start_outgoing_migration(s, p, &local_err); @@ -1404,6 +1419,24 @@ int64_t migrate_xbzrle_cache_size(void) return s->xbzrle_cache_size; } +bool migrate_use_block(void) +{ + MigrationState *s; + + s = migrate_get_current(); + + return s->enabled_capabilities[MIGRATION_CAPABILITY_BLOCK]; +} + +bool migrate_use_block_incremental(void) +{ + MigrationState *s; + + s = migrate_get_current(); + + return s->parameters.block_incremental; +} + /* migration thread support */ /* * Something bad happened to the RP stream, mark an error @@ -1913,7 +1946,7 @@ static void *migration_thread(void *opaque) qemu_savevm_send_postcopy_advise(s->to_dst_file); } - qemu_savevm_state_begin(s->to_dst_file, &s->params); + qemu_savevm_state_begin(s->to_dst_file); s->setup_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) - setup_start; migrate_set_state(&s->state, MIGRATION_STATUS_SETUP, diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index a0489f6542..a37620dac6 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -19,7 +19,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "exec/target_page.h" #include "migration/migration.h" +#include "migration/qemu-file.h" #include "postcopy-ram.h" #include "sysemu/sysemu.h" #include "sysemu/balloon.h" @@ -96,14 +98,24 @@ static bool ufd_version_check(int ufd) /* Callback from postcopy_ram_supported_by_host block iterator. */ -static int test_range_shared(const char *block_name, void *host_addr, +static int test_ramblock_postcopiable(const char *block_name, void *host_addr, ram_addr_t offset, ram_addr_t length, void *opaque) { - if (qemu_ram_is_shared(qemu_ram_block_by_name(block_name))) { + RAMBlock *rb = qemu_ram_block_by_name(block_name); + size_t pagesize = qemu_ram_pagesize(rb); + + if (qemu_ram_is_shared(rb)) { error_report("Postcopy on shared RAM (%s) is not yet supported", block_name); return 1; } + + if (length % pagesize) { + error_report("Postcopy requires RAM blocks to be a page size multiple," + " block %s is 0x" RAM_ADDR_FMT " bytes with a " + "page size of 0x%zx", block_name, length, pagesize); + return 1; + } return 0; } @@ -140,7 +152,7 @@ bool postcopy_ram_supported_by_host(void) } /* We don't support postcopy with shared RAM yet */ - if (qemu_ram_foreach_block(test_range_shared, NULL)) { + if (qemu_ram_foreach_block(test_ramblock_postcopiable, NULL)) { goto out; } diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c index 45c13f1028..dc991c9051 100644 --- a/migration/qemu-file-channel.c +++ b/migration/qemu-file-channel.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qemu-file-channel.h" #include "migration/qemu-file.h" #include "io/channel-socket.h" #include "qemu/iov.h" diff --git a/net/tap-haiku.c b/migration/qemu-file-channel.h index b27e57e955..0028a09eb6 100644 --- a/net/tap-haiku.c +++ b/migration/qemu-file-channel.h @@ -1,7 +1,7 @@ /* - * QEMU System Emulator + * QEMUFile backend for QIOChannel objects * - * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2015-2016 Red Hat, Inc * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,66 +22,11 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "tap_int.h" +#ifndef QEMU_FILE_CHANNEL_H +#define QEMU_FILE_CHANNEL_H -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp) -{ - error_setg(errp, "no tap on Haiku"); - return -1; -} +#include "io/channel.h" -void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) -{ -} - -int tap_probe_vnet_hdr(int fd) -{ - return 0; -} - -int tap_probe_has_ufo(int fd) -{ - return 0; -} - -int tap_probe_vnet_hdr_len(int fd, int len) -{ - return 0; -} - -void tap_fd_set_vnet_hdr_len(int fd, int len) -{ -} - -int tap_fd_set_vnet_le(int fd, int is_le) -{ - return -EINVAL; -} - -int tap_fd_set_vnet_be(int fd, int is_be) -{ - return -EINVAL; -} - -void tap_fd_set_offload(int fd, int csum, int tso4, - int tso6, int ecn, int ufo) -{ -} - -int tap_fd_enable(int fd) -{ - return -1; -} - -int tap_fd_disable(int fd) -{ - return -1; -} - -int tap_fd_get_ifname(int fd, char *ifname) -{ - return -1; -} +QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc); +QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc); +#endif diff --git a/migration/qjson.c b/migration/qjson.c index f345904919..9d7f6eb9eb 100644 --- a/migration/qjson.c +++ b/migration/qjson.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "qapi/qmp/qstring.h" -#include "migration/qjson.h" +#include "qjson.h" struct QJSON { QString *str; diff --git a/include/migration/qjson.h b/migration/qjson.h index 2978b5f371..2978b5f371 100644 --- a/include/migration/qjson.h +++ b/migration/qjson.h diff --git a/migration/ram.c b/migration/ram.c index f59fdd41a4..c07a9c08d9 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -35,7 +35,10 @@ #include "qemu/bitmap.h" #include "qemu/timer.h" #include "qemu/main-loop.h" +#include "xbzrle.h" #include "migration/migration.h" +#include "migration/qemu-file.h" +#include "migration/vmstate.h" #include "postcopy-ram.h" #include "exec/address-spaces.h" #include "migration/page_cache.h" @@ -1312,6 +1315,8 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, * a host page in which case the remainder of the hostpage is sent. * Only dirty target pages are sent. Note that the host page size may * be a huge page for this block. + * The saving stops at the boundary of the used_length of the block + * if the RAMBlock isn't a multiple of the host page size. * * Returns the number of pages written or negative on error * @@ -1335,7 +1340,8 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, pages += tmppages; pss->page++; - } while (pss->page & (pagesize_bits - 1)); + } while ((pss->page & (pagesize_bits - 1)) && + offset_in_ramblock(pss->block, pss->page << TARGET_PAGE_BITS)); /* The offset we leave with is the last one we looked at */ pss->page--; diff --git a/migration/rdma.c b/migration/rdma.c index 7eaaf96479..166cd60a77 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -20,6 +20,7 @@ #include "migration/migration.h" #include "migration/qemu-file.h" #include "exec/cpu-common.h" +#include "qemu-file-channel.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/sockets.h" diff --git a/migration/savevm.c b/migration/savevm.c index f5e81948e6..d971e5ee47 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -27,7 +27,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/boards.h" #include "hw/hw.h" #include "hw/qdev.h" @@ -36,12 +35,14 @@ #include "sysemu/sysemu.h" #include "qemu/timer.h" #include "migration/migration.h" +#include "qemu-file-channel.h" #include "postcopy-ram.h" #include "qapi/qmp/qerror.h" #include "qemu/error-report.h" #include "qemu/queue.h" #include "sysemu/cpus.h" #include "exec/memory.h" +#include "exec/target_page.h" #include "qmp-commands.h" #include "trace.h" #include "qemu/bitops.h" @@ -286,7 +287,7 @@ static void configuration_pre_save(void *opaque) state->len = strlen(current_name); state->name = current_name; - state->target_page_bits = TARGET_PAGE_BITS; + state->target_page_bits = qemu_target_page_bits(); } static int configuration_pre_load(void *opaque) @@ -297,7 +298,7 @@ static int configuration_pre_load(void *opaque) * predates the variable-target-page-bits support and is using the * minimum possible value for this CPU. */ - state->target_page_bits = TARGET_PAGE_BITS_MIN; + state->target_page_bits = qemu_target_page_bits_min(); return 0; } @@ -312,9 +313,9 @@ static int configuration_post_load(void *opaque, int version_id) return -EINVAL; } - if (state->target_page_bits != TARGET_PAGE_BITS) { + if (state->target_page_bits != qemu_target_page_bits()) { error_report("Received TARGET_PAGE_BITS is %d but local is %d", - state->target_page_bits, TARGET_PAGE_BITS); + state->target_page_bits, qemu_target_page_bits()); return -EINVAL; } @@ -330,7 +331,8 @@ static int configuration_post_load(void *opaque, int version_id) */ static bool vmstate_target_page_bits_needed(void *opaque) { - return TARGET_PAGE_BITS > TARGET_PAGE_BITS_MIN; + return qemu_target_page_bits() + > qemu_target_page_bits_min(); } static const VMStateDescription vmstate_target_page_bits = { @@ -966,21 +968,13 @@ void qemu_savevm_state_header(QEMUFile *f) } -void qemu_savevm_state_begin(QEMUFile *f, - const MigrationParams *params) +void qemu_savevm_state_begin(QEMUFile *f) { SaveStateEntry *se; int ret; trace_savevm_state_begin(); QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { - if (!se->ops || !se->ops->set_params) { - continue; - } - se->ops->set_params(params, se->opaque); - } - - QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { if (!se->ops || !se->ops->save_live_setup) { continue; } @@ -1144,7 +1138,7 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only) } vmdesc = qjson_new(); - json_prop_int(vmdesc, "page_size", TARGET_PAGE_SIZE); + json_prop_int(vmdesc, "page_size", qemu_target_page_size()); json_start_array(vmdesc, "devices"); QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { @@ -1232,11 +1226,7 @@ void qemu_savevm_state_cleanup(void) static int qemu_savevm_state(QEMUFile *f, Error **errp) { int ret; - MigrationParams params = { - .blk = 0, - .shared = 0 - }; - MigrationState *ms = migrate_init(¶ms); + MigrationState *ms = migrate_init(); MigrationStatus status; ms->to_dst_file = f; @@ -1245,9 +1235,15 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) goto done; } + if (migrate_use_block()) { + error_setg(errp, "Block migration and snapshots are incompatible"); + ret = -EINVAL; + goto done; + } + qemu_mutex_unlock_iothread(); qemu_savevm_state_header(f); - qemu_savevm_state_begin(f, ¶ms); + qemu_savevm_state_begin(f); qemu_mutex_lock_iothread(); while (qemu_file_get_error(f) == 0) { diff --git a/migration/socket.c b/migration/socket.c index 1cfbe81e69..53f9d61605 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -19,6 +19,7 @@ #include "qemu-common.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "channel.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "io/channel-socket.h" diff --git a/migration/tls.c b/migration/tls.c index a33ecb767e..34ad121abf 100644 --- a/migration/tls.c +++ b/migration/tls.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "channel.h" #include "migration/migration.h" #include "io/channel-tls.h" #include "crypto/tlscreds.h" diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c new file mode 100644 index 0000000000..cc95e47775 --- /dev/null +++ b/migration/vmstate-types.c @@ -0,0 +1,661 @@ +/* + * VMStateInfo's for basic typse + * + * Copyright (c) 2009-2017 Red Hat Inc + * + * Authors: + * Juan Quintela <quintela@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "migration/migration.h" +#include "migration/qemu-file.h" +#include "migration/vmstate.h" +#include "qemu/error-report.h" +#include "qemu/queue.h" +#include "trace.h" + +/* bool */ + +static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + bool *v = pv; + *v = qemu_get_byte(f); + return 0; +} + +static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + bool *v = pv; + qemu_put_byte(f, *v); + return 0; +} + +const VMStateInfo vmstate_info_bool = { + .name = "bool", + .get = get_bool, + .put = put_bool, +}; + +/* 8 bit int */ + +static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + int8_t *v = pv; + qemu_get_s8s(f, v); + return 0; +} + +static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + int8_t *v = pv; + qemu_put_s8s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_int8 = { + .name = "int8", + .get = get_int8, + .put = put_int8, +}; + +/* 16 bit int */ + +static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + int16_t *v = pv; + qemu_get_sbe16s(f, v); + return 0; +} + +static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + int16_t *v = pv; + qemu_put_sbe16s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_int16 = { + .name = "int16", + .get = get_int16, + .put = put_int16, +}; + +/* 32 bit int */ + +static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + int32_t *v = pv; + qemu_get_sbe32s(f, v); + return 0; +} + +static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + int32_t *v = pv; + qemu_put_sbe32s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_int32 = { + .name = "int32", + .get = get_int32, + .put = put_int32, +}; + +/* 32 bit int. See that the received value is the same than the one + in the field */ + +static int get_int32_equal(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + int32_t *v = pv; + int32_t v2; + qemu_get_sbe32s(f, &v2); + + if (*v == v2) { + return 0; + } + error_report("%" PRIx32 " != %" PRIx32, *v, v2); + return -EINVAL; +} + +const VMStateInfo vmstate_info_int32_equal = { + .name = "int32 equal", + .get = get_int32_equal, + .put = put_int32, +}; + +/* 32 bit int. Check that the received value is non-negative + * and less than or equal to the one in the field. + */ + +static int get_int32_le(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + int32_t *cur = pv; + int32_t loaded; + qemu_get_sbe32s(f, &loaded); + + if (loaded >= 0 && loaded <= *cur) { + *cur = loaded; + return 0; + } + error_report("Invalid value %" PRId32 + " expecting positive value <= %" PRId32, + loaded, *cur); + return -EINVAL; +} + +const VMStateInfo vmstate_info_int32_le = { + .name = "int32 le", + .get = get_int32_le, + .put = put_int32, +}; + +/* 64 bit int */ + +static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + int64_t *v = pv; + qemu_get_sbe64s(f, v); + return 0; +} + +static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + int64_t *v = pv; + qemu_put_sbe64s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_int64 = { + .name = "int64", + .get = get_int64, + .put = put_int64, +}; + +/* 8 bit unsigned int */ + +static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + uint8_t *v = pv; + qemu_get_8s(f, v); + return 0; +} + +static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + uint8_t *v = pv; + qemu_put_8s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_uint8 = { + .name = "uint8", + .get = get_uint8, + .put = put_uint8, +}; + +/* 16 bit unsigned int */ + +static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + uint16_t *v = pv; + qemu_get_be16s(f, v); + return 0; +} + +static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + uint16_t *v = pv; + qemu_put_be16s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_uint16 = { + .name = "uint16", + .get = get_uint16, + .put = put_uint16, +}; + +/* 32 bit unsigned int */ + +static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + uint32_t *v = pv; + qemu_get_be32s(f, v); + return 0; +} + +static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + uint32_t *v = pv; + qemu_put_be32s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_uint32 = { + .name = "uint32", + .get = get_uint32, + .put = put_uint32, +}; + +/* 32 bit uint. See that the received value is the same than the one + in the field */ + +static int get_uint32_equal(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + uint32_t *v = pv; + uint32_t v2; + qemu_get_be32s(f, &v2); + + if (*v == v2) { + return 0; + } + error_report("%" PRIx32 " != %" PRIx32, *v, v2); + return -EINVAL; +} + +const VMStateInfo vmstate_info_uint32_equal = { + .name = "uint32 equal", + .get = get_uint32_equal, + .put = put_uint32, +}; + +/* 64 bit unsigned int */ + +static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + uint64_t *v = pv; + qemu_get_be64s(f, v); + return 0; +} + +static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + uint64_t *v = pv; + qemu_put_be64s(f, v); + return 0; +} + +const VMStateInfo vmstate_info_uint64 = { + .name = "uint64", + .get = get_uint64, + .put = put_uint64, +}; + +static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field) + +{ + if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) { + return 0; + } + error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER"); + return -EINVAL; +} + +static int put_nullptr(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) + +{ + if (pv == NULL) { + qemu_put_byte(f, VMS_NULLPTR_MARKER); + return 0; + } + error_report("vmstate: put_nullptr must be called with pv == NULL"); + return -EINVAL; +} + +const VMStateInfo vmstate_info_nullptr = { + .name = "uint64", + .get = get_nullptr, + .put = put_nullptr, +}; + +/* 64 bit unsigned int. See that the received value is the same than the one + in the field */ + +static int get_uint64_equal(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + uint64_t *v = pv; + uint64_t v2; + qemu_get_be64s(f, &v2); + + if (*v == v2) { + return 0; + } + error_report("%" PRIx64 " != %" PRIx64, *v, v2); + return -EINVAL; +} + +const VMStateInfo vmstate_info_uint64_equal = { + .name = "int64 equal", + .get = get_uint64_equal, + .put = put_uint64, +}; + +/* 8 bit int. See that the received value is the same than the one + in the field */ + +static int get_uint8_equal(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + uint8_t *v = pv; + uint8_t v2; + qemu_get_8s(f, &v2); + + if (*v == v2) { + return 0; + } + error_report("%x != %x", *v, v2); + return -EINVAL; +} + +const VMStateInfo vmstate_info_uint8_equal = { + .name = "uint8 equal", + .get = get_uint8_equal, + .put = put_uint8, +}; + +/* 16 bit unsigned int int. See that the received value is the same than the one + in the field */ + +static int get_uint16_equal(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + uint16_t *v = pv; + uint16_t v2; + qemu_get_be16s(f, &v2); + + if (*v == v2) { + return 0; + } + error_report("%x != %x", *v, v2); + return -EINVAL; +} + +const VMStateInfo vmstate_info_uint16_equal = { + .name = "uint16 equal", + .get = get_uint16_equal, + .put = put_uint16, +}; + +/* floating point */ + +static int get_float64(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + float64 *v = pv; + + *v = make_float64(qemu_get_be64(f)); + return 0; +} + +static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + uint64_t *v = pv; + + qemu_put_be64(f, float64_val(*v)); + return 0; +} + +const VMStateInfo vmstate_info_float64 = { + .name = "float64", + .get = get_float64, + .put = put_float64, +}; + +/* CPU_DoubleU type */ + +static int get_cpudouble(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + CPU_DoubleU *v = pv; + qemu_get_be32s(f, &v->l.upper); + qemu_get_be32s(f, &v->l.lower); + return 0; +} + +static int put_cpudouble(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) +{ + CPU_DoubleU *v = pv; + qemu_put_be32s(f, &v->l.upper); + qemu_put_be32s(f, &v->l.lower); + return 0; +} + +const VMStateInfo vmstate_info_cpudouble = { + .name = "CPU_Double_U", + .get = get_cpudouble, + .put = put_cpudouble, +}; + +/* uint8_t buffers */ + +static int get_buffer(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + uint8_t *v = pv; + qemu_get_buffer(f, v, size); + return 0; +} + +static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + uint8_t *v = pv; + qemu_put_buffer(f, v, size); + return 0; +} + +const VMStateInfo vmstate_info_buffer = { + .name = "buffer", + .get = get_buffer, + .put = put_buffer, +}; + +/* unused buffers: space that was used for some fields that are + not useful anymore */ + +static int get_unused_buffer(QEMUFile *f, void *pv, size_t size, + VMStateField *field) +{ + uint8_t buf[1024]; + int block_len; + + while (size > 0) { + block_len = MIN(sizeof(buf), size); + size -= block_len; + qemu_get_buffer(f, buf, block_len); + } + return 0; +} + +static int put_unused_buffer(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) +{ + static const uint8_t buf[1024]; + int block_len; + + while (size > 0) { + block_len = MIN(sizeof(buf), size); + size -= block_len; + qemu_put_buffer(f, buf, block_len); + } + + return 0; +} + +const VMStateInfo vmstate_info_unused_buffer = { + .name = "unused_buffer", + .get = get_unused_buffer, + .put = put_unused_buffer, +}; + +/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate + * a temporary buffer and the pre_load/pre_save methods in the child vmsd + * copy stuff from the parent into the child and do calculations to fill + * in fields that don't really exist in the parent but need to be in the + * stream. + */ +static int get_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + int ret; + const VMStateDescription *vmsd = field->vmsd; + int version_id = field->version_id; + void *tmp = g_malloc(size); + + /* Writes the parent field which is at the start of the tmp */ + *(void **)tmp = pv; + ret = vmstate_load_state(f, vmsd, tmp, version_id); + g_free(tmp); + return ret; +} + +static int put_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + const VMStateDescription *vmsd = field->vmsd; + void *tmp = g_malloc(size); + + /* Writes the parent field which is at the start of the tmp */ + *(void **)tmp = pv; + vmstate_save_state(f, vmsd, tmp, vmdesc); + g_free(tmp); + + return 0; +} + +const VMStateInfo vmstate_info_tmp = { + .name = "tmp", + .get = get_tmp, + .put = put_tmp, +}; + +/* bitmaps (as defined by bitmap.h). Note that size here is the size + * of the bitmap in bits. The on-the-wire format of a bitmap is 64 + * bit words with the bits in big endian order. The in-memory format + * is an array of 'unsigned long', which may be either 32 or 64 bits. + */ +/* This is the number of 64 bit words sent over the wire */ +#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64) +static int get_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field) +{ + unsigned long *bmp = pv; + int i, idx = 0; + for (i = 0; i < BITS_TO_U64S(size); i++) { + uint64_t w = qemu_get_be64(f); + bmp[idx++] = w; + if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) { + bmp[idx++] = w >> 32; + } + } + return 0; +} + +static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) +{ + unsigned long *bmp = pv; + int i, idx = 0; + for (i = 0; i < BITS_TO_U64S(size); i++) { + uint64_t w = bmp[idx++]; + if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) { + w |= ((uint64_t)bmp[idx++]) << 32; + } + qemu_put_be64(f, w); + } + + return 0; +} + +const VMStateInfo vmstate_info_bitmap = { + .name = "bitmap", + .get = get_bitmap, + .put = put_bitmap, +}; + +/* get for QTAILQ + * meta data about the QTAILQ is encoded in a VMStateField structure + */ +static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size, + VMStateField *field) +{ + int ret = 0; + const VMStateDescription *vmsd = field->vmsd; + /* size of a QTAILQ element */ + size_t size = field->size; + /* offset of the QTAILQ entry in a QTAILQ element */ + size_t entry_offset = field->start; + int version_id = field->version_id; + void *elm; + + trace_get_qtailq(vmsd->name, version_id); + if (version_id > vmsd->version_id) { + error_report("%s %s", vmsd->name, "too new"); + trace_get_qtailq_end(vmsd->name, "too new", -EINVAL); + + return -EINVAL; + } + if (version_id < vmsd->minimum_version_id) { + error_report("%s %s", vmsd->name, "too old"); + trace_get_qtailq_end(vmsd->name, "too old", -EINVAL); + return -EINVAL; + } + + while (qemu_get_byte(f)) { + elm = g_malloc(size); + ret = vmstate_load_state(f, vmsd, elm, version_id); + if (ret) { + return ret; + } + QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset); + } + + trace_get_qtailq_end(vmsd->name, "end", ret); + return ret; +} + +/* put for QTAILQ */ +static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size, + VMStateField *field, QJSON *vmdesc) +{ + const VMStateDescription *vmsd = field->vmsd; + /* offset of the QTAILQ entry in a QTAILQ element*/ + size_t entry_offset = field->start; + void *elm; + + trace_put_qtailq(vmsd->name, vmsd->version_id); + + QTAILQ_RAW_FOREACH(elm, pv, entry_offset) { + qemu_put_byte(f, true); + vmstate_save_state(f, vmsd, elm, vmdesc); + } + qemu_put_byte(f, false); + + trace_put_qtailq_end(vmsd->name, "end"); + + return 0; +} +const VMStateInfo vmstate_info_qtailq = { + .name = "qtailq", + .get = get_qtailq, + .put = put_qtailq, +}; diff --git a/migration/vmstate.c b/migration/vmstate.c index 7b4a607c51..ff54531b44 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -1,3 +1,15 @@ +/* + * VMState interpreter + * + * Copyright (c) 2009-2017 Red Hat Inc + * + * Authors: + * Juan Quintela <quintela@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + #include "qemu/osdep.h" #include "qemu-common.h" #include "migration/migration.h" @@ -5,9 +17,8 @@ #include "migration/vmstate.h" #include "qemu/bitops.h" #include "qemu/error-report.h" -#include "qemu/queue.h" #include "trace.h" -#include "migration/qjson.h" +#include "qjson.h" static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, QJSON *vmdesc); @@ -475,644 +486,3 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, json_end_array(vmdesc); } } - -/* bool */ - -static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - bool *v = pv; - *v = qemu_get_byte(f); - return 0; -} - -static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - bool *v = pv; - qemu_put_byte(f, *v); - return 0; -} - -const VMStateInfo vmstate_info_bool = { - .name = "bool", - .get = get_bool, - .put = put_bool, -}; - -/* 8 bit int */ - -static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - int8_t *v = pv; - qemu_get_s8s(f, v); - return 0; -} - -static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - int8_t *v = pv; - qemu_put_s8s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_int8 = { - .name = "int8", - .get = get_int8, - .put = put_int8, -}; - -/* 16 bit int */ - -static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - int16_t *v = pv; - qemu_get_sbe16s(f, v); - return 0; -} - -static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - int16_t *v = pv; - qemu_put_sbe16s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_int16 = { - .name = "int16", - .get = get_int16, - .put = put_int16, -}; - -/* 32 bit int */ - -static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - int32_t *v = pv; - qemu_get_sbe32s(f, v); - return 0; -} - -static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - int32_t *v = pv; - qemu_put_sbe32s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_int32 = { - .name = "int32", - .get = get_int32, - .put = put_int32, -}; - -/* 32 bit int. See that the received value is the same than the one - in the field */ - -static int get_int32_equal(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - int32_t *v = pv; - int32_t v2; - qemu_get_sbe32s(f, &v2); - - if (*v == v2) { - return 0; - } - error_report("%" PRIx32 " != %" PRIx32, *v, v2); - return -EINVAL; -} - -const VMStateInfo vmstate_info_int32_equal = { - .name = "int32 equal", - .get = get_int32_equal, - .put = put_int32, -}; - -/* 32 bit int. Check that the received value is non-negative - * and less than or equal to the one in the field. - */ - -static int get_int32_le(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - int32_t *cur = pv; - int32_t loaded; - qemu_get_sbe32s(f, &loaded); - - if (loaded >= 0 && loaded <= *cur) { - *cur = loaded; - return 0; - } - error_report("Invalid value %" PRId32 - " expecting positive value <= %" PRId32, - loaded, *cur); - return -EINVAL; -} - -const VMStateInfo vmstate_info_int32_le = { - .name = "int32 le", - .get = get_int32_le, - .put = put_int32, -}; - -/* 64 bit int */ - -static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - int64_t *v = pv; - qemu_get_sbe64s(f, v); - return 0; -} - -static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - int64_t *v = pv; - qemu_put_sbe64s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_int64 = { - .name = "int64", - .get = get_int64, - .put = put_int64, -}; - -/* 8 bit unsigned int */ - -static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - uint8_t *v = pv; - qemu_get_8s(f, v); - return 0; -} - -static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - uint8_t *v = pv; - qemu_put_8s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_uint8 = { - .name = "uint8", - .get = get_uint8, - .put = put_uint8, -}; - -/* 16 bit unsigned int */ - -static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - uint16_t *v = pv; - qemu_get_be16s(f, v); - return 0; -} - -static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - uint16_t *v = pv; - qemu_put_be16s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_uint16 = { - .name = "uint16", - .get = get_uint16, - .put = put_uint16, -}; - -/* 32 bit unsigned int */ - -static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - uint32_t *v = pv; - qemu_get_be32s(f, v); - return 0; -} - -static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - uint32_t *v = pv; - qemu_put_be32s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_uint32 = { - .name = "uint32", - .get = get_uint32, - .put = put_uint32, -}; - -/* 32 bit uint. See that the received value is the same than the one - in the field */ - -static int get_uint32_equal(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - uint32_t *v = pv; - uint32_t v2; - qemu_get_be32s(f, &v2); - - if (*v == v2) { - return 0; - } - error_report("%" PRIx32 " != %" PRIx32, *v, v2); - return -EINVAL; -} - -const VMStateInfo vmstate_info_uint32_equal = { - .name = "uint32 equal", - .get = get_uint32_equal, - .put = put_uint32, -}; - -/* 64 bit unsigned int */ - -static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - uint64_t *v = pv; - qemu_get_be64s(f, v); - return 0; -} - -static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - uint64_t *v = pv; - qemu_put_be64s(f, v); - return 0; -} - -const VMStateInfo vmstate_info_uint64 = { - .name = "uint64", - .get = get_uint64, - .put = put_uint64, -}; - -static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field) - -{ - if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) { - return 0; - } - error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER"); - return -EINVAL; -} - -static int put_nullptr(QEMUFile *f, void *pv, size_t size, - VMStateField *field, QJSON *vmdesc) - -{ - if (pv == NULL) { - qemu_put_byte(f, VMS_NULLPTR_MARKER); - return 0; - } - error_report("vmstate: put_nullptr must be called with pv == NULL"); - return -EINVAL; -} - -const VMStateInfo vmstate_info_nullptr = { - .name = "uint64", - .get = get_nullptr, - .put = put_nullptr, -}; - -/* 64 bit unsigned int. See that the received value is the same than the one - in the field */ - -static int get_uint64_equal(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - uint64_t *v = pv; - uint64_t v2; - qemu_get_be64s(f, &v2); - - if (*v == v2) { - return 0; - } - error_report("%" PRIx64 " != %" PRIx64, *v, v2); - return -EINVAL; -} - -const VMStateInfo vmstate_info_uint64_equal = { - .name = "int64 equal", - .get = get_uint64_equal, - .put = put_uint64, -}; - -/* 8 bit int. See that the received value is the same than the one - in the field */ - -static int get_uint8_equal(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - uint8_t *v = pv; - uint8_t v2; - qemu_get_8s(f, &v2); - - if (*v == v2) { - return 0; - } - error_report("%x != %x", *v, v2); - return -EINVAL; -} - -const VMStateInfo vmstate_info_uint8_equal = { - .name = "uint8 equal", - .get = get_uint8_equal, - .put = put_uint8, -}; - -/* 16 bit unsigned int int. See that the received value is the same than the one - in the field */ - -static int get_uint16_equal(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - uint16_t *v = pv; - uint16_t v2; - qemu_get_be16s(f, &v2); - - if (*v == v2) { - return 0; - } - error_report("%x != %x", *v, v2); - return -EINVAL; -} - -const VMStateInfo vmstate_info_uint16_equal = { - .name = "uint16 equal", - .get = get_uint16_equal, - .put = put_uint16, -}; - -/* floating point */ - -static int get_float64(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - float64 *v = pv; - - *v = make_float64(qemu_get_be64(f)); - return 0; -} - -static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - uint64_t *v = pv; - - qemu_put_be64(f, float64_val(*v)); - return 0; -} - -const VMStateInfo vmstate_info_float64 = { - .name = "float64", - .get = get_float64, - .put = put_float64, -}; - -/* CPU_DoubleU type */ - -static int get_cpudouble(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - CPU_DoubleU *v = pv; - qemu_get_be32s(f, &v->l.upper); - qemu_get_be32s(f, &v->l.lower); - return 0; -} - -static int put_cpudouble(QEMUFile *f, void *pv, size_t size, - VMStateField *field, QJSON *vmdesc) -{ - CPU_DoubleU *v = pv; - qemu_put_be32s(f, &v->l.upper); - qemu_put_be32s(f, &v->l.lower); - return 0; -} - -const VMStateInfo vmstate_info_cpudouble = { - .name = "CPU_Double_U", - .get = get_cpudouble, - .put = put_cpudouble, -}; - -/* uint8_t buffers */ - -static int get_buffer(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - uint8_t *v = pv; - qemu_get_buffer(f, v, size); - return 0; -} - -static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - uint8_t *v = pv; - qemu_put_buffer(f, v, size); - return 0; -} - -const VMStateInfo vmstate_info_buffer = { - .name = "buffer", - .get = get_buffer, - .put = put_buffer, -}; - -/* unused buffers: space that was used for some fields that are - not useful anymore */ - -static int get_unused_buffer(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - uint8_t buf[1024]; - int block_len; - - while (size > 0) { - block_len = MIN(sizeof(buf), size); - size -= block_len; - qemu_get_buffer(f, buf, block_len); - } - return 0; -} - -static int put_unused_buffer(QEMUFile *f, void *pv, size_t size, - VMStateField *field, QJSON *vmdesc) -{ - static const uint8_t buf[1024]; - int block_len; - - while (size > 0) { - block_len = MIN(sizeof(buf), size); - size -= block_len; - qemu_put_buffer(f, buf, block_len); - } - - return 0; -} - -const VMStateInfo vmstate_info_unused_buffer = { - .name = "unused_buffer", - .get = get_unused_buffer, - .put = put_unused_buffer, -}; - -/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate - * a temporary buffer and the pre_load/pre_save methods in the child vmsd - * copy stuff from the parent into the child and do calculations to fill - * in fields that don't really exist in the parent but need to be in the - * stream. - */ -static int get_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - int ret; - const VMStateDescription *vmsd = field->vmsd; - int version_id = field->version_id; - void *tmp = g_malloc(size); - - /* Writes the parent field which is at the start of the tmp */ - *(void **)tmp = pv; - ret = vmstate_load_state(f, vmsd, tmp, version_id); - g_free(tmp); - return ret; -} - -static int put_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - const VMStateDescription *vmsd = field->vmsd; - void *tmp = g_malloc(size); - - /* Writes the parent field which is at the start of the tmp */ - *(void **)tmp = pv; - vmstate_save_state(f, vmsd, tmp, vmdesc); - g_free(tmp); - - return 0; -} - -const VMStateInfo vmstate_info_tmp = { - .name = "tmp", - .get = get_tmp, - .put = put_tmp, -}; - -/* bitmaps (as defined by bitmap.h). Note that size here is the size - * of the bitmap in bits. The on-the-wire format of a bitmap is 64 - * bit words with the bits in big endian order. The in-memory format - * is an array of 'unsigned long', which may be either 32 or 64 bits. - */ -/* This is the number of 64 bit words sent over the wire */ -#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64) -static int get_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field) -{ - unsigned long *bmp = pv; - int i, idx = 0; - for (i = 0; i < BITS_TO_U64S(size); i++) { - uint64_t w = qemu_get_be64(f); - bmp[idx++] = w; - if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) { - bmp[idx++] = w >> 32; - } - } - return 0; -} - -static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field, - QJSON *vmdesc) -{ - unsigned long *bmp = pv; - int i, idx = 0; - for (i = 0; i < BITS_TO_U64S(size); i++) { - uint64_t w = bmp[idx++]; - if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) { - w |= ((uint64_t)bmp[idx++]) << 32; - } - qemu_put_be64(f, w); - } - - return 0; -} - -const VMStateInfo vmstate_info_bitmap = { - .name = "bitmap", - .get = get_bitmap, - .put = put_bitmap, -}; - -/* get for QTAILQ - * meta data about the QTAILQ is encoded in a VMStateField structure - */ -static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size, - VMStateField *field) -{ - int ret = 0; - const VMStateDescription *vmsd = field->vmsd; - /* size of a QTAILQ element */ - size_t size = field->size; - /* offset of the QTAILQ entry in a QTAILQ element */ - size_t entry_offset = field->start; - int version_id = field->version_id; - void *elm; - - trace_get_qtailq(vmsd->name, version_id); - if (version_id > vmsd->version_id) { - error_report("%s %s", vmsd->name, "too new"); - trace_get_qtailq_end(vmsd->name, "too new", -EINVAL); - - return -EINVAL; - } - if (version_id < vmsd->minimum_version_id) { - error_report("%s %s", vmsd->name, "too old"); - trace_get_qtailq_end(vmsd->name, "too old", -EINVAL); - return -EINVAL; - } - - while (qemu_get_byte(f)) { - elm = g_malloc(size); - ret = vmstate_load_state(f, vmsd, elm, version_id); - if (ret) { - return ret; - } - QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset); - } - - trace_get_qtailq_end(vmsd->name, "end", ret); - return ret; -} - -/* put for QTAILQ */ -static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size, - VMStateField *field, QJSON *vmdesc) -{ - const VMStateDescription *vmsd = field->vmsd; - /* offset of the QTAILQ entry in a QTAILQ element*/ - size_t entry_offset = field->start; - void *elm; - - trace_put_qtailq(vmsd->name, vmsd->version_id); - - QTAILQ_RAW_FOREACH(elm, pv, entry_offset) { - qemu_put_byte(f, true); - vmstate_save_state(f, vmsd, elm, vmdesc); - } - qemu_put_byte(f, false); - - trace_put_qtailq_end(vmsd->name, "end"); - - return 0; -} -const VMStateInfo vmstate_info_qtailq = { - .name = "qtailq", - .get = get_qtailq, - .put = put_qtailq, -}; diff --git a/migration/xbzrle.c b/migration/xbzrle.c index c858339259..1ba482ded9 100644 --- a/migration/xbzrle.c +++ b/migration/xbzrle.c @@ -12,7 +12,7 @@ */ #include "qemu/osdep.h" #include "qemu/cutils.h" -#include "include/migration/migration.h" +#include "xbzrle.h" /* page = zrun nzrun diff --git a/migration/xbzrle.h b/migration/xbzrle.h new file mode 100644 index 0000000000..a0db507b9c --- /dev/null +++ b/migration/xbzrle.h @@ -0,0 +1,21 @@ +/* + * QEMU live migration + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_MIGRATION_XBZRLE_H +#define QEMU_MIGRATION_XBZRLE_H + +int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen, + uint8_t *dst, int dlen); + +int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen); +#endif diff --git a/monitor.c b/monitor.c index afbacfe1cb..baa73c98b7 100644 --- a/monitor.c +++ b/monitor.c @@ -49,7 +49,6 @@ #include "disas/disas.h" #include "sysemu/balloon.h" #include "qemu/timer.h" -#include "migration/migration.h" #include "sysemu/hw_accel.h" #include "qemu/acl.h" #include "sysemu/tpm.h" diff --git a/net/Makefile.objs b/net/Makefile.objs index 2e2fd43014..67ba5e26fb 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -3,13 +3,7 @@ common-obj-y += socket.o common-obj-y += dump.o common-obj-y += eth.o common-obj-$(CONFIG_L2TPV3) += l2tpv3.o -common-obj-$(CONFIG_POSIX) += tap.o vhost-user.o -common-obj-$(CONFIG_LINUX) += tap-linux.o -common-obj-$(CONFIG_WIN32) += tap-win32.o -common-obj-$(CONFIG_BSD) += tap-bsd.o -common-obj-$(CONFIG_SOLARIS) += tap-solaris.o -common-obj-$(CONFIG_AIX) += tap-aix.o -common-obj-$(CONFIG_HAIKU) += tap-haiku.o +common-obj-$(CONFIG_POSIX) += vhost-user.o common-obj-$(CONFIG_SLIRP) += slirp.o common-obj-$(CONFIG_VDE) += vde.o common-obj-$(CONFIG_NETMAP) += netmap.o @@ -20,3 +14,10 @@ common-obj-y += colo-compare.o common-obj-y += colo.o common-obj-y += filter-rewriter.o common-obj-y += filter-replay.o + +tap-obj-$(CONFIG_LINUX) = tap-linux.o +tap-obj-$(CONFIG_BSD) = tap-bsd.o +tap-obj-$(CONFIG_SOLARIS) = tap-solaris.o +tap-obj-y ?= tap-stub.o +common-obj-$(CONFIG_POSIX) += tap.o $(tap-obj-y) +common-obj-$(CONFIG_WIN32) += tap-win32.o diff --git a/net/colo-compare.c b/net/colo-compare.c index 4ab80b1cbb..2639c7f0a2 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -265,17 +265,28 @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt) } if (res != 0 && trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) { - trace_colo_compare_pkt_info_src(inet_ntoa(ppkt->ip->ip_src), - ntohl(stcp->th_seq), - ntohl(stcp->th_ack), - res, stcp->th_flags, - spkt->size); - - trace_colo_compare_pkt_info_dst(inet_ntoa(ppkt->ip->ip_dst), - ntohl(ptcp->th_seq), - ntohl(ptcp->th_ack), - res, ptcp->th_flags, - ppkt->size); + char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20]; + + strcpy(pri_ip_src, inet_ntoa(ppkt->ip->ip_src)); + strcpy(pri_ip_dst, inet_ntoa(ppkt->ip->ip_dst)); + strcpy(sec_ip_src, inet_ntoa(spkt->ip->ip_src)); + strcpy(sec_ip_dst, inet_ntoa(spkt->ip->ip_dst)); + + trace_colo_compare_ip_info(ppkt->size, pri_ip_src, + pri_ip_dst, spkt->size, + sec_ip_src, sec_ip_dst); + + trace_colo_compare_tcp_info("pri tcp packet", + ntohl(ptcp->th_seq), + ntohl(ptcp->th_ack), + res, ptcp->th_flags, + ppkt->size); + + trace_colo_compare_tcp_info("sec tcp packet", + ntohl(stcp->th_seq), + ntohl(stcp->th_ack), + res, stcp->th_flags, + spkt->size); qemu_hexdump((char *)ppkt->data, stderr, "colo-compare ppkt", ppkt->size); diff --git a/net/dump.c b/net/dump.c index 89a149b5dd..442eb532f9 100644 --- a/net/dump.c +++ b/net/dump.c @@ -194,6 +194,9 @@ int net_init_dump(const Netdev *netdev, const char *name, assert(peer); + error_report("'-net dump' is deprecated. " + "Please use '-object filter-dump' instead."); + if (dump->has_file) { file = dump->file; } else { diff --git a/net/filter-mirror.c b/net/filter-mirror.c index 72fa7c2b6c..8b1b06977d 100644 --- a/net/filter-mirror.c +++ b/net/filter-mirror.c @@ -43,9 +43,9 @@ typedef struct MirrorState { SocketReadState rs; } MirrorState; -static int filter_mirror_send(CharBackend *chr_out, - const struct iovec *iov, - int iovcnt) +static int filter_send(CharBackend *chr_out, + const struct iovec *iov, + int iovcnt) { int ret = 0; ssize_t size = 0; @@ -141,9 +141,9 @@ static ssize_t filter_mirror_receive_iov(NetFilterState *nf, MirrorState *s = FILTER_MIRROR(nf); int ret; - ret = filter_mirror_send(&s->chr_out, iov, iovcnt); + ret = filter_send(&s->chr_out, iov, iovcnt); if (ret) { - error_report("filter_mirror_send failed(%s)", strerror(-ret)); + error_report("filter mirror send failed(%s)", strerror(-ret)); } /* @@ -164,9 +164,9 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf, int ret; if (qemu_chr_fe_get_driver(&s->chr_out)) { - ret = filter_mirror_send(&s->chr_out, iov, iovcnt); + ret = filter_send(&s->chr_out, iov, iovcnt); if (ret) { - error_report("filter_mirror_send failed(%s)", strerror(-ret)); + error_report("filter redirector send failed(%s)", strerror(-ret)); } return iov_size(iov, iovcnt); } else { @@ -194,12 +194,6 @@ static void filter_mirror_setup(NetFilterState *nf, Error **errp) MirrorState *s = FILTER_MIRROR(nf); Chardev *chr; - if (!s->outdev) { - error_setg(errp, "filter mirror needs 'outdev' " - "property set"); - return; - } - chr = qemu_chr_find(s->outdev); if (chr == NULL) { error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, @@ -292,8 +286,9 @@ static char *filter_redirector_get_indev(Object *obj, Error **errp) return g_strdup(s->indev); } -static void -filter_redirector_set_indev(Object *obj, const char *value, Error **errp) +static void filter_redirector_set_indev(Object *obj, + const char *value, + Error **errp) { MirrorState *s = FILTER_REDIRECTOR(obj); @@ -308,8 +303,9 @@ static char *filter_mirror_get_outdev(Object *obj, Error **errp) return g_strdup(s->outdev); } -static void -filter_mirror_set_outdev(Object *obj, const char *value, Error **errp) +static void filter_mirror_set_outdev(Object *obj, + const char *value, + Error **errp) { MirrorState *s = FILTER_MIRROR(obj); @@ -329,8 +325,9 @@ static char *filter_redirector_get_outdev(Object *obj, Error **errp) return g_strdup(s->outdev); } -static void -filter_redirector_set_outdev(Object *obj, const char *value, Error **errp) +static void filter_redirector_set_outdev(Object *obj, + const char *value, + Error **errp) { MirrorState *s = FILTER_REDIRECTOR(obj); diff --git a/net/net.c b/net/net.c index 0ac3b9e80c..6235aabed8 100644 --- a/net/net.c +++ b/net/net.c @@ -45,6 +45,7 @@ #include "qapi-visit.h" #include "qapi/opts-visitor.h" #include "sysemu/sysemu.h" +#include "sysemu/qtest.h" #include "net/filter.h" #include "qapi/string-output-visitor.h" @@ -1149,6 +1150,12 @@ void hmp_host_net_add(Monitor *mon, const QDict *qdict) const char *opts_str = qdict_get_try_str(qdict, "opts"); Error *local_err = NULL; QemuOpts *opts; + static bool warned; + + if (!warned && !qtest_enabled()) { + error_report("host_net_add is deprecated, use netdev_add instead"); + warned = true; + } if (!net_host_check_device(device)) { monitor_printf(mon, "invalid host network device %s\n", device); @@ -1175,6 +1182,12 @@ void hmp_host_net_remove(Monitor *mon, const QDict *qdict) NetClientState *nc; int vlan_id = qdict_get_int(qdict, "vlan_id"); const char *device = qdict_get_str(qdict, "device"); + static bool warned; + + if (!warned && !qtest_enabled()) { + error_report("host_net_remove is deprecated, use netdev_del instead"); + warned = true; + } nc = net_hub_find_client_by_name(vlan_id, device); if (!nc) { diff --git a/net/tap-aix.c b/net/tap-stub.c index 0e6da63963..a9ab8f8293 100644 --- a/net/tap-aix.c +++ b/net/tap-stub.c @@ -29,7 +29,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required, int mq_required, Error **errp) { - error_setg(errp, "no tap on AIX"); + error_setg(errp, "tap is not supported in this build"); return -1; } @@ -85,4 +85,3 @@ int tap_fd_get_ifname(int fd, char *ifname) { return -1; } - diff --git a/net/trace-events b/net/trace-events index 35198bc742..247e5c04db 100644 --- a/net/trace-events +++ b/net/trace-events @@ -13,8 +13,7 @@ colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d" colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" colo_old_packet_check_found(int64_t old_time) "%" PRId64 colo_compare_miscompare(void) "" -colo_compare_pkt_info_src(const char *src, uint32_t sseq, uint32_t sack, int res, uint32_t sflag, int ssize) "src/dst: %s s: seq/ack=%u/%u res=%d flags=%x spkt_size: %d\n" -colo_compare_pkt_info_dst(const char *dst, uint32_t dseq, uint32_t dack, int res, uint32_t dflag, int dsize) "src/dst: %s d: seq/ack=%u/%u res=%d flags=%x dpkt_size: %d\n" +colo_compare_tcp_info(const char *pkt, uint32_t seq, uint32_t ack, int res, uint32_t flag, int size) "side: %s seq/ack= %u/%u res= %d flags= %x pkt_size: %d\n" # net/filter-rewriter.c colo_filter_rewriter_debug(void) "" diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index ed9a51e738..a4d9b2ca23 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc Binary files differdiff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 1cf43dbe1d..767e0af5b2 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 Binary files differdiff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 281d20d604..0c1048a83b 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 Binary files differdiff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 0b01d49495..5ad0564000 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img Binary files differdiff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 07d8cbcb20..2089274842 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -42,6 +42,13 @@ typedef unsigned long long __u64; #ifndef NULL #define NULL 0 #endif +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MIN_NON_ZERO +#define MIN_NON_ZERO(a, b) ((a) == 0 ? (b) : \ + ((b) == 0 ? (a) : (MIN(a, b)))) +#endif #include "cio.h" #include "iplb.h" diff --git a/pc-bios/s390-ccw/scsi.h b/pc-bios/s390-ccw/scsi.h index fc830f7e52..fe3fd5ac05 100644 --- a/pc-bios/s390-ccw/scsi.h +++ b/pc-bios/s390-ccw/scsi.h @@ -26,6 +26,15 @@ #define SCSI_SENSE_KEY_NO_SENSE 0 #define SCSI_SENSE_KEY_UNIT_ATTENTION 6 +/* SCSI Inquiry Types */ +#define SCSI_INQUIRY_STANDARD 0x00U +#define SCSI_INQUIRY_EVPD 0x01U + +/* SCSI Inquiry Pages */ +#define SCSI_INQUIRY_STANDARD_NONE 0x00U +#define SCSI_INQUIRY_EVPD_SUPPORTED_PAGES 0x00U +#define SCSI_INQUIRY_EVPD_BLOCK_LIMITS 0xb0U + union ScsiLun { uint64_t v64; /* numeric shortcut */ uint8_t v8[8]; /* generic 8 bytes representation */ @@ -71,6 +80,27 @@ struct ScsiInquiryStd { } __attribute__((packed)); typedef struct ScsiInquiryStd ScsiInquiryStd; +struct ScsiInquiryEvpdPages { + uint8_t peripheral_qdt; /* b0, use (b0 & 0x1f) to get SCSI_INQ_RDT */ + uint8_t page_code; /* b1 */ + uint16_t page_length; /* b2..b3 length = N-3 */ + uint8_t byte[28]; /* b4..bN Supported EVPD pages (N=31 here) */ +} __attribute__((packed)); +typedef struct ScsiInquiryEvpdPages ScsiInquiryEvpdPages; + +struct ScsiInquiryEvpdBl { + uint8_t peripheral_qdt; /* b0, use (b0 & 0x1f) to get SCSI_INQ_RDT */ + uint8_t page_code; + uint16_t page_length; + uint8_t b4; + uint8_t b5; + uint16_t b6; + uint32_t max_transfer; /* b8 */ + uint32_t b12[7]; /* b12..b43 (defined fields) */ + uint32_t b44[5]; /* b44..b63 (reserved fields) */ +} __attribute__((packed)); +typedef struct ScsiInquiryEvpdBl ScsiInquiryEvpdBl; + struct ScsiCdbInquiry { uint8_t command; /* b0, == 0x12 */ uint8_t b1; /* b1, |= 0x01 (evpd) */ diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c index d850a8deed..f61ecf0205 100644 --- a/pc-bios/s390-ccw/virtio-scsi.c +++ b/pc-bios/s390-ccw/virtio-scsi.c @@ -19,6 +19,8 @@ static VirtioScsiCmdReq req; static VirtioScsiCmdResp resp; static uint8_t scsi_inquiry_std_response[256]; +static ScsiInquiryEvpdPages scsi_inquiry_evpd_pages_response; +static ScsiInquiryEvpdBl scsi_inquiry_evpd_bl_response; static inline void vs_assert(bool term, const char **msgs) { @@ -89,10 +91,13 @@ static void vs_run(const char *title, VirtioCmd *cmd, VDev *vdev, /* SCSI protocol implementation routines */ -static bool scsi_inquiry(VDev *vdev, void *data, uint32_t data_size) +static bool scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page, + void *data, uint32_t data_size) { ScsiCdbInquiry cdb = { .command = 0x12, + .b1 = evpd, + .b2 = page, .alloc_len = data_size < 65535 ? data_size : 65535, }; VirtioCmd inquiry[] = { @@ -142,19 +147,18 @@ static bool scsi_report_luns(VDev *vdev, void *data, uint32_t data_size) } static bool scsi_read_10(VDev *vdev, - ulong sector, int sectors, void *data) + ulong sector, int sectors, void *data, + unsigned int data_size) { - int f = vdev->blk_factor; - unsigned int data_size = sectors * virtio_get_block_size() * f; ScsiCdbRead10 cdb = { .command = 0x28, - .lba = sector * f, - .xfer_length = sectors * f, + .lba = sector, + .xfer_length = sectors, }; VirtioCmd read_10[] = { { &req, sizeof(req), VRING_DESC_F_NEXT }, { &resp, sizeof(resp), VRING_DESC_F_WRITE | VRING_DESC_F_NEXT }, - { data, data_size * f, VRING_DESC_F_WRITE }, + { data, data_size, VRING_DESC_F_WRITE }, }; debug_print_int("read_10 sector", sector); @@ -203,6 +207,7 @@ static void virtio_scsi_locate_device(VDev *vdev) debug_print_int("config.scsi.max_channel", vdev->config.scsi.max_channel); debug_print_int("config.scsi.max_target ", vdev->config.scsi.max_target); debug_print_int("config.scsi.max_lun ", vdev->config.scsi.max_lun); + debug_print_int("config.scsi.max_sectors", vdev->config.scsi.max_sectors); if (vdev->scsi_device_selected) { sdev->channel = vdev->selected_scsi_device.channel; @@ -255,9 +260,23 @@ static void virtio_scsi_locate_device(VDev *vdev) int virtio_scsi_read_many(VDev *vdev, ulong sector, void *load_addr, int sec_num) { - if (!scsi_read_10(vdev, sector, sec_num, load_addr)) { - virtio_scsi_verify_response(&resp, "virtio-scsi:read_many"); - } + int sector_count; + int f = vdev->blk_factor; + unsigned int data_size; + unsigned int max_transfer = MIN_NON_ZERO(vdev->config.scsi.max_sectors, + vdev->max_transfer); + + do { + sector_count = MIN_NON_ZERO(sec_num, max_transfer); + data_size = sector_count * virtio_get_block_size() * f; + if (!scsi_read_10(vdev, sector * f, sector_count * f, load_addr, + data_size)) { + virtio_scsi_verify_response(&resp, "virtio-scsi:read_many"); + } + load_addr += data_size; + sector += sector_count; + sec_num -= sector_count; + } while (sec_num > 0); return 0; } @@ -304,6 +323,9 @@ void virtio_scsi_setup(VDev *vdev) int retry_test_unit_ready = 3; uint8_t data[256]; uint32_t data_size = sizeof(data); + ScsiInquiryEvpdPages *evpd = &scsi_inquiry_evpd_pages_response; + ScsiInquiryEvpdBl *evpd_bl = &scsi_inquiry_evpd_bl_response; + int i; vdev->scsi_device = &default_scsi_device; virtio_scsi_locate_device(vdev); @@ -334,7 +356,10 @@ void virtio_scsi_setup(VDev *vdev) } /* read and cache SCSI INQUIRY response */ - if (!scsi_inquiry(vdev, scsi_inquiry_std_response, + if (!scsi_inquiry(vdev, + SCSI_INQUIRY_STANDARD, + SCSI_INQUIRY_STANDARD_NONE, + scsi_inquiry_std_response, sizeof(scsi_inquiry_std_response))) { virtio_scsi_verify_response(&resp, "virtio-scsi:setup:inquiry"); } @@ -345,6 +370,44 @@ void virtio_scsi_setup(VDev *vdev) vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE; } + if (!scsi_inquiry(vdev, + SCSI_INQUIRY_EVPD, + SCSI_INQUIRY_EVPD_SUPPORTED_PAGES, + evpd, + sizeof(*evpd))) { + virtio_scsi_verify_response(&resp, "virtio-scsi:setup:supported_pages"); + } + + debug_print_int("EVPD length", evpd->page_length); + + for (i = 0; i <= evpd->page_length; i++) { + debug_print_int("supported EVPD page", evpd->byte[i]); + + if (evpd->byte[i] != SCSI_INQUIRY_EVPD_BLOCK_LIMITS) { + continue; + } + + if (!scsi_inquiry(vdev, + SCSI_INQUIRY_EVPD, + SCSI_INQUIRY_EVPD_BLOCK_LIMITS, + evpd_bl, + sizeof(*evpd_bl))) { + virtio_scsi_verify_response(&resp, "virtio-scsi:setup:blocklimits"); + } + + debug_print_int("max transfer", evpd_bl->max_transfer); + vdev->max_transfer = evpd_bl->max_transfer; + } + + /* + * The host sg driver will often be unhappy with particularly large + * I/Os that exceed the block iovec limits. Let's enforce something + * reasonable, despite what the device configuration tells us. + */ + + vdev->max_transfer = MIN_NON_ZERO(VIRTIO_SCSI_MAX_SECTORS, + vdev->max_transfer); + if (!scsi_read_capacity(vdev, data, data_size)) { virtio_scsi_verify_response(&resp, "virtio-scsi:setup:read_capacity"); } diff --git a/pc-bios/s390-ccw/virtio-scsi.h b/pc-bios/s390-ccw/virtio-scsi.h index f50b38b18b..4c4f4bbc31 100644 --- a/pc-bios/s390-ccw/virtio-scsi.h +++ b/pc-bios/s390-ccw/virtio-scsi.h @@ -19,6 +19,8 @@ #define VIRTIO_SCSI_CDB_SIZE SCSI_DEFAULT_CDB_SIZE #define VIRTIO_SCSI_SENSE_SIZE SCSI_DEFAULT_SENSE_SIZE +#define VIRTIO_SCSI_MAX_SECTORS 2048 + /* command-specific response values */ #define VIRTIO_SCSI_S_OK 0x00 #define VIRTIO_SCSI_S_BAD_TARGET 0x03 diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index 3388a423e5..1eaf865b1f 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -277,6 +277,7 @@ struct VDev { bool scsi_device_selected; ScsiDevice selected_scsi_device; uint64_t netboot_start_addr; + uint32_t max_transfer; }; typedef struct VDev VDev; diff --git a/qapi-schema.json b/qapi-schema.json index 80603cfc51..e38c5f0423 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -894,11 +894,18 @@ # @release-ram: if enabled, qemu will free the migrated ram pages on the source # during postcopy-ram migration. (since 2.9) # +# @block: If enabled, QEMU will also migrate the contents of all block +# devices. Default is disabled. A possible alternative uses +# mirror jobs to a builtin NBD server on the destination, which +# offers more flexibility. +# (Since 2.10) +# # Since: 1.2 ## { 'enum': 'MigrationCapability', 'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks', - 'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram'] } + 'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram', + 'block' ] } ## # @MigrationCapabilityStatus: @@ -1009,13 +1016,20 @@ # @x-checkpoint-delay: The delay time (in ms) between two COLO checkpoints in # periodic mode. (Since 2.8) # +# @block-incremental: Affects how much storage is migrated when the +# block migration capability is enabled. When false, the entire +# storage backing chain is migrated into a flattened image at +# the destination; when true, only the active qcow2 layer is +# migrated and the destination must already have access to the +# same backing chain as was used on the source. (since 2.10) +# # Since: 2.4 ## { 'enum': 'MigrationParameter', 'data': ['compress-level', 'compress-threads', 'decompress-threads', 'cpu-throttle-initial', 'cpu-throttle-increment', 'tls-creds', 'tls-hostname', 'max-bandwidth', - 'downtime-limit', 'x-checkpoint-delay' ] } + 'downtime-limit', 'x-checkpoint-delay', 'block-incremental' ] } ## # @migrate-set-parameters: @@ -1082,6 +1096,13 @@ # # @x-checkpoint-delay: the delay time between two COLO checkpoints. (Since 2.8) # +# @block-incremental: Affects how much storage is migrated when the +# block migration capability is enabled. When false, the entire +# storage backing chain is migrated into a flattened image at +# the destination; when true, only the active qcow2 layer is +# migrated and the destination must already have access to the +# same backing chain as was used on the source. (since 2.10) +# # Since: 2.4 ## { 'struct': 'MigrationParameters', @@ -1094,7 +1115,8 @@ '*tls-hostname': 'str', '*max-bandwidth': 'int', '*downtime-limit': 'int', - '*x-checkpoint-delay': 'int'} } + '*x-checkpoint-delay': 'int', + '*block-incremental': 'bool' } } ## # @query-migrate-parameters: diff --git a/qemu-options.hx b/qemu-options.hx index f07a310eb1..0c67319891 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -42,7 +42,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ " dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" " suppress-vmdesc=on|off disables self-describing migration (default=off)\n" " nvdimm=on|off controls NVDIMM support (default=off)\n" - " enforce-config-section=on|off enforce configuration section migration (default=off)\n", + " enforce-config-section=on|off enforce configuration section migration (default=off)\n" + " s390-squash-mcss=on|off controls support for squashing into default css (default=off)\n", QEMU_ARCH_ALL) STEXI @item -machine [type=]@var{name}[,prop=@var{value}[,...]] @@ -81,6 +82,9 @@ controls whether DEA wrapping keys will be created to allow execution of DEA cryptographic functions. The default is on. @item nvdimm=on|off Enables or disables NVDIMM support. The default is off. +@item s390-squash-mcss=on|off +Enables or disables squashing subchannels into the default css. +The default is off. @end table ETEXI @@ -4072,7 +4076,7 @@ Create a filter-redirector we need to differ outdev id from indev id, id can not be the same. we can just use indev or outdev, but at least one of indev or outdev need to be specified. -@item -object filter-rewriter,id=@var{id},netdev=@var{netdevid},rewriter-mode=@var{mode}[,queue=@var{all|rx|tx}] +@item -object filter-rewriter,id=@var{id},netdev=@var{netdevid}[,queue=@var{all|rx|tx}] Filter-rewriter is a part of COLO project.It will rewrite tcp packet to secondary from primary to keep secondary tcp connection,and rewrite diff --git a/roms/openbios b/roms/openbios -Subproject 04898e8ce4c2f7bd94c7eeff9d26f2ff23aae8d +Subproject 3ebaaa2e22eec2ed3debfd956604f395f28c46e diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 6a370a8669..2f906c4d16 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -113,7 +113,7 @@ done rm -rf "$output/linux-headers/linux" mkdir -p "$output/linux-headers/linux" -for header in kvm.h kvm_para.h vfio.h vhost.h \ +for header in kvm.h kvm_para.h vfio.h vfio_ccw.h vhost.h \ psci.h userfaultfd.h; do cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" done diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index a1bf2ba5a7..a69005d9b5 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -92,9 +92,10 @@ static void s390_cpu_initial_reset(CPUState *s) int i; s390_cpu_reset(s); - /* initial reset does not touch regs,fregs and aregs */ - memset(&env->fpc, 0, offsetof(CPUS390XState, end_reset_fields) - - offsetof(CPUS390XState, fpc)); + /* initial reset does not clear everything! */ + memset(&env->start_initial_reset_fields, 0, + offsetof(CPUS390XState, end_reset_fields) - + offsetof(CPUS390XState, start_initial_reset_fields)); /* architectured initial values for CR 0 and 14 */ env->cregs[0] = CR0_RESET; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 240b8a5c22..c74b4193ee 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -88,6 +88,10 @@ typedef struct CPUS390XState { */ CPU_DoubleU vregs[32][2]; /* vector registers */ uint32_t aregs[16]; /* access registers */ + uint8_t riccb[64]; /* runtime instrumentation control */ + + /* Fields up to this point are not cleared by initial CPU reset */ + struct {} start_initial_reset_fields; uint32_t fpc; /* floating-point control register */ uint32_t cc_op; @@ -137,8 +141,6 @@ typedef struct CPUS390XState { uint64_t gbea; uint64_t pp; - uint8_t riccb[64]; - /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; @@ -1256,6 +1258,16 @@ static inline void s390_crypto_reset(void) } } +static inline bool s390_get_squash_mcss(void) +{ + if (object_property_get_bool(OBJECT(qdev_get_machine()), "s390-squash-mcss", + NULL)) { + return true; + } + + return false; +} + /* machine check interruption code */ /* subclasses */ diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 590bfa4f12..62a777100c 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -244,6 +244,15 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) case -EBUSY: cc = 2; break; + case -EFAULT: + /* + * TODO: + * I'm wondering whether there is something better + * to do for us here (like setting some device or + * subchannel status). + */ + program_interrupt(env, PGM_ADDRESSING, 4); + return; case 0: cc = 0; break; diff --git a/tests/Makefile.include b/tests/Makefile.include index 4277597e93..75893838e5 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -574,7 +574,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/reset.o \ $(test-qapi-obj-y) tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ - migration/vmstate.o migration/qemu-file.o \ + migration/vmstate.o migration/vmstate-types.o migration/qemu-file.o \ migration/qemu-file-channel.o migration/qjson.o \ $(test-io-obj-y) tests/test-timed-average$(EXESUF): tests/test-timed-average.o $(test-util-obj-y) diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index f694a89782..25389bcce4 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -27,6 +27,8 @@ #include "qemu-common.h" #include "migration/migration.h" #include "migration/vmstate.h" +#include "migration/qemu-file.h" +#include "../migration/qemu-file-channel.h" #include "qemu/coroutine.h" #include "io/channel-file.h" diff --git a/tests/test-xbzrle.c b/tests/test-xbzrle.c index 49f64195a6..f5e08de91e 100644 --- a/tests/test-xbzrle.c +++ b/tests/test-xbzrle.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/cutils.h" -#include "include/migration/migration.h" +#include "../migration/xbzrle.h" #define PAGE_SIZE 4096 diff --git a/ui/Makefile.objs b/ui/Makefile.objs index aac6ae8bef..3369451285 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -33,7 +33,7 @@ common-obj-y += shader.o common-obj-y += console-gl.o common-obj-y += egl-helpers.o common-obj-y += egl-context.o -common-obj-y += egl-headless.o +common-obj-$(CONFIG_OPENGL_DMABUF) += egl-headless.o ifeq ($(CONFIG_GTK_GL),y) common-obj-$(CONFIG_GTK) += gtk-gl-area.o else diff --git a/vl.c b/vl.c index 1512df6e9e..3465121217 100644 --- a/vl.c +++ b/vl.c @@ -89,6 +89,7 @@ int main(int argc, char **argv) #include "migration/block.h" #include "sysemu/tpm.h" #include "sysemu/dma.h" +#include "hw/audio/soundhw.h" #include "audio/audio.h" #include "migration/migration.h" #include "sysemu/cpus.h" @@ -2129,7 +2130,7 @@ static DisplayType select_display(const char *p) exit(1); } } else if (strstart(p, "egl-headless", &opts)) { -#ifdef CONFIG_OPENGL +#ifdef CONFIG_OPENGL_DMABUF request_opengl = 1; display_opengl = 1; display = DT_EGL; @@ -4574,7 +4575,7 @@ int main(int argc, char **argv, char **envp) realtime_init(); - audio_init(); + soundhw_init(); if (hax_enabled()) { hax_sync_vcpus(); @@ -4668,7 +4669,7 @@ int main(int argc, char **argv, char **envp) qemu_spice_display_init(); } -#ifdef CONFIG_OPENGL +#ifdef CONFIG_OPENGL_DMABUF if (display_type == DT_EGL) { egl_headless_init(); } |