From b9731850d746e528d317097f907f27116798d7fe Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 12 Dec 2018 10:16:16 +0100 Subject: pci/pcie: stop plug/unplug if the slot is locked We better stop right away. For now, errors would be partially ignored (so the guest might get informed or the device might get unplugged), although actual plug/unplug will be reported as failed to the user. While at it, properly move the check to the pre_plug handler for the plug case, as we can test the slot state before the device will be realized. Reviewed-by: Igor Mammedov Reviewed-by: David Gibson Signed-off-by: David Hildenbrand Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 25 +++++++++++++++++-------- hw/pci/pcie_port.c | 1 + include/hw/pci/pcie.h | 2 ++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 2d3d8a0..230478f 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -391,10 +391,10 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) } static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev, - uint8_t **exp_cap, Error **errp) + Error **errp) { - *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap; - uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA); + uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap; + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta); if (sltsta & PCI_EXP_SLTSTA_EIS) { @@ -405,14 +405,19 @@ static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev, } } +void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp); +} + void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - uint8_t *exp_cap; + PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); + uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; PCIDevice *pci_dev = PCI_DEVICE(dev); - pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); - /* Don't send event when device is enabled during qemu machine creation: * it is present on boot, no hotplug event is necessary. We do send an * event when the device is disabled later. */ @@ -458,11 +463,15 @@ static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque) void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - uint8_t *exp_cap; + Error *local_err = NULL; PCIDevice *pci_dev = PCI_DEVICE(dev); PCIBus *bus = pci_get_bus(pci_dev); - pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); + pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } /* In case user cancel the operation of multi-function hot-add, * remove the function that is unexposed to guest individually, diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index bc07abc..a30291e 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -154,6 +154,7 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data) HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); dc->props = pcie_slot_props; + hc->pre_plug = pcie_cap_slot_pre_plug_cb; hc->plug = pcie_cap_slot_plug_cb; hc->unplug = pcie_cap_slot_unplug_cb; hc->unplug_request = pcie_cap_slot_unplug_request_cb; diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index cd31864..5b82a0d 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -132,6 +132,8 @@ void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num); void pcie_ats_init(PCIDevice *dev, uint16_t offset); +void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp); void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -- cgit v1.1 From 17323e8b689a1f6d1b711df034e9ee3a88ff27ba Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Mon, 17 Dec 2018 07:34:39 +0800 Subject: msix: make pba size math more uniform In msix_exclusive_bar the bar_pba_size is more than what the pba is expected to have, although this never affects the bar size. Specifically, the math in msix_init_exclusive_bar allocates too much memory in some cases. For example consider nentries = 8. msix_exclusive_bar will give us bar_pba_size = 16. So 16 bytes. However 8 bytes would be enough - this is all that the spec requires. So in practice bar_pba_size sometimes allocates an extra 8 bytes but never more. Since each MSIX entry size is 16 bytes, and since we make sure that table+pba is a power of two, this always leaves a multiple of 16 bytes for the PBA, so extra 8 bytes have no effect. However, its ugly to have pba size temporary variable have an incorrect value. For consistency switch to the formula used in msix_init. Signed-off-by: Dongli Zhang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/msix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index c7bdbed..4e33641 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -345,7 +345,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, char *name; uint32_t bar_size = 4096; uint32_t bar_pba_offset = bar_size / 2; - uint32_t bar_pba_size = (nentries / 8 + 1) * 8; + uint32_t bar_pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; /* * Migration compatibility dictates that this remains a 4k -- cgit v1.1 From 5a0e75f0a9ad063ebaa7eb19b82104f00acb80a0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 19 Dec 2018 14:13:25 +0100 Subject: hw/misc/ivshmem: Remove deprecated "ivshmem" legacy device It's been marked as deprecated in QEMU v2.6.0 already, so really nobody should use the legacy "ivshmem" device anymore (but use ivshmem-plain or ivshmem-doorbell instead). Time to remove the deprecated device now. Belatedly also update a mention of the deprecated "ivshmem" in the file docs/specs/ivshmem-spec.txt to "ivshmem-doorbell". Missed in commit 5400c02b90b ("ivshmem: Split ivshmem-plain, ivshmem-doorbell off ivshmem"). Signed-off-by: Thomas Huth Reviewed-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/ivshmem-spec.txt | 8 +- hw/i386/pc_piix.c | 1 - hw/misc/ivshmem.c | 210 ++------------------------------------------ qemu-deprecated.texi | 5 -- scripts/device-crash-test | 1 - tests/ivshmem-test.c | 67 +++++--------- 6 files changed, 34 insertions(+), 258 deletions(-) diff --git a/docs/specs/ivshmem-spec.txt b/docs/specs/ivshmem-spec.txt index a1f5499..042f7ea 100644 --- a/docs/specs/ivshmem-spec.txt +++ b/docs/specs/ivshmem-spec.txt @@ -17,12 +17,16 @@ get interrupted by its peers. There are two basic configurations: -- Just shared memory: -device ivshmem-plain,memdev=HMB,... +- Just shared memory: + + -device ivshmem-plain,memdev=HMB,... This uses host memory backend HMB. It should have option "share" set. -- Shared memory plus interrupts: -device ivshmem,chardev=CHR,vectors=N,... +- Shared memory plus interrupts: + + -device ivshmem-doorbell,chardev=CHR,vectors=N,... An ivshmem server must already be running on the host. The device connects to the server's UNIX domain socket via character device diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 5088e2f..63c84e3 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -715,7 +715,6 @@ static void pc_i440fx_1_2_machine_options(MachineClass *m) PC_CPU_MODEL_IDS("1.2.0") { "nec-usb-xhci", "msi", "off" }, { "nec-usb-xhci", "msix", "off" }, - { "ivshmem", "use64", "0" }, { "qxl", "revision", "3" }, { "qxl-vga", "revision", "3" }, { "VGA", "mmio", "off" }, diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 8213659..c7b6bbc 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -112,13 +112,6 @@ typedef struct IVShmemState { /* migration stuff */ OnOffAuto master; Error *migration_blocker; - - /* legacy cruft */ - char *role; - char *shmobj; - char *sizearg; - size_t legacy_size; - uint32_t not_legacy_32bit; } IVShmemState; /* registers for the Inter-VM shared memory device */ @@ -529,17 +522,6 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp) size = buf.st_size; - /* Legacy cruft */ - if (s->legacy_size != SIZE_MAX) { - if (size < s->legacy_size) { - error_setg(errp, "server sent only %zd bytes of shared memory", - (size_t)buf.st_size); - close(fd); - return; - } - size = s->legacy_size; - } - /* mmap the region and map into the BAR2 */ memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s), "ivshmem.bar2", size, true, fd, &local_err); @@ -882,8 +864,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) IVShmemState *s = IVSHMEM_COMMON(dev); Error *err = NULL; uint8_t *pci_conf; - uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY | - PCI_BASE_ADDRESS_MEM_PREFETCH; Error *local_err = NULL; /* IRQFD requires MSI */ @@ -903,10 +883,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem_mmio); - if (s->not_legacy_32bit) { - attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; - } - if (s->hostmem != NULL) { IVSHMEM_DPRINTF("using hostmem\n"); @@ -964,7 +940,11 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) } vmstate_register_ram(s->ivshmem_bar2, DEVICE(s)); - pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2); + pci_register_bar(PCI_DEVICE(s), 2, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH | + PCI_BASE_ADDRESS_MEM_TYPE_64, + s->ivshmem_bar2); } static void ivshmem_exit(PCIDevice *dev) @@ -1084,13 +1064,6 @@ static Property ivshmem_plain_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void ivshmem_plain_init(Object *obj) -{ - IVShmemState *s = IVSHMEM_PLAIN(obj); - - s->not_legacy_32bit = 1; -} - static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) { IVShmemState *s = IVSHMEM_COMMON(dev); @@ -1122,7 +1095,6 @@ static const TypeInfo ivshmem_plain_info = { .name = TYPE_IVSHMEM_PLAIN, .parent = TYPE_IVSHMEM_COMMON, .instance_size = sizeof(IVShmemState), - .instance_init = ivshmem_plain_init, .class_init = ivshmem_plain_class_init, }; @@ -1155,8 +1127,6 @@ static void ivshmem_doorbell_init(Object *obj) IVShmemState *s = IVSHMEM_DOORBELL(obj); s->features |= (1 << IVSHMEM_MSI); - s->legacy_size = SIZE_MAX; /* whatever the server sends */ - s->not_legacy_32bit = 1; } static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp) @@ -1189,181 +1159,11 @@ static const TypeInfo ivshmem_doorbell_info = { .class_init = ivshmem_doorbell_class_init, }; -static int ivshmem_load_old(QEMUFile *f, void *opaque, int version_id) -{ - IVShmemState *s = opaque; - PCIDevice *pdev = PCI_DEVICE(s); - int ret; - - IVSHMEM_DPRINTF("ivshmem_load_old\n"); - - if (version_id != 0) { - return -EINVAL; - } - - ret = ivshmem_pre_load(s); - if (ret) { - return ret; - } - - ret = pci_device_load(pdev, f); - if (ret) { - return ret; - } - - if (ivshmem_has_feature(s, IVSHMEM_MSI)) { - msix_load(pdev, f); - ivshmem_msix_vector_use(s); - } else { - s->intrstatus = qemu_get_be32(f); - s->intrmask = qemu_get_be32(f); - } - - return 0; -} - -static bool test_msix(void *opaque, int version_id) -{ - IVShmemState *s = opaque; - - return ivshmem_has_feature(s, IVSHMEM_MSI); -} - -static bool test_no_msix(void *opaque, int version_id) -{ - return !test_msix(opaque, version_id); -} - -static const VMStateDescription ivshmem_vmsd = { - .name = "ivshmem", - .version_id = 1, - .minimum_version_id = 1, - .pre_load = ivshmem_pre_load, - .post_load = ivshmem_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, IVShmemState), - - VMSTATE_MSIX_TEST(parent_obj, IVShmemState, test_msix), - VMSTATE_UINT32_TEST(intrstatus, IVShmemState, test_no_msix), - VMSTATE_UINT32_TEST(intrmask, IVShmemState, test_no_msix), - - VMSTATE_END_OF_LIST() - }, - .load_state_old = ivshmem_load_old, - .minimum_version_id_old = 0 -}; - -static Property ivshmem_properties[] = { - DEFINE_PROP_CHR("chardev", IVShmemState, server_chr), - DEFINE_PROP_STRING("size", IVShmemState, sizearg), - DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1), - DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, - false), - DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true), - DEFINE_PROP_STRING("shm", IVShmemState, shmobj), - DEFINE_PROP_STRING("role", IVShmemState, role), - DEFINE_PROP_UINT32("use64", IVShmemState, not_legacy_32bit, 1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void desugar_shm(IVShmemState *s) -{ - Object *obj; - char *path; - - obj = object_new("memory-backend-file"); - path = g_strdup_printf("/dev/shm/%s", s->shmobj); - object_property_set_str(obj, path, "mem-path", &error_abort); - g_free(path); - object_property_set_int(obj, s->legacy_size, "size", &error_abort); - object_property_set_bool(obj, true, "share", &error_abort); - object_property_add_child(OBJECT(s), "internal-shm-backend", obj, - &error_abort); - object_unref(obj); - user_creatable_complete(USER_CREATABLE(obj), &error_abort); - s->hostmem = MEMORY_BACKEND(obj); -} - -static void ivshmem_realize(PCIDevice *dev, Error **errp) -{ - IVShmemState *s = IVSHMEM_COMMON(dev); - - if (!qtest_enabled()) { - warn_report("ivshmem is deprecated, please use ivshmem-plain" - " or ivshmem-doorbell instead"); - } - - if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) { - error_setg(errp, "You must specify either 'shm' or 'chardev'"); - return; - } - - if (s->sizearg == NULL) { - s->legacy_size = 4 * MiB; /* 4 MB default */ - } else { - int ret; - uint64_t size; - - ret = qemu_strtosz_MiB(s->sizearg, NULL, &size); - if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) { - error_setg(errp, "Invalid size %s", s->sizearg); - return; - } - s->legacy_size = size; - } - - /* check that role is reasonable */ - if (s->role) { - if (strncmp(s->role, "peer", 5) == 0) { - s->master = ON_OFF_AUTO_OFF; - } else if (strncmp(s->role, "master", 7) == 0) { - s->master = ON_OFF_AUTO_ON; - } else { - error_setg(errp, "'role' must be 'peer' or 'master'"); - return; - } - } else { - s->master = ON_OFF_AUTO_AUTO; - } - - if (s->shmobj) { - desugar_shm(s); - } - - /* - * Note: we don't use INTx with IVSHMEM_MSI at all, so this is a - * bald-faced lie then. But it's a backwards compatible lie. - */ - pci_config_set_interrupt_pin(dev->config, 1); - - ivshmem_common_realize(dev, errp); -} - -static void ivshmem_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->realize = ivshmem_realize; - k->revision = 0; - dc->desc = "Inter-VM shared memory (legacy)"; - dc->props = ivshmem_properties; - dc->vmsd = &ivshmem_vmsd; -} - -static const TypeInfo ivshmem_info = { - .name = TYPE_IVSHMEM, - .parent = TYPE_IVSHMEM_COMMON, - .instance_size = sizeof(IVShmemState), - .class_init = ivshmem_class_init, -}; - static void ivshmem_register_types(void) { type_register_static(&ivshmem_common_info); type_register_static(&ivshmem_plain_info); type_register_static(&ivshmem_doorbell_info); - type_register_static(&ivshmem_info); } type_init(ivshmem_register_types) diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi index 81de5fc..219206a 100644 --- a/qemu-deprecated.texi +++ b/qemu-deprecated.texi @@ -126,11 +126,6 @@ documentation of ``query-hotpluggable-cpus'' for additional details. @section System emulator devices -@subsection ivshmem (since 2.6.0) - -The ``ivshmem'' device type is replaced by either the ``ivshmem-plain'' -or ``ivshmem-doorbell`` device types. - @subsection bluetooth (since 3.1) The bluetooth subsystem is unmaintained since many years and likely bitrotten diff --git a/scripts/device-crash-test b/scripts/device-crash-test index e93a7c0..a835772 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -83,7 +83,6 @@ ERROR_WHITELIST = [ {'device':'isa-ipmi-bt', 'expected':True}, # IPMI device requires a bmc attribute to be set {'device':'isa-ipmi-kcs', 'expected':True}, # IPMI device requires a bmc attribute to be set {'device':'isa-parallel', 'expected':True}, # Can't create serial device, empty char device - {'device':'ivshmem', 'expected':True}, # You must specify either 'shm' or 'chardev' {'device':'ivshmem-doorbell', 'expected':True}, # You must specify a 'chardev' {'device':'ivshmem-plain', 'expected':True}, # You must specify a 'memdev' {'device':'loader', 'expected':True}, # please include valid arguments diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index fe5eb30..4911b69 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -291,20 +291,20 @@ static void *server_thread(void *data) return NULL; } -static void setup_vm_with_server(IVState *s, int nvectors, bool msi) +static void setup_vm_with_server(IVState *s, int nvectors) { - char *cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait " - "-device ivshmem%s,chardev=chr0,vectors=%d", - tmpserver, - msi ? "-doorbell" : ",size=1M,msi=off", - nvectors); + char *cmd; - setup_vm_cmd(s, cmd, msi); + cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait " + "-device ivshmem-doorbell,chardev=chr0,vectors=%d", + tmpserver, nvectors); + + setup_vm_cmd(s, cmd, true); g_free(cmd); } -static void test_ivshmem_server(bool msi) +static void test_ivshmem_server(void) { IVState state1, state2, *s1, *s2; ServerThread thread; @@ -327,9 +327,9 @@ static void test_ivshmem_server(bool msi) thread.thread = g_thread_new("ivshmem-server", server_thread, &thread); g_assert(thread.thread != NULL); - setup_vm_with_server(&state1, nvectors, msi); + setup_vm_with_server(&state1, nvectors); s1 = &state1; - setup_vm_with_server(&state2, nvectors, msi); + setup_vm_with_server(&state2, nvectors); s2 = &state2; /* check got different VM ids */ @@ -340,38 +340,28 @@ static void test_ivshmem_server(bool msi) g_assert_cmpint(vm1, !=, vm2); /* check number of MSI-X vectors */ - if (msi) { - ret = qpci_msix_table_size(s1->dev); - g_assert_cmpuint(ret, ==, nvectors); - } + ret = qpci_msix_table_size(s1->dev); + g_assert_cmpuint(ret, ==, nvectors); /* TODO test behavior before MSI-X is enabled */ /* ping vm2 -> vm1 on vector 0 */ - if (msi) { - ret = qpci_msix_pending(s1->dev, 0); - g_assert_cmpuint(ret, ==, 0); - } else { - g_assert_cmpuint(in_reg(s1, INTRSTATUS), ==, 0); - } + ret = qpci_msix_pending(s1->dev, 0); + g_assert_cmpuint(ret, ==, 0); out_reg(s2, DOORBELL, vm1 << 16); do { g_usleep(10000); - ret = msi ? qpci_msix_pending(s1->dev, 0) : in_reg(s1, INTRSTATUS); + ret = qpci_msix_pending(s1->dev, 0); } while (ret == 0 && g_get_monotonic_time() < end_time); g_assert_cmpuint(ret, !=, 0); /* ping vm1 -> vm2 on vector 1 */ - if (msi) { - ret = qpci_msix_pending(s2->dev, 1); - g_assert_cmpuint(ret, ==, 0); - } else { - g_assert_cmpuint(in_reg(s2, INTRSTATUS), ==, 0); - } + ret = qpci_msix_pending(s2->dev, 1); + g_assert_cmpuint(ret, ==, 0); out_reg(s1, DOORBELL, vm2 << 16 | 1); do { g_usleep(10000); - ret = msi ? qpci_msix_pending(s2->dev, 1) : in_reg(s2, INTRSTATUS); + ret = qpci_msix_pending(s2->dev, 1); } while (ret == 0 && g_get_monotonic_time() < end_time); g_assert_cmpuint(ret, !=, 0); @@ -389,27 +379,17 @@ static void test_ivshmem_server(bool msi) close(thread.pipe[0]); } -static void test_ivshmem_server_msi(void) -{ - test_ivshmem_server(true); -} - -static void test_ivshmem_server_irq(void) -{ - test_ivshmem_server(false); -} - #define PCI_SLOT_HP 0x06 static void test_ivshmem_hotplug(void) { const char *arch = qtest_get_arch(); - qtest_start(""); + qtest_start("-object memory-backend-ram,size=1M,id=mb1"); - qtest_qmp_device_add("ivshmem", - "iv1", "{'addr': %s, 'shm': %s, 'size': '1M'}", - stringify(PCI_SLOT_HP), tmpshm); + qtest_qmp_device_add("ivshmem-plain", "iv1", + "{'addr': %s, 'memdev': 'mb1'}", + stringify(PCI_SLOT_HP)); if (strcmp(arch, "ppc64") != 0) { qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP); } @@ -509,8 +489,7 @@ int main(int argc, char **argv) if (g_test_slow()) { qtest_add_func("/ivshmem/pair", test_ivshmem_pair); if (strcmp(arch, "ppc64") != 0) { - qtest_add_func("/ivshmem/server-msi", test_ivshmem_server_msi); - qtest_add_func("/ivshmem/server-irq", test_ivshmem_server_irq); + qtest_add_func("/ivshmem/server", test_ivshmem_server); } } -- cgit v1.1 From a5390d936714482ac5996e1635a6ffd9c3c133df Mon Sep 17 00:00:00 2001 From: Jian Wang Date: Sat, 22 Dec 2018 18:27:28 +0800 Subject: qemu: avoid memory leak while remove disk Memset vhost_dev to zero in the vhost_dev_cleanup function. This causes dev.vqs to be NULL, so that vqs does not free up space when calling the g_free function. This will result in a memory leak. But you can't release vqs directly in the vhost_dev_cleanup function, because vhost_net will also call this function, and vhost_net's vqs is assigned by array. In order to solve this problem, we first save the pointer of vqs, and release the space of vqs after vhost_dev_cleanup is called. Signed-off-by: Jian Wang Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/vhost-user-blk.c | 7 +++++-- hw/scsi/vhost-scsi.c | 3 ++- hw/scsi/vhost-user-scsi.c | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 1451940..c3af28f 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -250,6 +250,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(vdev); VhostUserState *user; + struct vhost_virtqueue *vqs = NULL; int i, ret; if (!s->chardev.chr) { @@ -288,6 +289,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs); s->dev.vq_index = 0; s->dev.backend_features = 0; + vqs = s->dev.vqs; vhost_dev_set_config_notifier(&s->dev, &blk_ops); @@ -314,7 +316,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) vhost_err: vhost_dev_cleanup(&s->dev); virtio_err: - g_free(s->dev.vqs); + g_free(vqs); virtio_cleanup(vdev); vhost_user_cleanup(user); @@ -326,10 +328,11 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(dev); + struct vhost_virtqueue *vqs = s->dev.vqs; vhost_user_blk_set_status(vdev, 0); vhost_dev_cleanup(&s->dev); - g_free(s->dev.vqs); + g_free(vqs); virtio_cleanup(vdev); if (s->vhost_user) { diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 7f21b4f..61e2e57 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -215,6 +215,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); + struct vhost_virtqueue *vqs = vsc->dev.vqs; migrate_del_blocker(vsc->migration_blocker); error_free(vsc->migration_blocker); @@ -223,7 +224,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) vhost_scsi_set_status(vdev, 0); vhost_dev_cleanup(&vsc->dev); - g_free(vsc->dev.vqs); + g_free(vqs); virtio_scsi_common_unrealize(dev, errp); } diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 2e1ba4a..6728878 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -121,12 +121,13 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserSCSI *s = VHOST_USER_SCSI(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + struct vhost_virtqueue *vqs = vsc->dev.vqs; /* This will stop the vhost backend. */ vhost_user_scsi_set_status(vdev, 0); vhost_dev_cleanup(&vsc->dev); - g_free(vsc->dev.vqs); + g_free(vqs); virtio_scsi_common_unrealize(dev, errp); -- cgit v1.1 From 82248cd45e6f82da892127c4749ae89335217e31 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Sat, 15 Dec 2018 04:03:51 -0800 Subject: tests: vhost-user-test: initialize 'fd' in chr_read Currently when processing VHOST_USER_SET_VRING_CALL if 'qemu_chr_fe_get_msgfds' get no fd, the 'fd' will be a stack uninitialized value. Signed-off-by: Li Qiang Reviewed-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/vhost-user-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index 54982f6..84e50d8 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -309,7 +309,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) CharBackend *chr = &s->chr; VhostUserMsg msg; uint8_t *p = (uint8_t *) &msg; - int fd; + int fd = -1; if (s->test_fail) { qemu_chr_fe_disconnect(chr); -- cgit v1.1 From b0aa77d36d9150aaa7acd8b86e4e65162939d0bf Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Sat, 15 Dec 2018 04:03:52 -0800 Subject: vhost-user: fix ioeventfd_enabled Currently, the vhost-user-test assumes the eventfd is available. However it's not true because the accel is qtest. So the 'vhost_set_vring_file' will not add fds to the msg and the server side of vhost-user-test will be broken. The bug is in 'ioeventfd_enabled'. We should make this function return true if not using kvm accel. Signed-off-by: Li Qiang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index e09bed0..564a31d 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -207,7 +207,7 @@ struct vhost_user { static bool ioeventfd_enabled(void) { - return kvm_enabled() && kvm_eventfds_enabled(); + return !kvm_enabled() || kvm_eventfds_enabled(); } static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) -- cgit v1.1 From da93b82079dcb43885a84bc25b746fd15ae29dfb Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Sat, 15 Dec 2018 04:03:53 -0800 Subject: util: check the return value of fcntl in qemu_set_{block, nonblock} Assert that the return value is not an error. This is like commit 7e6478e7d4f for qemu_set_cloexec. Signed-off-by: Li Qiang Reviewed-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- util/oslib-posix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index c1bee2a..4ce1ba9 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -233,14 +233,18 @@ void qemu_set_block(int fd) { int f; f = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, f & ~O_NONBLOCK); + assert(f != -1); + f = fcntl(fd, F_SETFL, f & ~O_NONBLOCK); + assert(f != -1); } void qemu_set_nonblock(int fd) { int f; f = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, f | O_NONBLOCK); + assert(f != -1); + f = fcntl(fd, F_SETFL, f | O_NONBLOCK); + assert(f != -1); } int socket_set_fast_reuse(int fd) -- cgit v1.1 From 81eb530db4ce24b7cc3cd8303505a8053ee1b6cc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:27 +0100 Subject: tests: acpi: use AcpiSdtTable::aml in consistent way Currently in the 1st case we store table body fetched from QEMU in AcpiSdtTable::aml minus it's header but in the 2nd case when we load reference aml from disk, it holds whole blob including header. More over in the 1st case, we read header in separate AcpiSdtTable::header structure and then jump over hoops to fixup tables and combine both. Treat AcpiSdtTable::aml as whole table blob approach in both cases and when fetching tables from QEMU, first get table length and then fetch whole table into AcpiSdtTable::aml instead if doing it field by field. As result * AcpiSdtTable::aml is used in consistent manner * FADT fixups use offsets from spec instead of being shifted by header length * calculating checksums and dumping blobs becomes simpler Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/acpi-utils.h | 6 +++-- tests/bios-tables-test.c | 64 ++++++++++++++++++------------------------------ 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h index c5b0e12..1b0e80d 100644 --- a/tests/acpi-utils.h +++ b/tests/acpi-utils.h @@ -18,8 +18,10 @@ /* DSDT and SSDTs format */ typedef struct { - AcpiTableHeader header; - gchar *aml; /* aml bytecode from guest */ + union { + AcpiTableHeader *header; + uint8_t *aml; /* aml bytecode from guest */ + }; gsize aml_len; gchar *aml_file; gchar *asl; /* asl code generated from aml */ diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index d455b2a..3f20bbd 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -163,29 +163,23 @@ static void sanitize_fadt_ptrs(test_data *data) for (i = 0; i < data->tables->len; i++) { AcpiSdtTable *sdt = &g_array_index(data->tables, AcpiSdtTable, i); - if (memcmp(&sdt->header.signature, "FACP", 4)) { + if (memcmp(&sdt->header->signature, "FACP", 4)) { continue; } /* check original FADT checksum before sanitizing table */ - g_assert(!(uint8_t)( - acpi_calc_checksum((uint8_t *)sdt, sizeof(AcpiTableHeader)) + - acpi_calc_checksum((uint8_t *)sdt->aml, sdt->aml_len) - )); - - /* sdt->aml field offset := spec offset - header size */ - memset(sdt->aml + 0, 0, 4); /* sanitize FIRMWARE_CTRL(36) ptr */ - memset(sdt->aml + 4, 0, 4); /* sanitize DSDT(40) ptr */ - if (sdt->header.revision >= 3) { - memset(sdt->aml + 96, 0, 8); /* sanitize X_FIRMWARE_CTRL(132) ptr */ - memset(sdt->aml + 104, 0, 8); /* sanitize X_DSDT(140) ptr */ + g_assert(!acpi_calc_checksum(sdt->aml, sdt->aml_len)); + + memset(sdt->aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */ + memset(sdt->aml + 40, 0, 4); /* sanitize DSDT ptr */ + if (sdt->header->revision >= 3) { + memset(sdt->aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */ + memset(sdt->aml + 140, 0, 8); /* sanitize X_DSDT ptr */ } /* update checksum */ - sdt->header.checksum = 0; - sdt->header.checksum -= - acpi_calc_checksum((uint8_t *)sdt, sizeof(AcpiTableHeader)) + - acpi_calc_checksum((uint8_t *)sdt->aml, sdt->aml_len); + sdt->header->checksum = 0; + sdt->header->checksum -= acpi_calc_checksum(sdt->aml, sdt->aml_len); break; } } @@ -212,30 +206,23 @@ static void test_acpi_facs_table(test_data *data) */ static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, uint32_t addr) { - uint8_t checksum; - - memset(sdt_table, 0, sizeof(*sdt_table)); - ACPI_READ_TABLE_HEADER(qts, &sdt_table->header, addr); - - sdt_table->aml_len = le32_to_cpu(sdt_table->header.length) - - sizeof(AcpiTableHeader); + qtest_memread(qts, addr + 4 /* Length of ACPI table */, + &sdt_table->aml_len, 4); + sdt_table->aml_len = le32_to_cpu(sdt_table->aml_len); sdt_table->aml = g_malloc0(sdt_table->aml_len); - ACPI_READ_ARRAY_PTR(qts, sdt_table->aml, sdt_table->aml_len, addr); + /* get whole table */ + qtest_memread(qts, addr, sdt_table->aml, sdt_table->aml_len); - checksum = acpi_calc_checksum((uint8_t *)sdt_table, - sizeof(AcpiTableHeader)) + - acpi_calc_checksum((uint8_t *)sdt_table->aml, - sdt_table->aml_len); - g_assert(!checksum); + g_assert(!acpi_calc_checksum(sdt_table->aml, sdt_table->aml_len)); } static void test_acpi_dsdt_table(test_data *data) { - AcpiSdtTable dsdt_table; + AcpiSdtTable dsdt_table = {}; uint32_t addr = le32_to_cpu(data->dsdt_addr); fetch_table(data->qts, &dsdt_table, addr); - ACPI_ASSERT_CMP(dsdt_table.header.signature, "DSDT"); + ACPI_ASSERT_CMP(dsdt_table.header->signature, "DSDT"); /* Since DSDT isn't in RSDT, add DSDT to ASL test tables list manually */ g_array_append_val(data->tables, dsdt_table); @@ -248,7 +235,7 @@ static void fetch_rsdt_referenced_tables(test_data *data) int i; for (i = 0; i < tables_nr; i++) { - AcpiSdtTable ssdt_table; + AcpiSdtTable ssdt_table = {}; uint32_t addr; addr = le32_to_cpu(data->rsdt_tables_addr[i]); @@ -275,7 +262,7 @@ static void dump_aml_files(test_data *data, bool rebuild) if (rebuild) { aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, - (gchar *)&sdt->header.signature, ext); + (gchar *)&sdt->header->signature, ext); fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); } else { @@ -284,8 +271,6 @@ static void dump_aml_files(test_data *data, bool rebuild) } g_assert(fd >= 0); - ret = qemu_write_full(fd, sdt, sizeof(AcpiTableHeader)); - g_assert(ret == sizeof(AcpiTableHeader)); ret = qemu_write_full(fd, sdt->aml, sdt->aml_len); g_assert(ret == sdt->aml_len); @@ -297,7 +282,7 @@ static void dump_aml_files(test_data *data, bool rebuild) static bool compare_signature(AcpiSdtTable *sdt, const char *signature) { - return !memcmp(&sdt->header.signature, signature, 4); + return !memcmp(&sdt->header->signature, signature, 4); } static bool load_asl(GArray *sdts, AcpiSdtTable *sdt) @@ -395,11 +380,10 @@ static GArray *load_expected_aml(test_data *data) sdt = &g_array_index(data->tables, AcpiSdtTable, i); memset(&exp_sdt, 0, sizeof(exp_sdt)); - exp_sdt.header.signature = sdt->header.signature; try_again: aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, - (gchar *)&sdt->header.signature, ext); + (gchar *)&sdt->header->signature, ext); if (getenv("V")) { fprintf(stderr, "Looking for expected file '%s'\n", aml_file); } @@ -415,7 +399,7 @@ try_again: if (getenv("V")) { fprintf(stderr, "Using expected file '%s'\n", aml_file); } - ret = g_file_get_contents(aml_file, &exp_sdt.aml, + ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml, &exp_sdt.aml_len, &error); g_assert(ret); g_assert_no_error(error); @@ -459,7 +443,7 @@ static void test_acpi_asl(test_data *data) fprintf(stderr, "Warning! iasl couldn't parse the expected aml\n"); } else { - uint32_t signature = cpu_to_le32(exp_sdt->header.signature); + uint32_t signature = cpu_to_le32(exp_sdt->header->signature); sdt->tmp_files_retain = true; exp_sdt->tmp_files_retain = true; fprintf(stderr, -- cgit v1.1 From db5754498878c754a1ea755e726816ee50cbf2c0 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:28 +0100 Subject: tests: acpi: make sure FADT is fetched only once Whole FADT is fetched as part of RSDT referenced tables in fetch_rsdt_referenced_tables() albeit a bit later than when FADT is partially parsed in fadt_fetch_facs_and_dsdt_ptrs(). However there is no reason for calling fetch_rsdt_referenced_tables() so late, just move it right after we fetched RSDT and before fadt_fetch_facs_and_dsdt_ptrs(). That way we can reuse whole FADT fetched by fetch_rsdt_referenced_tables() and avoid duplicate custom fields fetching in fadt_fetch_facs_and_dsdt_ptrs(). While at it rename fadt_fetch_facs_and_dsdt_ptrs() to test_acpi_fadt_table(). The follow up patch will merge fadt_fetch_facs_and_dsdt_ptrs() into test_acpi_rsdt_table(), so that we would end up calling only test_acpi_FOO_table() for consistency for tables that require special processing. Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/bios-tables-test.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 3f20bbd..b2a40bb 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -141,18 +141,15 @@ static void test_acpi_rsdt_table(test_data *data) data->rsdt_tables_nr = tables_nr; } -static void fadt_fetch_facs_and_dsdt_ptrs(test_data *data) +static void test_acpi_fadt_table(test_data *data) { - uint32_t addr; - AcpiTableHeader hdr; + /* FADT table is 1st */ + AcpiSdtTable *fadt = &g_array_index(data->tables, typeof(*fadt), 0); - /* FADT table comes first */ - addr = le32_to_cpu(data->rsdt_tables_addr[0]); - ACPI_READ_TABLE_HEADER(data->qts, &hdr, addr); - ACPI_ASSERT_CMP(hdr.signature, "FACP"); + ACPI_ASSERT_CMP(fadt->header->signature, "FACP"); - ACPI_READ_FIELD(data->qts, data->facs_addr, addr); - ACPI_READ_FIELD(data->qts, data->dsdt_addr, addr); + memcpy(&data->facs_addr, fadt->aml + 36 /* FIRMWARE_CTRL */, 4); + memcpy(&data->dsdt_addr, fadt->aml + 40 /* DSDT */, 4); } static void sanitize_fadt_ptrs(test_data *data) @@ -628,10 +625,10 @@ static void test_acpi_one(const char *params, test_data *data) test_acpi_rsdp_address(data); test_acpi_rsdp_table(data); test_acpi_rsdt_table(data); - fadt_fetch_facs_and_dsdt_ptrs(data); + fetch_rsdt_referenced_tables(data); + test_acpi_fadt_table(data); test_acpi_facs_table(data); test_acpi_dsdt_table(data); - fetch_rsdt_referenced_tables(data); sanitize_fadt_ptrs(data); -- cgit v1.1 From 569afd8428a5d0d9dab5be60df46920fb277194c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:29 +0100 Subject: tests: acpi: simplify rsdt handling RSDT referenced tables always have length at offset 4 and checksum at offset 9, that's enough for reusing fetch_table() and replacing custom RSDT fetching code with it. While at it * merge fetch_rsdt_referenced_tables() into test_acpi_rsdt_table() * drop test_data::rsdt_table/rsdt_tables_addr/rsdt_tables_nr since we need this data only for duration of test_acpi_rsdt_table() to fetch other tables and use locals instead. Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/bios-tables-test.c | 137 +++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 82 deletions(-) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index b2a40bb..8082adc 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -28,12 +28,9 @@ typedef struct { const char *variant; uint32_t rsdp_addr; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */]; - AcpiRsdtDescriptorRev1 rsdt_table; uint32_t dsdt_addr; uint32_t facs_addr; AcpiFacsDescriptorRev1 facs_table; - uint32_t *rsdt_tables_addr; - int rsdt_tables_nr; GArray *tables; uint32_t smbios_ep_addr; struct smbios_21_entry_point smbios_ep_table; @@ -50,33 +47,50 @@ static const char *iasl = stringify(CONFIG_IASL); static const char *iasl; #endif +static void cleanup_table_descriptor(AcpiSdtTable *table) +{ + g_free(table->aml); + if (table->aml_file && + !table->tmp_files_retain && + g_strstr_len(table->aml_file, -1, "aml-")) { + unlink(table->aml_file); + } + g_free(table->aml_file); + g_free(table->asl); + if (table->asl_file && + !table->tmp_files_retain) { + unlink(table->asl_file); + } + g_free(table->asl_file); +} + static void free_test_data(test_data *data) { - AcpiSdtTable *temp; int i; - g_free(data->rsdt_tables_addr); - for (i = 0; i < data->tables->len; ++i) { - temp = &g_array_index(data->tables, AcpiSdtTable, i); - g_free(temp->aml); - if (temp->aml_file && - !temp->tmp_files_retain && - g_strstr_len(temp->aml_file, -1, "aml-")) { - unlink(temp->aml_file); - } - g_free(temp->aml_file); - g_free(temp->asl); - if (temp->asl_file && - !temp->tmp_files_retain) { - unlink(temp->asl_file); - } - g_free(temp->asl_file); + cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i)); } g_array_free(data->tables, true); } +/** fetch_table + * load ACPI table at @addr into table descriptor @sdt_table + * and check that header checksum matches actual one. + */ +static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, uint32_t addr) +{ + qtest_memread(qts, addr + 4 /* Length of ACPI table */, + &sdt_table->aml_len, 4); + sdt_table->aml_len = le32_to_cpu(sdt_table->aml_len); + sdt_table->aml = g_malloc0(sdt_table->aml_len); + /* get whole table */ + qtest_memread(qts, addr, sdt_table->aml, sdt_table->aml_len); + + g_assert(!acpi_calc_checksum(sdt_table->aml, sdt_table->aml_len)); +} + static void test_acpi_rsdp_address(test_data *data) { uint32_t off = acpi_find_rsdp_address(data->qts); @@ -109,36 +123,30 @@ static void test_acpi_rsdp_table(test_data *data) static void test_acpi_rsdt_table(test_data *data) { - AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table; uint32_t addr = acpi_get_rsdt_address(data->rsdp_table); - uint32_t *tables; - int tables_nr; - uint8_t checksum; - uint32_t rsdt_table_length; - - /* read the header */ - ACPI_READ_TABLE_HEADER(data->qts, rsdt_table, addr); - ACPI_ASSERT_CMP(rsdt_table->signature, "RSDT"); - - rsdt_table_length = le32_to_cpu(rsdt_table->length); - - /* compute the table entries in rsdt */ - tables_nr = (rsdt_table_length - sizeof(AcpiRsdtDescriptorRev1)) / - sizeof(uint32_t); - g_assert(tables_nr > 0); - - /* get the addresses of the tables pointed by rsdt */ - tables = g_new0(uint32_t, tables_nr); - ACPI_READ_ARRAY_PTR(data->qts, tables, tables_nr, addr); + const int entry_size = 4 /* 32-bit Entry size */; + const int tables_off = 36 /* 1st Entry */; + AcpiSdtTable rsdt = {}; + int i, table_len, table_nr; + uint32_t *entry; + + fetch_table(data->qts, &rsdt, addr); + ACPI_ASSERT_CMP(rsdt.header->signature, "RSDT"); + + /* Load all tables and add to test list directly RSDT referenced tables */ + table_len = le32_to_cpu(rsdt.header->length); + table_nr = (table_len - tables_off) / entry_size; + for (i = 0; i < table_nr; i++) { + AcpiSdtTable ssdt_table = {}; - checksum = acpi_calc_checksum((uint8_t *)rsdt_table, rsdt_table_length) + - acpi_calc_checksum((uint8_t *)tables, - tables_nr * sizeof(uint32_t)); - g_assert(!checksum); + entry = (uint32_t *)(rsdt.aml + tables_off + i * entry_size); + addr = le32_to_cpu(*entry); + fetch_table(data->qts, &ssdt_table, addr); - /* SSDT tables after FADT */ - data->rsdt_tables_addr = tables; - data->rsdt_tables_nr = tables_nr; + /* Add table to ASL test tables list */ + g_array_append_val(data->tables, ssdt_table); + } + cleanup_table_descriptor(&rsdt); } static void test_acpi_fadt_table(test_data *data) @@ -197,22 +205,6 @@ static void test_acpi_facs_table(test_data *data) ACPI_ASSERT_CMP(facs_table->signature, "FACS"); } -/** fetch_table - * load ACPI table at @addr into table descriptor @sdt_table - * and check that header checksum matches actual one. - */ -static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, uint32_t addr) -{ - qtest_memread(qts, addr + 4 /* Length of ACPI table */, - &sdt_table->aml_len, 4); - sdt_table->aml_len = le32_to_cpu(sdt_table->aml_len); - sdt_table->aml = g_malloc0(sdt_table->aml_len); - /* get whole table */ - qtest_memread(qts, addr, sdt_table->aml, sdt_table->aml_len); - - g_assert(!acpi_calc_checksum(sdt_table->aml, sdt_table->aml_len)); -} - static void test_acpi_dsdt_table(test_data *data) { AcpiSdtTable dsdt_table = {}; @@ -225,24 +217,6 @@ static void test_acpi_dsdt_table(test_data *data) g_array_append_val(data->tables, dsdt_table); } -/* Load all tables and add to test list directly RSDT referenced tables */ -static void fetch_rsdt_referenced_tables(test_data *data) -{ - int tables_nr = data->rsdt_tables_nr; - int i; - - for (i = 0; i < tables_nr; i++) { - AcpiSdtTable ssdt_table = {}; - uint32_t addr; - - addr = le32_to_cpu(data->rsdt_tables_addr[i]); - fetch_table(data->qts, &ssdt_table, addr); - - /* Add table to ASL test tables list */ - g_array_append_val(data->tables, ssdt_table); - } -} - static void dump_aml_files(test_data *data, bool rebuild) { AcpiSdtTable *sdt; @@ -625,7 +599,6 @@ static void test_acpi_one(const char *params, test_data *data) test_acpi_rsdp_address(data); test_acpi_rsdp_table(data); test_acpi_rsdt_table(data); - fetch_rsdt_referenced_tables(data); test_acpi_fadt_table(data); test_acpi_facs_table(data); test_acpi_dsdt_table(data); -- cgit v1.1 From 59f9c6cc014309cde537842af2104b2f9956b0d6 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:30 +0100 Subject: tests: acpi: reuse fetch_table() for fetching FACS and DSDT It allows to remove a bit more of code duplication and reuse common utility to get ACPI tables from guest (modulo RSDP). While at it, consolidate signature checking into fetch_table() instead of open-codding it. Considering FACS is special and doesn't have checksum, make checksum validation optin, the same goes for signature verification. PS: By pure accident, patch also fixes FACS not being tested against reference table since it wasn't added to data::tables list. But we managed not to regress it since reference file was added by commit (d25979380 acpi unit-test: add test files) back in 2013 Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/bios-tables-test.c | 78 +++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 8082adc..0f6dd84 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -28,9 +28,6 @@ typedef struct { const char *variant; uint32_t rsdp_addr; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */]; - uint32_t dsdt_addr; - uint32_t facs_addr; - AcpiFacsDescriptorRev1 facs_table; GArray *tables; uint32_t smbios_ep_addr; struct smbios_21_entry_point smbios_ep_table; @@ -76,11 +73,18 @@ static void free_test_data(test_data *data) } /** fetch_table - * load ACPI table at @addr into table descriptor @sdt_table - * and check that header checksum matches actual one. + * load ACPI table at @addr_ptr offset pointer into table descriptor + * @sdt_table and check that signature/checksum matches actual one. */ -static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, uint32_t addr) +static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, + uint8_t *addr_ptr, const char *sig, + bool verify_checksum) { + uint32_t addr; + + memcpy(&addr, addr_ptr , sizeof(addr)); + addr = le32_to_cpu(addr); + qtest_memread(qts, addr + 4 /* Length of ACPI table */, &sdt_table->aml_len, 4); sdt_table->aml_len = le32_to_cpu(sdt_table->aml_len); @@ -88,7 +92,12 @@ static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, uint32_t addr) /* get whole table */ qtest_memread(qts, addr, sdt_table->aml, sdt_table->aml_len); - g_assert(!acpi_calc_checksum(sdt_table->aml, sdt_table->aml_len)); + if (sig) { + ACPI_ASSERT_CMP(sdt_table->header->signature, sig); + } + if (verify_checksum) { + g_assert(!acpi_calc_checksum(sdt_table->aml, sdt_table->aml_len)); + } } static void test_acpi_rsdp_address(test_data *data) @@ -123,15 +132,13 @@ static void test_acpi_rsdp_table(test_data *data) static void test_acpi_rsdt_table(test_data *data) { - uint32_t addr = acpi_get_rsdt_address(data->rsdp_table); const int entry_size = 4 /* 32-bit Entry size */; const int tables_off = 36 /* 1st Entry */; AcpiSdtTable rsdt = {}; int i, table_len, table_nr; - uint32_t *entry; - fetch_table(data->qts, &rsdt, addr); - ACPI_ASSERT_CMP(rsdt.header->signature, "RSDT"); + fetch_table(data->qts, &rsdt, &data->rsdp_table[16 /* RsdtAddress */], + "RSDT", true); /* Load all tables and add to test list directly RSDT referenced tables */ table_len = le32_to_cpu(rsdt.header->length); @@ -139,9 +146,8 @@ static void test_acpi_rsdt_table(test_data *data) for (i = 0; i < table_nr; i++) { AcpiSdtTable ssdt_table = {}; - entry = (uint32_t *)(rsdt.aml + tables_off + i * entry_size); - addr = le32_to_cpu(*entry); - fetch_table(data->qts, &ssdt_table, addr); + fetch_table(data->qts, &ssdt_table, + rsdt.aml + tables_off + i * entry_size, NULL, true); /* Add table to ASL test tables list */ g_array_append_val(data->tables, ssdt_table); @@ -152,12 +158,18 @@ static void test_acpi_rsdt_table(test_data *data) static void test_acpi_fadt_table(test_data *data) { /* FADT table is 1st */ - AcpiSdtTable *fadt = &g_array_index(data->tables, typeof(*fadt), 0); + AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0); + uint8_t *fadt_aml = table.aml; - ACPI_ASSERT_CMP(fadt->header->signature, "FACP"); + ACPI_ASSERT_CMP(table.header->signature, "FACP"); - memcpy(&data->facs_addr, fadt->aml + 36 /* FIRMWARE_CTRL */, 4); - memcpy(&data->dsdt_addr, fadt->aml + 40 /* DSDT */, 4); + /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */ + fetch_table(data->qts, &table, fadt_aml + 36 /* FIRMWARE_CTRL */, + "FACS", false); + g_array_append_val(data->tables, table); + + fetch_table(data->qts, &table, fadt_aml + 40 /* DSDT */, "DSDT", true); + g_array_append_val(data->tables, table); } static void sanitize_fadt_ptrs(test_data *data) @@ -189,34 +201,6 @@ static void sanitize_fadt_ptrs(test_data *data) } } -static void test_acpi_facs_table(test_data *data) -{ - AcpiFacsDescriptorRev1 *facs_table = &data->facs_table; - uint32_t addr = le32_to_cpu(data->facs_addr); - - ACPI_READ_FIELD(data->qts, facs_table->signature, addr); - ACPI_READ_FIELD(data->qts, facs_table->length, addr); - ACPI_READ_FIELD(data->qts, facs_table->hardware_signature, addr); - ACPI_READ_FIELD(data->qts, facs_table->firmware_waking_vector, addr); - ACPI_READ_FIELD(data->qts, facs_table->global_lock, addr); - ACPI_READ_FIELD(data->qts, facs_table->flags, addr); - ACPI_READ_ARRAY(data->qts, facs_table->resverved3, addr); - - ACPI_ASSERT_CMP(facs_table->signature, "FACS"); -} - -static void test_acpi_dsdt_table(test_data *data) -{ - AcpiSdtTable dsdt_table = {}; - uint32_t addr = le32_to_cpu(data->dsdt_addr); - - fetch_table(data->qts, &dsdt_table, addr); - ACPI_ASSERT_CMP(dsdt_table.header->signature, "DSDT"); - - /* Since DSDT isn't in RSDT, add DSDT to ASL test tables list manually */ - g_array_append_val(data->tables, dsdt_table); -} - static void dump_aml_files(test_data *data, bool rebuild) { AcpiSdtTable *sdt; @@ -600,8 +584,6 @@ static void test_acpi_one(const char *params, test_data *data) test_acpi_rsdp_table(data); test_acpi_rsdt_table(data); test_acpi_fadt_table(data); - test_acpi_facs_table(data); - test_acpi_dsdt_table(data); sanitize_fadt_ptrs(data); -- cgit v1.1 From acee774b3dbeb7fcd294b1f96c1a286d39d9b495 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:31 +0100 Subject: tests: acpi: reuse fetch_table() in vmgenid-test Move fetch_table() into acpi-utils.c renaming it to acpi_fetch_table() and reuse it in vmgenid-test that reads RSDT and then tables it references, to find and parse VMGNEID SSDT. While at it wrap RSDT referenced tables enumeration into FOREACH macro (similar to what we do with QLIST_FOREACH & co) to reuse it with bios and vmgenid tests. Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/acpi-utils.c | 35 ++++++++++++++++++++------ tests/acpi-utils.h | 23 ++++++----------- tests/bios-tables-test.c | 57 +++++++++++------------------------------- tests/vmgenid-test.c | 64 +++++++++++++++--------------------------------- 4 files changed, 69 insertions(+), 110 deletions(-) diff --git a/tests/acpi-utils.c b/tests/acpi-utils.c index 17abcc4..cc33b46 100644 --- a/tests/acpi-utils.c +++ b/tests/acpi-utils.c @@ -51,14 +51,6 @@ uint32_t acpi_find_rsdp_address(QTestState *qts) return off; } -uint32_t acpi_get_rsdt_address(uint8_t *rsdp_table) -{ - uint32_t rsdt_physical_address; - - memcpy(&rsdt_physical_address, &rsdp_table[16 /* RsdtAddress offset */], 4); - return le32_to_cpu(rsdt_physical_address); -} - uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table) { uint64_t xsdt_physical_address; @@ -92,3 +84,30 @@ void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table) ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR "); } + +/** acpi_fetch_table + * load ACPI table at @addr_ptr offset pointer into buffer and return it in + * @aml, its length in @aml_len and check that signature/checksum matches + * actual one. + */ +void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len, + const uint8_t *addr_ptr, const char *sig, + bool verify_checksum) +{ + uint32_t addr, len; + + memcpy(&addr, addr_ptr , sizeof(addr)); + addr = le32_to_cpu(addr); + qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */ + *aml_len = le32_to_cpu(len); + *aml = g_malloc0(*aml_len); + /* get whole table */ + qtest_memread(qts, addr, *aml, *aml_len); + + if (sig) { + ACPI_ASSERT_CMP(**aml, sig); + } + if (verify_checksum) { + g_assert(!acpi_calc_checksum(*aml, *aml_len)); + } +} diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h index 1b0e80d..1aa00db 100644 --- a/tests/acpi-utils.h +++ b/tests/acpi-utils.h @@ -22,7 +22,7 @@ typedef struct { AcpiTableHeader *header; uint8_t *aml; /* aml bytecode from guest */ }; - gsize aml_len; + uint32_t aml_len; gchar *aml_file; gchar *asl; /* asl code generated from aml */ gsize asl_len; @@ -47,19 +47,6 @@ typedef struct { #define ACPI_READ_ARRAY(qts, arr, addr) \ ACPI_READ_ARRAY_PTR(qts, arr, sizeof(arr) / sizeof(arr[0]), addr) -#define ACPI_READ_TABLE_HEADER(qts, table, addr) \ - do { \ - ACPI_READ_FIELD(qts, (table)->signature, addr); \ - ACPI_READ_FIELD(qts, (table)->length, addr); \ - ACPI_READ_FIELD(qts, (table)->revision, addr); \ - ACPI_READ_FIELD(qts, (table)->checksum, addr); \ - ACPI_READ_ARRAY(qts, (table)->oem_id, addr); \ - ACPI_READ_ARRAY(qts, (table)->oem_table_id, addr); \ - ACPI_READ_FIELD(qts, (table)->oem_revision, addr); \ - ACPI_READ_ARRAY(qts, (table)->asl_compiler_id, addr); \ - ACPI_READ_FIELD(qts, (table)->asl_compiler_revision, addr); \ - } while (0) - #define ACPI_ASSERT_CMP(actual, expected) do { \ char ACPI_ASSERT_CMP_str[5] = {}; \ memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \ @@ -73,11 +60,17 @@ typedef struct { } while (0) +#define ACPI_FOREACH_RSDT_ENTRY(table, table_len, entry_ptr, entry_size) \ + for (entry_ptr = table + 36 /* 1st Entry */; \ + entry_ptr < table + table_len; \ + entry_ptr += entry_size) uint8_t acpi_calc_checksum(const uint8_t *data, int len); uint32_t acpi_find_rsdp_address(QTestState *qts); -uint32_t acpi_get_rsdt_address(uint8_t *rsdp_table); uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table); void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table); +void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len, + const uint8_t *addr_ptr, const char *sig, + bool verify_checksum); #endif /* TEST_ACPI_UTILS_H */ diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 0f6dd84..3f9830f 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -72,34 +72,6 @@ static void free_test_data(test_data *data) g_array_free(data->tables, true); } -/** fetch_table - * load ACPI table at @addr_ptr offset pointer into table descriptor - * @sdt_table and check that signature/checksum matches actual one. - */ -static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, - uint8_t *addr_ptr, const char *sig, - bool verify_checksum) -{ - uint32_t addr; - - memcpy(&addr, addr_ptr , sizeof(addr)); - addr = le32_to_cpu(addr); - - qtest_memread(qts, addr + 4 /* Length of ACPI table */, - &sdt_table->aml_len, 4); - sdt_table->aml_len = le32_to_cpu(sdt_table->aml_len); - sdt_table->aml = g_malloc0(sdt_table->aml_len); - /* get whole table */ - qtest_memread(qts, addr, sdt_table->aml, sdt_table->aml_len); - - if (sig) { - ACPI_ASSERT_CMP(sdt_table->header->signature, sig); - } - if (verify_checksum) { - g_assert(!acpi_calc_checksum(sdt_table->aml, sdt_table->aml_len)); - } -} - static void test_acpi_rsdp_address(test_data *data) { uint32_t off = acpi_find_rsdp_address(data->qts); @@ -132,23 +104,19 @@ static void test_acpi_rsdp_table(test_data *data) static void test_acpi_rsdt_table(test_data *data) { - const int entry_size = 4 /* 32-bit Entry size */; - const int tables_off = 36 /* 1st Entry */; AcpiSdtTable rsdt = {}; - int i, table_len, table_nr; + uint8_t *ent; - fetch_table(data->qts, &rsdt, &data->rsdp_table[16 /* RsdtAddress */], - "RSDT", true); + /* read RSDT table */ + acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len, + &data->rsdp_table[16 /* RsdtAddress */], "RSDT", true); /* Load all tables and add to test list directly RSDT referenced tables */ - table_len = le32_to_cpu(rsdt.header->length); - table_nr = (table_len - tables_off) / entry_size; - for (i = 0; i < table_nr; i++) { + ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, 4 /* Entry size */) { AcpiSdtTable ssdt_table = {}; - fetch_table(data->qts, &ssdt_table, - rsdt.aml + tables_off + i * entry_size, NULL, true); - + acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent, + NULL, true); /* Add table to ASL test tables list */ g_array_append_val(data->tables, ssdt_table); } @@ -164,11 +132,12 @@ static void test_acpi_fadt_table(test_data *data) ACPI_ASSERT_CMP(table.header->signature, "FACP"); /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */ - fetch_table(data->qts, &table, fadt_aml + 36 /* FIRMWARE_CTRL */, - "FACS", false); + acpi_fetch_table(data->qts, &table.aml, &table.aml_len, + fadt_aml + 36 /* FIRMWARE_CTRL */, "FACS", false); g_array_append_val(data->tables, table); - fetch_table(data->qts, &table, fadt_aml + 40 /* DSDT */, "DSDT", true); + acpi_fetch_table(data->qts, &table.aml, &table.aml_len, + fadt_aml + 40 /* DSDT */, "DSDT", true); g_array_append_val(data->tables, table); } @@ -322,6 +291,7 @@ static GArray *load_expected_aml(test_data *data) AcpiSdtTable *sdt; GError *error = NULL; gboolean ret; + gsize aml_len; GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable)); if (getenv("V")) { @@ -355,7 +325,8 @@ try_again: fprintf(stderr, "Using expected file '%s'\n", aml_file); } ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml, - &exp_sdt.aml_len, &error); + &aml_len, &error); + exp_sdt.aml_len = aml_len; g_assert(ret); g_assert_no_error(error); g_assert(exp_sdt.aml); diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c index 1c1d435..52cdd83 100644 --- a/tests/vmgenid-test.c +++ b/tests/vmgenid-test.c @@ -23,26 +23,13 @@ */ #define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */ -typedef struct { - AcpiTableHeader header; - gchar name_op; - gchar vgia[4]; - gchar val_op; - uint32_t vgia_val; -} QEMU_PACKED VgidTable; - static uint32_t acpi_find_vgia(QTestState *qts) { uint32_t rsdp_offset; uint32_t guid_offset = 0; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */]; - uint32_t rsdt, rsdt_table_length; - AcpiRsdtDescriptorRev1 rsdt_table; - size_t tables_nr; - uint32_t *tables; - AcpiTableHeader ssdt_table; - VgidTable vgid_table; - int i; + uint32_t rsdt_len, table_length; + uint8_t *rsdt, *ent; /* Wait for guest firmware to finish and start the payload. */ boot_sector_test(qts); @@ -52,48 +39,37 @@ static uint32_t acpi_find_vgia(QTestState *qts) g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID); - acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table); - - rsdt = acpi_get_rsdt_address(rsdp_table); - g_assert(rsdt); - /* read the header */ - ACPI_READ_TABLE_HEADER(qts, &rsdt_table, rsdt); - ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT"); - rsdt_table_length = le32_to_cpu(rsdt_table.length); - - /* compute the table entries in rsdt */ - g_assert_cmpint(rsdt_table_length, >, sizeof(AcpiRsdtDescriptorRev1)); - tables_nr = (rsdt_table_length - sizeof(AcpiRsdtDescriptorRev1)) / - sizeof(uint32_t); + acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table); + acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */], + "RSDT", true); - /* get the addresses of the tables pointed by rsdt */ - tables = g_new0(uint32_t, tables_nr); - ACPI_READ_ARRAY_PTR(qts, tables, tables_nr, rsdt); + ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) { + uint8_t *table_aml; - for (i = 0; i < tables_nr; i++) { - uint32_t addr = le32_to_cpu(tables[i]); - ACPI_READ_TABLE_HEADER(qts, &ssdt_table, addr); - if (!strncmp((char *)ssdt_table.oem_table_id, "VMGENID", 7)) { + acpi_fetch_table(qts, &table_aml, &table_length, ent, NULL, true); + if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) { + uint32_t vgia_val; + uint8_t *aml = &table_aml[36 /* AML byte-code start */]; /* the first entry in the table should be VGIA * That's all we need */ - ACPI_READ_FIELD(qts, vgid_table.name_op, addr); - g_assert(vgid_table.name_op == 0x08); /* name */ - ACPI_READ_ARRAY(qts, vgid_table.vgia, addr); - g_assert(memcmp(vgid_table.vgia, "VGIA", 4) == 0); - ACPI_READ_FIELD(qts, vgid_table.val_op, addr); - g_assert(vgid_table.val_op == 0x0C); /* dword */ - ACPI_READ_FIELD(qts, vgid_table.vgia_val, addr); + g_assert(aml[0 /* name_op*/] == 0x08); + g_assert(memcmp(&aml[1 /* name */], "VGIA", 4) == 0); + g_assert(aml[5 /* value op */] == 0x0C /* dword */); + memcpy(&vgia_val, &aml[6 /* value */], 4); + /* The GUID is written at a fixed offset into the fw_cfg file * in order to implement the "OVMF SDT Header probe suppressor" * see docs/specs/vmgenid.txt for more details */ - guid_offset = le32_to_cpu(vgid_table.vgia_val) + VMGENID_GUID_OFFSET; + guid_offset = le32_to_cpu(vgia_val) + VMGENID_GUID_OFFSET; + g_free(table_aml); break; } + g_free(table_aml); } - g_free(tables); + g_free(rsdt); return guid_offset; } -- cgit v1.1 From 3314778d8834a9c446b14b340dbb0fdf07d01975 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:32 +0100 Subject: tests: smbios: fetch whole table in one step instead of reading it step by step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace a bunch of ACPI_READ_ARRAY/ACPI_READ_FIELD macro, that read SMBIOS table field by field with one memread() to fetch whole table at once and drop no longer used ACPI_READ_ARRAY/ACPI_READ_FIELD macro. Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/acpi-utils.h | 17 ----------------- tests/bios-tables-test.c | 15 +-------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h index 1aa00db..cb7183e 100644 --- a/tests/acpi-utils.h +++ b/tests/acpi-utils.h @@ -30,23 +30,6 @@ typedef struct { bool tmp_files_retain; /* do not delete the temp asl/aml */ } AcpiSdtTable; -#define ACPI_READ_FIELD(qts, field, addr) \ - do { \ - qtest_memread(qts, addr, &field, sizeof(field)); \ - addr += sizeof(field); \ - } while (0) - -#define ACPI_READ_ARRAY_PTR(qts, arr, length, addr) \ - do { \ - int idx; \ - for (idx = 0; idx < length; ++idx) { \ - ACPI_READ_FIELD(qts, arr[idx], addr); \ - } \ - } while (0) - -#define ACPI_READ_ARRAY(qts, arr, addr) \ - ACPI_READ_ARRAY_PTR(qts, arr, sizeof(arr) / sizeof(arr[0]), addr) - #define ACPI_ASSERT_CMP(actual, expected) do { \ char ACPI_ASSERT_CMP_str[5] = {}; \ memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \ diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 3f9830f..c0b4e9a 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -408,32 +408,19 @@ static bool smbios_ep_table_ok(test_data *data) struct smbios_21_entry_point *ep_table = &data->smbios_ep_table; uint32_t addr = data->smbios_ep_addr; - ACPI_READ_ARRAY(data->qts, ep_table->anchor_string, addr); + qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table)); if (memcmp(ep_table->anchor_string, "_SM_", 4)) { return false; } - ACPI_READ_FIELD(data->qts, ep_table->checksum, addr); - ACPI_READ_FIELD(data->qts, ep_table->length, addr); - ACPI_READ_FIELD(data->qts, ep_table->smbios_major_version, addr); - ACPI_READ_FIELD(data->qts, ep_table->smbios_minor_version, addr); - ACPI_READ_FIELD(data->qts, ep_table->max_structure_size, addr); - ACPI_READ_FIELD(data->qts, ep_table->entry_point_revision, addr); - ACPI_READ_ARRAY(data->qts, ep_table->formatted_area, addr); - ACPI_READ_ARRAY(data->qts, ep_table->intermediate_anchor_string, addr); if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) { return false; } - ACPI_READ_FIELD(data->qts, ep_table->intermediate_checksum, addr); - ACPI_READ_FIELD(data->qts, ep_table->structure_table_length, addr); if (ep_table->structure_table_length == 0) { return false; } - ACPI_READ_FIELD(data->qts, ep_table->structure_table_address, addr); - ACPI_READ_FIELD(data->qts, ep_table->number_of_structures, addr); if (ep_table->number_of_structures == 0) { return false; } - ACPI_READ_FIELD(data->qts, ep_table->smbios_bcd_revision, addr); if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) || acpi_calc_checksum((uint8_t *)ep_table + 0x10, sizeof *ep_table - 0x10)) { -- cgit v1.1 From b997a04a5048e496a67f0c03f1f420cfa5a48c72 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:33 +0100 Subject: tests: acpi: squash sanitize_fadt_ptrs() into test_acpi_fadt_table() some parts of sanitize_fadt_ptrs() do redundant job - locating FADT - checking original checksum There is no need to do it as test_acpi_fadt_table() already does that, so drop duplicate code and move remaining fixup code into test_acpi_fadt_table(). Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/bios-tables-test.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index c0b4e9a..db04816 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -128,6 +128,7 @@ static void test_acpi_fadt_table(test_data *data) /* FADT table is 1st */ AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0); uint8_t *fadt_aml = table.aml; + uint32_t fadt_len = table.aml_len; ACPI_ASSERT_CMP(table.header->signature, "FACP"); @@ -139,35 +140,17 @@ static void test_acpi_fadt_table(test_data *data) acpi_fetch_table(data->qts, &table.aml, &table.aml_len, fadt_aml + 40 /* DSDT */, "DSDT", true); g_array_append_val(data->tables, table); -} - -static void sanitize_fadt_ptrs(test_data *data) -{ - /* fixup pointers in FADT */ - int i; - - for (i = 0; i < data->tables->len; i++) { - AcpiSdtTable *sdt = &g_array_index(data->tables, AcpiSdtTable, i); - - if (memcmp(&sdt->header->signature, "FACP", 4)) { - continue; - } - /* check original FADT checksum before sanitizing table */ - g_assert(!acpi_calc_checksum(sdt->aml, sdt->aml_len)); - - memset(sdt->aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */ - memset(sdt->aml + 40, 0, 4); /* sanitize DSDT ptr */ - if (sdt->header->revision >= 3) { - memset(sdt->aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */ - memset(sdt->aml + 140, 0, 8); /* sanitize X_DSDT ptr */ - } - - /* update checksum */ - sdt->header->checksum = 0; - sdt->header->checksum -= acpi_calc_checksum(sdt->aml, sdt->aml_len); - break; + memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */ + memset(fadt_aml + 40, 0, 4); /* sanitize DSDT ptr */ + if (fadt_aml[8 /* FADT Major Version */] >= 3) { + memset(fadt_aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */ + memset(fadt_aml + 140, 0, 8); /* sanitize X_DSDT ptr */ } + + /* update checksum */ + fadt_aml[9 /* Checksum */] = 0; + fadt_aml[9 /* Checksum */] -= acpi_calc_checksum(fadt_aml, fadt_len); } static void dump_aml_files(test_data *data, bool rebuild) @@ -543,8 +526,6 @@ static void test_acpi_one(const char *params, test_data *data) test_acpi_rsdt_table(data); test_acpi_fadt_table(data); - sanitize_fadt_ptrs(data); - if (iasl) { if (getenv(ACPI_REBUILD_EXPECTED_AML)) { dump_aml_files(data, true); -- cgit v1.1 From b137522c35c1708adb10c73378e97e7dd0badbfc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 27 Dec 2018 15:13:34 +0100 Subject: tests: acpi: use AcpiSdtTable::aml instead of AcpiSdtTable::header::signature AcpiSdtTable::header::signature is the only remained field from AcpiTableHeader structure used by tests. Instead of using packed structure to access signature, just read it directly from table blob and remove no longer used AcpiSdtTable::header / union and keep only AcpiSdtTable::aml byte array. Signed-off-by: Igor Mammedov Acked-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/acpi-utils.h | 6 +----- tests/bios-tables-test.c | 20 +++++++++----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h index cb7183e..ef388bb 100644 --- a/tests/acpi-utils.h +++ b/tests/acpi-utils.h @@ -13,15 +13,11 @@ #ifndef TEST_ACPI_UTILS_H #define TEST_ACPI_UTILS_H -#include "hw/acpi/acpi-defs.h" #include "libqtest.h" /* DSDT and SSDTs format */ typedef struct { - union { - AcpiTableHeader *header; - uint8_t *aml; /* aml bytecode from guest */ - }; + uint8_t *aml; /* aml bytecode from guest */ uint32_t aml_len; gchar *aml_file; gchar *asl; /* asl code generated from aml */ diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index db04816..a506dcb 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -44,6 +44,11 @@ static const char *iasl = stringify(CONFIG_IASL); static const char *iasl; #endif +static bool compare_signature(const AcpiSdtTable *sdt, const char *signature) +{ + return !memcmp(sdt->aml, signature, 4); +} + static void cleanup_table_descriptor(AcpiSdtTable *table) { g_free(table->aml); @@ -130,7 +135,7 @@ static void test_acpi_fadt_table(test_data *data) uint8_t *fadt_aml = table.aml; uint32_t fadt_len = table.aml_len; - ACPI_ASSERT_CMP(table.header->signature, "FACP"); + g_assert(compare_signature(&table, "FACP")); /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */ acpi_fetch_table(data->qts, &table.aml, &table.aml_len, @@ -169,7 +174,7 @@ static void dump_aml_files(test_data *data, bool rebuild) if (rebuild) { aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, - (gchar *)&sdt->header->signature, ext); + sdt->aml, ext); fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); } else { @@ -187,11 +192,6 @@ static void dump_aml_files(test_data *data, bool rebuild) } } -static bool compare_signature(AcpiSdtTable *sdt, const char *signature) -{ - return !memcmp(&sdt->header->signature, signature, 4); -} - static bool load_asl(GArray *sdts, AcpiSdtTable *sdt) { AcpiSdtTable *temp; @@ -291,7 +291,7 @@ static GArray *load_expected_aml(test_data *data) try_again: aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, - (gchar *)&sdt->header->signature, ext); + sdt->aml, ext); if (getenv("V")) { fprintf(stderr, "Looking for expected file '%s'\n", aml_file); } @@ -352,14 +352,12 @@ static void test_acpi_asl(test_data *data) fprintf(stderr, "Warning! iasl couldn't parse the expected aml\n"); } else { - uint32_t signature = cpu_to_le32(exp_sdt->header->signature); sdt->tmp_files_retain = true; exp_sdt->tmp_files_retain = true; fprintf(stderr, "acpi-test: Warning! %.4s mismatch. " "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n", - (gchar *)&signature, - sdt->asl_file, sdt->aml_file, + exp_sdt->aml, sdt->asl_file, sdt->aml_file, exp_sdt->asl_file, exp_sdt->aml_file); if (getenv("V")) { const char *diff_cmd = getenv("DIFF"); -- cgit v1.1 From 2974e916df8790fa4db2edac99627f5e3c79d7a7 Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Thu, 3 Jan 2019 15:12:29 +0200 Subject: virtio-net: support RSC v4/v6 tcp traffic for Windows HCK This commit adds implementation of RX packets coalescing, compatible with requirements of Windows Hardware compatibility kit. The device enables feature VIRTIO_NET_F_RSC_EXT in host features if it supports extended RSC functionality as defined in the specification. This feature requires at least one of VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6. Windows guest driver acks this feature only if VIRTIO_NET_F_CTRL_GUEST_OFFLOADS is also present. If the guest driver acks VIRTIO_NET_F_RSC_EXT feature, the device coalesces TCPv4 and TCPv6 packets (if respective VIRTIO_NET_F_GUEST_TSO feature is on, populates extended RSC information in virtio header and sets VIRTIO_NET_HDR_F_RSC_INFO bit in header flags. The device does not recalculate checksums in the coalesced packet, so they are not valid. In this case: All the data packets in a tcp connection are cached to a single buffer in every receive interval, and will be sent out via a timer, the 'virtio_net_rsc_timeout' controls the interval, this value may impact the performance and response time of tcp connection, 50000(50us) is an experience value to gain a performance improvement, since the whql test sends packets every 100us, so '300000(300us)' passes the test case, it is the default value as well, tune it via the command line parameter 'rsc_interval' within 'virtio-net-pci' device, for example, to launch a guest with interval set as '500000': 'virtio-net-pci,netdev=hostnet1,bus=pci.0,id=net1,mac=00, guest_rsc_ext=on,rsc_interval=500000' The timer will only be triggered if the packets pool is not empty, and it'll drain off all the cached packets. 'NetRscChain' is used to save the segments of IPv4/6 in a VirtIONet device. A new segment becomes a 'Candidate' as well as it passed sanity check, the main handler of TCP includes TCP window update, duplicated ACK check and the real data coalescing. An 'Candidate' segment means: 1. Segment is within current window and the sequence is the expected one. 2. 'ACK' of the segment is in the valid window. Sanity check includes: 1. Incorrect version in IP header 2. An IP options or IP fragment 3. Not a TCP packet 4. Sanity size check to prevent buffer overflow attack. 5. An ECN packet Even though, there might more cases should be considered such as ip identification other flags, while it breaks the test because windows set it to the same even it's not a fragment. Normally it includes 2 typical ways to handle a TCP control flag, 'bypass' and 'finalize', 'bypass' means should be sent out directly, while 'finalize' means the packets should also be bypassed, but this should be done after search for the same connection packets in the pool and drain all of them out, this is to avoid out of order fragment. All the 'SYN' packets will be bypassed since this always begin a new' connection, other flags such 'URG/FIN/RST/CWR/ECE' will trigger a finalization, because this normally happens upon a connection is going to be closed, an 'URG' packet also finalize current coalescing unit. Statistics can be used to monitor the basic coalescing status, the 'out of order' and 'out of window' means how many retransmitting packets, thus describe the performance intuitively. Difference between ip v4 and v6 processing: Fragment length in ipv4 header includes itself, while it's not included for ipv6, thus means ipv6 can carry a real 65535 payload. Note that main goal of implementing this feature in software is to create reference setup for certification tests. In such setups guest migration is not required, so the coalesced packets not yet delivered to the guest will be lost in case of migration. Signed-off-by: Wei Xu Signed-off-by: Yuri Benditovich Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 667 ++++++++++++++++++++++++++++++++++++++++- include/hw/virtio/virtio-net.h | 83 +++++ include/net/eth.h | 2 + 3 files changed, 751 insertions(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index e37fc34..9e5fb1e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -41,6 +41,47 @@ #define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE #define VIRTIO_NET_TX_QUEUE_MIN_SIZE VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE +#define VIRTIO_NET_IP4_ADDR_SIZE 8 /* ipv4 saddr + daddr */ + +#define VIRTIO_NET_TCP_FLAG 0x3F +#define VIRTIO_NET_TCP_HDR_LENGTH 0xF000 + +/* IPv4 max payload, 16 bits in the header */ +#define VIRTIO_NET_MAX_IP4_PAYLOAD (65535 - sizeof(struct ip_header)) +#define VIRTIO_NET_MAX_TCP_PAYLOAD 65535 + +/* header length value in ip header without option */ +#define VIRTIO_NET_IP4_HEADER_LENGTH 5 + +#define VIRTIO_NET_IP6_ADDR_SIZE 32 /* ipv6 saddr + daddr */ +#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD + +/* Purge coalesced packets timer interval, This value affects the performance + a lot, and should be tuned carefully, '300000'(300us) is the recommended + value to pass the WHQL test, '50000' can gain 2x netperf throughput with + tso/gso/gro 'off'. */ +#define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000 + +/* temporary until standard header include it */ +#if !defined(VIRTIO_NET_HDR_F_RSC_INFO) + +#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */ +#define VIRTIO_NET_F_RSC_EXT 38 + +static inline __virtio16 *virtio_net_rsc_ext_num_packets( + struct virtio_net_hdr *hdr) +{ + return &hdr->csum_start; +} + +static inline __virtio16 *virtio_net_rsc_ext_num_dupacks( + struct virtio_net_hdr *hdr) +{ + return &hdr->csum_offset; +} + +#endif + /* * Calculate the number of bytes up to and including the given 'field' of * 'container'. @@ -628,6 +669,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, if (!get_vhost_net(nc->peer)) { return features; } + features = vhost_net_get_features(get_vhost_net(nc->peer), features); vdev->backend_features = features; @@ -701,6 +743,11 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) virtio_has_feature(features, VIRTIO_F_VERSION_1)); + n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4); + n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6); + if (n->has_vnet_hdr) { n->curr_guest_offloads = virtio_net_guest_offloads_by_features(features); @@ -781,6 +828,12 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; } + n->rsc4_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO4); + n->rsc6_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO6); + virtio_clear_feature(&offloads, VIRTIO_NET_F_RSC_EXT); + supported_offloads = virtio_net_supported_guest_offloads(n); if (offloads & ~supported_offloads) { return VIRTIO_NET_ERR; @@ -1292,7 +1345,7 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, return size; } -static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, +static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, size_t size) { ssize_t r; @@ -1303,6 +1356,612 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, return r; } +static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, + const uint8_t *buf, + VirtioNetRscUnit *unit) +{ + uint16_t ip_hdrlen; + struct ip_header *ip; + + ip = (struct ip_header *)(buf + chain->n->guest_hdr_len + + sizeof(struct eth_header)); + unit->ip = (void *)ip; + ip_hdrlen = (ip->ip_ver_len & 0xF) << 2; + unit->ip_plen = &ip->ip_len; + unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen); + unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; + unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen; +} + +static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, + const uint8_t *buf, + VirtioNetRscUnit *unit) +{ + struct ip6_header *ip6; + + ip6 = (struct ip6_header *)(buf + chain->n->guest_hdr_len + + sizeof(struct eth_header)); + unit->ip = ip6; + unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); + unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\ + + sizeof(struct ip6_header)); + unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; + + /* There is a difference between payload lenght in ipv4 and v6, + ip header is excluded in ipv6 */ + unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen; +} + +static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg) +{ + int ret; + struct virtio_net_hdr *h; + + h = (struct virtio_net_hdr *)seg->buf; + h->flags = 0; + h->gso_type = VIRTIO_NET_HDR_GSO_NONE; + + if (seg->is_coalesced) { + *virtio_net_rsc_ext_num_packets(h) = seg->packets; + *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack; + h->flags = VIRTIO_NET_HDR_F_RSC_INFO; + if (chain->proto == ETH_P_IP) { + h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; + } else { + h->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + } + } + + ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size); + QTAILQ_REMOVE(&chain->buffers, seg, next); + g_free(seg->buf); + g_free(seg); + + return ret; +} + +static void virtio_net_rsc_purge(void *opq) +{ + VirtioNetRscSeg *seg, *rn; + VirtioNetRscChain *chain = (VirtioNetRscChain *)opq; + + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn) { + if (virtio_net_rsc_drain_seg(chain, seg) == 0) { + chain->stat.purge_failed++; + continue; + } + } + + chain->stat.timer++; + if (!QTAILQ_EMPTY(&chain->buffers)) { + timer_mod(chain->drain_timer, + qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); + } +} + +static void virtio_net_rsc_cleanup(VirtIONet *n) +{ + VirtioNetRscChain *chain, *rn_chain; + VirtioNetRscSeg *seg, *rn_seg; + + QTAILQ_FOREACH_SAFE(chain, &n->rsc_chains, next, rn_chain) { + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn_seg) { + QTAILQ_REMOVE(&chain->buffers, seg, next); + g_free(seg->buf); + g_free(seg); + } + + timer_del(chain->drain_timer); + timer_free(chain->drain_timer); + QTAILQ_REMOVE(&n->rsc_chains, chain, next); + g_free(chain); + } +} + +static void virtio_net_rsc_cache_buf(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size) +{ + uint16_t hdr_len; + VirtioNetRscSeg *seg; + + hdr_len = chain->n->guest_hdr_len; + seg = g_malloc(sizeof(VirtioNetRscSeg)); + seg->buf = g_malloc(hdr_len + sizeof(struct eth_header) + + sizeof(struct ip6_header) + VIRTIO_NET_MAX_TCP_PAYLOAD); + memcpy(seg->buf, buf, size); + seg->size = size; + seg->packets = 1; + seg->dup_ack = 0; + seg->is_coalesced = 0; + seg->nc = nc; + + QTAILQ_INSERT_TAIL(&chain->buffers, seg, next); + chain->stat.cache++; + + switch (chain->proto) { + case ETH_P_IP: + virtio_net_rsc_extract_unit4(chain, seg->buf, &seg->unit); + break; + case ETH_P_IPV6: + virtio_net_rsc_extract_unit6(chain, seg->buf, &seg->unit); + break; + default: + g_assert_not_reached(); + } +} + +static int32_t virtio_net_rsc_handle_ack(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, + struct tcp_header *n_tcp, + struct tcp_header *o_tcp) +{ + uint32_t nack, oack; + uint16_t nwin, owin; + + nack = htonl(n_tcp->th_ack); + nwin = htons(n_tcp->th_win); + oack = htonl(o_tcp->th_ack); + owin = htons(o_tcp->th_win); + + if ((nack - oack) >= VIRTIO_NET_MAX_TCP_PAYLOAD) { + chain->stat.ack_out_of_win++; + return RSC_FINAL; + } else if (nack == oack) { + /* duplicated ack or window probe */ + if (nwin == owin) { + /* duplicated ack, add dup ack count due to whql test up to 1 */ + chain->stat.dup_ack++; + return RSC_FINAL; + } else { + /* Coalesce window update */ + o_tcp->th_win = n_tcp->th_win; + chain->stat.win_update++; + return RSC_COALESCE; + } + } else { + /* pure ack, go to 'C', finalize*/ + chain->stat.pure_ack++; + return RSC_FINAL; + } +} + +static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, + VirtioNetRscUnit *n_unit) +{ + void *data; + uint16_t o_ip_len; + uint32_t nseq, oseq; + VirtioNetRscUnit *o_unit; + + o_unit = &seg->unit; + o_ip_len = htons(*o_unit->ip_plen); + nseq = htonl(n_unit->tcp->th_seq); + oseq = htonl(o_unit->tcp->th_seq); + + /* out of order or retransmitted. */ + if ((nseq - oseq) > VIRTIO_NET_MAX_TCP_PAYLOAD) { + chain->stat.data_out_of_win++; + return RSC_FINAL; + } + + data = ((uint8_t *)n_unit->tcp) + n_unit->tcp_hdrlen; + if (nseq == oseq) { + if ((o_unit->payload == 0) && n_unit->payload) { + /* From no payload to payload, normal case, not a dup ack or etc */ + chain->stat.data_after_pure_ack++; + goto coalesce; + } else { + return virtio_net_rsc_handle_ack(chain, seg, buf, + n_unit->tcp, o_unit->tcp); + } + } else if ((nseq - oseq) != o_unit->payload) { + /* Not a consistent packet, out of order */ + chain->stat.data_out_of_order++; + return RSC_FINAL; + } else { +coalesce: + if ((o_ip_len + n_unit->payload) > chain->max_payload) { + chain->stat.over_size++; + return RSC_FINAL; + } + + /* Here comes the right data, the payload length in v4/v6 is different, + so use the field value to update and record the new data len */ + o_unit->payload += n_unit->payload; /* update new data len */ + + /* update field in ip header */ + *o_unit->ip_plen = htons(o_ip_len + n_unit->payload); + + /* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced + for windows guest, while this may change the behavior for linux + guest (only if it uses RSC feature). */ + o_unit->tcp->th_offset_flags = n_unit->tcp->th_offset_flags; + + o_unit->tcp->th_ack = n_unit->tcp->th_ack; + o_unit->tcp->th_win = n_unit->tcp->th_win; + + memmove(seg->buf + seg->size, data, n_unit->payload); + seg->size += n_unit->payload; + seg->packets++; + chain->stat.coalesced++; + return RSC_COALESCE; + } +} + +static int32_t virtio_net_rsc_coalesce4(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, size_t size, + VirtioNetRscUnit *unit) +{ + struct ip_header *ip1, *ip2; + + ip1 = (struct ip_header *)(unit->ip); + ip2 = (struct ip_header *)(seg->unit.ip); + if ((ip1->ip_src ^ ip2->ip_src) || (ip1->ip_dst ^ ip2->ip_dst) + || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) + || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { + chain->stat.no_match++; + return RSC_NO_MATCH; + } + + return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); +} + +static int32_t virtio_net_rsc_coalesce6(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, size_t size, + VirtioNetRscUnit *unit) +{ + struct ip6_header *ip1, *ip2; + + ip1 = (struct ip6_header *)(unit->ip); + ip2 = (struct ip6_header *)(seg->unit.ip); + if (memcmp(&ip1->ip6_src, &ip2->ip6_src, sizeof(struct in6_address)) + || memcmp(&ip1->ip6_dst, &ip2->ip6_dst, sizeof(struct in6_address)) + || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) + || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { + chain->stat.no_match++; + return RSC_NO_MATCH; + } + + return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); +} + +/* Packets with 'SYN' should bypass, other flag should be sent after drain + * to prevent out of order */ +static int virtio_net_rsc_tcp_ctrl_check(VirtioNetRscChain *chain, + struct tcp_header *tcp) +{ + uint16_t tcp_hdr; + uint16_t tcp_flag; + + tcp_flag = htons(tcp->th_offset_flags); + tcp_hdr = (tcp_flag & VIRTIO_NET_TCP_HDR_LENGTH) >> 10; + tcp_flag &= VIRTIO_NET_TCP_FLAG; + tcp_flag = htons(tcp->th_offset_flags) & 0x3F; + if (tcp_flag & TH_SYN) { + chain->stat.tcp_syn++; + return RSC_BYPASS; + } + + if (tcp_flag & (TH_FIN | TH_URG | TH_RST | TH_ECE | TH_CWR)) { + chain->stat.tcp_ctrl_drain++; + return RSC_FINAL; + } + + if (tcp_hdr > sizeof(struct tcp_header)) { + chain->stat.tcp_all_opt++; + return RSC_FINAL; + } + + return RSC_CANDIDATE; +} + +static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size, + VirtioNetRscUnit *unit) +{ + int ret; + VirtioNetRscSeg *seg, *nseg; + + if (QTAILQ_EMPTY(&chain->buffers)) { + chain->stat.empty_cache++; + virtio_net_rsc_cache_buf(chain, nc, buf, size); + timer_mod(chain->drain_timer, + qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); + return size; + } + + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { + if (chain->proto == ETH_P_IP) { + ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit); + } else { + ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit); + } + + if (ret == RSC_FINAL) { + if (virtio_net_rsc_drain_seg(chain, seg) == 0) { + /* Send failed */ + chain->stat.final_failed++; + return 0; + } + + /* Send current packet */ + return virtio_net_do_receive(nc, buf, size); + } else if (ret == RSC_NO_MATCH) { + continue; + } else { + /* Coalesced, mark coalesced flag to tell calc cksum for ipv4 */ + seg->is_coalesced = 1; + return size; + } + } + + chain->stat.no_match_cache++; + virtio_net_rsc_cache_buf(chain, nc, buf, size); + return size; +} + +/* Drain a connection data, this is to avoid out of order segments */ +static size_t virtio_net_rsc_drain_flow(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size, + uint16_t ip_start, uint16_t ip_size, + uint16_t tcp_port) +{ + VirtioNetRscSeg *seg, *nseg; + uint32_t ppair1, ppair2; + + ppair1 = *(uint32_t *)(buf + tcp_port); + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { + ppair2 = *(uint32_t *)(seg->buf + tcp_port); + if (memcmp(buf + ip_start, seg->buf + ip_start, ip_size) + || (ppair1 != ppair2)) { + continue; + } + if (virtio_net_rsc_drain_seg(chain, seg) == 0) { + chain->stat.drain_failed++; + } + + break; + } + + return virtio_net_do_receive(nc, buf, size); +} + +static int32_t virtio_net_rsc_sanity_check4(VirtioNetRscChain *chain, + struct ip_header *ip, + const uint8_t *buf, size_t size) +{ + uint16_t ip_len; + + /* Not an ipv4 packet */ + if (((ip->ip_ver_len & 0xF0) >> 4) != IP_HEADER_VERSION_4) { + chain->stat.ip_option++; + return RSC_BYPASS; + } + + /* Don't handle packets with ip option */ + if ((ip->ip_ver_len & 0xF) != VIRTIO_NET_IP4_HEADER_LENGTH) { + chain->stat.ip_option++; + return RSC_BYPASS; + } + + if (ip->ip_p != IPPROTO_TCP) { + chain->stat.bypass_not_tcp++; + return RSC_BYPASS; + } + + /* Don't handle packets with ip fragment */ + if (!(htons(ip->ip_off) & IP_DF)) { + chain->stat.ip_frag++; + return RSC_BYPASS; + } + + /* Don't handle packets with ecn flag */ + if (IPTOS_ECN(ip->ip_tos)) { + chain->stat.ip_ecn++; + return RSC_BYPASS; + } + + ip_len = htons(ip->ip_len); + if (ip_len < (sizeof(struct ip_header) + sizeof(struct tcp_header)) + || ip_len > (size - chain->n->guest_hdr_len - + sizeof(struct eth_header))) { + chain->stat.ip_hacked++; + return RSC_BYPASS; + } + + return RSC_CANDIDATE; +} + +static size_t virtio_net_rsc_receive4(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size) +{ + int32_t ret; + uint16_t hdr_len; + VirtioNetRscUnit unit; + + hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; + + if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header) + + sizeof(struct tcp_header))) { + chain->stat.bypass_not_tcp++; + return virtio_net_do_receive(nc, buf, size); + } + + virtio_net_rsc_extract_unit4(chain, buf, &unit); + if (virtio_net_rsc_sanity_check4(chain, unit.ip, buf, size) + != RSC_CANDIDATE) { + return virtio_net_do_receive(nc, buf, size); + } + + ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); + if (ret == RSC_BYPASS) { + return virtio_net_do_receive(nc, buf, size); + } else if (ret == RSC_FINAL) { + return virtio_net_rsc_drain_flow(chain, nc, buf, size, + ((hdr_len + sizeof(struct eth_header)) + 12), + VIRTIO_NET_IP4_ADDR_SIZE, + hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header)); + } + + return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); +} + +static int32_t virtio_net_rsc_sanity_check6(VirtioNetRscChain *chain, + struct ip6_header *ip6, + const uint8_t *buf, size_t size) +{ + uint16_t ip_len; + + if (((ip6->ip6_ctlun.ip6_un1.ip6_un1_flow & 0xF0) >> 4) + != IP_HEADER_VERSION_6) { + return RSC_BYPASS; + } + + /* Both option and protocol is checked in this */ + if (ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) { + chain->stat.bypass_not_tcp++; + return RSC_BYPASS; + } + + ip_len = htons(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); + if (ip_len < sizeof(struct tcp_header) || + ip_len > (size - chain->n->guest_hdr_len - sizeof(struct eth_header) + - sizeof(struct ip6_header))) { + chain->stat.ip_hacked++; + return RSC_BYPASS; + } + + /* Don't handle packets with ecn flag */ + if (IP6_ECN(ip6->ip6_ctlun.ip6_un3.ip6_un3_ecn)) { + chain->stat.ip_ecn++; + return RSC_BYPASS; + } + + return RSC_CANDIDATE; +} + +static size_t virtio_net_rsc_receive6(void *opq, NetClientState *nc, + const uint8_t *buf, size_t size) +{ + int32_t ret; + uint16_t hdr_len; + VirtioNetRscChain *chain; + VirtioNetRscUnit unit; + + chain = (VirtioNetRscChain *)opq; + hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; + + if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip6_header) + + sizeof(tcp_header))) { + return virtio_net_do_receive(nc, buf, size); + } + + virtio_net_rsc_extract_unit6(chain, buf, &unit); + if (RSC_CANDIDATE != virtio_net_rsc_sanity_check6(chain, + unit.ip, buf, size)) { + return virtio_net_do_receive(nc, buf, size); + } + + ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); + if (ret == RSC_BYPASS) { + return virtio_net_do_receive(nc, buf, size); + } else if (ret == RSC_FINAL) { + return virtio_net_rsc_drain_flow(chain, nc, buf, size, + ((hdr_len + sizeof(struct eth_header)) + 8), + VIRTIO_NET_IP6_ADDR_SIZE, + hdr_len + sizeof(struct eth_header) + + sizeof(struct ip6_header)); + } + + return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); +} + +static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n, + NetClientState *nc, + uint16_t proto) +{ + VirtioNetRscChain *chain; + + if ((proto != (uint16_t)ETH_P_IP) && (proto != (uint16_t)ETH_P_IPV6)) { + return NULL; + } + + QTAILQ_FOREACH(chain, &n->rsc_chains, next) { + if (chain->proto == proto) { + return chain; + } + } + + chain = g_malloc(sizeof(*chain)); + chain->n = n; + chain->proto = proto; + if (proto == (uint16_t)ETH_P_IP) { + chain->max_payload = VIRTIO_NET_MAX_IP4_PAYLOAD; + chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; + } else { + chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD; + chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + } + chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST, + virtio_net_rsc_purge, chain); + memset(&chain->stat, 0, sizeof(chain->stat)); + + QTAILQ_INIT(&chain->buffers); + QTAILQ_INSERT_TAIL(&n->rsc_chains, chain, next); + + return chain; +} + +static ssize_t virtio_net_rsc_receive(NetClientState *nc, + const uint8_t *buf, + size_t size) +{ + uint16_t proto; + VirtioNetRscChain *chain; + struct eth_header *eth; + VirtIONet *n; + + n = qemu_get_nic_opaque(nc); + if (size < (n->host_hdr_len + sizeof(struct eth_header))) { + return virtio_net_do_receive(nc, buf, size); + } + + eth = (struct eth_header *)(buf + n->guest_hdr_len); + proto = htons(eth->h_proto); + + chain = virtio_net_rsc_lookup_chain(n, nc, proto); + if (chain) { + chain->stat.received++; + if (proto == (uint16_t)ETH_P_IP && n->rsc4_enabled) { + return virtio_net_rsc_receive4(chain, nc, buf, size); + } else if (proto == (uint16_t)ETH_P_IPV6 && n->rsc6_enabled) { + return virtio_net_rsc_receive6(chain, nc, buf, size); + } + } + return virtio_net_do_receive(nc, buf, size); +} + +static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + VirtIONet *n = qemu_get_nic_opaque(nc); + if ((n->rsc4_enabled || n->rsc6_enabled)) { + return virtio_net_rsc_receive(nc, buf, size); + } else { + return virtio_net_do_receive(nc, buf, size); + } +} + static int32_t virtio_net_flush_tx(VirtIONetQueue *q); static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) @@ -2075,6 +2734,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) nc = qemu_get_queue(n->nic); nc->rxfilter_notify_enabled = 1; + QTAILQ_INIT(&n->rsc_chains); n->qdev = dev; } @@ -2104,6 +2764,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) timer_free(n->announce_timer); g_free(n->vqs); qemu_del_nic(n->nic); + virtio_net_rsc_cleanup(n); virtio_cleanup(vdev); } @@ -2184,6 +2845,10 @@ static Property virtio_net_properties[] = { DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), + DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, + VIRTIO_NET_F_RSC_EXT, false), + DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, + VIRTIO_NET_RSC_DEFAULT_INTERVAL), DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf), DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer, TX_TIMER_INTERVAL), diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 4d7f3c8..c7ec1a7 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -44,6 +44,83 @@ typedef struct virtio_net_conf uint8_t duplex; } virtio_net_conf; +/* Coalesced packets type & status */ +typedef enum { + RSC_COALESCE, /* Data been coalesced */ + RSC_FINAL, /* Will terminate current connection */ + RSC_NO_MATCH, /* No matched in the buffer pool */ + RSC_BYPASS, /* Packet to be bypass, not tcp, tcp ctrl, etc */ + RSC_CANDIDATE /* Data want to be coalesced */ +} CoalesceStatus; + +typedef struct VirtioNetRscStat { + uint32_t received; + uint32_t coalesced; + uint32_t over_size; + uint32_t cache; + uint32_t empty_cache; + uint32_t no_match_cache; + uint32_t win_update; + uint32_t no_match; + uint32_t tcp_syn; + uint32_t tcp_ctrl_drain; + uint32_t dup_ack; + uint32_t dup_ack1; + uint32_t dup_ack2; + uint32_t pure_ack; + uint32_t ack_out_of_win; + uint32_t data_out_of_win; + uint32_t data_out_of_order; + uint32_t data_after_pure_ack; + uint32_t bypass_not_tcp; + uint32_t tcp_option; + uint32_t tcp_all_opt; + uint32_t ip_frag; + uint32_t ip_ecn; + uint32_t ip_hacked; + uint32_t ip_option; + uint32_t purge_failed; + uint32_t drain_failed; + uint32_t final_failed; + int64_t timer; +} VirtioNetRscStat; + +/* Rsc unit general info used to checking if can coalescing */ +typedef struct VirtioNetRscUnit { + void *ip; /* ip header */ + uint16_t *ip_plen; /* data len pointer in ip header field */ + struct tcp_header *tcp; /* tcp header */ + uint16_t tcp_hdrlen; /* tcp header len */ + uint16_t payload; /* pure payload without virtio/eth/ip/tcp */ +} VirtioNetRscUnit; + +/* Coalesced segmant */ +typedef struct VirtioNetRscSeg { + QTAILQ_ENTRY(VirtioNetRscSeg) next; + void *buf; + size_t size; + uint16_t packets; + uint16_t dup_ack; + bool is_coalesced; /* need recal ipv4 header checksum, mark here */ + VirtioNetRscUnit unit; + NetClientState *nc; +} VirtioNetRscSeg; + +struct VirtIONet; +typedef struct VirtIONet VirtIONet; + +/* Chain is divided by protocol(ipv4/v6) and NetClientInfo */ +typedef struct VirtioNetRscChain { + QTAILQ_ENTRY(VirtioNetRscChain) next; + VirtIONet *n; /* VirtIONet */ + uint16_t proto; + uint8_t gso_type; + uint16_t max_payload; + QEMUTimer *drain_timer; + QTAILQ_HEAD(, VirtioNetRscSeg) buffers; + VirtioNetRscStat stat; +} VirtioNetRscChain; + /* Maximum packet size we can receive from tap device: header + 64k */ #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB)) @@ -66,12 +143,18 @@ typedef struct VirtIONet { VirtIONetQueue *vqs; VirtQueue *ctrl_vq; NICState *nic; + /* RSC Chains - temporary storage of coalesced data, + all these data are lost in case of migration */ + QTAILQ_HEAD(, VirtioNetRscChain) rsc_chains; uint32_t tx_timeout; int32_t tx_burst; uint32_t has_vnet_hdr; size_t host_hdr_len; size_t guest_hdr_len; uint64_t host_features; + uint32_t rsc_timeout; + uint8_t rsc4_enabled; + uint8_t rsc6_enabled; uint8_t has_ufo; uint32_t mergeable_rx_bufs; uint8_t promisc; diff --git a/include/net/eth.h b/include/net/eth.h index e6dc8a7..7f45c67 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -177,6 +177,8 @@ struct tcp_hdr { #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 u_short th_win; /* window */ u_short th_sum; /* checksum */ u_short th_urp; /* urgent pointer */ -- cgit v1.1 From d47e5e31c37be43dc11a7a29d168f535589dbebd Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Thu, 3 Jan 2019 15:12:30 +0200 Subject: virtio-net: changed VIRTIO_NET_F_RSC_EXT to be 61 Allocated feature bit changed in spec draft per TC request. Signed-off-by: Yuri Benditovich Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 9e5fb1e..3f319ef 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -66,7 +66,7 @@ #if !defined(VIRTIO_NET_HDR_F_RSC_INFO) #define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */ -#define VIRTIO_NET_F_RSC_EXT 38 +#define VIRTIO_NET_F_RSC_EXT 61 static inline __virtio16 *virtio_net_rsc_ext_num_packets( struct virtio_net_hdr *hdr) -- cgit v1.1 From ef7e7845b2040385f425bf39de60c700c12ceb4f Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:09:58 +0100 Subject: virtio: split vhost vsock bits from virtio-pci Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 3 ++ hw/virtio/vhost-vsock-pci.c | 86 +++++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 53 ---------------------------- hw/virtio/virtio-pci.h | 18 ---------- 4 files changed, 89 insertions(+), 71 deletions(-) create mode 100644 hw/virtio/vhost-vsock-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 1b2799c..39884c5 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -11,6 +11,9 @@ obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-p obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o +ifeq ($(CONFIG_PCI),y) +obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o +endif endif common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c new file mode 100644 index 0000000..6f43ca3 --- /dev/null +++ b/hw/virtio/vhost-vsock-pci.c @@ -0,0 +1,86 @@ +/* + * Vhost vsock PCI Bindings + * + * Copyright 2015 Red Hat, Inc. + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/vhost-vsock.h" + +typedef struct VHostVSockPCI VHostVSockPCI; + +/* + * vhost-vsock-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci-base" +#define VHOST_VSOCK_PCI(obj) \ + OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI) + +struct VHostVSockPCI { + VirtIOPCIProxy parent_obj; + VHostVSock vdev; +}; + +/* vhost-vsock-pci */ + +static Property vhost_vsock_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_vsock_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->props = vhost_vsock_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_vsock_pci_instance_init(Object *obj) +{ + VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_VSOCK); +} + +static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = { + .base_name = TYPE_VHOST_VSOCK_PCI, + .generic_name = "vhost-vsock-pci", + .transitional_name = "vhost-vsock-pci-transitional", + .non_transitional_name = "vhost-vsock-pci-non-transitional", + .instance_size = sizeof(VHostVSockPCI), + .instance_init = vhost_vsock_pci_instance_init, + .class_init = vhost_vsock_pci_class_init, +}; + +static void virtio_pci_vhost_register(void) +{ + virtio_pci_types_register(&vhost_vsock_pci_info); +} + +type_init(virtio_pci_vhost_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index d05066d..4312d95 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2357,56 +2357,6 @@ static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = { }; #endif -/* vhost-vsock-pci */ - -#ifdef CONFIG_VHOST_VSOCK -static Property vhost_vsock_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = vhost_vsock_pci_realize; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = vhost_vsock_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; -} - -static void vhost_vsock_pci_instance_init(Object *obj) -{ - VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_VSOCK); -} - -static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = { - .base_name = TYPE_VHOST_VSOCK_PCI, - .generic_name = "vhost-vsock-pci", - .transitional_name = "vhost-vsock-pci-transitional", - .non_transitional_name = "vhost-vsock-pci-non-transitional", - .instance_size = sizeof(VHostVSockPCI), - .instance_init = vhost_vsock_pci_instance_init, - .class_init = vhost_vsock_pci_class_init, -}; -#endif - /* virtio-balloon-pci */ static Property virtio_balloon_pci_properties[] = { @@ -2855,9 +2805,6 @@ static void virtio_pci_register_types(void) #if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) virtio_pci_types_register(&vhost_user_scsi_pci_info); #endif -#ifdef CONFIG_VHOST_VSOCK - virtio_pci_types_register(&vhost_vsock_pci_info); -#endif } type_init(virtio_pci_register_types) diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 29b4216..2109d00 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -37,9 +37,6 @@ #ifdef CONFIG_VHOST_SCSI #include "hw/virtio/vhost-scsi.h" #endif -#ifdef CONFIG_VHOST_VSOCK -#include "hw/virtio/vhost-vsock.h" -#endif typedef struct VirtIOPCIProxy VirtIOPCIProxy; typedef struct VirtIOBlkPCI VirtIOBlkPCI; @@ -55,7 +52,6 @@ typedef struct VirtIOInputPCI VirtIOInputPCI; typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; -typedef struct VHostVSockPCI VHostVSockPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; /* virtio-pci-bus */ @@ -388,20 +384,6 @@ struct VirtIOGPUPCI { VirtIOGPU vdev; }; -#ifdef CONFIG_VHOST_VSOCK -/* - * vhost-vsock-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci-base" -#define VHOST_VSOCK_PCI(obj) \ - OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI) - -struct VHostVSockPCI { - VirtIOPCIProxy parent_obj; - VHostVSock vdev; -}; -#endif - /* * virtio-crypto-pci: This extends VirtioPCIProxy. */ -- cgit v1.1 From 7df2c7181a0792257b775a5c4171254d80083689 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:09:59 +0100 Subject: virtio: split virtio input host bits from virtio-pci For consistency with other devices, rename virtio_host_{initfn,pci_info} to virtio_input_host_{initfn,info}. Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- default-configs/virtio.mak | 1 + hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-input-host-pci.c | 48 +++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 23 ------------------- hw/virtio/virtio-pci.h | 14 ------------ 5 files changed, 50 insertions(+), 37 deletions(-) create mode 100644 hw/virtio/virtio-input-host-pci.c diff --git a/default-configs/virtio.mak b/default-configs/virtio.mak index 1304849..5ae4a61 100644 --- a/default-configs/virtio.mak +++ b/default-configs/virtio.mak @@ -12,3 +12,4 @@ CONFIG_VIRTIO_RNG=y CONFIG_SCSI=y CONFIG_VIRTIO_SCSI=y CONFIG_VIRTIO_SERIAL=y +CONFIG_VIRTIO_INPUT_HOST=$(CONFIG_LINUX) diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 39884c5..a6b850e 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -13,6 +13,7 @@ obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o +obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o endif endif diff --git a/hw/virtio/virtio-input-host-pci.c b/hw/virtio/virtio-input-host-pci.c new file mode 100644 index 0000000..725a51a --- /dev/null +++ b/hw/virtio/virtio-input-host-pci.c @@ -0,0 +1,48 @@ +/* + * Virtio input host PCI Bindings + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-input.h" + +typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; + +#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci-base" +#define VIRTIO_INPUT_HOST_PCI(obj) \ + OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI) + +struct VirtIOInputHostPCI { + VirtIOPCIProxy parent_obj; + VirtIOInputHost vdev; +}; + +static void virtio_host_initfn(Object *obj) +{ + VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_INPUT_HOST); +} + +static const VirtioPCIDeviceTypeInfo virtio_input_host_pci_info = { + .base_name = TYPE_VIRTIO_INPUT_HOST_PCI, + .generic_name = "virtio-input-host-pci", + .transitional_name = "virtio-input-host-pci-transitional", + .non_transitional_name = "virtio-input-host-pci-non-transitional", + .parent = TYPE_VIRTIO_INPUT_PCI, + .instance_size = sizeof(VirtIOInputHostPCI), + .instance_init = virtio_host_initfn, +}; + +static void virtio_input_host_pci_register(void) +{ + virtio_pci_types_register(&virtio_input_host_pci_info); +} + +type_init(virtio_input_host_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 4312d95..d951f27 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2707,26 +2707,6 @@ static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = { .instance_init = virtio_tablet_initfn, }; -#ifdef CONFIG_LINUX -static void virtio_host_initfn(Object *obj) -{ - VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_INPUT_HOST); -} - -static const VirtioPCIDeviceTypeInfo virtio_host_pci_info = { - .base_name = TYPE_VIRTIO_INPUT_HOST_PCI, - .generic_name = "virtio-input-host-pci", - .transitional_name = "virtio-input-host-pci-transitional", - .non_transitional_name = "virtio-input-host-pci-non-transitional", - .parent = TYPE_VIRTIO_INPUT_PCI, - .instance_size = sizeof(VirtIOInputHostPCI), - .instance_init = virtio_host_initfn, -}; -#endif - /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -2785,9 +2765,6 @@ static void virtio_pci_register_types(void) virtio_pci_types_register(&virtio_keyboard_pci_info); virtio_pci_types_register(&virtio_mouse_pci_info); virtio_pci_types_register(&virtio_tablet_pci_info); -#ifdef CONFIG_LINUX - virtio_pci_types_register(&virtio_host_pci_info); -#endif #ifdef CONFIG_VIRTFS virtio_pci_types_register(&virtio_9p_pci_info); #endif diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 2109d00..fb10afe 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -50,7 +50,6 @@ typedef struct VHostUserBlkPCI VHostUserBlkPCI; typedef struct VirtIORngPCI VirtIORngPCI; typedef struct VirtIOInputPCI VirtIOInputPCI; typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; -typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -359,19 +358,6 @@ struct VirtIOInputHIDPCI { VirtIOInputHID vdev; }; -#ifdef CONFIG_LINUX - -#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci-base" -#define VIRTIO_INPUT_HOST_PCI(obj) \ - OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI) - -struct VirtIOInputHostPCI { - VirtIOPCIProxy parent_obj; - VirtIOInputHost vdev; -}; - -#endif - /* * virtio-gpu-pci: This extends VirtioPCIProxy. */ -- cgit v1.1 From 9436b8c62cbae61781f34c5c4be3ec5bc3fa1f49 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:00 +0100 Subject: virtio: split virtio input bits from virtio-pci Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-input-pci.c | 157 +++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 113 ------------------------------- hw/virtio/virtio-pci.h | 22 ------ 4 files changed, 158 insertions(+), 135 deletions(-) create mode 100644 hw/virtio/virtio-input-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index a6b850e..c61bcd1 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -14,6 +14,7 @@ obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o +obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o endif endif diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c new file mode 100644 index 0000000..2c13978 --- /dev/null +++ b/hw/virtio/virtio-input-pci.c @@ -0,0 +1,157 @@ +/* + * Virtio input PCI Bindings + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-input.h" + +typedef struct VirtIOInputPCI VirtIOInputPCI; +typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; + +/* + * virtio-input-pci: This extends VirtioPCIProxy. + */ +#define VIRTIO_INPUT_PCI(obj) \ + OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI) + +struct VirtIOInputPCI { + VirtIOPCIProxy parent_obj; + VirtIOInput vdev; +}; + +#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci" +#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci" +#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci" +#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci" +#define VIRTIO_INPUT_HID_PCI(obj) \ + OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI) + +struct VirtIOInputHIDPCI { + VirtIOPCIProxy parent_obj; + VirtIOInputHID vdev; +}; + +static Property virtio_input_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&vinput->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + virtio_pci_force_virtio_1(vpci_dev); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_input_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + dc->props = virtio_input_pci_properties; + k->realize = virtio_input_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + + pcidev_k->class_id = PCI_CLASS_INPUT_OTHER; +} + +static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD; +} + +static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass, + void *data) +{ + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE; +} + +static void virtio_keyboard_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_KEYBOARD); +} + +static void virtio_mouse_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_MOUSE); +} + +static void virtio_tablet_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_TABLET); +} + +static const TypeInfo virtio_input_pci_info = { + .name = TYPE_VIRTIO_INPUT_PCI, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(VirtIOInputPCI), + .class_init = virtio_input_pci_class_init, + .abstract = true, +}; + +static const TypeInfo virtio_input_hid_pci_info = { + .name = TYPE_VIRTIO_INPUT_HID_PCI, + .parent = TYPE_VIRTIO_INPUT_PCI, + .instance_size = sizeof(VirtIOInputHIDPCI), + .abstract = true, +}; + +static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = { + .generic_name = TYPE_VIRTIO_KEYBOARD_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .class_init = virtio_input_hid_kbd_pci_class_init, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_keyboard_initfn, +}; + +static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = { + .generic_name = TYPE_VIRTIO_MOUSE_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .class_init = virtio_input_hid_mouse_pci_class_init, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_mouse_initfn, +}; + +static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = { + .generic_name = TYPE_VIRTIO_TABLET_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_tablet_initfn, +}; + +static void virtio_pci_input_register(void) +{ + /* Base types: */ + type_register_static(&virtio_input_pci_info); + type_register_static(&virtio_input_hid_pci_info); + + /* Implementations: */ + virtio_pci_types_register(&virtio_keyboard_pci_info); + virtio_pci_types_register(&virtio_mouse_pci_info); + virtio_pci_types_register(&virtio_tablet_pci_info); +} + +type_init(virtio_pci_input_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index d951f27..185db53 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -24,7 +24,6 @@ #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-balloon.h" -#include "hw/virtio/virtio-input.h" #include "hw/pci/pci.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -2600,113 +2599,6 @@ static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = { .class_init = virtio_rng_pci_class_init, }; -/* virtio-input-pci */ - -static Property virtio_input_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&vinput->vdev); - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - virtio_pci_force_virtio_1(vpci_dev); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_input_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - dc->props = virtio_input_pci_properties; - k->realize = virtio_input_pci_realize; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - - pcidev_k->class_id = PCI_CLASS_INPUT_OTHER; -} - -static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD; -} - -static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass, - void *data) -{ - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE; -} - -static void virtio_keyboard_initfn(Object *obj) -{ - VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_KEYBOARD); -} - -static void virtio_mouse_initfn(Object *obj) -{ - VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_MOUSE); -} - -static void virtio_tablet_initfn(Object *obj) -{ - VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_TABLET); -} - -static const TypeInfo virtio_input_pci_info = { - .name = TYPE_VIRTIO_INPUT_PCI, - .parent = TYPE_VIRTIO_PCI, - .instance_size = sizeof(VirtIOInputPCI), - .class_init = virtio_input_pci_class_init, - .abstract = true, -}; - -static const TypeInfo virtio_input_hid_pci_info = { - .name = TYPE_VIRTIO_INPUT_HID_PCI, - .parent = TYPE_VIRTIO_INPUT_PCI, - .instance_size = sizeof(VirtIOInputHIDPCI), - .abstract = true, -}; - -static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = { - .generic_name = TYPE_VIRTIO_KEYBOARD_PCI, - .parent = TYPE_VIRTIO_INPUT_HID_PCI, - .class_init = virtio_input_hid_kbd_pci_class_init, - .instance_size = sizeof(VirtIOInputHIDPCI), - .instance_init = virtio_keyboard_initfn, -}; - -static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = { - .generic_name = TYPE_VIRTIO_MOUSE_PCI, - .parent = TYPE_VIRTIO_INPUT_HID_PCI, - .class_init = virtio_input_hid_mouse_pci_class_init, - .instance_size = sizeof(VirtIOInputHIDPCI), - .instance_init = virtio_mouse_initfn, -}; - -static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = { - .generic_name = TYPE_VIRTIO_TABLET_PCI, - .parent = TYPE_VIRTIO_INPUT_HID_PCI, - .instance_size = sizeof(VirtIOInputHIDPCI), - .instance_init = virtio_tablet_initfn, -}; - /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -2757,14 +2649,9 @@ static void virtio_pci_register_types(void) /* Base types: */ type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); - type_register_static(&virtio_input_pci_info); - type_register_static(&virtio_input_hid_pci_info); /* Implementations: */ virtio_pci_types_register(&virtio_rng_pci_info); - virtio_pci_types_register(&virtio_keyboard_pci_info); - virtio_pci_types_register(&virtio_mouse_pci_info); - virtio_pci_types_register(&virtio_tablet_pci_info); #ifdef CONFIG_VIRTFS virtio_pci_types_register(&virtio_9p_pci_info); #endif diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index fb10afe..f1c75b0 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -23,7 +23,6 @@ #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-balloon.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-input.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" #include "hw/virtio/vhost-user-scsi.h" @@ -48,8 +47,6 @@ typedef struct VHostSCSIPCI VHostSCSIPCI; typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; typedef struct VHostUserBlkPCI VHostUserBlkPCI; typedef struct VirtIORngPCI VirtIORngPCI; -typedef struct VirtIOInputPCI VirtIOInputPCI; -typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -338,25 +335,6 @@ struct VirtIORngPCI { * virtio-input-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" -#define VIRTIO_INPUT_PCI(obj) \ - OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI) - -struct VirtIOInputPCI { - VirtIOPCIProxy parent_obj; - VirtIOInput vdev; -}; - -#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci" -#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci" -#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci" -#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci" -#define VIRTIO_INPUT_HID_PCI(obj) \ - OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI) - -struct VirtIOInputHIDPCI { - VirtIOPCIProxy parent_obj; - VirtIOInputHID vdev; -}; /* * virtio-gpu-pci: This extends VirtioPCIProxy. -- cgit v1.1 From 06d97bb63ba16a417137d820d320c7212e1043ce Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:01 +0100 Subject: virtio: split virtio rng bits from virtio-pci Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-pci.c | 54 ---------------------------- hw/virtio/virtio-pci.h | 14 -------- hw/virtio/virtio-rng-pci.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ tests/Makefile.include | 2 +- 5 files changed, 90 insertions(+), 69 deletions(-) create mode 100644 hw/virtio/virtio-rng-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index c61bcd1..032ba2f 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -15,6 +15,7 @@ ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o +obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o endif endif diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 185db53..2e3eafd 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2546,59 +2546,6 @@ static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = { .class_init = virtio_net_pci_class_init, }; -/* virtio-rng-pci */ - -static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&vrng->vdev); - Error *err = NULL; - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_link(OBJECT(vrng), - OBJECT(vrng->vdev.conf.rng), "rng", - NULL); -} - -static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - k->realize = virtio_rng_pci_realize; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_OTHERS; -} - -static void virtio_rng_initfn(Object *obj) -{ - VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_RNG); -} - -static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = { - .base_name = TYPE_VIRTIO_RNG_PCI, - .generic_name = "virtio-rng-pci", - .transitional_name = "virtio-rng-pci-transitional", - .non_transitional_name = "virtio-rng-pci-non-transitional", - .instance_size = sizeof(VirtIORngPCI), - .instance_init = virtio_rng_initfn, - .class_init = virtio_rng_pci_class_init, -}; - /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -2651,7 +2598,6 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_pci_info); /* Implementations: */ - virtio_pci_types_register(&virtio_rng_pci_info); #ifdef CONFIG_VIRTFS virtio_pci_types_register(&virtio_9p_pci_info); #endif diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index f1c75b0..a8b2e49 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -18,7 +18,6 @@ #include "hw/pci/msi.h" #include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-net.h" -#include "hw/virtio/virtio-rng.h" #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-balloon.h" @@ -46,7 +45,6 @@ typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VHostSCSIPCI VHostSCSIPCI; typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; typedef struct VHostUserBlkPCI VHostUserBlkPCI; -typedef struct VirtIORngPCI VirtIORngPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -320,18 +318,6 @@ typedef struct V9fsPCIState { #endif /* - * virtio-rng-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci-base" -#define VIRTIO_RNG_PCI(obj) \ - OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI) - -struct VirtIORngPCI { - VirtIOPCIProxy parent_obj; - VirtIORNG vdev; -}; - -/* * virtio-input-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c new file mode 100644 index 0000000..6cc6374 --- /dev/null +++ b/hw/virtio/virtio-rng-pci.c @@ -0,0 +1,88 @@ +/* + * Virtio rng PCI Bindings + * + * Copyright 2012 Red Hat, Inc. + * Copyright 2012 Amit Shah + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-rng.h" +#include "qapi/error.h" + +typedef struct VirtIORngPCI VirtIORngPCI; + +/* + * virtio-rng-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci-base" +#define VIRTIO_RNG_PCI(obj) \ + OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI) + +struct VirtIORngPCI { + VirtIOPCIProxy parent_obj; + VirtIORNG vdev; +}; + +static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&vrng->vdev); + Error *err = NULL; + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_link(OBJECT(vrng), + OBJECT(vrng->vdev.conf.rng), "rng", + NULL); +} + +static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + k->realize = virtio_rng_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_OTHERS; +} + +static void virtio_rng_initfn(Object *obj) +{ + VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); +} + +static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = { + .base_name = TYPE_VIRTIO_RNG_PCI, + .generic_name = "virtio-rng-pci", + .transitional_name = "virtio-rng-pci-transitional", + .non_transitional_name = "virtio-rng-pci-non-transitional", + .instance_size = sizeof(VirtIORngPCI), + .instance_init = virtio_rng_initfn, + .class_init = virtio_rng_pci_class_init, +}; + +static void virtio_rng_pci_register(void) +{ + virtio_pci_types_register(&virtio_rng_pci_info); +} + +type_init(virtio_rng_pci_register) diff --git a/tests/Makefile.include b/tests/Makefile.include index 601ef4f..3a50b3b 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -149,7 +149,7 @@ check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF) check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) -check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF) +check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF) check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF) ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF) -- cgit v1.1 From 271458d7833b95863c472e8be9ddffd750e64a04 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:02 +0100 Subject: virtio: split virtio balloon bits from virtio-pci Reviewed-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-balloon-pci.c | 95 ++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 61 +-------------------------- hw/virtio/virtio-pci.h | 14 ------- tests/Makefile.include | 2 +- 5 files changed, 98 insertions(+), 75 deletions(-) create mode 100644 hw/virtio/virtio-balloon-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 032ba2f..9e33104 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -16,6 +16,7 @@ obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o +obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o endif endif diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c new file mode 100644 index 0000000..2a213bb --- /dev/null +++ b/hw/virtio/virtio-balloon-pci.c @@ -0,0 +1,95 @@ +/* + * Virtio balloon PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori + * Paul Brook + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-balloon.h" +#include "qapi/error.h" + +typedef struct VirtIOBalloonPCI VirtIOBalloonPCI; + +/* + * virtio-balloon-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base" +#define VIRTIO_BALLOON_PCI(obj) \ + OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI) + +struct VirtIOBalloonPCI { + VirtIOPCIProxy parent_obj; + VirtIOBalloon vdev; +}; +static Property virtio_balloon_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + if (vpci_dev->class_code != PCI_CLASS_OTHERS && + vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */ + vpci_dev->class_code = PCI_CLASS_OTHERS; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = virtio_balloon_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->props = virtio_balloon_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_OTHERS; +} + +static void virtio_balloon_pci_instance_init(Object *obj) +{ + VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BALLOON); + object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev), + "guest-stats", &error_abort); + object_property_add_alias(obj, "guest-stats-polling-interval", + OBJECT(&dev->vdev), + "guest-stats-polling-interval", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = { + .base_name = TYPE_VIRTIO_BALLOON_PCI, + .generic_name = "virtio-balloon-pci", + .transitional_name = "virtio-balloon-pci-transitional", + .non_transitional_name = "virtio-balloon-pci-non-transitional", + .instance_size = sizeof(VirtIOBalloonPCI), + .instance_init = virtio_balloon_pci_instance_init, + .class_init = virtio_balloon_pci_class_init, +}; + +static void virtio_balloon_pci_register(void) +{ + virtio_pci_types_register(&virtio_balloon_pci_info); +} + +type_init(virtio_balloon_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 2e3eafd..a01c9dd 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -23,7 +23,6 @@ #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-scsi.h" -#include "hw/virtio/virtio-balloon.h" #include "hw/pci/pci.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -2356,64 +2355,6 @@ static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = { }; #endif -/* virtio-balloon-pci */ - -static Property virtio_balloon_pci_properties[] = { - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - if (vpci_dev->class_code != PCI_CLASS_OTHERS && - vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */ - vpci_dev->class_code = PCI_CLASS_OTHERS; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = virtio_balloon_pci_realize; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = virtio_balloon_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_OTHERS; -} - -static void virtio_balloon_pci_instance_init(Object *obj) -{ - VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_BALLOON); - object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev), - "guest-stats", &error_abort); - object_property_add_alias(obj, "guest-stats-polling-interval", - OBJECT(&dev->vdev), - "guest-stats-polling-interval", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = { - .base_name = TYPE_VIRTIO_BALLOON_PCI, - .generic_name = "virtio-balloon-pci", - .transitional_name = "virtio-balloon-pci-transitional", - .non_transitional_name = "virtio-balloon-pci-non-transitional", - .instance_size = sizeof(VirtIOBalloonPCI), - .instance_init = virtio_balloon_pci_instance_init, - .class_init = virtio_balloon_pci_class_init, -}; - /* virtio-serial-pci */ static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) @@ -2606,7 +2547,6 @@ static void virtio_pci_register_types(void) virtio_pci_types_register(&vhost_user_blk_pci_info); #endif virtio_pci_types_register(&virtio_scsi_pci_info); - virtio_pci_types_register(&virtio_balloon_pci_info); virtio_pci_types_register(&virtio_serial_pci_info); virtio_pci_types_register(&virtio_net_pci_info); #ifdef CONFIG_VHOST_SCSI @@ -2618,3 +2558,4 @@ static void virtio_pci_register_types(void) } type_init(virtio_pci_register_types) + diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index a8b2e49..a2988ef 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -20,7 +20,6 @@ #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-scsi.h" -#include "hw/virtio/virtio-balloon.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" @@ -39,7 +38,6 @@ typedef struct VirtIOPCIProxy VirtIOPCIProxy; typedef struct VirtIOBlkPCI VirtIOBlkPCI; typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; -typedef struct VirtIOBalloonPCI VirtIOBalloonPCI; typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VHostSCSIPCI VHostSCSIPCI; @@ -265,18 +263,6 @@ struct VirtIOBlkPCI { }; /* - * virtio-balloon-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base" -#define VIRTIO_BALLOON_PCI(obj) \ - OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI) - -struct VirtIOBalloonPCI { - VirtIOPCIProxy parent_obj; - VirtIOBalloon vdev; -}; - -/* * virtio-serial-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base" diff --git a/tests/Makefile.include b/tests/Makefile.include index 3a50b3b..0d76ec6 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -147,7 +147,7 @@ check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF) check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) -check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF) +check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF) check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF) check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF) -- cgit v1.1 From ddac19f534b3b6642c511ee498cc01df5661b20e Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:03 +0100 Subject: virtio: split virtio 9p bits from virtio-pci Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Acked-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-9p-pci.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 54 ----------------------------- hw/virtio/virtio-pci.h | 20 ----------- tests/Makefile.include | 2 +- 5 files changed, 90 insertions(+), 75 deletions(-) create mode 100644 hw/virtio/virtio-9p-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 9e33104..3e655fd 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -17,6 +17,7 @@ obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o +obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o endif endif diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c new file mode 100644 index 0000000..7bf1130 --- /dev/null +++ b/hw/virtio/virtio-9p-pci.c @@ -0,0 +1,88 @@ +/* + * Virtio 9p PCI Bindings + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/9pfs/virtio-9p.h" + +/* + * virtio-9p-pci: This extends VirtioPCIProxy. + */ + +#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci-base" +#define VIRTIO_9P_PCI(obj) \ + OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI) + +typedef struct V9fsPCIState { + VirtIOPCIProxy parent_obj; + V9fsVirtioState vdev; +} V9fsPCIState; + +static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static Property virtio_9p_pci_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + + k->realize = virtio_9p_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = 0x2; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = virtio_9p_pci_properties; +} + +static void virtio_9p_pci_instance_init(Object *obj) +{ + V9fsPCIState *dev = VIRTIO_9P_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_9P); +} + +static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = { + .base_name = TYPE_VIRTIO_9P_PCI, + .generic_name = "virtio-9p-pci", + .transitional_name = "virtio-9p-pci-transitional", + .non_transitional_name = "virtio-9p-pci-non-transitional", + .instance_size = sizeof(V9fsPCIState), + .instance_init = virtio_9p_pci_instance_init, + .class_init = virtio_9p_pci_class_init, +}; + +static void virtio_9p_pci_register(void) +{ + virtio_pci_types_register(&virtio_9p_pci_info); +} + +type_init(virtio_9p_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index a01c9dd..a62006c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1077,57 +1077,6 @@ static void virtio_pci_vmstate_change(DeviceState *d, bool running) } } -#ifdef CONFIG_VIRTFS -static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static Property virtio_9p_pci_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - - k->realize = virtio_9p_pci_realize; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = 0x2; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = virtio_9p_pci_properties; -} - -static void virtio_9p_pci_instance_init(Object *obj) -{ - V9fsPCIState *dev = VIRTIO_9P_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_9P); -} - -static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = { - .base_name = TYPE_VIRTIO_9P_PCI, - .generic_name = "virtio-9p-pci", - .transitional_name = "virtio-9p-pci-transitional", - .non_transitional_name = "virtio-9p-pci-non-transitional", - .instance_size = sizeof(V9fsPCIState), - .instance_init = virtio_9p_pci_instance_init, - .class_init = virtio_9p_pci_class_init, -}; -#endif /* CONFIG_VIRTFS */ - /* * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. */ @@ -2539,9 +2488,6 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_pci_info); /* Implementations: */ -#ifdef CONFIG_VIRTFS - virtio_pci_types_register(&virtio_9p_pci_info); -#endif virtio_pci_types_register(&virtio_blk_pci_info); #if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) virtio_pci_types_register(&vhost_user_blk_pci_info); diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index a2988ef..94af084 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -28,9 +28,6 @@ #include "hw/virtio/vhost-user-blk.h" #endif -#ifdef CONFIG_VIRTFS -#include "hw/9pfs/virtio-9p.h" -#endif #ifdef CONFIG_VHOST_SCSI #include "hw/virtio/vhost-scsi.h" #endif @@ -287,23 +284,6 @@ struct VirtIONetPCI { }; /* - * virtio-9p-pci: This extends VirtioPCIProxy. - */ - -#ifdef CONFIG_VIRTFS - -#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci-base" -#define VIRTIO_9P_PCI(obj) \ - OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI) - -typedef struct V9fsPCIState { - VirtIOPCIProxy parent_obj; - V9fsVirtioState vdev; -} V9fsPCIState; - -#endif - -/* * virtio-input-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" diff --git a/tests/Makefile.include b/tests/Makefile.include index 0d76ec6..c2845b6 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -152,7 +152,7 @@ check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF) check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF) ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) -check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF) +check-qtest-virtio-$(CONFIG_VIRTIO_9P) += tests/virtio-9p-test$(EXESUF) endif check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF) check-qtest-virtio-y += $(check-qtest-virtioserial-y) -- cgit v1.1 From f170c5ef2fd0f99e9b9fe72276f8b74f17eaf3c5 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:04 +0100 Subject: virtio: split vhost user blk bits from virtio-pci Reviewed-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/vhost-user-blk-pci.c | 103 +++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 62 ------------------------- hw/virtio/virtio-pci.h | 18 ------- 4 files changed, 104 insertions(+), 80 deletions(-) create mode 100644 hw/virtio/vhost-user-blk-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 3e655fd..35b7698 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -13,6 +13,7 @@ obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o +obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c new file mode 100644 index 0000000..ca66c21 --- /dev/null +++ b/hw/virtio/vhost-user-blk-pci.c @@ -0,0 +1,103 @@ +/* + * Vhost user blk PCI Bindings + * + * Copyright(C) 2017 Intel Corporation. + * + * Authors: + * Changpeng Liu + * + * Largely based on the "vhost-user-scsi.c" and "vhost-scsi.c" implemented by: + * Felipe Franciosi + * Stefan Hajnoczi + * Nicholas Bellinger + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "standard-headers/linux/virtio_pci.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/vhost-user-blk.h" +#include "hw/pci/pci.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "virtio-pci.h" + +typedef struct VHostUserBlkPCI VHostUserBlkPCI; + +/* + * vhost-user-blk-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci-base" +#define VHOST_USER_BLK_PCI(obj) \ + OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI) + +struct VHostUserBlkPCI { + VirtIOPCIProxy parent_obj; + VHostUserBlk vdev; +}; + +static Property vhost_user_blk_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.num_queues + 1; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = vhost_user_blk_pci_properties; + k->realize = vhost_user_blk_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void vhost_user_blk_pci_instance_init(Object *obj) +{ + VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_BLK); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = { + .base_name = TYPE_VHOST_USER_BLK_PCI, + .generic_name = "vhost-user-blk-pci", + .transitional_name = "vhost-user-blk-pci-transitional", + .non_transitional_name = "vhost-user-blk-pci-non-transitional", + .instance_size = sizeof(VHostUserBlkPCI), + .instance_init = vhost_user_blk_pci_instance_init, + .class_init = vhost_user_blk_pci_class_init, +}; + +static void vhost_user_blk_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_blk_pci_info); +} + +type_init(vhost_user_blk_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index a62006c..44cc022 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2061,65 +2061,6 @@ static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { .class_init = virtio_blk_pci_class_init, }; -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -/* vhost-user-blk */ - -static Property vhost_user_blk_pci_properties[] = { - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = dev->vdev.num_queues + 1; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = vhost_user_blk_pci_properties; - k->realize = vhost_user_blk_pci_realize; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void vhost_user_blk_pci_instance_init(Object *obj) -{ - VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_USER_BLK); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = { - .base_name = TYPE_VHOST_USER_BLK_PCI, - .generic_name = "vhost-user-blk-pci", - .transitional_name = "vhost-user-blk-pci-transitional", - .non_transitional_name = "vhost-user-blk-pci-non-transitional", - .instance_size = sizeof(VHostUserBlkPCI), - .instance_init = vhost_user_blk_pci_instance_init, - .class_init = vhost_user_blk_pci_class_init, -}; -#endif - /* virtio-scsi-pci */ static Property virtio_scsi_pci_properties[] = { @@ -2489,9 +2430,6 @@ static void virtio_pci_register_types(void) /* Implementations: */ virtio_pci_types_register(&virtio_blk_pci_info); -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) - virtio_pci_types_register(&vhost_user_blk_pci_info); -#endif virtio_pci_types_register(&virtio_scsi_pci_info); virtio_pci_types_register(&virtio_serial_pci_info); virtio_pci_types_register(&virtio_net_pci_info); diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 94af084..acbbe5c 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -24,9 +24,6 @@ #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" #include "hw/virtio/vhost-user-scsi.h" -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -#include "hw/virtio/vhost-user-blk.h" -#endif #ifdef CONFIG_VHOST_SCSI #include "hw/virtio/vhost-scsi.h" @@ -39,7 +36,6 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VHostSCSIPCI VHostSCSIPCI; typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; -typedef struct VHostUserBlkPCI VHostUserBlkPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -233,20 +229,6 @@ struct VHostUserSCSIPCI { VHostUserSCSI vdev; }; -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -/* - * vhost-user-blk-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci-base" -#define VHOST_USER_BLK_PCI(obj) \ - OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI) - -struct VHostUserBlkPCI { - VirtIOPCIProxy parent_obj; - VHostUserBlk vdev; -}; -#endif - /* * virtio-blk-pci: This extends VirtioPCIProxy. */ -- cgit v1.1 From 693510dd20000f0d5edd64f1fae269b0ee320af3 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:05 +0100 Subject: virtio: split vhost user scsi bits from virtio-pci Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/vhost-user-scsi-pci.c | 103 ++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 60 ----------------------- hw/virtio/virtio-pci.h | 11 ----- 4 files changed, 104 insertions(+), 71 deletions(-) create mode 100644 hw/virtio/vhost-user-scsi-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 35b7698..f851a6f 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -14,6 +14,7 @@ obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o +obj-$(CONFIG_VHOST_USER_SCSI) += vhost-user-scsi-pci.o obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c new file mode 100644 index 0000000..46f7193 --- /dev/null +++ b/hw/virtio/vhost-user-scsi-pci.c @@ -0,0 +1,103 @@ +/* + * Vhost user scsi PCI Bindings + * + * Copyright (c) 2016 Nutanix Inc. All rights reserved. + * + * Author: + * Felipe Franciosi + * + * This work is largely based on the "vhost-scsi" implementation by: + * Stefan Hajnoczi + * Nicholas Bellinger + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "standard-headers/linux/virtio_pci.h" +#include "hw/virtio/vhost-user-scsi.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-scsi.h" +#include "hw/pci/pci.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/loader.h" +#include "sysemu/kvm.h" +#include "virtio-pci.h" + +typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; + +#define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci-base" +#define VHOST_USER_SCSI_PCI(obj) \ + OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI) + +struct VHostUserSCSIPCI { + VirtIOPCIProxy parent_obj; + VHostUserSCSI vdev; +}; + +static Property vhost_user_scsi_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = vs->conf.num_queues + 3; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_user_scsi_pci_realize; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = vhost_user_scsi_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void vhost_user_scsi_pci_instance_init(Object *obj) +{ + VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_SCSI); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = { + .base_name = TYPE_VHOST_USER_SCSI_PCI, + .generic_name = "vhost-user-scsi-pci", + .transitional_name = "vhost-user-scsi-pci-transitional", + .non_transitional_name = "vhost-user-scsi-pci-non-transitional", + .instance_size = sizeof(VHostUserSCSIPCI), + .instance_init = vhost_user_scsi_pci_instance_init, + .class_init = vhost_user_scsi_pci_class_init, +}; + +static void vhost_user_scsi_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_scsi_pci_info); +} + +type_init(vhost_user_scsi_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 44cc022..13cb132 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2188,63 +2188,6 @@ static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = { }; #endif -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -/* vhost-user-scsi-pci */ -static Property vhost_user_scsi_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = vs->conf.num_queues + 3; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = vhost_user_scsi_pci_realize; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = vhost_user_scsi_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void vhost_user_scsi_pci_instance_init(Object *obj) -{ - VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_USER_SCSI); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = { - .base_name = TYPE_VHOST_USER_SCSI_PCI, - .generic_name = "vhost-user-scsi-pci", - .transitional_name = "vhost-user-scsi-pci-transitional", - .non_transitional_name = "vhost-user-scsi-pci-non-transitional", - .instance_size = sizeof(VHostUserSCSIPCI), - .instance_init = vhost_user_scsi_pci_instance_init, - .class_init = vhost_user_scsi_pci_class_init, -}; -#endif - /* virtio-serial-pci */ static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) @@ -2436,9 +2379,6 @@ static void virtio_pci_register_types(void) #ifdef CONFIG_VHOST_SCSI virtio_pci_types_register(&vhost_scsi_pci_info); #endif -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) - virtio_pci_types_register(&vhost_user_scsi_pci_info); -#endif } type_init(virtio_pci_register_types) diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index acbbe5c..ce6c194 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -23,7 +23,6 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" -#include "hw/virtio/vhost-user-scsi.h" #ifdef CONFIG_VHOST_SCSI #include "hw/virtio/vhost-scsi.h" @@ -35,7 +34,6 @@ typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VHostSCSIPCI VHostSCSIPCI; -typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -220,15 +218,6 @@ struct VHostSCSIPCI { }; #endif -#define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci-base" -#define VHOST_USER_SCSI_PCI(obj) \ - OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI) - -struct VHostUserSCSIPCI { - VirtIOPCIProxy parent_obj; - VHostUserSCSI vdev; -}; - /* * virtio-blk-pci: This extends VirtioPCIProxy. */ -- cgit v1.1 From 7dc768965759e3296c263027ca887e8329a3d4ee Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:06 +0100 Subject: virtio: split vhost scsi bits from virtio-pci Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/vhost-scsi-pci.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 61 ----------------------------- hw/virtio/virtio-pci.h | 19 --------- 4 files changed, 98 insertions(+), 80 deletions(-) create mode 100644 hw/virtio/vhost-scsi-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index f851a6f..0a56946 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -15,6 +15,7 @@ ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o obj-$(CONFIG_VHOST_USER_SCSI) += vhost-user-scsi-pci.o +obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-pci.o obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c new file mode 100644 index 0000000..523f7cb --- /dev/null +++ b/hw/virtio/vhost-scsi-pci.c @@ -0,0 +1,97 @@ +/* + * Vhost scsi PCI bindings + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * + * Changes for QEMU mainline + tcm_vhost kernel upstream: + * Nicholas Bellinger + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "standard-headers/linux/virtio_pci.h" +#include "hw/virtio/vhost-scsi.h" +#include "qapi/error.h" +#include "virtio-pci.h" + +typedef struct VHostSCSIPCI VHostSCSIPCI; + +/* + * vhost-scsi-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci-base" +#define VHOST_SCSI_PCI(obj) \ + OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI) + +struct VHostSCSIPCI { + VirtIOPCIProxy parent_obj; + VHostSCSI vdev; +}; + +static Property vhost_scsi_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = vs->conf.num_queues + 3; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_scsi_pci_realize; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = vhost_scsi_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void vhost_scsi_pci_instance_init(Object *obj) +{ + VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = { + .base_name = TYPE_VHOST_SCSI_PCI, + .generic_name = "vhost-scsi-pci", + .transitional_name = "vhost-scsi-pci-transitional", + .non_transitional_name = "vhost-scsi-pci-non-transitional", + .instance_size = sizeof(VHostSCSIPCI), + .instance_init = vhost_scsi_pci_instance_init, + .class_init = vhost_scsi_pci_class_init, +}; + +static void vhost_scsi_pci_register(void) +{ + virtio_pci_types_register(&vhost_scsi_pci_info); +} + +type_init(vhost_scsi_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 13cb132..b2ed6b3 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2130,64 +2130,6 @@ static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = { .class_init = virtio_scsi_pci_class_init, }; -/* vhost-scsi-pci */ - -#ifdef CONFIG_VHOST_SCSI -static Property vhost_scsi_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = vs->conf.num_queues + 3; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = vhost_scsi_pci_realize; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = vhost_scsi_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void vhost_scsi_pci_instance_init(Object *obj) -{ - VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_SCSI); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = { - .base_name = TYPE_VHOST_SCSI_PCI, - .generic_name = "vhost-scsi-pci", - .transitional_name = "vhost-scsi-pci-transitional", - .non_transitional_name = "vhost-scsi-pci-non-transitional", - .instance_size = sizeof(VHostSCSIPCI), - .instance_init = vhost_scsi_pci_instance_init, - .class_init = vhost_scsi_pci_class_init, -}; -#endif - /* virtio-serial-pci */ static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) @@ -2376,9 +2318,6 @@ static void virtio_pci_register_types(void) virtio_pci_types_register(&virtio_scsi_pci_info); virtio_pci_types_register(&virtio_serial_pci_info); virtio_pci_types_register(&virtio_net_pci_info); -#ifdef CONFIG_VHOST_SCSI - virtio_pci_types_register(&vhost_scsi_pci_info); -#endif } type_init(virtio_pci_register_types) diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index ce6c194..b14d83a 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -24,16 +24,11 @@ #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" -#ifdef CONFIG_VHOST_SCSI -#include "hw/virtio/vhost-scsi.h" -#endif - typedef struct VirtIOPCIProxy VirtIOPCIProxy; typedef struct VirtIOBlkPCI VirtIOBlkPCI; typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; -typedef struct VHostSCSIPCI VHostSCSIPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -204,20 +199,6 @@ struct VirtIOSCSIPCI { VirtIOSCSI vdev; }; -#ifdef CONFIG_VHOST_SCSI -/* - * vhost-scsi-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci-base" -#define VHOST_SCSI_PCI(obj) \ - OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI) - -struct VHostSCSIPCI { - VirtIOPCIProxy parent_obj; - VHostSCSI vdev; -}; -#endif - /* * virtio-blk-pci: This extends VirtioPCIProxy. */ -- cgit v1.1 From 2f9493984e34a0ddfbccde9b747370874143e222 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:07 +0100 Subject: virtio: split virtio scsi bits from virtio-pci Notice that we can't still run tests with it disabled. Both cdrom-test and drive_del-test use virtio-scsi without checking if it is enabled. Reviewed-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-pci.c | 71 ----------------------------- hw/virtio/virtio-pci.h | 14 ------ hw/virtio/virtio-scsi-pci.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ tests/Makefile.include | 2 +- 5 files changed, 109 insertions(+), 86 deletions(-) create mode 100644 hw/virtio/virtio-scsi-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 0a56946..012b6f7 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -21,6 +21,7 @@ obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o +obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi-pci.o endif endif diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index b2ed6b3..da812b7 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -22,7 +22,6 @@ #include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-scsi.h" #include "hw/pci/pci.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -2061,75 +2060,6 @@ static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { .class_init = virtio_blk_pci_class_init, }; -/* virtio-scsi-pci */ - -static Property virtio_scsi_pci_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - DeviceState *proxy = DEVICE(vpci_dev); - char *bus_name; - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = vs->conf.num_queues + 3; - } - - /* - * For command line compatibility, this sets the virtio-scsi-device bus - * name as before. - */ - if (proxy->id) { - bus_name = g_strdup_printf("%s.0", proxy->id); - virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); - g_free(bus_name); - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - k->realize = virtio_scsi_pci_realize; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = virtio_scsi_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void virtio_scsi_pci_instance_init(Object *obj) -{ - VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_SCSI); -} - -static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = { - .base_name = TYPE_VIRTIO_SCSI_PCI, - .generic_name = "virtio-scsi-pci", - .transitional_name = "virtio-scsi-pci-transitional", - .non_transitional_name = "virtio-scsi-pci-non-transitional", - .instance_size = sizeof(VirtIOSCSIPCI), - .instance_init = virtio_scsi_pci_instance_init, - .class_init = virtio_scsi_pci_class_init, -}; - /* virtio-serial-pci */ static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) @@ -2315,7 +2245,6 @@ static void virtio_pci_register_types(void) /* Implementations: */ virtio_pci_types_register(&virtio_blk_pci_info); - virtio_pci_types_register(&virtio_scsi_pci_info); virtio_pci_types_register(&virtio_serial_pci_info); virtio_pci_types_register(&virtio_net_pci_info); } diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index b14d83a..d00f6d6 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -19,14 +19,12 @@ #include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; typedef struct VirtIOBlkPCI VirtIOBlkPCI; -typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; @@ -188,18 +186,6 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) } /* - * virtio-scsi-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci-base" -#define VIRTIO_SCSI_PCI(obj) \ - OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI) - -struct VirtIOSCSIPCI { - VirtIOPCIProxy parent_obj; - VirtIOSCSI vdev; -}; - -/* * virtio-blk-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c new file mode 100644 index 0000000..2830849 --- /dev/null +++ b/hw/virtio/virtio-scsi-pci.c @@ -0,0 +1,107 @@ +/* + * Virtio scsi PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori + * Paul Brook + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-scsi.h" +#include "virtio-pci.h" + +typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; + +/* + * virtio-scsi-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci-base" +#define VIRTIO_SCSI_PCI(obj) \ + OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI) + +struct VirtIOSCSIPCI { + VirtIOPCIProxy parent_obj; + VirtIOSCSI vdev; +}; + +static Property virtio_scsi_pci_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + DeviceState *proxy = DEVICE(vpci_dev); + char *bus_name; + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = vs->conf.num_queues + 3; + } + + /* + * For command line compatibility, this sets the virtio-scsi-device bus + * name as before. + */ + if (proxy->id) { + bus_name = g_strdup_printf("%s.0", proxy->id); + virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); + g_free(bus_name); + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + k->realize = virtio_scsi_pci_realize; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = virtio_scsi_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void virtio_scsi_pci_instance_init(Object *obj) +{ + VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); +} + +static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = { + .base_name = TYPE_VIRTIO_SCSI_PCI, + .generic_name = "virtio-scsi-pci", + .transitional_name = "virtio-scsi-pci-transitional", + .non_transitional_name = "virtio-scsi-pci-non-transitional", + .instance_size = sizeof(VirtIOSCSIPCI), + .instance_init = virtio_scsi_pci_instance_init, + .class_init = virtio_scsi_pci_class_init, +}; + +static void virtio_scsi_pci_register(void) +{ + virtio_pci_types_register(&virtio_scsi_pci_info); +} + +type_init(virtio_scsi_pci_register) diff --git a/tests/Makefile.include b/tests/Makefile.include index c2845b6..ba82235 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -150,7 +150,7 @@ check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF) check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF) -check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF) +check-qtest-virtio-$(CONFIG_VIRTIO_SCSI) += tests/virtio-scsi-test$(EXESUF) ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) check-qtest-virtio-$(CONFIG_VIRTIO_9P) += tests/virtio-9p-test$(EXESUF) endif -- cgit v1.1 From ea7af5dba5ff0297ba48a029c95adecd529e71b7 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:08 +0100 Subject: virtio: split virtio blk bits from virtio-pci Reviewed-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-blk-pci.c | 100 +++++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 61 --------------------------- hw/virtio/virtio-pci.h | 14 ------- tests/Makefile.include | 4 +- 5 files changed, 103 insertions(+), 77 deletions(-) create mode 100644 hw/virtio/virtio-blk-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 012b6f7..557ad06 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -22,6 +22,7 @@ obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi-pci.o +obj-$(CONFIG_VIRTIO_BLK) += virtio-blk-pci.o endif endif diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c new file mode 100644 index 0000000..60c9185 --- /dev/null +++ b/hw/virtio/virtio-blk-pci.c @@ -0,0 +1,100 @@ +/* + * Virtio blk PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori + * Paul Brook + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-blk.h" +#include "virtio-pci.h" +#include "qapi/error.h" + +typedef struct VirtIOBlkPCI VirtIOBlkPCI; + +/* + * virtio-blk-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" +#define VIRTIO_BLK_PCI(obj) \ + OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI) + +struct VirtIOBlkPCI { + VirtIOPCIProxy parent_obj; + VirtIOBlock vdev; +}; + +static Property virtio_blk_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.conf.num_queues + 1; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = virtio_blk_pci_properties; + k->realize = virtio_blk_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void virtio_blk_pci_instance_init(Object *obj) +{ + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { + .base_name = TYPE_VIRTIO_BLK_PCI, + .generic_name = "virtio-blk-pci", + .transitional_name = "virtio-blk-pci-transitional", + .non_transitional_name = "virtio-blk-pci-non-transitional", + .instance_size = sizeof(VirtIOBlkPCI), + .instance_init = virtio_blk_pci_instance_init, + .class_init = virtio_blk_pci_class_init, +}; + +static void virtio_blk_pci_register(void) +{ + virtio_pci_types_register(&virtio_blk_pci_info); +} + +type_init(virtio_blk_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index da812b7..859b03a 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -19,7 +19,6 @@ #include "standard-headers/linux/virtio_pci.h" #include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" #include "hw/pci/pci.h" @@ -2001,65 +2000,6 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) } } -/* virtio-blk-pci */ - -static Property virtio_blk_pci_properties[] = { - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = dev->vdev.conf.num_queues + 1; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = virtio_blk_pci_properties; - k->realize = virtio_blk_pci_realize; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void virtio_blk_pci_instance_init(Object *obj) -{ - VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_BLK); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { - .base_name = TYPE_VIRTIO_BLK_PCI, - .generic_name = "virtio-blk-pci", - .transitional_name = "virtio-blk-pci-transitional", - .non_transitional_name = "virtio-blk-pci-non-transitional", - .instance_size = sizeof(VirtIOBlkPCI), - .instance_init = virtio_blk_pci_instance_init, - .class_init = virtio_blk_pci_class_init, -}; - /* virtio-serial-pci */ static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) @@ -2244,7 +2184,6 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_pci_info); /* Implementations: */ - virtio_pci_types_register(&virtio_blk_pci_info); virtio_pci_types_register(&virtio_serial_pci_info); virtio_pci_types_register(&virtio_net_pci_info); } diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index d00f6d6..b805c02 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -16,7 +16,6 @@ #define QEMU_VIRTIO_PCI_H #include "hw/pci/msi.h" -#include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-bus.h" @@ -24,7 +23,6 @@ #include "hw/virtio/virtio-crypto.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; -typedef struct VirtIOBlkPCI VirtIOBlkPCI; typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; @@ -186,18 +184,6 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) } /* - * virtio-blk-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" -#define VIRTIO_BLK_PCI(obj) \ - OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI) - -struct VirtIOBlkPCI { - VirtIOPCIProxy parent_obj; - VirtIOBlock vdev; -}; - -/* * virtio-serial-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base" diff --git a/tests/Makefile.include b/tests/Makefile.include index ba82235..03dbc6b 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -148,7 +148,7 @@ check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF) -check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) +check-qtest-virtio-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_SCSI) += tests/virtio-scsi-test$(EXESUF) ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) @@ -285,7 +285,7 @@ check-qtest-arm-y += tests/pca9552-test$(EXESUF) check-qtest-arm-y += tests/ds1338-test$(EXESUF) check-qtest-arm-y += tests/microbit-test$(EXESUF) check-qtest-arm-y += tests/m25p80-test$(EXESUF) -check-qtest-arm-y += tests/virtio-blk-test$(EXESUF) +check-qtest-arm-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF) check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF) check-qtest-arm-y += tests/boot-serial-test$(EXESUF) check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF) -- cgit v1.1 From cad3cd79a1d14873921dada2dfc6cc68b80cf0a5 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:09 +0100 Subject: virtio: split virtio net bits from virtio-pci Reviewed-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-net-pci.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 59 ---------------------------- hw/virtio/virtio-pci.h | 14 ------- tests/Makefile.include | 2 +- 5 files changed, 100 insertions(+), 74 deletions(-) create mode 100644 hw/virtio/virtio-net-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 557ad06..4c31acb 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -23,6 +23,7 @@ obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi-pci.o obj-$(CONFIG_VIRTIO_BLK) += virtio-blk-pci.o +obj-$(CONFIG_VIRTIO_NET) += virtio-net-pci.o endif endif diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c new file mode 100644 index 0000000..db07ab9 --- /dev/null +++ b/hw/virtio/virtio-net-pci.c @@ -0,0 +1,98 @@ +/* + * Virtio net PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori + * Paul Brook + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-net.h" +#include "virtio-pci.h" +#include "qapi/error.h" + +typedef struct VirtIONetPCI VirtIONetPCI; + +/* + * virtio-net-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_NET_PCI "virtio-net-pci-base" +#define VIRTIO_NET_PCI(obj) \ + OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI) + +struct VirtIONetPCI { + VirtIOPCIProxy parent_obj; + VirtIONet vdev; +}; + +static Property virtio_net_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + DeviceState *qdev = DEVICE(vpci_dev); + VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + virtio_net_set_netclient_name(&dev->vdev, qdev->id, + object_get_typename(OBJECT(qdev))); + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_net_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); + + k->romfile = "efi-virtio.rom"; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_NET; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->props = virtio_net_properties; + vpciklass->realize = virtio_net_pci_realize; +} + +static void virtio_net_pci_instance_init(Object *obj) +{ + VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = { + .base_name = TYPE_VIRTIO_NET_PCI, + .generic_name = "virtio-net-pci", + .transitional_name = "virtio-net-pci-transitional", + .non_transitional_name = "virtio-net-pci-non-transitional", + .instance_size = sizeof(VirtIONetPCI), + .instance_init = virtio_net_pci_instance_init, + .class_init = virtio_net_pci_class_init, +}; + +static void virtio_net_pci_register(void) +{ + virtio_pci_types_register(&virtio_net_pci_info); +} + +type_init(virtio_net_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 859b03a..c3e3791 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -19,7 +19,6 @@ #include "standard-headers/linux/virtio_pci.h" #include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" #include "hw/pci/pci.h" #include "qapi/error.h" @@ -2075,63 +2074,6 @@ static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = { .class_init = virtio_serial_pci_class_init, }; -/* virtio-net-pci */ - -static Property virtio_net_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - DeviceState *qdev = DEVICE(vpci_dev); - VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - virtio_net_set_netclient_name(&dev->vdev, qdev->id, - object_get_typename(OBJECT(qdev))); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_net_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); - - k->romfile = "efi-virtio.rom"; - k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = PCI_DEVICE_ID_VIRTIO_NET; - k->revision = VIRTIO_PCI_ABI_VERSION; - k->class_id = PCI_CLASS_NETWORK_ETHERNET; - set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); - dc->props = virtio_net_properties; - vpciklass->realize = virtio_net_pci_realize; -} - -static void virtio_net_pci_instance_init(Object *obj) -{ - VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_NET); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = { - .base_name = TYPE_VIRTIO_NET_PCI, - .generic_name = "virtio-net-pci", - .transitional_name = "virtio-net-pci-transitional", - .non_transitional_name = "virtio-net-pci-non-transitional", - .instance_size = sizeof(VirtIONetPCI), - .instance_init = virtio_net_pci_instance_init, - .class_init = virtio_net_pci_class_init, -}; - /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -2185,7 +2127,6 @@ static void virtio_pci_register_types(void) /* Implementations: */ virtio_pci_types_register(&virtio_serial_pci_info); - virtio_pci_types_register(&virtio_net_pci_info); } type_init(virtio_pci_register_types) diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index b805c02..8bfd4b9 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -16,7 +16,6 @@ #define QEMU_VIRTIO_PCI_H #include "hw/pci/msi.h" -#include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-gpu.h" @@ -24,7 +23,6 @@ typedef struct VirtIOPCIProxy VirtIOPCIProxy; typedef struct VirtIOSerialPCI VirtIOSerialPCI; -typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -196,18 +194,6 @@ struct VirtIOSerialPCI { }; /* - * virtio-net-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_NET_PCI "virtio-net-pci-base" -#define VIRTIO_NET_PCI(obj) \ - OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI) - -struct VirtIONetPCI { - VirtIOPCIProxy parent_obj; - VirtIONet vdev; -}; - -/* * virtio-input-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" diff --git a/tests/Makefile.include b/tests/Makefile.include index 03dbc6b..590ee0c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -146,7 +146,7 @@ check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF) check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) -check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) +check-qtest-virtio-$(CONFIG_VIRTIO_NET) += tests/virtio-net-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF) -- cgit v1.1 From f386df1744837b17f946fa4ced87bf421be4e65e Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:10 +0100 Subject: virtio: split virtio serial bits from virtio-pci Virtio console and qga tests also depend on CONFIG_VIRTIO_SERIAL. Reviewed-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-pci.c | 79 ----------------------------- hw/virtio/virtio-pci.h | 14 ----- hw/virtio/virtio-serial-pci.c | 115 ++++++++++++++++++++++++++++++++++++++++++ tests/Makefile.include | 6 +-- 5 files changed, 119 insertions(+), 96 deletions(-) create mode 100644 hw/virtio/virtio-serial-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 4c31acb..ea7913d 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -24,6 +24,7 @@ obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi-pci.o obj-$(CONFIG_VIRTIO_BLK) += virtio-blk-pci.o obj-$(CONFIG_VIRTIO_NET) += virtio-net-pci.o +obj-$(CONFIG_VIRTIO_SERIAL) += virtio-serial-pci.o endif endif diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index c3e3791..b282109 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -19,7 +19,6 @@ #include "standard-headers/linux/virtio_pci.h" #include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-serial.h" #include "hw/pci/pci.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -1999,81 +1998,6 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) } } -/* virtio-serial-pci */ - -static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - DeviceState *proxy = DEVICE(vpci_dev); - char *bus_name; - - if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER && - vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */ - vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */ - vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER; - } - - /* backwards-compatibility with machines that were created with - DEV_NVECTORS_UNSPECIFIED */ - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1; - } - - /* - * For command line compatibility, this sets the virtio-serial-device bus - * name as before. - */ - if (proxy->id) { - bus_name = g_strdup_printf("%s.0", proxy->id); - virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); - g_free(bus_name); - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static Property virtio_serial_pci_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = virtio_serial_pci_realize; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - dc->props = virtio_serial_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; -} - -static void virtio_serial_pci_instance_init(Object *obj) -{ - VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_SERIAL); -} - -static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = { - .base_name = TYPE_VIRTIO_SERIAL_PCI, - .generic_name = "virtio-serial-pci", - .transitional_name = "virtio-serial-pci-transitional", - .non_transitional_name = "virtio-serial-pci-non-transitional", - .instance_size = sizeof(VirtIOSerialPCI), - .instance_init = virtio_serial_pci_instance_init, - .class_init = virtio_serial_pci_class_init, -}; - /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -2124,9 +2048,6 @@ static void virtio_pci_register_types(void) /* Base types: */ type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); - - /* Implementations: */ - virtio_pci_types_register(&virtio_serial_pci_info); } type_init(virtio_pci_register_types) diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 8bfd4b9..d4491e2 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -16,13 +16,11 @@ #define QEMU_VIRTIO_PCI_H #include "hw/pci/msi.h" -#include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; -typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -182,18 +180,6 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) } /* - * virtio-serial-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base" -#define VIRTIO_SERIAL_PCI(obj) \ - OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI) - -struct VirtIOSerialPCI { - VirtIOPCIProxy parent_obj; - VirtIOSerial vdev; -}; - -/* * virtio-input-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c new file mode 100644 index 0000000..971b2eb --- /dev/null +++ b/hw/virtio/virtio-serial-pci.c @@ -0,0 +1,115 @@ +/* + * Virtio serial PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori + * Paul Brook + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-serial.h" +#include "virtio-pci.h" + +typedef struct VirtIOSerialPCI VirtIOSerialPCI; + +/* + * virtio-serial-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base" +#define VIRTIO_SERIAL_PCI(obj) \ + OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI) + +struct VirtIOSerialPCI { + VirtIOPCIProxy parent_obj; + VirtIOSerial vdev; +}; + +static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + DeviceState *proxy = DEVICE(vpci_dev); + char *bus_name; + + if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER && + vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */ + vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */ + vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER; + } + + /* backwards-compatibility with machines that were created with + DEV_NVECTORS_UNSPECIFIED */ + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1; + } + + /* + * For command line compatibility, this sets the virtio-serial-device bus + * name as before. + */ + if (proxy->id) { + bus_name = g_strdup_printf("%s.0", proxy->id); + virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); + g_free(bus_name); + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static Property virtio_serial_pci_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = virtio_serial_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + dc->props = virtio_serial_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void virtio_serial_pci_instance_init(Object *obj) +{ + VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); +} + +static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = { + .base_name = TYPE_VIRTIO_SERIAL_PCI, + .generic_name = "virtio-serial-pci", + .transitional_name = "virtio-serial-pci-transitional", + .non_transitional_name = "virtio-serial-pci-non-transitional", + .instance_size = sizeof(VirtIOSerialPCI), + .instance_init = virtio_serial_pci_instance_init, + .class_init = virtio_serial_pci_class_init, +}; + +static void virtio_serial_pci_register(void) +{ + virtio_pci_types_register(&virtio_serial_pci_info); +} + +type_init(virtio_serial_pci_register) diff --git a/tests/Makefile.include b/tests/Makefile.include index 590ee0c..aa68eb5 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -108,7 +108,7 @@ check-unit-y += tests/test-crypto-secret$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF) ifneq (,$(findstring qemu-ga,$(TOOLS))) -check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF) +check-unit-$(land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) endif check-unit-y += tests/test-timed-average$(EXESUF) check-unit-y += tests/test-util-sockets$(EXESUF) @@ -144,7 +144,7 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF) check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF) -check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) +check-qtest-virtioserial-$(CONFIG_VIRTIO_SERIAL) += tests/virtio-console-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_NET) += tests/virtio-net-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF) @@ -154,7 +154,7 @@ check-qtest-virtio-$(CONFIG_VIRTIO_SCSI) += tests/virtio-scsi-test$(EXESUF) ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) check-qtest-virtio-$(CONFIG_VIRTIO_9P) += tests/virtio-9p-test$(EXESUF) endif -check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF) +check-qtest-virtio-$(CONFIG_VIRTIO_SERIAL) += tests/virtio-serial-test$(EXESUF) check-qtest-virtio-y += $(check-qtest-virtioserial-y) check-qtest-pci-y += tests/e1000-test$(EXESUF) -- cgit v1.1 From 7ecb381fcf514fd5e083eb3c9eab4eb557eba593 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:11 +0100 Subject: virtio: split virtio gpu bits from virtio-pci.h Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/display/virtio-gpu-pci.c | 14 ++++++++++++++ hw/display/virtio-vga.c | 1 + hw/virtio/virtio-pci.h | 14 -------------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index faf76a8..bdcd33c 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -19,6 +19,20 @@ #include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-gpu.h" +typedef struct VirtIOGPUPCI VirtIOGPUPCI; + +/* + * virtio-gpu-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" +#define VIRTIO_GPU_PCI(obj) \ + OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI) + +struct VirtIOGPUPCI { + VirtIOPCIProxy parent_obj; + VirtIOGPU vdev; +}; + static Property virtio_gpu_pci_properties[] = { DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 8db4d91..1e48009 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -3,6 +3,7 @@ #include "hw/pci/pci.h" #include "vga_int.h" #include "hw/virtio/virtio-pci.h" +#include "hw/virtio/virtio-gpu.h" #include "qapi/error.h" /* diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index d4491e2..2f76055 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -17,11 +17,9 @@ #include "hw/pci/msi.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-crypto.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; -typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; /* virtio-pci-bus */ @@ -185,18 +183,6 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" /* - * virtio-gpu-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" -#define VIRTIO_GPU_PCI(obj) \ - OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI) - -struct VirtIOGPUPCI { - VirtIOPCIProxy parent_obj; - VirtIOGPU vdev; -}; - -/* * virtio-crypto-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci" -- cgit v1.1 From 7c8681d0d694bc477e225de5ccb12e07ef07fd5a Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:12 +0100 Subject: virtio: split virtio crypto bits from virtio-pci.h Reviewed-by: Laurent Vivier Signed-off-by: Juan Quintela Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-crypto-pci.c | 14 ++++++++++++++ hw/virtio/virtio-pci.h | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index 8cc3fa3..90a6e0d 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -19,6 +19,20 @@ #include "hw/virtio/virtio-crypto.h" #include "qapi/error.h" +typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; + +/* + * virtio-crypto-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci" +#define VIRTIO_CRYPTO_PCI(obj) \ + OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI) + +struct VirtIOCryptoPCI { + VirtIOPCIProxy parent_obj; + VirtIOCrypto vdev; +}; + static Property virtio_crypto_pci_properties[] = { DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 2f76055..bd223a6 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -17,10 +17,8 @@ #include "hw/pci/msi.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-crypto.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; -typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; /* virtio-pci-bus */ @@ -182,18 +180,6 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) */ #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" -/* - * virtio-crypto-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci" -#define VIRTIO_CRYPTO_PCI(obj) \ - OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI) - -struct VirtIOCryptoPCI { - VirtIOPCIProxy parent_obj; - VirtIOCrypto vdev; -}; - /* Virtio ABI version, if we increment this, we break the guest driver. */ #define VIRTIO_PCI_ABI_VERSION 0 -- cgit v1.1 From ecd3b89b0549d6b82bed5e25a0a2fb153d5df4d4 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 3 Jan 2019 15:10:13 +0100 Subject: virtio: virtio 9p really requires CONFIG_VIRTFS to work Signed-off-by: Juan Quintela Reviewed-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- default-configs/virtio.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-configs/virtio.mak b/default-configs/virtio.mak index 5ae4a61..ecb4420 100644 --- a/default-configs/virtio.mak +++ b/default-configs/virtio.mak @@ -1,7 +1,7 @@ CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) CONFIG_VIRTIO=y -CONFIG_VIRTIO_9P=y +CONFIG_VIRTIO_9P=$(CONFIG_VIRTFS) CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_BLK=y CONFIG_VIRTIO_CRYPTO=y -- cgit v1.1 From d7741743f4f3d2683d1bb6938f88dc0167c21afa Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Jan 2019 16:04:57 -0200 Subject: globals: Allow global properties to be optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Making some global properties optional will let us simplify compat code when a given property works on most (but not all) subclasses of a given type. Device types will be able to opt out from optional compat properties by simply not registering those properties. Signed-off-by: Eduardo Habkost Reviewed-by: Cornelia Huck Reviewed-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/qdev-core.h | 3 +++ qom/object.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 9614f76..0a84c42 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -250,6 +250,8 @@ struct PropertyInfo { /** * GlobalProperty: * @used: Set to true if property was used when initializing a device. + * @optional: If set to true, GlobalProperty will be skipped without errors + * if the property doesn't exist. * * An error is fatal for non-hotplugged devices, when the global is applied. */ @@ -258,6 +260,7 @@ typedef struct GlobalProperty { const char *property; const char *value; bool used; + bool optional; } GlobalProperty; static inline void diff --git a/qom/object.c b/qom/object.c index 4e5226c..b8c7320 100644 --- a/qom/object.c +++ b/qom/object.c @@ -385,6 +385,9 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp if (object_dynamic_cast(obj, p->driver) == NULL) { continue; } + if (p->optional && !object_property_find(obj, p->property, NULL)) { + continue; + } p->used = true; object_property_parse(obj, p->value, p->property, &err); if (err != NULL) { -- cgit v1.1 From 53921bfdce3f8fffcc22338633855247fb7b7a74 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Jan 2019 16:04:58 -0200 Subject: virtio: Make disable-legacy/disable-modern compat properties optional The disable-legacy and disable-modern properties apply only to some virtio-pci devices. Make those properties optional. This fixes the crash introduced by commit f6e501a28ef9 ("virtio: Provide version-specific variants of virtio PCI devices"): $ qemu-system-x86_64 -machine pc-i440fx-2.6 \ -device virtio-net-pci-non-transitional Unexpected error in object_property_find() at qom/object.c:1092: qemu-system-x86_64: -device virtio-net-pci-non-transitional: can't apply \ global virtio-pci.disable-modern=on: Property '.disable-modern' not found Aborted (core dumped) Reported-by: Thomas Huth Fixes: f6e501a28ef9 ("virtio: Provide version-specific variants of virtio PCI devices") Signed-off-by: Eduardo Habkost Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/machine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 95dc7c3..f0c0ae6 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -91,8 +91,9 @@ const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7); GlobalProperty hw_compat_2_6[] = { { "virtio-mmio", "format_transport_address", "off" }, - { "virtio-pci", "disable-modern", "on" }, - { "virtio-pci", "disable-legacy", "off" }, + /* Optional because not all virtio-pci devices support legacy mode */ + { "virtio-pci", "disable-modern", "on", .optional = true }, + { "virtio-pci", "disable-legacy", "off", .optional = true }, }; const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6); -- cgit v1.1 From 812e710a9624a3bf3c8bb126ac546b683edb60d5 Mon Sep 17 00:00:00 2001 From: Fei Li Date: Mon, 14 Jan 2019 21:10:15 +0800 Subject: hw/misc/edu: add msi_uninit() for pci_edu_uninit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's supplement the msi_uninit() when failing to realize the pci edu device. Reported-by: Markus Armbruster Signed-off-by: Fei Li Reviewed-by: Marcel Apfelbaum Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/misc/edu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/misc/edu.c b/hw/misc/edu.c index cdcf550..ceaf688 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -377,6 +377,7 @@ static void pci_edu_uninit(PCIDevice *pdev) qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer); + msi_uninit(pdev); } static void edu_obj_uint64(Object *obj, Visitor *v, const char *name, -- cgit v1.1 From b6148757f9baa2de11304c09aaf9f9a276c825cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 15 Jan 2019 02:27:49 +0400 Subject: tpm: add a "ppi" boolean property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following patches implement the TPM Physical Presence Interface, make use of a new memory region and a fw_cfg entry. Enable PPI by default with >=4.0 machine type, to avoid migration issues. Signed-off-by: Marc-André Lureau Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Tested-by: Stefan Berger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/machine.c | 2 ++ hw/tpm/tpm_crb.c | 3 +++ hw/tpm/tpm_tis.c | 3 +++ 3 files changed, 8 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index f0c0ae6..2629515 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -28,6 +28,8 @@ GlobalProperty hw_compat_3_1[] = { { "pcie-root-port", "x-width", "1" }, { "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" }, { "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" }, + { "tpm-crb", "ppi", "false" }, + { "tpm-tis", "ppi", "false" }, }; const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1); diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index a92dd50..d5b0ac5 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -41,6 +41,8 @@ typedef struct CRBState { MemoryRegion cmdmem; size_t be_buffer_size; + + bool ppi_enabled; } CRBState; #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB) @@ -221,6 +223,7 @@ static const VMStateDescription vmstate_tpm_crb = { static Property tpm_crb_properties[] = { DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe), + DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 2563d75..1698d83 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -81,6 +81,8 @@ typedef struct TPMState { TPMVersion be_tpm_version; size_t be_buffer_size; + + bool ppi_enabled; } TPMState; #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) @@ -954,6 +956,7 @@ static const VMStateDescription vmstate_tpm_tis = { static Property tpm_tis_properties[] = { DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), + DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true), DEFINE_PROP_END_OF_LIST(), }; -- cgit v1.1 From 3b97c01e9ccdfbd517a0fd631838d6252dbfa692 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 15 Jan 2019 02:27:50 +0400 Subject: tpm: allocate/map buffer for TPM Physical Presence interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement a virtual memory device for the TPM Physical Presence interface. The memory is located at 0xFED45000 and used by ACPI to send messages to the firmware (BIOS) and by the firmware to provide parameters for each one of the supported codes. This interface should be used by all TPM devices on x86 and can be added by calling tpm_ppi_init_io(). Note: bios_linker cannot be used to allocate the PPI memory region, since the reserved memory should stay stable across reboots, and might be needed before the ACPI tables are installed. Signed-off-by: Stefan Berger Signed-off-by: Marc-André Lureau Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Tested-by: Stefan Berger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/tpm/Makefile.objs | 1 + hw/tpm/tpm_crb.c | 7 +++++++ hw/tpm/tpm_ppi.c | 31 +++++++++++++++++++++++++++++++ hw/tpm/tpm_ppi.h | 36 ++++++++++++++++++++++++++++++++++++ hw/tpm/tpm_tis.c | 7 +++++++ include/hw/acpi/tpm.h | 6 ++++++ 6 files changed, 88 insertions(+) create mode 100644 hw/tpm/tpm_ppi.c create mode 100644 hw/tpm/tpm_ppi.h diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 1dc9f8b..700c878 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,4 +1,5 @@ common-obj-y += tpm_util.o +obj-y += tpm_ppi.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index d5b0ac5..012ec68 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -29,6 +29,7 @@ #include "sysemu/reset.h" #include "tpm_int.h" #include "tpm_util.h" +#include "tpm_ppi.h" #include "trace.h" typedef struct CRBState { @@ -43,6 +44,7 @@ typedef struct CRBState { size_t be_buffer_size; bool ppi_enabled; + TPMPPI ppi; } CRBState; #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB) @@ -294,6 +296,11 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(get_system_memory(), TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem); + if (s->ppi_enabled) { + tpm_ppi_init(&s->ppi, get_system_memory(), + TPM_PPI_ADDR_BASE, OBJECT(s)); + } + qemu_register_reset(tpm_crb_reset, dev); } diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c new file mode 100644 index 0000000..cf17779 --- /dev/null +++ b/hw/tpm/tpm_ppi.c @@ -0,0 +1,31 @@ +/* + * tpm_ppi.c - TPM Physical Presence Interface + * + * Copyright (C) 2018 IBM Corporation + * + * Authors: + * Stefan Berger + * + * 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 "cpu.h" +#include "sysemu/memory_mapping.h" +#include "migration/vmstate.h" +#include "tpm_ppi.h" + +void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, + hwaddr addr, Object *obj) +{ + tpmppi->buf = g_malloc0(HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); + memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi", + TPM_PPI_ADDR_SIZE, tpmppi->buf); + vmstate_register_ram(&tpmppi->ram, DEVICE(obj)); + + memory_region_add_subregion(m, addr, &tpmppi->ram); +} diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h new file mode 100644 index 0000000..c5e555f --- /dev/null +++ b/hw/tpm/tpm_ppi.h @@ -0,0 +1,36 @@ +/* + * TPM Physical Presence Interface + * + * Copyright (C) 2018 IBM Corporation + * + * Authors: + * Stefan Berger + * + * 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 TPM_TPM_PPI_H +#define TPM_TPM_PPI_H + +#include "hw/acpi/tpm.h" +#include "exec/address-spaces.h" + +typedef struct TPMPPI { + MemoryRegion ram; + uint8_t *buf; +} TPMPPI; + +/** + * tpm_ppi_init: + * @tpmppi: a TPMPPI + * @m: the address-space / MemoryRegion to use + * @addr: the address of the PPI region + * @obj: the owner object + * + * Register the TPM PPI memory region at @addr on the given address + * space for the object @obj. + **/ +void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, + hwaddr addr, Object *obj); + +#endif /* TPM_TPM_PPI_H */ diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 1698d83..02d9d5c 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -31,6 +31,7 @@ #include "sysemu/tpm_backend.h" #include "tpm_int.h" #include "tpm_util.h" +#include "tpm_ppi.h" #include "trace.h" #define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ @@ -83,6 +84,7 @@ typedef struct TPMState { size_t be_buffer_size; bool ppi_enabled; + TPMPPI ppi; } TPMState; #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) @@ -983,6 +985,11 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), TPM_TIS_ADDR_BASE, &s->mmio); + + if (s->ppi_enabled) { + tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), + TPM_PPI_ADDR_BASE, OBJECT(s)); + } } static void tpm_tis_initfn(Object *obj) diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h index 3580ffd..b8796df 100644 --- a/include/hw/acpi/tpm.h +++ b/include/hw/acpi/tpm.h @@ -188,4 +188,10 @@ REG32(CRB_DATA_BUFFER, 0x80) #define TPM2_START_METHOD_MMIO 6 #define TPM2_START_METHOD_CRB 7 +/* + * Physical Presence Interface + */ +#define TPM_PPI_ADDR_SIZE 0x400 +#define TPM_PPI_ADDR_BASE 0xFED45000 + #endif /* HW_ACPI_TPM_H */ -- cgit v1.1 From 0fe246690315335a40a132f05cb6fdc7bfb9adca Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 15 Jan 2019 02:27:51 +0400 Subject: acpi: expose TPM/PPI configuration parameters to firmware via fw_cfg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid having to hard code the base address of the PPI virtual memory device we introduce a fw_cfg file etc/tpm/config that holds the base address of the PPI device, the version of the PPI interface and the version of the attached TPM. Signed-off-by: Stefan Berger [ Marc-André: renamed to etc/tpm/config, made it static, document it ] Signed-off-by: Marc-André Lureau Acked-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Tested-by: Stefan Berger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/tpm.txt | 19 +++++++++++++++++++ hw/i386/acpi-build.c | 19 +++++++++++++++++++ include/hw/acpi/tpm.h | 3 +++ 3 files changed, 41 insertions(+) diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt index 1af82bb..e4bb094 100644 --- a/docs/specs/tpm.txt +++ b/docs/specs/tpm.txt @@ -34,6 +34,25 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 - QEMU files related to TPM CRB interface: - hw/tpm/tpm_crb.c += fw_cfg interface = + +The bios/firmware may read the "etc/tpm/config" fw_cfg entry for +configuring the guest appropriately. + +The entry of 6 bytes has the following content, in little-endian: + + #define TPM_VERSION_UNSPEC 0 + #define TPM_VERSION_1_2 1 + #define TPM_VERSION_2_0 2 + + #define TPM_PPI_VERSION_NONE 0 + #define TPM_PPI_VERSION_1_30 1 + + struct FwCfgTPMConfig { + uint32_t tpmppi_address; /* PPI memory location */ + uint8_t tpm_version; /* TPM version */ + uint8_t tpmppi_version; /* PPI version */ + }; = ACPI Interface = diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 14f757f..9898247 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef struct FwCfgTPMConfig { + uint32_t tpmppi_address; + uint8_t tpm_version; + uint8_t tpmppi_version; +} QEMU_PACKED FwCfgTPMConfig; + static void init_common_fadt_data(Object *o, AcpiFadtData *data) { uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL); @@ -2847,6 +2853,8 @@ void acpi_setup(void) AcpiBuildTables tables; AcpiBuildState *build_state; Object *vmgenid_dev; + TPMIf *tpm; + static FwCfgTPMConfig tpm_config; if (!pcms->fw_cfg) { ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); @@ -2881,6 +2889,17 @@ void acpi_setup(void) fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, acpi_data_len(tables.tcpalog)); + tpm = tpm_find(); + if (tpm && object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) { + tpm_config = (FwCfgTPMConfig) { + .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE), + .tpm_version = tpm_get_version(tpm), + .tpmppi_version = TPM_PPI_VERSION_NONE + }; + fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config", + &tpm_config, sizeof tpm_config); + } + vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg, diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h index b8796df..a6109a9 100644 --- a/include/hw/acpi/tpm.h +++ b/include/hw/acpi/tpm.h @@ -194,4 +194,7 @@ REG32(CRB_DATA_BUFFER, 0x80) #define TPM_PPI_ADDR_SIZE 0x400 #define TPM_PPI_ADDR_BASE 0xFED45000 +#define TPM_PPI_VERSION_NONE 0 +#define TPM_PPI_VERSION_1_30 1 + #endif /* HW_ACPI_TPM_H */ -- cgit v1.1 From ac6dd31e3fe7e19be6fcaa7bf2396780b355137d Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 15 Jan 2019 02:27:52 +0400 Subject: acpi: build TPM Physical Presence interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TPM Physical Presence interface consists of an ACPI part, a shared memory part, and code in the firmware. Users can send messages to the firmware by writing a code into the shared memory through invoking the ACPI code. When a reboot happens, the firmware looks for the code and acts on it by sending sequences of commands to the TPM. This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't assume that SMIs are necessary to use. It uses a similar datastructure for the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use of it. I extended the shared memory data structure with an array of 256 bytes, one for each code that could be implemented. The array contains flags describing the individual codes. This decouples the ACPI implementation from the firmware implementation. The underlying TCG specification is accessible from the following page. https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/ This patch implements version 1.30. Signed-off-by: Stefan Berger [ Marc-André - ACPI code improvements and windows fixes ] Signed-off-by: Marc-André Lureau Acked-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Tested-by: Stefan Berger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/tpm.txt | 83 +++++++++++ hw/acpi/Makefile.objs | 1 + hw/acpi/tpm.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 12 +- include/hw/acpi/tpm.h | 12 ++ stubs/tpm.c | 5 + 6 files changed, 514 insertions(+), 3 deletions(-) create mode 100644 hw/acpi/tpm.c diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt index e4bb094..424d151 100644 --- a/docs/specs/tpm.txt +++ b/docs/specs/tpm.txt @@ -76,6 +76,89 @@ URL: https://trustedcomputinggroup.org/tcg-acpi-specification/ +== ACPI PPI Interface == + +QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and TPM 2. This +interface requires ACPI and firmware support. The specification can be found at +the following URL: + +https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ + +PPI enables a system administrator (root) to request a modification to the +TPM upon reboot. The PPI specification defines the operation requests and the +actions the firmware has to take. The system administrator passes the operation +request number to the firmware through an ACPI interface which writes this +number to a memory location that the firmware knows. Upon reboot, the firmware +finds the number and sends commands to the the TPM. The firmware writes the TPM +result code and the operation request number to a memory location that ACPI can +read from and pass the result on to the administrator. + +The PPI specification defines a set of mandatory and optional operations for +the firmware to implement. The ACPI interface also allows an administrator to +list the supported operations. In QEMU the ACPI code is generated by QEMU, yet +the firmware needs to implement support on a per-operations basis, and +different firmwares may support a different subset. Therefore, QEMU introduces +the virtual memory device for PPI where the firmware can indicate which +operations it supports and ACPI can enable the ones that are supported and +disable all others. This interface lies in main memory and has the following +layout: + + +----------+--------+--------+-------------------------------------------+ + | Field | Length | Offset | Description | + +----------+--------+--------+-------------------------------------------+ + | func | 0x100 | 0x000 | Firmware sets values for each supported | + | | | | operation. See defined values below. | + +----------+--------+--------+-------------------------------------------+ + | ppin | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | + | | | | Not supported. | + +----------+--------+--------+-------------------------------------------+ + | ppip | 0x4 | 0x101 | ACPI function index to pass to SMM code. | + | | | | Set by ACPI. Not supported. | + +----------+--------+--------+-------------------------------------------+ + | pprp | 0x4 | 0x105 | Result of last executed operation. Set by | + | | | | firmware. See function index 5 for values.| + +----------+--------+--------+-------------------------------------------+ + | pprq | 0x4 | 0x109 | Operation request number to execute. See | + | | | | 'Physical Presence Interface Operation | + | | | | Summary' tables in specs. Set by ACPI. | + +----------+--------+--------+-------------------------------------------+ + | pprm | 0x4 | 0x10d | Operation request optional parameter. | + | | | | Values depend on operation. Set by ACPI. | + +----------+--------+--------+-------------------------------------------+ + | lppr | 0x4 | 0x111 | Last executed operation request number. | + | | | | Copied from pprq field by firmware. | + +----------+--------+--------+-------------------------------------------+ + | fret | 0x4 | 0x115 | Result code from SMM function. | + | | | | Not supported. | + +----------+--------+--------+-------------------------------------------+ + | res1 | 0x40 | 0x119 | Reserved for future use | + +----------+--------+--------+-------------------------------------------+ + | next_step| 0x1 | 0x159 | Operation to execute after reboot by | + | | | | firmware. Used by firmware. | + +----------+--------+--------+-------------------------------------------+ + + The following values are supported for the 'func' field. They correspond + to the values used by ACPI function index 8. + + +----------+-------------------------------------------------------------+ + | value | Description | + +----------+-------------------------------------------------------------+ + | 0 | Operation is not implemented. | + +----------+-------------------------------------------------------------+ + | 1 | Operation is only accessible through firmware. | + +----------+-------------------------------------------------------------+ + | 2 | Operation is blocked for OS by firmware configuration. | + +----------+-------------------------------------------------------------+ + | 3 | Operation is allowed and physically present user required. | + +----------+-------------------------------------------------------------+ + | 4 | Operation is allowed and physically present user is not | + | | required. | + +----------+-------------------------------------------------------------+ + +The location of the table is given by the fw_cfg tpmppi_address field. +The PPI memory region size is 0x400 (TPM_PPI_ADDR_SIZE) to leave +enough room for future updates. + QEMU files related to TPM ACPI tables: - hw/i386/acpi-build.c diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 11c35bc..2d46e37 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -11,6 +11,7 @@ common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o common-obj-y += acpi_interface.o common-obj-y += bios-linker-loader.o common-obj-y += aml-build.o +common-obj-$(CONFIG_TPM) += tpm.o common-obj-$(CONFIG_IPMI) += ipmi.o common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o diff --git a/hw/acpi/tpm.c b/hw/acpi/tpm.c new file mode 100644 index 0000000..9f20537 --- /dev/null +++ b/hw/acpi/tpm.c @@ -0,0 +1,404 @@ +/* Support for generating ACPI TPM tables + * + * Copyright (C) 2018 IBM, Corp. + * Copyright (C) 2018 Red Hat Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/acpi/tpm.h" + +void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev) +{ + Aml *method, *field, *ifctx, *ifctx2, *ifctx3, *func_mask, + *not_implemented, *pak, *tpm2, *tpm3, *pprm, *pprq, *zero, *one; + + if (!object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) { + return; + } + + zero = aml_int(0); + one = aml_int(1); + func_mask = aml_int(TPM_PPI_FUNC_MASK); + not_implemented = aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED); + + /* + * TPP2 is for the registers that ACPI code used to pass + * the PPI code and parameter (PPRQ, PPRM) to the firmware. + */ + aml_append(dev, + aml_operation_region("TPP2", AML_SYSTEM_MEMORY, + aml_int(TPM_PPI_ADDR_BASE + 0x100), + 0x5A)); + field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("PPIN", 8)); + aml_append(field, aml_named_field("PPIP", 32)); + aml_append(field, aml_named_field("PPRP", 32)); + aml_append(field, aml_named_field("PPRQ", 32)); + aml_append(field, aml_named_field("PPRM", 32)); + aml_append(field, aml_named_field("LPPR", 32)); + aml_append(dev, field); + pprq = aml_name("PPRQ"); + pprm = aml_name("PPRM"); + + /* + * DerefOf in Windows is broken with SYSTEM_MEMORY. Use a dynamic + * operation region inside of a method for getting FUNC[op]. + */ + method = aml_method("TPFN", 1, AML_SERIALIZED); + { + Aml *op = aml_arg(0); + ifctx = aml_if(aml_lgreater_equal(op, aml_int(0x100))); + { + aml_append(ifctx, aml_return(zero)); + } + aml_append(method, ifctx); + + aml_append(method, + aml_operation_region("TPP1", AML_SYSTEM_MEMORY, + aml_add(aml_int(TPM_PPI_ADDR_BASE), op, NULL), 0x1)); + field = aml_field("TPP1", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("TPPF", 8)); + aml_append(method, field); + aml_append(method, aml_return(aml_name("TPPF"))); + } + aml_append(dev, method); + + /* + * Use global TPM2 & TPM3 variables to workaround Windows ACPI bug + * when returning packages. + */ + pak = aml_package(2); + aml_append(pak, zero); + aml_append(pak, zero); + aml_append(dev, aml_name_decl("TPM2", pak)); + tpm2 = aml_name("TPM2"); + + pak = aml_package(3); + aml_append(pak, zero); + aml_append(pak, zero); + aml_append(pak, zero); + aml_append(dev, aml_name_decl("TPM3", pak)); + tpm3 = aml_name("TPM3"); + + method = aml_method("_DSM", 4, AML_SERIALIZED); + { + uint8_t zerobyte[1] = { 0 }; + Aml *function, *arguments, *rev, *op, *op_arg, *op_flags, *uuid; + + uuid = aml_arg(0); + rev = aml_arg(1); + function = aml_arg(2); + arguments = aml_arg(3); + op = aml_local(0); + op_flags = aml_local(1); + + /* Physical Presence Interface */ + ifctx = aml_if( + aml_equal(uuid, + aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653"))); + { + /* standard DSM query function */ + ifctx2 = aml_if(aml_equal(function, zero)); + { + uint8_t byte_list[2] = { 0xff, 0x01 }; /* functions 1-8 */ + + aml_append(ifctx2, + aml_return(aml_buffer(sizeof(byte_list), + byte_list))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.1 Get Physical Presence Interface Version + * + * Arg 2 (Integer): Function Index = 1 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: String + */ + ifctx2 = aml_if(aml_equal(function, one)); + { + aml_append(ifctx2, aml_return(aml_string("1.3"))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.3 Submit TPM Operation Request to Pre-OS Environment + * + * Arg 2 (Integer): Function Index = 2 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Operation Value of the Request + * Returns: Type: Integer + * 0: Success + * 1: Operation Value of the Request Not Supported + * 2: General Failure + */ + ifctx2 = aml_if(aml_equal(function, aml_int(2))); + { + /* get opcode */ + aml_append(ifctx2, + aml_store(aml_derefof(aml_index(arguments, + zero)), op)); + + /* get opcode flags */ + aml_append(ifctx2, + aml_store(aml_call1("TPFN", op), op_flags)); + + /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */ + ifctx3 = aml_if( + aml_equal( + aml_and(op_flags, func_mask, NULL), + not_implemented)); + { + /* 1: Operation Value of the Request Not Supported */ + aml_append(ifctx3, aml_return(one)); + } + aml_append(ifctx2, ifctx3); + + aml_append(ifctx2, aml_store(op, pprq)); + aml_append(ifctx2, aml_store(zero, pprm)); + /* 0: success */ + aml_append(ifctx2, aml_return(zero)); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.4 Get Pending TPM Operation Requested By the OS + * + * Arg 2 (Integer): Function Index = 3 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: Package of Integers + * Integer 1: Function Return code + * 0: Success + * 1: General Failure + * Integer 2: Pending operation requested by the OS + * 0: None + * >0: Operation Value of the Pending Request + * Integer 3: Optional argument to pending operation + * requested by the OS + * 0: None + * >0: Argument Value of the Pending Request + */ + ifctx2 = aml_if(aml_equal(function, aml_int(3))); + { + /* + * Revision ID of 1, no integer parameter beyond + * parameter two are expected + */ + ifctx3 = aml_if(aml_equal(rev, one)); + { + /* TPM2[1] = PPRQ */ + aml_append(ifctx3, + aml_store(pprq, aml_index(tpm2, one))); + aml_append(ifctx3, aml_return(tpm2)); + } + aml_append(ifctx2, ifctx3); + + /* + * A return value of {0, 23, 1} indicates that + * operation 23 with argument 1 is pending. + */ + ifctx3 = aml_if(aml_equal(rev, aml_int(2))); + { + /* TPM3[1] = PPRQ */ + aml_append(ifctx3, + aml_store(pprq, aml_index(tpm3, one))); + /* TPM3[2] = PPRM */ + aml_append(ifctx3, + aml_store(pprm, aml_index(tpm3, aml_int(2)))); + aml_append(ifctx3, aml_return(tpm3)); + } + aml_append(ifctx2, ifctx3); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.5 Get Platform-Specific Action to Transition to + * Pre-OS Environment + * + * Arg 2 (Integer): Function Index = 4 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: Integer + * 0: None + * 1: Shutdown + * 2: Reboot + * 3: OS Vendor-specific + */ + ifctx2 = aml_if(aml_equal(function, aml_int(4))); + { + /* reboot */ + aml_append(ifctx2, aml_return(aml_int(2))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.6 Return TPM Operation Response to OS Environment + * + * Arg 2 (Integer): Function Index = 5 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: Package of Integer + * Integer 1: Function Return code + * 0: Success + * 1: General Failure + * Integer 2: Most recent operation request + * 0: None + * >0: Operation Value of the most recent request + * Integer 3: Response to the most recent operation request + * 0: Success + * 0x00000001..0x00000FFF: Corresponding TPM + * error code + * 0xFFFFFFF0: User Abort or timeout of dialog + * 0xFFFFFFF1: firmware Failure + */ + ifctx2 = aml_if(aml_equal(function, aml_int(5))); + { + /* TPM3[1] = LPPR */ + aml_append(ifctx2, + aml_store(aml_name("LPPR"), + aml_index(tpm3, one))); + /* TPM3[2] = PPRP */ + aml_append(ifctx2, + aml_store(aml_name("PPRP"), + aml_index(tpm3, aml_int(2)))); + aml_append(ifctx2, aml_return(tpm3)); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.7 Submit preferred user language + * + * Arg 2 (Integer): Function Index = 6 + * Arg 3 (Package): Arguments = String Package + * Preferred language code + * Returns: Type: Integer + * Function Return Code + * 3: Not implemented + */ + ifctx2 = aml_if(aml_equal(function, aml_int(6))); + { + /* 3 = not implemented */ + aml_append(ifctx2, aml_return(aml_int(3))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.1: 2.1.7 Submit TPM Operation Request to + * Pre-OS Environment 2 + * + * Arg 2 (Integer): Function Index = 7 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Integer 1: Operation Value of the Request + * Integer 2: Argument for Operation (optional) + * Returns: Type: Integer + * 0: Success + * 1: Not Implemented + * 2: General Failure + * 3: Operation blocked by current firmware settings + */ + ifctx2 = aml_if(aml_equal(function, aml_int(7))); + { + /* get opcode */ + aml_append(ifctx2, aml_store(aml_derefof(aml_index(arguments, + zero)), + op)); + + /* get opcode flags */ + aml_append(ifctx2, aml_store(aml_call1("TPFN", op), + op_flags)); + /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */ + ifctx3 = aml_if( + aml_equal( + aml_and(op_flags, func_mask, NULL), + not_implemented)); + { + /* 1: not implemented */ + aml_append(ifctx3, aml_return(one)); + } + aml_append(ifctx2, ifctx3); + + /* if func[opcode] & TPM_PPI_FUNC_BLOCKED */ + ifctx3 = aml_if( + aml_equal( + aml_and(op_flags, func_mask, NULL), + aml_int(TPM_PPI_FUNC_BLOCKED))); + { + /* 3: blocked by firmware */ + aml_append(ifctx3, aml_return(aml_int(3))); + } + aml_append(ifctx2, ifctx3); + + /* revision to integer */ + ifctx3 = aml_if(aml_equal(rev, one)); + { + /* revision 1 */ + /* PPRQ = op */ + aml_append(ifctx3, aml_store(op, pprq)); + /* no argument, PPRM = 0 */ + aml_append(ifctx3, aml_store(zero, pprm)); + } + aml_append(ifctx2, ifctx3); + + ifctx3 = aml_if(aml_equal(rev, aml_int(2))); + { + /* revision 2 */ + /* PPRQ = op */ + op_arg = aml_derefof(aml_index(arguments, one)); + aml_append(ifctx3, aml_store(op, pprq)); + /* PPRM = arg3[1] */ + aml_append(ifctx3, aml_store(op_arg, pprm)); + } + aml_append(ifctx2, ifctx3); + /* 0: success */ + aml_append(ifctx2, aml_return(zero)); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.1: 2.1.8 Get User Confirmation Status for Operation + * + * Arg 2 (Integer): Function Index = 8 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Operation Value that may need user confirmation + * Returns: Type: Integer + * 0: Not implemented + * 1: Firmware only + * 2: Blocked for OS by firmware configuration + * 3: Allowed and physically present user required + * 4: Allowed and physically present user not required + */ + ifctx2 = aml_if(aml_equal(function, aml_int(8))); + { + /* get opcode */ + aml_append(ifctx2, + aml_store(aml_derefof(aml_index(arguments, + zero)), + op)); + + /* get opcode flags */ + aml_append(ifctx2, aml_store(aml_call1("TPFN", op), + op_flags)); + /* return confirmation status code */ + aml_append(ifctx2, + aml_return( + aml_and(op_flags, func_mask, NULL))); + } + aml_append(ifctx, ifctx2); + + aml_append(ifctx, aml_return(aml_buffer(1, zerobyte))); + } + aml_append(method, ifctx); + } + aml_append(dev, method); +} diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 9898247..2e21a31 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1802,6 +1802,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, uint32_t nr_mem = machine->ram_slots; int root_bus_limit = 0xFF; PCIBus *bus = NULL; + TPMIf *tpm = tpm_find(); int i; dsdt = init_aml_allocator(); @@ -2139,7 +2140,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, /* Scan all PCI buses. Generate tables to support hotplug. */ build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); - if (TPM_IS_TIS(tpm_find())) { + if (TPM_IS_TIS(tpm)) { dev = aml_device("ISA.TPM"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); @@ -2153,6 +2154,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, */ /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */ aml_append(dev, aml_name_decl("_CRS", crs)); + + tpm_build_ppi_acpi(tpm, dev); + aml_append(scope, dev); } @@ -2160,7 +2164,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } } - if (TPM_IS_CRB(tpm_find())) { + if (TPM_IS_CRB(tpm)) { dev = aml_device("TPM"); aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); crs = aml_resource_template(); @@ -2172,6 +2176,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(method, aml_return(aml_int(0x0f))); aml_append(dev, method); + tpm_build_ppi_acpi(tpm, dev); + aml_append(sb_scope, dev); } @@ -2894,7 +2900,7 @@ void acpi_setup(void) tpm_config = (FwCfgTPMConfig) { .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE), .tpm_version = tpm_get_version(tpm), - .tpmppi_version = TPM_PPI_VERSION_NONE + .tpmppi_version = TPM_PPI_VERSION_1_30 }; fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config", &tpm_config, sizeof tpm_config); diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h index a6109a9..1a2a57a 100644 --- a/include/hw/acpi/tpm.h +++ b/include/hw/acpi/tpm.h @@ -18,6 +18,8 @@ #include "qemu/units.h" #include "hw/registerfields.h" +#include "hw/acpi/aml-build.h" +#include "sysemu/tpm.h" #define TPM_TIS_ADDR_BASE 0xFED40000 #define TPM_TIS_ADDR_SIZE 0x5000 @@ -197,4 +199,14 @@ REG32(CRB_DATA_BUFFER, 0x80) #define TPM_PPI_VERSION_NONE 0 #define TPM_PPI_VERSION_1_30 1 +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */ +#define TPM_PPI_FUNC_NOT_IMPLEMENTED (0 << 0) +#define TPM_PPI_FUNC_BIOS_ONLY (1 << 0) +#define TPM_PPI_FUNC_BLOCKED (2 << 0) +#define TPM_PPI_FUNC_ALLOWED_USR_REQ (3 << 0) +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0) +#define TPM_PPI_FUNC_MASK (7 << 0) + +void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev); + #endif /* HW_ACPI_TPM_H */ diff --git a/stubs/tpm.c b/stubs/tpm.c index 80939cd..66c99d6 100644 --- a/stubs/tpm.c +++ b/stubs/tpm.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qapi/qapi-commands-tpm.h" #include "sysemu/tpm.h" +#include "hw/acpi/tpm.h" void tpm_init(void) { @@ -31,3 +32,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp) { return NULL; } + +void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev) +{ +} -- cgit v1.1 From ec86c0f678a9402fb4265c8874bd2ec712b33127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 15 Jan 2019 02:27:53 +0400 Subject: acpi: add ACPI memory clear interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface is described in the "TCG Platform Reset Attack Mitigation Specification", chapter 6 "ACPI _DSM Function". According to Laszlo, it's not so easy to implement in OVMF, he suggested to do it in qemu instead. See specification documentation for more details, and next commit for memory clear on reset handling. The underlying TCG specification is accessible from the following page. https://trustedcomputinggroup.org/resource/pc-client-work-group-platform-reset-attack-mitigation-specification-version-1-0/ This patch implements version 1.0. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov Tested-by: Stefan Berger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/tpm.txt | 2 ++ hw/acpi/tpm.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt index 424d151..5d8c26b 100644 --- a/docs/specs/tpm.txt +++ b/docs/specs/tpm.txt @@ -136,6 +136,8 @@ layout: | next_step| 0x1 | 0x159 | Operation to execute after reboot by | | | | | firmware. Used by firmware. | +----------+--------+--------+-------------------------------------------+ + | movv | 0x1 | 0x15a | Memory overwrite variable | + +----------+--------+--------+-------------------------------------------+ The following values are supported for the 'func' field. They correspond to the values used by ACPI function index 8. diff --git a/hw/acpi/tpm.c b/hw/acpi/tpm.c index 9f20537..b96459e 100644 --- a/hw/acpi/tpm.c +++ b/hw/acpi/tpm.c @@ -53,6 +53,16 @@ void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev) pprq = aml_name("PPRQ"); pprm = aml_name("PPRM"); + aml_append(dev, + aml_operation_region( + "TPP3", AML_SYSTEM_MEMORY, + aml_int(TPM_PPI_ADDR_BASE + + 0x15a /* movv, docs/specs/tpm.txt */), + 0x1)); + field = aml_field("TPP3", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("MOVV", 8)); + aml_append(dev, field); + /* * DerefOf in Windows is broken with SYSTEM_MEMORY. Use a dynamic * operation region inside of a method for getting FUNC[op]. @@ -399,6 +409,51 @@ void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev) aml_append(ifctx, aml_return(aml_buffer(1, zerobyte))); } aml_append(method, ifctx); + + /* + * "TCG Platform Reset Attack Mitigation Specification 1.00", + * Chapter 6 "ACPI _DSM Function" + */ + ifctx = aml_if( + aml_equal(uuid, + aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D"))); + { + /* standard DSM query function */ + ifctx2 = aml_if(aml_equal(function, zero)); + { + uint8_t byte_list[1] = { 0x03 }; /* functions 1-2 supported */ + + aml_append(ifctx2, + aml_return(aml_buffer(sizeof(byte_list), + byte_list))); + } + aml_append(ifctx, ifctx2); + + /* + * TCG Platform Reset Attack Mitigation Specification 1.0 Ch.6 + * + * Arg 2 (Integer): Function Index = 1 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Operation Value of the Request + * Returns: Type: Integer + * 0: Success + * 1: General Failure + */ + ifctx2 = aml_if(aml_equal(function, one)); + { + aml_append(ifctx2, + aml_store(aml_derefof(aml_index(arguments, zero)), + op)); + { + aml_append(ifctx2, aml_store(op, aml_name("MOVV"))); + + /* 0: success */ + aml_append(ifctx2, aml_return(zero)); + } + } + aml_append(ifctx, ifctx2); + } + aml_append(method, ifctx); } aml_append(dev, method); } -- cgit v1.1 From ffab1be70692c55f4c81642f03d629fd84eb4b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 15 Jan 2019 02:27:54 +0400 Subject: tpm: clear RAM when "memory overwrite" requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: the "Platform Reset Attack Mitigation" specification isn't explicit about NVDIMM, since they could have different usages. It uses the term "system memory" generally (and also "volatile memory RAM" in its introduction). For initial support, I propose to consider non-volatile memory as not being subject to the memory clear. There is an on-going discussion in the TCG "pcclientwg" working group for future revisions. CPU cache clearing is done unconditionally in edk2 since commit d20ae95a13e851 (edk2-stable201811). Signed-off-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Tested-by: Stefan Berger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/tpm/tpm_crb.c | 3 +++ hw/tpm/tpm_ppi.c | 22 ++++++++++++++++++++++ hw/tpm/tpm_ppi.h | 10 ++++++++++ hw/tpm/tpm_tis.c | 3 +++ hw/tpm/trace-events | 3 +++ 5 files changed, 41 insertions(+) diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 012ec68..3087acc 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -233,6 +233,9 @@ static void tpm_crb_reset(void *dev) { CRBState *s = CRB(dev); + if (s->ppi_enabled) { + tpm_ppi_reset(&s->ppi); + } tpm_backend_reset(s->tpmbe); memset(s->regs, 0, sizeof(s->regs)); diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c index cf17779..cd8205f 100644 --- a/hw/tpm/tpm_ppi.c +++ b/hw/tpm/tpm_ppi.c @@ -16,8 +16,30 @@ #include "qapi/error.h" #include "cpu.h" #include "sysemu/memory_mapping.h" +#include "sysemu/reset.h" #include "migration/vmstate.h" #include "tpm_ppi.h" +#include "trace.h" + +void tpm_ppi_reset(TPMPPI *tpmppi) +{ + if (tpmppi->buf[0x15a /* movv, docs/specs/tpm.txt */] & 0x1) { + GuestPhysBlockList guest_phys_blocks; + GuestPhysBlock *block; + + guest_phys_blocks_init(&guest_phys_blocks); + guest_phys_blocks_append(&guest_phys_blocks); + QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) { + trace_tpm_ppi_memset(block->host_addr, + block->target_end - block->target_start); + memset(block->host_addr, 0, + block->target_end - block->target_start); + memory_region_set_dirty(block->mr, 0, + block->target_end - block->target_start); + } + guest_phys_blocks_free(&guest_phys_blocks); + } +} void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, hwaddr addr, Object *obj) diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h index c5e555f..d33ef27 100644 --- a/hw/tpm/tpm_ppi.h +++ b/hw/tpm/tpm_ppi.h @@ -33,4 +33,14 @@ typedef struct TPMPPI { void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, hwaddr addr, Object *obj); +/** + * tpm_ppi_reset: + * @tpmppi: a TPMPPI + * + * Function to call on machine reset. It will check if the "Memory + * overwrite" variable is set, and perform a memory clear on volatile + * memory if requested. + **/ +void tpm_ppi_reset(TPMPPI *tpmppi); + #endif /* TPM_TPM_PPI_H */ diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 02d9d5c..fd6bb9b 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -872,6 +872,9 @@ static void tpm_tis_reset(DeviceState *dev) s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), TPM_TIS_BUFFER_MAX); + if (s->ppi_enabled) { + tpm_ppi_reset(&s->ppi); + } tpm_backend_reset(s->be_driver); s->active_locty = TPM_TIS_NO_LOCALITY; diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events index 25bee0c..920d32a 100644 --- a/hw/tpm/trace-events +++ b/hw/tpm/trace-events @@ -51,3 +51,6 @@ tpm_tis_mmio_write_init_abort(void) "Initiating abort" tpm_tis_mmio_write_lowering_irq(void) "Lowering IRQ" tpm_tis_mmio_write_data2send(uint32_t value, unsigned size) "Data to send to TPM: 0x%08x (size=%d)" tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" + +# hw/tpm/tpm_ppi.c +tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" -- cgit v1.1 From e674132ae759c182d46b2e2d4cb9390d145eb6f5 Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Mon, 5 Nov 2018 02:40:39 +0100 Subject: hw: acpi: Fix memory hotplug AML generation error When using the generated memory hotplug AML, the iasl compiler would give the following error: dsdt.dsl 266: Return (MOST (_UID, Arg0, Arg1, Arg2)) Error 6080 - Called method returns no value ^ Signed-off-by: Yang Zhong Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/memory_hotplug.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 8c7c101..921cad2 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -686,15 +686,15 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, method = aml_method("_OST", 3, AML_NOTSERIALIZED); s = MEMORY_SLOT_OST_METHOD; - aml_append(method, aml_return(aml_call4( - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) - ))); + aml_append(method, + aml_call4(s, aml_name("_UID"), aml_arg(0), + aml_arg(1), aml_arg(2))); aml_append(dev, method); method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); s = MEMORY_SLOT_EJECT_METHOD; - aml_append(method, aml_return(aml_call2( - s, aml_name("_UID"), aml_arg(0)))); + aml_append(method, + aml_call2(s, aml_name("_UID"), aml_arg(0))); aml_append(dev, method); aml_append(dev_container, dev); -- cgit v1.1 From 31cf4b977319001238f24a4e0513835a2d19191f Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 14 Jan 2019 19:29:32 -0500 Subject: acpi: update expected files Update expected files affected by: hw: acpi: Fix memory hotplug AML generation error Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/DSDT.dimmpxm | Bin 6790 -> 6784 bytes tests/data/acpi/pc/DSDT.memhp | Bin 6496 -> 6490 bytes tests/data/acpi/q35/DSDT.dimmpxm | Bin 9474 -> 9468 bytes tests/data/acpi/q35/DSDT.memhp | Bin 9180 -> 9174 bytes tests/data/acpi/q35/DSDT.mmio64 | Bin 8947 -> 8945 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm index f6ec911..ad2800d 100644 Binary files a/tests/data/acpi/pc/DSDT.dimmpxm and b/tests/data/acpi/pc/DSDT.dimmpxm differ diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp index e31ef50..9e75ac9 100644 Binary files a/tests/data/acpi/pc/DSDT.memhp and b/tests/data/acpi/pc/DSDT.memhp differ diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm index 3837792..7177116 100644 Binary files a/tests/data/acpi/q35/DSDT.dimmpxm and b/tests/data/acpi/q35/DSDT.dimmpxm differ diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp index 8fba0ba..0235461 100644 Binary files a/tests/data/acpi/q35/DSDT.memhp and b/tests/data/acpi/q35/DSDT.memhp differ diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64 index a058ff2..f60ee77 100644 Binary files a/tests/data/acpi/q35/DSDT.mmio64 and b/tests/data/acpi/q35/DSDT.mmio64 differ -- cgit v1.1 From 1daff2f8193496b0e5e0ab56dc48c570c81f804e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Jan 2019 09:56:34 +0100 Subject: qemu/compiler: Define QEMU_NONSTRING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 8 introduced the -Wstringop-truncation checker to detect truncation by the strncat and strncpy functions (closely related to -Wstringop-overflow, which detect buffer overflow by string-modifying functions declared in ). In tandem of -Wstringop-truncation, the "nonstring" attribute was added: The nonstring variable attribute specifies that an object or member declaration with type array of char, signed char, or unsigned char, or pointer to such a type is intended to store character arrays that do not necessarily contain a terminating NUL. This is useful in detecting uses of such arrays or pointers with functions that expect NUL-terminated strings, and to avoid warnings when such an array or pointer is used as an argument to a bounded string manipulation function such as strncpy. From the GCC manual: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-nonstring-variable-attribute Add the QEMU_NONSTRING macro which checks if the compiler supports this attribute. Suggested-by: Michael S. Tsirkin Reviewed-by: Eric Blake Reviewed-by: Michael S. Tsirkin Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé --- include/qemu/compiler.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 261842b..2d8f507 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -151,6 +151,21 @@ # define QEMU_ERROR(X) #endif +/* + * The nonstring variable attribute specifies that an object or member + * declaration with type array of char or pointer to char is intended + * to store character arrays that do not necessarily contain a terminating + * NUL character. This is useful in detecting uses of such arrays or pointers + * with functions that expect NUL-terminated strings, and to avoid warnings + * when such an array or pointer is used as an argument to a bounded string + * manipulation function such as strncpy. + */ +#if __has_attribute(nonstring) +# define QEMU_NONSTRING __attribute__((nonstring)) +#else +# define QEMU_NONSTRING +#endif + /* Implement C11 _Generic via GCC builtins. Example: * * QEMU_GENERIC(x, (float, sinf), (long double, sinl), sin) (x) -- cgit v1.1 From 97b583f46c435aaa40942ca73739d79190776b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Jan 2019 09:56:35 +0100 Subject: block/sheepdog: Use QEMU_NONSTRING for non NUL-terminated arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 8 added a -Wstringop-truncation warning: The -Wstringop-truncation warning added in GCC 8.0 via r254630 for bug 81117 is specifically intended to highlight likely unintended uses of the strncpy function that truncate the terminating NUL character from the source string. This new warning leads to compilation failures: CC block/sheepdog.o qemu/block/sheepdog.c: In function 'find_vdi_name': qemu/block/sheepdog.c:1239:5: error: 'strncpy' specified bound 256 equals destination size [-Werror=stringop-truncation] strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ make: *** [qemu/rules.mak:69: block/sheepdog.o] Error 1 As described previous to the strncpy() calls, the use of strncpy() is correct here: /* This pair of strncpy calls ensures that the buffer is zero-filled, * which is desirable since we'll soon be sending those bytes, and * don't want the send_req to read uninitialized data. */ strncpy(buf, filename, SD_MAX_VDI_LEN); strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN); Use the QEMU_NONSTRING attribute, since this array is intended to store character arrays that do not necessarily contain a terminating NUL. Suggested-by: Michael S. Tsirkin Reviewed-by: Eric Blake Reviewed-by: Michael S. Tsirkin Signed-off-by: Philippe Mathieu-Daudé --- block/sheepdog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 90ab43b..ed14f7a 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1224,7 +1224,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename, SheepdogVdiReq hdr; SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; unsigned int wlen, rlen = 0; - char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN]; + char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN] QEMU_NONSTRING; fd = connect_to_sdog(s, errp); if (fd < 0) { -- cgit v1.1 From 9cbb8eca1729eab1123847e37454975bb555008a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Jan 2019 09:56:36 +0100 Subject: hw/acpi: Use QEMU_NONSTRING for non NUL-terminated arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 8 added a -Wstringop-truncation warning: The -Wstringop-truncation warning added in GCC 8.0 via r254630 for bug 81117 is specifically intended to highlight likely unintended uses of the strncpy function that truncate the terminating NUL character from the source string. This new warning leads to compilation failures: CC hw/acpi/core.o In function 'acpi_table_install', inlined from 'acpi_table_add' at qemu/hw/acpi/core.c:296:5: qemu/hw/acpi/core.c:184:9: error: 'strncpy' specified bound 4 equals destination size [-Werror=stringop-truncation] strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ make: *** [qemu/rules.mak:69: hw/acpi/core.o] Error 1 Use the QEMU_NONSTRING attribute, since ACPI tables don't require the strings to be NUL-terminated. Suggested-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov Signed-off-by: Philippe Mathieu-Daudé --- hw/acpi/core.c | 12 ++++++++---- include/hw/acpi/acpi-defs.h | 13 ++++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index d6f0709..47877c0 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -35,14 +35,18 @@ struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ /* allows easier parsing for fw_cfg clients */ - char sig[4]; /* ACPI signature (4 ASCII characters) */ + char sig[4] + QEMU_NONSTRING; /* ACPI signature (4 ASCII characters) */ uint32_t length; /* Length of table, in bytes, including header */ uint8_t revision; /* ACPI Specification minor version # */ uint8_t checksum; /* To make sum of entire table == 0 */ - char oem_id[6]; /* OEM identification */ - char oem_table_id[8]; /* OEM table identification */ + char oem_id[6] + QEMU_NONSTRING; /* OEM identification */ + char oem_table_id[8] + QEMU_NONSTRING; /* OEM table identification */ uint32_t oem_revision; /* OEM revision number */ - char asl_compiler_id[4]; /* ASL compiler vendor ID */ + char asl_compiler_id[4] + QEMU_NONSTRING; /* ASL compiler vendor ID */ uint32_t asl_compiler_revision; /* ASL compiler revision number */ } QEMU_PACKED; diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 5021cb9..4ed160a 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -41,8 +41,8 @@ enum { }; typedef struct AcpiRsdpData { - uint8_t oem_id[6]; /* OEM identification */ - uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ + uint8_t oem_id[6] QEMU_NONSTRING; /* OEM identification */ + uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ unsigned *rsdt_tbl_offset; unsigned *xsdt_tbl_offset; @@ -57,10 +57,13 @@ typedef struct AcpiRsdpData { uint32_t length; /* Length of table, in bytes, including header */ \ uint8_t revision; /* ACPI Specification minor version # */ \ uint8_t checksum; /* To make sum of entire table == 0 */ \ - uint8_t oem_id [6]; /* OEM identification */ \ - uint8_t oem_table_id [8]; /* OEM table identification */ \ + uint8_t oem_id[6] \ + QEMU_NONSTRING; /* OEM identification */ \ + uint8_t oem_table_id[8] \ + QEMU_NONSTRING; /* OEM table identification */ \ uint32_t oem_revision; /* OEM revision number */ \ - uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */ \ + uint8_t asl_compiler_id[4] \ + QEMU_NONSTRING; /* ASL compiler vendor ID */ \ uint32_t asl_compiler_revision; /* ASL compiler revision number */ -- cgit v1.1 From 0a5526a18b0245dfa20a9fe453b2a9af3125d175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 3 Jan 2019 09:56:37 +0100 Subject: migration: Fix stringop-truncation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 8 added a -Wstringop-truncation warning: The -Wstringop-truncation warning added in GCC 8.0 via r254630 for bug 81117 is specifically intended to highlight likely unintended uses of the strncpy function that truncate the terminating NUL character from the source string. This new warning leads to compilation failures: CC migration/global_state.o qemu/migration/global_state.c: In function 'global_state_store_running': qemu/migration/global_state.c:45:5: error: 'strncpy' specified bound 100 equals destination size [-Werror=stringop-truncation] strncpy((char *)global_state.runstate, state, sizeof(global_state.runstate)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ make: *** [qemu/rules.mak:69: migration/global_state.o] Error 1 Adding an assert is enough to silence GCC. (alternatively, we could hard-code "running") Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Philippe Mathieu-Daudé [PMD: More verbose commit message] Signed-off-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- migration/global_state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/global_state.c b/migration/global_state.c index 8e8ab5c..01805c5 100644 --- a/migration/global_state.c +++ b/migration/global_state.c @@ -42,6 +42,7 @@ int global_state_store(void) void global_state_store_running(void) { const char *state = RunState_str(RUN_STATE_RUNNING); + assert(strlen(state) < sizeof(global_state.runstate)); strncpy((char *)global_state.runstate, state, sizeof(global_state.runstate)); } -- cgit v1.1 From a346af9c881147f04eb7ff9264fe1599928cf067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Jan 2019 09:56:38 +0100 Subject: migration: Use strnlen() for fixed-size string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 8 introduced the -Wstringop-overflow, which detect buffer overflow by string-modifying functions declared in , such strncpy(), used in global_state_store_running(). GCC indeed found an incorrect use of strlen(), because this array is loaded by VMSTATE_BUFFER(runstate, GlobalState) then parsed using qapi_enum_parse which does not get the buffer length. Use strnlen() which returns sizeof(s->runstate) if the array is not NUL-terminated, assert the size is within range, and enforce the array to be NUL-terminated to avoid an overflow in qapi_enum_parse(). This fixes: CC migration/global_state.o qemu/migration/global_state.c: In function 'global_state_pre_save': qemu/migration/global_state.c:109:15: error: 'strlen' argument 1 declared attribute 'nonstring' [-Werror=stringop-overflow=] s->size = strlen((char *)s->runstate) + 1; ^~~~~~~~~~~~~~~~~~~~~~~~~~~ qemu/migration/global_state.c:24:13: note: argument 'runstate' declared here uint8_t runstate[100] QEMU_NONSTRING; ^~~~~~~~ cc1: all warnings being treated as errors make: *** [qemu/rules.mak:69: migration/global_state.o] Error 1 Suggested-by: Michael S. Tsirkin Reviewed-by: Richard Henderson Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- migration/global_state.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/migration/global_state.c b/migration/global_state.c index 01805c5..2c8c447 100644 --- a/migration/global_state.c +++ b/migration/global_state.c @@ -89,6 +89,17 @@ static int global_state_post_load(void *opaque, int version_id) s->received = true; trace_migrate_global_state_post_load(runstate); + if (strnlen((char *)s->runstate, + sizeof(s->runstate)) == sizeof(s->runstate)) { + /* + * This condition should never happen during migration, because + * all runstate names are shorter than 100 bytes (the size of + * s->runstate). However, a malicious stream could overflow + * the qapi_enum_parse() call, so we force the last character + * to a NUL byte. + */ + s->runstate[sizeof(s->runstate) - 1] = '\0'; + } r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err); if (r == -1) { @@ -107,7 +118,8 @@ static int global_state_pre_save(void *opaque) GlobalState *s = opaque; trace_migrate_global_state_pre_save((char *)s->runstate); - s->size = strlen((char *)s->runstate) + 1; + s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1; + assert(s->size <= sizeof(s->runstate)); return 0; } -- cgit v1.1