diff options
author | Marcel Apfelbaum <marcel@redhat.com> | 2018-01-17 21:19:47 +0200 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2018-02-13 18:25:48 +0200 |
commit | fc67208f228af8e444f74362db1bced56a3daa71 (patch) | |
tree | ecb6f3d0bdef955a75d6f723c956040ee85afc53 | |
parent | 293084a7196b1d7781b6fe19b24e85eb8b7f4de0 (diff) |
hw/pci-bridge: fix pcie root port's IO hints capability
The gen_pcie_root_port mem-reserve and pref32-reserve properties are
defined as size (so uint64_t), but passed as uint32_t when building
the 'IO hints' vendor specific capability.
Passing 4G (or more) gets truncated and passed as a zero reservation.
Is not a huge issue since the guest firmware will always compare the
hints with the default value and take the maximum.
Fix it by passing the values as uint64_t and failing to init the
gen_pcie_root_port id invalid values are used.
Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r-- | hw/pci/pci_bridge.c | 24 | ||||
-rw-r--r-- | include/hw/pci/pci_bridge.h | 4 |
2 files changed, 21 insertions, 7 deletions
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index b2e50c36a0..40a39f57cb 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -412,22 +412,36 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, uint32_t bus_reserve, uint64_t io_reserve, - uint32_t mem_non_pref_reserve, - uint32_t mem_pref_32_reserve, + uint64_t mem_non_pref_reserve, + uint64_t mem_pref_32_reserve, uint64_t mem_pref_64_reserve, Error **errp) { - if (mem_pref_32_reserve != (uint32_t)-1 && + if (mem_pref_32_reserve != (uint64_t)-1 && mem_pref_64_reserve != (uint64_t)-1) { error_setg(errp, "PCI resource reserve cap: PREF32 and PREF64 conflict"); return -EINVAL; } + if (mem_non_pref_reserve != (uint64_t)-1 && + mem_non_pref_reserve >= (1ULL << 32)) { + error_setg(errp, + "PCI resource reserve cap: mem-reserve must be less than 4G"); + return -EINVAL; + } + + if (mem_pref_32_reserve != (uint64_t)-1 && + mem_pref_32_reserve >= (1ULL << 32)) { + error_setg(errp, + "PCI resource reserve cap: pref32-reserve must be less than 4G"); + return -EINVAL; + } + if (bus_reserve == (uint32_t)-1 && io_reserve == (uint64_t)-1 && - mem_non_pref_reserve == (uint32_t)-1 && - mem_pref_32_reserve == (uint32_t)-1 && + mem_non_pref_reserve == (uint64_t)-1 && + mem_pref_32_reserve == (uint64_t)-1 && mem_pref_64_reserve == (uint64_t)-1) { return 0; } diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index 9b44ffd22a..0347da52d2 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -135,8 +135,8 @@ typedef struct PCIBridgeQemuCap { int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, uint32_t bus_reserve, uint64_t io_reserve, - uint32_t mem_non_pref_reserve, - uint32_t mem_pref_32_reserve, + uint64_t mem_non_pref_reserve, + uint64_t mem_pref_32_reserve, uint64_t mem_pref_64_reserve, Error **errp); |