Skip to contentSkip to conversation

pci: Various PCI BAR checks

PATCH In review Alexander Gordeev 2 participants 14 messages Jan 23, 2017 – Feb 13, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover pci: Various PCI BAR checks

Hi Andrew,

Here is v2 of the series - it improves BAR validation function and scatters more calls to that around.

Cc Thomas Huth <[email protected]>
Cc Andrew Jones <[email protected]>

Alexander Gordeev (4):
pci: Rework pci_bar_is_valid()
pci: Split and rename pci_bar_is_valid() to pci_bar_exists()
pci: Ensure BAR validity for public functions
pci: pci-host-generic: Use INVALID_PHYS_ADDR instead of ~0

 lib/pci-host-generic.c |  6 +++---
 lib/pci-testdev.c      |  2 +-
 lib/pci.c              | 35 ++++++++++++++++++++++++++++++++---
 lib/pci.h              |  5 +++++
 x86/vmexit.c           |  2 +-
 5 files changed, 42 insertions(+), 8 deletions(-)
Signature · 1 line
1.8.3.1
#1 lore raw

PATCH v2 1/4 pci: Rework pci_bar_is_valid()

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.

---
 lib/pci.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)
lib/pci.c +18 -1
index fdd88296f0ae..00fba6e07860 100644
@@ -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)
Signature · 1 line
1.8.3.1
#2 lore raw

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

Quoted 12 lines · Alexander Gordeev

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.

Quoted 9 lines

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.

Quoted 9 lines

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.

Quoted 13 lines
---
 lib/pci.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)
lib/pci.c +0 -0
index fdd88296f0ae..00fba6e07860 100644

lib/pci.c bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num) · line 125

Quoted 10 lines
lib/pci.c +6 -1
@@ -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?

lib/pci.c bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num) · line 127

Quoted 2 lines
lib/pci.c +2 -0
+		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?

lib/pci.c bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num) · line 128

Quoted 1 line
lib/pci.c +1 -0
+			assert(pci_bar_is64(dev, i));

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

Quoted 15 lines
lib/pci.c +9 -0
+
+			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)
Signature · 1 line
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

#3 lore raw

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

Quoted 11 lines · Andrew Jones
Quoted 9 lines

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

I do not know actually. We spread sanity checks (asserts) here and there to avoid i.e. DT inconsistency. If we were to propagate this approach to the rest of the code, then we should assume BARs could be messed up, right?

It is a design decision, therefore - up to you ;)

Quoted 3 lines

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.

[...]

Quoted 2 lines

Thanks,
drew

#4 lore raw

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

Quoted 11 lines · Alexander Gordeev
Quoted 10 lines · Andrew Jones
Quoted 9 lines

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.

Quoted 8 lines
Quoted 1 line

Is it possible to have bars messed up like this? I think I'd

I do not know actually. We spread sanity checks (asserts) here and there to avoid i.e. DT inconsistency. If we were to propagate this approach to the rest of the code, then we should assume BARs could be messed up, right?

It is a design decision, therefore - up to you ;)

I like sanity checking asserts, but a check for bar layout sanity only needs to be made once, not each time any bar is checked for existence. If you want to confirm the layout of bars is sane, then pci_scan_bars is probably the right place.

Quoted 9 lines
Quoted 4 lines

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.

[...]

Quoted 2 lines

Thanks,
drew

#5 lore raw

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

In reply to Andrew Jones
Quoted 9 lines · Andrew Jones

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);

}

This one can not distinguish between PCI_BASE_ADDRESS_* flags and address bits of high part of a 64 bit address.

However, it seems a newly introduced pci_dev::resource[] can be used for that.

Quoted 2 lines

Thanks,
drew

#6 lore raw

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

Quoted 11 lines · Alexander Gordeev
Quoted 9 lines · Andrew Jones

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);

}

Quoted 5 lines

This one can not distinguish between PCI_BASE_ADDRESS_* flags and address bits of high part of a 64 bit address.

However, it seems a newly introduced pci_dev::resource[] can be used for that.

Hi Andrew,

Although using pci_dev::resource[] is possible I do not like a result for various reasons. I.e. I anticipate these:

- pci_bar_get/set_addr() logic will get quite cryptic;
- mismatch between pci_dev::resource[] 64 bit size and

    32 bit BAR size. While it is okay right now it will
    be confusing once pci_dev::resource[] are reused as
    BAR validity flags;
  - architecture specific pci_probe() reworked to seed
    pci_dev::resource[] (and being invoked on all archs);

Overall, the current compact implementetion is going to turn into a framework with not so obvious logic.

I suggest just polish v1 or drop the idea of checking BARs altogether.

Thoughts?

Quoted 2 lines
Quoted 2 lines

Thanks,
drew

#7 lore raw

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

Quoted 31 lines · Alexander Gordeev
Quoted 11 lines · Alexander Gordeev
Quoted 9 lines · Andrew Jones

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);

}

Quoted 5 lines

This one can not distinguish between PCI_BASE_ADDRESS_* flags and address bits of high part of a 64 bit address.

However, it seems a newly introduced pci_dev::resource[] can be used for that.

Hi Andrew,

Although using pci_dev::resource[] is possible I do not like a result for various reasons. I.e. I anticipate these:

- pci_bar_get/set_addr() logic will get quite cryptic;
- mismatch between pci_dev::resource[] 64 bit size and

    32 bit BAR size. While it is okay right now it will
    be confusing once pci_dev::resource[] are reused as
    BAR validity flags;
  - architecture specific pci_probe() reworked to seed
    pci_dev::resource[] (and being invoked on all archs);
Quoted 5 lines

Overall, the current compact implementetion is going to turn into a framework with not so obvious logic.

I suggest just polish v1 or drop the idea of checking BARs altogether.

We definitely need to improve pci_bar_is_valid(), so let's see how a v2 of this series looks.

Thanks,
drew

Quoted 5 lines

Thoughts?

Quoted 2 lines
Quoted 2 lines

Thanks,
drew

#8 lore raw

PATCH v2 2/4 pci: Split and rename pci_bar_is_valid() to pci_bar_exists()

In reply to Alexander Gordeev

Function pci_bar_is_valid() does two logical steps:
1. Checks BAR validity in the context of all device BARs;
2. Checks if the BAR is implemented (AKA exists);

In some cases checking BAR existence (step 2) is redundant. So reduce function pci_bar_is_valid() to only checking BAR validity(step 1).

In most cases we do need to check BAR existence, but we must ensure the BAR validity first (steps 1 and 2). For such cases pci_bar_exists() function is introduced. In essence it does what pci_bar_is_valid() used to do before this change.

---
 lib/pci-host-generic.c |  4 ++--
 lib/pci-testdev.c      |  2 +-
 lib/pci.c              | 15 +++++++++------
 lib/pci.h              |  5 +++++
 x86/vmexit.c           |  2 +-
 5 files changed, 18 insertions(+), 10 deletions(-)
lib/pci-host-generic.c +2 -2
index 4263365e8288..a881ec5a9d4f 100644
@@ -175,8 +175,7 @@ static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr)
 
 	*addr = ~0;
 
-	size = pci_bar_size(dev, bar_num);
-	if (!size)
+	if (!pci_bar_exists(dev, bar_num))
 		return false;
 
 	bar = pci_bar_get(dev, bar_num);
@@ -199,6 +198,7 @@ static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr)
 		return false;
 	}
 
+	size = pci_bar_size(dev, bar_num);
 	pci_addr = ALIGN(as->pci_start + as->allocated, size);
 	size += pci_addr - (as->pci_start + as->allocated);
 	assert(as->allocated + size <= as->size);
lib/pci-testdev.c +1 -1
index ad482d3291c7..712ada5c5860 100644
@@ -176,7 +176,7 @@ int pci_testdev(void)
 		return -1;
 	}
 
-	ret = pci_bar_is_valid(dev, 0) && pci_bar_is_valid(dev, 1);
+	ret = pci_bar_exists(dev, 0) && pci_bar_exists(dev, 1);
 	assert(ret);
 
 	addr = pci_bar_get_addr(dev, 0);
lib/pci.c +9 -6
index 00fba6e07860..7a3e505ab314 100644
@@ -124,17 +124,20 @@ bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num)
 
 	for (i = 0; i < 6; i++) {
 		if (is64) {
-			assert(i == bar_num);	/* high part of 64-bit BAR */
-			assert(pci_bar_is64(dev, i));
+			if (i == bar_num)	/* high part of 64-bit BAR */
+				return false;
+			if (pci_bar_is64(dev, i))
+				return false;
 
 			is64 = false;
 		} else {
 			is64 = pci_bar_is64(dev, i);
 		}
 	}
-	assert(!is64);				/* incomplete 64-bit BAR */
+	if (is64)				/* incomplete 64-bit BAR */
+		return false;
 
-	return pci_bar_size(dev, bar_num);
+	return true;
 }
 
 bool pci_bar_is64(pcidevaddr_t dev, int bar_num)
@@ -153,12 +156,12 @@ void pci_bar_print(pcidevaddr_t dev, int bar_num)
 	phys_addr_t size, start, end;
 	uint32_t bar;
 
-	size = pci_bar_size(dev, bar_num);
-	if (!size)
+	if (!pci_bar_exists(dev, bar_num))
 		return;
 
 	bar = pci_bar_get(dev, bar_num);
 	start = pci_bar_get_addr(dev, bar_num);
+	size = pci_bar_size(dev, bar_num);
 	end = start + size - 1;
 
 	if (pci_bar_is64(dev, bar_num)) {
lib/pci.h +5 -0
index 30f538110610..0b07036f27ac 100644
@@ -43,6 +43,11 @@ extern bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num);
 extern void pci_bar_print(pcidevaddr_t dev, int bar_num);
 extern void pci_dev_print_id(pcidevaddr_t dev);
 
+static inline bool pci_bar_exists(pcidevaddr_t dev, int bar_num)
+{
+	return pci_bar_size(dev, bar_num);
+}
+
 int pci_testdev(void);
 
 /*
x86/vmexit.c +1 -1
index 2d99d5fdf1c2..32132667b617 100644
@@ -388,7 +388,7 @@ int main(int ac, char **av)
 	pcidev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
 	if (pcidev != PCIDEVADDR_INVALID) {
 		for (i = 0; i < PCI_TESTDEV_NUM_BARS; i++) {
-			if (!pci_bar_is_valid(pcidev, i)) {
+			if (!pci_bar_exists(pcidev, i)) {
 				continue;
 			}
 			if (pci_bar_is_memory(pcidev, i)) {
Signature · 1 line
1.8.3.1
#9 lore raw

Re: [kvm-unit-tests PATCH v2 2/4] pci: Split and rename pci_bar_is_valid() to pci_bar_exists()

If you take my suggestion for patch 1, then this patch can be dropped.

Quoted 135 lines · Alexander Gordeev

Function pci_bar_is_valid() does two logical steps:
1. Checks BAR validity in the context of all device BARs;
2. Checks if the BAR is implemented (AKA exists);

In some cases checking BAR existence (step 2) is redundant. So reduce function pci_bar_is_valid() to only checking BAR validity(step 1).

In most cases we do need to check BAR existence, but we must ensure the BAR validity first (steps 1 and 2). For such cases pci_bar_exists() function is introduced. In essence it does what pci_bar_is_valid() used to do before this change.

---
 lib/pci-host-generic.c |  4 ++--
 lib/pci-testdev.c      |  2 +-
 lib/pci.c              | 15 +++++++++------
 lib/pci.h              |  5 +++++
 x86/vmexit.c           |  2 +-
 5 files changed, 18 insertions(+), 10 deletions(-)
lib/pci-host-generic.c +2 -2
index 4263365e8288..a881ec5a9d4f 100644
@@ -175,8 +175,7 @@ static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr)
 
 	*addr = ~0;
 
-	size = pci_bar_size(dev, bar_num);
-	if (!size)
+	if (!pci_bar_exists(dev, bar_num))
 		return false;
 
 	bar = pci_bar_get(dev, bar_num);
@@ -199,6 +198,7 @@ static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr)
 		return false;
 	}
 
+	size = pci_bar_size(dev, bar_num);
 	pci_addr = ALIGN(as->pci_start + as->allocated, size);
 	size += pci_addr - (as->pci_start + as->allocated);
 	assert(as->allocated + size <= as->size);
lib/pci-testdev.c +1 -1
index ad482d3291c7..712ada5c5860 100644
@@ -176,7 +176,7 @@ int pci_testdev(void)
 		return -1;
 	}
 
-	ret = pci_bar_is_valid(dev, 0) && pci_bar_is_valid(dev, 1);
+	ret = pci_bar_exists(dev, 0) && pci_bar_exists(dev, 1);
 	assert(ret);
 
 	addr = pci_bar_get_addr(dev, 0);
lib/pci.c +9 -6
index 00fba6e07860..7a3e505ab314 100644
@@ -124,17 +124,20 @@ bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num)
 
 	for (i = 0; i < 6; i++) {
 		if (is64) {
-			assert(i == bar_num);	/* high part of 64-bit BAR */
-			assert(pci_bar_is64(dev, i));
+			if (i == bar_num)	/* high part of 64-bit BAR */
+				return false;
+			if (pci_bar_is64(dev, i))
+				return false;
 
 			is64 = false;
 		} else {
 			is64 = pci_bar_is64(dev, i);
 		}
 	}
-	assert(!is64);				/* incomplete 64-bit BAR */
+	if (is64)				/* incomplete 64-bit BAR */
+		return false;
 
-	return pci_bar_size(dev, bar_num);
+	return true;
 }
 
 bool pci_bar_is64(pcidevaddr_t dev, int bar_num)
@@ -153,12 +156,12 @@ void pci_bar_print(pcidevaddr_t dev, int bar_num)
 	phys_addr_t size, start, end;
 	uint32_t bar;
 
-	size = pci_bar_size(dev, bar_num);
-	if (!size)
+	if (!pci_bar_exists(dev, bar_num))
 		return;
 
 	bar = pci_bar_get(dev, bar_num);
 	start = pci_bar_get_addr(dev, bar_num);
+	size = pci_bar_size(dev, bar_num);
 	end = start + size - 1;
 
 	if (pci_bar_is64(dev, bar_num)) {
lib/pci.h +5 -0
index 30f538110610..0b07036f27ac 100644
@@ -43,6 +43,11 @@ extern bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num);
 extern void pci_bar_print(pcidevaddr_t dev, int bar_num);
 extern void pci_dev_print_id(pcidevaddr_t dev);
 
+static inline bool pci_bar_exists(pcidevaddr_t dev, int bar_num)
+{
+	return pci_bar_size(dev, bar_num);
+}
+
 int pci_testdev(void);
 
 /*
x86/vmexit.c +1 -1
index 2d99d5fdf1c2..32132667b617 100644
@@ -388,7 +388,7 @@ int main(int ac, char **av)
 	pcidev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
 	if (pcidev != PCIDEVADDR_INVALID) {
 		for (i = 0; i < PCI_TESTDEV_NUM_BARS; i++) {
-			if (!pci_bar_is_valid(pcidev, i)) {
+			if (!pci_bar_exists(pcidev, i)) {
 				continue;
 			}
 			if (pci_bar_is_memory(pcidev, i)) {
Signature · 1 line
1.8.3.1
#10 lore raw

PATCH v2 3/4 pci: Ensure BAR validity for public functions

In reply to Alexander Gordeev
---
 lib/pci.c | 9 +++++++++
 1 file changed, 9 insertions(+)
lib/pci.c +9 -0
index 7a3e505ab314..144bec755c8d 100644
@@ -35,6 +35,8 @@ uint32_t pci_bar_mask(uint32_t bar)
 
 uint32_t pci_bar_get(pcidevaddr_t dev, int bar_num)
 {
+	assert(bar_num >= 0 && bar_num < 6);
+
 	return pci_config_readl(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
 }
 
@@ -45,6 +47,9 @@ phys_addr_t pci_bar_get_addr(pcidevaddr_t dev, int bar_num)
 	uint64_t addr = bar & mask;
 	phys_addr_t phys_addr;
 
+	if (!pci_bar_exists(dev, bar_num))
+		return INVALID_PHYS_ADDR;
+
 	if (pci_bar_is64(dev, bar_num))
 		addr |= (uint64_t)pci_bar_get(dev, bar_num + 1) << 32;
 
@@ -58,6 +63,8 @@ void pci_bar_set_addr(pcidevaddr_t dev, int bar_num, phys_addr_t addr)
 {
 	int off = PCI_BASE_ADDRESS_0 + bar_num * 4;
 
+	assert(pci_bar_exists(dev, bar_num));
+
 	pci_config_writel(dev, off, (uint32_t)addr);
 
 	if (pci_bar_is64(dev, bar_num))
@@ -91,6 +98,8 @@ phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num)
 {
 	uint32_t bar, size;
 
+	assert(pci_bar_is_valid(dev, bar_num));
+
 	size = pci_bar_size_helper(dev, bar_num);
 	if (!size)
 		return 0;
Signature · 1 line
1.8.3.1
#11 lore raw

Re: [kvm-unit-tests PATCH v2 3/4] pci: Ensure BAR validity for public functions

Quoted 40 lines · Alexander Gordeev
---
 lib/pci.c | 9 +++++++++
 1 file changed, 9 insertions(+)
lib/pci.c +7 -0
index 7a3e505ab314..144bec755c8d 100644
@@ -35,6 +35,8 @@ uint32_t pci_bar_mask(uint32_t bar)
 
 uint32_t pci_bar_get(pcidevaddr_t dev, int bar_num)
 {
+	assert(bar_num >= 0 && bar_num < 6);
+
 	return pci_config_readl(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
 }
 
@@ -45,6 +47,9 @@ phys_addr_t pci_bar_get_addr(pcidevaddr_t dev, int bar_num)
 	uint64_t addr = bar & mask;
 	phys_addr_t phys_addr;
 
+	if (!pci_bar_exists(dev, bar_num))
+		return INVALID_PHYS_ADDR;
+
 	if (pci_bar_is64(dev, bar_num))
 		addr |= (uint64_t)pci_bar_get(dev, bar_num + 1) << 32;
 
@@ -58,6 +63,8 @@ void pci_bar_set_addr(pcidevaddr_t dev, int bar_num, phys_addr_t addr)
 {
 	int off = PCI_BASE_ADDRESS_0 + bar_num * 4;
 
+	assert(pci_bar_exists(dev, bar_num));
+
 	pci_config_writel(dev, off, (uint32_t)addr);
 
 	if (pci_bar_is64(dev, bar_num))

lib/pci.c phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num) · line 101

Quoted 4 lines
lib/pci.c +1 -0
@@ -91,6 +98,8 @@ phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num)
 {
 	uint32_t bar, size;
 
+	assert(pci_bar_is_valid(dev, bar_num));

If dropping patch 2, then we can replace this condition with (bar_num == 0 || !pci_bar_is64(dev, bar_num - 1))

Quoted 7 lines
lib/pci.c +1 -0
+
 	size = pci_bar_size_helper(dev, bar_num);
 	if (!size)
 		return 0;
Signature · 1 line
1.8.3.1
#12 lore raw

PATCH v2 4/4 pci: pci-host-generic: Use INVALID_PHYS_ADDR instead of ~0

In reply to Alexander Gordeev

This update is better be squashed into commit b8b9fcf56253b ("pci: Make all ones invalid translate address")

---
 lib/pci-host-generic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/pci-host-generic.c +1 -1
index a881ec5a9d4f..4008fed153b6 100644
@@ -173,7 +173,7 @@ static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr)
 	u64 size, pci_addr;
 	int type, i;
 
-	*addr = ~0;
+	*addr = INVALID_PHYS_ADDR;
 
 	if (!pci_bar_exists(dev, bar_num))
 		return false;
Signature · 1 line
1.8.3.1
Reviewed-by on v2 4/4
#13 lore raw

Re: [kvm-unit-tests PATCH v2 4/4] pci: pci-host-generic: Use INVALID_PHYS_ADDR instead of ~0

Quoted 9 lines · Alexander Gordeev

This update is better be squashed into commit b8b9fcf56253b ("pci: Make all ones invalid translate address")

---
 lib/pci-host-generic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 17 lines
lib/pci-host-generic.c +1 -1
index a881ec5a9d4f..4008fed153b6 100644
@@ -173,7 +173,7 @@ static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr)
 	u64 size, pci_addr;
 	int type, i;
 
-	*addr = ~0;
+	*addr = INVALID_PHYS_ADDR;
 
 	if (!pci_bar_exists(dev, bar_num))
 		return false;
Signature · 1 line
1.8.3.1