From eb7a20a3616085d46aa6b4b4224e15587ec67e6e Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 28 Nov 2016 17:49:04 -0800 Subject: watchdog: 6300esb: add exit function When the Intel 6300ESB watchdog is hot unplug. The timer allocated in realize isn't freed thus leaking memory leak. This patch avoid this through adding the exit function. Signed-off-by: Li Qiang Message-Id: <583cde9c.3223ed0a.7f0c2.886e@mx.google.com> Signed-off-by: Paolo Bonzini --- hw/watchdog/wdt_i6300esb.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'hw') diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index a83d951213..49b3cd188a 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -428,6 +428,14 @@ static void i6300esb_realize(PCIDevice *dev, Error **errp) /* qemu_register_coalesced_mmio (addr, 0x10); ? */ } +static void i6300esb_exit(PCIDevice *dev) +{ + I6300State *d = WATCHDOG_I6300ESB_DEVICE(dev); + + timer_del(d->timer); + timer_free(d->timer); +} + static WatchdogTimerModel model = { .wdt_name = "i6300esb", .wdt_description = "Intel 6300ESB", @@ -441,6 +449,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data) k->config_read = i6300esb_config_read; k->config_write = i6300esb_config_write; k->realize = i6300esb_realize; + k->exit = i6300esb_exit; k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_ESB_9; k->class_id = PCI_CLASS_SYSTEM_OTHER; -- cgit v1.2.3-55-g7522 From e7a9f35321a048922233c90f32e91d033faac176 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Dec 2015 19:13:17 +0100 Subject: virtio-scsi: introduce virtio_scsi_acquire/release These will be used more as soon as the acquire/release is pushed down to the ioeventfd handlers. Reviewed-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 10fd687193..34bba35d83 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -420,6 +420,20 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } } +static inline void virtio_scsi_acquire(VirtIOSCSI *s) +{ + if (s->ctx) { + aio_context_acquire(s->ctx); + } +} + +static inline void virtio_scsi_release(VirtIOSCSI *s) +{ + if (s->ctx) { + aio_context_release(s->ctx); + } +} + void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; @@ -691,10 +705,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, return; } - if (s->dataplane_started) { - assert(s->ctx); - aio_context_acquire(s->ctx); - } + virtio_scsi_acquire(s); req = virtio_scsi_pop_req(s, vs->event_vq); if (!req) { @@ -730,9 +741,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, } virtio_scsi_complete_req(req); out: - if (s->dataplane_started) { - aio_context_release(s->ctx); - } + virtio_scsi_release(s); } void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) @@ -778,9 +787,9 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { return; } - aio_context_acquire(s->ctx); + virtio_scsi_acquire(s); blk_set_aio_context(sd->conf.blk, s->ctx); - aio_context_release(s->ctx); + virtio_scsi_release(s); } -- cgit v1.2.3-55-g7522 From be232eb07692a5d10d07aee8386faa7e860e73ea Mon Sep 17 00:00:00 2001 From: Chao Peng Date: Sat, 5 Nov 2016 03:19:48 -0400 Subject: pc: make smbus configurable Signed-off-by: Chao Peng Message-Id: <1478330391-74060-2-git-send-email-chao.p.peng@linux.intel.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 18 ++++++++++++++++++ hw/i386/pc_q35.c | 12 +++++++----- include/hw/i386/pc.h | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index a9e64a88e5..40bec88681 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -2158,6 +2158,20 @@ static void pc_machine_set_nvdimm(Object *obj, bool value, Error **errp) pcms->acpi_nvdimm_state.is_enabled = value; } +static bool pc_machine_get_smbus(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->smbus; +} + +static void pc_machine_set_smbus(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->smbus = value; +} + static void pc_machine_initfn(Object *obj) { PCMachineState *pcms = PC_MACHINE(obj); @@ -2169,6 +2183,7 @@ static void pc_machine_initfn(Object *obj) pcms->acpi_nvdimm_state.is_enabled = false; /* acpi build is enabled by default if machine supports it */ pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; + pcms->smbus = true; } static void pc_machine_reset(void) @@ -2329,6 +2344,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, PC_MACHINE_NVDIMM, pc_machine_get_nvdimm, pc_machine_set_nvdimm, &error_abort); + + object_class_property_add_bool(oc, PC_MACHINE_SMBUS, + pc_machine_get_smbus, pc_machine_set_smbus, &error_abort); } static const TypeInfo pc_machine_info = { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index b40d19ee00..5efc65aec6 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -248,11 +248,13 @@ static void pc_q35_init(MachineState *machine) ehci_create_ich9_with_companions(host_bus, 0x1d); } - /* TODO: Populate SPD eeprom data. */ - smbus_eeprom_init(ich9_smb_init(host_bus, - PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), - 0xb100), - 8, NULL, 0); + if (pcms->smbus) { + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(ich9_smb_init(host_bus, + PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), + 0xb100), + 8, NULL, 0); + } pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4b74130559..e5447a08c6 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -63,6 +63,7 @@ struct PCMachineState { AcpiNVDIMMState acpi_nvdimm_state; bool acpi_build_enabled; + bool smbus; /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; @@ -88,6 +89,7 @@ struct PCMachineState { #define PC_MACHINE_VMPORT "vmport" #define PC_MACHINE_SMM "smm" #define PC_MACHINE_NVDIMM "nvdimm" +#define PC_MACHINE_SMBUS "smbus" /** * PCMachineClass: -- cgit v1.2.3-55-g7522 From 272f042877d3ad95be99ea313789972752781c0b Mon Sep 17 00:00:00 2001 From: Chao Peng Date: Sat, 5 Nov 2016 03:19:49 -0400 Subject: pc: make sata configurable Signed-off-by: Chao Peng Message-Id: <1478330391-74060-3-git-send-email-chao.p.peng@linux.intel.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 29 ++++++++++++++++++++++++----- hw/i386/pc_q35.c | 24 ++++++++++++++---------- include/hw/i386/pc.h | 2 ++ 3 files changed, 40 insertions(+), 15 deletions(-) (limited to 'hw') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 40bec88681..b0beea3ef9 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -400,13 +400,13 @@ static void pc_cmos_init_late(void *opaque) int i, trans; val = 0; - if (ide_get_geometry(arg->idebus[0], 0, - &cylinders, &heads, §ors) >= 0) { + if (arg->idebus[0] && ide_get_geometry(arg->idebus[0], 0, + &cylinders, &heads, §ors) >= 0) { cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors); val |= 0xf0; } - if (ide_get_geometry(arg->idebus[0], 1, - &cylinders, &heads, §ors) >= 0) { + if (arg->idebus[0] && ide_get_geometry(arg->idebus[0], 1, + &cylinders, &heads, §ors) >= 0) { cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors); val |= 0x0f; } @@ -418,7 +418,8 @@ static void pc_cmos_init_late(void *opaque) geometry. It is always such that: 1 <= sects <= 63, 1 <= heads <= 16, 1 <= cylinders <= 16383. The BIOS geometry can be different if a translation is done. */ - if (ide_get_geometry(arg->idebus[i / 2], i % 2, + if (arg->idebus[i / 2] && + ide_get_geometry(arg->idebus[i / 2], i % 2, &cylinders, &heads, §ors) >= 0) { trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1; assert((trans & ~3) == 0); @@ -2172,6 +2173,20 @@ static void pc_machine_set_smbus(Object *obj, bool value, Error **errp) pcms->smbus = value; } +static bool pc_machine_get_sata(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->sata; +} + +static void pc_machine_set_sata(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->sata = value; +} + static void pc_machine_initfn(Object *obj) { PCMachineState *pcms = PC_MACHINE(obj); @@ -2184,6 +2199,7 @@ static void pc_machine_initfn(Object *obj) /* acpi build is enabled by default if machine supports it */ pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; pcms->smbus = true; + pcms->sata = true; } static void pc_machine_reset(void) @@ -2347,6 +2363,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, PC_MACHINE_SMBUS, pc_machine_get_smbus, pc_machine_set_smbus, &error_abort); + + object_class_property_add_bool(oc, PC_MACHINE_SATA, + pc_machine_get_sata, pc_machine_set_sata, &error_abort); } static const TypeInfo pc_machine_info = { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 5efc65aec6..205c33e1a2 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -232,16 +232,20 @@ static void pc_q35_init(MachineState *machine) /* connect pm stuff to lpc */ ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms)); - /* ahci and SATA device, for q35 1 ahci controller is built-in */ - ahci = pci_create_simple_multifunction(host_bus, - PCI_DEVFN(ICH9_SATA1_DEV, - ICH9_SATA1_FUNC), - true, "ich9-ahci"); - idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); - idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); - g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports); - ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports); - ahci_ide_create_devs(ahci, hd); + if (pcms->sata) { + /* ahci and SATA device, for q35 1 ahci controller is built-in */ + ahci = pci_create_simple_multifunction(host_bus, + PCI_DEVFN(ICH9_SATA1_DEV, + ICH9_SATA1_FUNC), + true, "ich9-ahci"); + idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); + g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports); + ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports); + ahci_ide_create_devs(ahci, hd); + } else { + idebus[0] = idebus[1] = NULL; + } if (machine_usb(machine)) { /* Should we create 6 UHCI according to ich9 spec? */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index e5447a08c6..9535f4a252 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -64,6 +64,7 @@ struct PCMachineState { bool acpi_build_enabled; bool smbus; + bool sata; /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; @@ -90,6 +91,7 @@ struct PCMachineState { #define PC_MACHINE_SMM "smm" #define PC_MACHINE_NVDIMM "nvdimm" #define PC_MACHINE_SMBUS "smbus" +#define PC_MACHINE_SATA "sata" /** * PCMachineClass: -- cgit v1.2.3-55-g7522 From feddd2fd91524b3457f3f4a20c22285acf887ba8 Mon Sep 17 00:00:00 2001 From: Chao Peng Date: Sat, 5 Nov 2016 03:19:50 -0400 Subject: pc: make pit configurable Signed-off-by: Chao Peng Message-Id: <1478330391-74060-4-git-send-email-chao.p.peng@linux.intel.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 21 ++++++++++++++++++++- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 3 ++- include/hw/i386/pc.h | 3 +++ 4 files changed, 26 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index b0beea3ef9..25e8586b48 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1536,6 +1536,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, + bool has_pit, uint32_t hpet_irqs) { int i; @@ -1589,7 +1590,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_register_boot_set(pc_boot_set, *rtc_state); - if (!xen_enabled()) { + if (!xen_enabled() && has_pit) { if (kvm_pit_in_kernel()) { pit = kvm_pit_init(isa_bus, 0x40); } else { @@ -2187,6 +2188,20 @@ static void pc_machine_set_sata(Object *obj, bool value, Error **errp) pcms->sata = value; } +static bool pc_machine_get_pit(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->pit; +} + +static void pc_machine_set_pit(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->pit = value; +} + static void pc_machine_initfn(Object *obj) { PCMachineState *pcms = PC_MACHINE(obj); @@ -2200,6 +2215,7 @@ static void pc_machine_initfn(Object *obj) pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; pcms->smbus = true; pcms->sata = true; + pcms->pit = true; } static void pc_machine_reset(void) @@ -2366,6 +2382,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, PC_MACHINE_SATA, pc_machine_get_sata, pc_machine_set_sata, &error_abort); + + object_class_property_add_bool(oc, PC_MACHINE_PIT, + pc_machine_get_pit, pc_machine_set_pit, &error_abort); } static const TypeInfo pc_machine_info = { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a54a468c0a..5e1adbe53c 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -235,7 +235,7 @@ static void pc_init1(MachineState *machine, /* init basic PC hardware */ pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true, - (pcms->vmport != ON_OFF_AUTO_ON), 0x4); + (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4); pc_nic_init(isa_bus, pci_bus); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 205c33e1a2..d042fe0843 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -227,7 +227,8 @@ static void pc_q35_init(MachineState *machine) /* init basic PC hardware */ pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy, - (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104); + (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, + 0xff0104); /* connect pm stuff to lpc */ ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms)); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 9535f4a252..b37bc5b139 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -65,6 +65,7 @@ struct PCMachineState { bool acpi_build_enabled; bool smbus; bool sata; + bool pit; /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; @@ -92,6 +93,7 @@ struct PCMachineState { #define PC_MACHINE_NVDIMM "nvdimm" #define PC_MACHINE_SMBUS "smbus" #define PC_MACHINE_SATA "sata" +#define PC_MACHINE_PIT "pit" /** * PCMachineClass: @@ -264,6 +266,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, + bool has_pit, uint32_t hpet_irqs); void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(PCMachineState *pcms, -- cgit v1.2.3-55-g7522 From 96a3d3927730c9445983f50ac0f55e0fce3851fa Mon Sep 17 00:00:00 2001 From: Vlad Lungu Date: Thu, 15 Dec 2016 14:32:04 +0200 Subject: multiboot: copy the cmdline verbatim, unescape module strings get_opt_value() truncates the value at the first comma Use memcpy() instead so that -append works correctly in the presence of commas. For -initrd to work right, instead, unescape the module filename and parameters with get_opt_value() before calling mb_add_cmdline(). Signed-off-by: Vlad Lungu Message-Id: <1481805124-16242-1-git-send-email-vlad.lungu@windriver.com> Signed-off-by: Paolo Bonzini --- hw/i386/multiboot.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'hw') diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index 387caa67d4..f13e23139b 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -109,7 +109,7 @@ static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline) hwaddr p = s->offset_cmdlines; char *b = (char *)s->mb_buf + p; - get_opt_value(b, strlen(cmdline) + 1, cmdline); + memcpy(b, cmdline, strlen(cmdline) + 1); s->offset_cmdlines += strlen(b) + 1; return s->mb_buf_phys + p; } @@ -287,7 +287,8 @@ int load_multiboot(FWCfgState *fw_cfg, mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len; if (initrd_filename) { - char *next_initrd, not_last; + const char *next_initrd; + char not_last, tmpbuf[strlen(initrd_filename) + 1]; mbs.offset_mods = mbs.mb_buf_size; @@ -296,25 +297,24 @@ int load_multiboot(FWCfgState *fw_cfg, int mb_mod_length; uint32_t offs = mbs.mb_buf_size; - next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename); + next_initrd = get_opt_value(tmpbuf, sizeof(tmpbuf), initrd_filename); not_last = *next_initrd; - *next_initrd = '\0'; /* if a space comes after the module filename, treat everything after that as parameters */ - hwaddr c = mb_add_cmdline(&mbs, initrd_filename); - if ((next_space = strchr(initrd_filename, ' '))) + hwaddr c = mb_add_cmdline(&mbs, tmpbuf); + if ((next_space = strchr(tmpbuf, ' '))) *next_space = '\0'; - mb_debug("multiboot loading module: %s\n", initrd_filename); - mb_mod_length = get_image_size(initrd_filename); + mb_debug("multiboot loading module: %s\n", tmpbuf); + mb_mod_length = get_image_size(tmpbuf); if (mb_mod_length < 0) { - fprintf(stderr, "Failed to open file '%s'\n", initrd_filename); + fprintf(stderr, "Failed to open file '%s'\n", tmpbuf); exit(1); } mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size); mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); - load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs); + load_image(tmpbuf, (unsigned char *)mbs.mb_buf + offs); mb_add_mod(&mbs, mbs.mb_buf_phys + offs, mbs.mb_buf_phys + offs + mb_mod_length, c); -- cgit v1.2.3-55-g7522 From 8929fc3a55f33a103adddf9cfd010bcf2b255c7d Mon Sep 17 00:00:00 2001 From: Ziyue Yang Date: Thu, 15 Dec 2016 22:04:53 +0800 Subject: hw/block/pflash_cfi*.c: fix confusing assert fail message The patch is to fix the confusing assert fail message caused by un-initialized device structure (from bite sized tasks). The bug can be reproduced by ./qemu-system-x86_64 -nographic -device cfi.pflash01 The CFI hardware is dynamically loaded by QOM realizing mechanism, however the realizing function in pflash_cfi01_realize function requires the device being initialized manually before calling, like ./qemu-system-x86_64 -nographic -device cfi.pflash01,num-blocks=1024,sector-length=4096,name=testcard Once the initializing parameters are left off in the command, it will leave the device structure not initialized, which makes pflash_cfi01_realize try to realize a zero-volume card, causing /mnt/EXT_volume/projects/qemu/qemu-dev/exec.c:1378: find_ram_offset: Assertion `size != 0\' failed. Through my test, at least the flash device's block-number, sector-length and its name is needed for pflash_cfi01_realize to behave correctly. So I think the new asserts are needed to hint the QEMU user to specify the device's parameters correctly. Signed-off-by: Ziyue Yang Message-Id: <1481810693-13733-1-git-send-email-skiver.cloud.yzy@gmail.com> Signed-off-by: Paolo Bonzini Signed-off-by: Ziyue Yang --- hw/block/pflash_cfi01.c | 13 +++++++++++++ hw/block/pflash_cfi02.c | 13 +++++++++++++ 2 files changed, 26 insertions(+) (limited to 'hw') diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 62d7a5661d..5f0ee9db00 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -707,6 +707,19 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) int num_devices; Error *local_err = NULL; + if (pfl->sector_len == 0) { + error_setg(errp, "attribute \"sector-length\" not specified or zero."); + return; + } + if (pfl->nb_blocs == 0) { + error_setg(errp, "attribute \"num-blocks\" not specified or zero."); + return; + } + if (pfl->name == NULL) { + error_setg(errp, "attribute \"name\" not specified."); + return; + } + total_len = pfl->sector_len * pfl->nb_blocs; /* These are only used to expose the parameters of each device diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 4f6105cc58..ef71322759 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -600,6 +600,19 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) int ret; Error *local_err = NULL; + if (pfl->sector_len == 0) { + error_setg(errp, "attribute \"sector-length\" not specified or zero."); + return; + } + if (pfl->nb_blocs == 0) { + error_setg(errp, "attribute \"num-blocks\" not specified or zero."); + return; + } + if (pfl->name == NULL) { + error_setg(errp, "attribute \"name\" not specified."); + return; + } + chip_len = pfl->sector_len * pfl->nb_blocs; /* XXX: to be fixed */ #if 0 -- cgit v1.2.3-55-g7522 From 166dbda7e131f7b6540f56c3234bb2f8b23d84c0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Dec 2016 11:10:28 +0100 Subject: scsi-disk: fix VERIFY for scsi-block When a scsi-disk object receives VERIFY command with BYTCHK bit being zero, scsi_block_is_passthrough returns false and finally makes req being proceeded by scsi_block_dma_command. Because scsi_block_dma_command has removed process of VERIFY, QEMU will abort in this function. Reported-by: Junlian Bell Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index a96319138a..bdd1e5f86c 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2157,6 +2157,13 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) DPRINTF("Write %s(sector %" PRId64 ", count %u)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: + /* We get here only for BYTCHK == 0x01 and only for scsi-block. + * As far as DMA is concerned, we can treat it the same as a write; + * scsi_block_do_sgio will send VERIFY commands. + */ if (r->req.cmd.buf[1] & 0xe0) { goto illegal_request; } @@ -2712,7 +2719,7 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) case WRITE_VERIFY_16: /* MMC writing cannot be done via DMA helpers, because it sometimes * involves writing beyond the maximum LBA or to negative LBA (lead-in). - * We might use scsi_disk_dma_reqops as long as no writing commands are + * We might use scsi_block_dma_reqops as long as no writing commands are * seen, but performance usually isn't paramount on optical media. So, * just make scsi-block operate the same as scsi-generic for them. */ -- cgit v1.2.3-55-g7522 From 6053a86fe7bd3d5b07b49dae6c05f2cd0d44e687 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 21 Nov 2016 08:50:04 -0200 Subject: kvmclock: reduce kvmclock difference on migration Check for KVM_CAP_ADJUST_CLOCK capability KVM_CLOCK_TSC_STABLE, which indicates that KVM_GET_CLOCK returns a value as seen by the guest at that moment. For new machine types, use this value rather than reading from guest memory. This reduces kvmclock difference on migration from 5s to 0.1s (when max_downtime == 5s). Signed-off-by: Marcelo Tosatti Message-Id: <20161121105052.598267440@redhat.com> [Add comment explaining what is going on. - Paolo] Signed-off-by: Paolo Bonzini --- hw/i386/kvm/clock.c | 142 +++++++++++++++++++++++++++++++++++++++++++------ include/hw/i386/pc.h | 5 ++ target/i386/kvm.c | 7 +++ target/i386/kvm_i386.h | 1 + 4 files changed, 140 insertions(+), 15 deletions(-) (limited to 'hw') diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 0f75dd385a..ef9d560f9c 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -36,6 +36,13 @@ typedef struct KVMClockState { uint64_t clock; bool clock_valid; + + /* whether machine type supports reliable KVM_GET_CLOCK */ + bool mach_use_reliable_get_clock; + + /* whether the 'clock' value was obtained in a host with + * reliable KVM_GET_CLOCK */ + bool clock_is_reliable; } KVMClockState; struct pvclock_vcpu_time_info { @@ -81,6 +88,60 @@ static uint64_t kvmclock_current_nsec(KVMClockState *s) return nsec + time.system_time; } +static void kvm_update_clock(KVMClockState *s) +{ + struct kvm_clock_data data; + int ret; + + ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); + if (ret < 0) { + fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); + abort(); + } + s->clock = data.clock; + + /* If kvm_has_adjust_clock_stable() is false, KVM_GET_CLOCK returns + * essentially CLOCK_MONOTONIC plus a guest-specific adjustment. This + * can drift from the TSC-based value that is computed by the guest, + * so we need to go through kvmclock_current_nsec(). If + * kvm_has_adjust_clock_stable() is true, and the flags contain + * KVM_CLOCK_TSC_STABLE, then KVM_GET_CLOCK returns a TSC-based value + * and kvmclock_current_nsec() is not necessary. + * + * Here, however, we need not check KVM_CLOCK_TSC_STABLE. This is because: + * + * - if the host has disabled the kvmclock master clock, the guest already + * has protection against time going backwards. This "safety net" is only + * absent when kvmclock is stable; + * + * - therefore, we can replace a check like + * + * if last KVM_GET_CLOCK was not reliable then + * read from memory + * + * with + * + * if last KVM_GET_CLOCK was not reliable && masterclock is enabled + * read from memory + * + * However: + * + * - if kvm_has_adjust_clock_stable() returns false, the left side is + * always true (KVM_GET_CLOCK is never reliable), and the right side is + * unknown (because we don't have data.flags). We must assume it's true + * and read from memory. + * + * - if kvm_has_adjust_clock_stable() returns true, the result of the && + * is always false (masterclock is enabled iff KVM_GET_CLOCK is reliable) + * + * So we can just use this instead: + * + * if !kvm_has_adjust_clock_stable() then + * read from memory + */ + s->clock_is_reliable = kvm_has_adjust_clock_stable(); +} + static void kvmclock_vm_state_change(void *opaque, int running, RunState state) { @@ -91,15 +152,21 @@ static void kvmclock_vm_state_change(void *opaque, int running, if (running) { struct kvm_clock_data data = {}; - uint64_t time_at_migration = kvmclock_current_nsec(s); - - s->clock_valid = false; - /* We can't rely on the migrated clock value, just discard it */ - if (time_at_migration) { - s->clock = time_at_migration; + /* + * If the host where s->clock was read did not support reliable + * KVM_GET_CLOCK, read kvmclock value from memory. + */ + if (!s->clock_is_reliable) { + uint64_t pvclock_via_mem = kvmclock_current_nsec(s); + /* We can't rely on the saved clock value, just discard it */ + if (pvclock_via_mem) { + s->clock = pvclock_via_mem; + } } + s->clock_valid = false; + data.clock = s->clock; ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data); if (ret < 0) { @@ -120,8 +187,6 @@ static void kvmclock_vm_state_change(void *opaque, int running, } } } else { - struct kvm_clock_data data; - int ret; if (s->clock_valid) { return; @@ -129,13 +194,7 @@ static void kvmclock_vm_state_change(void *opaque, int running, kvm_synchronize_all_tsc(); - ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); - if (ret < 0) { - fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); - abort(); - } - s->clock = data.clock; - + kvm_update_clock(s); /* * If the VM is stopped, declare the clock state valid to * avoid re-reading it on next vmsave (which would return @@ -149,25 +208,78 @@ static void kvmclock_realize(DeviceState *dev, Error **errp) { KVMClockState *s = KVM_CLOCK(dev); + kvm_update_clock(s); + qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s); } +static bool kvmclock_clock_is_reliable_needed(void *opaque) +{ + KVMClockState *s = opaque; + + return s->mach_use_reliable_get_clock; +} + +static const VMStateDescription kvmclock_reliable_get_clock = { + .name = "kvmclock/clock_is_reliable", + .version_id = 1, + .minimum_version_id = 1, + .needed = kvmclock_clock_is_reliable_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(clock_is_reliable, KVMClockState), + VMSTATE_END_OF_LIST() + } +}; + +/* + * When migrating, read the clock just before migration, + * so that the guest clock counts during the events + * between: + * + * * vm_stop() + * * + * * pre_save() + * + * This reduces kvmclock difference on migration from 5s + * to 0.1s (when max_downtime == 5s), because sending the + * final pages of memory (which happens between vm_stop() + * and pre_save()) takes max_downtime. + */ +static void kvmclock_pre_save(void *opaque) +{ + KVMClockState *s = opaque; + + kvm_update_clock(s); +} + static const VMStateDescription kvmclock_vmsd = { .name = "kvmclock", .version_id = 1, .minimum_version_id = 1, + .pre_save = kvmclock_pre_save, .fields = (VMStateField[]) { VMSTATE_UINT64(clock, KVMClockState), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &kvmclock_reliable_get_clock, + NULL } }; +static Property kvmclock_properties[] = { + DEFINE_PROP_BOOL("x-mach-use-reliable-get-clock", KVMClockState, + mach_use_reliable_get_clock, true), + DEFINE_PROP_END_OF_LIST(), +}; + static void kvmclock_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = kvmclock_realize; dc->vmsd = &kvmclock_vmsd; + dc->props = kvmclock_properties; } static const TypeInfo kvmclock_info = { diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index b37bc5b139..b22e699c46 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -378,6 +378,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); #define PC_COMPAT_2_7 \ HW_COMPAT_2_7 \ + {\ + .driver = "kvmclock",\ + .property = "x-mach-use-reliable-get-clock",\ + .value = "off",\ + },\ {\ .driver = TYPE_X86_CPU,\ .property = "l3-cache",\ diff --git a/target/i386/kvm.c b/target/i386/kvm.c index f62264a7a8..10a9cd8f7f 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -117,6 +117,13 @@ bool kvm_has_smm(void) return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM); } +bool kvm_has_adjust_clock_stable(void) +{ + int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK); + + return (ret == KVM_CLOCK_TSC_STABLE); +} + bool kvm_allows_irq0_override(void) { return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing(); diff --git a/target/i386/kvm_i386.h b/target/i386/kvm_i386.h index 76079295b2..bfce427f86 100644 --- a/target/i386/kvm_i386.h +++ b/target/i386/kvm_i386.h @@ -17,6 +17,7 @@ bool kvm_allows_irq0_override(void); bool kvm_has_smm(void); +bool kvm_has_adjust_clock_stable(void); void kvm_synchronize_all_tsc(void); void kvm_arch_reset_vcpu(X86CPU *cs); void kvm_arch_do_init_vcpu(X86CPU *cs); -- cgit v1.2.3-55-g7522