qrap: Introduce machine-specific PCI address base

For pc machines, devices are placed directly on pci.0 with
addresses like

  bus=pci.0,addr=0xa

and in this case the existing code works correctly.

For q35 machines, however, a separate PCI bus is created for
each devices using a pcie-root-port, and the resulting
addresses look like

  bus=pci.9,addr=0x0

In this case, we need to treat PCI addresses as decimal, not
hexadecimal, both when parsing and generating them.

This issue has gone unnoticed for a long time because it only
shows up when enough PCI devices are present: for small
numbers, decimal and hexadecimal overlap, masking the issue.

Reported-by: Alona Paz <alkaplan@redhat.com>
Fixes: 5307faa059 ("qrap: Strip network devices from command line, set them up according to machine")
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Andrea Bolognani 2023-02-24 19:49:48 +01:00 committed by Stefano Brivio
parent 8828a637ba
commit 4f2341f31d

22
qrap.c
View file

@ -77,6 +77,7 @@ static const struct drop_arg {
* @template_post: Suffix for device specification (last part of address) * @template_post: Suffix for device specification (last part of address)
* @template_json: Device prefix for when JSON is used * @template_json: Device prefix for when JSON is used
* @template_json_post: Device suffix for when JSON is used * @template_json_post: Device suffix for when JSON is used
* @base: Base used for PCI addresses
* @first: First usable PCI address * @first: First usable PCI address
* @last: Last usable PCI address * @last: Last usable PCI address
*/ */
@ -87,6 +88,7 @@ static const struct pci_dev {
char *template_post; char *template_post;
char *template_json; char *template_json;
char *template_json_post; char *template_json_post;
int base;
int first; int first;
int last; int last;
} pci_devs[] = { } pci_devs[] = {
@ -94,19 +96,19 @@ static const struct pci_dev {
"pc-q35", "virtio-net-pci", "pc-q35", "virtio-net-pci",
"bus=pci.", ",addr=0x0", "bus=pci.", ",addr=0x0",
"\"bus\":\"pci.", ",\"addr\":\"0x0\"", "\"bus\":\"pci.", ",\"addr\":\"0x0\"",
3, /* 2: hotplug bus */ 31 10, 3, /* 2: hotplug bus */ 31
}, },
{ {
"pc-", "virtio-net-pci", "pc-", "virtio-net-pci",
"bus=pci.0,addr=0x", "", "bus=pci.0,addr=0x", "",
"\"bus\":\"pci.0\",\"addr\":\"0x", "", "\"bus\":\"pci.0\",\"addr\":\"0x", "",
2, /* 1: ISA bridge */ 31 16, 2, /* 1: ISA bridge */ 31
}, },
{ {
"s390-ccw", "virtio-net-ccw", "s390-ccw", "virtio-net-ccw",
"devno=fe.0.", "", "devno=fe.0.", "",
"\"devno\":\"fe.0.", "", "\"devno\":\"fe.0.", "",
1, 16 16, 1, 16
}, },
{ 0 }, { 0 },
}; };
@ -264,7 +266,7 @@ int main(int argc, char **argv)
if (template) { if (template) {
long n; long n;
n = strtol(p + strlen(template), NULL, 16); n = strtol(p + strlen(template), NULL, dev->base);
if (!errno) if (!errno)
addr_map |= (1 << n); addr_map |= (1 << n);
} }
@ -285,13 +287,25 @@ int main(int argc, char **argv)
if (has_dev) { if (has_dev) {
qemu_argv[qemu_argc++] = "-device"; qemu_argv[qemu_argc++] = "-device";
if (!has_json) { if (!has_json) {
if (dev->base == 16) {
snprintf(dev_str, ARG_MAX, snprintf(dev_str, ARG_MAX,
"%s,%s%x%s,netdev=hostnet0,x-txburst=4096", "%s,%s%x%s,netdev=hostnet0,x-txburst=4096",
dev->name, dev->template, i, dev->template_post); dev->name, dev->template, i, dev->template_post);
} else if (dev->base == 10) {
snprintf(dev_str, ARG_MAX,
"%s,%s%d%s,netdev=hostnet0,x-txburst=4096",
dev->name, dev->template, i, dev->template_post);
}
} else { } else {
if (dev->base == 16) {
snprintf(dev_str, ARG_MAX, snprintf(dev_str, ARG_MAX,
"{\"driver\":\"%s\",%s%x\"%s,\"netdev\":\"hostnet0\",\"x-txburst\":4096}", "{\"driver\":\"%s\",%s%x\"%s,\"netdev\":\"hostnet0\",\"x-txburst\":4096}",
dev->name, dev->template_json, i, dev->template_json_post); dev->name, dev->template_json, i, dev->template_json_post);
} else if (dev->base == 10) {
snprintf(dev_str, ARG_MAX,
"{\"driver\":\"%s\",%s%d\"%s,\"netdev\":\"hostnet0\",\"x-txburst\":4096}",
dev->name, dev->template_json, i, dev->template_json_post);
}
} }
qemu_argv[qemu_argc++] = dev_str; qemu_argv[qemu_argc++] = dev_str;
} }