From 8b3d26342c4aa171e759e6392fe3b742759d4963 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 25 Aug 2017 16:54:06 -0300 Subject: [PATCH 01/26] xio3130_downstream: Report error if pcie_chassis_add_slot() failed On commit f8cd1b02 ("pci: Convert to realize"), no error_set*() call was added for the pcie_chassis_add_slot() error case. pcie_chassis_add_slot() errors get ignored, making QEMU crash later. e.g.: $ qemu-system-x86_64 -device ioh3420 -device xio3130-downstream qemu-system-x86_64: memory.c:2166: memory_region_del_subregion: Assertion `subregion->container == mr' failed. Aborted (core dumped) Fix it by reporting the error using error_setg(). Fixes: f8cd1b0201c41d88bb97dcafb80348a0e88d8805 Signed-off-by: Eduardo Habkost Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/xio3130_downstream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index e706f36cb7..5a882b0433 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -94,6 +94,7 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp) pcie_chassis_create(s->chassis); rc = pcie_chassis_add_slot(s); if (rc < 0) { + error_setg(errp, "Can't add chassis slot, error %d", rc); goto err_pcie_cap; } From 06592d7e28794dcd93dbd5186910ba8c987453ba Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Sat, 9 Sep 2017 14:22:26 +0800 Subject: [PATCH 02/26] pci: Set err to errp directly rather than through error_propagate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ioh3420_interrupts_init() pass error message to local_err, then propagate it to errp by error_propagate(), which is not necessary. So eliminate it and pass errp directly instead of local_err. Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Signed-off-by: Mao Zhongyi Reviewed-by: Eric Blake Reviewed-by: Marcel Apfelbaum Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/ioh3420.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index da4e5bdf04..5f56a2feb6 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -64,15 +64,13 @@ static uint8_t ioh3420_aer_vector(const PCIDevice *d) static int ioh3420_interrupts_init(PCIDevice *d, Error **errp) { int rc; - Error *local_err = NULL; rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR, IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, - &local_err); + errp); if (rc < 0) { assert(rc == -ENOTSUP); - error_propagate(errp, local_err); } return rc; From 5f9252f7cc12c5cec1b3c6695aca02eb52ea7acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Sep 2017 18:59:23 +0200 Subject: [PATCH 03/26] fw_cfg: add write callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reintroduce the write callback that was removed when write support was removed in commit 023e3148567ac898c7258138f8e86c3c2bb40d07. Contrary to the previous callback implementation, the write_cb callback is called whenever a write happened, so handlers must be ready to handle partial write as necessary. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/vmgenid.c | 2 +- hw/core/loader.c | 2 +- hw/i386/acpi-build.c | 2 +- hw/isa/lpc_ich9.c | 4 ++-- hw/nvram/fw_cfg.c | 14 ++++++++++---- include/hw/nvram/fw_cfg.h | 3 +++ 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c index 2876d8a639..105044f666 100644 --- a/hw/acpi/vmgenid.c +++ b/hw/acpi/vmgenid.c @@ -124,7 +124,7 @@ void vmgenid_add_fw_cfg(VmGenIdState *vms, FWCfgState *s, GArray *guid) fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data, VMGENID_FW_CFG_SIZE); /* Create a read-write fw_cfg file for Address */ - fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL, + fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL, NULL, vms->vmgenid_addr_le, ARRAY_SIZE(vms->vmgenid_addr_le), false); } diff --git a/hw/core/loader.c b/hw/core/loader.c index 4593061445..91669d65aa 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1023,7 +1023,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, } fw_cfg_add_file_callback(fw_cfg, fw_file_name, - fw_callback, callback_opaque, + fw_callback, NULL, callback_opaque, data, rom->datasize, read_only); } return mr; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2af37a9129..73519ab3ac 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2911,7 +2911,7 @@ void acpi_setup(void) build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size); fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE, - acpi_build_update, build_state, + acpi_build_update, NULL, build_state, build_state->rsdp, rsdp_size, true); build_state->rsdp_mr = NULL; } else { diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index ac8416d42b..de8fbb7260 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -402,12 +402,12 @@ void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled) * just link them into fw_cfg here. */ fw_cfg_add_file_callback(fw_cfg, "etc/smi/requested-features", - NULL, NULL, + NULL, NULL, NULL, lpc->smi_guest_features_le, sizeof lpc->smi_guest_features_le, false); fw_cfg_add_file_callback(fw_cfg, "etc/smi/features-ok", - smi_features_ok_callback, lpc, + smi_features_ok_callback, NULL, lpc, &lpc->smi_features_ok, sizeof lpc->smi_features_ok, true); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index e3bd626b8c..753ac0e4ea 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -56,6 +56,7 @@ struct FWCfgEntry { uint8_t *data; void *callback_opaque; FWCfgCallback select_cb; + FWCfgWriteCallback write_cb; }; #define JPG_FILE 0 @@ -370,6 +371,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) dma_memory_read(s->dma_as, dma.address, &e->data[s->cur_offset], len)) { dma.control |= FW_CFG_DMA_CTL_ERROR; + } else if (e->write_cb) { + e->write_cb(e->callback_opaque, s->cur_offset, len); } } @@ -570,6 +573,7 @@ static const VMStateDescription vmstate_fw_cfg = { static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, FWCfgCallback select_cb, + FWCfgWriteCallback write_cb, void *callback_opaque, void *data, size_t len, bool read_only) @@ -584,6 +588,7 @@ static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, s->entries[arch][key].data = data; s->entries[arch][key].len = (uint32_t)len; s->entries[arch][key].select_cb = select_cb; + s->entries[arch][key].write_cb = write_cb; s->entries[arch][key].callback_opaque = callback_opaque; s->entries[arch][key].allow_write = !read_only; } @@ -610,7 +615,7 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key, void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) { - fw_cfg_add_bytes_callback(s, key, NULL, NULL, data, len, true); + fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true); } void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) @@ -737,6 +742,7 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name) void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, FWCfgCallback select_cb, + FWCfgWriteCallback write_cb, void *callback_opaque, void *data, size_t len, bool read_only) { @@ -800,7 +806,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, } fw_cfg_add_bytes_callback(s, FW_CFG_FILE_FIRST + index, - select_cb, + select_cb, write_cb, callback_opaque, data, len, read_only); @@ -815,7 +821,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, size_t len) { - fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true); + fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true); } void *fw_cfg_modify_file(FWCfgState *s, const char *filename, @@ -838,7 +844,7 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, } } /* add new one */ - fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true); + fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true); return NULL; } diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index f50d068563..7ccbae5fba 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -45,6 +45,7 @@ typedef struct FWCfgDmaAccess { } QEMU_PACKED FWCfgDmaAccess; typedef void (*FWCfgCallback)(void *opaque); +typedef void (*FWCfgWriteCallback)(void *opaque, off_t start, size_t len); struct FWCfgState { /*< private >*/ @@ -183,6 +184,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, * @s: fw_cfg device being modified * @filename: name of new fw_cfg file item * @select_cb: callback function when selecting + * @write_cb: callback function after a write * @callback_opaque: argument to be passed into callback function * @data: pointer to start of item data * @len: size of item data @@ -202,6 +204,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, */ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, FWCfgCallback select_cb, + FWCfgWriteCallback write_cb, void *callback_opaque, void *data, size_t len, bool read_only); From 6e43353f10c6688060af0bc26bdfdd4cf9c96ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Sep 2017 18:59:24 +0200 Subject: [PATCH 04/26] hw/misc: add vmcoreinfo device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See docs/specs/vmcoreinfo.txt for details. "etc/vmcoreinfo" fw_cfg entry is added when using "-device vmcoreinfo". Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/vmcoreinfo.txt | 41 +++++++++++++++ hw/misc/Makefile.objs | 1 + hw/misc/vmcoreinfo.c | 96 ++++++++++++++++++++++++++++++++++++ include/hw/misc/vmcoreinfo.h | 46 +++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 docs/specs/vmcoreinfo.txt create mode 100644 hw/misc/vmcoreinfo.c create mode 100644 include/hw/misc/vmcoreinfo.h diff --git a/docs/specs/vmcoreinfo.txt b/docs/specs/vmcoreinfo.txt new file mode 100644 index 0000000000..2868a77142 --- /dev/null +++ b/docs/specs/vmcoreinfo.txt @@ -0,0 +1,41 @@ +================= +VMCoreInfo device +================= + +The `-device vmcoreinfo` will create a fw_cfg entry for a guest to +store dump details. + +etc/vmcoreinfo +************** + +A guest may use this fw_cfg entry to add information details to qemu +dumps. + +The entry of 16 bytes has the following layout, in little-endian:: + +#define VMCOREINFO_FORMAT_NONE 0x0 +#define VMCOREINFO_FORMAT_ELF 0x1 + + struct FWCfgVMCoreInfo { + uint16_t host_format; /* formats host supports */ + uint16_t guest_format; /* format guest supplies */ + uint32_t size; /* size of vmcoreinfo region */ + uint64_t paddr; /* physical address of vmcoreinfo region */ + }; + +Only full write (of 16 bytes) are considered valid for further +processing of entry values. + +A write of 0 in guest_format will disable further processing of +vmcoreinfo entry values & content. + +Format & content +**************** + +As of qemu 2.11, only VMCOREINFO_FORMAT_ELF is supported. + +The entry gives location and size of an ELF note that is appended in +qemu dumps. + +The note format/class must be of the target bitness and the size must +be less than 1Mb. diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e8f0a02f35..19202d90cf 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -9,6 +9,7 @@ common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o common-obj-$(CONFIG_EDU) += edu.o common-obj-y += unimp.o +common-obj-y += vmcoreinfo.o obj-$(CONFIG_VMPORT) += vmport.o diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c new file mode 100644 index 0000000000..a618e12677 --- /dev/null +++ b/hw/misc/vmcoreinfo.c @@ -0,0 +1,96 @@ +/* + * Virtual Machine coreinfo device + * + * Copyright (C) 2017 Red Hat, Inc. + * + * Authors: Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/nvram/fw_cfg.h" +#include "hw/misc/vmcoreinfo.h" + +static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len) +{ + VMCoreInfoState *s = VMCOREINFO(dev); + + s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo) + && s->vmcoreinfo.guest_format != VMCOREINFO_FORMAT_NONE; +} + +static void vmcoreinfo_reset(void *dev) +{ + VMCoreInfoState *s = VMCOREINFO(dev); + + s->has_vmcoreinfo = false; + memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo)); + s->vmcoreinfo.host_format = cpu_to_le16(VMCOREINFO_FORMAT_ELF); +} + +static void vmcoreinfo_realize(DeviceState *dev, Error **errp) +{ + VMCoreInfoState *s = VMCOREINFO(dev); + FWCfgState *fw_cfg = fw_cfg_find(); + + /* Given that this function is executing, there is at least one VMCOREINFO + * device. Check if there are several. + */ + if (!vmcoreinfo_find()) { + error_setg(errp, "at most one %s device is permitted", + VMCOREINFO_DEVICE); + return; + } + + if (!fw_cfg || !fw_cfg->dma_enabled) { + error_setg(errp, "%s device requires fw_cfg with DMA", + VMCOREINFO_DEVICE); + return; + } + + fw_cfg_add_file_callback(fw_cfg, "etc/vmcoreinfo", + NULL, fw_cfg_vmci_write, s, + &s->vmcoreinfo, sizeof(s->vmcoreinfo), false); + + qemu_register_reset(vmcoreinfo_reset, dev); +} + +static const VMStateDescription vmstate_vmcoreinfo = { + .name = "vmcoreinfo", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(has_vmcoreinfo, VMCoreInfoState), + VMSTATE_UINT16(vmcoreinfo.host_format, VMCoreInfoState), + VMSTATE_UINT16(vmcoreinfo.guest_format, VMCoreInfoState), + VMSTATE_UINT32(vmcoreinfo.size, VMCoreInfoState), + VMSTATE_UINT64(vmcoreinfo.paddr, VMCoreInfoState), + VMSTATE_END_OF_LIST() + }, +}; + +static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_vmcoreinfo; + dc->realize = vmcoreinfo_realize; + dc->hotpluggable = false; +} + +static const TypeInfo vmcoreinfo_device_info = { + .name = VMCOREINFO_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VMCoreInfoState), + .class_init = vmcoreinfo_device_class_init, +}; + +static void vmcoreinfo_register_types(void) +{ + type_register_static(&vmcoreinfo_device_info); +} + +type_init(vmcoreinfo_register_types) diff --git a/include/hw/misc/vmcoreinfo.h b/include/hw/misc/vmcoreinfo.h new file mode 100644 index 0000000000..c3aa856545 --- /dev/null +++ b/include/hw/misc/vmcoreinfo.h @@ -0,0 +1,46 @@ +/* + * Virtual Machine coreinfo device + * + * Copyright (C) 2017 Red Hat, Inc. + * + * Authors: Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#ifndef VMCOREINFO_H +#define VMCOREINFO_H + +#include "hw/qdev.h" + +#define VMCOREINFO_DEVICE "vmcoreinfo" +#define VMCOREINFO(obj) OBJECT_CHECK(VMCoreInfoState, (obj), VMCOREINFO_DEVICE) + +#define VMCOREINFO_FORMAT_NONE 0x0 +#define VMCOREINFO_FORMAT_ELF 0x1 + +/* all fields are little-endian */ +typedef struct FWCfgVMCoreInfo { + uint16_t host_format; /* set on reset */ + uint16_t guest_format; + uint32_t size; + uint64_t paddr; +} QEMU_PACKED FWCfgVMCoreInfo; + +typedef struct VMCoreInfoState { + DeviceClass parent_obj; + + bool has_vmcoreinfo; + FWCfgVMCoreInfo vmcoreinfo; +} VMCoreInfoState; + +/* returns NULL unless there is exactly one device */ +static inline VMCoreInfoState *vmcoreinfo_find(void) +{ + Object *o = object_resolve_path_type("", VMCOREINFO_DEVICE, NULL); + + return o ? VMCOREINFO(o) : NULL; +} + +#endif From 903ef7349699dcd932b5981b85c1f1ebe4a4bf2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Sep 2017 18:59:25 +0200 Subject: [PATCH 05/26] dump: add guest ELF note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read the guest ELF PT_NOTE from guest memory when fw_cfg etc/vmcoreinfo entry provides the location, and write it as an additional note in the dump. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- dump.c | 107 ++++++++++++++++++++++++++++++++++++++++++ include/sysemu/dump.h | 2 + 2 files changed, 109 insertions(+) diff --git a/dump.c b/dump.c index 7ebcf553b2..1479f1f04e 100644 --- a/dump.c +++ b/dump.c @@ -25,6 +25,8 @@ #include "qapi/qmp/qerror.h" #include "qmp-commands.h" #include "qapi-event.h" +#include "qemu/error-report.h" +#include "hw/misc/vmcoreinfo.h" #include #ifdef CONFIG_LZO @@ -37,6 +39,13 @@ #define ELF_MACHINE_UNAME "Unknown" #endif +#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */ + +#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \ + ((DIV_ROUND_UP((hdr_size), 4) + \ + DIV_ROUND_UP((name_size), 4) + \ + DIV_ROUND_UP((desc_size), 4)) * 4) + uint16_t cpu_to_dump16(DumpState *s, uint16_t val) { if (s->dump_info.d_endian == ELFDATA2LSB) { @@ -75,6 +84,8 @@ static int dump_cleanup(DumpState *s) guest_phys_blocks_free(&s->guest_phys_blocks); memory_mapping_list_free(&s->list); close(s->fd); + g_free(s->guest_note); + s->guest_note = NULL; if (s->resume) { if (s->detached) { qemu_mutex_lock_iothread(); @@ -234,6 +245,19 @@ static inline int cpu_index(CPUState *cpu) return cpu->cpu_index + 1; } +static void write_guest_note(WriteCoreDumpFunction f, DumpState *s, + Error **errp) +{ + int ret; + + if (s->guest_note) { + ret = f(s->guest_note, s->guest_note_size, s); + if (ret < 0) { + error_setg(errp, "dump: failed to write guest note"); + } + } +} + static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, Error **errp) { @@ -257,6 +281,8 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, return; } } + + write_guest_note(f, s, errp); } static void write_elf32_note(DumpState *s, Error **errp) @@ -302,6 +328,8 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, return; } } + + write_guest_note(f, s, errp); } static void write_elf_section(DumpState *s, int type, Error **errp) @@ -713,6 +741,44 @@ static int buf_write_note(const void *buf, size_t size, void *opaque) return 0; } +/* + * This function retrieves various sizes from an elf header. + * + * @note has to be a valid ELF note. The return sizes are unmodified + * (not padded or rounded up to be multiple of 4). + */ +static void get_note_sizes(DumpState *s, const void *note, + uint64_t *note_head_size, + uint64_t *name_size, + uint64_t *desc_size) +{ + uint64_t note_head_sz; + uint64_t name_sz; + uint64_t desc_sz; + + if (s->dump_info.d_class == ELFCLASS64) { + const Elf64_Nhdr *hdr = note; + note_head_sz = sizeof(Elf64_Nhdr); + name_sz = tswap64(hdr->n_namesz); + desc_sz = tswap64(hdr->n_descsz); + } else { + const Elf32_Nhdr *hdr = note; + note_head_sz = sizeof(Elf32_Nhdr); + name_sz = tswap32(hdr->n_namesz); + desc_sz = tswap32(hdr->n_descsz); + } + + if (note_head_size) { + *note_head_size = note_head_sz; + } + if (name_size) { + *name_size = name_sz; + } + if (desc_size) { + *desc_size = desc_sz; + } +} + /* write common header, sub header and elf note to vmcore */ static void create_header32(DumpState *s, Error **errp) { @@ -1491,6 +1557,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, DumpGuestMemoryFormat format, bool paging, bool has_filter, int64_t begin, int64_t length, Error **errp) { + VMCoreInfoState *vmci = vmcoreinfo_find(); CPUState *cpu; int nr_cpus; Error *err = NULL; @@ -1568,6 +1635,46 @@ static void dump_init(DumpState *s, int fd, bool has_format, goto cleanup; } + /* + * The goal of this block is to copy the guest note out of + * the guest. Failure to do so is not fatal for dumping. + */ + if (vmci) { + uint64_t addr, note_head_size, name_size, desc_size; + uint32_t size; + uint16_t format; + + note_head_size = s->dump_info.d_class == ELFCLASS32 ? + sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr); + + format = le16_to_cpu(vmci->vmcoreinfo.guest_format); + size = le32_to_cpu(vmci->vmcoreinfo.size); + addr = le64_to_cpu(vmci->vmcoreinfo.paddr); + if (!vmci->has_vmcoreinfo) { + warn_report("guest note is not present"); + } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) { + warn_report("guest note size is invalid: %" PRIu32, size); + } else if (format != VMCOREINFO_FORMAT_ELF) { + warn_report("guest note format is unsupported: %" PRIu16, format); + } else { + s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */ + cpu_physical_memory_read(addr, s->guest_note, size); + + get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size); + s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size, + desc_size); + if (name_size > MAX_GUEST_NOTE_SIZE || + desc_size > MAX_GUEST_NOTE_SIZE || + s->guest_note_size > size) { + warn_report("Invalid guest note header"); + g_free(s->guest_note); + s->guest_note = NULL; + } else { + s->note_size += s->guest_note_size; + } + } + } + /* get memory mapping */ if (paging) { qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err); diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 2672a15f8b..df43bd0e07 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -192,6 +192,8 @@ typedef struct DumpState { * this could be used to calculate * how much work we have * finished. */ + uint8_t *guest_note; /* ELF note content */ + size_t guest_note_size; } DumpState; uint16_t cpu_to_dump16(DumpState *s, uint16_t val); From d9feb51772b4ade9700c7fa54529327a6c8183a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Sep 2017 18:59:26 +0200 Subject: [PATCH 06/26] dump: update phys_base header field based on VMCOREINFO content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the guest note is VMCOREINFO, try to get phys_base from it. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/vmcoreinfo.txt | 8 ++++++ dump.c | 56 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/docs/specs/vmcoreinfo.txt b/docs/specs/vmcoreinfo.txt index 2868a77142..821261067f 100644 --- a/docs/specs/vmcoreinfo.txt +++ b/docs/specs/vmcoreinfo.txt @@ -39,3 +39,11 @@ qemu dumps. The note format/class must be of the target bitness and the size must be less than 1Mb. + +If the ELF note name is "VMCOREINFO", it is expected to be the Linux +vmcoreinfo note (see Documentation/ABI/testing/sysfs-kernel-vmcoreinfo +in Linux source). In this case, qemu dump code will read the content +as a key=value text file, looking for "NUMBER(phys_base)" key +value. The value is expected to be more accurate than architecture +guess of the value. This is useful for KASLR-enabled guest with +ancient tools not handling the VMCOREINFO note. diff --git a/dump.c b/dump.c index 1479f1f04e..5674512416 100644 --- a/dump.c +++ b/dump.c @@ -779,6 +779,23 @@ static void get_note_sizes(DumpState *s, const void *note, } } +static bool note_name_equal(DumpState *s, + const uint8_t *note, const char *name) +{ + int len = strlen(name) + 1; + uint64_t head_size, name_size; + + get_note_sizes(s, note, &head_size, &name_size, NULL); + head_size = ROUND_UP(head_size, 4); + + if (name_size != len || + memcmp(note + head_size, "VMCOREINFO", len)) { + return false; + } + + return true; +} + /* write common header, sub header and elf note to vmcore */ static void create_header32(DumpState *s, Error **errp) { @@ -1553,6 +1570,39 @@ static int64_t dump_calculate_size(DumpState *s) return total; } +static void vmcoreinfo_update_phys_base(DumpState *s) +{ + uint64_t size, note_head_size, name_size, phys_base; + char **lines; + uint8_t *vmci; + size_t i; + + if (!note_name_equal(s, s->guest_note, "VMCOREINFO")) { + return; + } + + get_note_sizes(s, s->guest_note, ¬e_head_size, &name_size, &size); + note_head_size = ROUND_UP(note_head_size, 4); + + vmci = s->guest_note + note_head_size + ROUND_UP(name_size, 4); + *(vmci + size) = '\0'; + + lines = g_strsplit((char *)vmci, "\n", -1); + for (i = 0; lines[i]; i++) { + if (g_str_has_prefix(lines[i], "NUMBER(phys_base)=")) { + if (qemu_strtou64(lines[i] + 18, NULL, 16, + &phys_base) < 0) { + warn_report("Failed to read NUMBER(phys_base)="); + } else { + s->dump_info.phys_base = phys_base; + } + break; + } + } + + g_strfreev(lines); +} + static void dump_init(DumpState *s, int fd, bool has_format, DumpGuestMemoryFormat format, bool paging, bool has_filter, int64_t begin, int64_t length, Error **errp) @@ -1636,8 +1686,9 @@ static void dump_init(DumpState *s, int fd, bool has_format, } /* - * The goal of this block is to copy the guest note out of - * the guest. Failure to do so is not fatal for dumping. + * The goal of this block is to (a) update the previously guessed + * phys_base, (b) copy the guest note out of the guest. + * Failure to do so is not fatal for dumping. */ if (vmci) { uint64_t addr, note_head_size, name_size, desc_size; @@ -1670,6 +1721,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, g_free(s->guest_note); s->guest_note = NULL; } else { + vmcoreinfo_update_phys_base(s); s->note_size += s->guest_note_size; } } From 9ada575bbafaf6d3724a7f59df9da89776817cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Sep 2017 18:59:27 +0200 Subject: [PATCH 07/26] kdump: set vmcoreinfo location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kdump header provides offset and size of the vmcoreinfo content, append it if available (skip the ELF note header). crash-7.1.9 was the first version that started looking in the vmcoreinfo data for phys_base instead of in the kdump_sub_header. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- dump.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dump.c b/dump.c index 5674512416..d4a8c942eb 100644 --- a/dump.c +++ b/dump.c @@ -857,6 +857,18 @@ static void create_header32(DumpState *s, Error **errp) kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; + if (s->guest_note && + note_name_equal(s, s->guest_note, "VMCOREINFO")) { + uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo; + + get_note_sizes(s, s->guest_note, + &hsize, &name_size, &size_vmcoreinfo_desc); + offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size + + (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4; + kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo); + kh->size_vmcoreinfo = cpu_to_dump32(s, size_vmcoreinfo_desc); + } + kh->offset_note = cpu_to_dump64(s, offset_note); kh->note_size = cpu_to_dump32(s, s->note_size); @@ -957,6 +969,18 @@ static void create_header64(DumpState *s, Error **errp) kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; + if (s->guest_note && + note_name_equal(s, s->guest_note, "VMCOREINFO")) { + uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo; + + get_note_sizes(s, s->guest_note, + &hsize, &name_size, &size_vmcoreinfo_desc); + offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size + + (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4; + kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo); + kh->size_vmcoreinfo = cpu_to_dump64(s, size_vmcoreinfo_desc); + } + kh->offset_note = cpu_to_dump64(s, offset_note); kh->note_size = cpu_to_dump64(s, s->note_size); From d23bfa91b7789534d16ede6cb7d925bfac3f3c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Sep 2017 18:59:28 +0200 Subject: [PATCH 08/26] scripts/dump-guest-memory.py: add vmcoreinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a vmcoreinfo ELF note in the dump if vmcoreinfo device has the memory location details. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- scripts/dump-guest-memory.py | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py index f7c6635f15..69dd5efadf 100644 --- a/scripts/dump-guest-memory.py +++ b/scripts/dump-guest-memory.py @@ -14,6 +14,7 @@ the COPYING file in the top-level directory. """ import ctypes +import struct UINTPTR_T = gdb.lookup_type("uintptr_t") @@ -45,6 +46,17 @@ EM_S390 = 22 EM_AARCH = 183 EM_X86_64 = 62 +VMCOREINFO_FORMAT_ELF = 1 + +def le16_to_cpu(val): + return struct.unpack(" 1 << 20: + print('warning: invalid vmcoreinfo size') + return + # now get the full note + note = get_arch_note(self.endianness, + header.n_namesz - 1, header.n_descsz) + ctypes.memmove(ctypes.pointer(note), vmcoreinfo, ctypes.sizeof(note)) + + self.notes.append(note) + self.segments[0].p_filesz += ctypes.sizeof(note) + self.segments[0].p_memsz += ctypes.sizeof(note) + def add_segment(self, p_type, p_paddr, p_size): """Adds a segment to the elf.""" @@ -505,6 +536,35 @@ shape and this command should mostly work.""" cur += chunk_size left -= chunk_size + def phys_memory_read(self, addr, size): + qemu_core = gdb.inferiors()[0] + for block in self.guest_phys_blocks: + if block["target_start"] <= addr \ + and addr + size <= block["target_end"]: + haddr = block["host_addr"] + (addr - block["target_start"]) + return qemu_core.read_memory(haddr, size) + return None + + def add_vmcoreinfo(self): + if not gdb.parse_and_eval("vmcoreinfo_find()") \ + or not gdb.parse_and_eval("vmcoreinfo_find()->has_vmcoreinfo"): + return + + fmt = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.guest_format") + addr = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.paddr") + size = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.size") + + fmt = le16_to_cpu(fmt) + addr = le64_to_cpu(addr) + size = le32_to_cpu(size) + + if fmt != VMCOREINFO_FORMAT_ELF: + return + + vmcoreinfo = self.phys_memory_read(addr, size) + if vmcoreinfo: + self.elf.add_vmcoreinfo_note(vmcoreinfo.tobytes()) + def invoke(self, args, from_tty): """Handles command invocation from gdb.""" @@ -518,6 +578,7 @@ shape and this command should mostly work.""" self.elf = ELF(argv[1]) self.guest_phys_blocks = get_guest_phys_blocks() + self.add_vmcoreinfo() with open(argv[0], "wb") as vmcore: self.dump_init(vmcore) From 3505a22bcb6a220545894264b3dacbb164a0669b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Sep 2017 18:59:29 +0200 Subject: [PATCH 09/26] MAINTAINERS: add Dump maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proposing myself, since I have some familiarity with the code now. Signed-off-by: Marc-André Lureau Acked-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 772ac209e1..9cff9737d3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1317,6 +1317,17 @@ S: Maintained F: device_tree.c F: include/sysemu/device_tree.h +Dump +S: Supported +M: Marc-André Lureau +F: dump.c +F: hw/misc/vmcoreinfo.c +F: include/hw/misc/vmcoreinfo.h +F: include/sysemu/dump-arch.h +F: include/sysemu/dump.h +F: scripts/dump-guest-memory.py +F: stubs/dump.c + Error reporting M: Markus Armbruster S: Supported From 5c0ba1be37181bd8a7c96c7f81b19ae5f8e66e2d Mon Sep 17 00:00:00 2001 From: Felipe Franciosi Date: Wed, 20 Sep 2017 11:53:06 -0700 Subject: [PATCH 10/26] virtio/vhost: reset dev->log after syncing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost_log_put() is called to decomission the dirty log between qemu and a vhost device when stopping the device. Such a call can happen from migration_completion(). Present code sets dev->log_size to zero too early in vhost_log_put(), causing the sync check to always return false. As a consequence, the last pass on the dirty bitmap never happens at the end of migration. If a vhost device was busy (writing to guest memory) until the last moments before vhost_virtqueue_stop(), this error will result in guest memory corruption (at least) following migrations. Signed-off-by: Felipe Franciosi Acked-by: Jason Wang Reviewed-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 5fd69f0b2e..ddc42f0f93 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -375,8 +375,6 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync) if (!log) { return; } - dev->log = NULL; - dev->log_size = 0; --log->refcnt; if (log->refcnt == 0) { @@ -396,6 +394,9 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync) g_free(log); } + + dev->log = NULL; + dev->log_size = 0; } static bool vhost_dev_log_is_shared(struct vhost_dev *dev) From 9cd1e97a7ae2856ec00b5682db0dea17f42fc734 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 22 Sep 2017 13:18:31 +0100 Subject: [PATCH 11/26] pci: allow 32-bit PCI IO accesses to pass through the PCI bridge Whilst the underlying PCI bridge implementation supports 32-bit PCI IO accesses, unfortunately they are truncated at the legacy 64K limit. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci_bridge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 17feae5ed8..a47d257149 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -379,7 +379,8 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename) sec_bus->address_space_mem = &br->address_space_mem; memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX); sec_bus->address_space_io = &br->address_space_io; - memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", 65536); + memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", + UINT32_MAX); br->windows = pci_bridge_region_init(br); QLIST_INIT(&sec_bus->child); QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); From d659d94013390238961fac741572306c95496bf5 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezzubikov Date: Mon, 25 Sep 2017 02:21:58 +0300 Subject: [PATCH 12/26] hw/pci-bridge/pcie_pci_bridge: properly handle MSI unavailability case QEMU with the pcie-pci-bridge device crashes if the guest board doesn't support MSI, e.g. 'qemu-system-ppc64 -M prep -device pcie-pci-bridge'. This is caused by wrong pcie-pci-bridge instantiation error handling. This patch fixes this issue by falling back to legacy INTx if MSI is not available. Also set the bridge's 'msi' property default value to 'auto' in order to trigger errors only when user explicitly set msi=on. Reported-by: Eduardo Habkost Signed-off-by: Aleksandr Bezzubikov Reviewed-by: Marcel Apfelbaum Tested-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/pcie_pci_bridge.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c index 9aa5cc3e45..da562fe041 100644 --- a/hw/pci-bridge/pcie_pci_bridge.c +++ b/hw/pci-bridge/pcie_pci_bridge.c @@ -65,10 +65,18 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp) goto aer_error; } + Error *local_err = NULL; if (pcie_br->msi != ON_OFF_AUTO_OFF) { - rc = msi_init(d, 0, 1, true, true, errp); + rc = msi_init(d, 0, 1, true, true, &local_err); if (rc < 0) { - goto msi_error; + assert(rc == -ENOTSUP); + if (pcie_br->msi != ON_OFF_AUTO_ON) { + error_free(local_err); + } else { + /* failed to satisfy user's explicit request for MSI */ + error_propagate(errp, local_err); + goto msi_error; + } } } pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | @@ -81,7 +89,7 @@ aer_error: pm_error: pcie_cap_exit(d); cap_error: - shpc_free(d); + shpc_cleanup(d, &pcie_br->shpc_bar); error: pci_bridge_exitfn(d); } @@ -98,7 +106,9 @@ static void pcie_pci_bridge_reset(DeviceState *qdev) { PCIDevice *d = PCI_DEVICE(qdev); pci_bridge_reset(qdev); - msi_reset(d); + if (msi_present(d)) { + msi_reset(d); + } shpc_reset(d); } @@ -106,12 +116,14 @@ static void pcie_pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_bridge_write_config(d, address, val, len); - msi_write_config(d, address, val, len); + if (msi_present(d)) { + msi_write_config(d, address, val, len); + } shpc_cap_write_config(d, address, val, len); } static Property pcie_pci_bridge_dev_properties[] = { - DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_ON), + DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_AUTO), DEFINE_PROP_END_OF_LIST(), }; From b81b948ecc8659d78066f374c787ed12379d21dd Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 25 Sep 2017 17:05:17 +0100 Subject: [PATCH 13/26] virtio/pci/migration: Convert to VMState Convert the 'modern_state' part of virtio-pci to modern migration macros. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 108 +++++++++++------------------------------ 1 file changed, 27 insertions(+), 81 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 8b0d6b69cd..f825a68a84 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -88,77 +88,19 @@ static void virtio_pci_save_config(DeviceState *d, QEMUFile *f) qemu_put_be16(f, vdev->config_vector); } -static void virtio_pci_load_modern_queue_state(VirtIOPCIQueue *vq, - QEMUFile *f) -{ - vq->num = qemu_get_be16(f); - vq->enabled = qemu_get_be16(f); - vq->desc[0] = qemu_get_be32(f); - vq->desc[1] = qemu_get_be32(f); - vq->avail[0] = qemu_get_be32(f); - vq->avail[1] = qemu_get_be32(f); - vq->used[0] = qemu_get_be32(f); - vq->used[1] = qemu_get_be32(f); -} - -static bool virtio_pci_has_extra_state(DeviceState *d) -{ - VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - - return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA; -} - -static int get_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size, - VMStateField *field) -{ - VirtIOPCIProxy *proxy = pv; - int i; - - proxy->dfselect = qemu_get_be32(f); - proxy->gfselect = qemu_get_be32(f); - proxy->guest_features[0] = qemu_get_be32(f); - proxy->guest_features[1] = qemu_get_be32(f); - for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - virtio_pci_load_modern_queue_state(&proxy->vqs[i], f); +static const VMStateDescription vmstate_virtio_pci_modern_queue_state = { + .name = "virtio_pci/modern_queue_state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT16(num, VirtIOPCIQueue), + VMSTATE_UNUSED(1), /* enabled was stored as be16 */ + VMSTATE_BOOL(enabled, VirtIOPCIQueue), + VMSTATE_UINT32_ARRAY(desc, VirtIOPCIQueue, 2), + VMSTATE_UINT32_ARRAY(avail, VirtIOPCIQueue, 2), + VMSTATE_UINT32_ARRAY(used, VirtIOPCIQueue, 2), + VMSTATE_END_OF_LIST() } - - return 0; -} - -static void virtio_pci_save_modern_queue_state(VirtIOPCIQueue *vq, - QEMUFile *f) -{ - qemu_put_be16(f, vq->num); - qemu_put_be16(f, vq->enabled); - qemu_put_be32(f, vq->desc[0]); - qemu_put_be32(f, vq->desc[1]); - qemu_put_be32(f, vq->avail[0]); - qemu_put_be32(f, vq->avail[1]); - qemu_put_be32(f, vq->used[0]); - qemu_put_be32(f, vq->used[1]); -} - -static int put_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size, - VMStateField *field, QJSON *vmdesc) -{ - VirtIOPCIProxy *proxy = pv; - int i; - - qemu_put_be32(f, proxy->dfselect); - qemu_put_be32(f, proxy->gfselect); - qemu_put_be32(f, proxy->guest_features[0]); - qemu_put_be32(f, proxy->guest_features[1]); - for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - virtio_pci_save_modern_queue_state(&proxy->vqs[i], f); - } - - return 0; -} - -static const VMStateInfo vmstate_info_virtio_pci_modern_state = { - .name = "virtqueue_state", - .get = get_virtio_pci_modern_state, - .put = put_virtio_pci_modern_state, }; static bool virtio_pci_modern_state_needed(void *opaque) @@ -168,21 +110,18 @@ static bool virtio_pci_modern_state_needed(void *opaque) return virtio_pci_modern(proxy); } -static const VMStateDescription vmstate_virtio_pci_modern_state = { +static const VMStateDescription vmstate_virtio_pci_modern_state_sub = { .name = "virtio_pci/modern_state", .version_id = 1, .minimum_version_id = 1, .needed = &virtio_pci_modern_state_needed, .fields = (VMStateField[]) { - { - .name = "modern_state", - .version_id = 0, - .field_exists = NULL, - .size = 0, - .info = &vmstate_info_virtio_pci_modern_state, - .flags = VMS_SINGLE, - .offset = 0, - }, + VMSTATE_UINT32(dfselect, VirtIOPCIProxy), + VMSTATE_UINT32(gfselect, VirtIOPCIProxy), + VMSTATE_UINT32_ARRAY(guest_features, VirtIOPCIProxy, 2), + VMSTATE_STRUCT_ARRAY(vqs, VirtIOPCIProxy, VIRTIO_QUEUE_MAX, 0, + vmstate_virtio_pci_modern_queue_state, + VirtIOPCIQueue), VMSTATE_END_OF_LIST() } }; @@ -196,11 +135,18 @@ static const VMStateDescription vmstate_virtio_pci = { VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription*[]) { - &vmstate_virtio_pci_modern_state, + &vmstate_virtio_pci_modern_state_sub, NULL } }; +static bool virtio_pci_has_extra_state(DeviceState *d) +{ + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + + return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA; +} + static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); From a6c242aaf52409ea827665e6f5f84b446d17a859 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 15 Aug 2017 15:44:17 +0100 Subject: [PATCH 14/26] PCI: PCIe access should always be little endian PCIe busses are always little endian, so set the endianness of the memory region to little endian rather than native such that operations work as expected on big endian targets. Signed-off-by: Matt Redfearn Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c index dcebf57ed4..553db56778 100644 --- a/hw/pci/pcie_host.c +++ b/hw/pci/pcie_host.c @@ -81,7 +81,7 @@ static uint64_t pcie_mmcfg_data_read(void *opaque, static const MemoryRegionOps pcie_mmcfg_ops = { .read = pcie_mmcfg_data_read, .write = pcie_mmcfg_data_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void pcie_host_init(Object *obj) From 619f02aefc587e5e2821cd84b584eba199c97c9e Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 27 Sep 2017 16:56:31 -0300 Subject: [PATCH 15/26] pci: conventional-pci-device and pci-express-device interfaces Those two interfaces will be used to indicate which device types support Conventional PCI or PCI Express buses. Management software will be able to use the qom-list-types QMP command to query that information. Signed-off-by: Eduardo Habkost Reviewed-by: David Gibson Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 12 ++++++++++++ include/hw/pci/pci.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 1e6fb88eba..1b08e18205 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -170,6 +170,16 @@ static const TypeInfo pci_bus_info = { .class_init = pci_bus_class_init, }; +static const TypeInfo pcie_interface_info = { + .name = INTERFACE_PCIE_DEVICE, + .parent = TYPE_INTERFACE, +}; + +static const TypeInfo conventional_pci_interface_info = { + .name = INTERFACE_CONVENTIONAL_PCI_DEVICE, + .parent = TYPE_INTERFACE, +}; + static const TypeInfo pcie_bus_info = { .name = TYPE_PCIE_BUS, .parent = TYPE_PCI_BUS, @@ -2667,6 +2677,8 @@ static void pci_register_types(void) { type_register_static(&pci_bus_info); type_register_static(&pcie_bus_info); + type_register_static(&conventional_pci_interface_info); + type_register_static(&pcie_interface_info); type_register_static(&pci_device_type_info); } diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index aa7ef9cf69..8d02a0a383 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -198,6 +198,12 @@ enum { #define PCI_DEVICE_GET_CLASS(obj) \ OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) +/* Implemented by devices that can be plugged on PCI Express buses */ +#define INTERFACE_PCIE_DEVICE "pci-express-device" + +/* Implemented by devices that can be plugged on Conventional PCI buses */ +#define INTERFACE_CONVENTIONAL_PCI_DEVICE "conventional-pci-device" + typedef struct PCIINTxRoute { enum { PCI_INTX_ENABLED, From a5fa336f11a1eddad9f2be6506e59ba50ed81818 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 27 Sep 2017 16:56:32 -0300 Subject: [PATCH 16/26] pci: Add interface names to hybrid PCI devices The following devices support both PCI Express and Conventional PCI, by including special code to handle the QEMU_PCI_CAP_EXPRESS flag and/or conditional pcie_endpoint_cap_init() calls: * vfio-pci (is_express=1, but legacy PCI handled by vfio_populate_device()) * vmxnet3 (is_express=0, but PCIe handled by vmxnet3_realize()) * pvscsi (is_express=0, but PCIe handled by pvscsi_realize()) * virtio-pci (is_express=0, but PCIe handled by virtio_pci_dc_realize(), and additional legacy PCI code at virtio_pci_realize()) * base-xhci (is_express=1, but pcie_endpoint_cap_init() call is conditional on pci_bus_is_express(dev->bus) * Note that xhci does not clear QEMU_PCI_CAP_EXPRESS like the other hybrid devices Cc: Dmitry Fleytman Cc: Jason Wang Cc: Paolo Bonzini Cc: Gerd Hoffmann Cc: Alex Williamson Cc: "Michael S. Tsirkin" Signed-off-by: Eduardo Habkost Reviewed-by: David Gibson Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/vmxnet3.c | 5 +++++ hw/scsi/vmw_pvscsi.c | 2 ++ hw/usb/hcd-xhci.c | 5 +++++ hw/vfio/pci.c | 5 +++++ hw/virtio/virtio-pci.c | 5 +++++ 5 files changed, 22 insertions(+) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index b43b58be2b..8c4bae5394 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2653,6 +2653,11 @@ static const TypeInfo vmxnet3_info = { .instance_size = sizeof(VMXNET3State), .class_init = vmxnet3_class_init, .instance_init = vmxnet3_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { } + }, }; static void vmxnet3_register_types(void) diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index d8079158ac..d564e5caff 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1302,6 +1302,8 @@ static const TypeInfo pvscsi_info = { .class_init = pvscsi_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, + { INTERFACE_PCIE_DEVICE }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } }; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index d75c085d94..af3a9d88de 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3670,6 +3670,11 @@ static const TypeInfo xhci_info = { .instance_size = sizeof(XHCIState), .class_init = xhci_class_init, .abstract = true, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { } + }, }; static void qemu_xhci_class_init(ObjectClass *klass, void *data) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 9e86db7c3b..c977ee327f 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3036,6 +3036,11 @@ static const TypeInfo vfio_pci_dev_info = { .class_init = vfio_pci_dev_class_init, .instance_init = vfio_instance_init, .instance_finalize = vfio_instance_finalize, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { } + }, }; static void register_vfio_pci_dev_type(void) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index f825a68a84..6c60aa0f51 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1904,6 +1904,11 @@ static const TypeInfo virtio_pci_info = { .class_init = virtio_pci_class_init, .class_size = sizeof(VirtioPCIClass), .abstract = true, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { } + }, }; /* virtio-blk-pci */ From 71d787677d0cacea846dc851c3e56ad076d59c04 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 27 Sep 2017 16:56:33 -0300 Subject: [PATCH 17/26] pci: Add INTERFACE_PCIE_DEVICE to all PCIe devices Change all devices that set is_express=1 to implement INTERFACE_PCIE_DEVICE. Cc: Keith Busch Cc: Kevin Wolf Cc: Max Reitz Cc: Dmitry Fleytman Cc: Jason Wang Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Cc: Paul Burton Cc: Paolo Bonzini Cc: Hannes Reinecke Cc: qemu-block@nongnu.org Reviewed-by: Alistair Francis Signed-off-by: Eduardo Habkost Reviewed-by: David Gibson Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/nvme.c | 4 ++++ hw/net/e1000e.c | 4 ++++ hw/pci-bridge/pcie_pci_bridge.c | 1 + hw/pci-bridge/pcie_root_port.c | 4 ++++ hw/pci-bridge/xio3130_downstream.c | 4 ++++ hw/pci-bridge/xio3130_upstream.c | 4 ++++ hw/pci-host/xilinx-pcie.c | 4 ++++ hw/scsi/megasas.c | 6 ++++++ 8 files changed, 31 insertions(+) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 9aa32692a3..441e21ed1f 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1110,6 +1110,10 @@ static const TypeInfo nvme_info = { .instance_size = sizeof(NvmeCtrl), .class_init = nvme_class_init, .instance_init = nvme_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { } + }, }; static void nvme_register_types(void) diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 744f0f3b91..f1af279e8d 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -710,6 +710,10 @@ static const TypeInfo e1000e_info = { .instance_size = sizeof(E1000EState), .class_init = e1000e_class_init, .instance_init = e1000e_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { } + }, }; static void e1000e_register_types(void) diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c index da562fe041..a4d827c99d 100644 --- a/hw/pci-bridge/pcie_pci_bridge.c +++ b/hw/pci-bridge/pcie_pci_bridge.c @@ -192,6 +192,7 @@ static const TypeInfo pcie_pci_bridge_info = { .class_init = pcie_pci_bridge_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, + { INTERFACE_PCIE_DEVICE }, { }, } }; diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index 4d588cb22e..9b6e4ce512 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -161,6 +161,10 @@ static const TypeInfo rp_info = { .class_init = rp_class_init, .abstract = true, .class_size = sizeof(PCIERootPortClass), + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { } + }, }; static void rp_register_types(void) diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 5a882b0433..1e09d2afb7 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -196,6 +196,10 @@ static const TypeInfo xio3130_downstream_info = { .name = "xio3130-downstream", .parent = TYPE_PCIE_SLOT, .class_init = xio3130_downstream_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { } + }, }; static void xio3130_downstream_register_types(void) diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index a052224bbf..227997ce46 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -166,6 +166,10 @@ static const TypeInfo xio3130_upstream_info = { .name = "x3130-upstream", .parent = TYPE_PCIE_PORT, .class_init = xio3130_upstream_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { } + }, }; static void xio3130_upstream_register_types(void) diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c index 4613dda1d2..7659253090 100644 --- a/hw/pci-host/xilinx-pcie.c +++ b/hw/pci-host/xilinx-pcie.c @@ -317,6 +317,10 @@ static const TypeInfo xilinx_pcie_root_info = { .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(XilinxPCIERoot), .class_init = xilinx_pcie_root_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { } + }, }; static void xilinx_pcie_register(void) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 0db68aacee..535ee267c3 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2451,6 +2451,7 @@ typedef struct MegasasInfo { int osts; const VMStateDescription *vmsd; Property *props; + InterfaceInfo *interfaces; } MegasasInfo; static struct MegasasInfo megasas_devices[] = { @@ -2480,6 +2481,10 @@ static struct MegasasInfo megasas_devices[] = { .is_express = true, .vmsd = &vmstate_megasas_gen2, .props = megasas_properties_gen2, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { } + }, } }; @@ -2531,6 +2536,7 @@ static void megasas_register_types(void) type_info.parent = TYPE_MEGASAS_BASE; type_info.class_data = (void *)info; type_info.class_init = megasas_class_init; + type_info.interfaces = info->interfaces; type_register(&type_info); } From fd3b02c8896d597dd8b9e053dec579cf0386aee1 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 27 Sep 2017 16:56:34 -0300 Subject: [PATCH 18/26] pci: Add INTERFACE_CONVENTIONAL_PCI_DEVICE to Conventional PCI devices Add INTERFACE_CONVENTIONAL_PCI_DEVICE to all direct subtypes of TYPE_PCI_DEVICE, except: 1) The ones that already have INTERFACE_PCIE_DEVICE set: * base-xhci * e1000e * nvme * pvscsi * vfio-pci * virtio-pci * vmxnet3 2) base-pci-bridge Not all PCI bridges are Conventional PCI devices, so INTERFACE_CONVENTIONAL_PCI_DEVICE is added only to the subtypes that are actually Conventional PCI: * dec-21154-p2p-bridge * i82801b11-bridge * pbm-bridge * pci-bridge The direct subtypes of base-pci-bridge not touched by this patch are: * xilinx-pcie-root: Already marked as PCIe-only. * pcie-pci-bridge: Already marked as PCIe-only. * pcie-port: all non-abstract subtypes of pcie-port are already marked as PCIe-only devices. 3) megasas-base Not all megasas devices are Conventional PCI devices, so the interface names are added to the subclasses registered by megasas_register_types(), according to information in the megasas_devices[] array. "megasas-gen2" already implements INTERFACE_PCIE_DEVICE, so add INTERFACE_CONVENTIONAL_PCI_DEVICE only to "megasas". Acked-by: Alberto Garcia Acked-by: John Snow Acked-by: Anthony PERARD Signed-off-by: Eduardo Habkost Reviewed-by: David Gibson Acked-by: David Gibson Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/piix4.c | 1 + hw/audio/ac97.c | 4 ++++ hw/audio/es1370.c | 4 ++++ hw/audio/intel-hda.c | 4 ++++ hw/char/serial-pci.c | 12 ++++++++++++ hw/display/cirrus_vga.c | 4 ++++ hw/display/qxl.c | 4 ++++ hw/display/sm501.c | 4 ++++ hw/display/vga-pci.c | 4 ++++ hw/display/vmware_vga.c | 4 ++++ hw/i2c/smbus_ich9.c | 4 ++++ hw/i386/amd_iommu.c | 4 ++++ hw/i386/kvm/pci-assign.c | 4 ++++ hw/i386/pc_piix.c | 4 ++++ hw/i386/xen/xen_platform.c | 4 ++++ hw/i386/xen/xen_pvdevice.c | 4 ++++ hw/ide/ich.c | 4 ++++ hw/ide/pci.c | 4 ++++ hw/ipack/tpci200.c | 4 ++++ hw/isa/i82378.c | 4 ++++ hw/isa/lpc_ich9.c | 1 + hw/isa/piix4.c | 4 ++++ hw/isa/vt82c686.c | 16 ++++++++++++++++ hw/mips/gt64xxx_pci.c | 4 ++++ hw/misc/edu.c | 5 +++++ hw/misc/ivshmem.c | 4 ++++ hw/misc/macio/macio.c | 4 ++++ hw/misc/pci-testdev.c | 4 ++++ hw/net/e1000.c | 4 ++++ hw/net/eepro100.c | 4 ++++ hw/net/ne2000.c | 4 ++++ hw/net/pcnet-pci.c | 4 ++++ hw/net/rocker/rocker.c | 4 ++++ hw/net/rtl8139.c | 4 ++++ hw/net/sungem.c | 4 ++++ hw/net/sunhme.c | 4 ++++ hw/pci-bridge/dec.c | 8 ++++++++ hw/pci-bridge/i82801b11.c | 4 ++++ hw/pci-bridge/pci_bridge_dev.c | 1 + hw/pci-bridge/pci_expander_bridge.c | 8 ++++++++ hw/pci-host/apb.c | 8 ++++++++ hw/pci-host/bonito.c | 4 ++++ hw/pci-host/gpex.c | 4 ++++ hw/pci-host/grackle.c | 4 ++++ hw/pci-host/piix.c | 8 ++++++++ hw/pci-host/ppce500.c | 4 ++++ hw/pci-host/prep.c | 4 ++++ hw/pci-host/q35.c | 4 ++++ hw/pci-host/uninorth.c | 16 ++++++++++++++++ hw/pci-host/versatile.c | 4 ++++ hw/ppc/ppc4xx_pci.c | 4 ++++ hw/scsi/esp-pci.c | 4 ++++ hw/scsi/lsi53c895a.c | 4 ++++ hw/scsi/megasas.c | 4 ++++ hw/scsi/mptsas.c | 4 ++++ hw/sd/sdhci.c | 4 ++++ hw/sh4/sh_pci.c | 4 ++++ hw/sparc64/sun4u.c | 4 ++++ hw/usb/hcd-ehci-pci.c | 4 ++++ hw/usb/hcd-ohci.c | 4 ++++ hw/usb/hcd-uhci.c | 4 ++++ hw/vfio/pci-quirks.c | 4 ++++ hw/watchdog/wdt_i6300esb.c | 4 ++++ hw/xen/xen_pt.c | 4 ++++ 64 files changed, 296 insertions(+) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index f4fd5907b8..a0fb1ce037 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -718,6 +718,7 @@ static const TypeInfo piix4_pm_info = { .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } }; diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 959c786261..337402e9c6 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -1431,6 +1431,10 @@ static const TypeInfo ac97_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (AC97LinkState), .class_init = ac97_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void ac97_register_types (void) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index dd7c23d185..59cf252754 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -1082,6 +1082,10 @@ static const TypeInfo es1370_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (ES1370State), .class_init = es1370_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void es1370_register_types (void) diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 18a50a8f83..a3e670c188 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -1263,6 +1263,10 @@ static const TypeInfo intel_hda_info = { .instance_size = sizeof(IntelHDAState), .class_init = intel_hda_class_init, .abstract = true, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static const TypeInfo intel_hda_info_ich6 = { diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 303104dd19..cb0d04c1d9 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -250,6 +250,10 @@ static const TypeInfo serial_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCISerialState), .class_init = serial_pci_class_initfn, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static const TypeInfo multi_2x_serial_pci_info = { @@ -257,6 +261,10 @@ static const TypeInfo multi_2x_serial_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIMultiSerialState), .class_init = multi_2x_serial_pci_class_initfn, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static const TypeInfo multi_4x_serial_pci_info = { @@ -264,6 +272,10 @@ static const TypeInfo multi_4x_serial_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIMultiSerialState), .class_init = multi_4x_serial_pci_class_initfn, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void serial_pci_register_types(void) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index afc290ab91..b4d579857a 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -3162,6 +3162,10 @@ static const TypeInfo cirrus_vga_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCICirrusVGAState), .class_init = cirrus_vga_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void cirrus_vga_register_types(void) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index d92fe05f1a..99365c3e8f 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2432,6 +2432,10 @@ static const TypeInfo qxl_pci_type_info = { .instance_size = sizeof(PCIQXLDevice), .abstract = true, .class_init = qxl_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void qxl_primary_class_init(ObjectClass *klass, void *data) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 9aa515b3da..6eddac911e 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1843,6 +1843,10 @@ static const TypeInfo sm501_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(SM501PCIState), .class_init = sm501_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void sm501_register_types(void) diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index ac9a76499e..7adb89fcb4 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -338,6 +338,10 @@ static const TypeInfo vga_pci_type_info = { .instance_size = sizeof(PCIVGAState), .abstract = true, .class_init = vga_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void vga_class_init(ObjectClass *klass, void *data) diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 4a64b41259..cdc3fed6ca 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1350,6 +1350,10 @@ static const TypeInfo vmsvga_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(struct pci_vmsvga_state_s), .class_init = vmsvga_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void vmsvga_register_types(void) diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index ea51e09186..e47556c9d8 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -119,6 +119,10 @@ static const TypeInfo ich9_smb_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(ICH9SMBState), .class_init = ich9_smb_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void ich9_smb_register(void) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 334938a280..ad8155ca4c 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1227,6 +1227,10 @@ static const TypeInfo amdviPCI = { .name = "AMDVI-PCI", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(AMDVIPCIState), + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, void *data) diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index 33e20cb3e8..d8559d8342 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -1864,6 +1864,10 @@ static const TypeInfo assign_info = { .instance_size = sizeof(AssignedDevice), .class_init = assign_class_init, .instance_init = assigned_dev_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void assign_register_types(void) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 9ff79b1fd9..1a56465490 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -1055,6 +1055,10 @@ static TypeInfo isa_bridge_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = isa_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pt_graphics_register_types(void) diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 9ba7474566..056b87de0b 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -517,6 +517,10 @@ static const TypeInfo xen_platform_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIXenPlatformState), .class_init = xen_platform_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void xen_platform_register_types(void) diff --git a/hw/i386/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c index c093b34458..f748823658 100644 --- a/hw/i386/xen/xen_pvdevice.c +++ b/hw/i386/xen/xen_pvdevice.c @@ -127,6 +127,10 @@ static const TypeInfo xen_pv_type_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(XenPVDevice), .class_init = xen_pv_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void xen_pv_register_types(void) diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 9472a60cab..8dd0ced6b3 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -184,6 +184,10 @@ static const TypeInfo ich_ahci_info = { .instance_size = sizeof(AHCIPCIState), .instance_init = pci_ich9_ahci_init, .class_init = ich_ahci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void ich_ahci_register_types(void) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index d53ff5341c..25f1d36f3a 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -453,6 +453,10 @@ static const TypeInfo pci_ide_type_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), .abstract = true, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pci_ide_register_types(void) diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c index 4dfa6b33f3..da05c8589d 100644 --- a/hw/ipack/tpci200.c +++ b/hw/ipack/tpci200.c @@ -646,6 +646,10 @@ static const TypeInfo tpci200_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(TPCI200State), .class_init = tpci200_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void tpci200_register_types(void) diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index 4d29a9900c..d20ea4c2ee 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -138,6 +138,10 @@ static const TypeInfo i82378_type_info = { .instance_size = sizeof(I82378State), .instance_init = i82378_init, .class_init = i82378_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void i82378_register_types(void) diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index de8fbb7260..ec3c9f7d0b 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -823,6 +823,7 @@ static const TypeInfo ich9_lpc_info = { .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } }; diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index f811eba59d..6b8bc3faf0 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -132,6 +132,10 @@ static const TypeInfo piix4_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX4State), .class_init = piix4_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void piix4_register_types(void) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 50dc83df77..c129985e2a 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -301,6 +301,10 @@ static const TypeInfo via_ac97_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686AC97State), .class_init = via_ac97_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void vt82c686b_mc97_realize(PCIDevice *dev, Error **errp) @@ -341,6 +345,10 @@ static const TypeInfo via_mc97_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686MC97State), .class_init = via_mc97_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; /* vt82c686 pm init */ @@ -419,6 +427,10 @@ static const TypeInfo via_pm_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686PMState), .class_init = via_pm_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static const VMStateDescription vmstate_via = { @@ -502,6 +514,10 @@ static const TypeInfo via_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT82C686BState), .class_init = via_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void vt82c686b_register_types(void) diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index e8b2eef688..5a9dad9aae 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -1232,6 +1232,10 @@ static const TypeInfo gt64120_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = gt64120_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void gt64120_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/edu.c b/hw/misc/edu.c index 01acacf142..34eb05d213 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -408,12 +408,17 @@ static void edu_class_init(ObjectClass *class, void *data) static void pci_edu_register_types(void) { + static InterfaceInfo interfaces[] = { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }; static const TypeInfo edu_info = { .name = "edu", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(EduState), .instance_init = edu_instance_init, .class_init = edu_class_init, + .interfaces = interfaces, }; type_register_static(&edu_info); diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index b3ef3ec1e3..a5a46827fe 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -1010,6 +1010,10 @@ static const TypeInfo ivshmem_common_info = { .instance_size = sizeof(IVShmemState), .abstract = true, .class_init = ivshmem_common_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static const VMStateDescription ivshmem_plain_vmsd = { diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 9aa7e7559b..44f91d1e7f 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -426,6 +426,10 @@ static const TypeInfo macio_type_info = { .instance_init = macio_instance_init, .abstract = true, .class_init = macio_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void macio_register_types(void) diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index 7d5990213e..32041f535f 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -326,6 +326,10 @@ static const TypeInfo pci_testdev_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCITestDevState), .class_init = pci_testdev_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pci_testdev_register_types(void) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index cae95185a5..c0abee4f7e 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1687,6 +1687,10 @@ static const TypeInfo e1000_base_info = { .instance_init = e1000_instance_init, .class_size = sizeof(E1000BaseClass), .abstract = true, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static const E1000Info e1000_devices[] = { diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index a7b9f77519..80b8f47c4b 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -2116,6 +2116,10 @@ static void eepro100_register_types(void) type_info.class_init = eepro100_class_init; type_info.instance_size = sizeof(EEPRO100State); type_info.instance_init = eepro100_instance_init; + type_info.interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }; type_register(&type_info); } diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 798d681e25..3938e6ddd8 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -786,6 +786,10 @@ static const TypeInfo ne2000_info = { .instance_size = sizeof(PCINE2000State), .class_init = ne2000_class_init, .instance_init = ne2000_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void ne2000_register_types(void) diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 0acf8a4879..0ae5ca4701 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -365,6 +365,10 @@ static const TypeInfo pcnet_info = { .instance_size = sizeof(PCIPCNetState), .class_init = pcnet_class_init, .instance_init = pcnet_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pci_pcnet_register_types(void) diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 9273473d59..823a29df03 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -1525,6 +1525,10 @@ static const TypeInfo rocker_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(Rocker), .class_init = rocker_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void rocker_register_types(void) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index d6c8188ae1..a6b2a9f7a4 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -3444,6 +3444,10 @@ static const TypeInfo rtl8139_info = { .instance_size = sizeof(RTL8139State), .class_init = rtl8139_class_init, .instance_init = rtl8139_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void rtl8139_register_types(void) diff --git a/hw/net/sungem.c b/hw/net/sungem.c index dffa0c90f3..6aa8d1117b 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -1437,6 +1437,10 @@ static const TypeInfo sungem_info = { .instance_size = sizeof(SunGEMState), .class_init = sungem_class_init, .instance_init = sungem_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { } + } }; static void sungem_register_types(void) diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index 60277adcf1..b1efa1b88d 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -968,6 +968,10 @@ static const TypeInfo sunhme_info = { .class_init = sunhme_class_init, .instance_size = sizeof(SunHMEState), .instance_init = sunhme_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { } + } }; static void sunhme_register_types(void) diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c index eb275e1a25..84492d5e5f 100644 --- a/hw/pci-bridge/dec.c +++ b/hw/pci-bridge/dec.c @@ -79,6 +79,10 @@ static const TypeInfo dec_21154_pci_bridge_info = { .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(PCIBridge), .class_init = dec_21154_pci_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) @@ -138,6 +142,10 @@ static const TypeInfo dec_21154_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = dec_21154_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index 2c1b747b4b..cb522bf30c 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -106,6 +106,10 @@ static const TypeInfo i82801b11_bridge_info = { .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(I82801b11Bridge), .class_init = i82801b11_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void d2pbr_register(void) diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 4373f1d3e2..d56f6638c2 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -238,6 +238,7 @@ static const TypeInfo pci_bridge_dev_info = { .instance_finalize = pci_bridge_dev_instance_finalize, .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } }; diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index ff59abf208..8c8ac737ad 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -316,6 +316,10 @@ static const TypeInfo pxb_dev_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PXBDev), .class_init = pxb_dev_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp) @@ -350,6 +354,10 @@ static const TypeInfo pxb_pcie_dev_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PXBDev), .class_init = pxb_pcie_dev_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pxb_register_types(void) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index b709456b97..1edf57f600 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -836,6 +836,10 @@ static const TypeInfo pbm_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = pbm_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pbm_host_class_init(ObjectClass *klass, void *data) @@ -883,6 +887,10 @@ static const TypeInfo pbm_pci_bridge_info = { .parent = TYPE_PCI_BRIDGE, .class_init = pbm_pci_bridge_class_init, .instance_size = sizeof(PBMPCIBridge), + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 89133a9dd3..9f61e27edc 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -833,6 +833,10 @@ static const TypeInfo bonito_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBonitoState), .class_init = bonito_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void bonito_pcihost_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index be25245219..4090793cf0 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -166,6 +166,10 @@ static const TypeInfo gpex_root_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(GPEXRootState), .class_init = gpex_root_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void gpex_register(void) diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index 2e281f6155..38cd279b6b 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -142,6 +142,10 @@ static const TypeInfo grackle_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = grackle_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pci_grackle_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index dec345fd24..a7e2256870 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -696,6 +696,10 @@ static const TypeInfo piix3_pci_type_info = { .instance_size = sizeof(PIIX3State), .abstract = true, .class_init = pci_piix3_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void piix3_class_init(ObjectClass *klass, void *data) @@ -750,6 +754,10 @@ static const TypeInfo i440fx_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCII440FXState), .class_init = i440fx_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; /* IGD Passthrough Host Bridge. */ diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index becc0eeb76..39cd24464d 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -516,6 +516,10 @@ static const TypeInfo e500_host_bridge_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PPCE500PCIBridgeState), .class_init = e500_host_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static Property pcihost_properties[] = { diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index 8b293ba0f1..92eed0f3e1 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -372,6 +372,10 @@ static const TypeInfo raven_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(RavenPCIState), .class_init = raven_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static Property raven_pcihost_properties[] = { diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 1ff648e80c..ddaa7d1b44 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -591,6 +591,10 @@ static const TypeInfo mch_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MCHPCIState), .class_init = mch_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void q35_register(void) diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index 6cf5e59f86..ea5c265718 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -374,6 +374,10 @@ static const TypeInfo unin_main_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = unin_main_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data) @@ -398,6 +402,10 @@ static const TypeInfo u3_agp_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = u3_agp_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data) @@ -422,6 +430,10 @@ static const TypeInfo unin_agp_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = unin_agp_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data) @@ -446,6 +458,10 @@ static const TypeInfo unin_internal_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = unin_internal_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void pci_unin_main_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index aa1fdf75fd..6394a520fc 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -487,6 +487,10 @@ static const TypeInfo versatile_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = versatile_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static Property pci_vpb_properties[] = { diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c index 6953f8b9ac..4765dcecca 100644 --- a/hw/ppc/ppc4xx_pci.c +++ b/hw/ppc/ppc4xx_pci.c @@ -359,6 +359,10 @@ static const TypeInfo ppc4xx_host_bridge_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = ppc4xx_host_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data) diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index e295d88939..419fc668ac 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -398,6 +398,10 @@ static const TypeInfo esp_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIESPState), .class_init = esp_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; typedef struct { diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index a67ee074d9..191505df5b 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2246,6 +2246,10 @@ static const TypeInfo lsi_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(LSIState), .class_init = lsi_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void lsi53c810_class_init(ObjectClass *klass, void *data) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 535ee267c3..d5eae6239a 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2468,6 +2468,10 @@ static struct MegasasInfo megasas_devices[] = { .is_express = false, .vmsd = &vmstate_megasas_gen1, .props = megasas_properties_gen1, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, },{ .name = TYPE_MEGASAS_GEN2, .desc = "LSI MegaRAID SAS 2108", diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index d05fa9f549..f6db1b0103 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -1439,6 +1439,10 @@ static const TypeInfo mptsas_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MPTSASState), .class_init = mptsas1068_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void mptsas_register_types(void) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 6d6a791ee9..b064a087c9 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1315,6 +1315,10 @@ static const TypeInfo sdhci_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(SDHCIState), .class_init = sdhci_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static Property sdhci_sysbus_properties[] = { diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c index 38395c082b..cbb01af57f 100644 --- a/hw/sh4/sh_pci.c +++ b/hw/sh4/sh_pci.c @@ -179,6 +179,10 @@ static const TypeInfo sh_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = sh_pci_host_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void sh_pci_device_class_init(ObjectClass *klass, void *data) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index c3280aaf38..8282651aeb 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -275,6 +275,10 @@ static const TypeInfo ebus_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(EbusState), .class_init = ebus_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; #define TYPE_OPENPROM "openprom" diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 6dedcb8989..8c0fc53a26 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -170,6 +170,10 @@ static const TypeInfo ehci_pci_type_info = { .instance_finalize = usb_ehci_pci_finalize, .abstract = true, .class_init = ehci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void ehci_data_class_init(ObjectClass *klass, void *data) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 17beeddb09..d4c0293db5 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -2146,6 +2146,10 @@ static const TypeInfo ohci_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(OHCIPCIState), .class_init = ohci_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static Property ohci_sysbus_properties[] = { diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index e3562a4c60..836b11f177 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1323,6 +1323,10 @@ static const TypeInfo uhci_pci_type_info = { .class_size = sizeof(UHCIPCIDeviceClass), .abstract = true, .class_init = uhci_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void uhci_data_class_init(ObjectClass *klass, void *data) diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 14291c2a16..60ad5fb91a 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1198,6 +1198,10 @@ static TypeInfo vfio_pci_igd_lpc_bridge_info = { .name = "vfio-pci-igd-lpc-bridge", .parent = TYPE_PCI_DEVICE, .class_init = vfio_pci_igd_lpc_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void vfio_pci_igd_register_types(void) diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index 49b3cd188a..e596b0804d 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -463,6 +463,10 @@ static const TypeInfo i6300esb_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(I6300State), .class_init = i6300esb_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void i6300esb_register_types(void) diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 375efa68f6..01df3414d3 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -964,6 +964,10 @@ static const TypeInfo xen_pci_passthrough_info = { .instance_size = sizeof(XenPCIPassthroughState), .instance_finalize = xen_pci_passthrough_finalize, .class_init = xen_pci_passthrough_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void xen_pci_passthrough_register_types(void) From 6d7023763ec8cc7999468769a0c6bf1335dc3bf4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 5 Oct 2017 09:45:07 -0300 Subject: [PATCH 19/26] xen/pt: Mark TYPE_XEN_PT_DEVICE as hybrid xen-pt doesn't set the is_express field, but is supposed to be able to handle PCI Express devices too. Mark it as hybrid. Suggested-by: Jan Beulich Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/xen/xen_pt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 01df3414d3..9bba717708 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -966,6 +966,7 @@ static const TypeInfo xen_pci_passthrough_info = { .class_init = xen_pci_passthrough_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { INTERFACE_PCIE_DEVICE }, { }, }, }; From 2fefa16cec5a719f5cbc26c0672dd2099cd2ed9b Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 27 Sep 2017 16:56:35 -0300 Subject: [PATCH 20/26] pci: Validate interfaces on base_class_init Make sure we don't forget to add the Conventional PCI or PCI Express interface names on PCI device classes in the future. Signed-off-by: Eduardo Habkost Revieed-by: David Gibson Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 1b08e18205..5ed3c8dca4 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2547,6 +2547,17 @@ static void pci_device_class_init(ObjectClass *klass, void *data) pc->realize = pci_default_realize; } +static void pci_device_class_base_init(ObjectClass *klass, void *data) +{ + if (!object_class_is_abstract(klass)) { + ObjectClass *conventional = + object_class_dynamic_cast(klass, INTERFACE_CONVENTIONAL_PCI_DEVICE); + ObjectClass *pcie = + object_class_dynamic_cast(klass, INTERFACE_PCIE_DEVICE); + assert(conventional || pcie); + } +} + AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) { PCIBus *bus = PCI_BUS(dev->bus); @@ -2671,6 +2682,7 @@ static const TypeInfo pci_device_type_info = { .abstract = true, .class_size = sizeof(PCIDeviceClass), .class_init = pci_device_class_init, + .class_base_init = pci_device_class_base_init, }; static void pci_register_types(void) From 8e36c336d943c3bfe0d06f5465cc64d44b306e13 Mon Sep 17 00:00:00 2001 From: Marcel Apfelbaum Date: Mon, 2 Oct 2017 13:31:35 +0300 Subject: [PATCH 21/26] hw/gen_pcie_root_port: make IO RO 0 on IO disabled IO_LIMIT and IO_BASE registers should not be writable if gen_pcie_root_port's io-reserve property is set to 0. The COMMAND register should have the IO flag read only. Signed-off-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/gen_pcie_root_port.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index ed03ffc764..ad4e6aa7ff 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -85,6 +85,13 @@ static void gen_rp_realize(DeviceState *dev, Error **errp) rpc->parent_class.exit(d); return; } + + if (!grp->io_reserve) { + pci_word_test_and_clear_mask(d->wmask + PCI_COMMAND, + PCI_COMMAND_IO); + d->wmask[PCI_IO_BASE] = 0; + d->wmask[PCI_IO_LIMIT] = 0; + } } static const VMStateDescription vmstate_rp_dev = { From 37ef70be6af7e9f2a6f852c68f74bd98dac2664b Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 20 Sep 2017 08:09:33 +0200 Subject: [PATCH 22/26] virtio: fix descriptor counting in virtqueue_pop While changing the s/g list allocation, commit 3b3b0628 also changed the descriptor counting to count iovec entries as split by cpu_physical_memory_map(). Previously only the actual descriptor entries were counted and the split into the iovec happened afterwards in virtqueue_map(). Count the entries again instead to avoid erroneous "Looped descriptor" errors. Reported-by: Hans Middelhoek Link: https://forum.proxmox.com/threads/vm-crash-with-memory-hotplug.35904/ Fixes: 3b3b0628217e ("virtio: slim down allocation of VirtQueueElements") Signed-off-by: Wolfgang Bumiller Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 311929e9df..5884ce3480 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -834,7 +834,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) int64_t len; VirtIODevice *vdev = vq->vdev; VirtQueueElement *elem = NULL; - unsigned out_num, in_num; + unsigned out_num, in_num, elem_entries; hwaddr addr[VIRTQUEUE_MAX_SIZE]; struct iovec iov[VIRTQUEUE_MAX_SIZE]; VRingDesc desc; @@ -852,7 +852,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) smp_rmb(); /* When we start there are none of either input nor output. */ - out_num = in_num = 0; + out_num = in_num = elem_entries = 0; max = vq->vring.num; @@ -922,7 +922,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) } /* If we've got too many, that implies a descriptor loop. */ - if ((in_num + out_num) > max) { + if (++elem_entries > max) { virtio_error(vdev, "Looped descriptor"); goto err_undo_map; } From a93c8d828af186d9a6a1c915a1be8ba22fb89849 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 9 Oct 2017 14:19:41 +1100 Subject: [PATCH 23/26] virtio-pci: Replace modern_as with direct access to modern_bar The modern bar is accessed now via yet another address space created just for that purpose and it does not really need FlatView and dispatch tree as it has a single memory region so it is just a waste of memory. Things get even worse when there are dozens or hundreds of virtio-pci devices - since these address spaces are global, changing any of them triggers rebuilding all address spaces. This replaces indirect accesses to the modern BAR with a simple lookup and direct calls to memory_region_dispatch_read/write. This is expected to save lots of memory at boot time after applying: [Qemu-devel] [PULL 00/32] Misc changes for 2017-09-22 Signed-off-by: Alexey Kardashevskiy Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 75 +++++++++++++++++++++++++----------------- hw/virtio/virtio-pci.h | 17 ++++++---- 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 6c60aa0f51..e92837c42b 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -491,6 +491,24 @@ static const MemoryRegionOps virtio_pci_config_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy, + hwaddr *off, int len) +{ + int i; + VirtIOPCIRegion *reg; + + for (i = 0; i < ARRAY_SIZE(proxy->regs); ++i) { + reg = &proxy->regs[i]; + if (*off >= reg->offset && + *off + len <= reg->offset + reg->size) { + *off -= reg->offset; + return ®->mr; + } + } + + return NULL; +} + /* Below are generic functions to do memcpy from/to an address space, * without byteswaps, with input validation. * @@ -504,63 +522,72 @@ static const MemoryRegionOps virtio_pci_config_ops = { * Note: host pointer must be aligned. */ static -void virtio_address_space_write(AddressSpace *as, hwaddr addr, +void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr, const uint8_t *buf, int len) { - uint32_t val; + uint64_t val; + MemoryRegion *mr; /* address_space_* APIs assume an aligned address. * As address is under guest control, handle illegal values. */ addr &= ~(len - 1); + mr = virtio_address_space_lookup(proxy, &addr, len); + if (!mr) { + return; + } + /* Make sure caller aligned buf properly */ assert(!(((uintptr_t)buf) & (len - 1))); switch (len) { case 1: val = pci_get_byte(buf); - address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); break; case 2: - val = pci_get_word(buf); - address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); + val = cpu_to_le16(pci_get_word(buf)); break; case 4: - val = pci_get_long(buf); - address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); + val = cpu_to_le32(pci_get_long(buf)); break; default: /* As length is under guest control, handle illegal values. */ - break; + return; } + memory_region_dispatch_write(mr, addr, val, len, MEMTXATTRS_UNSPECIFIED); } static void -virtio_address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len) +virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr, + uint8_t *buf, int len) { - uint32_t val; + uint64_t val; + MemoryRegion *mr; /* address_space_* APIs assume an aligned address. * As address is under guest control, handle illegal values. */ addr &= ~(len - 1); + mr = virtio_address_space_lookup(proxy, &addr, len); + if (!mr) { + return; + } + /* Make sure caller aligned buf properly */ assert(!(((uintptr_t)buf) & (len - 1))); + memory_region_dispatch_read(mr, addr, &val, len, MEMTXATTRS_UNSPECIFIED); switch (len) { case 1: - val = address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); pci_set_byte(buf, val); break; case 2: - val = address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); - pci_set_word(buf, val); + pci_set_word(buf, le16_to_cpu(val)); break; case 4: - val = address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); - pci_set_long(buf, val); + pci_set_long(buf, le32_to_cpu(val)); break; default: /* As length is under guest control, handle illegal values. */ @@ -596,8 +623,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, if (len == 1 || len == 2 || len == 4) { assert(len <= sizeof cfg->pci_cfg_data); - virtio_address_space_write(&proxy->modern_as, off, - cfg->pci_cfg_data, len); + virtio_address_space_write(proxy, off, cfg->pci_cfg_data, len); } } } @@ -621,8 +647,7 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, if (len == 1 || len == 2 || len == 4) { assert(len <= sizeof cfg->pci_cfg_data); - virtio_address_space_read(&proxy->modern_as, off, - cfg->pci_cfg_data, len); + virtio_address_space_read(proxy, off, cfg->pci_cfg_data, len); } } @@ -1729,15 +1754,6 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) /* PCI BAR regions must be powers of 2 */ pow2ceil(proxy->notify.offset + proxy->notify.size)); - memory_region_init_alias(&proxy->modern_cfg, - OBJECT(proxy), - "virtio-pci-cfg", - &proxy->modern_bar, - 0, - memory_region_size(&proxy->modern_bar)); - - address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as"); - if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) { proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } @@ -1806,10 +1822,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) static void virtio_pci_exit(PCIDevice *pci_dev) { - VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); - msix_uninit_exclusive_bar(pci_dev); - address_space_destroy(&proxy->modern_as); } static void virtio_pci_reset(DeviceState *qdev) diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 69f5959623..12d3a90686 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -155,15 +155,18 @@ typedef struct VirtIOPCIQueue { struct VirtIOPCIProxy { PCIDevice pci_dev; MemoryRegion bar; - VirtIOPCIRegion common; - VirtIOPCIRegion isr; - VirtIOPCIRegion device; - VirtIOPCIRegion notify; - VirtIOPCIRegion notify_pio; + union { + struct { + VirtIOPCIRegion common; + VirtIOPCIRegion isr; + VirtIOPCIRegion device; + VirtIOPCIRegion notify; + VirtIOPCIRegion notify_pio; + }; + VirtIOPCIRegion regs[5]; + }; MemoryRegion modern_bar; MemoryRegion io_bar; - MemoryRegion modern_cfg; - AddressSpace modern_as; uint32_t legacy_io_bar_idx; uint32_t msix_bar_idx; uint32_t modern_io_bar_idx; From b5dac424922d62467ec2fd5bbe3a37b8d51919f3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 6 Oct 2017 10:25:02 -0300 Subject: [PATCH 24/26] isapc: Remove unnecessary migration compatibility code We don't touch isapc when we change guest ABI and add new entries to PC_COMPAT_* or new PCMachineClass compat flags. This means isapc never guaranteed guest ABI and cross-QEMU-version live migration compatibility. There's no point in keeping code for kvm-pv-eoi and APIC ID compatibility in pc_init_isa(). Signed-off-by: Eduardo Habkost Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 1a56465490..9dbcbcd57c 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -378,8 +378,6 @@ static void pc_compat_0_13(MachineState *machine) static void pc_init_isa(MachineState *machine) { - x86_cpu_change_kvm_default("kvm-pv-eoi", NULL); - enable_compat_apic_id_mode(); pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE); } From 46202d85d75b3a57c322f4832aac1dd20d5b3233 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 10 Oct 2017 15:32:41 +0200 Subject: [PATCH 25/26] pc: remove useless hot_add_cpu initialisation Since 4458fb3a79 (pc: Eliminate pc_default_machine_options()), hot_add_cpu is set in pc_machine_class_init(), so we don't need to set it in pc_q35_machine_options(), pc_i440fx_machine_options() and xenfv_machine_options(), except to clear it in pc_i440fx_1_4_machine_opt(). Signed-off-by: Laurent Vivier Reviewed-by: Igor Mammedov Reviewed-by: Eduardo Habkost Acked-by: Anthony PERARD Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 2 -- hw/i386/pc_q35.c | 1 - 2 files changed, 3 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 9dbcbcd57c..f79d5cb694 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -426,7 +426,6 @@ static void pc_i440fx_machine_options(MachineClass *m) { m->family = "pc_piix"; m->desc = "Standard PC (i440FX + PIIX, 1996)"; - m->hot_add_cpu = pc_hot_add_cpu; m->default_machine_opts = "firmware=bios-256k.bin"; m->default_display = "std"; } @@ -1125,7 +1124,6 @@ static void xenfv_machine_options(MachineClass *m) m->desc = "Xen Fully-virtualized PC"; m->max_cpus = HVM_MAX_VCPUS; m->default_machine_opts = "accel=xen"; - m->hot_add_cpu = pc_hot_add_cpu; } DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 6c4ec4be4e..da3ea602e1 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -295,7 +295,6 @@ static void pc_q35_machine_options(MachineClass *m) { m->family = "pc_q35"; m->desc = "Standard PC (Q35 + ICH9, 2009)"; - m->hot_add_cpu = pc_hot_add_cpu; m->units_per_default_bus = 1; m->default_machine_opts = "firmware=bios-256k.bin"; m->default_display = "std"; From ab06ec43577177a442e8e5ca28d0154efe4ff60f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 20 Sep 2017 11:02:07 +0200 Subject: [PATCH 26/26] tests/pxe: Test more NICs when running in SPEED=slow mode The pxe-test is a very good test to excercise NICs, thus we should use it to test all NICs that can be used by the BIOS for booting via network. However, to avoid that the default testing time increases too much, the additional NICs are only tested in the "make check SPEED=slow" mode. The virtio-net NIC on ppc64 is now also only tested in slow mode, since the test on ppc64 is really quite slow and we've got test coverage for virtio-net in big endian mode now on s390x, too. Signed-off-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/pxe-test.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tests/pxe-test.c b/tests/pxe-test.c index 0d70afccd6..937f29e631 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -1,11 +1,12 @@ /* * PXE test cases. * - * Copyright (c) 2016 Red Hat Inc. + * Copyright (c) 2016, 2017 Red Hat Inc. * * Authors: * Michael S. Tsirkin , * Victor Kaplansky + * Thomas Huth * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -36,14 +37,14 @@ static void test_pxe_one(const char *params, bool ipv6) g_free(args); } -static void test_pxe_e1000(void) +static void test_pxe_ipv4(gconstpointer data) { - test_pxe_one("-device e1000,netdev=" NETNAME, false); -} + const char *model = data; + char *dev_arg; -static void test_pxe_virtio_pci(void) -{ - test_pxe_one("-device virtio-net-pci,netdev=" NETNAME, false); + dev_arg = g_strdup_printf("-device %s,netdev=" NETNAME, model); + test_pxe_one(dev_arg, false); + g_free(dev_arg); } static void test_pxe_spapr_vlan(void) @@ -68,11 +69,21 @@ int main(int argc, char *argv[]) g_test_init(&argc, &argv, NULL); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - qtest_add_func("pxe/e1000", test_pxe_e1000); - qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + qtest_add_data_func("pxe/e1000", "e1000", test_pxe_ipv4); + qtest_add_data_func("pxe/virtio", "virtio-net-pci", test_pxe_ipv4); + if (g_test_slow()) { + qtest_add_data_func("pxe/ne2000", "ne2k_pci", test_pxe_ipv4); + qtest_add_data_func("pxe/eepro100", "i82550", test_pxe_ipv4); + qtest_add_data_func("pxe/pcnet", "pcnet", test_pxe_ipv4); + qtest_add_data_func("pxe/rtl8139", "rtl8139", test_pxe_ipv4); + qtest_add_data_func("pxe/vmxnet3", "vmxnet3", test_pxe_ipv4); + } } else if (strcmp(arch, "ppc64") == 0) { - qtest_add_func("pxe/virtio", test_pxe_virtio_pci); qtest_add_func("pxe/spapr-vlan", test_pxe_spapr_vlan); + if (g_test_slow()) { + qtest_add_data_func("pxe/virtio", "virtio-net-pci", test_pxe_ipv4); + qtest_add_data_func("pxe/e1000", "e1000", test_pxe_ipv4); + } } else if (g_str_equal(arch, "s390x")) { qtest_add_func("pxe/virtio-ccw", test_pxe_virtio_ccw); }