diff options
112 files changed, 1745 insertions, 995 deletions
diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000000..9d322fca93 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,8 @@ +# GDB may have ./.gdbinit loading disabled by default. In that case you can +# follow the instructions it prints. They boil down to adding the following to +# your home directory's ~/.gdbinit file: +# +# add-auto-load-safe-path /path/to/qemu/.gdbinit + +# Load QEMU-specific sub-commands and settings +source scripts/qemu-gdb.py diff --git a/block/gluster.c b/block/gluster.c index 031596adbc..addceed6eb 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -493,8 +493,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, Error *local_err = NULL; char *str = NULL; const char *ptr; - size_t num_servers; - int i, type; + int i, type, num_servers; /* create opts info from runtime_json_opts list */ opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort); diff --git a/chardev/char.c b/chardev/char.c index 7aa0210765..bcfc065d16 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -450,12 +450,12 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) } if (strstart(filename, "/dev/parport", NULL) || strstart(filename, "/dev/ppi", NULL)) { - qemu_opt_set(opts, "backend", "parport", &error_abort); + qemu_opt_set(opts, "backend", "parallel", &error_abort); qemu_opt_set(opts, "path", filename, &error_abort); return opts; } if (strstart(filename, "/dev/", NULL)) { - qemu_opt_set(opts, "backend", "tty", &error_abort); + qemu_opt_set(opts, "backend", "serial", &error_abort); qemu_opt_set(opts, "path", filename, &error_abort); return opts; } diff --git a/configure b/configure index 71f5612a65..b147191ae6 100755 --- a/configure +++ b/configure @@ -91,7 +91,8 @@ update_cxxflags() { # Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those # options which some versions of GCC's C++ compiler complain about # because they only make sense for C programs. - QEMU_CXXFLAGS= + QEMU_CXXFLAGS="$QEMU_CXXFLAGS -D__STDC_LIMIT_MACROS" + for arg in $QEMU_CFLAGS; do case $arg in -Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\ @@ -345,6 +346,9 @@ for opt do --extra-cflags=*) QEMU_CFLAGS="$QEMU_CFLAGS $optarg" EXTRA_CFLAGS="$optarg" ;; + --extra-cxxflags=*) QEMU_CXXFLAGS="$QEMU_CXXFLAGS $optarg" + EXTRA_CXXFLAGS="$optarg" + ;; --extra-ldflags=*) LDFLAGS="$LDFLAGS $optarg" EXTRA_LDFLAGS="$optarg" ;; @@ -788,6 +792,8 @@ for opt do ;; --extra-cflags=*) ;; + --extra-cxxflags=*) + ;; --extra-ldflags=*) ;; --enable-debug-info) @@ -1305,6 +1311,7 @@ Advanced options (experts only): --cxx=CXX use C++ compiler CXX [$cxx] --objcc=OBJCC use Objective-C compiler OBJCC [$objcc] --extra-cflags=CFLAGS append extra C compiler flags QEMU_CFLAGS + --extra-cxxflags=CXXFLAGS append extra C++ compiler flags QEMU_CXXFLAGS --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS --make=MAKE use specified make [$make] --install=INSTALL use specified install [$install] @@ -1490,37 +1497,6 @@ if test "$bogus_os" = "yes"; then error_exit "Unrecognized host OS $targetos" fi -# Check that the C++ compiler exists and works with the C compiler -if has $cxx; then - cat > $TMPC <<EOF -int c_function(void); -int main(void) { return c_function(); } -EOF - - compile_object - - cat > $TMPCXX <<EOF -extern "C" { - int c_function(void); -} -int c_function(void) { return 42; } -EOF - - update_cxxflags - - if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then - # C++ compiler $cxx works ok with C compiler $cc - : - else - echo "C++ compiler $cxx does not work with C compiler $cc" - echo "Disabling C++ specific optional code" - cxx= - fi -else - echo "No C++ compiler available; disabling C++ specific optional code" - cxx= -fi - gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" @@ -5064,6 +5040,38 @@ EOF fi fi +# Check that the C++ compiler exists and works with the C compiler. +# All the QEMU_CXXFLAGS are based on QEMU_CFLAGS. Keep this at the end to don't miss any other that could be added. +if has $cxx; then + cat > $TMPC <<EOF +int c_function(void); +int main(void) { return c_function(); } +EOF + + compile_object + + cat > $TMPCXX <<EOF +extern "C" { + int c_function(void); +} +int c_function(void) { return 42; } +EOF + + update_cxxflags + + if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then + # C++ compiler $cxx works ok with C compiler $cc + : + else + echo "C++ compiler $cxx does not work with C compiler $cc" + echo "Disabling C++ specific optional code" + cxx= + fi +else + echo "No C++ compiler available; disabling C++ specific optional code" + cxx= +fi + echo_version() { if test "$1" = "yes" ; then echo "($2)" @@ -5269,6 +5277,7 @@ if test "$mingw32" = "no" ; then fi echo "qemu_helperdir=$libexecdir" >> $config_host_mak echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak +echo "extra_cxxflags=$EXTRA_CXXFLAGS" >> $config_host_mak echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak echo "qemu_localedir=$qemu_localedir" >> $config_host_mak echo "libs_softmmu=$libs_softmmu" >> $config_host_mak @@ -5911,6 +5920,7 @@ echo "WINDRES=$windres" >> $config_host_mak echo "CFLAGS=$CFLAGS" >> $config_host_mak echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $config_host_mak echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak +echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak if test "$sparse" = "yes" ; then echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak @@ -6376,6 +6386,7 @@ FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES pc-bios/s390-ccw/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" FILES="$FILES pc-bios/qemu-icon.bmp" +FILES="$FILES .gdbinit scripts" # scripts needed by relative path in .gdbinit for bios_file in \ $source_path/pc-bios/*.bin \ $source_path/pc-bios/*.lid \ diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 78d7af03a2..93e995d318 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -15,6 +15,7 @@ CONFIG_TWL92230=y CONFIG_TSC2005=y CONFIG_LM832X=y CONFIG_TMP105=y +CONFIG_TMP421=y CONFIG_STELLARIS=y CONFIG_STELLARIS_INPUT=y CONFIG_STELLARIS_ENET=y diff --git a/disas/libvixl/Makefile.objs b/disas/libvixl/Makefile.objs index 860fb7f384..27183b7c20 100644 --- a/disas/libvixl/Makefile.objs +++ b/disas/libvixl/Makefile.objs @@ -6,9 +6,9 @@ libvixl_OBJS = vixl/utils.o \ # The -Wno-sign-compare is needed only for gcc 4.6, which complains about # some signed-unsigned equality comparisons which later gcc versions do not. -$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CFLAGS) -Wno-sign-compare +$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CXXFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CXXFLAGS) -Wno-sign-compare # Ensure that C99 macros are defined regardless of the inclusion order of # headers in vixl. This is required at least on NetBSD. -$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS +$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CXXFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS common-obj-$(CONFIG_ARM_A64_DIS) += $(libvixl_OBJS) diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index 8e7d6ec034..b5734f5897 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -338,9 +338,10 @@ static void nvdimm_build_structure_dcr(GArray *structures, DeviceState *dev) nfit_dcr->revision_id = cpu_to_le16(1 /* Current Revision supported in ACPI 6.0 is 1. */); nfit_dcr->serial_number = cpu_to_le32(sn); - nfit_dcr->fic = cpu_to_le16(0x201 /* Format Interface Code. See Chapter - 2: NVDIMM Device Specific Method - (DSM) in DSM Spec Rev1.*/); + nfit_dcr->fic = cpu_to_le16(0x301 /* Format Interface Code: + Byte addressable, no energy backed. + See ACPI 6.2, sect 5.2.25.6 and + JEDEC Annex L Release 3. */); } static GArray *nvdimm_build_device_structure(void) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index e824ea87a9..155eeb242b 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -239,10 +239,19 @@ static void aspeed_board_init(MachineState *machine, static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; + DeviceState *dev; /* The palmetto platform expects a ds3231 RTC but a ds1338 is * enough to provide basic RTC features. Alarms will be missing */ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68); + + /* add a TMP423 temperature sensor */ + dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), + "tmp423", 0x4c); + object_property_set_int(OBJECT(dev), 31000, "temperature0", &error_abort); + object_property_set_int(OBJECT(dev), 28000, "temperature1", &error_abort); + object_property_set_int(OBJECT(dev), 20000, "temperature2", &error_abort); + object_property_set_int(OBJECT(dev), 110000, "temperature3", &error_abort); } static void palmetto_bmc_init(MachineState *machine) diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 960f27e45a..0050626a69 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -26,6 +26,7 @@ #include "qemu-common.h" #include "qemu/log.h" #include "cpu.h" +#include "hw/cpu/a9mpcore.h" #include "hw/boards.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" @@ -160,16 +161,14 @@ static uint64_t exynos4210_calc_affinity(int cpu) return mp_affinity; } -Exynos4210State *exynos4210_init(MemoryRegion *system_mem, - unsigned long ram_size) +Exynos4210State *exynos4210_init(MemoryRegion *system_mem) { - int i, n; Exynos4210State *s = g_new(Exynos4210State, 1); qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; - unsigned long mem_size; - DeviceState *dev; SysBusDevice *busdev; ObjectClass *cpu_oc; + DeviceState *dev; + int i, n; cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9"); assert(cpu_oc); @@ -213,7 +212,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, } /* Private memory region and Internal GIC */ - dev = qdev_create(NULL, "a9mpcore_priv"); + dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); @@ -299,22 +298,6 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR, &s->iram_mem); - /* DRAM */ - mem_size = ram_size; - if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { - memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1", - mem_size - EXYNOS4210_DRAM_MAX_SIZE, &error_fatal); - vmstate_register_ram_global(&s->dram1_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, - &s->dram1_mem); - mem_size = EXYNOS4210_DRAM_MAX_SIZE; - } - memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size, - &error_fatal); - vmstate_register_ram_global(&s->dram0_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, - &s->dram0_mem); - /* PMU. * The only reason of existence at the moment is that secondary CPU boot * loader uses PMU INFORM5 register as a holding pen. diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 4853c31802..6240b26839 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -22,6 +22,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu-common.h" #include "cpu.h" @@ -56,6 +57,12 @@ typedef enum Exynos4BoardType { EXYNOS4_NUM_OF_BOARDS } Exynos4BoardType; +typedef struct Exynos4BoardState { + Exynos4210State *soc; + MemoryRegion dram0_mem; + MemoryRegion dram1_mem; +} Exynos4BoardState; + static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = { [EXYNOS4_BOARD_NURI] = 0xD33, [EXYNOS4_BOARD_SMDKC210] = 0xB16, @@ -96,9 +103,34 @@ static void lan9215_init(uint32_t base, qemu_irq irq) } } -static Exynos4210State *exynos4_boards_init_common(MachineState *machine, - Exynos4BoardType board_type) +static void exynos4_boards_init_ram(Exynos4BoardState *s, + MemoryRegion *system_mem, + unsigned long ram_size) +{ + unsigned long mem_size = ram_size; + + if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { + memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1", + mem_size - EXYNOS4210_DRAM_MAX_SIZE, + &error_fatal); + vmstate_register_ram_global(&s->dram1_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, + &s->dram1_mem); + mem_size = EXYNOS4210_DRAM_MAX_SIZE; + } + + memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size, + &error_fatal); + vmstate_register_ram_global(&s->dram0_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, + &s->dram0_mem); +} + +static Exynos4BoardState * +exynos4_boards_init_common(MachineState *machine, + Exynos4BoardType board_type) { + Exynos4BoardState *s = g_new(Exynos4BoardState, 1); MachineClass *mc = MACHINE_GET_CLASS(machine); if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) { @@ -127,8 +159,12 @@ static Exynos4210State *exynos4_boards_init_common(MachineState *machine, machine->kernel_cmdline, machine->initrd_filename); - return exynos4210_init(get_system_memory(), - exynos4_board_ram_size[board_type]); + exynos4_boards_init_ram(s, get_system_memory(), + exynos4_board_ram_size[board_type]); + + s->soc = exynos4210_init(get_system_memory()); + + return s; } static void nuri_init(MachineState *machine) @@ -140,11 +176,11 @@ static void nuri_init(MachineState *machine) static void smdkc210_init(MachineState *machine) { - Exynos4210State *s = exynos4_boards_init_common(machine, - EXYNOS4_BOARD_SMDKC210); + Exynos4BoardState *s = exynos4_boards_init_common(machine, + EXYNOS4_BOARD_SMDKC210); lan9215_init(SMDK_LAN9118_BASE_ADDR, - qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); + qemu_irq_invert(s->soc->irq_table[exynos4210_get_irq(37, 1)])); arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); } diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs index 942a4bb82e..cd52d20b65 100644 --- a/hw/cpu/Makefile.objs +++ b/hw/cpu/Makefile.objs @@ -2,5 +2,4 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o obj-$(CONFIG_REALVIEW) += realview_mpcore.o obj-$(CONFIG_A9MPCORE) += a9mpcore.o obj-$(CONFIG_A15MPCORE) += a15mpcore.o -obj-y += core.o - +common-obj-y += core.o diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2234bd0461..46a2bc41ab 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -52,7 +52,8 @@ #include <xen/hvm/hvm_info_table.h> #include "hw/xen/xen_pt.h" #endif -#include "migration/migration.h" +#include "migration/global_state.h" +#include "migration/misc.h" #include "kvm_i386.h" #include "sysemu/numa.h" diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index af5cd367e9..ae095d08a3 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -100,14 +100,14 @@ static void kvm_gicd_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, - KVM_VGIC_ATTR(offset, cpu), val, write); + KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); } static void kvm_gicc_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, - KVM_VGIC_ATTR(offset, cpu), val, write); + KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); } #define for_each_irq_reg(_ctr, _max_irq, _field_width) \ @@ -538,13 +538,14 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { uint32_t numirqs = s->num_irq; kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, - &numirqs, true); + &numirqs, true, &error_abort); } /* Tell the kernel to complete VGIC initialization now */ if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT)) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, + &error_abort); } } else if (ret != -ENODEV && ret != -ENOTSUP) { error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index c6493d6c07..4228b7ca00 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -145,6 +145,7 @@ static const VMStateDescription vmstate_gicv3 = { .minimum_version_id = 1, .pre_save = gicv3_pre_save, .post_load = gicv3_post_load, + .priority = MIG_PRI_GICV3, .fields = (VMStateField[]) { VMSTATE_UINT32(gicd_ctlr, GICv3State), VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2), diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 9d67c5c1ee..68b20fccd1 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -48,7 +48,16 @@ static const VMStateDescription vmstate_its = { .name = "arm_gicv3_its", .pre_save = gicv3_its_pre_save, .post_load = gicv3_its_post_load, - .unmigratable = true, + .priority = MIG_PRI_GICV3_ITS, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ctlr, GICv3ITSState), + VMSTATE_UINT32(iidr, GICv3ITSState), + VMSTATE_UINT64(cbaser, GICv3ITSState), + VMSTATE_UINT64(cwriter, GICv3ITSState), + VMSTATE_UINT64(creadr, GICv3ITSState), + VMSTATE_UINT64_ARRAY(baser, GICv3ITSState, 8), + VMSTATE_END_OF_LIST() + }, }; static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset, @@ -118,6 +127,7 @@ static void gicv3_its_common_reset(DeviceState *dev) s->cbaser = 0; s->cwriter = 0; s->creadr = 0; + s->iidr = 0; memset(&s->baser, 0, sizeof(s->baser)); gicv3_its_post_load(s, 0); diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index a0441d6bd1..1f8991b8a6 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -53,23 +53,38 @@ static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid) return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); } -static void kvm_arm_its_realize(DeviceState *dev, Error **errp) +/** + * vm_change_state_handler - VM change state callback aiming at flushing + * ITS tables into guest RAM + * + * The tables get flushed to guest RAM whenever the VM gets stopped. + */ +static void vm_change_state_handler(void *opaque, int running, + RunState state) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); - Error *local_err = NULL; + GICv3ITSState *s = (GICv3ITSState *)opaque; + Error *err = NULL; + int ret; - /* - * Block migration of a KVM GICv3 ITS device: the API for saving and - * restoring the state in the kernel is not yet available - */ - error_setg(&s->migration_blocker, "vITS migration is not implemented"); - migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_free(s->migration_blocker); + if (running) { return; } + ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err); + if (err) { + error_report_err(err); + } + if (ret < 0 && ret != -EFAULT) { + abort(); + } +} + +static void kvm_arm_its_realize(DeviceState *dev, Error **errp) +{ + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + Error *local_err = NULL; + s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false); if (s->dev_fd < 0) { error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS"); @@ -78,7 +93,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) /* explicit init of the ITS */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); /* register the base address */ kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, @@ -86,9 +101,23 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) gicv3_its_init_mmio(s, NULL); + if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR)) { + error_setg(&s->migration_blocker, "This operating system kernel " + "does not support vITS migration"); + migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + return; + } + } + kvm_msi_use_devid = true; kvm_gsi_direct_mapping = false; kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); + + qemu_add_vm_change_state_handler(vm_change_state_handler, s); } static void kvm_arm_its_init(Object *obj) @@ -102,6 +131,80 @@ static void kvm_arm_its_init(Object *obj) &error_abort); } +/** + * kvm_arm_its_pre_save - handles the saving of ITS registers. + * ITS tables are flushed into guest RAM separately and earlier, + * through the VM change state handler, since at the moment pre_save() + * is called, the guest RAM has already been saved. + */ +static void kvm_arm_its_pre_save(GICv3ITSState *s) +{ + int i; + + for (i = 0; i < 8; i++) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_BASER + i * 8, &s->baser[i], false, + &error_abort); + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR, &s->ctlr, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CBASER, &s->cbaser, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CREADR, &s->creadr, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CWRITER, &s->cwriter, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_IIDR, &s->iidr, false, &error_abort); +} + +/** + * kvm_arm_its_post_load - Restore both the ITS registers and tables + */ +static void kvm_arm_its_post_load(GICv3ITSState *s) +{ + int i; + + if (!s->iidr) { + return; + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_IIDR, &s->iidr, true, &error_abort); + + /* + * must be written before GITS_CREADR since GITS_CBASER write + * access resets GITS_CREADR. + */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CBASER, &s->cbaser, true, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CREADR, &s->creadr, true, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CWRITER, &s->cwriter, true, &error_abort); + + + for (i = 0; i < 8; i++) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_BASER + i * 8, &s->baser[i], true, + &error_abort); + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_RESTORE_TABLES, NULL, true, + &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR, &s->ctlr, true, &error_abort); +} + static void kvm_arm_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -109,6 +212,8 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data) dc->realize = kvm_arm_its_realize; icc->send_msi = kvm_its_send_msi; + icc->pre_save = kvm_arm_its_pre_save; + icc->post_load = kvm_arm_its_post_load; } static const TypeInfo kvm_arm_its_info = { diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 4ee2baa691..6051c77705 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" +#include "sysemu/sysemu.h" #include "kvm_arm.h" #include "gicv3_internal.h" #include "vgic_common.h" @@ -93,7 +94,7 @@ static inline void kvm_gicd_access(GICv3State *s, int offset, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_VGIC_ATTR(offset, 0), - val, write); + val, write, &error_abort); } static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, @@ -101,7 +102,7 @@ static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), - val, write); + val, write, &error_abort); } static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, @@ -109,7 +110,7 @@ static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), - val, write); + val, write, &error_abort); } static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, @@ -119,7 +120,7 @@ static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | (VGIC_LEVEL_INFO_LINE_LEVEL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT), - val, write); + val, write, &error_abort); } /* Loop through each distributor IRQ related register; since bits @@ -630,7 +631,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) /* Initialize to actual HW supported configuration */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), - &c->icc_ctlr_el1[GICV3_NS], false); + &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; } @@ -680,6 +681,35 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { REGINFO_SENTINEL }; +/** + * vm_change_state_handler - VM change state callback aiming at flushing + * RDIST pending tables into guest RAM + * + * The tables get flushed to guest RAM whenever the VM gets stopped. + */ +static void vm_change_state_handler(void *opaque, int running, + RunState state) +{ + GICv3State *s = (GICv3State *)opaque; + Error *err = NULL; + int ret; + + if (running) { + return; + } + + ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES, + NULL, true, &err); + if (err) { + error_report_err(err); + } + if (ret < 0 && ret != -EFAULT) { + abort(); + } +} + + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { GICv3State *s = KVM_ARM_GICV3(dev); @@ -717,11 +747,11 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, - 0, &s->num_irq, true); + 0, &s->num_irq, true, &error_abort); /* Tell the kernel to complete VGIC initialization now */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); @@ -751,6 +781,10 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) return; } } + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES)) { + qemu_add_vm_change_state_handler(vm_change_state_handler, s); + } } static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 2a55817b76..b6b00a4f58 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -116,7 +116,7 @@ enum ExtInt { * which is INTG16 in Internal Interrupt Combiner. */ -static uint32_t +static const uint32_t combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { /* int combiner groups 16-19 */ { }, { }, { }, { }, @@ -286,21 +286,21 @@ static void exynos4210_gic_init(Object *obj) DeviceState *dev = DEVICE(obj); Exynos4210GicState *s = EXYNOS4210_GIC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - uint32_t i; const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; const char dist_prefix[] = "exynos4210-gic-alias_dist"; char cpu_alias_name[sizeof(cpu_prefix) + 3]; char dist_alias_name[sizeof(cpu_prefix) + 3]; - SysBusDevice *busdev; + SysBusDevice *gicbusdev; + uint32_t i; s->gic = qdev_create(NULL, "arm_gic"); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); qdev_init_nofail(s->gic); - busdev = SYS_BUS_DEVICE(s->gic); + gicbusdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ - sysbus_pass_irq(sbd, busdev); + sysbus_pass_irq(sbd, gicbusdev); /* Pass through inbound GPIO lines to the GIC */ qdev_init_gpio_in(dev, exynos4210_gic_set_irq, @@ -316,7 +316,7 @@ static void exynos4210_gic_init(Object *obj) sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); memory_region_init_alias(&s->cpu_alias[i], obj, cpu_alias_name, - sysbus_mmio_get_region(busdev, 1), + sysbus_mmio_get_region(gicbusdev, 1), 0, EXYNOS4210_GIC_CPU_REGION_SIZE); memory_region_add_subregion(&s->cpu_container, @@ -326,7 +326,7 @@ static void exynos4210_gic_init(Object *obj) sprintf(dist_alias_name, "%s%x", dist_prefix, i); memory_region_init_alias(&s->dist_alias[i], obj, dist_alias_name, - sysbus_mmio_get_region(busdev, 0), + sysbus_mmio_get_region(gicbusdev, 0), 0, EXYNOS4210_GIC_DIST_REGION_SIZE); memory_region_add_subregion(&s->dist_container, diff --git a/hw/intc/xics.c b/hw/intc/xics.c index ea3516794a..7ccfb53c55 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -38,50 +38,6 @@ #include "monitor/monitor.h" #include "hw/intc/intc.h" -void xics_cpu_destroy(XICSFabric *xi, PowerPCCPU *cpu) -{ - CPUState *cs = CPU(cpu); - ICPState *icp = ICP(cpu->intc); - - assert(icp); - assert(cs == icp->cs); - - icp->output = NULL; - icp->cs = NULL; -} - -void xics_cpu_setup(XICSFabric *xi, PowerPCCPU *cpu, ICPState *icp) -{ - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - ICPStateClass *icpc; - - assert(icp); - - cpu->intc = OBJECT(icp); - icp->cs = cs; - - icpc = ICP_GET_CLASS(icp); - if (icpc->cpu_setup) { - icpc->cpu_setup(icp, cpu); - } - - switch (PPC_INPUT(env)) { - case PPC_FLAGS_INPUT_POWER7: - icp->output = env->irq_inputs[POWER7_INPUT_INT]; - break; - - case PPC_FLAGS_INPUT_970: - icp->output = env->irq_inputs[PPC970_INPUT_INT]; - break; - - default: - error_report("XICS interrupt controller does not support this CPU " - "bus model"); - abort(); - } -} - void icp_pic_print_info(ICPState *icp, Monitor *mon) { int cpu_index = icp->cs ? icp->cs->cpu_index : -1; @@ -325,6 +281,7 @@ static const VMStateDescription vmstate_icp_server = { static void icp_reset(void *dev) { ICPState *icp = ICP(dev); + ICPStateClass *icpc = ICP_GET_CLASS(icp); icp->xirr = 0; icp->pending_priority = 0xff; @@ -332,26 +289,58 @@ static void icp_reset(void *dev) /* Make all outputs are deasserted */ qemu_set_irq(icp->output, 0); + + if (icpc->reset) { + icpc->reset(icp); + } } static void icp_realize(DeviceState *dev, Error **errp) { ICPState *icp = ICP(dev); ICPStateClass *icpc = ICP_GET_CLASS(dev); + PowerPCCPU *cpu; + CPUPPCState *env; Object *obj; Error *err = NULL; - obj = object_property_get_link(OBJECT(dev), "xics", &err); + obj = object_property_get_link(OBJECT(dev), ICP_PROP_XICS, &err); if (!obj) { - error_setg(errp, "%s: required link 'xics' not found: %s", + error_setg(errp, "%s: required link '" ICP_PROP_XICS "' not found: %s", __func__, error_get_pretty(err)); return; } icp->xics = XICS_FABRIC(obj); + obj = object_property_get_link(OBJECT(dev), ICP_PROP_CPU, &err); + if (!obj) { + error_setg(errp, "%s: required link '" ICP_PROP_CPU "' not found: %s", + __func__, error_get_pretty(err)); + return; + } + + cpu = POWERPC_CPU(obj); + cpu->intc = OBJECT(icp); + icp->cs = CPU(obj); + + env = &cpu->env; + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_POWER7: + icp->output = env->irq_inputs[POWER7_INPUT_INT]; + break; + + case PPC_FLAGS_INPUT_970: + icp->output = env->irq_inputs[PPC970_INPUT_INT]; + break; + + default: + error_setg(errp, "XICS interrupt controller does not support this CPU bus model"); + return; + } + if (icpc->realize) { - icpc->realize(dev, errp); + icpc->realize(icp, errp); } qemu_register_reset(icp_reset, dev); @@ -601,10 +590,8 @@ static void ics_simple_initfn(Object *obj) ics->offset = XICS_IRQ_BASE; } -static void ics_simple_realize(DeviceState *dev, Error **errp) +static void ics_simple_realize(ICSState *ics, Error **errp) { - ICSState *ics = ICS_SIMPLE(dev); - if (!ics->nr_irqs) { error_setg(errp, "Number of interrupts needs to be greater 0"); return; @@ -612,7 +599,7 @@ static void ics_simple_realize(DeviceState *dev, Error **errp) ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); - qemu_register_reset(ics_simple_reset, dev); + qemu_register_reset(ics_simple_reset, ics); } static Property ics_simple_properties[] = { @@ -649,9 +636,9 @@ static void ics_base_realize(DeviceState *dev, Error **errp) Object *obj; Error *err = NULL; - obj = object_property_get_link(OBJECT(dev), "xics", &err); + obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err); if (!obj) { - error_setg(errp, "%s: required link 'xics' not found: %s", + error_setg(errp, "%s: required link '" ICS_PROP_XICS "' not found: %s", __func__, error_get_pretty(err)); return; } @@ -659,7 +646,7 @@ static void ics_base_realize(DeviceState *dev, Error **errp) if (icsc->realize) { - icsc->realize(dev, errp); + icsc->realize(ics, errp); } } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 14b8f6f6e4..3091ad3ac2 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -110,25 +110,14 @@ static int icp_set_kvm_state(ICPState *icp, int version_id) return 0; } -static void icp_kvm_reset(void *dev) +static void icp_kvm_reset(ICPState *icp) { - ICPState *icp = ICP(dev); - - icp->xirr = 0; - icp->pending_priority = 0xff; - icp->mfrr = 0xff; - - /* Make all outputs as deasserted only if the CPU thread is in use */ - if (icp->output) { - qemu_set_irq(icp->output, 0); - } - icp_set_kvm_state(icp, 1); } -static void icp_kvm_cpu_setup(ICPState *icp, PowerPCCPU *cpu) +static void icp_kvm_realize(ICPState *icp, Error **errp) { - CPUState *cs = CPU(cpu); + CPUState *cs = icp->cs; KVMEnabledICP *enabled_icp; unsigned long vcpu_id = kvm_arch_vcpu_id(cs); int ret; @@ -150,35 +139,23 @@ static void icp_kvm_cpu_setup(ICPState *icp, PowerPCCPU *cpu) ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, vcpu_id); if (ret < 0) { - error_report("Unable to connect CPU%ld to kernel XICS: %s", vcpu_id, - strerror(errno)); - exit(1); + error_setg(errp, "Unable to connect CPU%ld to kernel XICS: %s", vcpu_id, + strerror(errno)); + return; } enabled_icp = g_malloc(sizeof(*enabled_icp)); enabled_icp->vcpu_id = vcpu_id; QLIST_INSERT_HEAD(&kvm_enabled_icps, enabled_icp, node); } -static void icp_kvm_realize(DeviceState *dev, Error **errp) -{ - qemu_register_reset(icp_kvm_reset, dev); -} - -static void icp_kvm_unrealize(DeviceState *dev, Error **errp) -{ - qemu_unregister_reset(icp_kvm_reset, dev); -} - static void icp_kvm_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); ICPStateClass *icpc = ICP_CLASS(klass); - dc->realize = icp_kvm_realize; - dc->unrealize = icp_kvm_unrealize; icpc->pre_save = icp_get_kvm_state; icpc->post_load = icp_set_kvm_state; - icpc->cpu_setup = icp_kvm_cpu_setup; + icpc->realize = icp_kvm_realize; + icpc->reset = icp_kvm_reset; } static const TypeInfo icp_kvm_info = { @@ -351,10 +328,8 @@ static void ics_kvm_reset(void *dev) ics_set_kvm_state(ics, 1); } -static void ics_kvm_realize(DeviceState *dev, Error **errp) +static void ics_kvm_realize(ICSState *ics, Error **errp) { - ICSState *ics = ICS_SIMPLE(dev); - if (!ics->nr_irqs) { error_setg(errp, "Number of interrupts needs to be greater 0"); return; @@ -362,7 +337,7 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp) ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs); - qemu_register_reset(ics_kvm_reset, dev); + qemu_register_reset(ics_kvm_reset, ics); } static void ics_kvm_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/xics_pnv.c b/hw/intc/xics_pnv.c index 12ae605f10..2a955a8946 100644 --- a/hw/intc/xics_pnv.c +++ b/hw/intc/xics_pnv.c @@ -159,11 +159,11 @@ static const MemoryRegionOps pnv_icp_ops = { }, }; -static void pnv_icp_realize(DeviceState *dev, Error **errp) +static void pnv_icp_realize(ICPState *icp, Error **errp) { - PnvICPState *icp = PNV_ICP(dev); + PnvICPState *pnv_icp = PNV_ICP(icp); - memory_region_init_io(&icp->mmio, OBJECT(dev), &pnv_icp_ops, + memory_region_init_io(&pnv_icp->mmio, OBJECT(icp), &pnv_icp_ops, icp, "icp-thread", 0x1000); } diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index c8b489390f..20198466f0 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -1,6 +1,7 @@ common-obj-$(CONFIG_APPLESMC) += applesmc.o common-obj-$(CONFIG_MAX111X) += max111x.o common-obj-$(CONFIG_TMP105) += tmp105.o +common-obj-$(CONFIG_TMP421) += tmp421.o common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o common-obj-$(CONFIG_SGA) += sga.o common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c index 63a8ccd355..0d7b64c5b3 100644 --- a/hw/misc/exynos4210_pmu.c +++ b/hw/misc/exynos4210_pmu.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" +#include "sysemu/sysemu.h" #ifndef DEBUG_PMU #define DEBUG_PMU 0 @@ -350,7 +351,11 @@ static const Exynos4210PmuReg exynos4210_pmu_regs[] = { {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000}, {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000}, {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000}, - {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200}, + /* + * PS_HOLD_CONTROL: reset value and manually toggle high the DATA bit. + * DATA bit high, set usually by bootloader, keeps system on. + */ + {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200 | BIT(8)}, {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001}, {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001}, {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000}, @@ -397,6 +402,12 @@ typedef struct Exynos4210PmuState { uint32_t reg[PMU_NUM_OF_REGISTERS]; } Exynos4210PmuState; +static void exynos4210_pmu_poweroff(void) +{ + PRINT_DEBUG("QEMU PMU: PS_HOLD bit down, powering off\n"); + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); +} + static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset, unsigned size) { @@ -428,6 +439,13 @@ static void exynos4210_pmu_write(void *opaque, hwaddr offset, PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name, (uint32_t)offset, (uint32_t)val); s->reg[i] = val; + if ((offset == PS_HOLD_CONTROL) && ((val & BIT(8)) == 0)) { + /* + * We are interested only in setting data bit + * of PS_HOLD_CONTROL register to indicate power off request. + */ + exynos4210_pmu_poweroff(); + } return; } reg_p++; diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c new file mode 100644 index 0000000000..4a505abbce --- /dev/null +++ b/hw/misc/tmp421.c @@ -0,0 +1,402 @@ +/* + * Texas Instruments TMP421 temperature sensor. + * + * Copyright (c) 2016 IBM Corporation. + * + * Largely inspired by : + * + * Texas Instruments TMP105 temperature sensor. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski <andrew@openedhand.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/i2c/i2c.h" +#include "qapi/error.h" +#include "qapi/visitor.h" + +/* Manufacturer / Device ID's */ +#define TMP421_MANUFACTURER_ID 0x55 +#define TMP421_DEVICE_ID 0x21 +#define TMP422_DEVICE_ID 0x22 +#define TMP423_DEVICE_ID 0x23 + +typedef struct DeviceInfo { + int model; + const char *name; +} DeviceInfo; + +static const DeviceInfo devices[] = { + { TMP421_DEVICE_ID, "tmp421" }, + { TMP422_DEVICE_ID, "tmp422" }, + { TMP423_DEVICE_ID, "tmp423" }, +}; + +typedef struct TMP421State { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + + int16_t temperature[4]; + + uint8_t status; + uint8_t config[2]; + uint8_t rate; + + uint8_t len; + uint8_t buf[2]; + uint8_t pointer; + +} TMP421State; + +typedef struct TMP421Class { + I2CSlaveClass parent_class; + DeviceInfo *dev; +} TMP421Class; + +#define TYPE_TMP421 "tmp421-generic" +#define TMP421(obj) OBJECT_CHECK(TMP421State, (obj), TYPE_TMP421) + +#define TMP421_CLASS(klass) \ + OBJECT_CLASS_CHECK(TMP421Class, (klass), TYPE_TMP421) +#define TMP421_GET_CLASS(obj) \ + OBJECT_GET_CLASS(TMP421Class, (obj), TYPE_TMP421) + +/* the TMP421 registers */ +#define TMP421_STATUS_REG 0x08 +#define TMP421_STATUS_BUSY (1 << 7) +#define TMP421_CONFIG_REG_1 0x09 +#define TMP421_CONFIG_RANGE (1 << 2) +#define TMP421_CONFIG_SHUTDOWN (1 << 6) +#define TMP421_CONFIG_REG_2 0x0A +#define TMP421_CONFIG_RC (1 << 2) +#define TMP421_CONFIG_LEN (1 << 3) +#define TMP421_CONFIG_REN (1 << 4) +#define TMP421_CONFIG_REN2 (1 << 5) +#define TMP421_CONFIG_REN3 (1 << 6) + +#define TMP421_CONVERSION_RATE_REG 0x0B +#define TMP421_ONE_SHOT 0x0F + +#define TMP421_RESET 0xFC +#define TMP421_MANUFACTURER_ID_REG 0xFE +#define TMP421_DEVICE_ID_REG 0xFF + +#define TMP421_TEMP_MSB0 0x00 +#define TMP421_TEMP_MSB1 0x01 +#define TMP421_TEMP_MSB2 0x02 +#define TMP421_TEMP_MSB3 0x03 +#define TMP421_TEMP_LSB0 0x10 +#define TMP421_TEMP_LSB1 0x11 +#define TMP421_TEMP_LSB2 0x12 +#define TMP421_TEMP_LSB3 0x13 + +static const int32_t mins[2] = { -40000, -55000 }; +static const int32_t maxs[2] = { 127000, 150000 }; + +static void tmp421_get_temperature(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + TMP421State *s = TMP421(obj); + bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE); + int offset = ext_range * 64 * 256; + int64_t value; + int tempid; + + if (sscanf(name, "temperature%d", &tempid) != 1) { + error_setg(errp, "error reading %s: %m", name); + return; + } + + if (tempid >= 4 || tempid < 0) { + error_setg(errp, "error reading %s", name); + return; + } + + value = ((s->temperature[tempid] - offset) * 1000 + 128) / 256; + + visit_type_int(v, name, &value, errp); +} + +/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8 + * fixed point, so units are 1/256 centigrades. A simple ratio will do. + */ +static void tmp421_set_temperature(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + TMP421State *s = TMP421(obj); + Error *local_err = NULL; + int64_t temp; + bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE); + int offset = ext_range * 64 * 256; + int tempid; + + visit_type_int(v, name, &temp, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (temp >= maxs[ext_range] || temp < mins[ext_range]) { + error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range", + temp / 1000, temp % 1000); + return; + } + + if (sscanf(name, "temperature%d", &tempid) != 1) { + error_setg(errp, "error reading %s: %m", name); + return; + } + + if (tempid >= 4 || tempid < 0) { + error_setg(errp, "error reading %s", name); + return; + } + + s->temperature[tempid] = (int16_t) ((temp * 256 - 128) / 1000) + offset; +} + +static void tmp421_read(TMP421State *s) +{ + TMP421Class *sc = TMP421_GET_CLASS(s); + + s->len = 0; + + switch (s->pointer) { + case TMP421_MANUFACTURER_ID_REG: + s->buf[s->len++] = TMP421_MANUFACTURER_ID; + break; + case TMP421_DEVICE_ID_REG: + s->buf[s->len++] = sc->dev->model; + break; + case TMP421_CONFIG_REG_1: + s->buf[s->len++] = s->config[0]; + break; + case TMP421_CONFIG_REG_2: + s->buf[s->len++] = s->config[1]; + break; + case TMP421_CONVERSION_RATE_REG: + s->buf[s->len++] = s->rate; + break; + case TMP421_STATUS_REG: + s->buf[s->len++] = s->status; + break; + + /* FIXME: check for channel enablement in config registers */ + case TMP421_TEMP_MSB0: + s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0; + break; + case TMP421_TEMP_MSB1: + s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0; + break; + case TMP421_TEMP_MSB2: + s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0; + break; + case TMP421_TEMP_MSB3: + s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB0: + s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB1: + s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB2: + s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB3: + s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0; + break; + } +} + +static void tmp421_reset(I2CSlave *i2c); + +static void tmp421_write(TMP421State *s) +{ + switch (s->pointer) { + case TMP421_CONVERSION_RATE_REG: + s->rate = s->buf[0]; + break; + case TMP421_CONFIG_REG_1: + s->config[0] = s->buf[0]; + break; + case TMP421_CONFIG_REG_2: + s->config[1] = s->buf[0]; + break; + case TMP421_RESET: + tmp421_reset(I2C_SLAVE(s)); + break; + } +} + +static int tmp421_rx(I2CSlave *i2c) +{ + TMP421State *s = TMP421(i2c); + + if (s->len < 2) { + return s->buf[s->len++]; + } else { + return 0xff; + } +} + +static int tmp421_tx(I2CSlave *i2c, uint8_t data) +{ + TMP421State *s = TMP421(i2c); + + if (s->len == 0) { + /* first byte is the register pointer for a read or write + * operation */ + s->pointer = data; + s->len++; + } else if (s->len == 1) { + /* second byte is the data to write. The device only supports + * one byte writes */ + s->buf[0] = data; + tmp421_write(s); + } + + return 0; +} + +static int tmp421_event(I2CSlave *i2c, enum i2c_event event) +{ + TMP421State *s = TMP421(i2c); + + if (event == I2C_START_RECV) { + tmp421_read(s); + } + + s->len = 0; + return 0; +} + +static const VMStateDescription vmstate_tmp421 = { + .name = "TMP421", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(len, TMP421State), + VMSTATE_UINT8_ARRAY(buf, TMP421State, 2), + VMSTATE_UINT8(pointer, TMP421State), + VMSTATE_UINT8_ARRAY(config, TMP421State, 2), + VMSTATE_UINT8(status, TMP421State), + VMSTATE_UINT8(rate, TMP421State), + VMSTATE_INT16_ARRAY(temperature, TMP421State, 4), + VMSTATE_I2C_SLAVE(i2c, TMP421State), + VMSTATE_END_OF_LIST() + } +}; + +static void tmp421_reset(I2CSlave *i2c) +{ + TMP421State *s = TMP421(i2c); + TMP421Class *sc = TMP421_GET_CLASS(s); + + memset(s->temperature, 0, sizeof(s->temperature)); + s->pointer = 0; + + s->config[0] = 0; /* TMP421_CONFIG_RANGE */ + + /* resistance correction and channel enablement */ + switch (sc->dev->model) { + case TMP421_DEVICE_ID: + s->config[1] = 0x1c; + break; + case TMP422_DEVICE_ID: + s->config[1] = 0x3c; + break; + case TMP423_DEVICE_ID: + s->config[1] = 0x7c; + break; + } + + s->rate = 0x7; /* 8Hz */ + s->status = 0; +} + +static int tmp421_init(I2CSlave *i2c) +{ + TMP421State *s = TMP421(i2c); + + tmp421_reset(&s->i2c); + + return 0; +} + +static void tmp421_initfn(Object *obj) +{ + object_property_add(obj, "temperature0", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); + object_property_add(obj, "temperature1", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); + object_property_add(obj, "temperature2", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); + object_property_add(obj, "temperature3", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); +} + +static void tmp421_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + TMP421Class *sc = TMP421_CLASS(klass); + + k->init = tmp421_init; + k->event = tmp421_event; + k->recv = tmp421_rx; + k->send = tmp421_tx; + dc->vmsd = &vmstate_tmp421; + sc->dev = (DeviceInfo *) data; +} + +static const TypeInfo tmp421_info = { + .name = TYPE_TMP421, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(TMP421State), + .class_size = sizeof(TMP421Class), + .instance_init = tmp421_initfn, + .abstract = true, +}; + +static void tmp421_register_types(void) +{ + int i; + + type_register_static(&tmp421_info); + for (i = 0; i < ARRAY_SIZE(devices); ++i) { + TypeInfo ti = { + .name = devices[i].name, + .parent = TYPE_TMP421, + .class_init = tmp421_class_init, + .class_data = (void *) &devices[i], + }; + type_register(&ti); + } +} + +type_init(tmp421_register_types) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 9a3d769aa2..91eddaf93b 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -25,6 +25,7 @@ #include "qapi/qmp/qjson.h" #include "qapi-event.h" #include "hw/virtio/virtio-access.h" +#include "migration/misc.h" #define VIRTIO_NET_VM_VERSION 11 diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 4df31101ec..a19a7a31dd 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -26,6 +26,7 @@ #include "qemu/bswap.h" #include "hw/pci/msix.h" #include "hw/pci/msi.h" +#include "migration/register.h" #include "vmxnet3.h" #include "vmxnet_debug.h" diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 8ebffa8bb0..cb694d6da5 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -20,6 +20,14 @@ #define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100 #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1 +typedef struct GenPCIERootPort { + /*< private >*/ + PCIESlot parent_obj; + /*< public >*/ + + bool migrate_msix; +} GenPCIERootPort; + static uint8_t gen_rp_aer_vector(const PCIDevice *d) { return 0; @@ -45,6 +53,13 @@ static void gen_rp_interrupts_uninit(PCIDevice *d) msix_uninit_exclusive_bar(d); } +static bool gen_rp_test_migrate_msix(void *opaque, int version_id) +{ + GenPCIERootPort *rp = opaque; + + return rp->migrate_msix; +} + static const VMStateDescription vmstate_rp_dev = { .name = "pcie-root-port", .version_id = 1, @@ -54,10 +69,18 @@ static const VMStateDescription vmstate_rp_dev = { VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), + VMSTATE_MSIX_TEST(parent_obj.parent_obj.parent_obj.parent_obj, + GenPCIERootPort, + gen_rp_test_migrate_msix), VMSTATE_END_OF_LIST() } }; +static Property gen_rp_props[] = { + DEFINE_PROP_BOOL("x-migrate-msix", GenPCIERootPort, migrate_msix, true), + DEFINE_PROP_END_OF_LIST() +}; + static void gen_rp_dev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -68,6 +91,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_RP; dc->desc = "PCI Express Root Port"; dc->vmsd = &vmstate_rp_dev; + dc->props = gen_rp_props; rpc->aer_vector = gen_rp_aer_vector; rpc->interrupts_init = gen_rp_interrupts_init; rpc->interrupts_uninit = gen_rp_interrupts_uninit; @@ -77,6 +101,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) static const TypeInfo gen_rp_dev_info = { .name = TYPE_GEN_PCIE_ROOT_PORT, .parent = TYPE_PCIE_ROOT_PORT, + .instance_size = sizeof(GenPCIERootPort), .class_init = gen_rp_dev_class_init, }; diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 1b7ec70f03..c7b00b610c 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -118,18 +118,20 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp) PowerPCCPU *cpu = POWERPC_CPU(cs); Object *obj; - obj = object_new(TYPE_PNV_ICP); - object_property_add_child(OBJECT(cpu), "icp", obj, NULL); - object_property_add_const_link(obj, "xics", OBJECT(xi), &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + object_property_set_bool(child, true, "realized", &local_err); if (local_err) { error_propagate(errp, local_err); return; } - object_property_set_bool(child, true, "realized", &local_err); + obj = object_new(TYPE_PNV_ICP); + object_property_add_child(child, "icp", obj, NULL); + object_unref(obj); + object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(xi), + &error_abort); + object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort); + object_property_set_bool(obj, true, "realized", &local_err); if (local_err) { - object_unparent(obj); error_propagate(errp, local_err); return; } @@ -140,8 +142,6 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp) error_propagate(errp, local_err); return; } - - xics_cpu_setup(xi, cpu, ICP(obj)); } static void pnv_core_realize(DeviceState *dev, Error **errp) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 2bf5bfe3fd..9876c26622 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -474,7 +474,8 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp) } /* Create PSI interrupt control source */ - object_property_add_const_link(OBJECT(ics), "xics", obj, &error_abort); + object_property_add_const_link(OBJECT(ics), ICS_PROP_XICS, obj, + &error_abort); object_property_set_int(OBJECT(ics), PSI_NUM_INTERRUPTS, "nr-irqs", &err); if (err) { error_propagate(errp, err); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 91b4057933..e877d45db8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -38,7 +38,9 @@ #include "sysemu/cpus.h" #include "sysemu/hw_accel.h" #include "kvm_ppc.h" -#include "migration/migration.h" +#include "migration/misc.h" +#include "migration/global_state.h" +#include "migration/register.h" #include "mmu-hash64.h" #include "mmu-book3s-v3.h" #include "qom/cpu.h" @@ -107,7 +109,8 @@ static ICSState *spapr_ics_create(sPAPRMachineState *spapr, obj = object_new(type_ics); object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); - object_property_add_const_link(obj, "xics", OBJECT(spapr), &error_abort); + object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), + &error_abort); object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err); if (local_err) { goto error; @@ -2441,6 +2444,12 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32); } + if (g_str_equal("pci-bridge", qdev_fw_name(dev))) { + /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */ + PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE); + return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn)); + } + return NULL; } @@ -2523,7 +2532,6 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, Error **errp) { sPAPRDRConnector *drc; - sPAPRDRConnectorClass *drck; uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE; int i, fdt_offset, fdt_size; void *fdt; @@ -2538,10 +2546,10 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, fdt_offset = spapr_populate_memory_node(fdt, node, addr, SPAPR_MEMORY_BLOCK_SIZE); - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp); + spapr_drc_attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp); addr += SPAPR_MEMORY_BLOCK_SIZE; if (!dev->hotplugged) { + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); /* guests expect coldplugged LMBs to be pre-allocated */ drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE); drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED); @@ -2554,7 +2562,6 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, if (dedicated_hp_event_source) { drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr_start / SPAPR_MEMORY_BLOCK_SIZE); - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs, spapr_drc_index(drc)); @@ -2615,8 +2622,11 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, if (mem_dev && !kvmppc_is_mem_backend_page_size_ok(mem_dev)) { error_setg(errp, "Memory backend has bad page size. " "Use 'memory-backend-file' with correct mem-path."); - return; + goto out; } + +out: + g_free(mem_dev); } struct sPAPRDIMMState { @@ -2673,7 +2683,7 @@ static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms, drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / SPAPR_MEMORY_BLOCK_SIZE); g_assert(drc); - if (drc->indicator_state != SPAPR_DR_INDICATOR_STATE_INACTIVE) { + if (drc->dev) { avail_lmbs++; } addr += SPAPR_MEMORY_BLOCK_SIZE; @@ -2697,10 +2707,11 @@ void spapr_lmb_release(DeviceState *dev) * during the unplug process. In this case recover it. */ if (ds == NULL) { ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev)); - if (ds->nr_lmbs) { - return; - } - } else if (--ds->nr_lmbs) { + /* The DRC being examined by the caller at least must be counted */ + g_assert(ds->nr_lmbs); + } + + if (--ds->nr_lmbs) { return; } @@ -2738,7 +2749,6 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, uint64_t addr_start, addr; int i; sPAPRDRConnector *drc; - sPAPRDRConnectorClass *drck; sPAPRDIMMState *ds; addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, @@ -2758,14 +2768,12 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, addr / SPAPR_MEMORY_BLOCK_SIZE); g_assert(drc); - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->detach(drc, dev, errp); + spapr_drc_detach(drc, dev, errp); addr += SPAPR_MEMORY_BLOCK_SIZE; } drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr_start / SPAPR_MEMORY_BLOCK_SIZE); - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs, spapr_drc_index(drc)); out: @@ -2820,7 +2828,6 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, { int index; sPAPRDRConnector *drc; - sPAPRDRConnectorClass *drck; Error *local_err = NULL; CPUCore *cc = CPU_CORE(dev); int smt = kvmppc_smt_threads(); @@ -2838,8 +2845,7 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index * smt); g_assert(drc); - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->detach(drc, dev, &local_err); + spapr_drc_detach(drc, dev, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -2883,8 +2889,8 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, } if (drc) { - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err); + spapr_drc_attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, + &local_err); if (local_err) { g_free(fdt); error_propagate(errp, local_err); diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 029a14120e..9fb896b407 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -53,9 +53,6 @@ static void spapr_cpu_reset(void *opaque) static void spapr_cpu_destroy(PowerPCCPU *cpu) { - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - - xics_cpu_destroy(XICS_FABRIC(spapr), cpu); qemu_unregister_reset(spapr_cpu_reset, cpu); } @@ -140,28 +137,29 @@ static void spapr_cpu_core_realize_child(Object *child, Error **errp) sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); CPUState *cs = CPU(child); PowerPCCPU *cpu = POWERPC_CPU(cs); - Object *obj; + Object *obj = NULL; - obj = object_new(spapr->icp_type); - object_property_add_child(OBJECT(cpu), "icp", obj, &error_abort); - object_unref(obj); - object_property_add_const_link(obj, "xics", OBJECT(spapr), &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + object_property_set_bool(child, true, "realized", &local_err); if (local_err) { goto error; } - object_property_set_bool(child, true, "realized", &local_err); + spapr_cpu_init(spapr, cpu, &local_err); if (local_err) { goto error; } - spapr_cpu_init(spapr, cpu, &local_err); + obj = object_new(spapr->icp_type); + object_property_add_child(child, "icp", obj, &error_abort); + object_unref(obj); + object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(spapr), + &error_abort); + object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort); + object_property_set_bool(obj, true, "realized", &local_err); if (local_err) { goto error; } - xics_cpu_setup(XICS_FABRIC(spapr), cpu, ICP(obj)); return; error: diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 39e7f3080a..5cb75bbf34 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -49,8 +49,6 @@ uint32_t spapr_drc_index(sPAPRDRConnector *drc) static uint32_t set_isolation_state(sPAPRDRConnector *drc, sPAPRDRIsolationState state) { - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - trace_spapr_drc_set_isolation_state(spapr_drc_index(drc), state); /* if the guest is configuring a device attached to this DRC, we @@ -105,7 +103,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, uint32_t drc_index = spapr_drc_index(drc); if (drc->configured) { trace_spapr_drc_set_isolation_state_finalizing(drc_index); - drck->detach(drc, DEVICE(drc->dev), NULL); + spapr_drc_detach(drc, DEVICE(drc->dev), NULL); } else { trace_spapr_drc_set_isolation_state_deferring(drc_index); } @@ -116,19 +114,9 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, return RTAS_OUT_SUCCESS; } -static uint32_t set_indicator_state(sPAPRDRConnector *drc, - sPAPRDRIndicatorState state) -{ - trace_spapr_drc_set_indicator_state(spapr_drc_index(drc), state); - drc->indicator_state = state; - return RTAS_OUT_SUCCESS; -} - static uint32_t set_allocation_state(sPAPRDRConnector *drc, sPAPRDRAllocationState state) { - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - trace_spapr_drc_set_allocation_state(spapr_drc_index(drc), state); if (state == SPAPR_DR_ALLOCATION_STATE_USABLE) { @@ -140,17 +128,6 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, if (!drc->dev) { return RTAS_OUT_NO_SUCH_INDICATOR; } - if (drc->awaiting_release && drc->awaiting_allocation) { - /* kernel is acknowledging a previous hotplug event - * while we are already removing it. - * it's safe to ignore awaiting_allocation here since we know the - * situation is predicated on the guest either already having done - * so (boot-time hotplug), or never being able to acquire in the - * first place (hotplug followed by immediate unplug). - */ - drc->awaiting_allocation_skippable = true; - return RTAS_OUT_NO_SUCH_INDICATOR; - } } if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) { @@ -159,7 +136,7 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) { uint32_t drc_index = spapr_drc_index(drc); trace_spapr_drc_set_allocation_state_finalizing(drc_index); - drck->detach(drc, DEVICE(drc->dev), NULL); + spapr_drc_detach(drc, DEVICE(drc->dev), NULL); } else if (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) { drc->awaiting_allocation = false; } @@ -167,9 +144,32 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, return RTAS_OUT_SUCCESS; } -static const char *get_name(sPAPRDRConnector *drc) +static const char *spapr_drc_name(sPAPRDRConnector *drc) { - return drc->name; + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + + /* human-readable name for a DRC to encode into the DT + * description. this is mainly only used within a guest in place + * of the unique DRC index. + * + * in the case of VIO/PCI devices, it corresponds to a "location + * code" that maps a logical device/function (DRC index) to a + * physical (or virtual in the case of VIO) location in the system + * by chaining together the "location label" for each + * encapsulating component. + * + * since this is more to do with diagnosing physical hardware + * issues than guest compatibility, we choose location codes/DRC + * names that adhere to the documented format, but avoid encoding + * the entire topology information into the label/code, instead + * just using the location codes based on the labels for the + * endpoints (VIO/PCI adaptor connectors), which is basically just + * "C" followed by an integer ID. + * + * DRC names as documented by PAPR+ v2.7, 13.5.2.4 + * location codes as documented by PAPR+ v2.7, 12.3.1.5 + */ + return g_strdup_printf("%s%d", drck->drc_name_prefix, drc->id); } /* has the guest been notified of device attachment? */ @@ -185,39 +185,25 @@ static void set_signalled(sPAPRDRConnector *drc) * based on the current allocation/indicator/power states * for the DR connector. */ -static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state) +static sPAPRDREntitySense physical_entity_sense(sPAPRDRConnector *drc) { - if (drc->dev) { - if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI && - drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) { - /* for logical DR, we return a state of UNUSABLE - * iff the allocation state UNUSABLE. - * Otherwise, report the state as USABLE/PRESENT, - * as we would for PCI. - */ - *state = SPAPR_DR_ENTITY_SENSE_UNUSABLE; - } else { - /* this assumes all PCI devices are assigned to - * a 'live insertion' power domain, where QEMU - * manages power state automatically as opposed - * to the guest. present, non-PCI resources are - * unaffected by power state. - */ - *state = SPAPR_DR_ENTITY_SENSE_PRESENT; - } + /* this assumes all PCI devices are assigned to a 'live insertion' + * power domain, where QEMU manages power state automatically as + * opposed to the guest. present, non-PCI resources are unaffected + * by power state. + */ + return drc->dev ? SPAPR_DR_ENTITY_SENSE_PRESENT + : SPAPR_DR_ENTITY_SENSE_EMPTY; +} + +static sPAPRDREntitySense logical_entity_sense(sPAPRDRConnector *drc) +{ + if (drc->dev + && (drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE)) { + return SPAPR_DR_ENTITY_SENSE_PRESENT; } else { - if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) { - /* PCI devices, and only PCI devices, use EMPTY - * in cases where we'd otherwise use UNUSABLE - */ - *state = SPAPR_DR_ENTITY_SENSE_EMPTY; - } else { - *state = SPAPR_DR_ENTITY_SENSE_UNUSABLE; - } + return SPAPR_DR_ENTITY_SENSE_UNUSABLE; } - - trace_spapr_drc_entity_sense(spapr_drc_index(drc), *state); - return RTAS_OUT_SUCCESS; } static void prop_get_index(Object *obj, Visitor *v, const char *name, @@ -228,13 +214,6 @@ static void prop_get_index(Object *obj, Visitor *v, const char *name, visit_type_uint32(v, name, &value, errp); } -static char *prop_get_name(Object *obj, Error **errp) -{ - sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj); - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - return g_strdup(drck->get_name(drc)); -} - static void prop_get_fdt(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -311,8 +290,8 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, } while (fdt_depth != 0); } -static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, - int fdt_start_offset, bool coldplug, Error **errp) +void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, + int fdt_start_offset, bool coldplug, Error **errp) { trace_spapr_drc_attach(spapr_drc_index(drc)); @@ -335,7 +314,7 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) { drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED; } - drc->indicator_state = SPAPR_DR_INDICATOR_STATE_ACTIVE; + drc->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE; drc->dev = d; drc->fdt = fdt; @@ -363,7 +342,7 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, NULL, 0, NULL); } -static void detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp) +void spapr_drc_detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp) { trace_spapr_drc_detach(spapr_drc_index(drc)); @@ -401,14 +380,12 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp) } if (drc->awaiting_allocation) { - if (!drc->awaiting_allocation_skippable) { - drc->awaiting_release = true; - trace_spapr_drc_awaiting_allocation(spapr_drc_index(drc)); - return; - } + drc->awaiting_release = true; + trace_spapr_drc_awaiting_allocation(spapr_drc_index(drc)); + return; } - drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE; + drc->dr_indicator = SPAPR_DR_INDICATOR_INACTIVE; /* Calling release callbacks based on spapr_drc_type(drc). */ switch (spapr_drc_type(drc)) { @@ -428,7 +405,6 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp) } drc->awaiting_release = false; - drc->awaiting_allocation_skippable = false; g_free(drc->fdt); drc->fdt = NULL; drc->fdt_start_offset = 0; @@ -445,7 +421,6 @@ static void reset(DeviceState *d) { sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d); sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - sPAPRDREntitySense state; trace_spapr_drc_reset(spapr_drc_index(drc)); @@ -467,7 +442,7 @@ static void reset(DeviceState *d) * force removal if we are */ if (drc->awaiting_release) { - drck->detach(drc, DEVICE(drc->dev), NULL); + spapr_drc_detach(drc, DEVICE(drc->dev), NULL); } /* non-PCI devices may be awaiting a transition to UNUSABLE */ @@ -477,8 +452,7 @@ static void reset(DeviceState *d) } } - drck->entity_sense(drc, &state); - if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) { + if (drck->dr_entity_sense(drc) == SPAPR_DR_ENTITY_SENSE_PRESENT) { drck->set_signalled(drc); } } @@ -488,8 +462,7 @@ static bool spapr_drc_needed(void *opaque) sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque; sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); bool rc = false; - sPAPRDREntitySense value; - drck->entity_sense(drc, &value); + sPAPRDREntitySense value = drck->dr_entity_sense(drc); /* If no dev is plugged in there is no need to migrate the DRC state */ if (value != SPAPR_DR_ENTITY_SENSE_PRESENT) { @@ -524,7 +497,7 @@ static const VMStateDescription vmstate_spapr_drc = { .fields = (VMStateField []) { VMSTATE_UINT32(isolation_state, sPAPRDRConnector), VMSTATE_UINT32(allocation_state, sPAPRDRConnector), - VMSTATE_UINT32(indicator_state, sPAPRDRConnector), + VMSTATE_UINT32(dr_indicator, sPAPRDRConnector), VMSTATE_BOOL(configured, sPAPRDRConnector), VMSTATE_BOOL(awaiting_release, sPAPRDRConnector), VMSTATE_BOOL(awaiting_allocation, sPAPRDRConnector), @@ -596,45 +569,6 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type, object_property_set_bool(OBJECT(drc), true, "realized", NULL); g_free(prop_name); - /* human-readable name for a DRC to encode into the DT - * description. this is mainly only used within a guest in place - * of the unique DRC index. - * - * in the case of VIO/PCI devices, it corresponds to a - * "location code" that maps a logical device/function (DRC index) - * to a physical (or virtual in the case of VIO) location in the - * system by chaining together the "location label" for each - * encapsulating component. - * - * since this is more to do with diagnosing physical hardware - * issues than guest compatibility, we choose location codes/DRC - * names that adhere to the documented format, but avoid encoding - * the entire topology information into the label/code, instead - * just using the location codes based on the labels for the - * endpoints (VIO/PCI adaptor connectors), which is basically - * just "C" followed by an integer ID. - * - * DRC names as documented by PAPR+ v2.7, 13.5.2.4 - * location codes as documented by PAPR+ v2.7, 12.3.1.5 - */ - switch (spapr_drc_type(drc)) { - case SPAPR_DR_CONNECTOR_TYPE_CPU: - drc->name = g_strdup_printf("CPU %d", id); - break; - case SPAPR_DR_CONNECTOR_TYPE_PHB: - drc->name = g_strdup_printf("PHB %d", id); - break; - case SPAPR_DR_CONNECTOR_TYPE_VIO: - case SPAPR_DR_CONNECTOR_TYPE_PCI: - drc->name = g_strdup_printf("C%d", id); - break; - case SPAPR_DR_CONNECTOR_TYPE_LMB: - drc->name = g_strdup_printf("LMB %d", id); - break; - default: - g_assert(false); - } - /* PCI slot always start in a USABLE state, and stay there */ if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) { drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE; @@ -650,7 +584,6 @@ static void spapr_dr_connector_instance_init(Object *obj) object_property_add_uint32_ptr(obj, "id", &drc->id, NULL); object_property_add(obj, "index", "uint32", prop_get_index, NULL, NULL, NULL, NULL); - object_property_add_str(obj, "name", prop_get_name, NULL, NULL); object_property_add(obj, "fdt", "struct", prop_get_fdt, NULL, NULL, NULL, NULL); } @@ -664,12 +597,7 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data) dk->realize = realize; dk->unrealize = unrealize; drck->set_isolation_state = set_isolation_state; - drck->set_indicator_state = set_indicator_state; drck->set_allocation_state = set_allocation_state; - drck->get_name = get_name; - drck->entity_sense = entity_sense; - drck->attach = attach; - drck->detach = detach; drck->release_pending = release_pending; drck->set_signalled = set_signalled; /* @@ -678,12 +606,27 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data) dk->user_creatable = false; } +static void spapr_drc_physical_class_init(ObjectClass *k, void *data) +{ + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); + + drck->dr_entity_sense = physical_entity_sense; +} + +static void spapr_drc_logical_class_init(ObjectClass *k, void *data) +{ + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); + + drck->dr_entity_sense = logical_entity_sense; +} + static void spapr_drc_cpu_class_init(ObjectClass *k, void *data) { sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU; drck->typename = "CPU"; + drck->drc_name_prefix = "CPU "; } static void spapr_drc_pci_class_init(ObjectClass *k, void *data) @@ -692,6 +635,7 @@ static void spapr_drc_pci_class_init(ObjectClass *k, void *data) drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI; drck->typename = "28"; + drck->drc_name_prefix = "C"; } static void spapr_drc_lmb_class_init(ObjectClass *k, void *data) @@ -700,6 +644,7 @@ static void spapr_drc_lmb_class_init(ObjectClass *k, void *data) drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB; drck->typename = "MEM"; + drck->drc_name_prefix = "LMB "; } static const TypeInfo spapr_dr_connector_info = { @@ -716,6 +661,7 @@ static const TypeInfo spapr_drc_physical_info = { .name = TYPE_SPAPR_DRC_PHYSICAL, .parent = TYPE_SPAPR_DR_CONNECTOR, .instance_size = sizeof(sPAPRDRConnector), + .class_init = spapr_drc_physical_class_init, .abstract = true, }; @@ -723,6 +669,7 @@ static const TypeInfo spapr_drc_logical_info = { .name = TYPE_SPAPR_DRC_LOGICAL, .parent = TYPE_SPAPR_DR_CONNECTOR, .instance_size = sizeof(sPAPRDRConnector), + .class_init = spapr_drc_logical_class_init, .abstract = true, }; @@ -846,7 +793,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, g_array_append_val(drc_power_domains, drc_power_domain); /* ibm,drc-names */ - drc_names = g_string_append(drc_names, drck->get_name(drc)); + drc_names = g_string_append(drc_names, spapr_drc_name(drc)); drc_names = g_string_insert_len(drc_names, -1, "\0", 1); /* ibm,drc-types */ @@ -905,74 +852,78 @@ out: * RTAS calls */ -static bool sensor_type_is_dr(uint32_t sensor_type) +static uint32_t rtas_set_isolation_state(uint32_t idx, uint32_t state) { - switch (sensor_type) { - case RTAS_SENSOR_TYPE_ISOLATION_STATE: - case RTAS_SENSOR_TYPE_DR: - case RTAS_SENSOR_TYPE_ALLOCATION_STATE: - return true; + sPAPRDRConnector *drc = spapr_drc_by_index(idx); + sPAPRDRConnectorClass *drck; + + if (!drc) { + return RTAS_OUT_PARAM_ERROR; } - return false; + drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + return drck->set_isolation_state(drc, state); } -static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, uint32_t nret, - target_ulong rets) +static uint32_t rtas_set_allocation_state(uint32_t idx, uint32_t state) { - uint32_t sensor_type; - uint32_t sensor_index; - uint32_t sensor_state; - uint32_t ret = RTAS_OUT_SUCCESS; - sPAPRDRConnector *drc; + sPAPRDRConnector *drc = spapr_drc_by_index(idx); sPAPRDRConnectorClass *drck; - if (nargs != 3 || nret != 1) { - ret = RTAS_OUT_PARAM_ERROR; - goto out; + if (!drc) { + return RTAS_OUT_PARAM_ERROR; } - sensor_type = rtas_ld(args, 0); - sensor_index = rtas_ld(args, 1); - sensor_state = rtas_ld(args, 2); + drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + return drck->set_allocation_state(drc, state); +} - if (!sensor_type_is_dr(sensor_type)) { - goto out_unimplemented; - } +static uint32_t rtas_set_dr_indicator(uint32_t idx, uint32_t state) +{ + sPAPRDRConnector *drc = spapr_drc_by_index(idx); - /* if this is a DR sensor we can assume sensor_index == drc_index */ - drc = spapr_drc_by_index(sensor_index); if (!drc) { - trace_spapr_rtas_set_indicator_invalid(sensor_index); + return RTAS_OUT_PARAM_ERROR; + } + + trace_spapr_drc_set_dr_indicator(idx, state); + drc->dr_indicator = state; + return RTAS_OUT_SUCCESS; +} + +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t type, idx, state; + uint32_t ret = RTAS_OUT_SUCCESS; + + if (nargs != 3 || nret != 1) { ret = RTAS_OUT_PARAM_ERROR; goto out; } - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - switch (sensor_type) { + type = rtas_ld(args, 0); + idx = rtas_ld(args, 1); + state = rtas_ld(args, 2); + + switch (type) { case RTAS_SENSOR_TYPE_ISOLATION_STATE: - ret = drck->set_isolation_state(drc, sensor_state); + ret = rtas_set_isolation_state(idx, state); break; case RTAS_SENSOR_TYPE_DR: - ret = drck->set_indicator_state(drc, sensor_state); + ret = rtas_set_dr_indicator(idx, state); break; case RTAS_SENSOR_TYPE_ALLOCATION_STATE: - ret = drck->set_allocation_state(drc, sensor_state); + ret = rtas_set_allocation_state(idx, state); break; default: - goto out_unimplemented; + ret = RTAS_OUT_NOT_SUPPORTED; } out: rtas_st(rets, 0, ret); - return; - -out_unimplemented: - /* currently only DR-related sensors are implemented */ - trace_spapr_rtas_set_indicator_not_supported(sensor_index, sensor_type); - rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED); } static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr, @@ -1010,7 +961,7 @@ static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr, goto out; } drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - ret = drck->entity_sense(drc, &sensor_state); + sensor_state = drck->dr_entity_sense(drc); out: rtas_st(rets, 0, ret); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 0c181bbca5..0b447f2eed 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1344,31 +1344,6 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev, return offset; } -static void spapr_phb_add_pci_device(sPAPRDRConnector *drc, - sPAPRPHBState *phb, - PCIDevice *pdev, - Error **errp) -{ - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - DeviceState *dev = DEVICE(pdev); - void *fdt = NULL; - int fdt_start_offset = 0, fdt_size; - - fdt = create_device_tree(&fdt_size); - fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0); - if (!fdt_start_offset) { - error_setg(errp, "Failed to create pci child device tree node"); - goto out; - } - - drck->attach(drc, DEVICE(pdev), - fdt, fdt_start_offset, !dev->hotplugged, errp); -out: - if (*errp) { - g_free(fdt); - } -} - /* Callback to be called during DRC release. */ void spapr_phb_remove_pci_device_cb(DeviceState *dev) { @@ -1386,16 +1361,6 @@ void spapr_phb_remove_pci_device_cb(DeviceState *dev) object_unparent(OBJECT(dev)); } -static void spapr_phb_remove_pci_device(sPAPRDRConnector *drc, - sPAPRPHBState *phb, - PCIDevice *pdev, - Error **errp) -{ - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - - drck->detach(drc, DEVICE(pdev), errp); -} - static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb, uint32_t busnr, int32_t devfn) @@ -1432,6 +1397,8 @@ static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler, Error *local_err = NULL; PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))); uint32_t slotnr = PCI_SLOT(pdev->devfn); + void *fdt = NULL; + int fdt_start_offset, fdt_size; /* if DR is disabled we don't need to do anything in the case of * hotplug or coldplug callbacks @@ -1441,10 +1408,10 @@ static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler, * we need to let them know it's not enabled */ if (plugged_dev->hotplugged) { - error_setg(errp, QERR_BUS_NO_HOTPLUG, + error_setg(&local_err, QERR_BUS_NO_HOTPLUG, object_get_typename(OBJECT(phb))); } - return; + goto out; } g_assert(drc); @@ -1455,16 +1422,23 @@ static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler, */ if (plugged_dev->hotplugged && bus->devices[PCI_DEVFN(slotnr, 0)] && PCI_FUNC(pdev->devfn) != 0) { - error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s," + error_setg(&local_err, "PCI: slot %d function 0 already ocuppied by %s," " additional functions can no longer be exposed to guest.", slotnr, bus->devices[PCI_DEVFN(slotnr, 0)]->name); - return; + goto out; + } + + fdt = create_device_tree(&fdt_size); + fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0); + if (!fdt_start_offset) { + error_setg(&local_err, "Failed to create pci child device tree node"); + goto out; } - spapr_phb_add_pci_device(drc, phb, pdev, &local_err); + spapr_drc_attach(drc, DEVICE(pdev), fdt, fdt_start_offset, + !plugged_dev->hotplugged, &local_err); if (local_err) { - error_propagate(errp, local_err); - return; + goto out; } /* If this is function 0, signal hotplug for all the device functions. @@ -1481,13 +1455,19 @@ static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler, func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus), PCI_DEVFN(slotnr, i)); func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc); - func_drck->entity_sense(func_drc, &state); + state = func_drck->dr_entity_sense(func_drc); if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) { spapr_hotplug_req_add_by_index(func_drc); } } } + +out: + if (local_err) { + error_propagate(errp, local_err); + g_free(fdt); + } } static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler, @@ -1522,7 +1502,7 @@ static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler, func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus), PCI_DEVFN(slotnr, i)); func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc); - func_drck->entity_sense(func_drc, &state); + state = func_drck->dr_entity_sense(func_drc); if (state == SPAPR_DR_ENTITY_SENSE_PRESENT && !func_drck->release_pending(func_drc)) { error_setg(errp, @@ -1534,7 +1514,7 @@ static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler, } } - spapr_phb_remove_pci_device(drc, phb, pdev, &local_err); + spapr_drc_detach(drc, DEVICE(pdev), &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1548,7 +1528,7 @@ static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler, func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus), PCI_DEVFN(slotnr, i)); func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc); - func_drck->entity_sense(func_drc, &state); + state = func_drck->dr_entity_sense(func_drc); if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) { spapr_hotplug_req_remove_by_index(func_drc); } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 707c4d4936..94a2799b99 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -293,12 +293,9 @@ static void rtas_ibm_os_term(PowerPCCPU *cpu, target_ulong args, uint32_t nret, target_ulong rets) { - target_ulong ret = 0; + qemu_system_guest_panicked(NULL); - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, false, NULL, - &error_abort); - - rtas_st(rets, 0, ret); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_set_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr, diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 43d265f351..3e8e3cffde 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -39,12 +39,11 @@ spapr_iommu_ddw_reset(uint64_t buid, uint32_t cfgaddr) "buid=%"PRIx64" addr=%"PR spapr_drc_set_isolation_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: %"PRIx32 spapr_drc_set_isolation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_set_isolation_state_deferring(uint32_t index) "drc: 0x%"PRIx32 -spapr_drc_set_indicator_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" +spapr_drc_set_dr_indicator(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" spapr_drc_set_allocation_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" spapr_drc_set_allocation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_set_configured(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_set_configured_skipping(uint32_t index) "drc: 0x%"PRIx32", isolated device" -spapr_drc_entity_sense(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" spapr_drc_attach(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_detach(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_awaiting_isolated(uint32_t index) "drc: 0x%"PRIx32 @@ -61,8 +60,6 @@ spapr_ovec_parse_vector(int vector, int byte, uint16_t vec_len, uint8_t entry) " spapr_ovec_populate_dt(int byte, uint16_t vec_len, uint8_t entry) "encoding guest vector byte %3d / %3d: 0x%.2x" # hw/ppc/spapr_rtas.c -spapr_rtas_set_indicator_invalid(uint32_t index) "sensor index: 0x%"PRIx32 -spapr_rtas_set_indicator_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32 spapr_rtas_get_sensor_state_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32 spapr_rtas_get_sensor_state_invalid(uint32_t index) "sensor index: 0x%"PRIx32 spapr_rtas_ibm_configure_connector_invalid(uint32_t index) "DRC index: 0x%"PRIx32 diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 1e2f26b65a..599805d275 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -15,6 +15,7 @@ #include "hw/qdev.h" #include "qemu/error-report.h" #include "qemu/bitops.h" +#include "qemu/error-report.h" #include "exec/address-spaces.h" #include "cpu.h" #include "hw/s390x/ioinst.h" @@ -432,6 +433,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, return -EINVAL; } + /* We don't support MIDA. */ + if (ccw.flags & CCW_FLAG_MIDA) { + return -EINVAL; + } + if (ccw.flags & CCW_FLAG_SUSPEND) { return suspend_allowed ? -EINPROGRESS : -EINVAL; } @@ -1800,13 +1806,26 @@ void subch_device_save(SubchDev *s, QEMUFile *f) int subch_device_load(SubchDev *s, QEMUFile *f) { SubchDev *old_s; + Error *err = NULL; uint16_t old_schid = s->schid; + uint16_t old_devno = s->devno; int i; s->cssid = qemu_get_byte(f); s->ssid = qemu_get_byte(f); s->schid = qemu_get_be16(f); s->devno = qemu_get_be16(f); + if (s->devno != old_devno) { + /* Only possible if machine < 2.7 (no css_dev_path) */ + + error_setg(&err, "%x != %x", old_devno, s->devno); + error_append_hint(&err, "Devno mismatch, tried to load wrong section!" + " Likely reason: some sequences of plug and unplug" + " can break migration for machine versions prior to" + " 2.7 (known design flaw).\n"); + error_report_err(err); + return -EINVAL; + } /* Re-assign subch. */ if (old_schid != s->schid) { old_s = channel_subsys.css[s->cssid]->sch_set[s->ssid]->sch[old_schid]; diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index 35e7f6316f..c0de3b0c35 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -15,6 +15,7 @@ #include "hw/s390x/storage-keys.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" +#include "migration/register.h" #define S390_SKEYS_BUFFER_SIZE 131072 /* Room for 128k storage keys */ #define S390_SKEYS_SAVE_FLAG_EOS 0x01 diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index a806345276..41ca6668e2 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -28,6 +28,7 @@ #include "ipl.h" #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/css-bridge.h" +#include "migration/register.h" static const char *const reset_dev_types[] = { TYPE_VIRTUAL_CSS_BRIDGE, diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e6a6f74be3..90d37cb9ff 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1279,9 +1279,13 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) SubchDev *s = ccw_dev->sch; VirtIODevice *vdev = virtio_ccw_get_vdev(s); int len; + int ret; s->driver_data = dev; - subch_device_load(s, f); + ret = subch_device_load(s, f); + if (ret) { + return ret; + } /* Re-fill subch_id after loading the subchannel states.*/ if (ck->refill_ids) { ck->refill_ids(ccw_dev); diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 9b70ee09b0..50acbf530a 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -130,15 +130,26 @@ static uint64_t calculate_next(struct AspeedTimer *t) next = seq[1]; } else if (now < seq[2]) { next = seq[2]; - } else { + } else if (t->reload) { reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate); t->start = now - ((now - t->start) % reload_ns); + } else { + /* no reload value, return 0 */ + break; } } return next; } +static void aspeed_timer_mod(AspeedTimer *t) +{ + uint64_t next = calculate_next(t); + if (next) { + timer_mod(&t->timer, next); + } +} + static void aspeed_timer_expire(void *opaque) { AspeedTimer *t = opaque; @@ -164,7 +175,7 @@ static void aspeed_timer_expire(void *opaque) qemu_set_irq(t->irq, t->level); } - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg) @@ -227,10 +238,23 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, uint32_t value) { AspeedTimer *t; + uint32_t old_reload; trace_aspeed_timer_set_value(timer, reg, value); t = &s->timers[timer]; switch (reg) { + case TIMER_REG_RELOAD: + old_reload = t->reload; + t->reload = value; + + /* If the reload value was not previously set, or zero, and + * the current value is valid, try to start the timer if it is + * enabled. + */ + if (old_reload || !t->reload) { + break; + } + case TIMER_REG_STATUS: if (timer_enabled(t)) { uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); @@ -238,17 +262,14 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, uint32_t rate = calculate_rate(t); t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate); - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } break; - case TIMER_REG_RELOAD: - t->reload = value; - break; case TIMER_REG_MATCH_FIRST: case TIMER_REG_MATCH_SECOND: t->match[reg - 2] = value; if (timer_enabled(t)) { - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } break; default: @@ -268,7 +289,7 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable) trace_aspeed_timer_ctrl_enable(t->id, enable); if (enable) { t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } else { timer_del(&t->timer); } diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index a2ec3920f8..e4ef4cfd36 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -173,13 +173,10 @@ enum LocalTimerRegCntIndexes { L_REG_CNT_AMOUNT }; -#define MCT_NIRQ 6 #define MCT_SFR_SIZE 0x444 #define MCT_GT_CMP_NUM 4 -#define MCT_GT_MAX_VAL UINT64_MAX - #define MCT_GT_COUNTER_STEP 0x100000000ULL #define MCT_LT_COUNTER_STEP 0x100000000ULL #define MCT_LT_CNT_LOW_LIMIT 0x100 @@ -937,7 +934,7 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s) { uint32_t freq = s->freq; s->freq = 24000000 / - ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) * + ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg) + 1) * MCT_CFG_GET_DIVIDER(s->reg_mct_cfg)); if (freq != s->freq) { @@ -1016,9 +1013,9 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift); + index = GET_G_COMP_IDX(offset); + shift = 8 * (offset & 0x4); + value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift); break; case G_TCON: @@ -1067,7 +1064,6 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, lt_i = GET_L_TIMER_IDX(offset); value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]); - break; case L0_TCON: case L1_TCON: @@ -1153,23 +1149,23 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - s->g_timer.reg.comp[index] = - (s->g_timer.reg.comp[index] & - (((uint64_t)UINT32_MAX << 32) >> shift)) + - (value << shift); + index = GET_G_COMP_IDX(offset); + shift = 8 * (offset & 0x4); + s->g_timer.reg.comp[index] = + (s->g_timer.reg.comp[index] & + (((uint64_t)UINT32_MAX << 32) >> shift)) + + (value << shift); - DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift); + DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift); - if (offset&0x4) { - s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index); - } else { - s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); - } + if (offset & 0x4) { + s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index); + } else { + s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); + } - exynos4210_gfrc_restart(s); - break; + exynos4210_gfrc_restart(s); + break; case G_TCON: old_val = s->g_timer.reg.tcon; @@ -1207,7 +1203,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, break; case G_INT_ENB: - /* Raise IRQ if transition from disabled to enabled and CSTAT pending */ for (i = 0; i < MCT_GT_CMP_NUM; i++) { if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon & @@ -1288,7 +1283,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, break; case L0_TCNTB: case L1_TCNTB: - lt_i = GET_L_TIMER_IDX(offset); index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); @@ -1316,7 +1310,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, break; case L0_ICNTB: case L1_ICNTB: - lt_i = GET_L_TIMER_IDX(offset); index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); @@ -1353,13 +1346,12 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, if (icntb_max[lt_i] < value) { icntb_max[lt_i] = value; } -DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n", - lt_i, value, icntb_max[lt_i], icntb_min[lt_i]); + DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n", + lt_i, value, icntb_max[lt_i], icntb_min[lt_i]); #endif -break; + break; case L0_FRCNTB: case L1_FRCNTB: - lt_i = GET_L_TIMER_IDX(offset); index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c index 0bed5770c9..d3fa705a82 100644 --- a/hw/xen/xen-common.c +++ b/hw/xen/xen-common.c @@ -13,7 +13,8 @@ #include "qmp-commands.h" #include "chardev/char.h" #include "sysemu/accel.h" -#include "migration/migration.h" +#include "migration/misc.h" +#include "migration/global_state.h" //#define DEBUG_XEN diff --git a/include/chardev/char-parallel.h b/include/chardev/char-parallel.h index 3284a1b96b..c09751fd6c 100644 --- a/include/chardev/char-parallel.h +++ b/include/chardev/char-parallel.h @@ -26,11 +26,6 @@ #include "chardev/char.h" -#if defined(__linux__) || defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#define HAVE_CHARDEV_PARPORT 1 -#endif - #define CHR_IOCTL_PP_READ_DATA 3 #define CHR_IOCTL_PP_WRITE_DATA 4 #define CHR_IOCTL_PP_READ_CONTROL 5 diff --git a/include/chardev/char-serial.h b/include/chardev/char-serial.h index cb2e59e82a..ad6891b26d 100644 --- a/include/chardev/char-serial.h +++ b/include/chardev/char-serial.h @@ -26,14 +26,6 @@ #include "chardev/char.h" -#ifdef _WIN32 -#define HAVE_CHARDEV_SERIAL 1 -#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ - || defined(__GLIBC__) -#define HAVE_CHARDEV_SERIAL 1 -#endif - #define CHR_IOCTL_SERIAL_SET_PARAMS 1 typedef struct { int speed; diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h index d9e08014d6..098a69ec73 100644 --- a/include/hw/arm/exynos4210.h +++ b/include/hw/arm/exynos4210.h @@ -93,8 +93,6 @@ typedef struct Exynos4210State { MemoryRegion iram_mem; MemoryRegion irom_mem; MemoryRegion irom_alias_mem; - MemoryRegion dram0_mem; - MemoryRegion dram1_mem; MemoryRegion boot_secondary; MemoryRegion bootreg_mem; I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER]; @@ -103,8 +101,7 @@ typedef struct Exynos4210State { void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info); -Exynos4210State *exynos4210_init(MemoryRegion *system_mem, - unsigned long ram_size); +Exynos4210State *exynos4210_init(MemoryRegion *system_mem); /* Initialize exynos4210 IRQ subsystem stub */ qemu_irq *exynos4210_init_irq(Exynos4210Irq *env); diff --git a/include/hw/compat.h b/include/hw/compat.h index 400c64b318..26cd5851a5 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -14,6 +14,10 @@ .driver = "virtio-net-device",\ .property = "x-mtu-bypass-backend",\ .value = "off",\ + },{\ + .driver = "pcie-root-port",\ + .property = "x-migrate-msix",\ + .value = "false",\ }, #define HW_COMPAT_2_8 \ diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h index 1ba18944cf..fd1fe64c03 100644 --- a/include/hw/intc/arm_gicv3_its_common.h +++ b/include/hw/intc/arm_gicv3_its_common.h @@ -28,6 +28,13 @@ #define ITS_TRANS_SIZE 0x10000 #define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE) +#define GITS_CTLR 0x0 +#define GITS_IIDR 0x4 +#define GITS_CBASER 0x80 +#define GITS_CWRITER 0x88 +#define GITS_CREADR 0x90 +#define GITS_BASER 0x100 + struct GICv3ITSState { SysBusDevice parent_obj; @@ -43,6 +50,7 @@ struct GICv3ITSState { /* Registers */ uint32_t ctlr; + uint32_t iidr; uint64_t cbaser; uint64_t cwriter; uint64_t creadr; diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h index c88e1beed4..bc9f98851e 100644 --- a/include/hw/ppc/spapr_drc.h +++ b/include/hw/ppc/spapr_drc.h @@ -125,7 +125,7 @@ typedef enum { } sPAPRDRAllocationState; /* - * LED/visual indicator state + * DR-indicator (LED/visual indicator) * * set via set-indicator RTAS calls * as documented by PAPR+ 2.7 13.5.3.4, Table 177, @@ -137,10 +137,10 @@ typedef enum { * action: (currently unused) */ typedef enum { - SPAPR_DR_INDICATOR_STATE_INACTIVE = 0, - SPAPR_DR_INDICATOR_STATE_ACTIVE = 1, - SPAPR_DR_INDICATOR_STATE_IDENTIFY = 2, - SPAPR_DR_INDICATOR_STATE_ACTION = 3, + SPAPR_DR_INDICATOR_INACTIVE = 0, + SPAPR_DR_INDICATOR_ACTIVE = 1, + SPAPR_DR_INDICATOR_IDENTIFY = 2, + SPAPR_DR_INDICATOR_ACTION = 3, } sPAPRDRIndicatorState; /* @@ -184,12 +184,13 @@ typedef struct sPAPRDRConnector { uint32_t id; Object *owner; - const char *name; + + /* DR-indicator */ + uint32_t dr_indicator; /* sensor/indicator states */ uint32_t isolation_state; uint32_t allocation_state; - uint32_t indicator_state; /* configure-connector state */ void *fdt; @@ -200,7 +201,6 @@ typedef struct sPAPRDRConnector { bool awaiting_release; bool signalled; bool awaiting_allocation; - bool awaiting_allocation_skippable; /* device pointer, via link property */ DeviceState *dev; @@ -213,22 +213,17 @@ typedef struct sPAPRDRConnectorClass { /*< public >*/ sPAPRDRConnectorTypeShift typeshift; const char *typename; /* used in device tree, PAPR 13.5.2.6 & C.6.1 */ + const char *drc_name_prefix; /* used other places in device tree */ + + sPAPRDREntitySense (*dr_entity_sense)(sPAPRDRConnector *drc); /* accessors for guest-visible (generally via RTAS) DR state */ uint32_t (*set_isolation_state)(sPAPRDRConnector *drc, sPAPRDRIsolationState state); - uint32_t (*set_indicator_state)(sPAPRDRConnector *drc, - sPAPRDRIndicatorState state); uint32_t (*set_allocation_state)(sPAPRDRConnector *drc, sPAPRDRAllocationState state); - const char *(*get_name)(sPAPRDRConnector *drc); - - uint32_t (*entity_sense)(sPAPRDRConnector *drc, sPAPRDREntitySense *state); /* QEMU interfaces for managing hotplug operations */ - void (*attach)(sPAPRDRConnector *drc, DeviceState *d, void *fdt, - int fdt_start_offset, bool coldplug, Error **errp); - void (*detach)(sPAPRDRConnector *drc, DeviceState *d, Error **errp); bool (*release_pending)(sPAPRDRConnector *drc); void (*set_signalled)(sPAPRDRConnector *drc); } sPAPRDRConnectorClass; @@ -243,4 +238,8 @@ sPAPRDRConnector *spapr_drc_by_id(const char *type, uint32_t id); int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, uint32_t drc_type_mask); +void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, + int fdt_start_offset, bool coldplug, Error **errp); +void spapr_drc_detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp); + #endif /* HW_SPAPR_DRC_H */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index a3073f9053..28d248abad 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -65,10 +65,10 @@ typedef struct XICSFabric XICSFabric; struct ICPStateClass { DeviceClass parent_class; - void (*realize)(DeviceState *dev, Error **errp); - void (*pre_save)(ICPState *s); - int (*post_load)(ICPState *s, int version_id); - void (*cpu_setup)(ICPState *icp, PowerPCCPU *cpu); + void (*realize)(ICPState *icp, Error **errp); + void (*pre_save)(ICPState *icp); + int (*post_load)(ICPState *icp, int version_id); + void (*reset)(ICPState *icp); }; struct ICPState { @@ -85,6 +85,9 @@ struct ICPState { XICSFabric *xics; }; +#define ICP_PROP_XICS "xics" +#define ICP_PROP_CPU "cpu" + struct PnvICPState { ICPState parent_obj; @@ -110,7 +113,7 @@ struct PnvICPState { struct ICSStateClass { DeviceClass parent_class; - void (*realize)(DeviceState *dev, Error **errp); + void (*realize)(ICSState *s, Error **errp); void (*pre_save)(ICSState *s); int (*post_load)(ICSState *s, int version_id); void (*reject)(ICSState *s, uint32_t irq); @@ -129,6 +132,8 @@ struct ICSState { XICSFabric *xics; }; +#define ICS_PROP_XICS "xics" + static inline bool ics_valid_irq(ICSState *ics, uint32_t nr) { return (ics->offset != 0) && (nr >= ics->offset) @@ -182,8 +187,6 @@ void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle); qemu_irq xics_get_qirq(XICSFabric *xi, int irq); ICPState *xics_icp_get(XICSFabric *xi, int server); -void xics_cpu_setup(XICSFabric *xi, PowerPCCPU *cpu, ICPState *icp); -void xics_cpu_destroy(XICSFabric *xi, PowerPCCPU *cpu); /* Internal XICS interfaces */ void icp_set_cppr(ICPState *icp, uint8_t cppr); diff --git a/include/hw/s390x/ioinst.h b/include/hw/s390x/ioinst.h index c559f53426..92d15655e4 100644 --- a/include/hw/s390x/ioinst.h +++ b/include/hw/s390x/ioinst.h @@ -182,6 +182,7 @@ typedef struct CCW1 { #define CCW_FLAG_PCI 0x08 #define CCW_FLAG_IDA 0x04 #define CCW_FLAG_SUSPEND 0x02 +#define CCW_FLAG_MIDA 0x01 #define CCW_CMD_NOOP 0x03 #define CCW_CMD_BASIC_SENSE 0x04 diff --git a/include/migration/colo.h b/include/migration/colo.h index ba0bb6e6d5..be6beba301 100644 --- a/include/migration/colo.h +++ b/include/migration/colo.h @@ -14,9 +14,6 @@ #define QEMU_COLO_H #include "qemu-common.h" -#include "qemu/coroutine_int.h" -#include "qemu/thread.h" -#include "qemu/main-loop.h" bool colo_supported(void); void colo_info_init(void); diff --git a/include/migration/global_state.h b/include/migration/global_state.h new file mode 100644 index 0000000000..90faea72b4 --- /dev/null +++ b/include/migration/global_state.h @@ -0,0 +1,25 @@ +/* + * Global State configuration + * + * Copyright (c) 2014-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. + */ + +#ifndef QEMU_MIGRATION_GLOBAL_STATE_H +#define QEMU_MIGRATION_GLOBAL_STATE_H + +#include "sysemu/sysemu.h" + +void register_global_state(void); +void global_state_set_optional(void); +int global_state_store(void); +void global_state_store_running(void); +bool global_state_received(void); +RunState global_state_get_runstate(void); + +#endif diff --git a/include/migration/misc.h b/include/migration/misc.h index d7892b7956..65c7070262 100644 --- a/include/migration/misc.h +++ b/include/migration/misc.h @@ -14,6 +14,8 @@ #ifndef MIGRATION_MISC_H #define MIGRATION_MISC_H +#include "qemu/notify.h" + /* migration/ram.c */ void ram_mig_init(void); @@ -26,4 +28,30 @@ void blk_mig_init(void); static inline void blk_mig_init(void) {} #endif +#define SELF_ANNOUNCE_ROUNDS 5 + +static inline +int64_t self_announce_delay(int round) +{ + assert(round < SELF_ANNOUNCE_ROUNDS && round > 0); + /* delay 50ms, 150ms, 250ms, ... */ + return 50 + (SELF_ANNOUNCE_ROUNDS - round - 1) * 100; +} + +/* migration/savevm.c */ + +void dump_vmstate_json_to_file(FILE *out_fp); +void savevm_skip_section_footers(void); +void savevm_skip_configuration(void); + +/* migration/migration.c */ +void qemu_start_incoming_migration(const char *uri, Error **errp); +bool migration_is_idle(void); +void add_migration_state_change_notifier(Notifier *notify); +void remove_migration_state_change_notifier(Notifier *notify); +bool migration_in_setup(MigrationState *); +bool migration_has_finished(MigrationState *); +bool migration_has_failed(MigrationState *); +/* ...and after the device transmission */ +bool migration_in_postcopy_after_devices(MigrationState *); #endif diff --git a/include/migration/register.h b/include/migration/register.h new file mode 100644 index 0000000000..d9498d95eb --- /dev/null +++ b/include/migration/register.h @@ -0,0 +1,53 @@ +/* + * QEMU migration vmstate registration + * + * 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 MIGRATION_REGISTER_H +#define MIGRATION_REGISTER_H + +typedef struct SaveVMHandlers { + /* This runs inside the iothread lock. */ + SaveStateHandler *save_state; + + void (*cleanup)(void *opaque); + int (*save_live_complete_postcopy)(QEMUFile *f, void *opaque); + int (*save_live_complete_precopy)(QEMUFile *f, void *opaque); + + /* This runs both outside and inside the iothread lock. */ + bool (*is_active)(void *opaque); + + /* This runs outside the iothread lock in the migration case, and + * within the lock in the savevm case. The callback had better only + * use data that is local to the migration thread or protected + * by other locks. + */ + int (*save_live_iterate)(QEMUFile *f, void *opaque); + + /* This runs outside the iothread lock! */ + int (*save_live_setup)(QEMUFile *f, void *opaque); + void (*save_live_pending)(QEMUFile *f, void *opaque, + uint64_t threshold_size, + uint64_t *non_postcopiable_pending, + uint64_t *postcopiable_pending); + LoadStateHandler *load_state; +} SaveVMHandlers; + +int register_savevm_live(DeviceState *dev, + const char *idstr, + int instance_id, + int version_id, + SaveVMHandlers *ops, + void *opaque); + +void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque); + +#endif diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 8a3e9e6088..e85fbd81fc 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -29,45 +29,6 @@ #include "migration/qjson.h" -typedef void SaveStateHandler(QEMUFile *f, void *opaque); -typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); - -typedef struct SaveVMHandlers { - /* This runs inside the iothread lock. */ - SaveStateHandler *save_state; - - void (*cleanup)(void *opaque); - int (*save_live_complete_postcopy)(QEMUFile *f, void *opaque); - int (*save_live_complete_precopy)(QEMUFile *f, void *opaque); - - /* This runs both outside and inside the iothread lock. */ - bool (*is_active)(void *opaque); - - /* This runs outside the iothread lock in the migration case, and - * within the lock in the savevm case. The callback had better only - * use data that is local to the migration thread or protected - * by other locks. - */ - int (*save_live_iterate)(QEMUFile *f, void *opaque); - - /* This runs outside the iothread lock! */ - int (*save_live_setup)(QEMUFile *f, void *opaque); - void (*save_live_pending)(QEMUFile *f, void *opaque, - uint64_t threshold_size, - uint64_t *non_postcopiable_pending, - uint64_t *postcopiable_pending); - LoadStateHandler *load_state; -} SaveVMHandlers; - -int register_savevm_live(DeviceState *dev, - const char *idstr, - int instance_id, - int version_id, - SaveVMHandlers *ops, - void *opaque); - -void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque); - typedef struct VMStateInfo VMStateInfo; typedef struct VMStateDescription VMStateDescription; typedef struct VMStateField VMStateField; @@ -187,6 +148,8 @@ enum VMStateFlags { typedef enum { MIG_PRI_DEFAULT = 0, MIG_PRI_IOMMU, /* Must happen before PCI devices */ + MIG_PRI_GICV3_ITS, /* Must happen before PCI devices */ + MIG_PRI_GICV3, /* Must happen before the ITS */ MIG_PRI_MAX, } MigrationPriority; @@ -1010,8 +973,6 @@ extern const VMStateInfo vmstate_info_qtailq; #define VMSTATE_END_OF_LIST() \ {} -#define SELF_ANNOUNCE_ROUNDS 5 - int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id); void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, @@ -1043,16 +1004,6 @@ void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev); void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev); void vmstate_register_ram_global(struct MemoryRegion *memory); -static inline -int64_t self_announce_delay(int round) -{ - assert(round < SELF_ANNOUNCE_ROUNDS && round > 0); - /* delay 50ms, 150ms, 250ms, ... */ - return 50 + (SELF_ANNOUNCE_ROUNDS - round - 1) * 100; -} - -void dump_vmstate_json_to_file(FILE *out_fp); - bool vmstate_check_only_migratable(const VMStateDescription *vmsd); #endif diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 1c9f5e260c..fb008a2e65 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -284,6 +284,19 @@ void qemu_anon_ram_free(void *ptr, size_t size); #endif +#ifdef _WIN32 +#define HAVE_CHARDEV_SERIAL 1 +#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ + || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ + || defined(__GLIBC__) +#define HAVE_CHARDEV_SERIAL 1 +#endif + +#if defined(__linux__) || defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#define HAVE_CHARDEV_PARPORT 1 +#endif + #if defined(CONFIG_LINUX) #ifndef BUS_MCEERR_AR #define BUS_MCEERR_AR 4 diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 8a1eb74839..1b518bca30 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -1020,10 +1020,9 @@ static inline int64_t cpu_get_host_ticks(void) /* The host CPU doesn't have an easily accessible cycle counter. Just return a monotonically increasing value. This will be totally wrong, but hopefully better than nothing. */ -static inline int64_t cpu_get_host_ticks (void) +static inline int64_t cpu_get_host_ticks(void) { - static int64_t ticks = 0; - return ticks++; + return get_clock(); } #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 51958bf7d3..f745d5faf7 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -96,5 +96,7 @@ typedef struct uWireSlave uWireSlave; typedef struct VirtIODevice VirtIODevice; typedef struct Visitor Visitor; typedef struct node_info NodeInfo; +typedef void SaveStateHandler(QEMUFile *f, void *opaque); +typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); #endif /* QEMU_TYPEDEFS_H */ diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index a45c145560..1e91613ca9 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -294,12 +294,15 @@ int kvm_device_check_attr(int fd, uint32_t group, uint64_t attr); * @attr: the attribute of that group to set or get * @val: pointer to a storage area for the value * @write: true for set and false for get operation + * @errp: error object handle * - * This function is not allowed to fail. Use kvm_device_check_attr() - * in order to check for the availability of optional attributes. + * Returns: 0 on success + * < 0 on error + * Use kvm_device_check_attr() in order to check for the availability + * of optional attributes. */ -void kvm_device_access(int fd, int group, uint64_t attr, - void *val, bool write); +int kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write, Error **errp); /** * kvm_create_device - create a KVM device for the device control API diff --git a/kvm-all.c b/kvm-all.c index 44b3cf43cc..ab8262f672 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -23,6 +23,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" @@ -2216,8 +2217,8 @@ int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute) ? 0 : 1; } -void kvm_device_access(int fd, int group, uint64_t attr, - void *val, bool write) +int kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write, Error **errp) { struct kvm_device_attr kvmattr; int err; @@ -2231,11 +2232,12 @@ void kvm_device_access(int fd, int group, uint64_t attr, write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR, &kvmattr); if (err < 0) { - error_report("KVM_%s_DEVICE_ATTR failed: %s", - write ? "SET" : "GET", strerror(-err)); - error_printf("Group %d attr 0x%016" PRIx64 "\n", group, attr); - abort(); + error_setg_errno(errp, -err, + "KVM_%s_DEVICE_ATTR failed: Group %d " + "attr 0x%016" PRIx64, + write ? "SET" : "GET", group, attr); } + return err; } /* Return 1 on success, 0 on failure */ diff --git a/migration/Makefile.objs b/migration/Makefile.objs index 90f8c1f177..1c7770da46 100644 --- a/migration/Makefile.objs +++ b/migration/Makefile.objs @@ -2,7 +2,7 @@ common-obj-y += migration.o socket.o fd.o exec.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 vmstate-types.o page_cache.o -common-obj-y += qemu-file.o +common-obj-y += qemu-file.o global_state.o common-obj-y += qemu-file-channel.o common-obj-y += xbzrle.o postcopy-ram.o common-obj-y += qjson.o diff --git a/migration/block.c b/migration/block.c index 114cedbfd0..3aae5a375e 100644 --- a/migration/block.c +++ b/migration/block.c @@ -15,18 +15,13 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" -#include "block/block.h" #include "qemu/error-report.h" -#include "qemu/main-loop.h" -#include "hw/hw.h" #include "qemu/cutils.h" #include "qemu/queue.h" -#include "qemu/timer.h" #include "block.h" #include "migration/misc.h" -#include "migration/migration.h" -#include "sysemu/blockdev.h" +#include "migration.h" +#include "migration/register.h" #include "qemu-file.h" #include "migration/vmstate.h" #include "sysemu/block-backend.h" diff --git a/migration/channel.c b/migration/channel.c index eae1d9e28a..3b7252f5a2 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -13,15 +13,16 @@ #include "qemu/osdep.h" #include "channel.h" #include "tls.h" -#include "migration/migration.h" +#include "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) +void migration_channel_process_incoming(QIOChannel *ioc) { + MigrationState *s = migrate_get_current(); + trace_migration_set_incoming_channel( ioc, object_get_typename(OBJECT(ioc))); diff --git a/migration/channel.h b/migration/channel.h index 2e0a7e33cc..e4b40579a1 100644 --- a/migration/channel.h +++ b/migration/channel.h @@ -18,8 +18,7 @@ #include "io/channel.h" -void migration_channel_process_incoming(MigrationState *s, - QIOChannel *ioc); +void migration_channel_process_incoming(QIOChannel *ioc); void migration_channel_connect(MigrationState *s, QIOChannel *ioc, diff --git a/migration/colo-comm.c b/migration/colo-comm.c index 8bfdf6825a..b61aa19a38 100644 --- a/migration/colo-comm.c +++ b/migration/colo-comm.c @@ -12,7 +12,7 @@ */ #include "qemu/osdep.h" -#include "migration/migration.h" +#include "migration.h" #include "migration/colo.h" #include "migration/vmstate.h" #include "trace.h" diff --git a/migration/colo-failover.c b/migration/colo-failover.c index cc229f5ab1..f9914869c5 100644 --- a/migration/colo-failover.c +++ b/migration/colo-failover.c @@ -13,6 +13,8 @@ #include "qemu/osdep.h" #include "migration/colo.h" #include "migration/failover.h" +#include "qemu/main-loop.h" +#include "migration.h" #include "qmp-commands.h" #include "qapi/qmp/qerror.h" #include "qemu/error-report.h" diff --git a/migration/colo.c b/migration/colo.c index 111b715546..c4ba4c328b 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -11,10 +11,9 @@ */ #include "qemu/osdep.h" -#include "qemu/timer.h" #include "sysemu/sysemu.h" #include "qemu-file-channel.h" -#include "migration/migration.h" +#include "migration.h" #include "qemu-file.h" #include "savevm.h" #include "migration/colo.h" @@ -22,7 +21,6 @@ #include "io/channel-buffer.h" #include "trace.h" #include "qemu/error-report.h" -#include "qapi/error.h" #include "migration/failover.h" #include "replication.h" #include "qmp-commands.h" @@ -354,7 +352,7 @@ static int colo_do_checkpoint_transaction(MigrationState *s, qemu_savevm_state_header(fb); qemu_savevm_state_begin(fb); qemu_mutex_lock_iothread(); - qemu_savevm_state_complete_precopy(fb, false); + qemu_savevm_state_complete_precopy(fb, false, false); qemu_mutex_unlock_iothread(); qemu_fflush(fb); diff --git a/migration/exec.c b/migration/exec.c index 9077024286..08b599e0e2 100644 --- a/migration/exec.c +++ b/migration/exec.c @@ -19,10 +19,8 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "channel.h" #include "exec.h" -#include "migration/migration.h" #include "io/channel-command.h" #include "trace.h" @@ -49,7 +47,7 @@ static gboolean exec_accept_incoming_migration(QIOChannel *ioc, GIOCondition condition, gpointer opaque) { - migration_channel_process_incoming(migrate_get_current(), ioc); + migration_channel_process_incoming(ioc); object_unref(OBJECT(ioc)); return FALSE; /* unregister */ } diff --git a/migration/fd.c b/migration/fd.c index 0077a505a3..30f5258a6a 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -16,10 +16,8 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "channel.h" #include "fd.h" -#include "migration/migration.h" #include "monitor/monitor.h" #include "io/channel-util.h" #include "trace.h" @@ -49,7 +47,7 @@ static gboolean fd_accept_incoming_migration(QIOChannel *ioc, GIOCondition condition, gpointer opaque) { - migration_channel_process_incoming(migrate_get_current(), ioc); + migration_channel_process_incoming(ioc); object_unref(OBJECT(ioc)); return FALSE; /* unregister */ } diff --git a/migration/global_state.c b/migration/global_state.c new file mode 100644 index 0000000000..f792cf5242 --- /dev/null +++ b/migration/global_state.c @@ -0,0 +1,139 @@ +/* + * Global State configuration + * + * Copyright (c) 2014-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/cutils.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/util.h" +#include "migration/global_state.h" +#include "migration/vmstate.h" +#include "trace.h" + +typedef struct { + bool optional; + uint32_t size; + uint8_t runstate[100]; + RunState state; + bool received; +} GlobalState; + +static GlobalState global_state; + +int global_state_store(void) +{ + if (!runstate_store((char *)global_state.runstate, + sizeof(global_state.runstate))) { + error_report("runstate name too big: %s", global_state.runstate); + trace_migrate_state_too_big(); + return -EINVAL; + } + return 0; +} + +void global_state_store_running(void) +{ + const char *state = RunState_lookup[RUN_STATE_RUNNING]; + strncpy((char *)global_state.runstate, + state, sizeof(global_state.runstate)); +} + +bool global_state_received(void) +{ + return global_state.received; +} + +RunState global_state_get_runstate(void) +{ + return global_state.state; +} + +void global_state_set_optional(void) +{ + global_state.optional = true; +} + +static bool global_state_needed(void *opaque) +{ + GlobalState *s = opaque; + char *runstate = (char *)s->runstate; + + /* If it is not optional, it is mandatory */ + + if (s->optional == false) { + return true; + } + + /* If state is running or paused, it is not needed */ + + if (strcmp(runstate, "running") == 0 || + strcmp(runstate, "paused") == 0) { + return false; + } + + /* for any other state it is needed */ + return true; +} + +static int global_state_post_load(void *opaque, int version_id) +{ + GlobalState *s = opaque; + Error *local_err = NULL; + int r; + char *runstate = (char *)s->runstate; + + s->received = true; + trace_migrate_global_state_post_load(runstate); + + r = qapi_enum_parse(RunState_lookup, runstate, RUN_STATE__MAX, + -1, &local_err); + + if (r == -1) { + if (local_err) { + error_report_err(local_err); + } + return -EINVAL; + } + s->state = r; + + return 0; +} + +static void global_state_pre_save(void *opaque) +{ + GlobalState *s = opaque; + + trace_migrate_global_state_pre_save((char *)s->runstate); + s->size = strlen((char *)s->runstate) + 1; +} + +static const VMStateDescription vmstate_globalstate = { + .name = "globalstate", + .version_id = 1, + .minimum_version_id = 1, + .post_load = global_state_post_load, + .pre_save = global_state_pre_save, + .needed = global_state_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(size, GlobalState), + VMSTATE_BUFFER(runstate, GlobalState), + VMSTATE_END_OF_LIST() + }, +}; + +void register_global_state(void) +{ + /* We would use it independently that we receive it */ + strcpy((char *)&global_state.runstate, ""); + global_state.received = false; + vmstate_register(NULL, 0, &vmstate_globalstate, &global_state); +} diff --git a/migration/migration.c b/migration/migration.c index fc95acbde6..f588329f4c 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -16,23 +16,22 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" #include "qemu/error-report.h" -#include "qemu/main-loop.h" #include "migration/blocker.h" #include "exec.h" #include "fd.h" #include "socket.h" #include "rdma.h" #include "ram.h" -#include "migration/migration.h" +#include "migration/global_state.h" +#include "migration/misc.h" +#include "migration.h" #include "savevm.h" #include "qemu-file-channel.h" #include "qemu-file.h" #include "migration/vmstate.h" -#include "sysemu/sysemu.h" #include "block/block.h" #include "qapi/qmp/qerror.h" #include "qapi/util.h" -#include "qemu/sockets.h" #include "qemu/rcu.h" #include "block.h" #include "postcopy-ram.h" @@ -40,9 +39,6 @@ #include "qmp-commands.h" #include "trace.h" #include "qapi-event.h" -#include "qom/cpu.h" -#include "exec/memory.h" -#include "exec/address-spaces.h" #include "exec/target_page.h" #include "io/channel-buffer.h" #include "migration/colo.h" @@ -86,6 +82,18 @@ static NotifierList migration_state_notifiers = static bool deferred_incoming; +/* Messages sent on the return path from destination to source */ +enum mig_rp_message_type { + MIG_RP_MSG_INVALID = 0, /* Must be 0 */ + MIG_RP_MSG_SHUT, /* sibling will not send any more RP messages */ + MIG_RP_MSG_PONG, /* Response to a PING; data (seq: be32 ) */ + + MIG_RP_MSG_REQ_PAGES_ID, /* data (start: be64, len: be32, id: string) */ + MIG_RP_MSG_REQ_PAGES, /* data (start: be64, len: be32) */ + + MIG_RP_MSG_MAX +}; + /* When we add fault tolerance, we could have several migrations at once. For now we don't need to add dynamic creation of migration */ @@ -152,126 +160,6 @@ void migration_incoming_state_destroy(void) qemu_event_destroy(&mis->main_thread_load_event); } - -typedef struct { - bool optional; - uint32_t size; - uint8_t runstate[100]; - RunState state; - bool received; -} GlobalState; - -static GlobalState global_state; - -int global_state_store(void) -{ - if (!runstate_store((char *)global_state.runstate, - sizeof(global_state.runstate))) { - error_report("runstate name too big: %s", global_state.runstate); - trace_migrate_state_too_big(); - return -EINVAL; - } - return 0; -} - -void global_state_store_running(void) -{ - const char *state = RunState_lookup[RUN_STATE_RUNNING]; - strncpy((char *)global_state.runstate, - state, sizeof(global_state.runstate)); -} - -static bool global_state_received(void) -{ - return global_state.received; -} - -static RunState global_state_get_runstate(void) -{ - return global_state.state; -} - -void global_state_set_optional(void) -{ - global_state.optional = true; -} - -static bool global_state_needed(void *opaque) -{ - GlobalState *s = opaque; - char *runstate = (char *)s->runstate; - - /* If it is not optional, it is mandatory */ - - if (s->optional == false) { - return true; - } - - /* If state is running or paused, it is not needed */ - - if (strcmp(runstate, "running") == 0 || - strcmp(runstate, "paused") == 0) { - return false; - } - - /* for any other state it is needed */ - return true; -} - -static int global_state_post_load(void *opaque, int version_id) -{ - GlobalState *s = opaque; - Error *local_err = NULL; - int r; - char *runstate = (char *)s->runstate; - - s->received = true; - trace_migrate_global_state_post_load(runstate); - - r = qapi_enum_parse(RunState_lookup, runstate, RUN_STATE__MAX, - -1, &local_err); - - if (r == -1) { - if (local_err) { - error_report_err(local_err); - } - return -EINVAL; - } - s->state = r; - - return 0; -} - -static void global_state_pre_save(void *opaque) -{ - GlobalState *s = opaque; - - trace_migrate_global_state_pre_save((char *)s->runstate); - s->size = strlen((char *)s->runstate) + 1; -} - -static const VMStateDescription vmstate_globalstate = { - .name = "globalstate", - .version_id = 1, - .minimum_version_id = 1, - .post_load = global_state_post_load, - .pre_save = global_state_pre_save, - .needed = global_state_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT32(size, GlobalState), - VMSTATE_BUFFER(runstate, GlobalState), - VMSTATE_END_OF_LIST() - }, -}; - -void register_global_state(void) -{ - /* We would use it independently that we receive it */ - strcpy((char *)&global_state.runstate, ""); - global_state.received = false; - vmstate_register(NULL, 0, &vmstate_globalstate, &global_state); -} - static void migrate_generate_event(int new_state) { if (migrate_use_events()) { @@ -292,6 +180,23 @@ static void deferred_incoming_migration(Error **errp) deferred_incoming = true; } +/* + * Send a message on the return channel back to the source + * of the migration. + */ +static void migrate_send_rp_message(MigrationIncomingState *mis, + enum mig_rp_message_type message_type, + uint16_t len, void *data) +{ + trace_migrate_send_rp_message((int)message_type, len); + qemu_mutex_lock(&mis->rp_mutex); + qemu_put_be16(mis->to_src_file, (unsigned int)message_type); + qemu_put_be16(mis->to_src_file, len); + qemu_put_buffer(mis->to_src_file, data, len); + qemu_fflush(mis->to_src_file); + qemu_mutex_unlock(&mis->rp_mutex); +} + /* Request a range of pages from the source VM at the given * start address. * rbname: Name of the RAMBlock to request the page in, if NULL it's the same @@ -462,23 +367,6 @@ void migration_fd_process_incoming(QEMUFile *f) } /* - * Send a message on the return channel back to the source - * of the migration. - */ -void migrate_send_rp_message(MigrationIncomingState *mis, - enum mig_rp_message_type message_type, - uint16_t len, void *data) -{ - trace_migrate_send_rp_message((int)message_type, len); - qemu_mutex_lock(&mis->rp_mutex); - qemu_put_be16(mis->to_src_file, (unsigned int)message_type); - qemu_put_be16(mis->to_src_file, len); - qemu_put_buffer(mis->to_src_file, data, len); - qemu_fflush(mis->to_src_file); - qemu_mutex_unlock(&mis->rp_mutex); -} - -/* * Send a 'SHUT' message on the return channel with the given value * to indicate that we've finished with the RP. Non-0 value indicates * error. @@ -627,6 +515,17 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) } } +static void populate_disk_info(MigrationInfo *info) +{ + if (blk_mig_active()) { + info->has_disk = true; + info->disk = g_malloc0(sizeof(*info->disk)); + info->disk->transferred = blk_mig_bytes_transferred(); + info->disk->remaining = blk_mig_bytes_remaining(); + info->disk->total = blk_mig_bytes_total(); + } +} + MigrationInfo *qmp_query_migrate(Error **errp) { MigrationInfo *info = g_malloc0(sizeof(*info)); @@ -642,28 +541,8 @@ MigrationInfo *qmp_query_migrate(Error **errp) break; case MIGRATION_STATUS_ACTIVE: case MIGRATION_STATUS_CANCELLING: - info->has_status = true; - info->has_total_time = true; - info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - - s->total_time; - info->has_expected_downtime = true; - info->expected_downtime = s->expected_downtime; - info->has_setup_time = true; - info->setup_time = s->setup_time; - - populate_ram_info(info, s); - - if (blk_mig_active()) { - info->has_disk = true; - info->disk = g_malloc0(sizeof(*info->disk)); - info->disk->transferred = blk_mig_bytes_transferred(); - info->disk->remaining = blk_mig_bytes_remaining(); - info->disk->total = blk_mig_bytes_total(); - } - - break; case MIGRATION_STATUS_POSTCOPY_ACTIVE: - /* Mostly the same as active; TODO add some postcopy stats */ + /* TODO add some postcopy stats */ info->has_status = true; info->has_total_time = true; info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) @@ -674,15 +553,7 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->setup_time = s->setup_time; populate_ram_info(info, s); - - if (blk_mig_active()) { - info->has_disk = true; - info->disk = g_malloc0(sizeof(*info->disk)); - info->disk->transferred = blk_mig_bytes_transferred(); - info->disk->remaining = blk_mig_bytes_remaining(); - info->disk->total = blk_mig_bytes_total(); - } - + populate_disk_info(info); break; case MIGRATION_STATUS_COLO: info->has_status = true; @@ -1179,7 +1050,7 @@ bool migration_is_blocked(Error **errp) } if (migration_blockers) { - *errp = error_copy(migration_blockers->data); + error_propagate(errp, error_copy(migration_blockers->data)); return true; } @@ -1682,7 +1553,7 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running) * Cause any non-postcopiable, but iterative devices to * send out their final data. */ - qemu_savevm_state_complete_precopy(ms->to_dst_file, true); + qemu_savevm_state_complete_precopy(ms->to_dst_file, true, false); /* * in Finish migrate and with the io-lock held everything should @@ -1726,7 +1597,7 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running) */ qemu_savevm_send_postcopy_listen(fb); - qemu_savevm_state_complete_precopy(fb, false); + qemu_savevm_state_complete_precopy(fb, false, false); qemu_savevm_send_ping(fb, 3); qemu_savevm_send_postcopy_run(fb); @@ -1824,20 +1695,15 @@ static void migration_completion(MigrationState *s, int current_active_state, ret = global_state_store(); if (!ret) { + bool inactivate = !migrate_colo_enabled(); ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); if (ret >= 0) { qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX); - qemu_savevm_state_complete_precopy(s->to_dst_file, false); + ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, + inactivate); } - /* - * Don't mark the image with BDRV_O_INACTIVE flag if - * we will go into COLO stage later. - */ - if (ret >= 0 && !migrate_colo_enabled()) { - ret = bdrv_inactivate_all(); - if (ret >= 0) { - s->block_inactive = true; - } + if (inactivate && ret >= 0) { + s->block_inactive = true; } } qemu_mutex_unlock_iothread(); @@ -1857,13 +1723,12 @@ static void migration_completion(MigrationState *s, int current_active_state, * cleaning everything else up (since if there are no failures * it will wait for the destination to send it's status in * a SHUT command). - * Postcopy opens rp if enabled (even if it's not avtivated) */ - if (migrate_postcopy_ram()) { + if (s->rp_state.from_dst_file) { int rp_error; - trace_migration_completion_postcopy_end_before_rp(); + trace_migration_return_path_end_before(); rp_error = await_return_path_close_on_source(s); - trace_migration_completion_postcopy_end_after_rp(rp_error); + trace_migration_return_path_end_after(rp_error); if (rp_error) { goto fail_invalidate; } @@ -1938,13 +1803,19 @@ static void *migration_thread(void *opaque) qemu_savevm_state_header(s->to_dst_file); - if (migrate_postcopy_ram()) { + /* + * If we opened the return path, we need to make sure dst has it + * opened as well. + */ + if (s->rp_state.from_dst_file) { /* Now tell the dest that it should open its end so it can reply */ qemu_savevm_send_open_return_path(s->to_dst_file); /* And do a ping that will make stuff easier to debug */ qemu_savevm_send_ping(s->to_dst_file, 1); + } + if (migrate_postcopy_ram()) { /* * Tell the destination that we *might* want to do postcopy later; * if the other end can't do postcopy it should fail now, nice and diff --git a/include/migration/migration.h b/migration/migration.h index 79b5484d65..d9a268a3af 100644 --- a/include/migration/migration.h +++ b/migration/migration.h @@ -14,41 +14,12 @@ #ifndef QEMU_MIGRATION_H #define QEMU_MIGRATION_H -#include "qapi/qmp/qdict.h" #include "qemu-common.h" #include "qemu/thread.h" -#include "qemu/notify.h" #include "qapi-types.h" #include "exec/cpu-common.h" #include "qemu/coroutine_int.h" -#define QEMU_VM_FILE_MAGIC 0x5145564d -#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 -#define QEMU_VM_FILE_VERSION 0x00000003 - -#define QEMU_VM_EOF 0x00 -#define QEMU_VM_SECTION_START 0x01 -#define QEMU_VM_SECTION_PART 0x02 -#define QEMU_VM_SECTION_END 0x03 -#define QEMU_VM_SECTION_FULL 0x04 -#define QEMU_VM_SUBSECTION 0x05 -#define QEMU_VM_VMDESCRIPTION 0x06 -#define QEMU_VM_CONFIGURATION 0x07 -#define QEMU_VM_COMMAND 0x08 -#define QEMU_VM_SECTION_FOOTER 0x7e - -/* Messages sent on the return path from destination to source */ -enum mig_rp_message_type { - MIG_RP_MSG_INVALID = 0, /* Must be 0 */ - MIG_RP_MSG_SHUT, /* sibling will not send any more RP messages */ - MIG_RP_MSG_PONG, /* Response to a PING; data (seq: be32 ) */ - - MIG_RP_MSG_REQ_PAGES_ID, /* data (start: be64, len: be32, id: string) */ - MIG_RP_MSG_REQ_PAGES, /* data (start: be64, len: be32) */ - - MIG_RP_MSG_MAX -}; - /* State for the incoming migration */ struct MigrationIncomingState { QEMUFile *from_src_file; @@ -149,26 +120,16 @@ void migrate_set_state(int *state, int old_state, int new_state); void migration_fd_process_incoming(QEMUFile *f); -void qemu_start_incoming_migration(const char *uri, Error **errp); - uint64_t migrate_max_downtime(void); void migrate_fd_error(MigrationState *s, const Error *error); 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(void); bool migration_is_blocked(Error **errp); -bool migration_in_setup(MigrationState *); -bool migration_is_idle(void); -bool migration_has_finished(MigrationState *); -bool migration_has_failed(MigrationState *); /* True if outgoing migration has entered postcopy phase */ bool migration_in_postcopy(void); -/* ...and after the device transmission */ -bool migration_in_postcopy_after_devices(MigrationState *); MigrationState *migrate_get_current(void); bool migrate_release_ram(void); @@ -191,9 +152,6 @@ int migrate_decompress_threads(void); bool migrate_use_events(void); /* Sending on the return path - generic and then for each message type */ -void migrate_send_rp_message(MigrationIncomingState *mis, - enum mig_rp_message_type message_type, - uint16_t len, void *data); void migrate_send_rp_shut(MigrationIncomingState *mis, uint32_t value); void migrate_send_rp_pong(MigrationIncomingState *mis, @@ -201,29 +159,4 @@ void migrate_send_rp_pong(MigrationIncomingState *mis, void migrate_send_rp_req_pages(MigrationIncomingState *mis, const char* rbname, ram_addr_t start, size_t len); -void ram_control_before_iterate(QEMUFile *f, uint64_t flags); -void ram_control_after_iterate(QEMUFile *f, uint64_t flags); -void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); - -/* Whenever this is found in the data stream, the flags - * will be passed to ram_control_load_hook in the incoming-migration - * side. This lets before_ram_iterate/after_ram_iterate add - * transport-specific sections to the RAM migration data. - */ -#define RAM_SAVE_FLAG_HOOK 0x80 - -#define RAM_SAVE_CONTROL_NOT_SUPP -1000 -#define RAM_SAVE_CONTROL_DELAYED -2000 - -size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, - ram_addr_t offset, size_t size, - uint64_t *bytes_sent); - -void savevm_skip_section_footers(void); -void register_global_state(void); -void global_state_set_optional(void); -void savevm_skip_configuration(void); -int global_state_store(void); -void global_state_store_running(void); - #endif diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 9c4188724e..7e21e6fd36 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -17,10 +17,8 @@ */ #include "qemu/osdep.h" - -#include "qemu-common.h" #include "exec/target_page.h" -#include "migration/migration.h" +#include "migration.h" #include "qemu-file.h" #include "savevm.h" #include "postcopy-ram.h" diff --git a/migration/qemu-file.c b/migration/qemu-file.c index ab26f4eea9..2ab2bf362d 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -26,9 +26,7 @@ #include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/iov.h" -#include "qemu/sockets.h" -#include "qemu/coroutine.h" -#include "migration/migration.h" +#include "migration.h" #include "qemu-file.h" #include "trace.h" diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 49fd6978ac..aae4e5ed36 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -156,5 +156,22 @@ void qemu_file_set_blocking(QEMUFile *f, bool block); size_t qemu_get_counted_string(QEMUFile *f, char buf[256]); +void ram_control_before_iterate(QEMUFile *f, uint64_t flags); +void ram_control_after_iterate(QEMUFile *f, uint64_t flags); +void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); + +/* Whenever this is found in the data stream, the flags + * will be passed to ram_control_load_hook in the incoming-migration + * side. This lets before_ram_iterate/after_ram_iterate add + * transport-specific sections to the RAM migration data. + */ +#define RAM_SAVE_FLAG_HOOK 0x80 + +#define RAM_SAVE_CONTROL_NOT_SUPP -1000 +#define RAM_SAVE_CONTROL_DELAYED -2000 + +size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size, + uint64_t *bytes_sent); #endif diff --git a/migration/ram.c b/migration/ram.c index 9ffd0a5479..0baa1e0d56 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -26,23 +26,20 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include <zlib.h> #include "qapi-event.h" #include "qemu/cutils.h" #include "qemu/bitops.h" #include "qemu/bitmap.h" -#include "qemu/timer.h" #include "qemu/main-loop.h" #include "xbzrle.h" #include "ram.h" -#include "migration/migration.h" +#include "migration.h" +#include "migration/register.h" #include "migration/misc.h" #include "qemu-file.h" -#include "migration/vmstate.h" #include "postcopy-ram.h" -#include "exec/address-spaces.h" #include "migration/page_cache.h" #include "qemu/error-report.h" #include "trace.h" @@ -2237,6 +2234,9 @@ void migrate_decompress_threads_create(void) { int i, thread_count; + if (!migrate_use_compression()) { + return; + } thread_count = migrate_decompress_threads(); decompress_threads = g_new0(QemuThread, thread_count); decomp_param = g_new0(DecompressParam, thread_count); @@ -2258,6 +2258,9 @@ void migrate_decompress_threads_join(void) { int i, thread_count; + if (!migrate_use_compression()) { + return; + } thread_count = migrate_decompress_threads(); for (i = 0; i < thread_count; i++) { qemu_mutex_lock(&decomp_param[i].mutex); @@ -2458,7 +2461,7 @@ static int ram_load_postcopy(QEMUFile *f) static int ram_load(QEMUFile *f, void *opaque, int version_id) { - int flags = 0, ret = 0; + int flags = 0, ret = 0, invalid_flags = 0; static uint64_t seq_iter; int len = 0; /* @@ -2475,6 +2478,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) ret = -EINVAL; } + if (!migrate_use_compression()) { + invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE; + } /* This RCU critical section can be very long running. * When RCU reclaims in the code start to become numerous, * it will be necessary to reduce the granularity of this @@ -2495,6 +2501,15 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) flags = addr & ~TARGET_PAGE_MASK; addr &= TARGET_PAGE_MASK; + if (flags & invalid_flags) { + if (flags & invalid_flags & RAM_SAVE_FLAG_COMPRESS_PAGE) { + error_report("Received an unexpected compressed page"); + } + + ret = -EINVAL; + break; + } + if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE)) { RAMBlock *block = ram_block_from_stream(f, flags); diff --git a/migration/rdma.c b/migration/rdma.c index e446c6fd6a..c6bc607a03 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -18,7 +18,7 @@ #include "qemu-common.h" #include "qemu/cutils.h" #include "rdma.h" -#include "migration/migration.h" +#include "migration.h" #include "qemu-file.h" #include "ram.h" #include "qemu-file-channel.h" diff --git a/migration/savevm.c b/migration/savevm.c index 745caaebef..6bfd4893e0 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -28,14 +28,13 @@ #include "qemu/osdep.h" #include "hw/boards.h" -#include "hw/hw.h" -#include "hw/qdev.h" #include "hw/xen/xen.h" #include "net/net.h" -#include "sysemu/sysemu.h" -#include "qemu/timer.h" -#include "migration/migration.h" +#include "migration.h" #include "migration/snapshot.h" +#include "migration/misc.h" +#include "migration/register.h" +#include "migration/global_state.h" #include "ram.h" #include "qemu-file-channel.h" #include "qemu-file.h" @@ -43,13 +42,11 @@ #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" #include "qemu/iov.h" #include "block/snapshot.h" #include "qemu/cutils.h" @@ -1107,7 +1104,8 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f) qemu_fflush(f); } -void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only) +int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, + bool inactivate_disks) { QJSON *vmdesc; int vmdesc_len; @@ -1141,12 +1139,12 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only) save_section_footer(f, se); if (ret < 0) { qemu_file_set_error(f, ret); - return; + return -1; } } if (iterable_only) { - return; + return 0; } vmdesc = qjson_new(); @@ -1176,6 +1174,15 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only) json_end_object(vmdesc); } + if (inactivate_disks) { + /* Inactivate before sending QEMU_VM_EOF so that the + * bdrv_invalidate_cache_all() on the other end won't fail. */ + ret = bdrv_inactivate_all(); + if (ret) { + qemu_file_set_error(f, ret); + return ret; + } + } if (!in_postcopy) { /* Postcopy stream will still be going */ qemu_put_byte(f, QEMU_VM_EOF); @@ -1193,6 +1200,7 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only) qjson_destroy(vmdesc); qemu_fflush(f); + return 0; } /* Give an estimate of the amount left to be transferred, @@ -1266,7 +1274,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) ret = qemu_file_get_error(f); if (ret == 0) { - qemu_savevm_state_complete_precopy(f, false); + qemu_savevm_state_complete_precopy(f, false, false); ret = qemu_file_get_error(f); } qemu_savevm_state_cleanup(); diff --git a/migration/savevm.h b/migration/savevm.h index eb4487771a..5a2ed1161d 100644 --- a/migration/savevm.h +++ b/migration/savevm.h @@ -14,13 +14,29 @@ #ifndef MIGRATION_SAVEVM_H #define MIGRATION_SAVEVM_H +#define QEMU_VM_FILE_MAGIC 0x5145564d +#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 +#define QEMU_VM_FILE_VERSION 0x00000003 + +#define QEMU_VM_EOF 0x00 +#define QEMU_VM_SECTION_START 0x01 +#define QEMU_VM_SECTION_PART 0x02 +#define QEMU_VM_SECTION_END 0x03 +#define QEMU_VM_SECTION_FULL 0x04 +#define QEMU_VM_SUBSECTION 0x05 +#define QEMU_VM_VMDESCRIPTION 0x06 +#define QEMU_VM_CONFIGURATION 0x07 +#define QEMU_VM_COMMAND 0x08 +#define QEMU_VM_SECTION_FOOTER 0x7e + bool qemu_savevm_state_blocked(Error **errp); 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); void qemu_savevm_state_complete_postcopy(QEMUFile *f); -void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only); +int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, + bool inactivate_disks); void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size, uint64_t *res_non_postcopiable, uint64_t *res_postcopiable); diff --git a/migration/socket.c b/migration/socket.c index 85bfdccae1..757d3821a1 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -21,7 +21,7 @@ #include "qapi/error.h" #include "channel.h" #include "socket.h" -#include "migration/migration.h" +#include "migration.h" #include "qemu-file.h" #include "io/channel-socket.h" #include "trace.h" @@ -148,8 +148,7 @@ static gboolean socket_accept_incoming_migration(QIOChannel *ioc, trace_migration_socket_incoming_accepted(); qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-incoming"); - migration_channel_process_incoming(migrate_get_current(), - QIO_CHANNEL(sioc)); + migration_channel_process_incoming(QIO_CHANNEL(sioc)); object_unref(OBJECT(sioc)); out: diff --git a/migration/tls.c b/migration/tls.c index bae9acad6c..596e8790bd 100644 --- a/migration/tls.c +++ b/migration/tls.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "channel.h" -#include "migration/migration.h" +#include "migration.h" #include "tls.h" #include "io/channel-tls.h" #include "crypto/tlscreds.h" @@ -74,7 +74,7 @@ static void migration_tls_incoming_handshake(QIOTask *task, error_report_err(err); } else { trace_migration_tls_incoming_handshake_complete(); - migration_channel_process_incoming(migrate_get_current(), ioc); + migration_channel_process_incoming(ioc); } object_unref(OBJECT(ioc)); } diff --git a/migration/trace-events b/migration/trace-events index 5b8ccf301c..38345be9c3 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -88,8 +88,8 @@ migrate_send_rp_message(int msg_type, uint16_t len) "%d: len %d" migration_completion_file_err(void) "" migration_completion_postcopy_end(void) "" migration_completion_postcopy_end_after_complete(void) "" -migration_completion_postcopy_end_before_rp(void) "" -migration_completion_postcopy_end_after_rp(int rp_error) "%d" +migration_return_path_end_before(void) "" +migration_return_path_end_after(int rp_error) "%d" migration_thread_after_loop(void) "" migration_thread_file_err(void) "" migration_thread_setup_complete(void) "" diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c index 7287c6baa6..02f05a3359 100644 --- a/migration/vmstate-types.c +++ b/migration/vmstate-types.c @@ -14,7 +14,7 @@ #include "qemu-common.h" #include "exec/cpu-common.h" #include "qemu-file.h" -#include "migration/migration.h" +#include "migration.h" #include "migration/vmstate.h" #include "qemu/error-report.h" #include "qemu/queue.h" diff --git a/migration/vmstate.c b/migration/vmstate.c index 51a19b668a..3226e8eb45 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -12,8 +12,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "migration/migration.h" +#include "migration.h" #include "migration/vmstate.h" +#include "migration/savevm.h" #include "qemu-file.h" #include "qemu/bitops.h" #include "qemu/error-report.h" diff --git a/monitor.c b/monitor.c index 1e63ace2d4..fcf4fad47b 100644 --- a/monitor.c +++ b/monitor.c @@ -3088,6 +3088,8 @@ static void handle_hmp_command(Monitor *mon, const char *cmdline) QDict *qdict; const mon_cmd_t *cmd; + trace_handle_hmp_command(mon, cmdline); + cmd = monitor_parse_command(mon, &cmdline, mon->cmd_table); if (!cmd) { return; @@ -3807,6 +3809,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) QDict *qdict = NULL; Monitor *mon = cur_mon; Error *err = NULL; + QString *req_json; req = json_parser_parse_err(tokens, NULL, &err); if (!req && !err) { @@ -3824,6 +3827,10 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) qdict_del(qdict, "id"); } /* else will fail qmp_dispatch() */ + req_json = qobject_to_json(req); + trace_handle_qmp_command(mon, qstring_get_str(req_json)); + qobject_decref(QOBJECT(req_json)); + rsp = qmp_dispatch(cur_mon->qmp.commands, req); if (mon->qmp.commands == &qmp_cap_negotiation_commands) { diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 79a46b6735..fb88c13bc7 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -21,8 +21,10 @@ build-all: s390-ccw.img s390-ccw.elf: $(OBJECTS) $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@") +STRIP ?= strip + s390-ccw.img: s390-ccw.elf - $(call quiet-command,strip --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") + $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") $(OBJECTS): Makefile diff --git a/qdev-monitor.c b/qdev-monitor.c index 3ecbf0bd25..8fd6df93d2 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -29,7 +29,7 @@ #include "qemu/error-report.h" #include "qemu/help_option.h" #include "sysemu/block-backend.h" -#include "migration/migration.h" +#include "migration/misc.h" /* * Aliases were a bad idea from the start. Let's keep them diff --git a/rules.mak b/rules.mak index 1c0eabb367..2a2fb72e85 100644 --- a/rules.mak +++ b/rules.mak @@ -20,9 +20,6 @@ MAKEFLAGS += -rR %.mak: clean-target: -# Flags for C++ compilation -QEMU_CXXFLAGS = -D__STDC_LIMIT_MACROS $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls, $(QEMU_CFLAGS)) - # Flags for dependency generation QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d diff --git a/scripts/coccinelle/return_directly.cocci b/scripts/coccinelle/return_directly.cocci index 48680f2c2a..4cf50e75ea 100644 --- a/scripts/coccinelle/return_directly.cocci +++ b/scripts/coccinelle/return_directly.cocci @@ -1,4 +1,4 @@ -// replace 'R = X; return R;' with 'return R;' +// replace 'R = X; return R;' with 'return X;' @@ identifier VAR; expression E; diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index d60b3a08f7..f1be6e419a 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -42,7 +42,15 @@ def get_record(edict, idtoname, rechdr, fobj): event_id = rechdr[0] name = idtoname[event_id] rec = (name, rechdr[1], rechdr[3]) - event = edict[name] + try: + event = edict[name] + except KeyError, e: + import sys + sys.stderr.write('%s event is logged but is not declared ' \ + 'in the trace events file, try using ' \ + 'trace-events-all instead.\n' % str(e)) + sys.exit(1) + for type, name in event.args: if is_string(type): l = fobj.read(4) diff --git a/slirp/slirp.c b/slirp/slirp.c index 23864938f7..1d6756821c 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -26,6 +26,7 @@ #include "qemu/timer.h" #include "qemu/error-report.h" #include "chardev/char-fe.h" +#include "migration/register.h" #include "slirp.h" #include "hw/hw.h" #include "qemu/cutils.h" diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 51249ce79e..f2f7c531bc 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -478,7 +478,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) } } -bool kvmppc_is_mem_backend_page_size_ok(char *obj_path) +bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) { Object *mem_obj = object_resolve_path(obj_path, NULL); char *mempath = object_property_get_str(mem_obj, "mem-path", NULL); @@ -486,6 +486,7 @@ bool kvmppc_is_mem_backend_page_size_ok(char *obj_path) if (mempath) { pagesize = qemu_mempath_getpagesize(mempath); + g_free(mempath); } else { pagesize = getpagesize(); } @@ -499,7 +500,7 @@ static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu) { } -bool kvmppc_is_mem_backend_page_size_ok(char *obj_path) +bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) { return true; } diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index f48243d13f..eab7c8fdb3 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -64,7 +64,7 @@ int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); -bool kvmppc_is_mem_backend_page_size_ok(char *obj_path); +bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path); #else @@ -211,7 +211,7 @@ static inline uint64_t kvmppc_rma_size(uint64_t current_size, return ram_size; } -static inline bool kvmppc_is_mem_backend_page_size_ok(char *obj_path) +static inline bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) { return true; } diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index a4d31df2b5..a4028fb315 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -149,7 +149,7 @@ typedef struct CPUS390XState { CPU_COMMON uint32_t cpu_num; - uint32_t machine_type; + uint64_t cpuid; uint64_t tod_offset; uint64_t tod_basetime; @@ -460,11 +460,6 @@ static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr) } #ifndef CONFIG_USER_ONLY -/* In several cases of runtime exceptions, we havn't recorded the true - instruction length. Use these codes when raising exceptions in order - to re-compute the length by examining the insn in memory. */ -#define ILEN_LATER 0x20 -#define ILEN_LATER_INC 0x21 void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen); #endif @@ -1133,6 +1128,8 @@ uint32_t set_cc_nz_f128(float128 v); int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3); void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3); #endif +/* automatically detect the instruction length */ +#define ILEN_AUTO 0xff void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, uintptr_t retaddr); diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index fc3cb25cc3..478bcc604e 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -184,6 +184,7 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, S390FeatBitmap features) { const S390CPUDef *last_compatible = NULL; + const S390CPUDef *matching_cpu_type = NULL; int i; if (!gen) { @@ -218,8 +219,16 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, if (def->type == type && def->ec_ga == ec_ga) { return def; } + /* remember if we've at least seen one with the same cpu type */ + if (def->type == type) { + matching_cpu_type = def; + } last_compatible = def; } + /* prefer the model with the same cpu type, esp. don't take the BC for EC */ + if (matching_cpu_type) { + return matching_cpu_type; + } return last_compatible; } @@ -728,8 +737,6 @@ static inline void apply_cpu_model(const S390CPUModel *model, Error **errp) if (kvm_enabled()) { kvm_s390_apply_cpu_model(model, errp); - } else if (model) { - /* FIXME TCG - use data for stdip/stfl */ } if (!*errp) { @@ -767,6 +774,7 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp) /* copy over properties that can vary */ cpu->model->lowest_ibc = max_model->lowest_ibc; cpu->model->cpu_id = max_model->cpu_id; + cpu->model->cpu_id_format = max_model->cpu_id_format; cpu->model->cpu_ver = max_model->cpu_ver; check_consistency(cpu->model); @@ -776,6 +784,12 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp) } apply_cpu_model(cpu->model, errp); + + cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model); + if (tcg_enabled()) { + /* basic mode, write the cpu address into the first 4 bit of the ID */ + cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.cpu_num); + } } static void get_feature(Object *obj, Visitor *v, const char *name, diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index 136a602313..d41f8d6e38 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -46,6 +46,7 @@ typedef struct S390CPUModel { /* values copied from the "host" model, can change during migration */ uint16_t lowest_ibc; /* lowest IBC that the hardware supports */ uint32_t cpu_id; /* CPU id */ + uint8_t cpu_id_format; /* CPU id format bit */ uint8_t cpu_ver; /* CPU version, usually "ff" for kvm */ } S390CPUModel; @@ -54,12 +55,14 @@ typedef struct S390CPUModel { * * bits 0-7: Zeroes (ff for kvm) * bits 8-31: CPU ID (serial number) - * bits 32-48: Machine type - * bits 48-63: Zeroes + * bits 32-47: Machine type + * bit 48: CPU ID format + * bits 49-63: Zeroes */ #define cpuid_type(x) (((x) >> 16) & 0xffff) #define cpuid_id(x) (((x) >> 32) & 0xffffff) #define cpuid_ver(x) (((x) >> 56) & 0xff) +#define cpuid_format(x) (((x) >> 15) & 0x1) #define lowest_ibc(x) (((uint32_t)(x) >> 16) & 0xfff) #define unblocked_ibc(x) ((uint32_t)(x) & 0xfff) @@ -92,7 +95,8 @@ static inline uint64_t s390_cpuid_from_cpu_model(const S390CPUModel *model) { return ((uint64_t)model->cpu_ver << 56) | ((uint64_t)model->cpu_id << 32) | - ((uint64_t)model->def->type << 16); + ((uint64_t)model->def->type << 16) | + (model->def->gen == 7 ? 0 : (uint64_t)model->cpu_id_format << 15); } S390CPUDef const *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, S390FeatBitmap features); diff --git a/target/s390x/helper.c b/target/s390x/helper.c index a8d20c51fa..aef09e1234 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -204,7 +204,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, if (raddr > ram_size) { DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)raddr, (uint64_t)ram_size); - trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER_INC); + trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO); return 1; } @@ -331,16 +331,42 @@ static void do_program_interrupt(CPUS390XState *env) LowCore *lowcore; int ilen = env->int_pgm_ilen; - switch (ilen) { - case ILEN_LATER: - ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); - break; - case ILEN_LATER_INC: + if (ilen == ILEN_AUTO) { ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); + } + assert(ilen == 2 || ilen == 4 || ilen == 6); + + switch (env->int_pgm_code) { + case PGM_PER: + if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) { + break; + } + /* FALL THROUGH */ + case PGM_OPERATION: + case PGM_PRIVILEGED: + case PGM_EXECUTE: + case PGM_PROTECTION: + case PGM_ADDRESSING: + case PGM_SPECIFICATION: + case PGM_DATA: + case PGM_FIXPT_OVERFLOW: + case PGM_FIXPT_DIVIDE: + case PGM_DEC_OVERFLOW: + case PGM_DEC_DIVIDE: + case PGM_HFP_EXP_OVERFLOW: + case PGM_HFP_EXP_UNDERFLOW: + case PGM_HFP_SIGNIFICANCE: + case PGM_HFP_DIVIDE: + case PGM_TRANS_SPEC: + case PGM_SPECIAL_OP: + case PGM_OPERAND: + case PGM_HFP_SQRT: + case PGM_PC_TRANS_SPEC: + case PGM_ALET_SPEC: + case PGM_MONITOR: + /* advance the PSW if our exception is not nullifying */ env->psw.addr += ilen; break; - default: - assert(ilen == 2 || ilen == 4 || ilen == 6); } qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", @@ -737,6 +763,6 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, if (retaddr) { cpu_restore_state(cs, retaddr); } - program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER); + program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); } #endif /* CONFIG_USER_ONLY */ diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 73dd05daf0..d089707073 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -960,7 +960,7 @@ /* STORE CPU ADDRESS */ C(0xb212, STAP, S, Z, la2, 0, new, m1_16, stap, 0) /* STORE CPU ID */ - C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) + C(0xb202, STIDP, S, Z, la2, 0, new, 0, stidp, 0) /* STORE CPU TIMER */ C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) /* STORE FACILITY LIST */ diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 62a777100c..d5e6b8066b 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -201,6 +201,10 @@ static int ioinst_orb_valid(ORB *orb) (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) { return 0; } + /* We don't support MIDA. */ + if (orb->ctrl1 & ORB_CTRL1_MASK_MIDAW) { + return 0; + } if ((orb->cpa & HIGH_ORDER_BIT) != 0) { return 0; } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index ba1e60f8a6..a3d00196f4 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -2580,6 +2580,7 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) unblocked_ibc = unblocked_ibc(prop.ibc); } model->cpu_id = cpuid_id(prop.cpuid); + model->cpu_id_format = cpuid_format(prop.cpuid); model->cpu_ver = 0xff; /* get supported cpu features indicated via STFL(E) */ diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index edcdf17db6..b5081019c5 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -54,19 +54,14 @@ void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, uintptr_t retaddr) { CPUState *cs = CPU(s390_env_get_cpu(env)); - int t; cs->exception_index = EXCP_PGM; env->int_pgm_code = excp; + env->int_pgm_ilen = ILEN_AUTO; /* Use the (ultimate) callers address to find the insn that trapped. */ cpu_restore_state(cs, retaddr); - /* Advance past the insn. */ - t = cpu_ldub_code(env, env->psw.addr); - env->int_pgm_ilen = t = get_ilen(t); - env->psw.addr += t; - cpu_loop_exit(cs); } @@ -199,12 +194,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) IplParameterBlock *iplb; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC); + program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO); return; } if ((subcode & ~0x0ffffULL) || (subcode > 6)) { - program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); + program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); return; } @@ -229,12 +224,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) break; case 5: if ((r1 & 1) || (addr & 0x0fffULL)) { - program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); + program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); return; } if (!address_space_access_valid(&address_space_memory, addr, sizeof(IplParameterBlock), false)) { - program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); + program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO); return; } iplb = g_malloc0(sizeof(IplParameterBlock)); @@ -258,12 +253,12 @@ out: return; case 6: if ((r1 & 1) || (addr & 0x0fffULL)) { - program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); + program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); return; } if (!address_space_access_valid(&address_space_memory, addr, sizeof(IplParameterBlock), true)) { - program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); + program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO); return; } iplb = s390_ipl_get_iplb(); @@ -307,7 +302,7 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) } if (r) { - program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); + program_interrupt(env, PGM_OPERATION, ILEN_AUTO); } } @@ -383,6 +378,7 @@ uint64_t HELPER(stpt)(CPUS390XState *env) uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) { + S390CPU *cpu = s390_env_get_cpu(env); int cc = 0; int sel1, sel2; @@ -402,12 +398,14 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, if ((sel1 == 1) && (sel2 == 1)) { /* Basic Machine Configuration */ struct sysib_111 sysib; + char type[5] = {}; memset(&sysib, 0, sizeof(sysib)); ebcdic_put(sysib.manuf, "QEMU ", 16); - /* same as machine type number in STORE CPU ID */ - ebcdic_put(sysib.type, "QEMU", 4); - /* same as model number in STORE CPU ID */ + /* same as machine type number in STORE CPU ID, but in EBCDIC */ + snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type); + ebcdic_put(sysib.type, type, 4); + /* model number (not stored in STORE CPU ID for z/Architecure) */ ebcdic_put(sysib.model, "QEMU ", 16); ebcdic_put(sysib.sequence, "QEMU ", 16); ebcdic_put(sysib.plant, "QEMU", 4); @@ -668,6 +666,7 @@ void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr) if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) { CPUState *cs = CPU(s390_env_get_cpu(env)); + env->per_perc_atmid |= PER_CODE_EVENT_NULLIFICATION; env->int_pgm_code = PGM_PER; env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr)); diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 501e39010d..a873dc48a0 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -79,13 +79,13 @@ static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, return; } - trigger_access_exception(env, PGM_PROTECTION, ILEN_LATER_INC, tec); + trigger_access_exception(env, PGM_PROTECTION, ILEN_AUTO, tec); } static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, uint64_t asc, int rw, bool exc) { - int ilen = ILEN_LATER; + int ilen = ILEN_AUTO; uint64_t tec; tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | asc >> 46; @@ -431,7 +431,7 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages, for (i = 0; i < nr_pages; i++) { /* Low-address protection? */ if (lowprot && (addr < 512 || (addr >= 4096 && addr < 4096 + 512))) { - trigger_access_exception(env, PGM_PROTECTION, ILEN_LATER_INC, 0); + trigger_access_exception(env, PGM_PROTECTION, ILEN_AUTO, 0); return -EACCES; } ret = mmu_translate(env, addr, is_write, asc, &pages[i], &pflags, true); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 95f91d4f08..8c055b7bb7 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -355,8 +355,7 @@ static void gen_program_exception(DisasContext *s, int code) tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen)); tcg_temp_free_i32(tmp); - /* Advance past instruction. */ - s->pc = s->next_pc; + /* update the psw */ update_psw_addr(s); /* Save off cc. */ @@ -3877,14 +3876,9 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o) static ExitStatus op_stidp(DisasContext *s, DisasOps *o) { - TCGv_i64 t1 = tcg_temp_new_i64(); - check_privileged(s); - tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); - tcg_gen_ld32u_i64(t1, cpu_env, offsetof(CPUS390XState, machine_type)); - tcg_gen_deposit_i64(o->out, o->out, t1, 32, 32); - tcg_temp_free_i64(t1); - + tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, cpuid)); + tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN); return NO_EXIT; } diff --git a/tests/test-char.c b/tests/test-char.c index dfe856cb85..9e361c8d09 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -450,6 +450,32 @@ static void char_udp_test(void) g_free(tmp); } +#ifdef HAVE_CHARDEV_SERIAL +static void char_serial_test(void) +{ + QemuOpts *opts; + Chardev *chr; + + opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id", + 1, &error_abort); + qemu_opt_set(opts, "backend", "serial", &error_abort); + qemu_opt_set(opts, "path", "/dev/null", &error_abort); + + chr = qemu_chr_new_from_opts(opts, NULL); + g_assert_nonnull(chr); + /* TODO: add more tests with a pty */ + object_unparent(OBJECT(chr)); + + /* test tty alias */ + qemu_opt_set(opts, "backend", "tty", &error_abort); + chr = qemu_chr_new_from_opts(opts, NULL); + g_assert_nonnull(chr); + object_unparent(OBJECT(chr)); + + qemu_opts_del(opts); +} +#endif + static void char_file_test(void) { char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); @@ -597,6 +623,9 @@ int main(int argc, char **argv) g_test_add_func("/char/file", char_file_test); g_test_add_func("/char/socket", char_socket_test); g_test_add_func("/char/udp", char_udp_test); +#ifdef HAVE_CHARDEV_SERIAL + g_test_add_func("/char/serial", char_serial_test); +#endif return g_test_run(); } diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index c52aff96d6..ee292c7bee 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -25,11 +25,12 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "migration/migration.h" +#include "../migration/migration.h" #include "migration/vmstate.h" #include "migration/qemu-file-types.h" #include "../migration/qemu-file.h" #include "../migration/qemu-file-channel.h" +#include "../migration/savevm.h" #include "qemu/coroutine.h" #include "io/channel-file.h" diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c index 8618c20d53..1e5b5ca3da 100644 --- a/tests/vhost-user-bridge.c +++ b/tests/vhost-user-bridge.c @@ -220,12 +220,18 @@ vubr_handle_tx(VuDev *dev, int qidx) free(elem); } + +/* this function reverse the effect of iov_discard_front() it must be + * called with 'front' being the original struct iovec and 'bytes' + * being the number of bytes you shaved off + */ static void iov_restore_front(struct iovec *front, struct iovec *iov, size_t bytes) { struct iovec *cur; - for (cur = front; front != iov; cur++) { + for (cur = front; cur != iov; cur++) { + assert(bytes >= cur->iov_len); bytes -= cur->iov_len; } @@ -302,7 +308,8 @@ vubr_backend_recv_cb(int sock, void *ctx) } iov_from_buf(sg, elem->in_num, 0, &hdr, sizeof hdr); total += hdrlen; - assert(iov_discard_front(&sg, &num, hdrlen) == hdrlen); + ret = iov_discard_front(&sg, &num, hdrlen); + assert(ret == hdrlen); } struct msghdr msg = { diff --git a/trace-events b/trace-events index b496be94d4..fd83087e39 100644 --- a/trace-events +++ b/trace-events @@ -45,6 +45,8 @@ qemu_system_powerdown_request(void) "" monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d data=%p" monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p" monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" PRId64 +handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" +handle_qmp_command(void *mon, const char *req) "mon %p req: %s" # dma-helpers.c dma_blk_io(void *dbs, void *bs, int64_t offset, bool to_dev) "dbs=%p bs=%p offset=%" PRId64 " to_dev=%d" diff --git a/ui/spice-core.c b/ui/spice-core.c index 804abc5c0f..a087ad5da9 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -35,7 +35,7 @@ #include "qapi/qmp/qstring.h" #include "qapi/qmp/qjson.h" #include "qemu/notify.h" -#include "migration/migration.h" +#include "migration/misc.h" #include "hw/hw.h" #include "ui/spice-display.h" #include "qapi-event.h" diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 048d40d9de..5e8b4b39ed 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -402,7 +402,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, /* touch pages simultaneously */ if (touch_all_pages(area, hpagesize, numpages, smp_cpus)) { error_setg(errp, "os_mem_prealloc: Insufficient free host memory " - "pages available to allocate guest RAM\n"); + "pages available to allocate guest RAM"); } ret = sigaction(SIGBUS, &oldact, NULL); diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 6328eed26b..b44b5d55eb 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -77,10 +77,25 @@ void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex) void qemu_co_queue_run_restart(Coroutine *co) { Coroutine *next; + QSIMPLEQ_HEAD(, Coroutine) tmp_queue_wakeup = + QSIMPLEQ_HEAD_INITIALIZER(tmp_queue_wakeup); trace_qemu_co_queue_run_restart(co); - while ((next = QSIMPLEQ_FIRST(&co->co_queue_wakeup))) { - QSIMPLEQ_REMOVE_HEAD(&co->co_queue_wakeup, co_queue_next); + + /* Because "co" has yielded, any coroutine that we wakeup can resume it. + * If this happens and "co" terminates, co->co_queue_wakeup becomes + * invalid memory. Therefore, use a temporary queue and do not touch + * the "co" coroutine as soon as you enter another one. + * + * In its turn resumed "co" can pupulate "co_queue_wakeup" queue with + * new coroutines to be woken up. The caller, who has resumed "co", + * will be responsible for traversing the same queue, which may cause + * a different wakeup order but not any missing wakeups. + */ + QSIMPLEQ_CONCAT(&tmp_queue_wakeup, &co->co_queue_wakeup); + + while ((next = QSIMPLEQ_FIRST(&tmp_queue_wakeup))) { + QSIMPLEQ_REMOVE_HEAD(&tmp_queue_wakeup, co_queue_next); qemu_coroutine_enter(next); } } diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 486af9a622..d6095c1d5a 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -126,6 +126,11 @@ void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co) qemu_co_queue_run_restart(co); + /* Beware, if ret == COROUTINE_YIELD and qemu_co_queue_run_restart() + * has started any other coroutine, "co" might have been reentered + * and even freed by now! So be careful and do not touch it. + */ + switch (ret) { case COROUTINE_YIELD: return; diff --git a/vl.c b/vl.c index be4dcf25ba..32db19e3b9 100644 --- a/vl.c +++ b/vl.c @@ -88,11 +88,11 @@ int main(int argc, char **argv) #include "hw/block/block.h" #include "migration/misc.h" #include "migration/snapshot.h" +#include "migration/global_state.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" #include "migration/colo.h" #include "sysemu/kvm.h" |