diff options
34 files changed, 567 insertions, 135 deletions
@@ -1119,20 +1119,19 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, } else { error_setg_errno(errp, -ret, "Could not open image"); } - goto free_and_fail; + goto open_failed; } ret = refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { error_setg_errno(errp, -ret, "Could not refresh total sector count"); - goto free_and_fail; + return ret; } bdrv_refresh_limits(bs, &local_err); if (local_err) { error_propagate(errp, local_err); - ret = -EINVAL; - goto free_and_fail; + return -EINVAL; } assert(bdrv_opt_mem_align(bs) != 0); @@ -1140,12 +1139,14 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, assert(is_power_of_2(bs->bl.request_alignment)); return 0; - -free_and_fail: - /* FIXME Close bs first if already opened*/ +open_failed: + bs->drv = NULL; + if (bs->file != NULL) { + bdrv_unref_child(bs, bs->file); + bs->file = NULL; + } g_free(bs->opaque); bs->opaque = NULL; - bs->drv = NULL; return ret; } @@ -1166,7 +1167,9 @@ BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, ret = bdrv_open_driver(bs, drv, node_name, bs->options, flags, errp); if (ret < 0) { QDECREF(bs->explicit_options); + bs->explicit_options = NULL; QDECREF(bs->options); + bs->options = NULL; bdrv_unref(bs); return NULL; } @@ -2600,14 +2603,12 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, fail: blk_unref(file); - if (bs->file != NULL) { - bdrv_unref_child(bs, bs->file); - } QDECREF(snapshot_options); QDECREF(bs->explicit_options); QDECREF(bs->options); QDECREF(options); bs->options = NULL; + bs->explicit_options = NULL; bdrv_unref(bs); error_propagate(errp, local_err); return NULL; @@ -3087,6 +3088,7 @@ static void bdrv_close(BlockDriverState *bs) QDECREF(bs->options); QDECREF(bs->explicit_options); bs->options = NULL; + bs->explicit_options = NULL; QDECREF(bs->full_open_options); bs->full_open_options = NULL; } diff --git a/block/qapi.c b/block/qapi.c index d2b18ee..5f1a71f 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -145,8 +145,9 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, /* Skip automatically inserted nodes that the user isn't aware of for * query-block (blk != NULL), but not for query-named-block-nodes */ - while (blk && bs0 && bs0->drv && bs0->implicit) { + while (blk && bs0->drv && bs0->implicit) { bs0 = backing_bs(bs0); + assert(bs0); } } diff --git a/chardev/char-fd.c b/chardev/char-fd.c index 1584a3d..6a62a54 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -141,7 +141,6 @@ void qemu_chr_open_fd(Chardev *chr, qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name); g_free(name); qemu_set_nonblock(fd_out); - s->chr = chr; } static void char_fd_class_init(ObjectClass *oc, void *data) diff --git a/chardev/char.c b/chardev/char.c index c34b44a..5d283b9 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -620,7 +620,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp) error_report("Available chardev backend types: %s", str->str); g_string_free(str, true); - exit(0); + return NULL; } if (id == NULL) { @@ -2203,7 +2203,7 @@ void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr) * Called within RCU critical section. */ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr, - hwaddr *size) + hwaddr *size, bool lock) { RAMBlock *block = ram_block; if (*size == 0) { @@ -2222,10 +2222,10 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr, * In that case just map the requested area. */ if (block->offset == 0) { - return xen_map_cache(addr, *size, 1, true); + return xen_map_cache(addr, *size, lock, lock); } - block->host = xen_map_cache(block->offset, block->max_length, 1, true); + block->host = xen_map_cache(block->offset, block->max_length, 1, lock); } return ramblock_ptr(block, addr); @@ -2947,7 +2947,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr, } } else { /* RAM case */ - ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l); + ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false); memcpy(ptr, buf, l); invalidate_and_set_dirty(mr, addr1, l); } @@ -3038,7 +3038,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr, } } else { /* RAM case */ - ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l); + ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false); memcpy(buf, ptr, l); } @@ -3349,7 +3349,7 @@ void *address_space_map(AddressSpace *as, memory_region_ref(mr); *plen = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write); - ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen); + ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true); rcu_read_unlock(); return ptr; diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c index f67b3b8..3cb60b9 100644 --- a/hw/bt/sdp.c +++ b/hw/bt/sdp.c @@ -580,7 +580,7 @@ static void bt_l2cap_sdp_close_ch(void *opaque) int i; for (i = 0; i < sdp->services; i ++) { - g_free(sdp->service_list[i].attribute_list->pair); + g_free(sdp->service_list[i].attribute_list[0].pair); g_free(sdp->service_list[i].attribute_list); g_free(sdp->service_list[i].uuid); } @@ -720,6 +720,8 @@ static void sdp_service_record_build(struct sdp_service_record_s *record, len += sdp_attr_max_size(&def->attributes[record->attributes ++].data, &record->uuids); } + + assert(len > 0); record->uuids = pow2ceil(record->uuids); record->attribute_list = g_malloc0(record->attributes * sizeof(*record->attribute_list)); @@ -730,12 +732,14 @@ static void sdp_service_record_build(struct sdp_service_record_s *record, record->attributes = 0; uuid = record->uuid; while (def->attributes[record->attributes].data.type) { + int attribute_id = def->attributes[record->attributes].id; record->attribute_list[record->attributes].pair = data; + record->attribute_list[record->attributes].attribute_id = attribute_id; len = 0; data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2; - data[len ++] = def->attributes[record->attributes].id >> 8; - data[len ++] = def->attributes[record->attributes].id & 0xff; + data[len ++] = attribute_id >> 8; + data[len ++] = attribute_id & 0xff; len += sdp_attr_write(data + len, &def->attributes[record->attributes].data, &uuid); @@ -749,10 +753,15 @@ static void sdp_service_record_build(struct sdp_service_record_s *record, data += len; } - /* Sort the attribute list by the AttributeID */ + /* Sort the attribute list by the AttributeID. The first must be + * SDP_ATTR_RECORD_HANDLE so that bt_l2cap_sdp_close_ch can free + * the buffer. + */ qsort(record->attribute_list, record->attributes, sizeof(*record->attribute_list), (void *) sdp_attributeid_compare); + assert(record->attribute_list[0].pair == data); + /* Sort the searchable UUIDs list for bisection */ qsort(record->uuid, record->uuids, sizeof(*record->uuid), diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 4a106da..77d8b6f 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1103,8 +1103,8 @@ static const struct SCSIBusInfo pvscsi_scsi_info = { .cancel = pvscsi_request_cancelled, }; -static int -pvscsi_init(PCIDevice *pci_dev) +static void +pvscsi_realizefn(PCIDevice *pci_dev, Error **errp) { PVSCSIState *s = PVSCSI(pci_dev); @@ -1138,18 +1138,12 @@ pvscsi_init(PCIDevice *pci_dev) } s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s); - if (!s->completion_worker) { - pvscsi_cleanup_msi(s); - return -ENOMEM; - } scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev), &pvscsi_scsi_info, NULL); /* override default SCSI bus hotplug-handler, with pvscsi's one */ qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(s), &error_abort); pvscsi_reset_state(s); - - return 0; } static void @@ -1282,7 +1276,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data) PVSCSIClass *pvs_k = PVSCSI_DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - k->init = pvscsi_init; + k->realize = pvscsi_realizefn; k->exit = pvscsi_uninit; k->vendor_id = PCI_VENDOR_ID_VMWARE; k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 1b8d3d7..82843ed 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -291,26 +291,15 @@ static void check_update_timer(RTCState *s) /* From the data sheet: "Holding the dividers in reset prevents * interrupts from operating, while setting the SET bit allows" - * them to occur. However, it will prevent an alarm interrupt - * from occurring, because the time of day is not updated. + * them to occur. */ if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) { - timer_del(s->update_timer); - return; - } - if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && - (s->cmos_data[RTC_REG_B] & REG_B_SET)) { - timer_del(s->update_timer); - return; - } - if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && - (s->cmos_data[RTC_REG_C] & REG_C_AF)) { + assert((s->cmos_data[RTC_REG_A] & REG_A_UIP) == 0); timer_del(s->update_timer); return; } guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND; - /* if UF is clear, reprogram to next second */ next_update_time = qemu_clock_get_ns(rtc_clock) + NANOSECONDS_PER_SECOND - guest_nsec; @@ -321,7 +310,21 @@ static void check_update_timer(RTCState *s) s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NANOSECONDS_PER_SECOND; - if (s->cmos_data[RTC_REG_C] & REG_C_UF) { + /* If update_in_progress latched the UIP bit, we must keep the timer + * programmed to the next second, so that UIP is cleared. Otherwise, + * if UF is already set, we might be able to optimize. + */ + if (!(s->cmos_data[RTC_REG_A] & REG_A_UIP) && + (s->cmos_data[RTC_REG_C] & REG_C_UF)) { + /* If AF cannot change (i.e. either it is set already, or + * SET=1 and then the time is not updated), nothing to do. + */ + if ((s->cmos_data[RTC_REG_B] & REG_B_SET) || + (s->cmos_data[RTC_REG_C] & REG_C_AF)) { + timer_del(s->update_timer); + return; + } + /* UF is set, but AF is clear. Program the timer to target * the alarm time. */ next_update_time = s->next_alarm_time; @@ -727,12 +730,10 @@ static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_A: + ret = s->cmos_data[s->cmos_index]; if (update_in_progress(s)) { - s->cmos_data[s->cmos_index] |= REG_A_UIP; - } else { - s->cmos_data[s->cmos_index] &= ~REG_A_UIP; + ret |= REG_A_UIP; } - ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; diff --git a/include/chardev/char-fd.h b/include/chardev/char-fd.h index 55ae5b4..e7c2b17 100644 --- a/include/chardev/char-fd.h +++ b/include/chardev/char-fd.h @@ -29,7 +29,7 @@ typedef struct FDChardev { Chardev parent; - Chardev *chr; + QIOChannel *ioc_in, *ioc_out; int max_size; } FDChardev; diff --git a/include/chardev/char.h b/include/chardev/char.h index 1604ea9..66dde46 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -65,7 +65,9 @@ struct Chardev { * * @opts see qemu-config.c for a list of valid options * - * Returns: a new character backend + * Returns: on success: a new character backend + * otherwise: NULL; @errp specifies the error + * or left untouched in case of help option */ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp); diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index c04f4f6..d017639 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -377,19 +377,20 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, uint64_t *real_dirty_pages) { ram_addr_t addr; - unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); + unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS); uint64_t num_dirty = 0; unsigned long *dest = rb->bmap; /* start address is aligned at the start of a word? */ - if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) { + if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) == + (start + rb->offset)) { int k; int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS); unsigned long * const *src; - unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS); unsigned long idx = (word * BITS_PER_LONG) / DIRTY_MEMORY_BLOCK_SIZE; unsigned long offset = BIT_WORD((word * BITS_PER_LONG) % DIRTY_MEMORY_BLOCK_SIZE); + unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); rcu_read_lock(); @@ -2357,8 +2357,15 @@ void memory_global_dirty_log_sync(void) } } +static VMChangeStateEntry *vmstate_change; + void memory_global_dirty_log_start(void) { + if (vmstate_change) { + qemu_del_vm_change_state_handler(vmstate_change); + vmstate_change = NULL; + } + global_dirty_log = true; MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward); @@ -2369,7 +2376,7 @@ void memory_global_dirty_log_start(void) memory_region_transaction_commit(); } -void memory_global_dirty_log_stop(void) +static void memory_global_dirty_log_do_stop(void) { global_dirty_log = false; @@ -2381,6 +2388,33 @@ void memory_global_dirty_log_stop(void) MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse); } +static void memory_vm_change_state_handler(void *opaque, int running, + RunState state) +{ + if (running) { + memory_global_dirty_log_do_stop(); + + if (vmstate_change) { + qemu_del_vm_change_state_handler(vmstate_change); + vmstate_change = NULL; + } + } +} + +void memory_global_dirty_log_stop(void) +{ + if (!runstate_is_running()) { + if (vmstate_change) { + return; + } + vmstate_change = qemu_add_vm_change_state_handler( + memory_vm_change_state_handler, NULL); + return; + } + + memory_global_dirty_log_do_stop(); +} + static void listener_add_address_space(MemoryListener *listener, AddressSpace *as) { diff --git a/qemu-doc.texi b/qemu-doc.texi index 48af515..aeb7bc5 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -38,6 +38,7 @@ * QEMU Guest Agent:: * QEMU User space emulator:: * Implementation notes:: +* Deprecated features:: * License:: * Index:: @end menu @@ -3128,6 +3129,180 @@ Run the emulation in single step mode. @include qemu-tech.texi +@node Deprecated features +@appendix Deprecated features + +In general features are intended to be supported indefinitely once +introduced into QEMU. In the event that a feature needs to be removed, +it will be listed in this appendix. The feature will remain functional +for 2 releases prior to actual removal. Deprecated features may also +generate warnings on the console when QEMU starts up, or if activated +via a monitor command, however, this is not a mandatory requirement. + +Prior to the 2.10.0 release there was no official policy on how +long features would be deprecated prior to their removal, nor +any documented list of which features were deprecated. Thus +any features deprecated prior to 2.10.0 will be treated as if +they were first deprecated in the 2.10.0 release. + +What follows is a list of all features currently marked as +deprecated. + +@section System emulator command line arguments + +@subsection -drive boot=on|off (since 1.3.0) + +The ``boot=on|off'' option to the ``-drive'' argument is +ignored. Applications should use the ``bootindex=N'' parameter +to set an absolute ordering between devices instead. + +@subsection -tdf (since 1.3.0) + +The ``-tdf'' argument is ignored. The behaviour implemented +by this argument is now the default when using the KVM PIT, +but can be requested explicitly using +``-global kvm-pit.lost_tick_policy=slew''. + +@subsection -no-kvm-pit-reinjection (since 1.3.0) + +The ``-no-kvm-pit-reinjection'' argument is now a +synonym for setting ``-global kvm-pit.lost_tick_policy=discard''. + +@subsection -no-kvm-irqchip (since 1.3.0) + +The ``-no-kvm-irqchip'' argument is now a synonym for +setting ``-machine kernel_irqchip=off''. + +@subsection -no-kvm-pit (since 1.3.0) + +The ``-no-kvm-pit'' argument is ignored. It is no longer +possible to disable the KVM PIT directly. + +@subsection -no-kvm (since 1.3.0) + +The ``-no-kvm'' argument is now a synonym for setting +``-machine accel=tcg''. + +@subsection -mon default=on (since 2.4.0) + +The ``default'' option to the ``-mon'' argument is +now ignored. When multiple monitors were enabled, it +indicated which monitor would receive log messages +from the various subsystems. This feature is no longer +required as messages are now only sent to the monitor +in response to explicitly monitor commands. + +@subsection -vnc tls (since 2.5.0) + +The ``-vnc tls'' argument is now a synonym for setting +``-object tls-creds-anon,id=tls0'' combined with +``-vnc tls-creds=tls0' + +@subsection -vnc x509 (since 2.5.0) + +The ``-vnc x509=/path/to/certs'' argument is now a +synonym for setting +``-object tls-creds-x509,dir=/path/to/certs,id=tls0,verify-peer=no'' +combined with ``-vnc tls-creds=tls0' + +@subsection -vnc x509verify (since 2.5.0) + +The ``-vnc x509verify=/path/to/certs'' argument is now a +synonym for setting +``-object tls-creds-x509,dir=/path/to/certs,id=tls0,verify-peer=yes'' +combined with ``-vnc tls-creds=tls0' + +@subsection -tftp (since 2.6.0) + +The ``-tftp /some/dir'' argument is now a synonym for setting +the ``-netdev user,tftp=/some/dir' argument. The new syntax +allows different settings to be provided per NIC. + +@subsection -bootp (since 2.6.0) + +The ``-bootp /some/file'' argument is now a synonym for setting +the ``-netdev user,bootp=/some/file' argument. The new syntax +allows different settings to be provided per NIC. + +@subsection -redir (since 2.6.0) + +The ``-redir ARGS'' argument is now a synonym for setting +the ``-netdev user,hostfwd=ARGS'' argument instead. The new +syntax allows different settings to be provided per NIC. + +@subsection -smb (since 2.6.0) + +The ``-smb /some/dir'' argument is now a synonym for setting +the ``-netdev user,smb=/some/dir'' argument instead. The new +syntax allows different settings to be provided per NIC. + +@subsection -net channel (since 2.6.0) + +The ``--net channel,ARGS'' argument is now a synonym for setting +the ``-netdev user,guestfwd=ARGS'' argument instead. + +@subsection -net vlan (since 2.9.0) + +The ``-net van=NN'' argument is partially replaced with the +new ``-netdev'' argument. The remaining use cases will no +longer be directly supported in QEMU. + +@subsection -drive if=scsi (since 2.9.0) + +The ``-drive if=scsi'' argument is replaced by the the +``-device BUS-TYPE'' argument combined with ``-drive if=none''. + +@subsection -net dump (since 2.10.0) + +The ``--net dump'' argument is now replaced with the +``-object filter-dump'' argument which works in combination +with the modern ``-netdev`` backends instead. + +@subsection -hdachs (since 2.10.0) + +The ``-hdachs'' argument is now a synonym for setting +the ``cyls'', ``heads'', ``secs'', and ``trans'' properties +on the ``ide-hd'' device using the ``-device'' argument. +The new syntax allows different settings to be provided +per disk. + +@subsection -usbdevice (since 2.10.0) + +The ``-usbdevice DEV'' argument is now a synonym for setting +the ``-device usb-DEV'' argument instead. The deprecated syntax +would automatically enable USB support on the machine type. +If using the new syntax, USB support must be explicitly +enabled via the ``-machine usb=on'' argument. + +@section qemu-img command line arguments + +@subsection convert -s (since 2.0.0) + +The ``convert -s snapshot_id_or_name'' argument is obsoleted +by the ``convert -l snapshot_param'' argument instead. + +@section System emulator human monitor commands + +@subsection usb_add (since 2.10.0) + +The ``usb_add'' command is replaced by the ``device_add'' command. + +@subsection usb_del (since 2.10.0) + +The ``usb_del'' command is replaced by the ``device_del'' command. + +@section System emulator devices + +@subsection ivshmem (since 2.6.0) + +The ``ivshmem'' device type is replaced by either the ``ivshmem-plain'' +or ``ivshmem-doorbell`` device types. + +@subsection spapr-pci-vfio-host-bridge (since 2.6.0) + +The ``spapr-pci-vfio-host-bridge'' device type is replaced by +the ``spapr-pci-host-bridge'' device type. + @node License @appendix License diff --git a/qemu-options.hx b/qemu-options.hx index 746b5fa..9f6e2ad 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -49,7 +49,20 @@ STEXI @item -machine [type=]@var{name}[,prop=@var{value}[,...]] @findex -machine Select the emulated machine by @var{name}. Use @code{-machine help} to list -available machines. Supported machine properties are: +available machines. + +For architectures which aim to support live migration compatibility +across releases, each release will introduce a new versioned machine +type. For example, the 2.8.0 release introduced machine types +``pc-i440fx-2.8'' and ``pc-q35-2.8'' for the x86_64/i686 architectures. + +To allow live migration of guests from QEMU version 2.8.0, to QEMU +version 2.9.0, the 2.9.0 version must support the ``pc-i440fx-2.8'' +and ``pc-q35-2.8'' machines too. To allow users live migrating VMs +to skip multiple intermediate releases when upgrading, new releases +of QEMU will support machine types from many previous versions. + +Supported machine properties are: @table @option @item accel=@var{accels1}[:@var{accels2}[:...]] This is used to enable an accelerator. Depending on the target architecture, diff --git a/target/i386/kvm.c b/target/i386/kvm.c index a6613e1..6db7783 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -2444,8 +2444,10 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) } if (level >= KVM_PUT_RESET_STATE) { - events.flags |= - KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR; + events.flags |= KVM_VCPUEVENT_VALID_NMI_PENDING; + if (env->mp_state == KVM_MP_STATE_SIPI_RECEIVED) { + events.flags |= KVM_VCPUEVENT_VALID_SIPI_VECTOR; + } } return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events); @@ -2633,6 +2635,10 @@ int kvm_arch_put_registers(CPUState *cpu, int level) if (ret < 0) { return ret; } + ret = kvm_put_vcpu_events(x86_cpu, level); + if (ret < 0) { + return ret; + } if (level >= KVM_PUT_RESET_STATE) { ret = kvm_put_mp_state(x86_cpu); if (ret < 0) { @@ -2644,11 +2650,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level) if (ret < 0) { return ret; } - - ret = kvm_put_vcpu_events(x86_cpu, level); - if (ret < 0) { - return ret; - } ret = kvm_put_debugregs(x86_cpu); if (ret < 0) { return ret; @@ -2668,35 +2669,39 @@ int kvm_arch_get_registers(CPUState *cs) assert(cpu_is_stopped(cs) || qemu_cpu_is_self(cs)); - ret = kvm_getput_regs(cpu, 0); + ret = kvm_get_vcpu_events(cpu); if (ret < 0) { goto out; } - ret = kvm_get_xsave(cpu); + /* + * KVM_GET_MPSTATE can modify CS and RIP, call it before + * KVM_GET_REGS and KVM_GET_SREGS. + */ + ret = kvm_get_mp_state(cpu); if (ret < 0) { goto out; } - ret = kvm_get_xcrs(cpu); + ret = kvm_getput_regs(cpu, 0); if (ret < 0) { goto out; } - ret = kvm_get_sregs(cpu); + ret = kvm_get_xsave(cpu); if (ret < 0) { goto out; } - ret = kvm_get_msrs(cpu); + ret = kvm_get_xcrs(cpu); if (ret < 0) { goto out; } - ret = kvm_get_mp_state(cpu); + ret = kvm_get_sregs(cpu); if (ret < 0) { goto out; } - ret = kvm_get_apic(cpu); + ret = kvm_get_msrs(cpu); if (ret < 0) { goto out; } - ret = kvm_get_vcpu_events(cpu); + ret = kvm_get_apic(cpu); if (ret < 0) { goto out; } diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 4cda540..a860a31 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -418,6 +418,7 @@ new_state = "1" def tearDown(self): self.vm.shutdown() os.remove(test_img) + os.remove(target_img) os.remove(backing_img) os.remove(self.blkdebug_file) @@ -568,6 +569,7 @@ new_state = "1" def tearDown(self): self.vm.shutdown() os.remove(test_img) + os.remove(target_img) os.remove(backing_img) os.remove(self.blkdebug_file) @@ -821,7 +823,7 @@ class TestRepairQuorum(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - for i in self.IMAGES + [ quorum_repair_img ]: + for i in self.IMAGES + [ quorum_repair_img, quorum_snapshot_file ]: # Do a try/except because the test may have deleted some images try: os.remove(i) diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 6655aaf..a1c34ee 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -29,7 +29,8 @@ status=1 # failure is the default! _cleanup() { - _cleanup_test_img + _cleanup_test_img + rm -f "$TEST_IMG.qcow2" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -72,15 +73,18 @@ echo echo "=== Testing monolithicFlat creation and opening ===" IMGOPTS="subformat=monolithicFlat" _make_test_img 2G _img_info +_cleanup_test_img echo echo "=== Testing monolithicFlat with zeroed_grain ===" IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G +_cleanup_test_img echo echo "=== Testing big twoGbMaxExtentFlat ===" IMGOPTS="subformat=twoGbMaxExtentFlat" _make_test_img 1000G $QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/' +_cleanup_test_img echo echo "=== Testing malformed VMFS extent description line ===" @@ -114,6 +118,7 @@ echo "=== Testing monolithicFlat with internally generated JSON file name ===" IMGOPTS="subformat=monolithicFlat" _make_test_img 64M $QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" 2>&1 \ | _filter_testdir | _filter_imgfmt +_cleanup_test_img echo echo "=== Testing version 3 ===" @@ -123,6 +128,7 @@ for i in {0..99}; do $QEMU_IO -r -c "read -P $(( i % 10 + 0x30 )) $(( i * 64 * 1024 * 10 + i * 512 )) 512" $TEST_IMG \ | _filter_qemu_io done +_cleanup_test_img echo echo "=== Testing 4TB monolithicFlat creation and IO ===" @@ -130,6 +136,7 @@ IMGOPTS="subformat=monolithicFlat" _make_test_img 4T _img_info $QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io +_cleanup_test_img echo echo "=== Testing qemu-img map on extents ===" @@ -139,12 +146,14 @@ for fmt in monolithicSparse twoGbMaxExtentSparse; do $QEMU_IO -c "write 2147483136 1k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "write 5G 1k" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map "$TEST_IMG" | _filter_testdir + _cleanup_test_img done echo echo "=== Testing afl image with a very large capacity ===" _use_sample_img afl9.vmdk.bz2 _img_info +_cleanup_test_img # success, all done echo "*** done" diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 6154509..f6dce79 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -2259,8 +2259,8 @@ read 512/512 bytes at offset 64931328 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing 4TB monolithicFlat creation and IO === -Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat -image: TEST_DIR/iotest-version3.IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat +image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 4.0T (4398046511104 bytes) wrote 512/512 bytes at offset 966367641600 @@ -2333,7 +2333,7 @@ read 1024/1024 bytes at offset 966367641600 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing qemu-img map on extents === -Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse wrote 1024/1024 bytes at offset 65024 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 2147483136 @@ -2341,10 +2341,10 @@ wrote 1024/1024 bytes at offset 2147483136 wrote 1024/1024 bytes at offset 5368709120 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Offset Length Mapped to File -0 0x20000 0x3f0000 TEST_DIR/iotest-version3.vmdk -0x7fff0000 0x20000 0x410000 TEST_DIR/iotest-version3.vmdk -0x140000000 0x10000 0x430000 TEST_DIR/iotest-version3.vmdk -Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse +0 0x20000 0x3f0000 TEST_DIR/t.vmdk +0x7fff0000 0x20000 0x410000 TEST_DIR/t.vmdk +0x140000000 0x10000 0x430000 TEST_DIR/t.vmdk +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse wrote 1024/1024 bytes at offset 65024 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 2147483136 @@ -2352,10 +2352,10 @@ wrote 1024/1024 bytes at offset 2147483136 wrote 1024/1024 bytes at offset 5368709120 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Offset Length Mapped to File -0 0x20000 0x50000 TEST_DIR/iotest-version3-s001.vmdk -0x7fff0000 0x10000 0x70000 TEST_DIR/iotest-version3-s001.vmdk -0x80000000 0x10000 0x50000 TEST_DIR/iotest-version3-s002.vmdk -0x140000000 0x10000 0x50000 TEST_DIR/iotest-version3-s003.vmdk +0 0x20000 0x50000 TEST_DIR/t-s001.vmdk +0x7fff0000 0x10000 0x70000 TEST_DIR/t-s001.vmdk +0x80000000 0x10000 0x50000 TEST_DIR/t-s002.vmdk +0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk === Testing afl image with a very large capacity === qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063 index 352e78c..e4f6ea9 100755 --- a/tests/qemu-iotests/063 +++ b/tests/qemu-iotests/063 @@ -31,7 +31,7 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img - rm -f "$TEST_IMG.orig" "$TEST_IMG.raw" "$TEST_IMG.raw2" + rm -f "$TEST_IMG.orig" "$TEST_IMG.raw1" "$TEST_IMG.raw2" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -91,8 +91,6 @@ if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG.orig" "$TEST_IMG" >/dev exit 1 fi -rm -f "$TEST_IMG.orig" "$TEST_IMG.raw" "$TEST_IMG.raw2" - echo "*** done" rm -f $seq.full status=0 diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074 index aba126c..b17866b 100755 --- a/tests/qemu-iotests/074 +++ b/tests/qemu-iotests/074 @@ -32,6 +32,7 @@ _cleanup() echo "Cleanup" _cleanup_test_img rm "${TEST_IMG2}" + rm -f "$TEST_DIR/blkdebug.conf" } trap "_cleanup; exit \$status" 0 1 2 3 15 diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index d0d2c2b..8e76e62 100644 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -336,7 +336,12 @@ class TestIncrementalBackup(TestIncrementalBackupBase): (('0xab', 0, 512), ('0xfe', '16M', '256k'), ('0x64', '32736k', '64k'))) - + # Check the dirty bitmap stats + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/name', 'bitmap0') + self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/count', 458752) + self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/granularity', 65536) + self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/status', 'active') # Prepare a cluster_size=128k backup target without a backing file. (target, _) = bitmap0.new_target() diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 index 40a3405..2f9d7b9 100755 --- a/tests/qemu-iotests/141 +++ b/tests/qemu-iotests/141 @@ -31,7 +31,7 @@ _cleanup() { _cleanup_qemu _cleanup_test_img - rm -f "$TEST_DIR/{b,m,o}.$IMGFMT" + rm -f "$TEST_DIR"/{b,m,o}.$IMGFMT } trap "_cleanup; exit \$status" 0 1 2 3 15 diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 index 0b45d78..fa25eb2 100755 --- a/tests/qemu-iotests/153 +++ b/tests/qemu-iotests/153 @@ -35,6 +35,7 @@ _cleanup() rm -f "${TEST_IMG}.convert" rm -f "${TEST_IMG}.a" rm -f "${TEST_IMG}.b" + rm -f "${TEST_IMG}.c" rm -f "${TEST_IMG}.lnk" } trap "_cleanup; exit \$status" 0 1 2 3 15 diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 index 2c4a06e..e75dc4d 100755 --- a/tests/qemu-iotests/156 +++ b/tests/qemu-iotests/156 @@ -38,7 +38,7 @@ status=1 # failure is the default! _cleanup() { _cleanup_qemu - rm -f "$TEST_IMG{,.target}{,.backing,.overlay}" + rm -f "$TEST_IMG"{,.target}{,.backing,.overlay} } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -83,7 +83,7 @@ _send_qemu_cmd $QEMU_HANDLE \ 'return' # Create target image -TEST_IMG="$TEST_IMG.target.overlay" _make_test_img -b "$TEST_IMG.target" 1M +TEST_IMG="$TEST_IMG.target.overlay" _make_test_img -u -b "$TEST_IMG.target" 1M # Mirror snapshot _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162 index cad2bd7..477a806 100755 --- a/tests/qemu-iotests/162 +++ b/tests/qemu-iotests/162 @@ -28,6 +28,13 @@ echo "QA output created by $seq" here="$PWD" status=1 # failure is the default! +_cleanup() +{ + rm -f "${TEST_DIR}/qemu-nbd.pid" + rm -f 42 +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + # get standard environment, filters and checks . ./common.rc . ./common.filter diff --git a/tests/qemu-iotests/179 b/tests/qemu-iotests/179 index 7bc8db8..115944a 100755 --- a/tests/qemu-iotests/179 +++ b/tests/qemu-iotests/179 @@ -30,6 +30,7 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img + rm -f "$TEST_DIR/blkdebug.conf" } trap "_cleanup; exit \$status" 0 1 2 3 15 diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 index ab83ee4..2b9f618 100755 --- a/tests/qemu-iotests/186 +++ b/tests/qemu-iotests/186 @@ -56,7 +56,7 @@ function do_run_qemu() done fi echo quit - ) | $QEMU -S -nodefaults -display none -device virtio-scsi-pci -monitor stdio "$@" + ) | $QEMU -S -nodefaults -display none -device virtio-scsi-pci -monitor stdio "$@" 2>&1 echo } diff --git a/tests/qemu-iotests/186.out b/tests/qemu-iotests/186.out index b8bf9a2..c8377fe 100644 --- a/tests/qemu-iotests/186.out +++ b/tests/qemu-iotests/186.out @@ -442,28 +442,28 @@ ide0-cd0 (NODE_NAME): null-co:// (null-co, read-only) Cache mode: writeback (qemu) quit -qemu-system-x86_64: -drive if=scsi,driver=null-co: warning: bus=0,unit=0 is deprecated with this machine type Testing: -drive if=scsi,driver=null-co QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block +(qemu) QEMU_PROG: -drive if=scsi,driver=null-co: warning: bus=0,unit=0 is deprecated with this machine type +info block scsi0-hd0 (NODE_NAME): null-co:// (null-co) Attached to: /machine/unattached/device[27]/scsi.0/legacy[0] Cache mode: writeback (qemu) quit -qemu-system-x86_64: -drive if=scsi,media=cdrom: warning: bus=0,unit=0 is deprecated with this machine type Testing: -drive if=scsi,media=cdrom QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block +(qemu) QEMU_PROG: -drive if=scsi,media=cdrom: warning: bus=0,unit=0 is deprecated with this machine type +info block scsi0-cd0: [not inserted] Attached to: /machine/unattached/device[27]/scsi.0/legacy[0] Removable device: not locked, tray closed (qemu) quit -qemu-system-x86_64: -drive if=scsi,driver=null-co,media=cdrom: warning: bus=0,unit=0 is deprecated with this machine type Testing: -drive if=scsi,driver=null-co,media=cdrom QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block +(qemu) QEMU_PROG: -drive if=scsi,driver=null-co,media=cdrom: warning: bus=0,unit=0 is deprecated with this machine type +info block scsi0-cd0 (NODE_NAME): null-co:// (null-co, read-only) Attached to: /machine/unattached/device[27]/scsi.0/legacy[0] Removable device: not locked, tray closed diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190 new file mode 100755 index 0000000..8f808fe --- /dev/null +++ b/tests/qemu-iotests/190 @@ -0,0 +1,59 @@ +#!/bin/bash +# +# qemu-img measure sub-command tests on huge qcow2 files +# +# Copyright (C) 2017 Red Hat, Inc. +# +# 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 of the License, or +# (at your option) any later version. +# +# 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/>. +# + +# creator +owner=eblake@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.converted" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.pattern + +# See 178 for more extensive tests across more formats +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +echo "== Huge file ==" +echo + +IMGOPTS='cluster_size=2M' _make_test_img 2T + +$QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG" +$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG" +$QEMU_IMG measure -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG" + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/190.out b/tests/qemu-iotests/190.out new file mode 100644 index 0000000..d001942 --- /dev/null +++ b/tests/qemu-iotests/190.out @@ -0,0 +1,11 @@ +QA output created by 190 +== Huge file == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2199023255552 +required size: 2199023255552 +fully allocated size: 2199023255552 +required size: 335806464 +fully allocated size: 2199359062016 +required size: 18874368 +fully allocated size: 2199042129920 +*** done diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 2548e58..bfbc80e 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -92,6 +92,7 @@ else TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT fi fi +ORIG_TEST_IMG="$TEST_IMG" _optstr_add() { @@ -228,6 +229,8 @@ _cleanup_test_img() if [ -n "$SAMPLE_IMG_FILE" ] then rm -f "$TEST_DIR/$SAMPLE_IMG_FILE" + SAMPLE_IMG_FILE= + TEST_IMG="$ORIG_TEST_IMG" fi ;; diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 287f0ea..8238110 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -184,3 +184,4 @@ 186 rw auto 188 rw auto quick 189 rw auto +190 rw auto quick diff --git a/tests/rtc-test.c b/tests/rtc-test.c index e78f701..d7a96cb 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -17,6 +17,8 @@ #include "qemu/timer.h" #include "hw/timer/mc146818rtc_regs.h" +#define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768) + static uint8_t base = 0x70; static int bcd2dec(int value) @@ -297,15 +299,53 @@ static void alarm_time(void) g_assert(cmos_read(RTC_REG_C) == 0); } +static void set_time_regs(int h, int m, int s) +{ + cmos_write(RTC_HOURS, h); + cmos_write(RTC_MINUTES, m); + cmos_write(RTC_SECONDS, s); +} + static void set_time(int mode, int h, int m, int s) { - /* set BCD 12 hour mode */ cmos_write(RTC_REG_B, mode); - cmos_write(RTC_REG_A, 0x76); + set_time_regs(h, m, s); + cmos_write(RTC_REG_A, 0x26); +} + +static void set_datetime_bcd(int h, int min, int s, int d, int m, int y) +{ cmos_write(RTC_HOURS, h); - cmos_write(RTC_MINUTES, m); + cmos_write(RTC_MINUTES, min); + cmos_write(RTC_SECONDS, s); + cmos_write(RTC_YEAR, y & 0xFF); + cmos_write(RTC_CENTURY, y >> 8); + cmos_write(RTC_MONTH, m); + cmos_write(RTC_DAY_OF_MONTH, d); +} + +static void set_datetime_dec(int h, int min, int s, int d, int m, int y) +{ + cmos_write(RTC_HOURS, h); + cmos_write(RTC_MINUTES, min); cmos_write(RTC_SECONDS, s); + cmos_write(RTC_YEAR, y % 100); + cmos_write(RTC_CENTURY, y / 100); + cmos_write(RTC_MONTH, m); + cmos_write(RTC_DAY_OF_MONTH, d); +} + +static void set_datetime(int mode, int h, int min, int s, int d, int m, int y) +{ + cmos_write(RTC_REG_B, mode); + + cmos_write(RTC_REG_A, 0x76); + if (mode & REG_B_DM) { + set_datetime_dec(h, min, s, d, m, y); + } else { + set_datetime_bcd(h, min, s, d, m, y); + } cmos_write(RTC_REG_A, 0x26); } @@ -316,6 +356,17 @@ static void set_time(int mode, int h, int m, int s) g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \ } while(0) +#define assert_datetime_bcd(h, min, s, d, m, y) \ + do { \ + g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \ + g_assert_cmpint(cmos_read(RTC_MINUTES), ==, min); \ + g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \ + g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, d); \ + g_assert_cmpint(cmos_read(RTC_MONTH), ==, m); \ + g_assert_cmpint(cmos_read(RTC_YEAR), ==, (y & 0xFF)); \ + g_assert_cmpint(cmos_read(RTC_CENTURY), ==, (y >> 8)); \ + } while(0) + static void basic_12h_bcd(void) { /* set BCD 12 hour mode */ @@ -506,41 +557,84 @@ static void fuzz_registers(void) static void register_b_set_flag(void) { + if (cmos_read(RTC_REG_A) & REG_A_UIP) { + clock_step(UIP_HOLD_LENGTH + NANOSECONDS_PER_SECOND / 5); + } + g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); + /* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/ cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET); - cmos_write(RTC_REG_A, 0x76); - cmos_write(RTC_YEAR, 0x11); - cmos_write(RTC_CENTURY, 0x20); - cmos_write(RTC_MONTH, 0x02); - cmos_write(RTC_DAY_OF_MONTH, 0x02); - cmos_write(RTC_HOURS, 0x02); - cmos_write(RTC_MINUTES, 0x04); - cmos_write(RTC_SECONDS, 0x58); - cmos_write(RTC_REG_A, 0x26); + set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); - /* Since SET flag is still enabled, these are equality checks. */ - g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02); - g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04); - g_assert_cmpint(cmos_read(RTC_SECONDS), ==, 0x58); - g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02); - g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02); - g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11); - g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); + assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); + + /* Since SET flag is still enabled, time does not advance. */ + clock_step(1000000000LL); + assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); /* Disable SET flag in Register B */ cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_SET); - g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02); - g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04); + assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); - /* Since SET flag is disabled, this is an inequality check. - * We (reasonably) assume that no (sexagesimal) overflow occurs. */ - g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58); - g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02); - g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02); - g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11); - g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); + /* Since SET flag is disabled, the clock now advances. */ + clock_step(1000000000LL); + assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011); +} + +static void divider_reset(void) +{ + /* Enable binary-coded decimal (BCD) mode in Register B*/ + cmos_write(RTC_REG_B, REG_B_24H); + + /* Enter divider reset */ + cmos_write(RTC_REG_A, 0x76); + set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); + + assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); + + /* Since divider reset flag is still enabled, these are equality checks. */ + clock_step(1000000000LL); + assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); + + /* The first update ends 500 ms after divider reset */ + cmos_write(RTC_REG_A, 0x26); + clock_step(500000000LL - UIP_HOLD_LENGTH - 1); + g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); + assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); + + clock_step(1); + g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0); + clock_step(UIP_HOLD_LENGTH); + g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); + + assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011); +} + +static void uip_stuck(void) +{ + set_datetime(REG_B_24H, 0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); + + /* The first update ends 500 ms after divider reset */ + (void)cmos_read(RTC_REG_C); + clock_step(500000000LL); + g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); + assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011); + + /* UF is now set. */ + cmos_write(RTC_HOURS_ALARM, 0x02); + cmos_write(RTC_MINUTES_ALARM, 0xC0); + cmos_write(RTC_SECONDS_ALARM, 0xC0); + + /* Because the alarm will fire soon, reading register A will latch UIP. */ + clock_step(1000000000LL - UIP_HOLD_LENGTH / 2); + g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0); + + /* Move the alarm far away. This must not cause UIP to remain stuck! */ + cmos_write(RTC_HOURS_ALARM, 0x03); + clock_step(UIP_HOLD_LENGTH); + g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); } #define RTC_PERIOD_CODE1 13 /* 8 Hz */ @@ -609,7 +703,9 @@ int main(int argc, char **argv) qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd); qtest_add_func("/rtc/set-year/20xx", set_year_20xx); qtest_add_func("/rtc/set-year/1980", set_year_1980); - qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag); + qtest_add_func("/rtc/update/register_b_set_flag", register_b_set_flag); + qtest_add_func("/rtc/update/divider-reset", divider_reset); + qtest_add_func("/rtc/update/uip-stuck", uip_stuck); qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers); qtest_add_func("/rtc/periodic/interrupt", periodic_timer); @@ -2344,10 +2344,12 @@ static int chardev_init_func(void *opaque, QemuOpts *opts, Error **errp) { Error *local_err = NULL; - qemu_chr_new_from_opts(opts, &local_err); - if (local_err) { - error_report_err(local_err); - return -1; + if (!qemu_chr_new_from_opts(opts, &local_err)) { + if (local_err) { + error_report_err(local_err); + return -1; + } + exit(0); } return 0; } @@ -4787,8 +4789,8 @@ int main(int argc, char **argv, char **envp) replay_disable_events(); iothread_stop_all(); - bdrv_close_all(); pause_all_vcpus(); + bdrv_close_all(); res_free(); /* vhost-user must be cleaned up before chardevs. */ |