Re: [kvm-unit-tests PATCH v2 1/4] pci: Rework pci_bar_is_valid()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jan 23, 2017 at 08:44:07AM +0100, Alexander Gordeev wrote:
> Currently pci_bar_is_valid() returns the value stored
> in a BAR. That is wrong, because the function fails if
> the returned value is zero. But that is wrong, because:
>   - an address in PIO address space may be zero;
>   - an upper part of 64-bit BAR may be zero;
> 
> The right way of validating a BAR is checking its size -
> for implemented BARs the size is non-zero.
> 
> It might look strange, but the function checks not just the
> queried BAR, but sanity of all six BARs of the device.
> 
> If we checked only requested BAR the function could have
> succeeded with inconsistent BAR sizes combinations. I.e.
> imagine a corrupted BARs reported by a device:
>   BAR 0 - 64 bit lower
>   BAR 1 - 64 bit lower
>   BAR 2 - 64 bit upper
>   ...
> If the function is asked about BAR 1 it would succeed, even
> though in fact the layout is ambiguous.

Is it possible to have bars messed up like this? I think I'd
just assume that sane layouts will exist and that we need to
avoid misinterpreting a high bar. So we just need to know a
high bar is a high bar, and in that case it's valid.

> 
> As result, the function is expected to be called only with
> valid BAR numbers and BARs layout should be consistent.
> Otherwise, an assert is raised.
> 
> The BAR number parameter bar_num is only allowed to refer
> a 32-bit BAR or lower part of a 64-bit BAR, as it does not
> make sense checking validity of high part of a 64-bit BAR.
> Thus, the caller is expected to know the device BARs layout.

I think the caller should be allowed to make this call on a
high bar.

> 
> Cc: Thomas Huth <thuth@xxxxxxxxxx>
> Cc: Andrew Jones <drjones@xxxxxxxxxx>
> Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx>
> ---
>  lib/pci.c | 19 ++++++++++++++++++-
>  1 file changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/pci.c b/lib/pci.c
> index fdd88296f0ae..00fba6e07860 100644
> --- a/lib/pci.c
> +++ b/lib/pci.c
> @@ -117,7 +117,24 @@ bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num)
>  
>  bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num)
>  {
> -	return pci_bar_get(dev, bar_num);
> +	bool is64 = false;
> +	int i;
> +
> +	assert(bar_num >= 0 && bar_num < 6);
> +
> +	for (i = 0; i < 6; i++) {

We have PCI_BAR_NUM now to use instead of 6, but don't you just want
to loop up to bar_num?

> +		if (is64) {
> +			assert(i == bar_num);	/* high part of 64-bit BAR */

This assert looks wrong. Let's assume we want to check bar_num == 2,
but bar0 is 64-bit. In that case wouldn't you hit it?

> +			assert(pci_bar_is64(dev, i));

Won't this assert always fire on the high bar?

> +
> +			is64 = false;
> +		} else {
> +			is64 = pci_bar_is64(dev, i);
> +		}
> +	}
> +	assert(!is64);				/* incomplete 64-bit BAR */
> +
> +	return pci_bar_size(dev, bar_num);
>  }
>  
>  bool pci_bar_is64(pcidevaddr_t dev, int bar_num)
> -- 
> 1.8.3.1
> 

How about just this instead (untested)

 bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num)
 {
   assert(bar_num >= 0 && bar_num < PCI_BAR_NUM);
   if (bar_num > 0 && pci_bar_is64(dev, bar_num - 1))
     return pci_bar_is_valid(dev, bar_num - 1);
   return pci_bar_size(dev, bar_num);
 }

Thanks,
drew



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux