Since Linux commit 7d5ec3d36123 ("PCI/MSI: Mask all unused MSI-X
entries"), kvmtool segfaults when the guest boots and tries to
disable all the MSI-X entries of a virtio device while MSI-X itself
is disabled.

What Linux does is seems perfectly correct. However, kvmtool uses
a different decoding depending on whether MSI-X is enabled for
this device or not. Which seems pretty wrong.

Cure the problem by removing the check against MSI-X being enabled,
and simplify the whole logic which looked a bit odd. With this,
Linux is back booting as a kvmtool guest with MSI-X.

Cc: Andre Przywara <[email protected]>
Cc: Alexandru Elisei <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Will Deacon <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
---
 include/kvm/virtio.h |  2 +-
 virtio/core.c        | 12 ++++--------
 virtio/pci.c         |  7 ++-----
 3 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index 3a311f54..7047d36f 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -166,7 +166,7 @@ u16 virt_queue__get_head_iov(struct virt_queue *vq, struct 
iovec iov[],
 u16 virt_queue__get_inout_iov(struct kvm *kvm, struct virt_queue *queue,
                              struct iovec in_iov[], struct iovec out_iov[],
                              u16 *in, u16 *out);
-int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off);
+int virtio__get_dev_specific_field(int offset, u32 *config_off);
 
 enum virtio_trans {
        VIRTIO_PCI,
diff --git a/virtio/core.c b/virtio/core.c
index 90a661d1..afb09e90 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -169,16 +169,12 @@ void virtio_exit_vq(struct kvm *kvm, struct virtio_device 
*vdev,
        memset(vq, 0, sizeof(*vq));
 }
 
-int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off)
+int virtio__get_dev_specific_field(int offset, u32 *config_off)
 {
-       if (msix) {
-               if (offset < 4)
-                       return VIRTIO_PCI_O_MSIX;
-               else
-                       offset -= 4;
-       }
+       if (offset < 24)
+               return VIRTIO_PCI_O_MSIX;
 
-       *config_off = offset;
+       *config_off = offset - 24;
 
        return VIRTIO_PCI_O_CONFIG;
 }
diff --git a/virtio/pci.c b/virtio/pci.c
index eb91f512..2a6e41f1 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -112,9 +112,7 @@ static bool virtio_pci__specific_data_in(struct kvm *kvm, 
struct virtio_device *
 {
        u32 config_offset;
        struct virtio_pci *vpci = vdev->virtio;
-       int type = virtio__get_dev_specific_field(offset - 20,
-                                                       
virtio_pci__msix_enabled(vpci),
-                                                       &config_offset);
+       int type = virtio__get_dev_specific_field(offset, &config_offset);
        if (type == VIRTIO_PCI_O_MSIX) {
                switch (offset) {
                case VIRTIO_MSI_CONFIG_VECTOR:
@@ -208,8 +206,7 @@ static bool virtio_pci__specific_data_out(struct kvm *kvm, 
struct virtio_device
        struct virtio_pci *vpci = vdev->virtio;
        u32 config_offset, vec;
        int gsi;
-       int type = virtio__get_dev_specific_field(offset - 20, 
virtio_pci__msix_enabled(vpci),
-                                                       &config_offset);
+       int type = virtio__get_dev_specific_field(offset, &config_offset);
        if (type == VIRTIO_PCI_O_MSIX) {
                switch (offset) {
                case VIRTIO_MSI_CONFIG_VECTOR:
-- 
2.30.2

_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to