@samitouri / QOSamiQemu / commits / c77da4c0d6

hw: Add "loadparm" property to virtio block PCI devices booting on s390x

The loadparm is required on s390x to pass the information to the boot loader such as which kernel should be started or whether the boot menu should be shown. Because PCI devices do not naturally allocate space for this, the property is added on an architecture specific basis for supported device types. Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com> Message-ID: <20260309003601.242634-15-jrossi@linux.ibm.com> Signed-off-by: Thomas Huth <thuth@redhat.com>

Jared Rossi committed Mar 8, 2026 at 20:36 UTC c77da4c0d63e7631161153973729377dd46a1c12
5 files changed +52 -2
hw/pci/pci.c
+38
@@ -36,6 +36,7 @@
36 #include "migration/qemu-file-types.h"
37 #include "migration/vmstate.h"
38 #include "net/net.h"
39 +#include "system/arch_init.h"
40 #include "system/numa.h"
41 #include "system/runstate.h"
42 #include "system/system.h"
@@ -2843,6 +2844,43 @@ int pci_qdev_find_device(const char *id, PCIDevice **pdev)
2844 return rc;
2845 }
2846
2847 +static char *pci_qdev_property_get_loadparm(Object *obj, Error **errp)
2848 +{
2849 + return g_strdup(PCI_DEVICE(obj)->loadparm);
2850 +}
2851 +
2852 +static void pci_qdev_property_set_loadparm(Object *obj, const char *value,
2853 + Error **errp)
2854 +{
2855 + void *lp_str;
2856 +
2857 + if (object_property_get_int(obj, "bootindex", NULL) < 0) {
2858 + error_setg(errp, "'loadparm' is only valid for boot devices");
2859 + return;
2860 + }
2861 +
2862 + lp_str = g_malloc0(strlen(value) + 1);
2863 + if (!qdev_prop_sanitize_s390x_loadparm(lp_str, value, errp)) {
2864 + g_free(lp_str);
2865 + return;
2866 + }
2867 + PCI_DEVICE(obj)->loadparm = lp_str;
2868 +}
2869 +
2870 +void pci_qdev_property_add_specifics(DeviceClass *dc)
2871 +{
2872 + ObjectClass *oc = OBJECT_CLASS(dc);
2873 +
2874 + /* The loadparm property is only supported on s390x */
2875 + if (target_s390x()) {
2876 + object_class_property_add_str(oc, "loadparm",
2877 + pci_qdev_property_get_loadparm,
2878 + pci_qdev_property_set_loadparm);
2879 + object_class_property_set_description(oc, "loadparm",
2880 + "load parameter (s390x only)");
2881 + }
2882 +}
2883 +
2884 MemoryRegion *pci_address_space(PCIDevice *dev)
2885 {
2886 return pci_get_bus(dev)->address_space_mem;
hw/s390x/ipl.c
+9 -2
@@ -461,6 +461,7 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
461 int devtype;
462 uint8_t *lp;
463 g_autofree void *scsi_lp = NULL;
464 + g_autofree void *pci_lp = NULL;
465
466 ccw_dev = s390_get_ccw_device(dev_st, &devtype);
467 if (ccw_dev) {
@@ -513,6 +514,14 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
514
515 pbdev = s390_get_pci_device(dev_st, &devtype);
516 if (pbdev) {
517 + pci_lp = object_property_get_str(OBJECT(pbdev->pdev), "loadparm", NULL);
518 + if (pci_lp && strlen(pci_lp) > 0) {
519 + lp = pci_lp;
520 + } else {
521 + /* Use machine loadparm as a place holder if PCI LP is unset */
522 + lp = S390_CCW_MACHINE(qdev_get_machine())->loadparm;
523 + }
524 +
525 switch (devtype) {
526 case PCI_DEVTYPE_VIRTIO:
527 iplb->len = cpu_to_be32(S390_IPLB_MIN_PCI_LEN);
@@ -523,8 +532,6 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
532 return false;
533 }
534
526 - /* Per-device loadparm not yet supported for non-ccw IPL */
527 - lp = S390_CCW_MACHINE(qdev_get_machine())->loadparm;
535 s390_ipl_convert_loadparm((char *)lp, iplb->loadparm);
536 iplb->flags |= DIAG308_FLAGS_LP_VALID;
537
hw/virtio/virtio-blk-pci.c
+1
@@ -71,6 +71,7 @@ static void virtio_blk_pci_class_init(ObjectClass *klass, const void *data)
71
72 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
73 device_class_set_props(dc, virtio_blk_pci_properties);
74 + pci_qdev_property_add_specifics(dc);
75 k->realize = virtio_blk_pci_realize;
76 pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
77 pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
include/hw/pci/pci.h
+1
@@ -380,6 +380,7 @@ const char *pci_root_bus_path(PCIDevice *dev);
380 bool pci_bus_bypass_iommu(PCIBus *bus);
381 PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
382 int pci_qdev_find_device(const char *id, PCIDevice **pdev);
383 +void pci_qdev_property_add_specifics(DeviceClass *dc);
384 void pci_bus_get_w64_range(PCIBus *bus, Range *range);
385
386 void pci_device_deassert_intx(PCIDevice *dev);
include/hw/pci/pci_device.h
+3
@@ -62,6 +62,9 @@ struct PCIDevice {
62 bool partially_hotplugged;
63 bool enabled;
64
65 + /* only for s390x */
66 + char *loadparm;
67 +
68 /* PCI config space */
69 uint8_t *config;
70