diff options
-rw-r--r-- | hw/acpi/core.c | 7 | ||||
-rw-r--r-- | hw/i386/kvm/apic.c | 3 | ||||
-rw-r--r-- | hw/i386/kvm/clock.c | 14 | ||||
-rw-r--r-- | hw/i386/smbios.c | 10 | ||||
-rw-r--r-- | hw/intc/apic_common.c | 38 | ||||
-rw-r--r-- | hw/scsi/esp-pci.c | 3 | ||||
-rw-r--r-- | hw/scsi/esp.c | 11 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi-dataplane.c | 9 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 17 | ||||
-rw-r--r-- | include/hw/scsi/esp.h | 1 | ||||
-rw-r--r-- | include/hw/virtio/virtio-scsi.h | 3 | ||||
-rw-r--r-- | target-i386/cpu.h | 2 | ||||
-rw-r--r-- | target-i386/seg_helper.c | 17 |
13 files changed, 109 insertions, 26 deletions
diff --git a/hw/acpi/core.c b/hw/acpi/core.c index a7368fb242..51913d6932 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -376,8 +376,11 @@ static void acpi_notify_wakeup(Notifier *notifier, void *data) /* ACPI PM1a EVT */ uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar) { - int64_t d = acpi_pm_tmr_get_clock(); - if (d >= ar->tmr.overflow_time) { + /* Compare ns-clock, not PM timer ticks, because + acpi_pm_tmr_update function uses ns for setting the timer. */ + int64_t d = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (d >= muldiv64(ar->tmr.overflow_time, + get_ticks_per_sec(), PM_TIMER_FREQUENCY)) { ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS; } return ar->pm1.evt.sts; diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index e873b509a5..271e97f86f 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -175,6 +175,9 @@ static void kvm_apic_realize(DeviceState *dev, Error **errp) { APICCommonState *s = APIC_COMMON(dev); + /* Not used by KVM, which uses the CPU mp_state instead. */ + s->wait_for_sipi = 0; + memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi", APIC_SPACE_SIZE); diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 1ac60d6cdd..58be2bda27 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -127,7 +127,21 @@ static void kvmclock_vm_state_change(void *opaque, int running, } cpu_synchronize_all_states(); + /* In theory, the cpu_synchronize_all_states() call above wouldn't + * affect the rest of the code, as the VCPU state inside CPUState + * is supposed to always match the VCPU state on the kernel side. + * + * In practice, calling cpu_synchronize_state() too soon will load the + * kernel-side APIC state into X86CPU.apic_state too early, APIC state + * won't be reloaded later because CPUState.vcpu_dirty==true, and + * outdated APIC state may be migrated to another host. + * + * The real fix would be to make sure outdated APIC state is read + * from the kernel again when necessary. While this is not fixed, we + * need the cpu_clean_all_dirty() call below. + */ cpu_clean_all_dirty(); + ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); if (ret < 0) { fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index 8a7ad48921..024e59445b 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -645,7 +645,7 @@ static void smbios_build_type_4_table(unsigned instance) static void smbios_build_type_16_table(unsigned dimm_cnt) { - ram_addr_t size_kb; + uint64_t size_kb; SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */ @@ -669,10 +669,10 @@ static void smbios_build_type_16_table(unsigned dimm_cnt) #define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */ #define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */ -static void smbios_build_type_17_table(unsigned instance, ram_addr_t size) +static void smbios_build_type_17_table(unsigned instance, uint64_t size) { char loc_str[128]; - ram_addr_t size_mb; + uint64_t size_mb; SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */ @@ -711,9 +711,9 @@ static void smbios_build_type_17_table(unsigned instance, ram_addr_t size) } static void smbios_build_type_19_table(unsigned instance, - ram_addr_t start, ram_addr_t size) + uint64_t start, uint64_t size) { - ram_addr_t end, start_kb, end_kb; + uint64_t end, start_kb, end_kb; SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */ diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index ce3d903b13..4e62f25edb 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -324,6 +324,19 @@ static void apic_common_realize(DeviceState *dev, Error **errp) } +static int apic_pre_load(void *opaque) +{ + APICCommonState *s = APIC_COMMON(opaque); + + /* The default is !cpu_is_bsp(s->cpu), but the common value is 0 + * so that's what apic_common_sipi_needed checks for. Reset to + * the value that is assumed when the apic_sipi subsection is + * absent. + */ + s->wait_for_sipi = 0; + return 0; +} + static void apic_dispatch_pre_save(void *opaque) { APICCommonState *s = APIC_COMMON(opaque); @@ -345,12 +358,30 @@ static int apic_dispatch_post_load(void *opaque, int version_id) return 0; } +static bool apic_common_sipi_needed(void *opaque) +{ + APICCommonState *s = APIC_COMMON(opaque); + return s->wait_for_sipi != 0; +} + +static const VMStateDescription vmstate_apic_common_sipi = { + .name = "apic_sipi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(sipi_vector, APICCommonState), + VMSTATE_INT32(wait_for_sipi, APICCommonState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_apic_common = { .name = "apic", .version_id = 3, .minimum_version_id = 3, .minimum_version_id_old = 1, .load_state_old = apic_load_old, + .pre_load = apic_pre_load, .pre_save = apic_dispatch_pre_save, .post_load = apic_dispatch_post_load, .fields = (VMStateField[]) { @@ -375,6 +406,13 @@ static const VMStateDescription vmstate_apic_common = { VMSTATE_INT64(timer_expiry, APICCommonState), /* open-coded timer state */ VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &vmstate_apic_common_sipi, + .needed = apic_common_sipi_needed, + }, + VMSTATE_END_OF_LIST() } }; diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 82795e68b8..00b7297354 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -268,6 +268,9 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len, /* update status registers */ pci->dma_regs[DMA_WBC] -= len; pci->dma_regs[DMA_WAC] += len; + if (pci->dma_regs[DMA_WBC] == 0) { + pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE; + } } static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len) diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 5ab44d860b..272d13d633 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -364,7 +364,7 @@ void esp_hard_reset(ESPState *s) { memset(s->rregs, 0, ESP_REGS); memset(s->wregs, 0, ESP_REGS); - s->rregs[ESP_TCHI] = s->chip_id; + s->tchi_written = 0; s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; @@ -422,6 +422,11 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr) esp_lower_irq(s); return old_val; + case ESP_TCHI: + /* Return the unique id if the value has never been written */ + if (!s->tchi_written) { + return s->chip_id; + } default: break; } @@ -432,9 +437,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) { trace_esp_mem_writeb(saddr, s->wregs[saddr], val); switch (saddr) { + case ESP_TCHI: + s->tchi_written = true; + /* fall through */ case ESP_TCLO: case ESP_TCMID: - case ESP_TCHI: s->rregs[ESP_RSTAT] &= ~STAT_TC; break; case ESP_FIFO: diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 9651e6f274..03a1e8cfcf 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -92,9 +92,14 @@ VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) { + VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent); + vring_push(&req->vring->vring, &req->elem, req->qsgl.size + req->resp_iov.size); - event_notifier_set(&req->vring->guest_notifier); + + if (vring_should_notify(vdev, &req->vring->vring)) { + event_notifier_set(&req->vring->guest_notifier); + } } static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier) @@ -230,7 +235,7 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) if (!s->event_vring) { goto fail_vrings; } - s->cmd_vrings = g_malloc0(sizeof(VirtIOSCSIVring) * vs->conf.num_queues); + s->cmd_vrings = g_new(VirtIOSCSIVring *, vs->conf.num_queues); for (i = 0; i < vs->conf.num_queues; i++) { s->cmd_vrings[i] = virtio_scsi_vring_init(s, vs->cmd_vqs[i], diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index fdcacfd79a..ef485508b1 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -118,6 +118,7 @@ static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov, static int virtio_scsi_parse_req(VirtIOSCSIReq *req, unsigned req_size, unsigned resp_size) { + VirtIODevice *vdev = (VirtIODevice *) req->dev; size_t in_size, out_size; if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, @@ -130,8 +131,24 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req, resp_size) < resp_size) { return -EINVAL; } + req->resp_size = resp_size; + /* Old BIOSes left some padding by mistake after the req_size/resp_size. + * As a workaround, always consider the first buffer as the virtio-scsi + * request/response, making the payload start at the second element + * of the iovec. + * + * The actual length of the response header, stored in req->resp_size, + * does not change. + * + * TODO: always disable this workaround for virtio 1.0 devices. + */ + if ((vdev->guest_features & VIRTIO_F_ANY_LAYOUT) == 0) { + req_size = req->elem.out_sg[0].iov_len; + resp_size = req->elem.in_sg[0].iov_len; + } + out_size = qemu_sgl_concat(req, req->elem.out_sg, &req->elem.out_addr[0], req->elem.out_num, req_size); diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h index e079fb8d16..6c795276c9 100644 --- a/include/hw/scsi/esp.h +++ b/include/hw/scsi/esp.h @@ -22,6 +22,7 @@ struct ESPState { uint8_t wregs[ESP_REGS]; qemu_irq irq; uint8_t chip_id; + bool tchi_written; int32_t ti_size; uint32_t ti_rptr, ti_wptr; uint32_t status; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 9e1a49c2c1..bf17cc9ea5 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -209,7 +209,8 @@ typedef struct VirtIOSCSIReq { /* Note: * - fields before elem are initialized by virtio_scsi_init_req; * - elem is uninitialized at the time of allocation. - * - fields after elem are zeroed by virtio_scsi_init_req. + * - fields after elem (except the ending cdb[]) are zeroed by + * virtio_scsi_init_req. * */ VirtQueueElement elem; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1b2c12ad94..015f5b5276 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1104,7 +1104,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, } static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu, - int sipi_vector) + uint8_t sipi_vector) { CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index af5c1c6830..c98eeb4351 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -883,32 +883,23 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, } if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { /* to inner privilege */ - if (ist != 0) { - esp = get_rsp_from_tss(env, ist + 3); - } else { - esp = get_rsp_from_tss(env, dpl); - } - esp &= ~0xfLL; /* align stack */ - ss = 0; new_stack = 1; + esp = get_rsp_from_tss(env, ist != 0 ? ist + 3 : dpl); + ss = 0; } else if ((e2 & DESC_C_MASK) || dpl == cpl) { /* to same privilege */ if (env->eflags & VM_MASK) { raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); } new_stack = 0; - if (ist != 0) { - esp = get_rsp_from_tss(env, ist + 3); - } else { - esp = env->regs[R_ESP]; - } - esp &= ~0xfLL; /* align stack */ + esp = env->regs[R_ESP]; dpl = cpl; } else { raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); new_stack = 0; /* avoid warning */ esp = 0; /* avoid warning */ } + esp &= ~0xfLL; /* align stack */ PUSHQ(esp, env->segs[R_SS].selector); PUSHQ(esp, env->regs[R_ESP]); |