diff --git a/accel/accel.c b/accel/accel.c index fa8584488e..8ae40e1e13 100644 --- a/accel/accel.c +++ b/accel/accel.c @@ -33,6 +33,7 @@ #include "sysemu/qtest.h" #include "hw/xen/xen.h" #include "qom/object.h" +#include "qemu/error-report.h" static const TypeInfo accel_type = { .name = TYPE_ACCEL, @@ -69,19 +70,20 @@ static int accel_init_machine(AccelClass *acc, MachineState *ms) void configure_accelerator(MachineState *ms) { - const char *p; + const char *accel, *p; char buf[10]; int ret; bool accel_initialised = false; bool init_failed = false; AccelClass *acc = NULL; - p = qemu_opt_get(qemu_get_machine_opts(), "accel"); - if (p == NULL) { + accel = qemu_opt_get(qemu_get_machine_opts(), "accel"); + if (accel == NULL) { /* Use the default "accelerator", tcg */ - p = "tcg"; + accel = "tcg"; } + p = accel; while (!accel_initialised && *p != '\0') { if (*p == ':') { p++; @@ -89,7 +91,6 @@ void configure_accelerator(MachineState *ms) p = get_opt_name(buf, sizeof(buf), p, ':'); acc = accel_find(buf); if (!acc) { - fprintf(stderr, "\"%s\" accelerator not found.\n", buf); continue; } if (acc->available && !acc->available()) { @@ -100,9 +101,8 @@ void configure_accelerator(MachineState *ms) ret = accel_init_machine(acc, ms); if (ret < 0) { init_failed = true; - fprintf(stderr, "failed to initialize %s: %s\n", - acc->name, - strerror(-ret)); + error_report("failed to initialize %s: %s", + acc->name, strerror(-ret)); } else { accel_initialised = true; } @@ -110,13 +110,13 @@ void configure_accelerator(MachineState *ms) if (!accel_initialised) { if (!init_failed) { - fprintf(stderr, "No accelerator found!\n"); + error_report("-machine accel=%s: No accelerator found", accel); } exit(1); } if (init_failed) { - fprintf(stderr, "Back to %s accelerator.\n", acc->name); + error_report("Back to %s accelerator", acc->name); } } diff --git a/chardev/char-fd.c b/chardev/char-fd.c index 1584a3de20..6a62a545f2 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 c34b44abc9..5d283b90d3 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) { diff --git a/exec.c b/exec.c index 01ac21e3cd..d20c34ca83 100644 --- a/exec.c +++ b/exec.c @@ -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 f67b3b89c0..3cb60b9495 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 4a106da856..77d8b6f9e2 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 1b8d3d7d4c..82843ed03f 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: - 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 = s->cmos_data[s->cmos_index]; + if (update_in_progress(s)) { + ret |= REG_A_UIP; + } 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 55ae5b47b0..e7c2b176f9 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 1604ea9143..66dde4637e 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 c04f4f67f6..d017639f7e 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(); diff --git a/memory.c b/memory.c index a7bc70aac1..c0adc35410 100644 --- a/memory.c +++ b/memory.c @@ -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 48af5155c7..aeb7bc52f5 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 746b5fa75d..9f6e2adfff 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 a6613e19f2..6db7783edc 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,6 +2669,18 @@ int kvm_arch_get_registers(CPUState *cs) assert(cpu_is_stopped(cs) || qemu_cpu_is_self(cs)); + ret = kvm_get_vcpu_events(cpu); + if (ret < 0) { + goto out; + } + /* + * 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_getput_regs(cpu, 0); if (ret < 0) { goto out; @@ -2688,18 +2701,10 @@ int kvm_arch_get_registers(CPUState *cs) if (ret < 0) { goto out; } - ret = kvm_get_mp_state(cpu); - if (ret < 0) { - goto out; - } ret = kvm_get_apic(cpu); if (ret < 0) { goto out; } - ret = kvm_get_vcpu_events(cpu); - if (ret < 0) { - goto out; - } ret = kvm_get_debugregs(cpu); if (ret < 0) { goto out; diff --git a/tests/rtc-test.c b/tests/rtc-test.c index e78f701afb..d7a96cbd79 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(int mode, int h, int m, int s) +static void set_time_regs(int h, int m, int s) { - /* set BCD 12 hour mode */ - cmos_write(RTC_REG_B, mode); - - cmos_write(RTC_REG_A, 0x76); 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) +{ + 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, 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); diff --git a/vl.c b/vl.c index fb6b2efafa..99fcfa0442 100644 --- a/vl.c +++ b/vl.c @@ -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. */