[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]

 



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.

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.

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++) {
+		if (is64) {
+			assert(i == bar_num);	/* high part of 64-bit BAR */
+			assert(pci_bar_is64(dev, i));
+
+			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




[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