diff options
38 files changed, 598 insertions, 227 deletions
@@ -417,7 +417,7 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options) { BlockDriver *drv; - drv = bdrv_find_protocol(filename); + drv = bdrv_find_protocol(filename, true); if (drv == NULL) { return -ENOENT; } @@ -482,7 +482,8 @@ static BlockDriver *find_hdev_driver(const char *filename) return drv; } -BlockDriver *bdrv_find_protocol(const char *filename) +BlockDriver *bdrv_find_protocol(const char *filename, + bool allow_protocol_prefix) { BlockDriver *drv1; char protocol[128]; @@ -503,9 +504,10 @@ BlockDriver *bdrv_find_protocol(const char *filename) return drv1; } - if (!path_has_protocol(filename)) { + if (!path_has_protocol(filename) || !allow_protocol_prefix) { return bdrv_find_format("file"); } + p = strchr(filename, ':'); assert(p != NULL); len = p - filename; @@ -784,6 +786,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, BlockDriverState *bs; BlockDriver *drv; const char *drvname; + bool allow_protocol_prefix = false; int ret; /* NULL means an empty set of options */ @@ -800,6 +803,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, filename = qdict_get_try_str(options, "filename"); } else if (filename && !qdict_haskey(options, "filename")) { qdict_put(options, "filename", qstring_from_str(filename)); + allow_protocol_prefix = true; } else { qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and " "'filename' options at the same time"); @@ -813,7 +817,10 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR)); qdict_del(options, "driver"); } else if (filename) { - drv = bdrv_find_protocol(filename); + drv = bdrv_find_protocol(filename, allow_protocol_prefix); + if (!drv) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Unknown protocol"); + } } else { qerror_report(ERROR_CLASS_GENERIC_ERROR, "Must specify either driver or file"); @@ -2903,13 +2910,19 @@ int bdrv_get_flags(BlockDriverState *bs) return bs->open_flags; } -void bdrv_flush_all(void) +int bdrv_flush_all(void) { BlockDriverState *bs; + int result = 0; QTAILQ_FOREACH(bs, &bdrv_states, list) { - bdrv_flush(bs); + int ret = bdrv_flush(bs); + if (ret < 0 && !result) { + result = ret; + } } + + return result; } int bdrv_has_zero_init_1(BlockDriverState *bs) @@ -4452,7 +4465,7 @@ void bdrv_img_create(const char *filename, const char *fmt, return; } - proto_drv = bdrv_find_protocol(filename); + proto_drv = bdrv_find_protocol(filename, true); if (!proto_drv) { error_setg(errp, "Unknown protocol '%s'", filename); return; diff --git a/block/sheepdog.c b/block/sheepdog.c index b397b5b4d3..6a41ad9b3c 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1510,7 +1510,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) BlockDriver *drv; /* Currently, only Sheepdog backing image is supported. */ - drv = bdrv_find_protocol(backing_file); + drv = bdrv_find_protocol(backing_file, true); if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) { error_report("backing_file must be a sheepdog image"); ret = -EINVAL; diff --git a/blockdev.c b/blockdev.c index b3a57e0c1d..c5abd65182 100644 --- a/blockdev.c +++ b/blockdev.c @@ -936,6 +936,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp) qmp_drive_backup(backup->device, backup->target, backup->has_format, backup->format, + backup->sync, backup->has_mode, backup->mode, backup->has_speed, backup->speed, backup->has_on_source_error, backup->on_source_error, @@ -1421,6 +1422,7 @@ void qmp_block_commit(const char *device, void qmp_drive_backup(const char *device, const char *target, bool has_format, const char *format, + enum MirrorSyncMode sync, bool has_mode, enum NewImageMode mode, bool has_speed, int64_t speed, bool has_on_source_error, BlockdevOnError on_source_error, @@ -1435,6 +1437,10 @@ void qmp_drive_backup(const char *device, const char *target, int64_t size; int ret; + if (sync != MIRROR_SYNC_MODE_FULL) { + error_setg(errp, "only sync mode 'full' is currently supported"); + return; + } if (!has_speed) { speed = 0; } @@ -434,17 +434,21 @@ bool cpu_is_stopped(CPUState *cpu) return !runstate_is_running() || cpu->stopped; } -static void do_vm_stop(RunState state) +static int do_vm_stop(RunState state) { + int ret = 0; + if (runstate_is_running()) { cpu_disable_ticks(); pause_all_vcpus(); runstate_set(state); vm_state_notify(0, state); bdrv_drain_all(); - bdrv_flush_all(); + ret = bdrv_flush_all(); monitor_protocol_event(QEVENT_STOP, NULL); } + + return ret; } static bool cpu_can_run(CPUState *cpu) @@ -1099,7 +1103,7 @@ void cpu_stop_current(void) } } -void vm_stop(RunState state) +int vm_stop(RunState state) { if (qemu_in_vcpu_thread()) { qemu_system_vmstop_request(state); @@ -1108,19 +1112,21 @@ void vm_stop(RunState state) * vm_stop() has been requested. */ cpu_stop_current(); - return; + return 0; } - do_vm_stop(state); + + return do_vm_stop(state); } /* does a state transition even if the VM is already stopped, current state is forgotten forever */ -void vm_stop_force_state(RunState state) +int vm_stop_force_state(RunState state) { if (runstate_is_running()) { - vm_stop(state); + return vm_stop(state); } else { runstate_set(state); + return 0; } } @@ -1896,15 +1896,37 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) return false; } -static inline int memory_access_size(MemoryRegion *mr, int l, hwaddr addr) +static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) { - if (l >= 4 && (((addr & 3) == 0 || mr->ops->impl.unaligned))) { - return 4; + unsigned access_size_min = mr->ops->impl.min_access_size; + unsigned access_size_max = mr->ops->impl.max_access_size; + + /* Regions are assumed to support 1-4 byte accesses unless + otherwise specified. */ + if (access_size_min == 0) { + access_size_min = 1; + } + if (access_size_max == 0) { + access_size_max = 4; + } + + /* Bound the maximum access by the alignment of the address. */ + if (!mr->ops->impl.unaligned) { + unsigned align_size_max = addr & -addr; + if (align_size_max != 0 && align_size_max < access_size_max) { + access_size_max = align_size_max; + } } - if (l >= 2 && (((addr & 1) == 0) || mr->ops->impl.unaligned)) { - return 2; + + /* Don't attempt accesses larger than the maximum. */ + if (l > access_size_max) { + l = access_size_max; } - return 1; + /* ??? The users of this function are wrong, not supporting minimums larger + than the remaining length. C.f. memory.c:access_with_adjusted_size. */ + assert(l >= access_size_min); + + return l; } bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, @@ -1926,18 +1948,29 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, l = memory_access_size(mr, l, addr1); /* XXX: could force current_cpu to NULL to avoid potential bugs */ - if (l == 4) { + switch (l) { + case 8: + /* 64 bit write access */ + val = ldq_p(buf); + error |= io_mem_write(mr, addr1, val, 8); + break; + case 4: /* 32 bit write access */ val = ldl_p(buf); error |= io_mem_write(mr, addr1, val, 4); - } else if (l == 2) { + break; + case 2: /* 16 bit write access */ val = lduw_p(buf); error |= io_mem_write(mr, addr1, val, 2); - } else { + break; + case 1: /* 8 bit write access */ val = ldub_p(buf); error |= io_mem_write(mr, addr1, val, 1); + break; + default: + abort(); } } else { addr1 += memory_region_get_ram_addr(mr); @@ -1950,18 +1983,29 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, if (!memory_access_is_direct(mr, is_write)) { /* I/O case */ l = memory_access_size(mr, l, addr1); - if (l == 4) { + switch (l) { + case 8: + /* 64 bit read access */ + error |= io_mem_read(mr, addr1, &val, 8); + stq_p(buf, val); + break; + case 4: /* 32 bit read access */ error |= io_mem_read(mr, addr1, &val, 4); stl_p(buf, val); - } else if (l == 2) { + break; + case 2: /* 16 bit read access */ error |= io_mem_read(mr, addr1, &val, 2); stw_p(buf, val); - } else { + break; + case 1: /* 8 bit read access */ error |= io_mem_read(mr, addr1, &val, 1); stb_p(buf, val); + break; + default: + abort(); } } else { /* RAM case */ diff --git a/hmp-commands.hx b/hmp-commands.hx index d1cdcfb71b..8c6b91a9c7 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1059,6 +1059,26 @@ using the specified target. ETEXI { + .name = "drive_backup", + .args_type = "reuse:-n,full:-f,device:B,target:s,format:s?", + .params = "[-n] [-f] device target [format]", + .help = "initiates a point-in-time\n\t\t\t" + "copy for a device. The device's contents are\n\t\t\t" + "copied to the new image file, excluding data that\n\t\t\t" + "is written after the command is started.\n\t\t\t" + "The -n flag requests QEMU to reuse the image found\n\t\t\t" + "in new-image-file, instead of recreating it from scratch.\n\t\t\t" + "The -f flag requests QEMU to copy the whole disk,\n\t\t\t" + "so that the result does not need a backing file.\n\t\t\t", + .mhandler.cmd = hmp_drive_backup, + }, +STEXI +@item drive_backup +@findex drive_backup +Start a point-in-time copy of a block device to a specificed target. +ETEXI + + { .name = "drive_add", .args_type = "pci_addr:s,opts:s", .params = "[[<domain>:]<bus>:]<slot>\n" @@ -907,6 +907,34 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &errp); } +void hmp_drive_backup(Monitor *mon, const QDict *qdict) +{ + const char *device = qdict_get_str(qdict, "device"); + const char *filename = qdict_get_str(qdict, "target"); + const char *format = qdict_get_try_str(qdict, "format"); + int reuse = qdict_get_try_bool(qdict, "reuse", 0); + int full = qdict_get_try_bool(qdict, "full", 0); + enum NewImageMode mode; + Error *errp = NULL; + + if (!filename) { + error_set(&errp, QERR_MISSING_PARAMETER, "target"); + hmp_handle_error(mon, &errp); + return; + } + + if (reuse) { + mode = NEW_IMAGE_MODE_EXISTING; + } else { + mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; + } + + qmp_drive_backup(device, filename, !!format, format, + full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, + true, mode, false, 0, false, 0, false, 0, &errp); + hmp_handle_error(mon, &errp); +} + void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); @@ -55,6 +55,7 @@ void hmp_balloon(Monitor *mon, const QDict *qdict); void hmp_block_resize(Monitor *mon, const QDict *qdict); void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict); void hmp_drive_mirror(Monitor *mon, const QDict *qdict); +void hmp_drive_backup(Monitor *mon, const QDict *qdict); void hmp_migrate_cancel(Monitor *mon, const QDict *qdict); void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict); void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict); diff --git a/hw/alpha/alpha_sys.h b/hw/alpha/alpha_sys.h index 50e7730caa..e11025b4be 100644 --- a/hw/alpha/alpha_sys.h +++ b/hw/alpha/alpha_sys.h @@ -14,7 +14,7 @@ PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4], pci_map_irq_fn); /* alpha_pci.c. */ -extern const MemoryRegionOps alpha_pci_bw_io_ops; +extern const MemoryRegionOps alpha_pci_ignore_ops; extern const MemoryRegionOps alpha_pci_conf1_ops; extern const MemoryRegionOps alpha_pci_iack_ops; diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 8dad08fac2..95fde615be 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -73,7 +73,9 @@ static void clipper_init(QEMUMachineInitArgs *args) pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, clipper_pci_map_irq); - rtc_init(isa_bus, 1980, rtc_irq); + /* Since we have an SRM-compatible PALcode, use the SRM epoch. */ + rtc_init(isa_bus, 1900, rtc_irq); + pit_init(isa_bus, 0x40, 0, NULL); isa_create_simple(isa_bus, "i8042"); diff --git a/hw/alpha/pci.c b/hw/alpha/pci.c index 7327d488fd..d839dd556a 100644 --- a/hw/alpha/pci.c +++ b/hw/alpha/pci.c @@ -12,50 +12,32 @@ #include "sysemu/sysemu.h" -/* PCI IO reads/writes, to byte-word addressable memory. */ -/* ??? Doesn't handle multiple PCI busses. */ +/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */ -static uint64_t bw_io_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) { - switch (size) { - case 1: - return cpu_inb(addr); - case 2: - return cpu_inw(addr); - case 4: - return cpu_inl(addr); - } - abort(); + return 0; } -static void bw_io_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) +static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) { - switch (size) { - case 1: - cpu_outb(addr, val); - break; - case 2: - cpu_outw(addr, val); - break; - case 4: - cpu_outl(addr, val); - break; - default: - abort(); - } } -const MemoryRegionOps alpha_pci_bw_io_ops = { - .read = bw_io_read, - .write = bw_io_write, +const MemoryRegionOps alpha_pci_ignore_ops = { + .read = ignore_read, + .write = ignore_write, .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, .impl = { .min_access_size = 1, - .max_access_size = 4, + .max_access_size = 8, }, }; + /* PCI config space reads/writes, to byte-word addressable memory. */ static uint64_t bw_conf1_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 1c3ac8e172..3d7a1cd8e8 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -51,9 +51,6 @@ typedef struct TyphoonState { TyphoonPchip pchip; MemoryRegion dchip_region; MemoryRegion ram_region; - - /* QEMU emulation state. */ - uint32_t latch_tmp; } TyphoonState; /* Called when one of DRIR or DIM changes. */ @@ -76,10 +73,6 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) TyphoonState *s = opaque; uint64_t ret = 0; - if (addr & 4) { - return s->latch_tmp; - } - switch (addr) { case 0x0000: /* CSC: Cchip System Configuration Register. */ @@ -199,7 +192,6 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) return -1; } - s->latch_tmp = ret >> 32; return ret; } @@ -214,10 +206,6 @@ static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) TyphoonState *s = opaque; uint64_t ret = 0; - if (addr & 4) { - return s->latch_tmp; - } - switch (addr) { case 0x0000: /* WSBA0: Window Space Base Address Register. */ @@ -302,23 +290,14 @@ static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) return -1; } - s->latch_tmp = ret >> 32; return ret; } static void cchip_write(void *opaque, hwaddr addr, - uint64_t v32, unsigned size) + uint64_t val, unsigned size) { TyphoonState *s = opaque; - uint64_t val, oldval, newval; - - if (addr & 4) { - val = v32 << 32 | s->latch_tmp; - addr ^= 4; - } else { - s->latch_tmp = v32; - return; - } + uint64_t oldval, newval; switch (addr) { case 0x0000: @@ -471,18 +450,10 @@ static void dchip_write(void *opaque, hwaddr addr, } static void pchip_write(void *opaque, hwaddr addr, - uint64_t v32, unsigned size) + uint64_t val, unsigned size) { TyphoonState *s = opaque; - uint64_t val, oldval; - - if (addr & 4) { - val = v32 << 32 | s->latch_tmp; - addr ^= 4; - } else { - s->latch_tmp = v32; - return; - } + uint64_t oldval; switch (addr) { case 0x0000: @@ -585,12 +556,12 @@ static const MemoryRegionOps cchip_ops = { .write = cchip_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { - .min_access_size = 4, /* ??? Should be 8. */ + .min_access_size = 8, .max_access_size = 8, }, .impl = { - .min_access_size = 4, - .max_access_size = 4, + .min_access_size = 8, + .max_access_size = 8, }, }; @@ -599,11 +570,11 @@ static const MemoryRegionOps dchip_ops = { .write = dchip_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { - .min_access_size = 4, /* ??? Should be 8. */ + .min_access_size = 8, .max_access_size = 8, }, .impl = { - .min_access_size = 4, + .min_access_size = 8, .max_access_size = 8, }, }; @@ -613,12 +584,12 @@ static const MemoryRegionOps pchip_ops = { .write = pchip_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { - .min_access_size = 4, /* ??? Should be 8. */ + .min_access_size = 8, .max_access_size = 8, }, .impl = { - .min_access_size = 4, - .max_access_size = 4, + .min_access_size = 8, + .max_access_size = 8, }, }; @@ -705,7 +676,6 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, const uint64_t MB = 1024 * 1024; const uint64_t GB = 1024 * MB; MemoryRegion *addr_space = get_system_memory(); - MemoryRegion *addr_space_io = get_system_io(); DeviceState *dev; TyphoonState *s; PCIHostState *phb; @@ -765,28 +735,26 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, &s->pchip.reg_mem); /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB. */ - /* ??? Ideally we drop the "system" i/o space on the floor and give the - PCI subsystem the full address space reserved by the chipset. - We can't do that until the MEM and IO paths in memory.c are unified. */ - memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_bw_io_ops, + memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops, NULL, "pci0-io", 32*MB); memory_region_add_subregion(addr_space, 0x801fc000000ULL, &s->pchip.reg_io); b = pci_register_bus(dev, "pci", typhoon_set_irq, sys_map_irq, s, - &s->pchip.reg_mem, addr_space_io, 0, 64, TYPE_PCI_BUS); + &s->pchip.reg_mem, &s->pchip.reg_io, + 0, 64, TYPE_PCI_BUS); phb->bus = b; /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ - memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops, b, - "pci0-iack", 64*MB); + memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops, + b, "pci0-iack", 64*MB); memory_region_add_subregion(addr_space, 0x801f8000000ULL, &s->pchip.reg_iack); /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB. */ - memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops, b, - "pci0-conf", 16*MB); + memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops, + b, "pci0-conf", 16*MB); memory_region_add_subregion(addr_space, 0x801fe000000ULL, &s->pchip.reg_conf); @@ -804,7 +772,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, { qemu_irq isa_pci_irq, *isa_irqs; - *isa_bus = isa_bus_new(NULL, addr_space_io); + *isa_bus = isa_bus_new(NULL, &s->pchip.reg_io); isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1); isa_irqs = i8259_init(*isa_bus, isa_pci_irq); isa_bus_irqs(*isa_bus, isa_irqs); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 3a2fb4c81c..be264d3eb3 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -183,20 +183,25 @@ type_init(highbank_regs_register_types) static struct arm_boot_info highbank_binfo; +enum cxmachines { + CALXEDA_HIGHBANK, + CALXEDA_MIDWAY, +}; + /* ram_size must be set to match the upper bound of memory in the * device tree (linux/arch/arm/boot/dts/highbank.dts), which is * normally 0xff900000 or -m 4089. When running this board on a * 32-bit host, set the reg value of memory to 0xf7ff00000 in the * device tree and pass -m 2047 to QEMU. */ -static void highbank_init(QEMUMachineInitArgs *args) +static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) { ram_addr_t ram_size = args->ram_size; const char *cpu_model = args->cpu_model; const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; - DeviceState *dev; + DeviceState *dev = NULL; SysBusDevice *busdev; qemu_irq *irqp; qemu_irq pic[128]; @@ -208,7 +213,14 @@ static void highbank_init(QEMUMachineInitArgs *args) char *sysboot_filename; if (!cpu_model) { - cpu_model = "cortex-a9"; + switch (machine) { + case CALXEDA_HIGHBANK: + cpu_model = "cortex-a9"; + break; + case CALXEDA_MIDWAY: + cpu_model = "cortex-a15"; + break; + } } for (n = 0; n < smp_cpus; n++) { @@ -246,7 +258,19 @@ static void highbank_init(QEMUMachineInitArgs *args) } } - dev = qdev_create(NULL, "a9mpcore_priv"); + switch (machine) { + case CALXEDA_HIGHBANK: + dev = qdev_create(NULL, "l2x0"); + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0xfff12000); + + dev = qdev_create(NULL, "a9mpcore_priv"); + break; + case CALXEDA_MIDWAY: + dev = qdev_create(NULL, "a15mpcore_priv"); + break; + } qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); qdev_init_nofail(dev); @@ -260,11 +284,6 @@ static void highbank_init(QEMUMachineInitArgs *args) pic[n] = qdev_get_gpio_in(dev, n); } - dev = qdev_create(NULL, "l2x0"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xfff12000); - dev = qdev_create(NULL, "sp804"); qdev_prop_set_uint32(dev, "freq0", 150000000); qdev_prop_set_uint32(dev, "freq1", 150000000); @@ -324,6 +343,16 @@ static void highbank_init(QEMUMachineInitArgs *args) arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo); } +static void highbank_init(QEMUMachineInitArgs *args) +{ + calxeda_init(args, CALXEDA_HIGHBANK); +} + +static void midway_init(QEMUMachineInitArgs *args) +{ + calxeda_init(args, CALXEDA_MIDWAY); +} + static QEMUMachine highbank_machine = { .name = "highbank", .desc = "Calxeda Highbank (ECX-1000)", @@ -333,9 +362,19 @@ static QEMUMachine highbank_machine = { DEFAULT_MACHINE_OPTIONS, }; -static void highbank_machine_init(void) +static QEMUMachine midway_machine = { + .name = "midway", + .desc = "Calxeda Midway (ECX-2000)", + .init = midway_init, + .block_default_type = IF_SCSI, + .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, +}; + +static void calxeda_machines_init(void) { qemu_register_machine(&highbank_machine); + qemu_register_machine(&midway_machine); } -machine_init(highbank_machine_init); +machine_init(calxeda_machines_init); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index fd18b60532..7d1b8233cd 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -67,6 +67,7 @@ enum { VE_CLCD, VE_NORFLASH0, VE_NORFLASH1, + VE_NORFLASHALIAS, VE_SRAM, VE_VIDEORAM, VE_ETHERNET, @@ -104,9 +105,11 @@ static hwaddr motherboard_legacy_map[] = { [VE_VIDEORAM] = 0x4c000000, [VE_ETHERNET] = 0x4e000000, [VE_USB] = 0x4f000000, + [VE_NORFLASHALIAS] = -1, /* not present */ }; static hwaddr motherboard_aseries_map[] = { + [VE_NORFLASHALIAS] = 0, /* CS0: 0x08000000 .. 0x0c000000 */ [VE_NORFLASH0] = 0x08000000, /* CS4: 0x0c000000 .. 0x10000000 */ @@ -400,10 +403,13 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, qemu_irq pic[64]; uint32_t sys_id; DriveInfo *dinfo; + pflash_t *pflash0; ram_addr_t vram_size, sram_size; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *vram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); + MemoryRegion *flashalias = g_new(MemoryRegion, 1); + MemoryRegion *flash0mem; const hwaddr *map = daughterboard->motherboard_map; int i; @@ -471,15 +477,24 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, sysbus_create_simple("pl111", map[VE_CLCD], pic[14]); dinfo = drive_get_next(IF_PFLASH); - if (!pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0", + pflash0 = pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0", VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, VEXPRESS_FLASH_SECT_SIZE, VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4, - 0x00, 0x89, 0x00, 0x18, 0)) { + 0x00, 0x89, 0x00, 0x18, 0); + if (!pflash0) { fprintf(stderr, "vexpress: error registering flash 0.\n"); exit(1); } + if (map[VE_NORFLASHALIAS] != -1) { + /* Map flash 0 as an alias into low memory */ + flash0mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(pflash0), 0); + memory_region_init_alias(flashalias, NULL, "vexpress.flashalias", + flash0mem, 0, VEXPRESS_FLASH_SIZE); + memory_region_add_subregion(sysmem, map[VE_NORFLASHALIAS], flashalias); + } + dinfo = drive_get_next(IF_PFLASH); if (!pflash_cfi01_register(map[VE_NORFLASH1], NULL, "vexpress.flash1", VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 131370a74b..4d457f8c65 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -157,7 +157,9 @@ static void uart_rx_reset(UartState *s) { s->rx_wpos = 0; s->rx_count = 0; - qemu_chr_accept_input(s->chr); + if (s->chr) { + qemu_chr_accept_input(s->chr); + } s->r[R_SR] |= UART_SR_INTR_REMPTY; s->r[R_SR] &= ~UART_SR_INTR_RFUL; diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index 967b0809f3..c736257f24 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -82,12 +82,12 @@ static int a15mp_priv_init(SysBusDevice *dev) static Property a15mp_priv_properties[] = { DEFINE_PROP_UINT32("num-cpu", A15MPPrivState, num_cpu, 1), /* The Cortex-A15MP may have anything from 0 to 224 external interrupt - * IRQ lines (with another 32 internal). We default to 64+32, which + * IRQ lines (with another 32 internal). We default to 128+32, which * is the number provided by the Cortex-A15MP test chip in the * Versatile Express A15 development board. * Other boards may differ and should set this property appropriately. */ - DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 96), + DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 160), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index a81ffc4026..0e8cccd27f 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -248,7 +248,7 @@ static void omap_dma_deactivate_channel(struct omap_dma_s *s, /* Don't deactive the channel if it is synchronized and the DMA request is active */ - if (ch->sync && ch->enable && (s->dma->drqbmp & (1 << ch->sync))) + if (ch->sync && ch->enable && (s->dma->drqbmp & (1ULL << ch->sync))) return; if (ch->active) { @@ -268,8 +268,9 @@ static void omap_dma_enable_channel(struct omap_dma_s *s, /* TODO: theoretically if ch->sync && ch->prefetch && * !s->dma->drqbmp[ch->sync], we should also activate and fetch * from source and then stall until signalled. */ - if ((!ch->sync) || (s->dma->drqbmp & (1 << ch->sync))) + if ((!ch->sync) || (s->dma->drqbmp & (1ULL << ch->sync))) { omap_dma_activate_channel(s, ch); + } } } @@ -1551,12 +1552,12 @@ static void omap_dma_request(void *opaque, int drq, int req) struct omap_dma_s *s = (struct omap_dma_s *) opaque; /* The request pins are level triggered in QEMU. */ if (req) { - if (~s->dma->drqbmp & (1 << drq)) { - s->dma->drqbmp |= 1 << drq; + if (~s->dma->drqbmp & (1ULL << drq)) { + s->dma->drqbmp |= 1ULL << drq; omap_dma_process_request(s, drq); } } else - s->dma->drqbmp &= ~(1 << drq); + s->dma->drqbmp &= ~(1ULL << drq); } /* XXX: this won't be needed once soc_dma knows about clocks. */ diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 97eddec920..1d863b5784 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1107,9 +1107,14 @@ static int ahci_dma_add_status(IDEDMA *dma, int status) static int ahci_dma_set_inactive(IDEDMA *dma) { + return 0; +} + +static int ahci_async_cmd_done(IDEDMA *dma) +{ AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - DPRINTF(ad->port_no, "dma done\n"); + DPRINTF(ad->port_no, "async cmd done\n"); /* update d2h status */ ahci_write_fis_d2h(ad, NULL); @@ -1144,6 +1149,7 @@ static const IDEDMAOps ahci_dma_ops = { .set_unit = ahci_dma_set_unit, .add_status = ahci_dma_add_status, .set_inactive = ahci_dma_set_inactive, + .async_cmd_done = ahci_async_cmd_done, .restart_cb = ahci_dma_restart_cb, .reset = ahci_dma_reset, }; diff --git a/hw/ide/core.c b/hw/ide/core.c index 03d1cfa7d2..a73af7252a 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -568,10 +568,18 @@ static void dma_buf_commit(IDEState *s) qemu_sglist_destroy(&s->sg); } +static void ide_async_cmd_done(IDEState *s) +{ + if (s->bus->dma->ops->async_cmd_done) { + s->bus->dma->ops->async_cmd_done(s->bus->dma); + } +} + void ide_set_inactive(IDEState *s) { s->bus->dma->aiocb = NULL; s->bus->dma->ops->set_inactive(s->bus->dma); + ide_async_cmd_done(s); } void ide_dma_error(IDEState *s) @@ -804,6 +812,7 @@ static void ide_flush_cb(void *opaque, int ret) bdrv_acct_done(s->bs, &s->acct); s->status = READY_STAT | SEEK_STAT; + ide_async_cmd_done(s); ide_set_irq(s->bus); } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 03f14896d6..048a052143 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -433,6 +433,7 @@ struct IDEDMAOps { DMAIntFunc *set_unit; DMAIntFunc *add_status; DMAFunc *set_inactive; + DMAFunc *async_cmd_done; DMARestartFunc *restart_cb; DMAFunc *reset; }; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e7449573fc..8835bd4339 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1031,6 +1031,9 @@ static Property virtio_ccw_blk_properties[] = { DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + DEFINE_PROP_BIT("x-data-plane", VirtIOBlkCcw, blk.data_plane, 0, false), +#endif DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index 4b1723418d..f5eb1e4012 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -175,7 +175,7 @@ static void pl181_send_command(pl181_state *s) if (rlen < 0) goto error; if (s->cmd & PL181_CMD_RESPONSE) { -#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \ +#define RWORD(n) (((uint32_t)response[n] << 24) | (response[n + 1] << 16) \ | (response[n + 2] << 8) | response[n + 3]) if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP))) goto error; diff --git a/include/block/block.h b/include/block/block.h index dd8eca1be1..b6b9014a9c 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -111,7 +111,8 @@ bool bdrv_io_limits_enabled(BlockDriverState *bs); void bdrv_init(void); void bdrv_init_with_whitelist(void); -BlockDriver *bdrv_find_protocol(const char *filename); +BlockDriver *bdrv_find_protocol(const char *filename, + bool allow_protocol_prefix); BlockDriver *bdrv_find_format(const char *format_name); BlockDriver *bdrv_find_whitelisted_format(const char *format_name, bool readonly); @@ -266,7 +267,7 @@ void bdrv_clear_incoming_migration_all(void); /* Ensure contents are flushed to disk. */ int bdrv_flush(BlockDriverState *bs); int coroutine_fn bdrv_co_flush(BlockDriverState *bs); -void bdrv_flush_all(void); +int bdrv_flush_all(void); void bdrv_close_all(void); void bdrv_drain_all(void); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index d85bdc0cac..3caeb66eb2 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -35,8 +35,8 @@ void vm_state_notify(int running, RunState state); #define VMRESET_REPORT true void vm_start(void); -void vm_stop(RunState state); -void vm_stop_force_state(RunState state); +int vm_stop(RunState state); +int vm_stop_force_state(RunState state); typedef enum WakeupReason { QEMU_WAKEUP_REASON_OTHER = 0, @@ -183,7 +183,6 @@ static void portio_write(void *opaque, hwaddr addr, uint64_t data, static const MemoryRegionOps portio_ops = { .read = portio_read, .write = portio_write, - .endianness = DEVICE_LITTLE_ENDIAN, .valid.unaligned = true, .impl.unaligned = true, }; diff --git a/migration.c b/migration.c index 184ae3ff5c..9f5a4230d1 100644 --- a/migration.c +++ b/migration.c @@ -536,15 +536,26 @@ static void *migration_thread(void *opaque) if (pending_size && pending_size >= max_size) { qemu_savevm_state_iterate(s->file); } else { + int ret; + DPRINTF("done iterating\n"); qemu_mutex_lock_iothread(); start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); old_vm_running = runstate_is_running(); - vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - qemu_file_set_rate_limit(s->file, INT_MAX); - qemu_savevm_state_complete(s->file); + + ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + if (ret >= 0) { + qemu_file_set_rate_limit(s->file, INT_MAX); + qemu_savevm_state_complete(s->file); + } qemu_mutex_unlock_iothread(); + + if (ret < 0) { + migrate_finish_set_state(s, MIG_STATE_ERROR); + break; + } + if (!qemu_file_get_error(s->file)) { migrate_finish_set_state(s, MIG_STATE_COMPLETED); break; diff --git a/qapi-schema.json b/qapi-schema.json index 35095ff0b3..7b9fef1bd1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1634,6 +1634,10 @@ # @format: #optional the format of the new destination, default is to # probe if @mode is 'existing', else the format of the source # +# @sync: what parts of the disk image should be copied to the destination +# (all the disk, only the sectors allocated in the topmost image, or +# only new I/O). +# # @mode: #optional whether and how QEMU should create a new image, default is # 'absolute-paths'. # @@ -1655,7 +1659,8 @@ ## { 'type': 'DriveBackup', 'data': { 'device': 'str', 'target': 'str', '*format': 'str', - '*mode': 'NewImageMode', '*speed': 'int', + 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', + '*speed': 'int', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } diff --git a/qemu-img.c b/qemu-img.c index f8c97d34d1..c55ca5c557 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -240,7 +240,7 @@ static int print_block_option_help(const char *filename, const char *fmt) return 1; } - proto_drv = bdrv_find_protocol(filename); + proto_drv = bdrv_find_protocol(filename, true); if (!proto_drv) { error_report("Unknown protocol '%s'", filename); return 1; @@ -1261,7 +1261,7 @@ static int img_convert(int argc, char **argv) goto out; } - proto_drv = bdrv_find_protocol(out_filename); + proto_drv = bdrv_find_protocol(out_filename, true); if (!proto_drv) { error_report("Unknown protocol '%s'", out_filename); ret = -1; diff --git a/qmp-commands.hx b/qmp-commands.hx index 362f0e1ef8..e075df423a 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -913,7 +913,7 @@ EQMP { .name = "drive-backup", - .args_type = "device:B,target:s,speed:i?,mode:s?,format:s?," + .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?," "on-source-error:s?,on-target-error:s?", .mhandler.cmd_new = qmp_marshal_input_drive_backup, }, @@ -939,6 +939,10 @@ Arguments: - "format": the format of the new destination, default is to probe if 'mode' is 'existing', else the format of the source (json-string, optional) +- "sync": what parts of the disk image should be copied to the destination; + possibilities include "full" for all the disk, "top" for only the sectors + allocated in the topmost image, or "none" to only replicate new I/O + (MirrorSyncMode). - "mode": whether and how QEMU should create a new image (NewImageMode, optional, default 'absolute-paths') - "speed": the maximum speed, in bytes per second (json-int, optional) diff --git a/stubs/vm-stop.c b/stubs/vm-stop.c index 45689354f6..f82c897dfe 100644 --- a/stubs/vm-stop.c +++ b/stubs/vm-stop.c @@ -1,7 +1,7 @@ #include "qemu-common.h" #include "sysemu/sysemu.h" -void vm_stop(RunState state) +int vm_stop(RunState state) { abort(); } diff --git a/target-arm/cpu.c b/target-arm/cpu.c index be26acc38d..9f1696f933 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -157,6 +157,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) CPUARMState *env = &cpu->env; /* Some features automatically imply others: */ + if (arm_feature(env, ARM_FEATURE_V8)) { + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_ARM_DIV); + set_feature(env, ARM_FEATURE_LPAE); + } if (arm_feature(env, ARM_FEATURE_V7)) { set_feature(env, ARM_FEATURE_VAPA); set_feature(env, ARM_FEATURE_THUMB2); @@ -744,7 +749,7 @@ static void pxa270c5_initfn(Object *obj) static void arm_any_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_VFP4); set_feature(&cpu->env, ARM_FEATURE_VFP_FP16); set_feature(&cpu->env, ARM_FEATURE_NEON); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1369604d65..c798b272a0 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -387,6 +387,7 @@ enum arm_features { ARM_FEATURE_MPIDR, /* has cp15 MPIDR */ ARM_FEATURE_PXN, /* has Privileged Execute Never bit */ ARM_FEATURE_LPAE, /* has Large Physical Address Extension */ + ARM_FEATURE_V8, }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index 5f639fdeb8..aeae024165 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -222,15 +222,23 @@ static gint cpreg_key_compare(gconstpointer a, gconstpointer b) return aidx - bidx; } +static void cpreg_make_keylist(gpointer key, gpointer value, gpointer udata) +{ + GList **plist = udata; + + *plist = g_list_prepend(*plist, key); +} + void init_cpreg_list(ARMCPU *cpu) { /* Initialise the cpreg_tuples[] array based on the cp_regs hash. * Note that we require cpreg_tuples[] to be sorted by key ID. */ - GList *keys; + GList *keys = NULL; int arraylen; - keys = g_hash_table_get_keys(cpu->cp_regs); + g_hash_table_foreach(cpu->cp_regs, cpreg_make_keylist, &keys); + keys = g_list_sort(keys, cpreg_key_compare); cpu->cpreg_array_len = 0; @@ -891,6 +899,8 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { static int vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + int maskshift = extract32(value, 0, 3); + if (arm_feature(env, ARM_FEATURE_LPAE)) { value &= ~((7 << 19) | (3 << 14) | (0xf << 3)); } else { @@ -902,8 +912,8 @@ static int vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, * and the c2_mask and c2_base_mask values are meaningless. */ env->cp15.c2_control = value; - env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> value); - env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> value); + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift); + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift); return 0; } @@ -1378,9 +1388,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_DUMMY_C15_REGS)) { define_arm_cp_regs(cpu, dummy_c15_cp_reginfo); } - if (arm_feature(env, ARM_FEATURE_MPIDR)) { - define_arm_cp_regs(cpu, mpidr_cp_reginfo); - } if (arm_feature(env, ARM_FEATURE_LPAE)) { define_arm_cp_regs(cpu, lpae_cp_reginfo); } @@ -1393,12 +1400,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) /* Note that the MIDR isn't a simple constant register because * of the TI925 behaviour where writes to another register can * cause the MIDR value to change. + * + * Unimplemented registers in the c15 0 0 0 space default to + * MIDR. Define MIDR first as this entire space, then CTR, TCMTR + * and friends override accordingly. */ { .name = "MIDR", - .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_R, .resetvalue = cpu->midr, .writefn = arm_cp_write_ignore, .raw_writefn = raw_write, - .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid) }, + .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid), + .type = ARM_CP_OVERRIDE }, { .name = "CTR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->ctr }, @@ -1435,21 +1447,20 @@ void register_cp_regs_for_features(ARMCPU *cpu) arm_feature(env, ARM_FEATURE_STRONGARM)) { ARMCPRegInfo *r; /* Register the blanket "writes ignored" value first to cover the - * whole space. Then define the specific ID registers, but update - * their access field to allow write access, so that they ignore - * writes rather than causing them to UNDEF. + * whole space. Then update the specific ID registers to allow write + * access, so that they ignore writes rather than causing them to + * UNDEF. */ define_one_arm_cp_reg(cpu, &crn0_wi_reginfo); for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) { r->access = PL1_RW; - define_one_arm_cp_reg(cpu, r); } - } else { - /* Just register the standard ID registers (read-only, meaning - * that writes will UNDEF). - */ - define_arm_cp_regs(cpu, id_cp_reginfo); } + define_arm_cp_regs(cpu, id_cp_reginfo); + } + + if (arm_feature(env, ARM_FEATURE_MPIDR)) { + define_arm_cp_regs(cpu, mpidr_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_AUXCR)) { @@ -1607,7 +1618,9 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2); - r2->opaque = opaque; + if (opaque) { + r2->opaque = opaque; + } /* Make sure reginfo passed to helpers for wildcarded regs * has the correct crm/opc1/opc2 for this reg, not CP_ANY: */ diff --git a/target-arm/translate.c b/target-arm/translate.c index 9310c586de..7b50c8c308 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -42,6 +42,7 @@ #define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K) #define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) #define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) +#define ENABLE_ARCH_8 arm_feature(env, ARM_FEATURE_V8) #define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0) @@ -3500,7 +3501,8 @@ static void gen_nop_hint(DisasContext *s, int val) break; case 2: /* wfe */ case 4: /* sev */ - /* TODO: Implement SEV and WFE. May help SMP performance. */ + case 5: /* sevl */ + /* TODO: Implement SEV, SEVL and WFE. May help SMP performance. */ default: /* nop */ break; } @@ -7273,14 +7275,72 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) rd = (insn >> 12) & 0xf; if (insn & (1 << 23)) { /* load/store exclusive */ + int op2 = (insn >> 8) & 3; op1 = (insn >> 21) & 0x3; - if (op1) - ARCH(6K); - else - ARCH(6); + + switch (op2) { + case 0: /* lda/stl */ + if (op1 == 1) { + goto illegal_op; + } + ARCH(8); + break; + case 1: /* reserved */ + goto illegal_op; + case 2: /* ldaex/stlex */ + ARCH(8); + break; + case 3: /* ldrex/strex */ + if (op1) { + ARCH(6K); + } else { + ARCH(6); + } + break; + } + addr = tcg_temp_local_new_i32(); load_reg_var(s, addr, rn); - if (insn & (1 << 20)) { + + /* Since the emulation does not have barriers, + the acquire/release semantics need no special + handling */ + if (op2 == 0) { + if (insn & (1 << 20)) { + tmp = tcg_temp_new_i32(); + switch (op1) { + case 0: /* lda */ + tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s)); + break; + case 2: /* ldab */ + tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s)); + break; + case 3: /* ldah */ + tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + store_reg(s, rd, tmp); + } else { + rm = insn & 0xf; + tmp = load_reg(s, rm); + switch (op1) { + case 0: /* stl */ + tcg_gen_qemu_st32(tmp, addr, IS_USER(s)); + break; + case 2: /* stlb */ + tcg_gen_qemu_st8(tmp, addr, IS_USER(s)); + break; + case 3: /* stlh */ + tcg_gen_qemu_st16(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_temp_free_i32(tmp); + } + } else if (insn & (1 << 20)) { switch (op1) { case 0: /* ldrex */ gen_load_exclusive(s, rd, 15, addr, 2); @@ -8125,7 +8185,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw gen_store_exclusive(s, rd, rs, 15, addr, 2); } tcg_temp_free_i32(addr); - } else if ((insn & (1 << 6)) == 0) { + } else if ((insn & (7 << 5)) == 0) { /* Table Branch. */ if (rn == 15) { addr = tcg_temp_new_i32(); @@ -8151,15 +8211,66 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw tcg_gen_addi_i32(tmp, tmp, s->pc); store_reg(s, 15, tmp); } else { - /* Load/store exclusive byte/halfword/doubleword. */ - ARCH(7); + int op2 = (insn >> 6) & 0x3; op = (insn >> 4) & 0x3; - if (op == 2) { + switch (op2) { + case 0: goto illegal_op; + case 1: + /* Load/store exclusive byte/halfword/doubleword */ + if (op == 2) { + goto illegal_op; + } + ARCH(7); + break; + case 2: + /* Load-acquire/store-release */ + if (op == 3) { + goto illegal_op; + } + /* Fall through */ + case 3: + /* Load-acquire/store-release exclusive */ + ARCH(8); + break; } addr = tcg_temp_local_new_i32(); load_reg_var(s, addr, rn); - if (insn & (1 << 20)) { + if (!(op2 & 1)) { + if (insn & (1 << 20)) { + tmp = tcg_temp_new_i32(); + switch (op) { + case 0: /* ldab */ + tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s)); + break; + case 1: /* ldah */ + tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s)); + break; + case 2: /* lda */ + tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + store_reg(s, rs, tmp); + } else { + tmp = load_reg(s, rs); + switch (op) { + case 0: /* stlb */ + tcg_gen_qemu_st8(tmp, addr, IS_USER(s)); + break; + case 1: /* stlh */ + tcg_gen_qemu_st16(tmp, addr, IS_USER(s)); + break; + case 2: /* stl */ + tcg_gen_qemu_st32(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_temp_free_i32(tmp); + } + } else if (insn & (1 << 20)) { gen_load_exclusive(s, rs, rd, addr, op); } else { gen_store_exclusive(s, rm, rs, rd, addr, op); diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 8039e23ab3..1cf8bf79b6 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -149,6 +149,18 @@ echo run_qemu -drive file=$TEST_IMG,file.driver=file run_qemu -drive file=$TEST_IMG,file.driver=qcow2 +echo +echo === Parsing protocol from file name === +echo + +# Protocol strings are supposed to be parsed from traditional option strings, +# but not when using driver-specific options. We can distinguish them by the +# error message for non-existing files. + +run_qemu -hda foo:bar +run_qemu -drive file=foo:bar +run_qemu -drive file.filename=foo:bar + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 3d1ac7b7da..95ff245f40 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -23,10 +23,12 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: could not === Enable and disable lazy refcounting on the command line, plus some invalid values === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=on -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=off -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts= QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=: Parameter 'lazy_refcounts' expects 'on' or 'off' @@ -49,112 +51,152 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=on: Lazy ref QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=on: could not open disk image TEST_DIR/t.qcow2: Invalid argument Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy_refcounts=off -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
=== No medium === Testing: -drive if=floppy -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=ide,media=cdrom -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=scsi,media=cdrom -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=ide -QEMU_PROG: Device needs media, but drive is empty +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: Device needs media, but drive is empty +QEMU_PROG: Device initialization failed. QEMU_PROG: Initialization of device ide-hd failed Testing: -drive if=virtio -QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty +QEMU_PROG: -drive if=virtio: Device initialization failed. +QEMU_PROG: -drive if=virtio: Device initialization failed. QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized Testing: -drive if=scsi -QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty +QEMU_PROG: -drive if=scsi: Device initialization failed. +QEMU_PROG: Device initialization failed. QEMU_PROG: Initialization of device lsi53c895a failed Testing: -drive if=none,id=disk -device ide-cd,drive=disk -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive if=none,id=disk -device ide-drive,drive=disk -QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized Testing: -drive if=none,id=disk -device ide-hd,drive=disk -QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk -QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device scsi-disk,drive=disk: Device initialization failed. QEMU_PROG: -device scsi-disk,drive=disk: Device 'scsi-disk' could not be initialized Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk -QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device scsi-hd,drive=disk: Device initialization failed. QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized === Read-only === Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on: readonly not supported by this bus type Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk -QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive +QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk -QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive +QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
=== Cache modes === Testing: -drive media=cdrom,cache=none -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=directsync -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=writeback -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=writethrough -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=unsafe -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive media=cdrom,cache=invalid_value QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option @@ -163,10 +205,25 @@ QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option === Specifying the protocol layer === Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
+QEMU 1.5.50 monitor - type 'help' for more information
+(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2 QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: Can't use 'qcow2' as a block driver for the protocol level QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Invalid argument + +=== Parsing protocol from file name === + +Testing: -hda foo:bar +QEMU_PROG: -hda foo:bar: Unknown protocol +QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: No such file or directory + +Testing: -drive file=foo:bar +QEMU_PROG: -drive file=foo:bar: Unknown protocol +QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: No such file or directory + +Testing: -drive file.filename=foo:bar +QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: No such file or directory + *** done diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index 887c959a3d..c66f8dbd7d 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -54,7 +54,7 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() result = self.vm.qmp('drive-backup', device='drive0', - target=target_img) + target=target_img, sync='full') self.assert_qmp(result, 'return', {}) event = self.cancel_and_wait() @@ -64,7 +64,7 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() result = self.vm.qmp('drive-backup', device='drive0', - target=target_img) + target=target_img, sync='full') self.assert_qmp(result, 'return', {}) result = self.vm.qmp('block-job-pause', device='drive0') @@ -89,17 +89,17 @@ class TestSingleDrive(iotests.QMPTestCase): def test_medium_not_found(self): result = self.vm.qmp('drive-backup', device='ide1-cd0', - target=target_img) + target=target_img, sync='full') self.assert_qmp(result, 'error/class', 'GenericError') def test_image_not_found(self): result = self.vm.qmp('drive-backup', device='drive0', - mode='existing', target=target_img) + target=target_img, sync='full', mode='existing') self.assert_qmp(result, 'error/class', 'GenericError') def test_device_not_found(self): result = self.vm.qmp('drive-backup', device='nonexistent', - target=target_img) + target=target_img, sync='full') self.assert_qmp(result, 'error/class', 'DeviceNotFound') class TestSetSpeed(iotests.QMPTestCase): @@ -119,7 +119,7 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() result = self.vm.qmp('drive-backup', device='drive0', - target=target_img) + target=target_img, sync='full') self.assert_qmp(result, 'return', {}) # Default speed is 0 @@ -140,7 +140,7 @@ class TestSetSpeed(iotests.QMPTestCase): # Check setting speed in drive-backup works result = self.vm.qmp('drive-backup', device='drive0', - target=target_img, speed=4*1024*1024) + target=target_img, sync='full', speed=4*1024*1024) self.assert_qmp(result, 'return', {}) result = self.vm.qmp('query-block-jobs') @@ -154,13 +154,13 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() result = self.vm.qmp('drive-backup', device='drive0', - target=target_img, speed=-1) + target=target_img, sync='full', speed=-1) self.assert_qmp(result, 'error/class', 'GenericError') self.assert_no_active_block_jobs() result = self.vm.qmp('drive-backup', device='drive0', - target=target_img) + target=target_img, sync='full') self.assert_qmp(result, 'return', {}) result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) @@ -196,7 +196,8 @@ class TestSingleTransaction(iotests.QMPTestCase): result = self.vm.qmp('transaction', actions=[{ 'type': 'drive-backup', 'data': { 'device': 'drive0', - 'target': target_img }, + 'target': target_img, + 'sync': 'full' }, } ]) self.assert_qmp(result, 'return', {}) @@ -210,7 +211,8 @@ class TestSingleTransaction(iotests.QMPTestCase): result = self.vm.qmp('transaction', actions=[{ 'type': 'drive-backup', 'data': { 'device': 'drive0', - 'target': target_img }, + 'target': target_img, + 'sync': 'full' }, } ]) self.assert_qmp(result, 'return', {}) @@ -239,7 +241,8 @@ class TestSingleTransaction(iotests.QMPTestCase): result = self.vm.qmp('transaction', actions=[{ 'type': 'drive-backup', 'data': { 'device': 'ide1-cd0', - 'target': target_img }, + 'target': target_img, + 'sync': 'full' }, } ]) self.assert_qmp(result, 'error/class', 'GenericError') @@ -249,7 +252,8 @@ class TestSingleTransaction(iotests.QMPTestCase): 'type': 'drive-backup', 'data': { 'device': 'drive0', 'mode': 'existing', - 'target': target_img }, + 'target': target_img, + 'sync': 'full' }, } ]) self.assert_qmp(result, 'error/class', 'GenericError') @@ -259,7 +263,8 @@ class TestSingleTransaction(iotests.QMPTestCase): 'type': 'drive-backup', 'data': { 'device': 'nonexistent', 'mode': 'existing', - 'target': target_img }, + 'target': target_img, + 'sync': 'full' }, } ]) self.assert_qmp(result, 'error/class', 'DeviceNotFound') @@ -269,7 +274,8 @@ class TestSingleTransaction(iotests.QMPTestCase): 'type': 'drive-backup', 'data': { 'device': 'nonexistent', 'mode': 'existing', - 'target': target_img }, + 'target': target_img, + 'sync': 'full' }, }, { 'type': 'Abort', 'data': {}, diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index dcf6391ea2..9dbcae8d8c 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -155,7 +155,7 @@ _filter_qemu_io() # replace occurrences of QEMU_PROG with "qemu" _filter_qemu() { - sed -e "s#^$(basename $QEMU_PROG):#QEMU_PROG:#" + sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" } # make sure this script returns success |