kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X
@ 2021-08-27 11:54 Marc Zyngier
  2021-08-31 11:10 ` Andre Przywara
  2021-08-31 15:05 ` Will Deacon
  0 siblings, 2 replies; 5+ messages in thread
From: Marc Zyngier @ 2021-08-27 11:54 UTC (permalink / raw)
  To: kvm, kvmarm; +Cc: Andre Przywara, Alexandru Elisei, Will Deacon

Since 45d3b59e8c45 ("kvm tools: Increase amount of possible interrupts
per PCI device"), the number of MSI-S has gone from 4 to 33.

However, the corresponding storage hasn't been upgraded, and writing
to the MSI-X table is a pretty risky business. Now that the Linux
kernel writes to *all* MSI-X entries before doing anything else
with the device, kvmtool dies a horrible death.

Fix it by properly defining the size of the MSI-X bar, and make
Linux great again.

This includes some fixes the PBA region decoding, as well as minor
cleanups to make this code a bit more maintainable.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 virtio/pci.c | 42 ++++++++++++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/virtio/pci.c b/virtio/pci.c
index eb91f512..41085291 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -7,6 +7,7 @@
 #include "kvm/irq.h"
 #include "kvm/virtio.h"
 #include "kvm/ioeventfd.h"
+#include "kvm/util.h"
 
 #include <sys/ioctl.h>
 #include <linux/virtio_pci.h>
@@ -14,6 +15,13 @@
 #include <assert.h>
 #include <string.h>
 
+#define ALIGN_UP(x, s)		ALIGN((x) + (s) - 1, (s))
+#define VIRTIO_NR_MSIX		(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG)
+#define VIRTIO_MSIX_TABLE_SIZE	(VIRTIO_NR_MSIX * 16)
+#define VIRTIO_MSIX_PBA_SIZE	(ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8)
+#define VIRTIO_MSIX_BAR_SIZE	(1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \
+						 VIRTIO_MSIX_PBA_SIZE))
+
 static u16 virtio_pci__port_addr(struct virtio_pci *vpci)
 {
 	return pci__bar_address(&vpci->pci_hdr, 0);
@@ -333,18 +341,27 @@ static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
 	struct virtio_pci *vpci = vdev->virtio;
 	struct msix_table *table;
 	u32 msix_io_addr = virtio_pci__msix_io_addr(vpci);
+	u32 pba_offset;
 	int vecnum;
 	size_t offset;
 
-	if (addr > msix_io_addr + PCI_IO_SIZE) {
+	BUILD_BUG_ON(VIRTIO_NR_MSIX > (sizeof(vpci->msix_pba) * 8));
+
+	pba_offset = vpci->pci_hdr.msix.pba_offset & ~PCI_MSIX_TABLE_BIR;
+	if (addr >= msix_io_addr + pba_offset) {
+		/* Read access to PBA */
 		if (is_write)
 			return;
-		table  = (struct msix_table *)&vpci->msix_pba;
-		offset = addr - (msix_io_addr + PCI_IO_SIZE);
-	} else {
-		table  = vpci->msix_table;
-		offset = addr - msix_io_addr;
+		offset = addr - (msix_io_addr + pba_offset);
+		if ((offset + len) > sizeof (vpci->msix_pba))
+			return;
+		memcpy(data, (void *)&vpci->msix_pba + offset, len);
+		return;
 	}
+
+	table  = vpci->msix_table;
+	offset = addr - msix_io_addr;
+
 	vecnum = offset / sizeof(struct msix_table);
 	offset = offset % sizeof(struct msix_table);
 
@@ -520,7 +537,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 
 	port_addr = pci_get_io_port_block(PCI_IO_SIZE);
 	mmio_addr = pci_get_mmio_block(PCI_IO_SIZE);
-	msix_io_block = pci_get_mmio_block(PCI_IO_SIZE * 2);
+	msix_io_block = pci_get_mmio_block(VIRTIO_MSIX_BAR_SIZE);
 
 	vpci->pci_hdr = (struct pci_device_header) {
 		.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
@@ -543,7 +560,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
 		.bar_size[0]		= cpu_to_le32(PCI_IO_SIZE),
 		.bar_size[1]		= cpu_to_le32(PCI_IO_SIZE),
-		.bar_size[2]		= cpu_to_le32(PCI_IO_SIZE*2),
+		.bar_size[2]		= cpu_to_le32(VIRTIO_MSIX_BAR_SIZE),
 	};
 
 	r = pci__register_bar_regions(kvm, &vpci->pci_hdr,
@@ -560,8 +577,9 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
 	vpci->pci_hdr.msix.next = 0;
 	/*
-	 * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
-	 * VIRTIO_PCI_MAX_CONFIG entries for config.
+	 * We at most have VIRTIO_NR_MSIX entries (VIRTIO_PCI_MAX_VQ
+	 * entries for virt queue, VIRTIO_PCI_MAX_CONFIG entries for
+	 * config).
 	 *
 	 * To quote the PCI spec:
 	 *
@@ -570,11 +588,11 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
 	 * For example, a returned value of "00000000011"
 	 * indicates a table size of 4.
 	 */
-	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
+	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_NR_MSIX - 1);
 
 	/* Both table and PBA are mapped to the same BAR (2) */
 	vpci->pci_hdr.msix.table_offset = cpu_to_le32(2);
-	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | PCI_IO_SIZE);
+	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | VIRTIO_MSIX_TABLE_SIZE);
 	vpci->config_vector = 0;
 
 	if (irq__can_signal_msi(kvm))
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X
  2021-08-27 11:54 [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X Marc Zyngier
@ 2021-08-31 11:10 ` Andre Przywara
  2021-08-31 11:28   ` Marc Zyngier
  2021-08-31 15:05 ` Will Deacon
  1 sibling, 1 reply; 5+ messages in thread
From: Andre Przywara @ 2021-08-31 11:10 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, kvmarm, Alexandru Elisei, Will Deacon

On Fri, 27 Aug 2021 12:54:05 +0100
Marc Zyngier <maz@kernel.org> wrote:

Hi Marc,

> Since 45d3b59e8c45 ("kvm tools: Increase amount of possible interrupts
> per PCI device"), the number of MSI-S has gone from 4 to 33.
> 
> However, the corresponding storage hasn't been upgraded, and writing
> to the MSI-X table is a pretty risky business. Now that the Linux
> kernel writes to *all* MSI-X entries before doing anything else
> with the device, kvmtool dies a horrible death.
> 
> Fix it by properly defining the size of the MSI-X bar, and make
> Linux great again.
> 
> This includes some fixes the PBA region decoding, as well as minor
> cleanups to make this code a bit more maintainable.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>

Many thanks for fixing this, it looks good to me now. Just some
questions below:

> ---
>  virtio/pci.c | 42 ++++++++++++++++++++++++++++++------------
>  1 file changed, 30 insertions(+), 12 deletions(-)
> 
> diff --git a/virtio/pci.c b/virtio/pci.c
> index eb91f512..41085291 100644
> --- a/virtio/pci.c
> +++ b/virtio/pci.c
> @@ -7,6 +7,7 @@
>  #include "kvm/irq.h"
>  #include "kvm/virtio.h"
>  #include "kvm/ioeventfd.h"
> +#include "kvm/util.h"
>  
>  #include <sys/ioctl.h>
>  #include <linux/virtio_pci.h>
> @@ -14,6 +15,13 @@
>  #include <assert.h>
>  #include <string.h>
>  
> +#define ALIGN_UP(x, s)		ALIGN((x) + (s) - 1, (s))
> +#define VIRTIO_NR_MSIX		(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG)
> +#define VIRTIO_MSIX_TABLE_SIZE	(VIRTIO_NR_MSIX * 16)
> +#define VIRTIO_MSIX_PBA_SIZE	(ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8)
> +#define VIRTIO_MSIX_BAR_SIZE	(1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \
> +						 VIRTIO_MSIX_PBA_SIZE))
> +
>  static u16 virtio_pci__port_addr(struct virtio_pci *vpci)
>  {
>  	return pci__bar_address(&vpci->pci_hdr, 0);
> @@ -333,18 +341,27 @@ static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
>  	struct virtio_pci *vpci = vdev->virtio;
>  	struct msix_table *table;
>  	u32 msix_io_addr = virtio_pci__msix_io_addr(vpci);
> +	u32 pba_offset;
>  	int vecnum;
>  	size_t offset;
>  
> -	if (addr > msix_io_addr + PCI_IO_SIZE) {

Ouch, the missing "=" looks like another long standing bug you fixed, I
wonder how this ever worked before? Looking deeper it looks like the
whole PBA code was quite broken (allowing writes, for instance, and
mixing with the code for the MSIX table)?

> +	BUILD_BUG_ON(VIRTIO_NR_MSIX > (sizeof(vpci->msix_pba) * 8));
> +
> +	pba_offset = vpci->pci_hdr.msix.pba_offset & ~PCI_MSIX_TABLE_BIR;

Any particular reason you read back the offset from the MSIX capability
instead of just using VIRTIO_MSIX_TABLE_SIZE here? Is that to avoid
accidentally diverging in the future, by having just one place of
definition?

> +	if (addr >= msix_io_addr + pba_offset) {
> +		/* Read access to PBA */
>  		if (is_write)
>  			return;
> -		table  = (struct msix_table *)&vpci->msix_pba;
> -		offset = addr - (msix_io_addr + PCI_IO_SIZE);
> -	} else {
> -		table  = vpci->msix_table;
> -		offset = addr - msix_io_addr;
> +		offset = addr - (msix_io_addr + pba_offset);
> +		if ((offset + len) > sizeof (vpci->msix_pba))
> +			return;
> +		memcpy(data, (void *)&vpci->msix_pba + offset, len);

Should this be a char* cast, since pointer arithmetic on void* is
somewhat frowned upon (aka "forbidden in the C standard, but allowed as
a GCC extension")?

Cheers,
Andre

> +		return;
>  	}
> +
> +	table  = vpci->msix_table;
> +	offset = addr - msix_io_addr;
> +
>  	vecnum = offset / sizeof(struct msix_table);
>  	offset = offset % sizeof(struct msix_table);
>  
> @@ -520,7 +537,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
>  
>  	port_addr = pci_get_io_port_block(PCI_IO_SIZE);
>  	mmio_addr = pci_get_mmio_block(PCI_IO_SIZE);
> -	msix_io_block = pci_get_mmio_block(PCI_IO_SIZE * 2);
> +	msix_io_block = pci_get_mmio_block(VIRTIO_MSIX_BAR_SIZE);
>  
>  	vpci->pci_hdr = (struct pci_device_header) {
>  		.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
> @@ -543,7 +560,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
>  		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
>  		.bar_size[0]		= cpu_to_le32(PCI_IO_SIZE),
>  		.bar_size[1]		= cpu_to_le32(PCI_IO_SIZE),
> -		.bar_size[2]		= cpu_to_le32(PCI_IO_SIZE*2),
> +		.bar_size[2]		= cpu_to_le32(VIRTIO_MSIX_BAR_SIZE),
>  	};
>  
>  	r = pci__register_bar_regions(kvm, &vpci->pci_hdr,
> @@ -560,8 +577,9 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
>  	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
>  	vpci->pci_hdr.msix.next = 0;
>  	/*
> -	 * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
> -	 * VIRTIO_PCI_MAX_CONFIG entries for config.
> +	 * We at most have VIRTIO_NR_MSIX entries (VIRTIO_PCI_MAX_VQ
> +	 * entries for virt queue, VIRTIO_PCI_MAX_CONFIG entries for
> +	 * config).
>  	 *
>  	 * To quote the PCI spec:
>  	 *
> @@ -570,11 +588,11 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
>  	 * For example, a returned value of "00000000011"
>  	 * indicates a table size of 4.
>  	 */
> -	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
> +	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_NR_MSIX - 1);
>  
>  	/* Both table and PBA are mapped to the same BAR (2) */
>  	vpci->pci_hdr.msix.table_offset = cpu_to_le32(2);
> -	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | PCI_IO_SIZE);
> +	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | VIRTIO_MSIX_TABLE_SIZE);
>  	vpci->config_vector = 0;
>  
>  	if (irq__can_signal_msi(kvm))


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X
  2021-08-31 11:10 ` Andre Przywara
@ 2021-08-31 11:28   ` Marc Zyngier
  2021-08-31 11:39     ` Andre Przywara
  0 siblings, 1 reply; 5+ messages in thread
From: Marc Zyngier @ 2021-08-31 11:28 UTC (permalink / raw)
  To: Andre Przywara; +Cc: kvm, kvmarm, Alexandru Elisei, Will Deacon

Hi Andre,

On Tue, 31 Aug 2021 12:10:35 +0100,
Andre Przywara <andre.przywara@arm.com> wrote:
> 
> On Fri, 27 Aug 2021 12:54:05 +0100
> Marc Zyngier <maz@kernel.org> wrote:
> 
> Hi Marc,
> 
> > Since 45d3b59e8c45 ("kvm tools: Increase amount of possible interrupts
> > per PCI device"), the number of MSI-S has gone from 4 to 33.
> > 
> > However, the corresponding storage hasn't been upgraded, and writing
> > to the MSI-X table is a pretty risky business. Now that the Linux
> > kernel writes to *all* MSI-X entries before doing anything else
> > with the device, kvmtool dies a horrible death.
> > 
> > Fix it by properly defining the size of the MSI-X bar, and make
> > Linux great again.
> > 
> > This includes some fixes the PBA region decoding, as well as minor
> > cleanups to make this code a bit more maintainable.
> > 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> 
> Many thanks for fixing this, it looks good to me now. Just some
> questions below:
> 
> > ---
> >  virtio/pci.c | 42 ++++++++++++++++++++++++++++++------------
> >  1 file changed, 30 insertions(+), 12 deletions(-)
> > 
> > diff --git a/virtio/pci.c b/virtio/pci.c
> > index eb91f512..41085291 100644
> > --- a/virtio/pci.c
> > +++ b/virtio/pci.c
> > @@ -7,6 +7,7 @@
> >  #include "kvm/irq.h"
> >  #include "kvm/virtio.h"
> >  #include "kvm/ioeventfd.h"
> > +#include "kvm/util.h"
> >  
> >  #include <sys/ioctl.h>
> >  #include <linux/virtio_pci.h>
> > @@ -14,6 +15,13 @@
> >  #include <assert.h>
> >  #include <string.h>
> >  
> > +#define ALIGN_UP(x, s)		ALIGN((x) + (s) - 1, (s))
> > +#define VIRTIO_NR_MSIX		(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG)
> > +#define VIRTIO_MSIX_TABLE_SIZE	(VIRTIO_NR_MSIX * 16)
> > +#define VIRTIO_MSIX_PBA_SIZE	(ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8)
> > +#define VIRTIO_MSIX_BAR_SIZE	(1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \
> > +						 VIRTIO_MSIX_PBA_SIZE))
> > +
> >  static u16 virtio_pci__port_addr(struct virtio_pci *vpci)
> >  {
> >  	return pci__bar_address(&vpci->pci_hdr, 0);
> > @@ -333,18 +341,27 @@ static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
> >  	struct virtio_pci *vpci = vdev->virtio;
> >  	struct msix_table *table;
> >  	u32 msix_io_addr = virtio_pci__msix_io_addr(vpci);
> > +	u32 pba_offset;
> >  	int vecnum;
> >  	size_t offset;
> >  
> > -	if (addr > msix_io_addr + PCI_IO_SIZE) {
> 
> Ouch, the missing "=" looks like another long standing bug you fixed, I
> wonder how this ever worked before? Looking deeper it looks like the
> whole PBA code was quite broken (allowing writes, for instance, and
> mixing with the code for the MSIX table)?

I don't think it ever worked. And to be fair, no known guest ever
reads from it either. It just that as I was reworking it, some of the
pitfalls became obvious.

> 
> > +	BUILD_BUG_ON(VIRTIO_NR_MSIX > (sizeof(vpci->msix_pba) * 8));
> > +
> > +	pba_offset = vpci->pci_hdr.msix.pba_offset & ~PCI_MSIX_TABLE_BIR;
> 
> Any particular reason you read back the offset from the MSIX capability
> instead of just using VIRTIO_MSIX_TABLE_SIZE here? Is that to avoid
> accidentally diverging in the future, by having just one place of
> definition?

Exactly. My first version of this patch actually failed to update the
offset advertised to the guest, so I decided to just have a single
location for this. At least, we won't have to touch this code again if
we change the number of MSI-X.

> 
> > +	if (addr >= msix_io_addr + pba_offset) {
> > +		/* Read access to PBA */
> >  		if (is_write)
> >  			return;
> > -		table  = (struct msix_table *)&vpci->msix_pba;
> > -		offset = addr - (msix_io_addr + PCI_IO_SIZE);
> > -	} else {
> > -		table  = vpci->msix_table;
> > -		offset = addr - msix_io_addr;
> > +		offset = addr - (msix_io_addr + pba_offset);
> > +		if ((offset + len) > sizeof (vpci->msix_pba))
> > +			return;
> > +		memcpy(data, (void *)&vpci->msix_pba + offset, len);
> 
> Should this be a char* cast, since pointer arithmetic on void* is
> somewhat frowned upon (aka "forbidden in the C standard, but allowed as
> a GCC extension")?

I am trying to be consistent. A quick grep shows at least 19
occurrences of pointer arithmetic with '(void *)', and none with
'(char *)'. Happy for someone to go and repaint this, but I don't
think this should be the purpose of this patch.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X
  2021-08-31 11:28   ` Marc Zyngier
@ 2021-08-31 11:39     ` Andre Przywara
  0 siblings, 0 replies; 5+ messages in thread
From: Andre Przywara @ 2021-08-31 11:39 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, kvmarm, Alexandru Elisei, Will Deacon

On Tue, 31 Aug 2021 12:28:28 +0100
Marc Zyngier <maz@kernel.org> wrote:

> Hi Andre,
> 
> On Tue, 31 Aug 2021 12:10:35 +0100,
> Andre Przywara <andre.przywara@arm.com> wrote:
> > 
> > On Fri, 27 Aug 2021 12:54:05 +0100
> > Marc Zyngier <maz@kernel.org> wrote:
> > 
> > Hi Marc,
> >   
> > > Since 45d3b59e8c45 ("kvm tools: Increase amount of possible interrupts
> > > per PCI device"), the number of MSI-S has gone from 4 to 33.
> > > 
> > > However, the corresponding storage hasn't been upgraded, and writing
> > > to the MSI-X table is a pretty risky business. Now that the Linux
> > > kernel writes to *all* MSI-X entries before doing anything else
> > > with the device, kvmtool dies a horrible death.
> > > 
> > > Fix it by properly defining the size of the MSI-X bar, and make
> > > Linux great again.
> > > 
> > > This includes some fixes the PBA region decoding, as well as minor
> > > cleanups to make this code a bit more maintainable.
> > > 
> > > Signed-off-by: Marc Zyngier <maz@kernel.org>  
> > 
> > Many thanks for fixing this, it looks good to me now. Just some
> > questions below:

Thanks for the explanation, and keeping (void *) as there are more
instances sounds fair enough. So:

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre


> >   
> > > ---
> > >  virtio/pci.c | 42 ++++++++++++++++++++++++++++++------------
> > >  1 file changed, 30 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/virtio/pci.c b/virtio/pci.c
> > > index eb91f512..41085291 100644
> > > --- a/virtio/pci.c
> > > +++ b/virtio/pci.c
> > > @@ -7,6 +7,7 @@
> > >  #include "kvm/irq.h"
> > >  #include "kvm/virtio.h"
> > >  #include "kvm/ioeventfd.h"
> > > +#include "kvm/util.h"
> > >  
> > >  #include <sys/ioctl.h>
> > >  #include <linux/virtio_pci.h>
> > > @@ -14,6 +15,13 @@
> > >  #include <assert.h>
> > >  #include <string.h>
> > >  
> > > +#define ALIGN_UP(x, s)		ALIGN((x) + (s) - 1, (s))
> > > +#define VIRTIO_NR_MSIX		(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG)
> > > +#define VIRTIO_MSIX_TABLE_SIZE	(VIRTIO_NR_MSIX * 16)
> > > +#define VIRTIO_MSIX_PBA_SIZE	(ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8)
> > > +#define VIRTIO_MSIX_BAR_SIZE	(1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \
> > > +						 VIRTIO_MSIX_PBA_SIZE))
> > > +
> > >  static u16 virtio_pci__port_addr(struct virtio_pci *vpci)
> > >  {
> > >  	return pci__bar_address(&vpci->pci_hdr, 0);
> > > @@ -333,18 +341,27 @@ static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
> > >  	struct virtio_pci *vpci = vdev->virtio;
> > >  	struct msix_table *table;
> > >  	u32 msix_io_addr = virtio_pci__msix_io_addr(vpci);
> > > +	u32 pba_offset;
> > >  	int vecnum;
> > >  	size_t offset;
> > >  
> > > -	if (addr > msix_io_addr + PCI_IO_SIZE) {  
> > 
> > Ouch, the missing "=" looks like another long standing bug you fixed, I
> > wonder how this ever worked before? Looking deeper it looks like the
> > whole PBA code was quite broken (allowing writes, for instance, and
> > mixing with the code for the MSIX table)?  
> 
> I don't think it ever worked. And to be fair, no known guest ever
> reads from it either. It just that as I was reworking it, some of the
> pitfalls became obvious.
> 
> >   
> > > +	BUILD_BUG_ON(VIRTIO_NR_MSIX > (sizeof(vpci->msix_pba) * 8));
> > > +
> > > +	pba_offset = vpci->pci_hdr.msix.pba_offset & ~PCI_MSIX_TABLE_BIR;  
> > 
> > Any particular reason you read back the offset from the MSIX capability
> > instead of just using VIRTIO_MSIX_TABLE_SIZE here? Is that to avoid
> > accidentally diverging in the future, by having just one place of
> > definition?  
> 
> Exactly. My first version of this patch actually failed to update the
> offset advertised to the guest, so I decided to just have a single
> location for this. At least, we won't have to touch this code again if
> we change the number of MSI-X.
> 
> >   
> > > +	if (addr >= msix_io_addr + pba_offset) {
> > > +		/* Read access to PBA */
> > >  		if (is_write)
> > >  			return;
> > > -		table  = (struct msix_table *)&vpci->msix_pba;
> > > -		offset = addr - (msix_io_addr + PCI_IO_SIZE);
> > > -	} else {
> > > -		table  = vpci->msix_table;
> > > -		offset = addr - msix_io_addr;
> > > +		offset = addr - (msix_io_addr + pba_offset);
> > > +		if ((offset + len) > sizeof (vpci->msix_pba))
> > > +			return;
> > > +		memcpy(data, (void *)&vpci->msix_pba + offset, len);  
> > 
> > Should this be a char* cast, since pointer arithmetic on void* is
> > somewhat frowned upon (aka "forbidden in the C standard, but allowed as
> > a GCC extension")?  
> 
> I am trying to be consistent. A quick grep shows at least 19
> occurrences of pointer arithmetic with '(void *)', and none with
> '(char *)'. Happy for someone to go and repaint this, but I don't
> think this should be the purpose of this patch.
> 
> Thanks,
> 
> 	M.
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X
  2021-08-27 11:54 [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X Marc Zyngier
  2021-08-31 11:10 ` Andre Przywara
@ 2021-08-31 15:05 ` Will Deacon
  1 sibling, 0 replies; 5+ messages in thread
From: Will Deacon @ 2021-08-31 15:05 UTC (permalink / raw)
  To: Marc Zyngier, kvmarm, kvm
  Cc: catalin.marinas, kernel-team, Will Deacon, Alexandru Elisei,
	Andre Przywara

On Fri, 27 Aug 2021 12:54:05 +0100, Marc Zyngier wrote:
> Since 45d3b59e8c45 ("kvm tools: Increase amount of possible interrupts
> per PCI device"), the number of MSI-S has gone from 4 to 33.
> 
> However, the corresponding storage hasn't been upgraded, and writing
> to the MSI-X table is a pretty risky business. Now that the Linux
> kernel writes to *all* MSI-X entries before doing anything else
> with the device, kvmtool dies a horrible death.
> 
> [...]

Applied to kvmtool (master), thanks!

[1/1] virtio/pci: Size the MSI-X bar according to the number of MSI-X
      https://git.kernel.org/will/kvmtool/c/2e7380db438d

Cheers,
-- 
Will

https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-08-31 15:06 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-27 11:54 [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X Marc Zyngier
2021-08-31 11:10 ` Andre Przywara
2021-08-31 11:28   ` Marc Zyngier
2021-08-31 11:39     ` Andre Przywara
2021-08-31 15:05 ` Will Deacon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).