From 00adced5c3166ee65b6880b48c1e0826b7304f76 Mon Sep 17 00:00:00 2001 From: Hanna Czenczek Date: Tue, 23 Jul 2024 18:39:39 +0200 Subject: [PATCH 01/18] virtio: Allow .get_vhost() without vhost_started Historically, .get_vhost() was probably only called when vdev->vhost_started is true. However, we now decidedly want to call it also when vhost_started is false, specifically so we can issue a reset to the vhost back-end while device operation is stopped. Some .get_vhost() implementations dereference some pointers (or return offsets from them) that are probably guaranteed to be non-NULL when vhost_started is true, but not necessarily otherwise. This patch makes all such implementations check all such pointers, returning NULL if any is NULL. Signed-off-by: Hanna Czenczek Message-Id: <20240723163941.48775-2-hreitz@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi --- hw/display/vhost-user-gpu.c | 2 +- hw/net/virtio-net.c | 19 +++++++++++++++++-- hw/virtio/virtio-crypto.c | 18 +++++++++++++++--- include/hw/virtio/virtio.h | 1 + 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index c0c66910f1..14548f1a57 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -642,7 +642,7 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp) static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev) { VhostUserGPU *g = VHOST_USER_GPU(vdev); - return &g->vhost->dev; + return g->vhost ? &g->vhost->dev : NULL; } static Property vhost_user_gpu_properties[] = { diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index ed33a32877..fb84d142ee 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3896,8 +3896,23 @@ static bool dev_unplug_pending(void *opaque) static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev) { VirtIONet *n = VIRTIO_NET(vdev); - NetClientState *nc = qemu_get_queue(n->nic); - struct vhost_net *net = get_vhost_net(nc->peer); + NetClientState *nc; + struct vhost_net *net; + + if (!n->nic) { + return NULL; + } + + nc = qemu_get_queue(n->nic); + if (!nc) { + return NULL; + } + + net = get_vhost_net(nc->peer); + if (!net) { + return NULL; + } + return &net->dev; } diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 5034768bff..0793f56965 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -1247,9 +1247,21 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) { VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); - CryptoDevBackend *b = vcrypto->cryptodev; - CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; - CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0); + CryptoDevBackend *b; + CryptoDevBackendClient *cc; + CryptoDevBackendVhost *vhost_crypto; + + b = vcrypto->cryptodev; + if (!b) { + return NULL; + } + + cc = b->conf.peers.ccs[0]; + vhost_crypto = cryptodev_get_vhost(cc, b, 0); + if (!vhost_crypto) { + return NULL; + } + return &vhost_crypto->dev; } diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 0fcbc5c0c6..f526ecc8fc 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -223,6 +223,7 @@ struct VirtioDeviceClass { int (*post_load)(VirtIODevice *vdev); const VMStateDescription *vmsd; bool (*primary_unplug_pending)(void *opaque); + /* May be called even when vdev->vhost_started is false */ struct vhost_dev *(*get_vhost)(VirtIODevice *vdev); void (*toggle_device_iotlb)(VirtIODevice *vdev); }; From 2688e8df60f5a655dc34c5e38523e425556f8483 Mon Sep 17 00:00:00 2001 From: Hanna Czenczek Date: Tue, 23 Jul 2024 18:39:40 +0200 Subject: [PATCH 02/18] virtio: Always reset vhost devices Requiring `vhost_started` to be true for resetting vhost devices in `virtio_reset()` seems like the wrong condition: Most importantly, the preceding `virtio_set_status(vdev, 0)` call will (for vhost devices) end up in `vhost_dev_stop()` (through vhost devices' `.set_status` implementations), setting `vdev->vhost_started = false`. Therefore, the gated `vhost_reset_device()` call is unreachable. `vhost_started` is not documented, so it is hard to say what exactly it is supposed to mean, but judging from the fact that `vhost_dev_start()` sets it and `vhost_dev_stop()` clears it, it seems like it indicates whether there is a vhost back-end, and whether that back-end is currently running and processing virtio requests. Making a reset conditional on whether the vhost back-end is processing virtio requests seems wrong; in fact, it is probably better to reset it only when it is not currently processing requests, which is exactly the current order of operations in `virtio_reset()`: First, the back-end is stopped through `virtio_set_status(vdev, 0)`, then we want to send a reset. Therefore, we should drop the `vhost_started` condition, but in its stead we then have to verify that we can indeed send a reset to this vhost device, by not just checking `k->get_vhost != NULL` (introduced by commit 95e1019a4a9), but also that the vhost back-end is connected (`hdev = k->get_vhost(); hdev != NULL && hdev->vhost_ops != NULL`). Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Hanna Czenczek Message-Id: <20240723163941.48775-3-hreitz@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 9e10cbc058..42589adf2c 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2331,8 +2331,12 @@ void virtio_reset(void *opaque) vdev->device_endian = virtio_default_endian(); } - if (vdev->vhost_started && k->get_vhost) { - vhost_reset_device(k->get_vhost(vdev)); + if (k->get_vhost) { + struct vhost_dev *hdev = k->get_vhost(vdev); + /* Only reset when vhost back-end is connected */ + if (hdev && hdev->vhost_ops) { + vhost_reset_device(hdev); + } } if (k->reset) { From e72a7f65c11565d2f216711588a4e767a1f6cd80 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 29 Jun 2024 22:01:53 +0200 Subject: [PATCH 03/18] hw: Move declaration of IRQState to header and add init function To allow embedding a qemu_irq in a struct move its definition to the header and add a function to init it in place without allocating it. Signed-off-by: BALATON Zoltan Message-Id: Signed-off-by: BALATON Zoltan --- hw/core/irq.c | 25 +++++++++++-------------- include/hw/irq.h | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/hw/core/irq.c b/hw/core/irq.c index 3f14e2dda7..db95ffc18f 100644 --- a/hw/core/irq.c +++ b/hw/core/irq.c @@ -26,16 +26,6 @@ #include "hw/irq.h" #include "qom/object.h" -OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ) - -struct IRQState { - Object parent_obj; - - qemu_irq_handler handler; - void *opaque; - int n; -}; - void qemu_set_irq(qemu_irq irq, int level) { if (!irq) @@ -44,6 +34,15 @@ void qemu_set_irq(qemu_irq irq, int level) irq->handler(irq->opaque, irq->n, level); } +void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque, + int n) +{ + object_initialize(irq, sizeof(*irq), TYPE_IRQ); + irq->handler = handler; + irq->opaque = opaque; + irq->n = n; +} + qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler, void *opaque, int n) { @@ -69,10 +68,8 @@ qemu_irq qemu_allocate_irq(qemu_irq_handler handler, void *opaque, int n) { IRQState *irq; - irq = IRQ(object_new(TYPE_IRQ)); - irq->handler = handler; - irq->opaque = opaque; - irq->n = n; + irq = g_new(IRQState, 1); + qemu_init_irq(irq, handler, opaque, n); return irq; } diff --git a/include/hw/irq.h b/include/hw/irq.h index 645b73d251..c861c1debd 100644 --- a/include/hw/irq.h +++ b/include/hw/irq.h @@ -1,9 +1,20 @@ #ifndef QEMU_IRQ_H #define QEMU_IRQ_H +#include "qom/object.h" + /* Generic IRQ/GPIO pin infrastructure. */ #define TYPE_IRQ "irq" +OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ) + +struct IRQState { + Object parent_obj; + + qemu_irq_handler handler; + void *opaque; + int n; +}; void qemu_set_irq(qemu_irq irq, int level); @@ -23,6 +34,13 @@ static inline void qemu_irq_pulse(qemu_irq irq) qemu_set_irq(irq, 0); } +/* + * Init a single IRQ. The irq is assigned with a handler, an opaque data + * and the interrupt number. + */ +void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque, + int n); + /* Returns an array of N IRQs. Each IRQ is assigned the argument handler and * opaque data. */ From 2225dc562a93dc191c3b2a43f273639bebad5d9a Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 29 Jun 2024 22:01:54 +0200 Subject: [PATCH 04/18] hw/isa/vt82c686.c: Embed i8259 irq in device state instead of allocating To avoid a warning about unfreed qemu_irq embed the i8259 irq in the device state instead of allocating it. Signed-off-by: BALATON Zoltan Message-Id: Signed-off-by: BALATON Zoltan --- hw/isa/vt82c686.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 505b44c4e6..82591e3e07 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -592,6 +592,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ViaISAState, VIA_ISA) struct ViaISAState { PCIDevice dev; + + IRQState i8259_irq; qemu_irq cpu_intr; qemu_irq *isa_irqs_in; uint16_t irq_state[ISA_NUM_IRQS]; @@ -715,13 +717,12 @@ static void via_isa_realize(PCIDevice *d, Error **errp) ViaISAState *s = VIA_ISA(d); DeviceState *dev = DEVICE(d); PCIBus *pci_bus = pci_get_bus(d); - qemu_irq *isa_irq; ISABus *isa_bus; int i; qdev_init_gpio_out_named(dev, &s->cpu_intr, "intr", 1); qdev_init_gpio_in_named(dev, via_isa_pirq, "pirq", PCI_NUM_PINS); - isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1); + qemu_init_irq(&s->i8259_irq, via_isa_request_i8259_irq, s, 0); isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d), errp); @@ -729,7 +730,7 @@ static void via_isa_realize(PCIDevice *d, Error **errp) return; } - s->isa_irqs_in = i8259_init(isa_bus, *isa_irq); + s->isa_irqs_in = i8259_init(isa_bus, &s->i8259_irq); isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in); i8254_pit_init(isa_bus, 0x40, 0, NULL); i8257_dma_init(OBJECT(d), isa_bus, 0); From e228d62b4af29bca698ec57efdceb46f392f5444 Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Sun, 7 Jul 2024 21:10:56 -0700 Subject: [PATCH 05/18] pci: don't skip function 0 occupancy verification for devfn auto assign When the devfn is already assigned in the command line, the do_pci_register_device() may verify if the function 0 is already occupied. However, when devfn < 0, the verification is skipped because it is part of the last "else if". For instance, suppose there is already a device at addr=00.00 of a port. -device pcie-root-port,bus=pcie.0,chassis=115,id=port01,addr=0e.00 \ -device virtio-net-pci,bus=port01,id=vnet01,addr=00.00 \ When 'addr' is specified for the 2nd device, the hotplug is denied. (qemu) device_add virtio-net-pci,bus=port01,id=vnet02,addr=01.00 Error: PCI: slot 0 function 0 already occupied by virtio-net-pci, new func virtio-net-pci cannot be exposed to guest. When 'addr' is automatically assigned, the hotplug is not denied. This is because the verification is skipped. (qemu) device_add virtio-net-pci,bus=port01,id=vnet02 warning: PCI: slot 1 is not valid for virtio-net-pci, parent device only allows plugging into slot 0. Fix the issue by moving the verification into an independent 'if' statement. Fixes: 3f1e1478db2d ("enable multi-function hot-add") Reported-by: Aswin Unnikrishnan Signed-off-by: Dongli Zhang Message-Id: <20240708041056.54504-1-dongli.zhang@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index d2caf3ee8b..87da35ca9b 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1181,14 +1181,15 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name, bus->devices[devfn]->qdev.id); return NULL; - } /* - * Populating function 0 triggers a scan from the guest that - * exposes other non-zero functions. Hence we need to ensure that - * function 0 wasn't added yet. - */ - else if (dev->hotplugged && - !pci_is_vf(pci_dev) && - pci_get_function_0(pci_dev)) { + } + + /* + * Populating function 0 triggers a scan from the guest that + * exposes other non-zero functions. Hence we need to ensure that + * function 0 wasn't added yet. + */ + if (dev->hotplugged && !pci_is_vf(pci_dev) && + pci_get_function_0(pci_dev)) { error_setg(errp, "PCI: slot %d function 0 already occupied by %s," " new func %s cannot be exposed to guest.", PCI_SLOT(pci_get_function_0(pci_dev)->devfn), From aa37616fb4eed38f3fc26507faf2433c998e0073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 1 Aug 2024 15:14:49 +0200 Subject: [PATCH 06/18] hw/pci/pci-hmp-cmds: Avoid displaying bogus size in 'info pci' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When BAR aren't mapped, we get: (qemu) info pci Bus 0, device 0, function 0: Host bridge: PCI device dead:beef ... BAR4: 32 bit memory at 0xffffffffffffffff [0x00000ffe]. BAR5: I/O at 0xffffffffffffffff [0x0ffe]. Check the BAR is mapped comparing its address to PCI_BAR_UNMAPPED which is what the PCI layer uses for unmapped BARs. See pci_bar_address and pci_update_mappings implementations and in "hw/pci/pci.h": typedef struct PCIIORegion { pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ #define PCI_BAR_UNMAPPED (~(pcibus_t)0) ... This improves the logging, not displaying bogus sizes: (qemu) info pci Bus 0, device 0, function 0: Host bridge: PCI device dead:beef ... BAR4: 32 bit memory (not mapped) BAR5: I/O (not mapped) Remove trailing dot which is not used in other commands format. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20240801131449.51328-1-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci-hmp-cmds.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/hw/pci/pci-hmp-cmds.c b/hw/pci/pci-hmp-cmds.c index b09fce9377..fdfe44435c 100644 --- a/hw/pci/pci-hmp-cmds.c +++ b/hw/pci/pci-hmp-cmds.c @@ -83,15 +83,25 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar); if (!strcmp(region->value->type, "io")) { - monitor_printf(mon, "I/O at 0x%04" PRIx64 - " [0x%04" PRIx64 "].\n", - addr, addr + size - 1); + if (addr != PCI_BAR_UNMAPPED) { + monitor_printf(mon, "I/O at 0x%04" PRIx64 + " [0x%04" PRIx64 "]\n", + addr, addr + size - 1); + } else { + monitor_printf(mon, "I/O (not mapped)\n"); + } } else { - monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64 - " [0x%08" PRIx64 "].\n", - region->value->mem_type_64 ? 64 : 32, - region->value->prefetch ? " prefetchable" : "", - addr, addr + size - 1); + if (addr != PCI_BAR_UNMAPPED) { + monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64 + " [0x%08" PRIx64 "]\n", + region->value->mem_type_64 ? 64 : 32, + region->value->prefetch ? " prefetchable" : "", + addr, addr + size - 1); + } else { + monitor_printf(mon, "%d bit%s memory (not mapped)\n", + region->value->mem_type_64 ? 64 : 32, + region->value->prefetch ? " prefetchable" : ""); + } } } From e667485a80ed3f3849ea7421a63fe8ba553cd25e Mon Sep 17 00:00:00 2001 From: Wenyu Huang Date: Thu, 1 Aug 2024 01:35:12 -0400 Subject: [PATCH 07/18] virtio: rename virtio_split_packed_update_used_idx virtio_split_packed_update_used_idx should be virtio_queue_split_update_used_idx like virtio_split_packed_update_used_idx. Signed-off-by: Wenyu Huang Message-Id: Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 42589adf2c..a26f18908e 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3669,7 +3669,7 @@ static void virtio_queue_packed_update_used_idx(VirtIODevice *vdev, int n) return; } -static void virtio_split_packed_update_used_idx(VirtIODevice *vdev, int n) +static void virtio_queue_split_update_used_idx(VirtIODevice *vdev, int n) { RCU_READ_LOCK_GUARD(); if (vdev->vq[n].vring.desc) { @@ -3682,7 +3682,7 @@ void virtio_queue_update_used_idx(VirtIODevice *vdev, int n) if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) { return virtio_queue_packed_update_used_idx(vdev, n); } else { - return virtio_split_packed_update_used_idx(vdev, n); + return virtio_queue_split_update_used_idx(vdev, n); } } From 663168943d3db6d9b51d3dfa0998848a6e6eda71 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Wed, 14 Aug 2024 15:13:19 +0800 Subject: [PATCH 08/18] intel_iommu: Fix invalidation descriptor type field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to spec, invalidation descriptor type is 7bits which is concatenation of bits[11:9] and bits[3:0] of invalidation descriptor. Currently we only pick bits[3:0] as the invalidation type and treat bits[11:9] as reserved zero. This is not a problem for now as bits[11:9] is zero for all current invalidation types. But it will break if newer type occupies bits[11:9]. Fix it by taking bits[11:9] into type and make reserved bits check accurate. Suggested-by: Clément Mathieu--Drif Signed-off-by: Zhenzhong Duan Reviewed-by: Yi Liu Reviewed-by: Clément Mathieu--Drif Message-Id: <20240814071321.2621384-2-zhenzhong.duan@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 2 +- hw/i386/intel_iommu_internal.h | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 16d2885fcc..68cb72a481 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2744,7 +2744,7 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) return false; } - desc_type = inv_desc.lo & VTD_INV_DESC_TYPE; + desc_type = VTD_INV_DESC_TYPE(inv_desc.lo); /* FIXME: should update at first or at last? */ s->iq_last_desc_type = desc_type; diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 5f32c36943..13d5d129ae 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -356,7 +356,8 @@ union VTDInvDesc { typedef union VTDInvDesc VTDInvDesc; /* Masks for struct VTDInvDesc */ -#define VTD_INV_DESC_TYPE 0xf +#define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \ + ((val) & 0xfULL)) #define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */ #define VTD_INV_DESC_IOTLB 0x2 #define VTD_INV_DESC_DEVICE 0x3 @@ -372,7 +373,7 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_WAIT_IF (1ULL << 4) #define VTD_INV_DESC_WAIT_FN (1ULL << 6) #define VTD_INV_DESC_WAIT_DATA_SHIFT 32 -#define VTD_INV_DESC_WAIT_RSVD_LO 0Xffffff80ULL +#define VTD_INV_DESC_WAIT_RSVD_LO 0Xfffff180ULL #define VTD_INV_DESC_WAIT_RSVD_HI 3ULL /* Masks for Context-cache Invalidation Descriptor */ @@ -383,7 +384,7 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_CC_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK) #define VTD_INV_DESC_CC_SID(val) (((val) >> 32) & 0xffffUL) #define VTD_INV_DESC_CC_FM(val) (((val) >> 48) & 3UL) -#define VTD_INV_DESC_CC_RSVD 0xfffc00000000ffc0ULL +#define VTD_INV_DESC_CC_RSVD 0xfffc00000000f1c0ULL /* Masks for IOTLB Invalidate Descriptor */ #define VTD_INV_DESC_IOTLB_G (3ULL << 4) @@ -393,7 +394,7 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_IOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK) #define VTD_INV_DESC_IOTLB_ADDR(val) ((val) & ~0xfffULL) #define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL) -#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL +#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL #define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL #define VTD_INV_DESC_IOTLB_PASID_PASID (2ULL << 4) #define VTD_INV_DESC_IOTLB_PASID_PAGE (3ULL << 4) @@ -406,7 +407,7 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_DEVICE_IOTLB_SIZE(val) ((val) & 0x1) #define VTD_INV_DESC_DEVICE_IOTLB_SID(val) (((val) >> 32) & 0xFFFFULL) #define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL -#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0fff8 +#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0f1f0 /* Rsvd field masks for spte */ #define VTD_SPTE_SNP 0x800ULL From 3b52cea829d873706ff86913ae99b4bd621c20e6 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Wed, 14 Aug 2024 15:13:20 +0800 Subject: [PATCH 09/18] intel_iommu: Make PASID-cache and PIOTLB type invalid in legacy mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In vtd_process_inv_desc(), VTD_INV_DESC_PC and VTD_INV_DESC_PIOTLB are bypassed without scalable mode check. These two types are not valid in legacy mode and we should report error. Fixes: 4a4f219e8a10 ("intel_iommu: add scalable-mode option to make scalable mode work") Suggested-by: Yi Liu Signed-off-by: Zhenzhong Duan Reviewed-by: Clément Mathieu--Drif Reviewed-by: Yi Liu Message-Id: <20240814071321.2621384-3-zhenzhong.duan@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 68cb72a481..90cd4e5044 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2763,17 +2763,6 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) } break; - /* - * TODO: the entity of below two cases will be implemented in future series. - * To make guest (which integrates scalable mode support patch set in - * iommu driver) work, just return true is enough so far. - */ - case VTD_INV_DESC_PC: - break; - - case VTD_INV_DESC_PIOTLB: - break; - case VTD_INV_DESC_WAIT: trace_vtd_inv_desc("wait", inv_desc.hi, inv_desc.lo); if (!vtd_process_wait_desc(s, &inv_desc)) { @@ -2795,6 +2784,17 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) } break; + /* + * TODO: the entity of below two cases will be implemented in future series. + * To make guest (which integrates scalable mode support patch set in + * iommu driver) work, just return true is enough so far. + */ + case VTD_INV_DESC_PC: + case VTD_INV_DESC_PIOTLB: + if (s->scalable_mode) { + break; + } + /* fallthrough */ default: error_report_once("%s: invalid inv desc: hi=%"PRIx64", lo=%"PRIx64 " (unknown type)", __func__, inv_desc.hi, From ae77a40e3c7f010d1d18a92806246654f92b6f26 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 14 Aug 2024 11:56:09 +0000 Subject: [PATCH 10/18] tests/acpi: pc: allow DSDT acpi table changes Signed-off-by: Ricardo Ribalda Message-Id: <20240814115736.1580337-2-ribalda@chromium.org> Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..f81f4e2469 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,16 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/x86/pc/DSDT", +"tests/data/acpi/x86/pc/DSDT.acpierst", +"tests/data/acpi/x86/pc/DSDT.acpihmat", +"tests/data/acpi/x86/pc/DSDT.bridge", +"tests/data/acpi/x86/pc/DSDT.cphp", +"tests/data/acpi/x86/pc/DSDT.dimmpxm", +"tests/data/acpi/x86/pc/DSDT.hpbridge", +"tests/data/acpi/x86/pc/DSDT.hpbrroot", +"tests/data/acpi/x86/pc/DSDT.ipmikcs", +"tests/data/acpi/x86/pc/DSDT.memhp", +"tests/data/acpi/x86/pc/DSDT.nohpet", +"tests/data/acpi/x86/pc/DSDT.numamem", +"tests/data/acpi/x86/pc/DSDT.roothp", +"tests/data/acpi/x86/q35/DSDT.cxl", +"tests/data/acpi/x86/q35/DSDT.viot", From 99cb2c6c7b3674359c61a40fb17a75516b8e159d Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 14 Aug 2024 11:56:10 +0000 Subject: [PATCH 11/18] hw/i386/acpi-build: Return a pre-computed _PRT table When qemu runs without kvm acceleration the ACPI executions take a great amount of time. If they take more than the default time (30sec), the ACPI calls fail and the system might not behave correctly. Now the _PRT table is computed on the fly. We can drastically reduce the execution of the _PRT method if we return a pre-computed table. Without this patch: [ 51.343484] ACPI Error: Aborting method \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/psparse-529) [ 51.527032] ACPI Error: Method execution failed \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/uteval-68) [ 51.530049] virtio-pci 0000:00:02.0: can't derive routing for PCI INT A [ 51.530797] virtio-pci 0000:00:02.0: PCI INT A: no GSI [ 81.922901] ACPI Error: Aborting method \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/psparse-529) [ 82.103534] ACPI Error: Method execution failed \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/uteval-68) [ 82.106088] virtio-pci 0000:00:04.0: can't derive routing for PCI INT A [ 82.106761] virtio-pci 0000:00:04.0: PCI INT A: no GSI [ 112.192568] ACPI Error: Aborting method \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/psparse-529) [ 112.486687] ACPI Error: Method execution failed \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/uteval-68) [ 112.489554] virtio-pci 0000:00:05.0: can't derive routing for PCI INT A [ 112.490027] virtio-pci 0000:00:05.0: PCI INT A: no GSI [ 142.559448] ACPI Error: Aborting method \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/psparse-529) [ 142.718596] ACPI Error: Method execution failed \_SB.PCI0._PRT due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/uteval-68) [ 142.722889] virtio-pci 0000:00:06.0: can't derive routing for PCI INT A [ 142.724578] virtio-pci 0000:00:06.0: PCI INT A: no GSI With this patch: [ 22.938076] ACPI: \_SB_.LNKB: Enabled at IRQ 10 [ 24.214002] ACPI: \_SB_.LNKD: Enabled at IRQ 11 [ 25.465170] ACPI: \_SB_.LNKA: Enabled at IRQ 10 [ 27.944920] ACPI: \_SB_.LNKC: Enabled at IRQ 11 ACPI disassembly: Scope (PCI0) { Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table { Return (Package (0x80) { Package (0x04) { 0xFFFF, Zero, LNKD, Zero }, Package (0x04) { 0xFFFF, One, LNKA, Zero }, Package (0x04) { 0xFFFF, 0x02, LNKB, Zero }, Package (0x04) { 0xFFFF, 0x03, LNKC, Zero }, Package (0x04) { 0x0001FFFF, Zero, LNKS, Zero }, Context: https://lore.kernel.org/virtualization/20240417145544.38d7b482@imammedo.users.ipa.redhat.com/T/#t Signed-off-by: Ricardo Ribalda Reviewed-by: Igor Mammedov Reviewed-by: Richard Henderson Message-Id: <20240814115736.1580337-3-ribalda@chromium.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 118 ++++++++----------------------------------- 1 file changed, 21 insertions(+), 97 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 5d4bd2b710..4967aa7459 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -724,120 +724,44 @@ static Aml *aml_pci_pdsm(void) return method; } -/** - * build_prt_entry: - * @link_name: link name for PCI route entry - * - * build AML package containing a PCI route entry for @link_name - */ -static Aml *build_prt_entry(const char *link_name) -{ - Aml *a_zero = aml_int(0); - Aml *pkg = aml_package(4); - aml_append(pkg, a_zero); - aml_append(pkg, a_zero); - aml_append(pkg, aml_name("%s", link_name)); - aml_append(pkg, a_zero); - return pkg; -} - /* - * initialize_route - Initialize the interrupt routing rule - * through a specific LINK: - * if (lnk_idx == idx) - * route using link 'link_name' - */ -static Aml *initialize_route(Aml *route, const char *link_name, - Aml *lnk_idx, int idx) -{ - Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx))); - Aml *pkg = build_prt_entry(link_name); - - aml_append(if_ctx, aml_store(pkg, route)); - - return if_ctx; -} - -/* - * build_prt - Define interrupt rounting rules + * build_prt - Define interrupt routing rules * * Returns an array of 128 routes, one for each device, * based on device location. * The main goal is to equally distribute the interrupts * over the 4 existing ACPI links (works only for i440fx). - * The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]". + * The hash function is: (slot + pin) & 3 -> "LNK[D|A|B|C]". * */ static Aml *build_prt(bool is_pci0_prt) { - Aml *method, *while_ctx, *pin, *res; + const int nroutes = 128; + Aml *rt_pkg, *method; + int pin; method = aml_method("_PRT", 0, AML_NOTSERIALIZED); - res = aml_local(0); - pin = aml_local(1); - aml_append(method, aml_store(aml_package(128), res)); - aml_append(method, aml_store(aml_int(0), pin)); + rt_pkg = aml_varpackage(nroutes); - /* while (pin < 128) */ - while_ctx = aml_while(aml_lless(pin, aml_int(128))); - { - Aml *slot = aml_local(2); - Aml *lnk_idx = aml_local(3); - Aml *route = aml_local(4); + for (pin = 0; pin < nroutes; pin++) { + Aml *pkg = aml_package(4); + int slot = pin >> 2; - /* slot = pin >> 2 */ - aml_append(while_ctx, - aml_store(aml_shiftright(pin, aml_int(2), NULL), slot)); - /* lnk_idx = (slot + pin) & 3 */ - aml_append(while_ctx, - aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL), - lnk_idx)); - - /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */ - aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0)); - if (is_pci0_prt) { - Aml *if_device_1, *if_pin_4, *else_pin_4; - - /* device 1 is the power-management device, needs SCI */ - if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1))); - { - if_pin_4 = aml_if(aml_equal(pin, aml_int(4))); - { - aml_append(if_pin_4, - aml_store(build_prt_entry("LNKS"), route)); - } - aml_append(if_device_1, if_pin_4); - else_pin_4 = aml_else(); - { - aml_append(else_pin_4, - aml_store(build_prt_entry("LNKA"), route)); - } - aml_append(if_device_1, else_pin_4); - } - aml_append(while_ctx, if_device_1); + aml_append(pkg, aml_int((slot << 16) | 0xFFFF)); + aml_append(pkg, aml_int(pin & 3)); + /* device 1 is the power-management device, needs SCI */ + if (is_pci0_prt && pin == 4) { + aml_append(pkg, aml_name("%s", "LNKS")); } else { - aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, 1)); + static const char link_name[][5] = {"LNKD", "LNKA", "LNKB", "LNKC"}; + int hash = (slot + pin) & 3; + aml_append(pkg, aml_name("%s", link_name[hash])); } - aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2)); - aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3)); - - /* route[0] = 0x[slot]FFFF */ - aml_append(while_ctx, - aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF), - NULL), - aml_index(route, aml_int(0)))); - /* route[1] = pin & 3 */ - aml_append(while_ctx, - aml_store(aml_and(pin, aml_int(3), NULL), - aml_index(route, aml_int(1)))); - /* res[pin] = route */ - aml_append(while_ctx, aml_store(route, aml_index(res, pin))); - /* pin++ */ - aml_append(while_ctx, aml_increment(pin)); + aml_append(pkg, aml_int(0)); + aml_append(rt_pkg, pkg); } - aml_append(method, while_ctx); - /* return res*/ - aml_append(method, aml_return(res)); + + aml_append(method, aml_return(rt_pkg)); return method; } From a6896ebc8ff8dadef391f6fe4f8fd4d38bc7d538 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 14 Aug 2024 11:56:11 +0000 Subject: [PATCH 12/18] tests/acpi: pc: update golden masters for DSDT Signed-off-by: Ricardo Ribalda Message-Id: <20240814115736.1580337-4-ribalda@chromium.org> Acked-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/x86/pc/DSDT | Bin 6830 -> 8527 bytes tests/data/acpi/x86/pc/DSDT.acpierst | Bin 6741 -> 8438 bytes tests/data/acpi/x86/pc/DSDT.acpihmat | Bin 8155 -> 9852 bytes tests/data/acpi/x86/pc/DSDT.bridge | Bin 13701 -> 15398 bytes tests/data/acpi/x86/pc/DSDT.cphp | Bin 7294 -> 8991 bytes tests/data/acpi/x86/pc/DSDT.dimmpxm | Bin 8484 -> 10181 bytes tests/data/acpi/x86/pc/DSDT.hpbridge | Bin 6781 -> 8478 bytes tests/data/acpi/x86/pc/DSDT.hpbrroot | Bin 3337 -> 5034 bytes tests/data/acpi/x86/pc/DSDT.ipmikcs | Bin 6902 -> 8599 bytes tests/data/acpi/x86/pc/DSDT.memhp | Bin 8189 -> 9886 bytes tests/data/acpi/x86/pc/DSDT.nohpet | Bin 6688 -> 8385 bytes tests/data/acpi/x86/pc/DSDT.numamem | Bin 6836 -> 8533 bytes tests/data/acpi/x86/pc/DSDT.roothp | Bin 10623 -> 12320 bytes tests/data/acpi/x86/q35/DSDT.cxl | Bin 9714 -> 13148 bytes tests/data/acpi/x86/q35/DSDT.viot | Bin 9464 -> 14615 bytes tests/qtest/bios-tables-test-allowed-diff.h | 15 --------------- 16 files changed, 15 deletions(-) diff --git a/tests/data/acpi/x86/pc/DSDT b/tests/data/acpi/x86/pc/DSDT index c93ad6b7f83a168a1833d7dba1112dd2ab8a431f..92225236e717b2e522a2ee00492fb0ded418dc7b 100644 GIT binary patch delta 1914 zcmY+_OK#gR6a`RPmVc7`lmCBo0R=kA0^&G>phg?inPg;S4auBYNk<(QD7uD@yN<4c zy?hjfcW1ixyAY2k+COjp9<$Ts^z`+EF^%V6*~i2_e7|0f*U|ay@$TW%^#1Mo`0dI3 zn4Dj;_cBj&=gj%b=aUK74P4)vvhbg03BoakCc>R5`)T1^!}!jnPQHb~LHJI37!A>y z%vW&(sU}jzaFu*D&L&2x7?mobZ(=zz+mvQpLeuzW9BqasMx}}9n{pS6^`=sdOGu>} zXVXxP%SY7GmNerMTGEW8ttfhc<3EK5d z>mQ&zl`cyWwX{dl9!YyFMby%)k_Ko-(9Brc(~PA#Npq6sEJf7Pf~18sBec*^>m0I{ z_DR|&X`iKtS~?)Q)RzMAOzky=#)LNxEh! zqLyw*x*_SNmI@S6L$}6Oe=qV1Zb`ajDWaC{NV+5Gj-`mc8GqpS8v5e)B;B(VQA-ab RJ&^RkQp6zr{V(~m_z%ZI%zOX< delta 204 zcmX@_w9b^vCD&(M*=z)(<~2(+*x Wg^{5kr6VDcp)_$x!saf{qv8OZMKp8( diff --git a/tests/data/acpi/x86/pc/DSDT.acpierst b/tests/data/acpi/x86/pc/DSDT.acpierst index f643fa2d034053fa07f74f095565b64f021d4290..25b39955059409b177870800949eaf937cd39005 100644 GIT binary patch delta 1914 zcmY+_OK#gR6a`RPmVc7`lmGv2pg;%NfD>mB)F^^Db0hQ4nmMzQ42o``=vumnZXi?k z@=+Ato$1=|LOh~q|GoJ*W~a;P`Qwu@ji0}>&xw6_zg}*yqx0+I-NTpZ{p
Dm06 zoPT6*WuE5Fne(@=Cljt4xIUV)@SkT1!fgyqggaCA)55ui@tsSZd<%nv@SXH98lp9s zui^$$O{9w9D*0-hO^j4ADpf?^#ByY|Db2Wqrt!@<+6+yMN)ypH6oR6T3V8{Bx%V~#2^j(KOyMESba_>EJf7PDM_a!ow5{BOJ~xI$8@Hl*3DRosHJm~ z&Ph6FDWaAxNVx@IY& zmTpM8A?c=;3KUU8x5id~FY*d*NxEezqL%JRx+Ce1rHH;6f8h5T`r`H^-Ln)?OAjPH Qko3S(#323iFZsUs5AYbxUH||9 delta 204 zcmez7c-4fpdSNqn$Vynr`XfU~E8hznPIKu`!nfe=$eLIFeK zA}7wNiChf@Rf$|o3`qsmMTtoaT+9r~3j`)70~K+yFfjP|dAl&AEKr%8%(y^sav~QC zTsW8^Wg#z|=Ll3JI60Y%2`=IU5-|n}F~fzN8Bz*rE0eec7`XrcXXr>_U?`|g1X|dU W!pKmN(vgtJP@1?TVRIK}jyM3xel%79 diff --git a/tests/data/acpi/x86/pc/DSDT.acpihmat b/tests/data/acpi/x86/pc/DSDT.acpihmat index 9d3695ff289036856886a093733926667a32a058..73a9ce59e9426b180fea0ec5820c4841ebdb6700 100644 GIT binary patch delta 1914 zcmY+_OODe(6a~h3UT5uq08dBhs%AyTmtMr;7F99F=TaZAOm zS1#+_nQ!v0T*u`~{=9#^*z@)L{Oye~t>rKKHgk_ZZrA(UUp)okBIuW=5(Ql`3LrVmUI~mS$Q)+k|EsZO0}?rHL4taumll2$B5jMBLOGlI^H)8}-?QbaAClXOnfIZF|>bRo@jOcxsJ{DP&3TDm0Z zlB7$PB5LW1q$_Er?O!!eCua{?OV=b_lXT5eL@nKrbfcwy!%##tUGvksCFz!=Tb3ef z>5im3lI|L*KoK=`Z(RNNBCp_{q4~H# QlAc(K7^T1eX8-p80f2$c3jhEB delta 204 zcmez4bK9QFCD>2?Y#^ zi<~&8CUP|tR3&mTF(egK7bPY!a4|C^FA$iV3{=F)!oc9;=k3CfvOr~WGUEcl$%$Mn zaN%Hvl!d%-o+D6^;N)a3Cb)T@#0(d5W=JWhtxVz)VBr4$pP?g#fuW!}5olpY W3L`^7N=HH>LuulYgw0)?pJV{0Fg61K diff --git a/tests/data/acpi/x86/pc/DSDT.bridge b/tests/data/acpi/x86/pc/DSDT.bridge index 840b45f354ac14c858d0af8fbd31e97949a65d4b..4cef454e379e1009141694e0f4036a2a701c80d7 100644 GIT binary patch delta 1914 zcmY+_J8#=C6a`>fmS2+mlHc#GTY#W*mn7~G)Cht&yV0pb#$@QmF8vopr=ok&U)5j1 z9$t#VJ)4ew55!Lt?e8zYzh=kt@%h~cV;W!nWLJs3|9LszUPh<4$GiLM>BqOr15`^0rnh1BM?5Blu4dXlKI{6j`2jM&EVKhW* zGGE0Fq?$+-!&UOtIGY%$VpOV#zKP|?Y*U(X2~FdhakLql7?mcXZ^~UP)|*N-E+Lg_ zoJ~VDE+0`#Thfe6Xh}1Uwn8(m9#KQv71V~+x1}0q+bl)Y(hf;GB<-*iv6cebC1}?- zt$%>>RJtrh)Y2YFdnE0#6j4jFN*bUUK{I1%PcxS0B+W^hvlLNF3z8PnjL4v16S}IUP4c!`B{k_O5xFzY9rHER(Bk7K$JC-8)X8eKQYv^aUC+VK0h+29e S>4BsNmLdk}-+#%E_x}Nim&}L& delta 204 zcmZ2h(VETW66_MvYRbUCD7leKm#N;vBtFa;7#Mu~yj>Vl7N|^4W?UdRIgyJ6 zE*#8|vXB?fa|9|9oSe+X1Q&4vi5LTgnBhXs3@HV*l}TIz4BY?!GjyadFcefL0xj%F WVPq&s=}1UqC{0|Fu(^wKju8N_-!y;# diff --git a/tests/data/acpi/x86/pc/DSDT.cphp b/tests/data/acpi/x86/pc/DSDT.cphp index dbc0141b2bbc77a6d806ff046dc137992c59a899..1dc928333d7ae7e4df6bb51d850af5e1cb480158 100644 GIT binary patch delta 1914 zcmY+_yN=U97zN;o@9BD5mgM?3@D4=+Ir4KIMGc_3bb;mkiC z>pz`O@*jCVk0<%}_Q!jBzMh{?uZ(H^`DI^c?(zHWdViZ-UY;Hv-^|~=+@3x?o1e4G z7yGp;^1^#_`S{^%;<xccv=C=QcyQPoa(QV5(tWdfzgkb8S*+VQ>_`lO9H6bjF4% zZXnf6su-?QsHWM>NEM?}MGQ?WM`qj7OiO5+&`hK4*u>+FEnxt!zu33txr5loNwA61HiioCbetNeg-I8?6QbaA? zk#tAWT_Y7JqK58`tN&i)72K0_&r(D!J&^Q3(gRBoLo@xrA2sx|Ka%vwQba91k@Q5; O6H5`J^!MNF+vY!d*vzW{ delta 204 zcmX}lKMR6T9EIWIpT%DU8ZAL%YY^1Xno1N#NV@CQyLSm1N-9Tby*Ovl7l^)JWsBo^ zc;VdUpDDS48=m`svVGA|y(}hCU`M7$zOx*4U5flo2+>jVSb#ljqhyqeBO?`w$aX9N zX-F$mrgdcKz-sNe;MG8;N@Yn#dcy(uz1^%?9a%CZwGsO-g{&d&$E`P!${Pr>1}`S7nA~~8 zA>QqHrFX$O9FFvH{Cvz#m($DV7h@Xlf3mNMefWL79IvDE>(kxCx9R=s_38P=d`!;2 zvbQo%bLY(Y$M=&7*9~0XnzHbpX9>bFh9<(DDf?;RT*LUzrB1$u!9n;=dKeASn#@;m z1F0rb#c-8;HO?kRsu-0jqHkh3GTW49Ttd_MW*lvXCPt-+=$mpEi}j{bjY~+S8fVi` zjmt;W(v~#i5?a!Xqpi@4t4Gw(b_KOz^=+xf*)~fNwX{Rh4oN#KMXaTOb_v?`P3s?^ zJe4j>5w)~O(jG~BEJf7Ptda(3M$pVy+S81sIZ1Pp<}5|j(t@OgG$XXoQ0pABmi9^7 zCuyIhh*~-z>42nz(2Q>+qHo@sYX65M9g=j&Qba8sk#t1Tk(N4#sG(!ul>L_jG$!eo zrHEQulC&gg$x_514f{VK=)_okPA4oy)Y2(QrzD-S6j4iO(u~J+rlHo&Sc<5nbCS+U zI%g@OmM%!TkY?QeMGdub_K>x7Nzx@rmn=op(iKTpTIyB|MMTrqKfP;`u1UIPDWaBc zNV*~Erj`m6QA4-JR(~(@3T{cdWhtVT?nt^L>5ip{z8Qbu_Zs@s?Mb?4DWaAhNO~aY Ofu)E+`uAUQv;PnBGR&(0 delta 204 zcmX@=zr=~lCDpdSNqn$Vynr`XfU~E8hznPIKu`!nfe=$eLIFeK zA}7wNiChf@Rf$|o3`qsmMTtoaT+9r~3j`)70~K+yFfjP|dAl&AEKr%8%(y^sav~QC zTsW8^Wg#z|=Ll3JI60Y%2`=IU5-|n}F~fzN8Bz*rE0eec7`XrcXXr>_U?`|g1X|dU W!pKmN(vgtJP@1?TVRIL!wHyFm@-w3V diff --git a/tests/data/acpi/x86/pc/DSDT.hpbridge b/tests/data/acpi/x86/pc/DSDT.hpbridge index 8012b5eb3155377dc7995b73059ecb267d19232c..db420593a3c51eced25cd57420353fbb9ccdf63c 100644 GIT binary patch delta 1914 zcmY+_OK#gR6a`RPmVc7`lmCBY0RcMb2I4q_AVv_xnHyb0GiNu@S;rZ514UQWMHI~C zqbR&P)3x7)ctp|u|MlaToi3-h{f#k=pMSF3#6EspFURZX{Qh$P_+|R=etmg;GruS2 z@7a$sPjlzY`T6N&!gT}Jccv`-=UIYqjG>8eZ_0jJIM*<~bE%VWVQ>(>lO9Gxv?lXa z+(4>{R54s7UyZYgkt#-|is+kIj?6Zt8JEyBz8OcGp@~sxBKoG>#bUjwRO1p-sm9qf zRO9jywX`M8xP+E8<7g{171l< zlFnI*sHF>%E~FW^e^EoNoIPYMU6OQ3(j`j~wRA<&m6o~{LlM!m^-u4bq-&C{S&FEo z8ivhYmpncVLk?w#ha$=yt1Oejtq}{XFVIb6#2Ula=?mMfPeLkv6cebBWN!)UATdA zS9&Z()Y3jl`y}nN6j4iUC5=!^P-`6Rsby(S(ww9@OA)oSAZa1Z1T8ewd5^561CkC% zI$$ZHmJUfeB+jKF!=a+yD+3IP??;}xIl1nA{Pr> zIG7=2AupWg2vj6EIhl(IF5(0dF$M}T!-bp~QVMD-leh#Jxc~oW=tyB;D5y>ZTG)}o V$WV~dk&wtxnz$rkvn@w1HvlZSGeiIY diff --git a/tests/data/acpi/x86/pc/DSDT.ipmikcs b/tests/data/acpi/x86/pc/DSDT.ipmikcs index 0a891baf458abee4a772ffba7a31914ec22418ec..c2a0330d97d495298889b9e28bde2f90235cea88 100644 GIT binary patch delta 1914 zcmY+_Np9OP7zJQjmM0A!*T9(HZfAgs8kVs6U&j=wlw1s+Qv8IXgf49DosS+l)G50H4c?-T3V5`B5B1^#2^j(KPBkYSba{XEJf7P8A)d(ov{>AOXt#z$8@ft*3DUpsHF>% zE=amyDWaAxNxGC~-2P<)wQ}~5wRA<&6-ietMby$YN!MEH)(k~N(>6c78&(M*=z)(<~2(+*x Wg^{5kr6VDcp)_$x!saecUI_p?z%-Ho diff --git a/tests/data/acpi/x86/pc/DSDT.memhp b/tests/data/acpi/x86/pc/DSDT.memhp index 9b442a64cf711b33d80691fe84f1d3a6256f943b..c15a9fae947bb3929a30c60b7c0f2092705868f8 100644 GIT binary patch delta 1914 zcmY+_OK#gR6a`RPmVc7`ljZ+!)>(n>ph)5jf;dG`XKr*2&756{N8LctRdo>sbNMI= z@6L4XcOf28wEus-y=14$>FxH(nAY>3>~mtDZr98Gb#i`xeR%p(J-%OGzrUH^v-8jF zSDB}|bLRZ*`DDU%3)gq1Ed1wLf^Z*08{xr}!?bX&Wqjw-B;Uf|D10Y9jD~1U=Bv1Y zR1>LUxK6$rXA>h;j7k;JH?bU2FKj< zN}r{OS~?)uTHl61;a zL@g~zT9UM6DPoX@{htwZW~@G^GnOK1X+_eCq!mjMwRA4ccueOSYTcZrh+4WJ>4KyS zmLh8DlB7#%#_eA=P%CE-SxZ+WU6FLfQba9XlXR`6Zp~0cG;QQGoA>8@Ar16+cJlE_h7FRfwG3q;Q+W{czb z@P+f()(i4NFRDj?Qh#WoURU!tbYjz|z+F#mkK$k-K@8L)5nwOJxHBrmnURWA?Y%p_#KQDLUu|imo8b=_=UE zM^Siprfa_o@ra`R>+a*2oi3-hj~inew|}xviGBKcy*yk;=l7S#r_a+b@7I^tH}iXP z{+|6P^E7wPoS(m*Ot@~~`e@3+f1V`>4>2?m9!=R#3+EcfcP@4EEesCAchbXXh}LAj ziW^8Zkt&9(%aPfpG~*JQ#y8_=Gc++OO+??6yI8C@m1l6FYiVJTuQ1++`hu5ViZ z0OhH4S&FEoJ(BiF+G8oAmS&YSKr@17#?qc}h9HNGfeN*;d4$zpS zW0oRnX-U$Oq$NucgEZ{_grE~+^*Noe6j4j3B%P9U%2Grvok=qu)0u`^H)AQHmd;5! zC+VD}h+4WJ=|Y-u`xiCT%GpEK(j`fkBwex;QA<}OU1_OXF%%I^TmST~NxCNKnx%+Z zx*_R?q?=kQP(%&g8e9Fn$Sb%d>6WF4TDl|Yj-)%5BKl_hf!}NBH@7G0o~4LddLZe6 Pqz9HF2I=2_$^GI#o+Hc) delta 204 zcmX@;xWI(VCD&(M*=z)(<~2(+*x Wg^{5kr6VDcp)_$x!saecb8!HyWi$f- diff --git a/tests/data/acpi/x86/pc/DSDT.numamem b/tests/data/acpi/x86/pc/DSDT.numamem index 9fc731d3d2bcde5e2612a8ccd81e12098134afe9..8a6b56fe7da18bf42c339d13b863aabf81780527 100644 GIT binary patch delta 1914 zcmY+_OK#gR6a`RPl7Eu?lmCBo0R=kA0^&G>phgkY>DcHRnmN0Yj=F)O-9^V;L{`CG zK8nJ-GhO>#h({FdKX?C5`T2T&`SQ+~R{AS{pV+4#x9jOPzPvs^JbjowzTTccznGuX z%eVY{Rb+*8=JM&|*@WvBuJ27%`p@$O;S@uP@L;MzRyx-*zH@DoZ((p4zLOqCL$oIM zRop-$G&C_PO+??6yI8C@lWJT-Ce=8b zg=$6oNrl8&|1IYbSe_@?Z?9H0qF zCoDzO(u$-NNh_8j25H#;DM6>k>T^0}DWaCnNIE0wjHQTLI+tcVrgIIoZq8CfEnSdw zLDB_F5w&zl(xo)x_AeW#m9vMer7M!INV;MvqL!{ny4F&+W+)<>w)yGZkaR=R4NDQV zbW74LNw(j7|?wRBI?JxTX0MfA=11AoxaukJw714|LL^hnYp PNslZ=4AS3k$=~IF&pOOL delta 204 zcmccWw8fOmCD>2?Y#^ zi<~&8CUP|tR3&mTF(egK7bPY!a4|C^FA$iV3{=F)!oc9;=k3CfvOr~WGUEcl$%$Mn zaN%Hvl!d%-o+D6^;N)a3Cb)T@#0(d5W=JWhtxVz)VBr4$pP?g#fuW!}5olpY W3L`^7N=HH>LuulYgw0)?r^Nv%qBS-E diff --git a/tests/data/acpi/x86/pc/DSDT.roothp b/tests/data/acpi/x86/pc/DSDT.roothp index e654c83ebe40c413b204c711adcefe3f04655e8c..a16b0d9d4becec47fa3cf57ed0077ff6cff88908 100644 GIT binary patch delta 1914 zcmY+_OK#gR6a`RPmVc7`lmGvWIxCPZByk2oj3S6Lce{pW&a5KCqJwUr=$bmnDwxYh zQFwQzYrhNeh@$PDe}B)8=i|%OwK0wVf3vTNefV`b-(E(i*QdLO>*@XL<>~pw{F$77 zW^ZMl=FXYZx5uLi*9~0Xn6mJnX9>b>3{8YPQ})xsxrXtbbDew(gM;v$^e`HtHJPvC z22xF=is35xYMf1sR52=5MBl`6WVR{IxP+$h%{bZ&O^iwt(KqET7VAx=8kdktHO{7? z8kdi#r7da3CA6d&M_Zv8SC6Qn?Fwqc>f2I{vu&0lYH5e09g=ofidahl?Gm)>o7O)- zc`99&B5G-mq&<@MSc<5nStSk7jG&pZw5J(MbCTvH%~^`5r3Fa~X+~(Fq1HKME$x%E zPtrb15w&zc(g8^ap&8#uMBltI)&37jIwa|krHEQOBI$^vBQ13fQA5YRDf=%6XiU;E zOA)oSBxy;~lBI}28uoue(2247oK9GZsHIbqPDwgtDWaCnq#2LtOhc`ku@q5D=Omqz zbk0&lEnSdwA>>+FElB7$LE?J7Gr7M!IwA8H_iioDIe|py>U6XXpQbaA? zkaR=RO)V8DqK0mbt^Qu*72J|^%Th!w-H~)h(j7|?eKY>R?=|#?+mm$9Qba91kn}*( O14|Ku^xsGF{^b*&XU!!5 delta 204 zcmX}lK?;IE7{&4D=*BMsjgAmOiy){Aq_ZfD5OuGkbATaeQ4+e8wo+{^xRNbW7mR=o`1`WfHl&Kh5*x- zn)zn9Pl!jTyZ?QX_DR}jDWaARNID?tfTf7886MtY1-1UUACh#)Qba8sk#t1T5laz| zQb5N99lNGIzNcfBB5G+)(ww9@OA)oSsH7fR5VSB>-th456)c^QbVAYzOA)nnO46w` z!|k7Hs4YumEuE2cM$#Ee5w&zq(m6@zz8Rp1uDLa5{@=17>4KySmLiJu_E-19!X*3V z35|KeV-TiTz1`GDTz$kH_qh6qlii{|;$+9Fk2rZ6>LX5lHTWNnxY^ya H2S4I}`F&X$ delta 354 zcmcbU_Q{*eCD`LRz;$|1)%?FfbHUCkg@$??_=}C`jo@NMtBYT#_(( UnQAtQGiB5Uqcb@dhXo0_6$h@HM|NS8z6b- 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 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index f81f4e2469..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,16 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/x86/pc/DSDT", -"tests/data/acpi/x86/pc/DSDT.acpierst", -"tests/data/acpi/x86/pc/DSDT.acpihmat", -"tests/data/acpi/x86/pc/DSDT.bridge", -"tests/data/acpi/x86/pc/DSDT.cphp", -"tests/data/acpi/x86/pc/DSDT.dimmpxm", -"tests/data/acpi/x86/pc/DSDT.hpbridge", -"tests/data/acpi/x86/pc/DSDT.hpbrroot", -"tests/data/acpi/x86/pc/DSDT.ipmikcs", -"tests/data/acpi/x86/pc/DSDT.memhp", -"tests/data/acpi/x86/pc/DSDT.nohpet", -"tests/data/acpi/x86/pc/DSDT.numamem", -"tests/data/acpi/x86/pc/DSDT.roothp", -"tests/data/acpi/x86/q35/DSDT.cxl", -"tests/data/acpi/x86/q35/DSDT.viot", From 6166799f698512ab35e216b4ff4f7156f47923c6 Mon Sep 17 00:00:00 2001 From: zuoboqun Date: Fri, 16 Aug 2024 15:08:35 +0800 Subject: [PATCH 13/18] vhost_net: configure all host notifiers in a single MR transaction This allows the vhost_net device which has multiple virtqueues to batch the setup of all its host notifiers. This significantly reduces the vhost_net device starting and stoping time, e.g. the time spend on enabling notifiers reduce from 630ms to 75ms and the time spend on disabling notifiers reduce from 441ms to 45ms for a VM with 192 vCPUs and 15 vhost-user-net devices (64vq per device) in our case. Signed-off-by: zuoboqun Message-Id: <20240816070835.8309-1-zuoboqun@baidu.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/vhost_net.c | 155 +++++++++++++++++++++++++++++++++++--- hw/virtio/vhost.c | 6 +- include/hw/virtio/vhost.h | 4 + 3 files changed, 150 insertions(+), 15 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index dedf9ad7c2..997aab0557 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -162,6 +162,135 @@ void vhost_net_save_acked_features(NetClientState *nc) #endif } +static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int nvhosts) +{ + VirtIONet *n = VIRTIO_NET(dev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); + struct vhost_net *net; + struct vhost_dev *hdev; + int r, i, j; + NetClientState *peer; + + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + for (j = 0; j < hdev->nvqs; j++) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j, + false); + if (r < 0) { + error_report("vhost %d VQ %d notifier cleanup failed: %d", + i, j, -r); + } + assert(r >= 0); + } + } + /* + * The transaction expects the ioeventfds to be open when it + * commits. Do it now, before the cleanup loop. + */ + memory_region_transaction_commit(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + for (j = 0; j < hdev->nvqs; j++) { + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j); + } + virtio_device_release_ioeventfd(dev); + } +} + +static int vhost_net_enable_notifiers(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int cvq) +{ + VirtIONet *n = VIRTIO_NET(dev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); + int nvhosts = data_queue_pairs + cvq; + struct vhost_net *net; + struct vhost_dev *hdev; + int r, i, j; + NetClientState *peer; + + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + /* + * We will pass the notifiers to the kernel, make sure that QEMU + * doesn't interfere. + */ + r = virtio_device_grab_ioeventfd(dev); + if (r < 0) { + error_report("binding does not support host notifiers"); + memory_region_transaction_commit(); + goto fail_nvhosts; + } + + for (j = 0; j < hdev->nvqs; j++) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j, + true); + if (r < 0) { + error_report("vhost %d VQ %d notifier binding failed: %d", + i, j, -r); + memory_region_transaction_commit(); + vhost_dev_disable_notifiers_nvqs(hdev, dev, j); + goto fail_nvhosts; + } + } + } + + memory_region_transaction_commit(); + + return 0; +fail_nvhosts: + vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i); + return r; +} + +/* + * Stop processing guest IO notifications in qemu. + * Start processing them in vhost in kernel. + */ +static void vhost_net_disable_notifiers(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int cvq) +{ + vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, + data_queue_pairs + cvq); +} + static int vhost_net_get_fd(NetClientState *backend) { switch (backend->info->type) { @@ -272,11 +401,6 @@ static int vhost_net_start_one(struct vhost_net *net, } } - r = vhost_dev_enable_notifiers(&net->dev, dev); - if (r < 0) { - goto fail_notifiers; - } - r = vhost_dev_start(&net->dev, dev, false); if (r < 0) { goto fail_start; @@ -328,8 +452,6 @@ fail: } vhost_dev_stop(&net->dev, dev, false); fail_start: - vhost_dev_disable_notifiers(&net->dev, dev); -fail_notifiers: return r; } @@ -351,7 +473,6 @@ static void vhost_net_stop_one(struct vhost_net *net, if (net->nc->info->stop) { net->nc->info->stop(net->nc); } - vhost_dev_disable_notifiers(&net->dev, dev); } int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, @@ -396,10 +517,16 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, } } + r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq); + if (r < 0) { + error_report("Error enabling host notifiers: %d", -r); + goto err; + } + r = k->set_guest_notifiers(qbus->parent, total_notifiers, true); if (r < 0) { error_report("Error binding guest notifier: %d", -r); - goto err; + goto err_host_notifiers; } for (i = 0; i < nvhosts; i++) { @@ -414,19 +541,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, r = vhost_set_vring_enable(peer, peer->vring_enable); if (r < 0) { - goto err_start; + goto err_guest_notifiers; } } r = vhost_net_start_one(get_vhost_net(peer), dev); if (r < 0) { - goto err_start; + goto err_guest_notifiers; } } return 0; -err_start: +err_guest_notifiers: while (--i >= 0) { peer = qemu_get_peer(ncs, i < data_queue_pairs ? i : n->max_queue_pairs); @@ -437,6 +564,8 @@ err_start: fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); fflush(stderr); } +err_host_notifiers: + vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); err: return r; } @@ -468,6 +597,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, fflush(stderr); } assert(r >= 0); + + vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); } void vhost_net_cleanup(struct vhost_net *net) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 06fc71746e..7c5ef81b55 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1682,9 +1682,9 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) memset(hdev, 0, sizeof(struct vhost_dev)); } -static void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev, - VirtIODevice *vdev, - unsigned int nvqs) +void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev, + VirtIODevice *vdev, + unsigned int nvqs) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); int i, r; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index d75faf46e9..c75be46c06 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -171,6 +171,10 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, */ void vhost_dev_cleanup(struct vhost_dev *hdev); +void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev, + VirtIODevice *vdev, + unsigned int nvqs); + /** * vhost_dev_enable_notifiers() - enable event notifiers * @hdev: common vhost_dev structure From ffa8a3e3b2e6ff017113b98d500d6a9e05b1560a Mon Sep 17 00:00:00 2001 From: Gao Shiyuan Date: Tue, 3 Sep 2024 20:03:04 +0800 Subject: [PATCH 14/18] virtio-pci: Add lookup subregion of VirtIOPCIRegion MR Now virtio_address_space_lookup only lookup common/isr/device/notify MR and exclude their subregions. When VHOST_USER_PROTOCOL_F_HOST_NOTIFIER enable, the notify MR has host-notifier subregions and we need use host-notifier MR to notify the hardware accelerator directly instead of eventfd notify. Further more, maybe common/isr/device MR also has subregions in the future, so need memory_region_find for each MR incluing their subregions. Add lookup subregion of VirtIOPCIRegion MR instead of only lookup container MR. Fixes: a93c8d8 ("virtio-pci: Replace modern_as with direct access to modern_bar") Co-developed-by: Zuo Boqun Signed-off-by: Gao Shiyuan Signed-off-by: Zuo Boqun Message-Id: <20240903120304.97833-1-gaoshiyuan@baidu.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 524b63e5c7..4d832fe845 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -615,8 +615,12 @@ static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy, reg = &proxy->regs[i]; if (*off >= reg->offset && *off + len <= reg->offset + reg->size) { - *off -= reg->offset; - return ®->mr; + MemoryRegionSection mrs = memory_region_find(®->mr, + *off - reg->offset, len); + assert(mrs.mr); + *off = mrs.offset_within_region; + memory_region_unref(mrs.mr); + return mrs.mr; } } From d29b7f3dd4f95da7173b3f0fb58a7d4dbb093f92 Mon Sep 17 00:00:00 2001 From: peng guo Date: Sun, 25 Aug 2024 18:22:12 +0800 Subject: [PATCH 15/18] hw/cxl: fix physical address field in get scan media results output When using the mailbox command get scan media results, the scan media restart physical address field in the ouput palyload is not 64-byte aligned. This patch removed the error source of the restart physical address. The Scan Media Restart Physical Address is the location from which the host should restart the Scan Media operation. [5:0] bits are reserved. Refer to CXL spec r3.1 Table 8-146 Fixes: 89b5cfcc31e6 ("hw/cxl: Add get scan media results cmd support") Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/linux-cxl/20240819154206.16456-1-engguopeng@buaa.edu.cn/ Signed-off-by: peng guo Message-Id: <20240825102212.3871-1-engguopeng@buaa.edu.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 3ebbd32e10..9258e48f95 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -2076,7 +2076,7 @@ static CXLRetCode cmd_media_get_scan_media_results(const struct cxl_cmd *cmd, start = ROUND_DOWN(ent->start, 64ull); stop = ROUND_DOWN(ent->start, 64ull) + ent->length; - stq_le_p(&out->records[i].addr, start | (ent->type & 0x7)); + stq_le_p(&out->records[i].addr, start); stl_le_p(&out->records[i].length, (stop - start) / CXL_CACHE_LINE_SIZE); i++; From 7fc6611cad3e9627b23ce83e550b668abba6c886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sun, 1 Sep 2024 15:01:12 +0200 Subject: [PATCH 16/18] hw/audio/virtio-sound: fix heap buffer overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the guest may write to the device configuration space, whereas the virtio sound device specification in chapter 5.14.4 clearly states that the fields in the device configuration space are driver-read-only. Remove the set_config function from the virtio_snd class. This also prevents a heap buffer overflow. See QEMU issue #2296. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2296 Signed-off-by: Volker Rümelin Message-Id: <20240901130112.8242-1-vr_qemu@t-online.de> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/audio/trace-events | 1 - hw/audio/virtio-snd.c | 24 ------------------------ 2 files changed, 25 deletions(-) diff --git a/hw/audio/trace-events b/hw/audio/trace-events index b1870ff224..b8ef572767 100644 --- a/hw/audio/trace-events +++ b/hw/audio/trace-events @@ -41,7 +41,6 @@ asc_update_irq(int irq, int a, int b) "set IRQ to %d (A: 0x%x B: 0x%x)" #virtio-snd.c virtio_snd_get_config(void *vdev, uint32_t jacks, uint32_t streams, uint32_t chmaps) "snd %p: get_config jacks=%"PRIu32" streams=%"PRIu32" chmaps=%"PRIu32"" -virtio_snd_set_config(void *vdev, uint32_t jacks, uint32_t new_jacks, uint32_t streams, uint32_t new_streams, uint32_t chmaps, uint32_t new_chmaps) "snd %p: set_config jacks from %"PRIu32"->%"PRIu32", streams from %"PRIu32"->%"PRIu32", chmaps from %"PRIu32"->%"PRIu32 virtio_snd_get_features(void *vdev, uint64_t features) "snd %p: get_features 0x%"PRIx64 virtio_snd_vm_state_running(void) "vm state running" virtio_snd_vm_state_stopped(void) "vm state stopped" diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c index d1cf5eb445..69838181dd 100644 --- a/hw/audio/virtio-snd.c +++ b/hw/audio/virtio-snd.c @@ -107,29 +107,6 @@ virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config) } -static void -virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config) -{ - VirtIOSound *s = VIRTIO_SND(vdev); - const virtio_snd_config *sndconfig = - (const virtio_snd_config *)config; - - - trace_virtio_snd_set_config(vdev, - s->snd_conf.jacks, - sndconfig->jacks, - s->snd_conf.streams, - sndconfig->streams, - s->snd_conf.chmaps, - sndconfig->chmaps); - - memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config)); - le32_to_cpus(&s->snd_conf.jacks); - le32_to_cpus(&s->snd_conf.streams); - le32_to_cpus(&s->snd_conf.chmaps); - -} - static void virtio_snd_pcm_buffer_free(VirtIOSoundPCMBuffer *buffer) { @@ -1400,7 +1377,6 @@ static void virtio_snd_class_init(ObjectClass *klass, void *data) vdc->realize = virtio_snd_realize; vdc->unrealize = virtio_snd_unrealize; vdc->get_config = virtio_snd_get_config; - vdc->set_config = virtio_snd_set_config; vdc->get_features = get_features; vdc->reset = virtio_snd_reset; vdc->legacy_features = 0; From 95b717a8154b955de2782305f305b63f357b0576 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 10 Sep 2024 18:34:33 +0200 Subject: [PATCH 17/18] virtio-mem: don't warn about THP sizes on a kernel without THP support If the config directory in sysfs does not exist at all, we are dealing with a system that does not support THPs. Simply use 1 MiB block size then, instead of warning "Could not detect THP size, falling back to ..." and falling back to the default THP size. Cc: "Michael S. Tsirkin" Cc: Gavin Shan Cc: Juraj Marcin Signed-off-by: David Hildenbrand Message-Id: <20240910163433.2100295-1-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mem.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index ef64bf1b4a..4075f3d4ce 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -88,6 +88,7 @@ static uint32_t virtio_mem_default_thp_size(void) static uint32_t thp_size; #define HPAGE_PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size" +#define HPAGE_PATH "/sys/kernel/mm/transparent_hugepage/" static uint32_t virtio_mem_thp_size(void) { gchar *content = NULL; @@ -98,6 +99,12 @@ static uint32_t virtio_mem_thp_size(void) return thp_size; } + /* No THP -> no restrictions. */ + if (!g_file_test(HPAGE_PATH, G_FILE_TEST_EXISTS)) { + thp_size = VIRTIO_MEM_MIN_BLOCK_SIZE; + return thp_size; + } + /* * Try to probe the actual THP size, fallback to (sane but eventually * incorrect) default sizes. From 6e3c2d58e967cde3dadae298e81c5e8eb9fb9080 Mon Sep 17 00:00:00 2001 From: Dominic Prinz Date: Tue, 10 Sep 2024 20:08:20 +0200 Subject: [PATCH 18/18] hw/acpi/ich9: Add periodic and swsmi timer This patch implements the periodic and the swsmi ICH9 chipset timers. They are especially useful when prototyping UEFI firmware (e.g. with EDK2's OVMF) using QEMU. For backwards compatibility, the compat properties "x-smi-swsmi-timer", and "x-smi-periodic-timer" are introduced. Additionally, writes to the SMI_STS register are enabled for the corresponding two bits using a write mask to make future work easier. Signed-off-by: Dominic Prinz Message-Id: <1d90ea69e01ab71a0f2ced116801dc78e04f4448.1725991505.git.git@dprinz.de> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/ich9.c | 23 +++++++++ hw/acpi/ich9_timer.c | 93 +++++++++++++++++++++++++++++++++++ hw/acpi/meson.build | 2 +- hw/i386/pc.c | 5 +- hw/isa/lpc_ich9.c | 14 ++++++ include/hw/acpi/ich9.h | 6 +++ include/hw/acpi/ich9_timer.h | 23 +++++++++ include/hw/southbridge/ich9.h | 4 ++ 8 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 hw/acpi/ich9_timer.c create mode 100644 include/hw/acpi/ich9_timer.h diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 02d8546bd3..c15e5b8281 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -35,6 +35,7 @@ #include "sysemu/runstate.h" #include "hw/acpi/acpi.h" #include "hw/acpi/ich9_tco.h" +#include "hw/acpi/ich9_timer.h" #include "hw/southbridge/ich9.h" #include "hw/mem/pc-dimm.h" @@ -108,6 +109,18 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val, } pm->smi_en &= ~pm->smi_en_wmask; pm->smi_en |= (val & pm->smi_en_wmask); + if (pm->swsmi_timer_enabled) { + ich9_pm_update_swsmi_timer(pm, pm->smi_en & + ICH9_PMIO_SMI_EN_SWSMI_EN); + } + if (pm->periodic_timer_enabled) { + ich9_pm_update_periodic_timer(pm, pm->smi_en & + ICH9_PMIO_SMI_EN_PERIODIC_EN); + } + break; + case 4: + pm->smi_sts &= ~pm->smi_sts_wmask; + pm->smi_sts |= (val & pm->smi_sts_wmask); break; } } @@ -286,6 +299,8 @@ static void pm_powerdown_req(Notifier *n, void *opaque) void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq) { + pm->smi_sts_wmask = 0; + memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE); memory_region_set_enabled(&pm->io, false); memory_region_add_subregion(pci_address_space_io(lpc_pci), @@ -305,6 +320,14 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq) "acpi-smi", 8); memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); + if (pm->swsmi_timer_enabled) { + ich9_pm_swsmi_timer_init(pm); + } + + if (pm->periodic_timer_enabled) { + ich9_pm_periodic_timer_init(pm); + } + if (pm->enable_tco) { acpi_pm_tco_init(&pm->tco_regs, &pm->io); } diff --git a/hw/acpi/ich9_timer.c b/hw/acpi/ich9_timer.c new file mode 100644 index 0000000000..5b1c910156 --- /dev/null +++ b/hw/acpi/ich9_timer.c @@ -0,0 +1,93 @@ +/* + * QEMU ICH9 Timer emulation + * + * Copyright (c) 2024 Dominic Prinz + * + * 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 "hw/core/cpu.h" +#include "hw/pci/pci.h" +#include "hw/southbridge/ich9.h" +#include "qemu/timer.h" + +#include "hw/acpi/ich9_timer.h" + +void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable) +{ + uint16_t swsmi_rate_sel; + int64_t expire_time; + ICH9LPCState *lpc; + + if (enable) { + lpc = container_of(pm, ICH9LPCState, pm); + swsmi_rate_sel = + (pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_3) & 0xc0) >> 6; + + if (swsmi_rate_sel == 0) { + expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1500000LL; + } else { + expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + 8 * (1 << swsmi_rate_sel) * 1000000LL; + } + + timer_mod(pm->swsmi_timer, expire_time); + } else { + timer_del(pm->swsmi_timer); + } +} + +static void ich9_pm_swsmi_timer_expired(void *opaque) +{ + ICH9LPCPMRegs *pm = opaque; + + pm->smi_sts |= ICH9_PMIO_SMI_STS_SWSMI_STS; + ich9_generate_smi(); + + ich9_pm_update_swsmi_timer(pm, pm->smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN); +} + +void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm) +{ + pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_SWSMI_STS; + pm->swsmi_timer = + timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_swsmi_timer_expired, pm); +} + +void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable) +{ + uint16_t per_smi_sel; + int64_t expire_time; + ICH9LPCState *lpc; + + if (enable) { + lpc = container_of(pm, ICH9LPCState, pm); + per_smi_sel = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1) & 3; + expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + 8 * (1 << (3 - per_smi_sel)) * NANOSECONDS_PER_SECOND; + + timer_mod(pm->periodic_timer, expire_time); + } else { + timer_del(pm->periodic_timer); + } +} + +static void ich9_pm_periodic_timer_expired(void *opaque) +{ + ICH9LPCPMRegs *pm = opaque; + + pm->smi_sts = ICH9_PMIO_SMI_STS_PERIODIC_STS; + ich9_generate_smi(); + + ich9_pm_update_periodic_timer(pm, + pm->smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN); +} + +void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm) +{ + pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_PERIODIC_STS; + pm->periodic_timer = + timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_periodic_timer_expired, pm); +} diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index fa5c07db90..7f8ccc9b7a 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -24,7 +24,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c')) -acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c')) +acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c', 'ich9_timer.c')) acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c')) acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c')) acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index ba0ff51183..8d84c22458 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -79,7 +79,10 @@ { "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ { "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, }, -GlobalProperty pc_compat_9_1[] = {}; +GlobalProperty pc_compat_9_1[] = { + { "ICH9-LPC", "x-smi-swsmi-timer", "off" }, + { "ICH9-LPC", "x-smi-periodic-timer", "off" }, +}; const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1); GlobalProperty pc_compat_9_0[] = { diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index bd727b2320..ab17b76f54 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -43,6 +43,7 @@ #include "hw/southbridge/ich9.h" #include "hw/acpi/acpi.h" #include "hw/acpi/ich9.h" +#include "hw/acpi/ich9_timer.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" #include "sysemu/runstate.h" @@ -531,6 +532,15 @@ ich9_lpc_pmcon_update(ICH9LPCState *lpc) uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1); uint16_t wmask; + if (lpc->pm.swsmi_timer_enabled) { + ich9_pm_update_swsmi_timer( + &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN); + } + if (lpc->pm.periodic_timer_enabled) { + ich9_pm_update_periodic_timer( + &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN); + } + if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) { wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1); wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK; @@ -826,6 +836,10 @@ static Property ich9_lpc_properties[] = { ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT, true), DEFINE_PROP_BIT64("x-smi-cpu-hotunplug", ICH9LPCState, smi_host_features, ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT, true), + DEFINE_PROP_BOOL("x-smi-swsmi-timer", ICH9LPCState, + pm.swsmi_timer_enabled, true), + DEFINE_PROP_BOOL("x-smi-periodic-timer", ICH9LPCState, + pm.periodic_timer_enabled, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index 2faf7f0cae..245fe08dc2 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -46,6 +46,7 @@ typedef struct ICH9LPCPMRegs { uint32_t smi_en; uint32_t smi_en_wmask; uint32_t smi_sts; + uint32_t smi_sts_wmask; qemu_irq irq; /* SCI */ @@ -68,6 +69,11 @@ typedef struct ICH9LPCPMRegs { bool smm_compat; bool enable_tco; TCOIORegs tco_regs; + + bool swsmi_timer_enabled; + bool periodic_timer_enabled; + QEMUTimer *swsmi_timer; + QEMUTimer *periodic_timer; } ICH9LPCPMRegs; #define ACPI_PM_PROP_TCO_ENABLED "enable_tco" diff --git a/include/hw/acpi/ich9_timer.h b/include/hw/acpi/ich9_timer.h new file mode 100644 index 0000000000..5112df4385 --- /dev/null +++ b/include/hw/acpi/ich9_timer.h @@ -0,0 +1,23 @@ +/* + * QEMU ICH9 Timer emulation + * + * Copyright (c) 2024 Dominic Prinz + * + * 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 HW_ACPI_ICH9_TIMER_H +#define HW_ACPI_ICH9_TIMER_H + +#include "hw/acpi/ich9.h" + +void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable); + +void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm); + +void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable); + +void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm); + +#endif diff --git a/include/hw/southbridge/ich9.h b/include/hw/southbridge/ich9.h index fd01649d04..6c60017024 100644 --- a/include/hw/southbridge/ich9.h +++ b/include/hw/southbridge/ich9.h @@ -196,8 +196,12 @@ struct ICH9LPCState { #define ICH9_PMIO_GPE0_LEN 16 #define ICH9_PMIO_SMI_EN 0x30 #define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5) +#define ICH9_PMIO_SMI_EN_SWSMI_EN (1 << 6) #define ICH9_PMIO_SMI_EN_TCO_EN (1 << 13) +#define ICH9_PMIO_SMI_EN_PERIODIC_EN (1 << 14) #define ICH9_PMIO_SMI_STS 0x34 +#define ICH9_PMIO_SMI_STS_SWSMI_STS (1 << 6) +#define ICH9_PMIO_SMI_STS_PERIODIC_STS (1 << 14) #define ICH9_PMIO_TCO_RLD 0x60 #define ICH9_PMIO_TCO_LEN 32