diff --git a/kvm-hw-s390-ccw-device-Convert-to-three-phase-reset.patch b/kvm-hw-s390-ccw-device-Convert-to-three-phase-reset.patch new file mode 100644 index 0000000..d5b71e3 --- /dev/null +++ b/kvm-hw-s390-ccw-device-Convert-to-three-phase-reset.patch @@ -0,0 +1,63 @@ +From 5126609c0714c66a0ec41328017e7e8388c78bf4 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 13 Sep 2024 15:31:43 +0100 +Subject: [PATCH 02/26] hw/s390/ccw-device: Convert to three-phase reset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [2/26] 58f6fc2e65a101e069feac399859464d31e43045 (thuth/qemu-kvm-cs) + +Convert the TYPE_CCW_DEVICE to three-phase reset. This is a +device class which is subclassed, so it needs to be three-phase +before we can convert the subclass. + +Signed-off-by: Peter Maydell +Reviewed-by: Nina Schoetterl-Glausch +Reviewed-by: Philippe Mathieu-Daudé +Acked-by: Thomas Huth +Message-id: 20240830145812.1967042-2-peter.maydell@linaro.org +(cherry picked from commit 6a0e10b76b68e2f412746a1d5ed7d6efee804864) +Signed-off-by: Thomas Huth +--- + hw/s390x/ccw-device.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c +index d7bb364579..30f2fb486f 100644 +--- a/hw/s390x/ccw-device.c ++++ b/hw/s390x/ccw-device.c +@@ -88,9 +88,9 @@ static Property ccw_device_properties[] = { + DEFINE_PROP_END_OF_LIST(), + }; + +-static void ccw_device_reset(DeviceState *d) ++static void ccw_device_reset_hold(Object *obj, ResetType type) + { +- CcwDevice *ccw_dev = CCW_DEVICE(d); ++ CcwDevice *ccw_dev = CCW_DEVICE(obj); + + css_reset_sch(ccw_dev->sch); + } +@@ -99,11 +99,12 @@ static void ccw_device_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + CCWDeviceClass *k = CCW_DEVICE_CLASS(klass); ++ ResettableClass *rc = RESETTABLE_CLASS(klass); + + k->realize = ccw_device_realize; + k->refill_ids = ccw_device_refill_ids; + device_class_set_props(dc, ccw_device_properties); +- dc->reset = ccw_device_reset; ++ rc->phases.hold = ccw_device_reset_hold; + dc->bus_type = TYPE_VIRTUAL_CSS_BUS; + } + +-- +2.48.1 + diff --git a/kvm-hw-s390-virtio-ccw-Convert-to-three-phase-reset.patch b/kvm-hw-s390-virtio-ccw-Convert-to-three-phase-reset.patch new file mode 100644 index 0000000..15ea0b0 --- /dev/null +++ b/kvm-hw-s390-virtio-ccw-Convert-to-three-phase-reset.patch @@ -0,0 +1,92 @@ +From 7cbf9be09907407a64d739a2d0862af2ad08eaf5 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 13 Sep 2024 15:31:43 +0100 +Subject: [PATCH 03/26] hw/s390/virtio-ccw: Convert to three-phase reset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [3/26] e06ee194fa289a387433b905eb0999a048681a92 (thuth/qemu-kvm-cs) + +Convert the virtio-ccw code to three-phase reset. This allows us to +remove a call to device_class_set_parent_reset(), replacing it with +the three-phase equivalent resettable_class_set_parent_phases(). +Removing all the device_class_set_parent_reset() uses will allow us +to remove some of the glue code that interworks between three-phase +and legacy reset. + +This is a simple conversion, with no behavioural changes. + +Signed-off-by: Peter Maydell +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Nina Schoetterl-Glausch +Acked-by: Thomas Huth +Reviewed-by: Richard Henderson +Message-id: 20240830145812.1967042-3-peter.maydell@linaro.org +(cherry picked from commit 6affa00d6ebebf24485667fe146470b0d6feb90d) +Signed-off-by: Thomas Huth +--- + hw/s390x/virtio-ccw.c | 13 ++++++++----- + hw/s390x/virtio-ccw.h | 2 +- + 2 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c +index b4676909dd..96747318d2 100644 +--- a/hw/s390x/virtio-ccw.c ++++ b/hw/s390x/virtio-ccw.c +@@ -913,14 +913,15 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector) + } + } + +-static void virtio_ccw_reset(DeviceState *d) ++static void virtio_ccw_reset_hold(Object *obj, ResetType type) + { +- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); ++ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(obj); + VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev); + + virtio_ccw_reset_virtio(dev); +- if (vdc->parent_reset) { +- vdc->parent_reset(d); ++ ++ if (vdc->parent_phases.hold) { ++ vdc->parent_phases.hold(obj, type); + } + } + +@@ -1233,11 +1234,13 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) + DeviceClass *dc = DEVICE_CLASS(klass); + CCWDeviceClass *k = CCW_DEVICE_CLASS(dc); + VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_CLASS(klass); ++ ResettableClass *rc = RESETTABLE_CLASS(klass); + + k->unplug = virtio_ccw_busdev_unplug; + dc->realize = virtio_ccw_busdev_realize; + dc->unrealize = virtio_ccw_busdev_unrealize; +- device_class_set_parent_reset(dc, virtio_ccw_reset, &vdc->parent_reset); ++ resettable_class_set_parent_phases(rc, NULL, virtio_ccw_reset_hold, NULL, ++ &vdc->parent_phases); + } + + static const TypeInfo virtio_ccw_device_info = { +diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h +index fac186c8f6..c7a830a194 100644 +--- a/hw/s390x/virtio-ccw.h ++++ b/hw/s390x/virtio-ccw.h +@@ -57,7 +57,7 @@ struct VirtIOCCWDeviceClass { + CCWDeviceClass parent_class; + void (*realize)(VirtioCcwDevice *dev, Error **errp); + void (*unrealize)(VirtioCcwDevice *dev); +- void (*parent_reset)(DeviceState *dev); ++ ResettablePhases parent_phases; + }; + + /* Performance improves when virtqueue kick processing is decoupled from the +-- +2.48.1 + diff --git a/kvm-hw-virtio-Also-include-md-stubs-in-case-CONFIG_VIRTI.patch b/kvm-hw-virtio-Also-include-md-stubs-in-case-CONFIG_VIRTI.patch new file mode 100644 index 0000000..c062e65 --- /dev/null +++ b/kvm-hw-virtio-Also-include-md-stubs-in-case-CONFIG_VIRTI.patch @@ -0,0 +1,59 @@ +From afa3a488f3ca52a5455987e4cd643882c4b15d8a Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Thu, 13 Mar 2025 07:35:22 +0100 +Subject: [PATCH 24/26] hw/virtio: Also include md stubs in case + CONFIG_VIRTIO_PCI is not set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [24/26] ae6307b26d01d2a317f7e5d1d3b3a16b6d5f56de (thuth/qemu-kvm-cs) + +For the s390x target, it's possible to build the QEMU binary without +CONFIG_VIRTIO_PCI and only have the virtio-mem device via the ccw +transport. In that case, QEMU currently fails to link correctly: + + /usr/bin/ld: libqemu-s390x-softmmu.a.p/hw_s390x_s390-virtio-ccw.c.o: in function `s390_machine_device_pre_plug': + ../hw/s390x/s390-virtio-ccw.c:579:(.text+0x1e96): undefined reference to `virtio_md_pci_pre_plug' + /usr/bin/ld: libqemu-s390x-softmmu.a.p/hw_s390x_s390-virtio-ccw.c.o: in function `s390_machine_device_plug': + ../hw/s390x/s390-virtio-ccw.c:608:(.text+0x21a4): undefined reference to `virtio_md_pci_plug' + /usr/bin/ld: libqemu-s390x-softmmu.a.p/hw_s390x_s390-virtio-ccw.c.o: in function `s390_machine_device_unplug_request': + ../hw/s390x/s390-virtio-ccw.c:622:(.text+0x2334): undefined reference to `virtio_md_pci_unplug_request' + /usr/bin/ld: libqemu-s390x-softmmu.a.p/hw_s390x_s390-virtio-ccw.c.o: in function `s390_machine_device_unplug': + ../hw/s390x/s390-virtio-ccw.c:633:(.text+0x2436): undefined reference to `virtio_md_pci_unplug' + clang: error: linker command failed with exit code 1 (use -v to see invocation) + +We also need to include the stubs when CONFIG_VIRTIO_PCI is missing. + +Fixes: aa910c20ec5 ("s390x: virtio-mem support") +Message-ID: <20250313063522.1348288-1-thuth@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Thomas Huth +(cherry picked from commit c1a6bff276ca52ffde472532d92bb5bb122dab3f) +Signed-off-by: Thomas Huth +--- + hw/virtio/meson.build | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index c38bdd6fa4..e2f9c75625 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -89,7 +89,8 @@ specific_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) + system_ss.add_all(when: 'CONFIG_VIRTIO', if_true: system_virtio_ss) + system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) + system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c')) +-system_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-md-stubs.c')) ++system_ss.add(when: ['CONFIG_VIRTIO_MD', 'CONFIG_VIRTIO_PCI'], ++ if_false: files('virtio-md-stubs.c')) + + system_ss.add(files('virtio-hmp-cmds.c')) + +-- +2.48.1 + diff --git a/kvm-redhat-Enable-virtio-mem-on-s390x.patch b/kvm-redhat-Enable-virtio-mem-on-s390x.patch new file mode 100644 index 0000000..ca56520 --- /dev/null +++ b/kvm-redhat-Enable-virtio-mem-on-s390x.patch @@ -0,0 +1,36 @@ +From 7300a435547b7e999227648fd1451db00e9c4867 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 24 Mar 2025 18:09:26 +0100 +Subject: [PATCH 26/26] redhat: Enable virtio-mem on s390x + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [26/26] 076b44c8f0262e903c5e17eda676614aec6f5c98 (thuth/qemu-kvm-cs) + +JIRA: https://issues.redhat.com/browse/RHEL-72977 + +Enable virtio-mem on s390x now, too. + +Signed-off-by: Thomas Huth +--- + configs/devices/s390x-softmmu/s390x-rh-devices.mak | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/configs/devices/s390x-softmmu/s390x-rh-devices.mak b/configs/devices/s390x-softmmu/s390x-rh-devices.mak +index 24cf6dbd03..834281d872 100644 +--- a/configs/devices/s390x-softmmu/s390x-rh-devices.mak ++++ b/configs/devices/s390x-softmmu/s390x-rh-devices.mak +@@ -12,6 +12,7 @@ CONFIG_VFIO_CCW=y + CONFIG_VFIO_PCI=y + CONFIG_VHOST_USER=y + CONFIG_VIRTIO_CCW=y ++CONFIG_VIRTIO_MEM=y + CONFIG_WDT_DIAG288=y + CONFIG_VHOST_VSOCK=y + CONFIG_VHOST_USER_VSOCK=y +-- +2.48.1 + diff --git a/kvm-reset-Add-RESET_TYPE_WAKEUP.patch b/kvm-reset-Add-RESET_TYPE_WAKEUP.patch new file mode 100644 index 0000000..bcdc6ac --- /dev/null +++ b/kvm-reset-Add-RESET_TYPE_WAKEUP.patch @@ -0,0 +1,94 @@ +From 2de79d978c2cd29ad686dd91e74a86dbf2121f1f Mon Sep 17 00:00:00 2001 +From: Juraj Marcin +Date: Wed, 4 Sep 2024 12:37:13 +0200 +Subject: [PATCH 06/26] reset: Add RESET_TYPE_WAKEUP + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [6/26] 6169fe25bfa5715340c180ee8711d0ad61832106 (thuth/qemu-kvm-cs) + +Some devices need to distinguish cold start reset from waking up from a +suspended state. This patch adds new value to the enum, and updates the +i386 wakeup method to use this new reset type. + +Message-ID: <20240904103722.946194-3-jmarcin@redhat.com> +Reviewed-by: David Hildenbrand +Signed-off-by: Juraj Marcin +Signed-off-by: David Hildenbrand +(cherry picked from commit 759cbb4ee971da13ddfa8ad73befc2351d542044) +Signed-off-by: Thomas Huth +--- + docs/devel/reset.rst | 12 +++++++++++- + hw/i386/pc.c | 2 +- + include/hw/resettable.h | 2 ++ + 3 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst +index d2799eba7a..44bd51b42e 100644 +--- a/docs/devel/reset.rst ++++ b/docs/devel/reset.rst +@@ -44,6 +44,17 @@ The Resettable interface handles reset types with an enum ``ResetType``: + value on each cold reset, such as RNG seed information, and which they + must not reinitialize on a snapshot-load reset. + ++``RESET_TYPE_WAKEUP`` ++ If the machine supports waking up from a suspended state and needs to reset ++ its devices during wake-up (from the ``MachineClass::wakeup()`` method), this ++ reset type should be used for such a request. Devices can utilize this reset ++ type to differentiate the reset requested during machine wake-up from other ++ reset requests. For example, RAM content must not be lost during wake-up, and ++ memory devices like virtio-mem that provide additional RAM must not reset ++ such state during wake-ups, but might do so during cold resets. However, this ++ reset type should not be used for wake-up detection, as not every machine ++ type issues a device reset request during wake-up. ++ + ``RESET_TYPE_S390_CPU_NORMAL`` + This is only used for S390 CPU objects; it clears interrupts, stops + processing, and clears the TLB, but does not touch register contents. +@@ -53,7 +64,6 @@ The Resettable interface handles reset types with an enum ``ResetType``: + ``RESET_TYPE_S390_CPU_NORMAL`` does and also clears the PSW, prefix, + FPC, timer and control registers. It does not touch gprs, fprs or acrs. + +- + Devices which implement reset methods must treat any unknown ``ResetType`` + as equivalent to ``RESET_TYPE_COLD``; this will reduce the amount of + existing code we need to change if we add more types in future. +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index fedcf2a65f..fa9f16cbaf 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1889,7 +1889,7 @@ static void pc_machine_reset(MachineState *machine, ResetType type) + static void pc_machine_wakeup(MachineState *machine) + { + cpu_synchronize_all_states(); +- pc_machine_reset(machine, RESET_TYPE_COLD); ++ pc_machine_reset(machine, RESET_TYPE_WAKEUP); + cpu_synchronize_all_post_reset(); + } + +diff --git a/include/hw/resettable.h b/include/hw/resettable.h +index 83b561fc83..cf37cd5ead 100644 +--- a/include/hw/resettable.h ++++ b/include/hw/resettable.h +@@ -29,6 +29,7 @@ typedef struct ResettableState ResettableState; + * Types of reset. + * + * + Cold: reset resulting from a power cycle of the object. ++ * + Wakeup: reset resulting from a wake-up from a suspended state. + * + * TODO: Support has to be added to handle more types. In particular, + * ResettableState structure needs to be expanded. +@@ -36,6 +37,7 @@ typedef struct ResettableState ResettableState; + typedef enum ResetType { + RESET_TYPE_COLD, + RESET_TYPE_SNAPSHOT_LOAD, ++ RESET_TYPE_WAKEUP, + RESET_TYPE_S390_CPU_INITIAL, + RESET_TYPE_S390_CPU_NORMAL, + } ResetType; +-- +2.48.1 + diff --git a/kvm-reset-Use-ResetType-for-qemu_devices_reset-and-Machi.patch b/kvm-reset-Use-ResetType-for-qemu_devices_reset-and-Machi.patch new file mode 100644 index 0000000..2b0b933 --- /dev/null +++ b/kvm-reset-Use-ResetType-for-qemu_devices_reset-and-Machi.patch @@ -0,0 +1,360 @@ +From 8d48193b5a661f31c1c1db068d241b31ae379339 Mon Sep 17 00:00:00 2001 +From: Juraj Marcin +Date: Wed, 4 Sep 2024 12:37:12 +0200 +Subject: [PATCH 05/26] reset: Use ResetType for qemu_devices_reset() and + MachineClass::reset() + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [5/26] ea1324b27885d979bcc54cc355dbdf940686776c (thuth/qemu-kvm-cs) + +Currently, both qemu_devices_reset() and MachineClass::reset() use +ShutdownCause for the reason of the reset. However, the Resettable +interface uses ResetState, so ShutdownCause needs to be translated to +ResetType somewhere. Translating it qemu_devices_reset() makes adding +new reset types harder, as they cannot always be matched to a single +ShutdownCause here, and devices may need to check the ResetType to +determine what to reset and if to reset at all. + +This patch moves this translation up in the call stack to +qemu_system_reset() and updates all MachineClass children to use the +ResetType instead. + +Message-ID: <20240904103722.946194-2-jmarcin@redhat.com> +Reviewed-by: David Hildenbrand +Reviewed-by: Peter Maydell +Signed-off-by: Juraj Marcin +Signed-off-by: David Hildenbrand +(cherry picked from commit 1b063fe2df002052cc2d10799764979b8c583480) +Signed-off-by: Thomas Huth +--- + hw/arm/aspeed.c | 4 ++-- + hw/arm/mps2-tz.c | 4 ++-- + hw/core/reset.c | 5 +---- + hw/hppa/machine.c | 4 ++-- + hw/i386/microvm.c | 4 ++-- + hw/i386/pc.c | 6 +++--- + hw/ppc/pegasos2.c | 4 ++-- + hw/ppc/pnv.c | 4 ++-- + hw/ppc/spapr.c | 6 +++--- + hw/s390x/s390-virtio-ccw.c | 4 ++-- + include/hw/boards.h | 3 ++- + include/sysemu/reset.h | 5 +++-- + system/runstate.c | 13 +++++++++++-- + 13 files changed, 37 insertions(+), 29 deletions(-) + +diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c +index fd5603f7aa..cbca7685da 100644 +--- a/hw/arm/aspeed.c ++++ b/hw/arm/aspeed.c +@@ -1529,12 +1529,12 @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) + aspeed_machine_class_init_cpus_defaults(mc); + } + +-static void fby35_reset(MachineState *state, ShutdownCause reason) ++static void fby35_reset(MachineState *state, ResetType type) + { + AspeedMachineState *bmc = ASPEED_MACHINE(state); + AspeedGPIOState *gpio = &bmc->soc->gpio; + +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + + /* Board ID: 7 (Class-1, 4 slots) */ + object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal); +diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c +index aec57c0d68..8edf57a66d 100644 +--- a/hw/arm/mps2-tz.c ++++ b/hw/arm/mps2-tz.c +@@ -1254,7 +1254,7 @@ static void mps2_set_remap(Object *obj, const char *value, Error **errp) + } + } + +-static void mps2_machine_reset(MachineState *machine, ShutdownCause reason) ++static void mps2_machine_reset(MachineState *machine, ResetType type) + { + MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); + +@@ -1264,7 +1264,7 @@ static void mps2_machine_reset(MachineState *machine, ShutdownCause reason) + * reset see the correct mapping. + */ + remap_memory(mms, mms->remap); +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + } + + static void mps2tz_class_init(ObjectClass *oc, void *data) +diff --git a/hw/core/reset.c b/hw/core/reset.c +index 58dfc8db3d..14a2639fbf 100644 +--- a/hw/core/reset.c ++++ b/hw/core/reset.c +@@ -170,11 +170,8 @@ void qemu_unregister_resettable(Object *obj) + resettable_container_remove(get_root_reset_container(), obj); + } + +-void qemu_devices_reset(ShutdownCause reason) ++void qemu_devices_reset(ResetType type) + { +- ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ? +- RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD; +- + /* Reset the simulation */ + resettable_reset(OBJECT(get_root_reset_container()), type); + } +diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c +index 5d0a8739de..8259fe2e38 100644 +--- a/hw/hppa/machine.c ++++ b/hw/hppa/machine.c +@@ -642,12 +642,12 @@ static void machine_HP_C3700_init(MachineState *machine) + machine_HP_common_init_tail(machine, pci_bus, translate); + } + +-static void hppa_machine_reset(MachineState *ms, ShutdownCause reason) ++static void hppa_machine_reset(MachineState *ms, ResetType type) + { + unsigned int smp_cpus = ms->smp.cpus; + int i; + +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + + /* Start all CPUs at the firmware entry point. + * Monarch CPU will initialize firmware, secondary CPUs +diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c +index 40edcee7af..8ae4dff7f2 100644 +--- a/hw/i386/microvm.c ++++ b/hw/i386/microvm.c +@@ -462,7 +462,7 @@ static void microvm_machine_state_init(MachineState *machine) + microvm_devices_init(mms); + } + +-static void microvm_machine_reset(MachineState *machine, ShutdownCause reason) ++static void microvm_machine_reset(MachineState *machine, ResetType type) + { + MicrovmMachineState *mms = MICROVM_MACHINE(machine); + CPUState *cs; +@@ -475,7 +475,7 @@ static void microvm_machine_reset(MachineState *machine, ShutdownCause reason) + mms->kernel_cmdline_fixed = true; + } + +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + + CPU_FOREACH(cs) { + cpu = X86_CPU(cs); +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index fa0e42d072..fedcf2a65f 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1869,12 +1869,12 @@ static void pc_machine_initfn(Object *obj) + qemu_add_machine_init_done_notifier(&pcms->machine_done); + } + +-static void pc_machine_reset(MachineState *machine, ShutdownCause reason) ++static void pc_machine_reset(MachineState *machine, ResetType type) + { + CPUState *cs; + X86CPU *cpu; + +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + + /* Reset APIC after devices have been reset to cancel + * any changes that qemu_devices_reset() might have done. +@@ -1889,7 +1889,7 @@ static void pc_machine_reset(MachineState *machine, ShutdownCause reason) + static void pc_machine_wakeup(MachineState *machine) + { + cpu_synchronize_all_states(); +- pc_machine_reset(machine, SHUTDOWN_CAUSE_NONE); ++ pc_machine_reset(machine, RESET_TYPE_COLD); + cpu_synchronize_all_post_reset(); + } + +diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c +index 9b0a6b70ab..8ff4a00c34 100644 +--- a/hw/ppc/pegasos2.c ++++ b/hw/ppc/pegasos2.c +@@ -291,14 +291,14 @@ static void pegasos2_superio_write(uint8_t addr, uint8_t val) + cpu_physical_memory_write(PCI1_IO_BASE + 0x3f1, &val, 1); + } + +-static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason) ++static void pegasos2_machine_reset(MachineState *machine, ResetType type) + { + Pegasos2MachineState *pm = PEGASOS2_MACHINE(machine); + void *fdt; + uint64_t d[2]; + int sz; + +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + if (!pm->vof) { + return; /* Firmware should set up machine so nothing to do */ + } +diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c +index 3526852685..988fd55d88 100644 +--- a/hw/ppc/pnv.c ++++ b/hw/ppc/pnv.c +@@ -709,13 +709,13 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque) + } + } + +-static void pnv_reset(MachineState *machine, ShutdownCause reason) ++static void pnv_reset(MachineState *machine, ResetType type) + { + PnvMachineState *pnv = PNV_MACHINE(machine); + IPMIBmc *bmc; + void *fdt; + +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + + /* + * The machine should provide by default an internal BMC simulator. +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index 29e66f1b3f..11c953669a 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -1725,7 +1725,7 @@ void spapr_check_mmu_mode(bool guest_radix) + } + } + +-static void spapr_machine_reset(MachineState *machine, ShutdownCause reason) ++static void spapr_machine_reset(MachineState *machine, ResetType type) + { + SpaprMachineState *spapr = SPAPR_MACHINE(machine); + PowerPCCPU *first_ppc_cpu; +@@ -1733,7 +1733,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason) + void *fdt; + int rc; + +- if (reason != SHUTDOWN_CAUSE_SNAPSHOT_LOAD) { ++ if (type != RESET_TYPE_SNAPSHOT_LOAD) { + /* + * Record-replay snapshot load must not consume random, this was + * already replayed from initial machine reset. +@@ -1769,7 +1769,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason) + spapr_setup_hpt(spapr); + } + +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + + spapr_ovec_cleanup(spapr->ov5_cas); + spapr->ov5_cas = spapr_ovec_new(); +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index ef2a9687c7..94cad1705b 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -434,7 +434,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms) + s390_pv_prep_reset(); + } + +-static void s390_machine_reset(MachineState *machine, ShutdownCause reason) ++static void s390_machine_reset(MachineState *machine, ResetType type) + { + S390CcwMachineState *ms = S390_CCW_MACHINE(machine); + enum s390_reset reset_type; +@@ -466,7 +466,7 @@ static void s390_machine_reset(MachineState *machine, ShutdownCause reason) + * Device reset includes CPU clear resets so this has to be + * done AFTER the unprotect call above. + */ +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + s390_crypto_reset(); + + /* configure and start the ipl CPU only */ +diff --git a/include/hw/boards.h b/include/hw/boards.h +index ffefc0a625..fe011b1e86 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -10,6 +10,7 @@ + #include "qemu/module.h" + #include "qom/object.h" + #include "hw/core/cpu.h" ++#include "hw/resettable.h" + + #define TYPE_MACHINE_SUFFIX "-machine" + +@@ -253,7 +254,7 @@ struct MachineClass { + const char *deprecation_reason; + + void (*init)(MachineState *state); +- void (*reset)(MachineState *state, ShutdownCause reason); ++ void (*reset)(MachineState *state, ResetType type); + void (*wakeup)(MachineState *state); + int (*kvm_type)(MachineState *machine, const char *arg); + +diff --git a/include/sysemu/reset.h b/include/sysemu/reset.h +index ae436044a9..0e297c0e02 100644 +--- a/include/sysemu/reset.h ++++ b/include/sysemu/reset.h +@@ -27,6 +27,7 @@ + #ifndef QEMU_SYSEMU_RESET_H + #define QEMU_SYSEMU_RESET_H + ++#include "hw/resettable.h" + #include "qapi/qapi-events-run-state.h" + + typedef void QEMUResetHandler(void *opaque); +@@ -110,7 +111,7 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque); + + /** + * qemu_devices_reset: Perform a complete system reset +- * @reason: reason for the reset ++ * @reason: type of the reset + * + * This function performs the low-level work needed to do a complete reset + * of the system (calling all the callbacks registered with +@@ -121,6 +122,6 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque); + * If you want to trigger a system reset from, for instance, a device + * model, don't use this function. Use qemu_system_reset_request(). + */ +-void qemu_devices_reset(ShutdownCause reason); ++void qemu_devices_reset(ResetType type); + + #endif +diff --git a/system/runstate.c b/system/runstate.c +index a0e2a5fd22..c2c9afa905 100644 +--- a/system/runstate.c ++++ b/system/runstate.c +@@ -32,6 +32,7 @@ + #include "exec/cpu-common.h" + #include "gdbstub/syscalls.h" + #include "hw/boards.h" ++#include "hw/resettable.h" + #include "migration/misc.h" + #include "migration/postcopy-ram.h" + #include "monitor/monitor.h" +@@ -507,15 +508,23 @@ static int qemu_debug_requested(void) + void qemu_system_reset(ShutdownCause reason) + { + MachineClass *mc; ++ ResetType type; + + mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + + cpu_synchronize_all_states(); + ++ switch (reason) { ++ case SHUTDOWN_CAUSE_SNAPSHOT_LOAD: ++ type = RESET_TYPE_SNAPSHOT_LOAD; ++ break; ++ default: ++ type = RESET_TYPE_COLD; ++ } + if (mc && mc->reset) { +- mc->reset(current_machine, reason); ++ mc->reset(current_machine, type); + } else { +- qemu_devices_reset(reason); ++ qemu_devices_reset(type); + } + switch (reason) { + case SHUTDOWN_CAUSE_NONE: +-- +2.48.1 + diff --git a/kvm-s390x-introduce-s390_get_memory_limit.patch b/kvm-s390x-introduce-s390_get_memory_limit.patch new file mode 100644 index 0000000..8647d8e --- /dev/null +++ b/kvm-s390x-introduce-s390_get_memory_limit.patch @@ -0,0 +1,144 @@ +From 1dd38383832fc27f2980f33bb5e10ec1af7e3fc3 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:07 +0100 +Subject: [PATCH 15/26] s390x: introduce s390_get_memory_limit() + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [15/26] 5ae6a624a6541283cb15e90ebeb8fef3940c823b (thuth/qemu-kvm-cs) + +Let's add s390_get_memory_limit(), to query what has been successfully +set via s390_set_memory_limit(). Allow setting the limit only once. + +We'll remember the limit in the machine state. Move +s390_set_memory_limit() to machine code, merging it into +set_memory_limit(), because this really is a machine property. + +Message-ID: <20241219144115.2820241-7-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit 27221b69a3ea49339a1f82b9622126f3928e0915) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-virtio-ccw.c | 17 ++++++++++++----- + include/hw/s390x/s390-virtio-ccw.h | 8 ++++++++ + target/s390x/cpu-sysemu.c | 8 -------- + target/s390x/cpu.h | 1 - + 4 files changed, 20 insertions(+), 14 deletions(-) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 248ac28d20..f5f147eb92 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -45,6 +45,7 @@ + #include "migration/blocker.h" + #include "qapi/visitor.h" + #include "hw/s390x/cpu-topology.h" ++#include "kvm/kvm_s390x.h" + #include CONFIG_DEVICES + + static Error *pv_mig_blocker; +@@ -121,12 +122,16 @@ static void subsystem_reset(void) + } + } + +-static void set_memory_limit(uint64_t new_limit) ++static void s390_set_memory_limit(S390CcwMachineState *s390ms, ++ uint64_t new_limit) + { +- uint64_t hw_limit; +- int ret; ++ uint64_t hw_limit = 0; ++ int ret = 0; + +- ret = s390_set_memory_limit(new_limit, &hw_limit); ++ assert(!s390ms->memory_limit && new_limit); ++ if (kvm_enabled()) { ++ ret = kvm_s390_set_mem_limit(new_limit, &hw_limit); ++ } + if (ret == -E2BIG) { + error_report("host supports a maximum of %" PRIu64 " GB", + hw_limit / GiB); +@@ -135,10 +140,12 @@ static void set_memory_limit(uint64_t new_limit) + error_report("setting the guest size failed"); + exit(EXIT_FAILURE); + } ++ s390ms->memory_limit = new_limit; + } + + static void s390_memory_init(MachineState *machine) + { ++ S390CcwMachineState *s390ms = S390_CCW_MACHINE(machine); + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = machine->ram; + uint64_t ram_size = memory_region_size(ram); +@@ -154,7 +161,7 @@ static void s390_memory_init(MachineState *machine) + exit(EXIT_FAILURE); + } + +- set_memory_limit(ram_size); ++ s390_set_memory_limit(s390ms, ram_size); + + /* Map the initial memory. Must happen after setting the memory limit. */ + memory_region_add_subregion(sysmem, 0, ram); +diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h +index 996864a34e..de04336c5a 100644 +--- a/include/hw/s390x/s390-virtio-ccw.h ++++ b/include/hw/s390x/s390-virtio-ccw.h +@@ -29,10 +29,18 @@ struct S390CcwMachineState { + bool dea_key_wrap; + bool pv; + uint8_t loadparm[8]; ++ uint64_t memory_limit; + + SCLPDevice *sclp; + }; + ++static inline uint64_t s390_get_memory_limit(S390CcwMachineState *s390ms) ++{ ++ /* We expect to be called only after the limit was set. */ ++ assert(s390ms->memory_limit); ++ return s390ms->memory_limit; ++} ++ + #define S390_PTF_REASON_NONE (0x00 << 8) + #define S390_PTF_REASON_DONE (0x01 << 8) + #define S390_PTF_REASON_BUSY (0x02 << 8) +diff --git a/target/s390x/cpu-sysemu.c b/target/s390x/cpu-sysemu.c +index 1cd30c1d84..3118a25fee 100644 +--- a/target/s390x/cpu-sysemu.c ++++ b/target/s390x/cpu-sysemu.c +@@ -255,14 +255,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) + return s390_count_running_cpus(); + } + +-int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) +-{ +- if (kvm_enabled()) { +- return kvm_s390_set_mem_limit(new_limit, hw_limit); +- } +- return 0; +-} +- + void s390_set_max_pagesize(uint64_t pagesize, Error **errp) + { + if (kvm_enabled()) { +diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h +index 6a64472403..ecaf3191d2 100644 +--- a/target/s390x/cpu.h ++++ b/target/s390x/cpu.h +@@ -881,7 +881,6 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg) + + /* cpu.c */ + void s390_crypto_reset(void); +-int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit); + void s390_set_max_pagesize(uint64_t pagesize, Error **errp); + void s390_cmma_reset(void); + void s390_enable_css_support(S390CPU *cpu); +-- +2.48.1 + diff --git a/kvm-s390x-pv-prepare-for-memory-devices.patch b/kvm-s390x-pv-prepare-for-memory-devices.patch new file mode 100644 index 0000000..16ff2c8 --- /dev/null +++ b/kvm-s390x-pv-prepare-for-memory-devices.patch @@ -0,0 +1,46 @@ +From 9d5420c4370b74d60f082f2aa1225b19150ee629 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:12 +0100 +Subject: [PATCH 20/26] s390x/pv: prepare for memory devices + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [20/26] cdbe71168b9afa9657b94f1e7500568314c707a8 (thuth/qemu-kvm-cs) + +Let's avoid checking for the maxram_size, and instead rely on the memory +limit determined in s390_memory_init(), that might be larger than +maxram_size, for example due to alignment purposes. + +This check now correctly mimics what the kernel will check in +kvm_s390_pv_set_aside(), whereby a VM <= 2 GiB VM would end up using +a segment type ASCE. + +Message-ID: <20241219144115.2820241-12-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Nina Schoetterl-Glausch +Signed-off-by: David Hildenbrand +(cherry picked from commit a056332e732110c8ef0d40ffd49bd03afc2f04ca) +Signed-off-by: Thomas Huth +--- + target/s390x/kvm/pv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/s390x/kvm/pv.c b/target/s390x/kvm/pv.c +index 424cce75ca..fa66607e7b 100644 +--- a/target/s390x/kvm/pv.c ++++ b/target/s390x/kvm/pv.c +@@ -133,7 +133,7 @@ bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms) + * If the feature is not present or if the VM is not larger than 2 GiB, + * KVM_PV_ASYNC_CLEANUP_PREPARE fill fail; no point in attempting it. + */ +- if ((MACHINE(ms)->ram_size <= 2 * GiB) || ++ if (s390_get_memory_limit(ms) <= 2 * GiB || + !kvm_check_extension(kvm_state, KVM_CAP_S390_PROTECTED_ASYNC_DISABLE)) { + return false; + } +-- +2.48.1 + diff --git a/kvm-s390x-remember-the-maximum-page-size.patch b/kvm-s390x-remember-the-maximum-page-size.patch new file mode 100644 index 0000000..b2fd41e --- /dev/null +++ b/kvm-s390x-remember-the-maximum-page-size.patch @@ -0,0 +1,107 @@ +From 5a311d410bca4a5530a51c0b789ce8525d2d0653 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:13 +0100 +Subject: [PATCH 21/26] s390x: remember the maximum page size + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [21/26] 3b97c555b153d42e4fcb27dbb65fbf3edac622a4 (thuth/qemu-kvm-cs) + +Let's remember the value (successfully) set via s390_set_max_pagesize(). +This will be helpful to reject hotplugged memory devices that would exceed +this initially set page size. + +Handle it just like how we handle s390_get_memory_limit(), storing it in +the machine, and moving the handling to machine code. + +Message-ID: <20241219144115.2820241-13-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit df2ac211a62e6ced7f1495b634fa6f78962f2321) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-virtio-ccw.c | 12 +++++++++++- + include/hw/s390x/s390-virtio-ccw.h | 1 + + target/s390x/cpu-sysemu.c | 7 ------- + target/s390x/cpu.h | 1 - + 4 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 824c73536a..bd05a22b4e 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -143,6 +143,16 @@ static void s390_set_memory_limit(S390CcwMachineState *s390ms, + s390ms->memory_limit = new_limit; + } + ++static void s390_set_max_pagesize(S390CcwMachineState *s390ms, ++ uint64_t pagesize) ++{ ++ assert(!s390ms->max_pagesize && pagesize); ++ if (kvm_enabled()) { ++ kvm_s390_set_max_pagesize(pagesize, &error_fatal); ++ } ++ s390ms->max_pagesize = pagesize; ++} ++ + static void s390_memory_init(MachineState *machine) + { + S390CcwMachineState *s390ms = S390_CCW_MACHINE(machine); +@@ -191,7 +201,7 @@ static void s390_memory_init(MachineState *machine) + * Configure the maximum page size. As no memory devices were created + * yet, this is the page size of initial memory only. + */ +- s390_set_max_pagesize(qemu_maxrampagesize(), &error_fatal); ++ s390_set_max_pagesize(s390ms, qemu_maxrampagesize()); + /* Initialize storage key device */ + s390_skeys_init(); + /* Initialize storage attributes device */ +diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h +index de04336c5a..599740a998 100644 +--- a/include/hw/s390x/s390-virtio-ccw.h ++++ b/include/hw/s390x/s390-virtio-ccw.h +@@ -30,6 +30,7 @@ struct S390CcwMachineState { + bool pv; + uint8_t loadparm[8]; + uint64_t memory_limit; ++ uint64_t max_pagesize; + + SCLPDevice *sclp; + }; +diff --git a/target/s390x/cpu-sysemu.c b/target/s390x/cpu-sysemu.c +index 3118a25fee..706a5c53e2 100644 +--- a/target/s390x/cpu-sysemu.c ++++ b/target/s390x/cpu-sysemu.c +@@ -255,13 +255,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) + return s390_count_running_cpus(); + } + +-void s390_set_max_pagesize(uint64_t pagesize, Error **errp) +-{ +- if (kvm_enabled()) { +- kvm_s390_set_max_pagesize(pagesize, errp); +- } +-} +- + void s390_cmma_reset(void) + { + if (kvm_enabled()) { +diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h +index ecaf3191d2..9770a62ac9 100644 +--- a/target/s390x/cpu.h ++++ b/target/s390x/cpu.h +@@ -881,7 +881,6 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg) + + /* cpu.c */ + void s390_crypto_reset(void); +-void s390_set_max_pagesize(uint64_t pagesize, Error **errp); + void s390_cmma_reset(void); + void s390_enable_css_support(S390CPU *cpu); + void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg); +-- +2.48.1 + diff --git a/kvm-s390x-rename-s390-virtio-hcall-to-s390-hypercall.patch b/kvm-s390x-rename-s390-virtio-hcall-to-s390-hypercall.patch new file mode 100644 index 0000000..90bb4c3 --- /dev/null +++ b/kvm-s390x-rename-s390-virtio-hcall-to-s390-hypercall.patch @@ -0,0 +1,113 @@ +From 2fbdf7e3cf23daea470aaa4a29e16641feb76f3c Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:05 +0100 +Subject: [PATCH 13/26] s390x: rename s390-virtio-hcall* to s390-hypercall* + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [13/26] 3c1ef3cbb137517b306871f0a88a61a59740af5a (thuth/qemu-kvm-cs) + +Let's make it clearer that we are talking about general +QEMU/KVM-specific hypercalls. + +Message-ID: <20241219144115.2820241-5-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit 85489fc3652d0c4433c940f1a80a952e8cb5d3cb) +Signed-off-by: Thomas Huth +--- + hw/s390x/meson.build | 2 +- + hw/s390x/{s390-virtio-hcall.c => s390-hypercall.c} | 2 +- + hw/s390x/{s390-virtio-hcall.h => s390-hypercall.h} | 6 +++--- + target/s390x/kvm/kvm.c | 2 +- + target/s390x/tcg/misc_helper.c | 2 +- + 5 files changed, 7 insertions(+), 7 deletions(-) + rename hw/s390x/{s390-virtio-hcall.c => s390-hypercall.c} (97%) + rename hw/s390x/{s390-virtio-hcall.h => s390-hypercall.h} (86%) + +diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build +index d6c8c33915..e344a3bd8c 100644 +--- a/hw/s390x/meson.build ++++ b/hw/s390x/meson.build +@@ -29,7 +29,7 @@ s390x_ss.add(when: 'CONFIG_TCG', if_true: files( + )) + s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files( + 's390-virtio-ccw.c', +- 's390-virtio-hcall.c', ++ 's390-hypercall.c', + )) + s390x_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('3270-ccw.c')) + s390x_ss.add(when: 'CONFIG_VFIO', if_true: files('s390-pci-vfio.c')) +diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-hypercall.c +similarity index 97% +rename from hw/s390x/s390-virtio-hcall.c +rename to hw/s390x/s390-hypercall.c +index 5fb78a719e..f816c2b1ef 100644 +--- a/hw/s390x/s390-virtio-hcall.c ++++ b/hw/s390x/s390-hypercall.c +@@ -12,7 +12,7 @@ + #include "qemu/osdep.h" + #include "cpu.h" + #include "hw/boards.h" +-#include "hw/s390x/s390-virtio-hcall.h" ++#include "hw/s390x/s390-hypercall.h" + #include "hw/s390x/ioinst.h" + #include "hw/s390x/css.h" + #include "virtio-ccw.h" +diff --git a/hw/s390x/s390-virtio-hcall.h b/hw/s390x/s390-hypercall.h +similarity index 86% +rename from hw/s390x/s390-virtio-hcall.h +rename to hw/s390x/s390-hypercall.h +index dca456b926..2fa81dbfdd 100644 +--- a/hw/s390x/s390-virtio-hcall.h ++++ b/hw/s390x/s390-hypercall.h +@@ -9,8 +9,8 @@ + * directory. + */ + +-#ifndef HW_S390_VIRTIO_HCALL_H +-#define HW_S390_VIRTIO_HCALL_H ++#ifndef HW_S390_HYPERCALL_H ++#define HW_S390_HYPERCALL_H + + #include "cpu.h" + +@@ -21,4 +21,4 @@ + + void handle_diag_500(S390CPU *cpu, uintptr_t ra); + +-#endif /* HW_S390_VIRTIO_HCALL_H */ ++#endif /* HW_S390_HYPERCALL_H */ +diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c +index 42d6a54126..afc8d570c9 100644 +--- a/target/s390x/kvm/kvm.c ++++ b/target/s390x/kvm/kvm.c +@@ -49,7 +49,7 @@ + #include "hw/s390x/ebcdic.h" + #include "exec/memattrs.h" + #include "hw/s390x/s390-virtio-ccw.h" +-#include "hw/s390x/s390-virtio-hcall.h" ++#include "hw/s390x/s390-hypercall.h" + #include "target/s390x/kvm/pv.h" + #include CONFIG_DEVICES + +diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c +index 2b4310003b..b726a95352 100644 +--- a/target/s390x/tcg/misc_helper.c ++++ b/target/s390x/tcg/misc_helper.c +@@ -36,7 +36,7 @@ + #include "sysemu/cpus.h" + #include "sysemu/sysemu.h" + #include "hw/s390x/ebcdic.h" +-#include "hw/s390x/s390-virtio-hcall.h" ++#include "hw/s390x/s390-hypercall.h" + #include "hw/s390x/sclp.h" + #include "hw/s390x/s390_flic.h" + #include "hw/s390x/ioinst.h" +-- +2.48.1 + diff --git a/kvm-s390x-s390-hypercall-introduce-DIAG500-STORAGE_LIMIT.patch b/kvm-s390x-s390-hypercall-introduce-DIAG500-STORAGE_LIMIT.patch new file mode 100644 index 0000000..af613d5 --- /dev/null +++ b/kvm-s390x-s390-hypercall-introduce-DIAG500-STORAGE_LIMIT.patch @@ -0,0 +1,99 @@ +From 86417a068f24964422d4fd5ea301d70a0f8142d2 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:08 +0100 +Subject: [PATCH 16/26] s390x/s390-hypercall: introduce DIAG500 STORAGE_LIMIT + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [16/26] c1c341227388735450ddbba0201e7523e0658c07 (thuth/qemu-kvm-cs) + +A guest OS that supports memory hotplug / memory devices must during +boot be aware of the maximum possible physical memory address that it might +have to handle at a later stage during its runtime. + +For example, the maximum possible memory address might be required to +prepare the kernel virtual address space accordingly (e.g., select page +table hierarchy depth). + +On s390x there is currently no such mechanism that is compatible with +paravirtualized memory devices, because the whole SCLP interface was +designed around the idea of "storage increments" and "standby memory". +Paravirtualized memory devices we want to support, such as virtio-mem, have +no intersection with any of that, but could co-exist with them in the +future if ever needed. + +In particular, a guest OS must never detect and use device memory +without the help of a proper device driver. Device memory must not be +exposed in any firmware-provided memory map (SCLP or diag260 on s390x). +For this reason, these memory devices will be places in memory *above* +the "maximum storage increment" exposed via SCLP. + +Let's provide a new diag500 subcode to query the memory limit determined in +s390_memory_init(). + +Message-ID: <20241219144115.2820241-8-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit f7c168657816486527727d860b73747d41f0c5f6) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-hypercall.c | 12 +++++++++++- + hw/s390x/s390-hypercall.h | 1 + + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/hw/s390x/s390-hypercall.c b/hw/s390x/s390-hypercall.c +index f816c2b1ef..ac1b08b2cd 100644 +--- a/hw/s390x/s390-hypercall.c ++++ b/hw/s390x/s390-hypercall.c +@@ -11,7 +11,7 @@ + + #include "qemu/osdep.h" + #include "cpu.h" +-#include "hw/boards.h" ++#include "hw/s390x/s390-virtio-ccw.h" + #include "hw/s390x/s390-hypercall.h" + #include "hw/s390x/ioinst.h" + #include "hw/s390x/css.h" +@@ -57,6 +57,13 @@ static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data) + return 0; + } + ++static uint64_t handle_storage_limit(void) ++{ ++ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine()); ++ ++ return s390_get_memory_limit(s390ms) - 1; ++} ++ + void handle_diag_500(S390CPU *cpu, uintptr_t ra) + { + CPUS390XState *env = &cpu->env; +@@ -69,6 +76,9 @@ void handle_diag_500(S390CPU *cpu, uintptr_t ra) + case DIAG500_VIRTIO_CCW_NOTIFY: + env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]); + break; ++ case DIAG500_STORAGE_LIMIT: ++ env->regs[2] = handle_storage_limit(); ++ break; + default: + s390_program_interrupt(env, PGM_SPECIFICATION, ra); + } +diff --git a/hw/s390x/s390-hypercall.h b/hw/s390x/s390-hypercall.h +index 2fa81dbfdd..4f07209128 100644 +--- a/hw/s390x/s390-hypercall.h ++++ b/hw/s390x/s390-hypercall.h +@@ -18,6 +18,7 @@ + #define DIAG500_VIRTIO_RESET 1 /* legacy */ + #define DIAG500_VIRTIO_SET_STATUS 2 /* legacy */ + #define DIAG500_VIRTIO_CCW_NOTIFY 3 /* KVM_S390_VIRTIO_CCW_NOTIFY */ ++#define DIAG500_STORAGE_LIMIT 4 + + void handle_diag_500(S390CPU *cpu, uintptr_t ra); + +-- +2.48.1 + diff --git a/kvm-s390x-s390-skeys-prepare-for-memory-devices.patch b/kvm-s390x-s390-skeys-prepare-for-memory-devices.patch new file mode 100644 index 0000000..885ebf1 --- /dev/null +++ b/kvm-s390x-s390-skeys-prepare-for-memory-devices.patch @@ -0,0 +1,56 @@ +From 53d1b43699c6b30583f41a18a33c28893718aeac Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:10 +0100 +Subject: [PATCH 18/26] s390x/s390-skeys: prepare for memory devices + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [18/26] 47edda0eeb6d5932f81633f2d9d294b1ca5f413c (thuth/qemu-kvm-cs) + +With memory devices, we will have storage keys for memory that +exceeds the initial ram size. + +The TODO already states that current handling is subopimal, +but we won't worry about improving that (TCG-only) thing for now. + +Message-ID: <20241219144115.2820241-10-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit d1e3c2ac41b3f73708682e4e8212c32ad35013b9) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-skeys.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c +index bf22d6863e..e4297b3b8a 100644 +--- a/hw/s390x/s390-skeys.c ++++ b/hw/s390x/s390-skeys.c +@@ -11,7 +11,7 @@ + + #include "qemu/osdep.h" + #include "qemu/units.h" +-#include "hw/boards.h" ++#include "hw/s390x/s390-virtio-ccw.h" + #include "hw/qdev-properties.h" + #include "hw/s390x/storage-keys.h" + #include "qapi/error.h" +@@ -251,9 +251,9 @@ static bool qemu_s390_enable_skeys(S390SKeysState *ss) + * g_once_init_enter() is good enough. + */ + if (g_once_init_enter(&initialized)) { +- MachineState *machine = MACHINE(qdev_get_machine()); ++ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine()); + +- skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE; ++ skeys->key_count = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE; + skeys->keydata = g_malloc0(skeys->key_count); + g_once_init_leave(&initialized, 1); + } +-- +2.48.1 + diff --git a/kvm-s390x-s390-stattrib-kvm-prepare-for-memory-devices-a.patch b/kvm-s390x-s390-stattrib-kvm-prepare-for-memory-devices-a.patch new file mode 100644 index 0000000..e8102a4 --- /dev/null +++ b/kvm-s390x-s390-stattrib-kvm-prepare-for-memory-devices-a.patch @@ -0,0 +1,155 @@ +From 1195c91d10892a888870248fd881612955b9e1eb Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:09 +0100 +Subject: [PATCH 17/26] s390x/s390-stattrib-kvm: prepare for memory devices and + sparse memory layouts + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [17/26] 799aa7b2b9cc2a948e9f391bc0ecf739254c78b1 (thuth/qemu-kvm-cs) + +With memory devices, we will have storage attributes for memory that +exceeds the initial ram size. Further, we can easily have memory holes, +for which there (currently) are no storage attributes. + +In particular, with memory holes, KVM_S390_SET_CMMA_BITS will fail to set +some storage attributes. + +So let's do it like we handle storage keys migration, relying on +guest_phys_blocks_append(). However, in contrast to storage key +migration, we will handle it on the migration destination. + +This is a preparation for virtio-mem support. Note that ever since the +"early migration" feature was added (x-early-migration), the state +of device blocks (plugged/unplugged) is migrated early such that +guest_phys_blocks_append() will properly consider all currently plugged +memory blocks and skip any unplugged ones. + +In the future, we should try getting rid of the large temporary buffer +and also not send any attributes for any memory holes, just so they +get ignored on the destination. + +Message-ID: <20241219144115.2820241-9-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit 241e6b2d27b090b17cda5b011b2064544b0c458b) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-stattrib-kvm.c | 67 +++++++++++++++++++++++------------- + 1 file changed, 43 insertions(+), 24 deletions(-) + +diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c +index eeaa811098..33ec91422a 100644 +--- a/hw/s390x/s390-stattrib-kvm.c ++++ b/hw/s390x/s390-stattrib-kvm.c +@@ -10,11 +10,12 @@ + */ + + #include "qemu/osdep.h" +-#include "hw/boards.h" ++#include "hw/s390x/s390-virtio-ccw.h" + #include "migration/qemu-file.h" + #include "hw/s390x/storage-attributes.h" + #include "qemu/error-report.h" + #include "sysemu/kvm.h" ++#include "sysemu/memory_mapping.h" + #include "exec/ram_addr.h" + #include "kvm/kvm_s390x.h" + #include "qapi/error.h" +@@ -84,8 +85,8 @@ static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa, + uint8_t *values) + { + KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa); +- MachineState *machine = MACHINE(qdev_get_machine()); +- unsigned long max = machine->ram_size / TARGET_PAGE_SIZE; ++ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine()); ++ unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE; + + if (start_gfn + count > max) { + error_report("Out of memory bounds when setting storage attributes"); +@@ -103,39 +104,57 @@ static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa, + static void kvm_s390_stattrib_synchronize(S390StAttribState *sa) + { + KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa); +- MachineState *machine = MACHINE(qdev_get_machine()); +- unsigned long max = machine->ram_size / TARGET_PAGE_SIZE; +- /* We do not need to reach the maximum buffer size allowed */ +- unsigned long cx, len = KVM_S390_SKEYS_MAX / 2; ++ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine()); ++ unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE; ++ unsigned long start_gfn, end_gfn, pages; ++ GuestPhysBlockList guest_phys_blocks; ++ GuestPhysBlock *block; + int r; + struct kvm_s390_cmma_log clog = { + .flags = 0, + .mask = ~0ULL, + }; + +- if (sas->incoming_buffer) { +- for (cx = 0; cx + len <= max; cx += len) { +- clog.start_gfn = cx; +- clog.count = len; +- clog.values = (uint64_t)(sas->incoming_buffer + cx); +- r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog); +- if (r) { +- error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r)); +- return; +- } +- } +- if (cx < max) { +- clog.start_gfn = cx; +- clog.count = max - cx; +- clog.values = (uint64_t)(sas->incoming_buffer + cx); ++ if (!sas->incoming_buffer) { ++ return; ++ } ++ guest_phys_blocks_init(&guest_phys_blocks); ++ guest_phys_blocks_append(&guest_phys_blocks); ++ ++ QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) { ++ assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE)); ++ assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE)); ++ ++ start_gfn = block->target_start / TARGET_PAGE_SIZE; ++ end_gfn = block->target_end / TARGET_PAGE_SIZE; ++ ++ while (start_gfn < end_gfn) { ++ /* Don't exceed the maximum buffer size. */ ++ pages = MIN(end_gfn - start_gfn, KVM_S390_SKEYS_MAX / 2); ++ ++ /* ++ * If we ever get guest physical memory beyond the configured ++ * memory limit, something went very wrong. ++ */ ++ assert(start_gfn + pages <= max); ++ ++ clog.start_gfn = start_gfn; ++ clog.count = pages; ++ clog.values = (uint64_t)(sas->incoming_buffer + start_gfn); + r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog); + if (r) { + error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r)); ++ goto out; + } ++ ++ start_gfn += pages; + } +- g_free(sas->incoming_buffer); +- sas->incoming_buffer = NULL; + } ++ ++out: ++ guest_phys_blocks_free(&guest_phys_blocks); ++ g_free(sas->incoming_buffer); ++ sas->incoming_buffer = NULL; + } + + static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val, +-- +2.48.1 + diff --git a/kvm-s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch b/kvm-s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch new file mode 100644 index 0000000..fa99566 --- /dev/null +++ b/kvm-s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch @@ -0,0 +1,63 @@ +From 4ee3076ac566622929f9410636483c4f0b2da967 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:02 +0100 +Subject: [PATCH 10/26] s390x/s390-virtio-ccw: don't crash on weird RAM sizes + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [10/26] 55738da52f3cf4746bee2b17780a10720fa05863 (thuth/qemu-kvm-cs) + +KVM is not happy when starting a VM with weird RAM sizes: + + # qemu-system-s390x --enable-kvm --nographic -m 1234K + qemu-system-s390x: kvm_set_user_memory_region: KVM_SET_USER_MEMORY_REGION + failed, slot=0, start=0x0, size=0x244000: Invalid argument + kvm_set_phys_mem: error registering slot: Invalid argument + Aborted (core dumped) + +Let's handle that in a better way by rejecting such weird RAM sizes +right from the start: + + # qemu-system-s390x --enable-kvm --nographic -m 1234K + qemu-system-s390x: ram size must be multiples of 1 MiB + +Message-ID: <20241219144115.2820241-2-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Eric Farman +Reviewed-by: Thomas Huth +Acked-by: Janosch Frank +Signed-off-by: David Hildenbrand +(cherry picked from commit 14e568ab4836347481af2e334009c385f456a734) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-virtio-ccw.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 94cad1705b..82ded9666c 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -180,6 +180,17 @@ static void s390_memory_init(MemoryRegion *ram) + { + MemoryRegion *sysmem = get_system_memory(); + ++ if (!QEMU_IS_ALIGNED(memory_region_size(ram), 1 * MiB)) { ++ /* ++ * SCLP cannot possibly expose smaller granularity right now and KVM ++ * cannot handle smaller granularity. As we don't support NUMA, the ++ * region size directly corresponds to machine->ram_size, and the region ++ * is a single RAM memory region. ++ */ ++ error_report("ram size must be multiples of 1 MiB"); ++ exit(EXIT_FAILURE); ++ } ++ + /* allocate RAM for core */ + memory_region_add_subregion(sysmem, 0, ram); + +-- +2.48.1 + diff --git a/kvm-s390x-s390-virtio-ccw-move-setting-the-maximum-guest.patch b/kvm-s390x-s390-virtio-ccw-move-setting-the-maximum-guest.patch new file mode 100644 index 0000000..5a498d6 --- /dev/null +++ b/kvm-s390x-s390-virtio-ccw-move-setting-the-maximum-guest.patch @@ -0,0 +1,140 @@ +From 9ec2d356210f1e66f50519cc4d58633a13db9004 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:06 +0100 +Subject: [PATCH 14/26] s390x/s390-virtio-ccw: move setting the maximum guest + size from sclp to machine code + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [14/26] a5970c1c6d8d09a473a25a7eee533ec3a6711ec8 (thuth/qemu-kvm-cs) + +Nowadays, it feels more natural to have that code located in +s390_memory_init(), where we also have direct access to the machine +object. + +While at it, use the actual RAM size, not the maximum RAM size which +cannot currently be reached without support for any memory devices. +Consequently update s390_pv_vm_try_disable_async() to rely on the RAM size +as well, to avoid temporary issues while we further rework that +handling. + +set_memory_limit() is temporary, we'll merge it with +s390_set_memory_limit() next. + +Message-ID: <20241219144115.2820241-6-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit 3c6fb557d295949bea291c3bf88ee9c83392e78c) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-virtio-ccw.c | 28 ++++++++++++++++++++++++---- + hw/s390x/sclp.c | 11 ----------- + target/s390x/kvm/pv.c | 2 +- + 3 files changed, 25 insertions(+), 16 deletions(-) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index d47e99028e..248ac28d20 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -121,11 +121,29 @@ static void subsystem_reset(void) + } + } + +-static void s390_memory_init(MemoryRegion *ram) ++static void set_memory_limit(uint64_t new_limit) ++{ ++ uint64_t hw_limit; ++ int ret; ++ ++ ret = s390_set_memory_limit(new_limit, &hw_limit); ++ if (ret == -E2BIG) { ++ error_report("host supports a maximum of %" PRIu64 " GB", ++ hw_limit / GiB); ++ exit(EXIT_FAILURE); ++ } else if (ret) { ++ error_report("setting the guest size failed"); ++ exit(EXIT_FAILURE); ++ } ++} ++ ++static void s390_memory_init(MachineState *machine) + { + MemoryRegion *sysmem = get_system_memory(); ++ MemoryRegion *ram = machine->ram; ++ uint64_t ram_size = memory_region_size(ram); + +- if (!QEMU_IS_ALIGNED(memory_region_size(ram), 1 * MiB)) { ++ if (!QEMU_IS_ALIGNED(ram_size, 1 * MiB)) { + /* + * SCLP cannot possibly expose smaller granularity right now and KVM + * cannot handle smaller granularity. As we don't support NUMA, the +@@ -136,7 +154,9 @@ static void s390_memory_init(MemoryRegion *ram) + exit(EXIT_FAILURE); + } + +- /* allocate RAM for core */ ++ set_memory_limit(ram_size); ++ ++ /* Map the initial memory. Must happen after setting the memory limit. */ + memory_region_add_subregion(sysmem, 0, ram); + + /* +@@ -211,7 +231,7 @@ static void ccw_init(MachineState *machine) + qdev_realize_and_unref(DEVICE(ms->sclp), NULL, &error_fatal); + + /* init memory + setup max page size. Required for the CPU model */ +- s390_memory_init(machine->ram); ++ s390_memory_init(machine); + + /* init CPUs (incl. CPU model) early so s390_has_feature() works */ + s390_init_cpus(machine); +diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c +index 8757626b5c..73e88ab4eb 100644 +--- a/hw/s390x/sclp.c ++++ b/hw/s390x/sclp.c +@@ -376,10 +376,7 @@ void sclp_service_interrupt(uint32_t sccb) + /* qemu object creation and initialization functions */ + static void sclp_realize(DeviceState *dev, Error **errp) + { +- MachineState *machine = MACHINE(qdev_get_machine()); + SCLPDevice *sclp = SCLP(dev); +- uint64_t hw_limit; +- int ret; + + /* + * qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long +@@ -389,14 +386,6 @@ static void sclp_realize(DeviceState *dev, Error **errp) + if (!sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), errp)) { + return; + } +- +- ret = s390_set_memory_limit(machine->maxram_size, &hw_limit); +- if (ret == -E2BIG) { +- error_setg(errp, "host supports a maximum of %" PRIu64 " GB", +- hw_limit / GiB); +- } else if (ret) { +- error_setg(errp, "setting the guest size failed"); +- } + } + + static void sclp_memory_init(SCLPDevice *sclp) +diff --git a/target/s390x/kvm/pv.c b/target/s390x/kvm/pv.c +index dde836d21a..424cce75ca 100644 +--- a/target/s390x/kvm/pv.c ++++ b/target/s390x/kvm/pv.c +@@ -133,7 +133,7 @@ bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms) + * If the feature is not present or if the VM is not larger than 2 GiB, + * KVM_PV_ASYNC_CLEANUP_PREPARE fill fail; no point in attempting it. + */ +- if ((MACHINE(ms)->maxram_size <= 2 * GiB) || ++ if ((MACHINE(ms)->ram_size <= 2 * GiB) || + !kvm_check_extension(kvm_state, KVM_CAP_S390_PROTECTED_ASYNC_DISABLE)) { + return false; + } +-- +2.48.1 + diff --git a/kvm-s390x-s390-virtio-ccw-prepare-for-memory-devices.patch b/kvm-s390x-s390-virtio-ccw-prepare-for-memory-devices.patch new file mode 100644 index 0000000..17e7e6a --- /dev/null +++ b/kvm-s390x-s390-virtio-ccw-prepare-for-memory-devices.patch @@ -0,0 +1,117 @@ +From 0e7d7bf86fb242c1ea90bf9648fb061626790eda Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:11 +0100 +Subject: [PATCH 19/26] s390x/s390-virtio-ccw: prepare for memory devices + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [19/26] 2441c8c5f5a06d5ca93188dd44e8a08f06d1722b (thuth/qemu-kvm-cs) + +Let's prepare our address space for memory devices if enabled via +"maxmem" and if we have CONFIG_MEM_DEVICE enabled at all. Note that +CONFIG_MEM_DEVICE will be selected automatically once we add support +for devices. + +Just like on other architectures, the region container for memory devices +is placed directly above our initial memory. For now, we only align the +start address of the region up to 1 GiB, but we won't add any additional +space to the region for internal alignment purposes; this can be done in +the future if really required. + +The RAM size returned via SCLP is not modified, as this only +covers initial RAM (and standby memory we don't implement) and not memory +devices; clarify that in the docs of read_SCP_info(). Existing OSes without +support for memory devices will keep working as is, even when memory +devices would be attached the VM. + +Guest OSs which support memory devices, such as virtio-mem, will +consult diag500(), to find out the maximum possible pfn. Guest OSes that +don't support memory devices, don't have to be changed and will continue +relying on information provided by SCLP. + +There are no remaining maxram_size users in s390x code, and the remaining +ram_size users only care about initial RAM: +* hw/s390x/ipl.c +* hw/s390x/s390-hypercall.c +* hw/s390x/sclp.c +* target/s390x/kvm/pv.c + +Message-ID: <20241219144115.2820241-11-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit 1e86400298cf0fed5f7d49427db477775b859093) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-virtio-ccw.c | 23 ++++++++++++++++++++++- + hw/s390x/sclp.c | 6 +++++- + 2 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index f5f147eb92..824c73536a 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -149,6 +149,7 @@ static void s390_memory_init(MachineState *machine) + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = machine->ram; + uint64_t ram_size = memory_region_size(ram); ++ uint64_t devmem_base, devmem_size; + + if (!QEMU_IS_ALIGNED(ram_size, 1 * MiB)) { + /* +@@ -161,11 +162,31 @@ static void s390_memory_init(MachineState *machine) + exit(EXIT_FAILURE); + } + +- s390_set_memory_limit(s390ms, ram_size); ++ devmem_size = 0; ++ devmem_base = ram_size; ++#ifdef CONFIG_MEM_DEVICE ++ if (machine->ram_size < machine->maxram_size) { ++ ++ /* ++ * Make sure memory devices have a sane default alignment, even ++ * when weird initial memory sizes are specified. ++ */ ++ devmem_base = QEMU_ALIGN_UP(devmem_base, 1 * GiB); ++ devmem_size = machine->maxram_size - machine->ram_size; ++ } ++#endif ++ s390_set_memory_limit(s390ms, devmem_base + devmem_size); + + /* Map the initial memory. Must happen after setting the memory limit. */ + memory_region_add_subregion(sysmem, 0, ram); + ++ /* Initialize address space for memory devices. */ ++#ifdef CONFIG_MEM_DEVICE ++ if (devmem_size) { ++ machine_memory_devices_init(machine, devmem_base, devmem_size); ++ } ++#endif /* CONFIG_MEM_DEVICE */ ++ + /* + * Configure the maximum page size. As no memory devices were created + * yet, this is the page size of initial memory only. +diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c +index 73e88ab4eb..5945c9b1d8 100644 +--- a/hw/s390x/sclp.c ++++ b/hw/s390x/sclp.c +@@ -161,7 +161,11 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) + read_info->rnsize2 = cpu_to_be32(rnsize); + } + +- /* we don't support standby memory, maxram_size is never exposed */ ++ /* ++ * We don't support standby memory. maxram_size is used for sizing the ++ * memory device region, which is not exposed through SCLP but through ++ * diag500. ++ */ + rnmax = machine->ram_size >> sclp->increment_size; + if (rnmax < 0x10000) { + read_info->rnmax = cpu_to_be16(rnmax); +-- +2.48.1 + diff --git a/kvm-s390x-s390-virtio-hcall-prepare-for-more-diag500-hyp.patch b/kvm-s390x-s390-virtio-hcall-prepare-for-more-diag500-hyp.patch new file mode 100644 index 0000000..4bc283e --- /dev/null +++ b/kvm-s390x-s390-virtio-hcall-prepare-for-more-diag500-hyp.patch @@ -0,0 +1,163 @@ +From d2764db41fc6edcead9ad27b8d31e7bff524c0c0 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:04 +0100 +Subject: [PATCH 12/26] s390x/s390-virtio-hcall: prepare for more diag500 + hypercalls + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [12/26] 6573602d71b9e70679a48315f913309be29d6239 (thuth/qemu-kvm-cs) + +Let's generalize, abstracting the virtio bits. diag500 is now a generic +hypercall to handle QEMU/KVM specific things. Explicitly specify all +already defined subcodes, including legacy ones (so we know what we can +use for new hypercalls). + +Move the PGM_SPECIFICATION injection into the renamed function +handle_diag_500(), so we can turn it into a void function. + +We'll rename the files separately, so git properly detects the rename. + +Message-ID: <20241219144115.2820241-4-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Signed-off-by: David Hildenbrand +(cherry picked from commit 6e9cc2da4e8b997fd6ff3249034f436b84fc7974) +Signed-off-by: Thomas Huth +--- + hw/s390x/s390-virtio-hcall.c | 15 ++++++++------- + hw/s390x/s390-virtio-hcall.h | 11 ++++++----- + target/s390x/kvm/kvm.c | 20 +++----------------- + target/s390x/tcg/misc_helper.c | 5 +++-- + 4 files changed, 20 insertions(+), 31 deletions(-) + +diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c +index ca49e3cd22..5fb78a719e 100644 +--- a/hw/s390x/s390-virtio-hcall.c ++++ b/hw/s390x/s390-virtio-hcall.c +@@ -1,5 +1,5 @@ + /* +- * Support for virtio hypercalls on s390 ++ * Support for QEMU/KVM hypercalls on s390 + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck +@@ -57,18 +57,19 @@ static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data) + return 0; + } + +-int s390_virtio_hypercall(CPUS390XState *env) ++void handle_diag_500(S390CPU *cpu, uintptr_t ra) + { ++ CPUS390XState *env = &cpu->env; + const uint64_t subcode = env->regs[1]; + + switch (subcode) { +- case KVM_S390_VIRTIO_NOTIFY: ++ case DIAG500_VIRTIO_NOTIFY: + env->regs[2] = handle_virtio_notify(env->regs[2]); +- return 0; +- case KVM_S390_VIRTIO_CCW_NOTIFY: ++ break; ++ case DIAG500_VIRTIO_CCW_NOTIFY: + env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]); +- return 0; ++ break; + default: +- return -EINVAL; ++ s390_program_interrupt(env, PGM_SPECIFICATION, ra); + } + } +diff --git a/hw/s390x/s390-virtio-hcall.h b/hw/s390x/s390-virtio-hcall.h +index 3d9fe147d2..dca456b926 100644 +--- a/hw/s390x/s390-virtio-hcall.h ++++ b/hw/s390x/s390-virtio-hcall.h +@@ -1,5 +1,5 @@ + /* +- * Support for virtio hypercalls on s390x ++ * Support for QEMU/KVM hypercalls on s390x + * + * Copyright IBM Corp. 2012, 2017 + * Author(s): Cornelia Huck +@@ -12,12 +12,13 @@ + #ifndef HW_S390_VIRTIO_HCALL_H + #define HW_S390_VIRTIO_HCALL_H + +-#include "standard-headers/asm-s390/virtio-ccw.h" + #include "cpu.h" + +-/* The only thing that we need from the old kvm_virtio.h file */ +-#define KVM_S390_VIRTIO_NOTIFY 0 ++#define DIAG500_VIRTIO_NOTIFY 0 /* legacy, implemented as a NOP */ ++#define DIAG500_VIRTIO_RESET 1 /* legacy */ ++#define DIAG500_VIRTIO_SET_STATUS 2 /* legacy */ ++#define DIAG500_VIRTIO_CCW_NOTIFY 3 /* KVM_S390_VIRTIO_CCW_NOTIFY */ + +-int s390_virtio_hypercall(CPUS390XState *env); ++void handle_diag_500(S390CPU *cpu, uintptr_t ra); + + #endif /* HW_S390_VIRTIO_HCALL_H */ +diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c +index 5947dda829..42d6a54126 100644 +--- a/target/s390x/kvm/kvm.c ++++ b/target/s390x/kvm/kvm.c +@@ -1492,22 +1492,6 @@ static int handle_e3(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl) + return r; + } + +-static int handle_hypercall(S390CPU *cpu, struct kvm_run *run) +-{ +- CPUS390XState *env = &cpu->env; +- int ret = -EINVAL; +- +-#ifdef CONFIG_S390_CCW_VIRTIO +- ret = s390_virtio_hypercall(env); +-#endif /* CONFIG_S390_CCW_VIRTIO */ +- if (ret == -EINVAL) { +- kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION); +- return 0; +- } +- +- return ret; +-} +- + static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run) + { + uint64_t r1, r3; +@@ -1603,9 +1587,11 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) + case DIAG_SET_CONTROL_PROGRAM_CODES: + handle_diag_318(cpu, run); + break; ++#ifdef CONFIG_S390_CCW_VIRTIO + case DIAG_KVM_HYPERCALL: +- r = handle_hypercall(cpu, run); ++ handle_diag_500(cpu, RA_IGNORED); + break; ++#endif /* CONFIG_S390_CCW_VIRTIO */ + case DIAG_KVM_BREAKPOINT: + r = handle_sw_breakpoint(cpu, run); + break; +diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c +index f44136a568..2b4310003b 100644 +--- a/target/s390x/tcg/misc_helper.c ++++ b/target/s390x/tcg/misc_helper.c +@@ -119,10 +119,11 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) + switch (num) { + #ifdef CONFIG_S390_CCW_VIRTIO + case 0x500: +- /* KVM hypercall */ ++ /* QEMU/KVM hypercall */ + bql_lock(); +- r = s390_virtio_hypercall(env); ++ handle_diag_500(env_archcpu(env), GETPC()); + bql_unlock(); ++ r = 0; + break; + #endif /* CONFIG_S390_CCW_VIRTIO */ + case 0x44: +-- +2.48.1 + diff --git a/kvm-s390x-s390-virtio-hcall-remove-hypercall-registratio.patch b/kvm-s390x-s390-virtio-hcall-remove-hypercall-registratio.patch new file mode 100644 index 0000000..14d03de --- /dev/null +++ b/kvm-s390x-s390-virtio-hcall-remove-hypercall-registratio.patch @@ -0,0 +1,296 @@ +From 16ccb16d393a3e63936dc993c30c67fdecb1f120 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:03 +0100 +Subject: [PATCH 11/26] s390x/s390-virtio-hcall: remove hypercall registration + mechanism + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [11/26] 5e8d2720fe9fd6e6e24487d71988821f1cf27f17 (thuth/qemu-kvm-cs) + +Nowadays, we only have a single machine type in QEMU, everything is based +on virtio-ccw and the traditional virtio machine does no longer exist. No +need to dynamically register diag500 handlers. Move the two existing +handlers into s390-virtio-hcall.c. + +Message-ID: <20241219144115.2820241-3-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Thomas Huth +Acked-by: Christian Borntraeger +Signed-off-by: David Hildenbrand +(cherry picked from commit 4be0fce498d0a08f18b3a9accdb9ded79484d30a) +Signed-off-by: Thomas Huth +--- + hw/s390x/meson.build | 6 ++-- + hw/s390x/s390-virtio-ccw.c | 58 ------------------------------ + hw/s390x/s390-virtio-hcall.c | 65 +++++++++++++++++++++++++--------- + hw/s390x/s390-virtio-hcall.h | 2 -- + target/s390x/kvm/kvm.c | 5 ++- + target/s390x/tcg/misc_helper.c | 3 ++ + 6 files changed, 60 insertions(+), 79 deletions(-) + +diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build +index 482fd13420..d6c8c33915 100644 +--- a/hw/s390x/meson.build ++++ b/hw/s390x/meson.build +@@ -12,7 +12,6 @@ s390x_ss.add(files( + 's390-pci-inst.c', + 's390-skeys.c', + 's390-stattrib.c', +- 's390-virtio-hcall.c', + 'sclp.c', + 'sclpcpu.c', + 'sclpquiesce.c', +@@ -28,7 +27,10 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files( + s390x_ss.add(when: 'CONFIG_TCG', if_true: files( + 'tod-tcg.c', + )) +-s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files('s390-virtio-ccw.c')) ++s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files( ++ 's390-virtio-ccw.c', ++ 's390-virtio-hcall.c', ++)) + s390x_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('3270-ccw.c')) + s390x_ss.add(when: 'CONFIG_VFIO', if_true: files('s390-pci-vfio.c')) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 82ded9666c..d47e99028e 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -16,11 +16,8 @@ + #include "exec/ram_addr.h" + #include "exec/confidential-guest-support.h" + #include "hw/boards.h" +-#include "hw/s390x/s390-virtio-hcall.h" + #include "hw/s390x/sclp.h" + #include "hw/s390x/s390_flic.h" +-#include "hw/s390x/ioinst.h" +-#include "hw/s390x/css.h" + #include "virtio-ccw.h" + #include "qemu/config-file.h" + #include "qemu/ctype.h" +@@ -124,58 +121,6 @@ static void subsystem_reset(void) + } + } + +-static int virtio_ccw_hcall_notify(const uint64_t *args) +-{ +- uint64_t subch_id = args[0]; +- uint64_t data = args[1]; +- SubchDev *sch; +- VirtIODevice *vdev; +- int cssid, ssid, schid, m; +- uint16_t vq_idx = data; +- +- if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) { +- return -EINVAL; +- } +- sch = css_find_subch(m, cssid, ssid, schid); +- if (!sch || !css_subch_visible(sch)) { +- return -EINVAL; +- } +- +- vdev = virtio_ccw_get_vdev(sch); +- if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) { +- return -EINVAL; +- } +- +- if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) { +- virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx), +- (data >> 16) & 0xFFFF); +- } +- +- virtio_queue_notify(vdev, vq_idx); +- return 0; +-} +- +-static int virtio_ccw_hcall_early_printk(const uint64_t *args) +-{ +- uint64_t mem = args[0]; +- MachineState *ms = MACHINE(qdev_get_machine()); +- +- if (mem < ms->ram_size) { +- /* Early printk */ +- return 0; +- } +- return -EINVAL; +-} +- +-static void virtio_ccw_register_hcalls(void) +-{ +- s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, +- virtio_ccw_hcall_notify); +- /* Tolerate early printk. */ +- s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY, +- virtio_ccw_hcall_early_printk); +-} +- + static void s390_memory_init(MemoryRegion *ram) + { + MemoryRegion *sysmem = get_system_memory(); +@@ -296,9 +241,6 @@ static void ccw_init(MachineState *machine) + OBJECT(dev)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + +- /* register hypercalls */ +- virtio_ccw_register_hcalls(); +- + s390_enable_css_support(s390_cpu_addr2state(0)); + + ret = css_create_css_image(VIRTUAL_CSSID, true); +diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c +index ec7cf8beb3..ca49e3cd22 100644 +--- a/hw/s390x/s390-virtio-hcall.c ++++ b/hw/s390x/s390-virtio-hcall.c +@@ -11,31 +11,64 @@ + + #include "qemu/osdep.h" + #include "cpu.h" ++#include "hw/boards.h" + #include "hw/s390x/s390-virtio-hcall.h" ++#include "hw/s390x/ioinst.h" ++#include "hw/s390x/css.h" ++#include "virtio-ccw.h" + +-#define MAX_DIAG_SUBCODES 255 ++static int handle_virtio_notify(uint64_t mem) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); + +-static s390_virtio_fn s390_diag500_table[MAX_DIAG_SUBCODES]; ++ if (mem < ms->ram_size) { ++ /* Early printk */ ++ return 0; ++ } ++ return -EINVAL; ++} + +-void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn) ++static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data) + { +- assert(code < MAX_DIAG_SUBCODES); +- assert(!s390_diag500_table[code]); ++ SubchDev *sch; ++ VirtIODevice *vdev; ++ int cssid, ssid, schid, m; ++ uint16_t vq_idx = data; ++ ++ if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) { ++ return -EINVAL; ++ } ++ sch = css_find_subch(m, cssid, ssid, schid); ++ if (!sch || !css_subch_visible(sch)) { ++ return -EINVAL; ++ } + +- s390_diag500_table[code] = fn; ++ vdev = virtio_ccw_get_vdev(sch); ++ if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) { ++ return -EINVAL; ++ } ++ ++ if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) { ++ virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx), ++ (data >> 16) & 0xFFFF); ++ } ++ ++ virtio_queue_notify(vdev, vq_idx); ++ return 0; + } + + int s390_virtio_hypercall(CPUS390XState *env) + { +- s390_virtio_fn fn; +- +- if (env->regs[1] < MAX_DIAG_SUBCODES) { +- fn = s390_diag500_table[env->regs[1]]; +- if (fn) { +- env->regs[2] = fn(&env->regs[2]); +- return 0; +- } +- } ++ const uint64_t subcode = env->regs[1]; + +- return -EINVAL; ++ switch (subcode) { ++ case KVM_S390_VIRTIO_NOTIFY: ++ env->regs[2] = handle_virtio_notify(env->regs[2]); ++ return 0; ++ case KVM_S390_VIRTIO_CCW_NOTIFY: ++ env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]); ++ return 0; ++ default: ++ return -EINVAL; ++ } + } +diff --git a/hw/s390x/s390-virtio-hcall.h b/hw/s390x/s390-virtio-hcall.h +index 3ae6d6ae3a..3d9fe147d2 100644 +--- a/hw/s390x/s390-virtio-hcall.h ++++ b/hw/s390x/s390-virtio-hcall.h +@@ -18,8 +18,6 @@ + /* The only thing that we need from the old kvm_virtio.h file */ + #define KVM_S390_VIRTIO_NOTIFY 0 + +-typedef int (*s390_virtio_fn)(const uint64_t *args); +-void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); + int s390_virtio_hypercall(CPUS390XState *env); + + #endif /* HW_S390_VIRTIO_HCALL_H */ +diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c +index 7a0ca5570f..5947dda829 100644 +--- a/target/s390x/kvm/kvm.c ++++ b/target/s390x/kvm/kvm.c +@@ -51,6 +51,7 @@ + #include "hw/s390x/s390-virtio-ccw.h" + #include "hw/s390x/s390-virtio-hcall.h" + #include "target/s390x/kvm/pv.h" ++#include CONFIG_DEVICES + + #define kvm_vm_check_mem_attr(s, attr) \ + kvm_vm_check_attr(s, KVM_S390_VM_MEM_CTRL, attr) +@@ -1494,9 +1495,11 @@ static int handle_e3(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl) + static int handle_hypercall(S390CPU *cpu, struct kvm_run *run) + { + CPUS390XState *env = &cpu->env; +- int ret; ++ int ret = -EINVAL; + ++#ifdef CONFIG_S390_CCW_VIRTIO + ret = s390_virtio_hypercall(env); ++#endif /* CONFIG_S390_CCW_VIRTIO */ + if (ret == -EINVAL) { + kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION); + return 0; +diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c +index 303f86d363..f44136a568 100644 +--- a/target/s390x/tcg/misc_helper.c ++++ b/target/s390x/tcg/misc_helper.c +@@ -43,6 +43,7 @@ + #include "hw/s390x/s390-pci-inst.h" + #include "hw/boards.h" + #include "hw/s390x/tod.h" ++#include CONFIG_DEVICES + #endif + + /* #define DEBUG_HELPER */ +@@ -116,12 +117,14 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) + uint64_t r; + + switch (num) { ++#ifdef CONFIG_S390_CCW_VIRTIO + case 0x500: + /* KVM hypercall */ + bql_lock(); + r = s390_virtio_hypercall(env); + bql_unlock(); + break; ++#endif /* CONFIG_S390_CCW_VIRTIO */ + case 0x44: + /* yield */ + r = 0; +-- +2.48.1 + diff --git a/kvm-s390x-virtio-ccw-add-support-for-virtio-based-memory.patch b/kvm-s390x-virtio-ccw-add-support-for-virtio-based-memory.patch new file mode 100644 index 0000000..808f95b --- /dev/null +++ b/kvm-s390x-virtio-ccw-add-support-for-virtio-based-memory.patch @@ -0,0 +1,423 @@ +From 6b82fca2ecac0c7b30780ebb71ce5bad0421b9b4 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:14 +0100 +Subject: [PATCH 22/26] s390x/virtio-ccw: add support for virtio based memory + devices + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [22/26] 270a9fbe7e5bacfa6c9377815a01da26c4d26097 (thuth/qemu-kvm-cs) + +Let's implement support for abstract virtio based memory devices, using +the virtio-pci implementation as an orientation. Wire them up in the +machine hotplug handler, taking care of s390x page size limitations. + +As we neither support virtio-mem or virtio-pmem yet, the code is +effectively unused. We'll implement support for virtio-mem based on this +next. + +Note that we won't wire up the virtio-pci variant (should currently be +impossible due to lack of support for MSI-X), but we'll add a safety net +to reject plugging them in the pre-plug handler. + +Message-ID: <20241219144115.2820241-14-david@redhat.com> +Acked-by: Michael S. Tsirkin +Signed-off-by: David Hildenbrand +(cherry picked from commit 88d86f6f1e36741ba9e1625da19a7ccf1a343d39) +Signed-off-by: Thomas Huth +--- + MAINTAINERS | 3 + + hw/s390x/meson.build | 3 + + hw/s390x/s390-virtio-ccw.c | 47 +++++++++- + hw/s390x/virtio-ccw-md-stubs.c | 24 ++++++ + hw/s390x/virtio-ccw-md.c | 153 +++++++++++++++++++++++++++++++++ + hw/s390x/virtio-ccw-md.h | 44 ++++++++++ + hw/virtio/Kconfig | 1 + + 7 files changed, 274 insertions(+), 1 deletion(-) + create mode 100644 hw/s390x/virtio-ccw-md-stubs.c + create mode 100644 hw/s390x/virtio-ccw-md.c + create mode 100644 hw/s390x/virtio-ccw-md.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index 3584d6a6c6..f21dc3fa75 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2387,6 +2387,9 @@ F: include/hw/virtio/virtio-crypto.h + virtio based memory device + M: David Hildenbrand + S: Supported ++F: hw/s390x/virtio-ccw-md.c ++F: hw/s390x/virtio-ccw-md.h ++F: hw/s390x/virtio-ccw-md-stubs.c + F: hw/virtio/virtio-md-pci.c + F: include/hw/virtio/virtio-md-pci.h + F: stubs/virtio-md-pci.c +diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build +index e344a3bd8c..4431868408 100644 +--- a/hw/s390x/meson.build ++++ b/hw/s390x/meson.build +@@ -50,8 +50,11 @@ endif + virtio_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-ccw.c')) + virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c')) ++virtio_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-ccw-md.c')) + s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss) + ++s390x_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-ccw-md-stubs.c')) ++ + hw_arch += {'s390x': s390x_ss} + + hw_s390x_modules = {} +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index bd05a22b4e..9f4ad01789 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -46,6 +46,8 @@ + #include "qapi/visitor.h" + #include "hw/s390x/cpu-topology.h" + #include "kvm/kvm_s390x.h" ++#include "hw/virtio/virtio-md-pci.h" ++#include "hw/s390x/virtio-ccw-md.h" + #include CONFIG_DEVICES + + static Error *pv_mig_blocker; +@@ -546,11 +548,39 @@ static void s390_machine_reset(MachineState *machine, ResetType type) + s390_ipl_clear_reset_request(); + } + ++static void s390_machine_device_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) { ++ virtio_ccw_md_pre_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) { ++ error_setg(errp, ++ "PCI-attached virtio based memory devices not supported"); ++ } ++} ++ + static void s390_machine_device_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { ++ S390CcwMachineState *s390ms = S390_CCW_MACHINE(hotplug_dev); ++ + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + s390_cpu_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) { ++ /* ++ * At this point, the device is realized and set all memdevs mapped, so ++ * qemu_maxrampagesize() will pick up the page sizes of these memdevs ++ * as well. Before we plug the device and expose any RAM memory regions ++ * to the system, make sure we don't exceed the previously set max page ++ * size. While only relevant for KVM, there is not really any use case ++ * for this with TCG, so we'll unconditionally reject it. ++ */ ++ if (qemu_maxrampagesize() != s390ms->max_pagesize) { ++ error_setg(errp, "Memory device uses a bigger page size than" ++ " initial memory"); ++ return; ++ } ++ virtio_ccw_md_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp); + } + } + +@@ -560,9 +590,20 @@ static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev, + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + error_setg(errp, "CPU hot unplug not supported on this machine"); + return; ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) { ++ virtio_ccw_md_unplug_request(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), ++ errp); + } + } + ++static void s390_machine_device_unplug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) { ++ virtio_ccw_md_unplug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp); ++ } ++ } ++ + static CpuInstanceProperties s390_cpu_index_to_props(MachineState *ms, + unsigned cpu_index) + { +@@ -609,7 +650,9 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms) + static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, + DeviceState *dev) + { +- if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) || ++ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW) || ++ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) { + return HOTPLUG_HANDLER(machine); + } + return NULL; +@@ -769,8 +812,10 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) + mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids; + /* it is overridden with 'host' cpu *in kvm_arch_init* */ + mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu"); ++ hc->pre_plug = s390_machine_device_pre_plug; + hc->plug = s390_machine_device_plug; + hc->unplug_request = s390_machine_device_unplug_request; ++ hc->unplug = s390_machine_device_unplug; + nc->nmi_monitor_handler = s390_nmi; + mc->default_ram_id = "s390.ram"; + mc->default_nic = "virtio-net-ccw"; +diff --git a/hw/s390x/virtio-ccw-md-stubs.c b/hw/s390x/virtio-ccw-md-stubs.c +new file mode 100644 +index 0000000000..e937865550 +--- /dev/null ++++ b/hw/s390x/virtio-ccw-md-stubs.c +@@ -0,0 +1,24 @@ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "hw/s390x/virtio-ccw-md.h" ++ ++void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) ++{ ++ error_setg(errp, "virtio based memory devices not supported"); ++} ++ ++void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) ++{ ++ error_setg(errp, "virtio based memory devices not supported"); ++} ++ ++void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms, ++ Error **errp) ++{ ++ error_setg(errp, "virtio based memory devices not supported"); ++} ++ ++void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) ++{ ++ error_setg(errp, "virtio based memory devices not supported"); ++} +diff --git a/hw/s390x/virtio-ccw-md.c b/hw/s390x/virtio-ccw-md.c +new file mode 100644 +index 0000000000..de333282df +--- /dev/null ++++ b/hw/s390x/virtio-ccw-md.c +@@ -0,0 +1,153 @@ ++/* ++ * Virtio CCW support for abstract virtio based memory device ++ * ++ * Copyright (C) 2024 Red Hat, Inc. ++ * ++ * Authors: ++ * David Hildenbrand ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/s390x/virtio-ccw-md.h" ++#include "hw/mem/memory-device.h" ++#include "qapi/error.h" ++#include "qemu/error-report.h" ++ ++void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) ++{ ++ DeviceState *dev = DEVICE(vmd); ++ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev); ++ MemoryDeviceState *md = MEMORY_DEVICE(vmd); ++ Error *local_err = NULL; ++ ++ if (!bus_handler && dev->hotplugged) { ++ /* ++ * Without a bus hotplug handler, we cannot control the plug/unplug ++ * order. We should never reach this point when hotplugging, but ++ * better add a safety net. ++ */ ++ error_setg(errp, "hotplug of virtio based memory devices not supported" ++ " on this bus."); ++ return; ++ } ++ ++ /* ++ * First, see if we can plug this memory device at all. If that ++ * succeeds, branch of to the actual hotplug handler. ++ */ ++ memory_device_pre_plug(md, ms, &local_err); ++ if (!local_err && bus_handler) { ++ hotplug_handler_pre_plug(bus_handler, dev, &local_err); ++ } ++ error_propagate(errp, local_err); ++} ++ ++void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) ++{ ++ DeviceState *dev = DEVICE(vmd); ++ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev); ++ MemoryDeviceState *md = MEMORY_DEVICE(vmd); ++ Error *local_err = NULL; ++ ++ /* ++ * Plug the memory device first and then branch off to the actual ++ * hotplug handler. If that one fails, we can easily undo the memory ++ * device bits. ++ */ ++ memory_device_plug(md, ms); ++ if (bus_handler) { ++ hotplug_handler_plug(bus_handler, dev, &local_err); ++ if (local_err) { ++ memory_device_unplug(md, ms); ++ } ++ } ++ error_propagate(errp, local_err); ++} ++ ++void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms, ++ Error **errp) ++{ ++ VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd); ++ DeviceState *dev = DEVICE(vmd); ++ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev); ++ HotplugHandlerClass *hdc; ++ Error *local_err = NULL; ++ ++ if (!vmdc->unplug_request_check) { ++ error_setg(errp, ++ "this virtio based memory devices cannot be unplugged"); ++ return; ++ } ++ ++ if (!bus_handler) { ++ error_setg(errp, "hotunplug of virtio based memory devices not" ++ "supported on this bus"); ++ return; ++ } ++ ++ vmdc->unplug_request_check(vmd, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ /* ++ * Forward the async request or turn it into a sync request (handling it ++ * like qdev_unplug()). ++ */ ++ hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler); ++ if (hdc->unplug_request) { ++ hotplug_handler_unplug_request(bus_handler, dev, &local_err); ++ } else { ++ virtio_ccw_md_unplug(vmd, ms, &local_err); ++ if (!local_err) { ++ object_unparent(OBJECT(dev)); ++ } ++ } ++} ++ ++void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) ++{ ++ DeviceState *dev = DEVICE(vmd); ++ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev); ++ MemoryDeviceState *md = MEMORY_DEVICE(vmd); ++ Error *local_err = NULL; ++ ++ /* Unplug the memory device while it is still realized. */ ++ memory_device_unplug(md, ms); ++ ++ if (bus_handler) { ++ hotplug_handler_unplug(bus_handler, dev, &local_err); ++ if (local_err) { ++ /* Not expected to fail ... but still try to recover. */ ++ memory_device_plug(md, ms); ++ error_propagate(errp, local_err); ++ return; ++ } ++ } else { ++ /* Very unexpected, but let's just try to do the right thing. */ ++ warn_report("Unexpected unplug of virtio based memory device"); ++ qdev_unrealize(dev); ++ } ++} ++ ++static const TypeInfo virtio_ccw_md_info = { ++ .name = TYPE_VIRTIO_MD_CCW, ++ .parent = TYPE_VIRTIO_CCW_DEVICE, ++ .instance_size = sizeof(VirtIOMDCcw), ++ .class_size = sizeof(VirtIOMDCcwClass), ++ .abstract = true, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_MEMORY_DEVICE }, ++ { } ++ }, ++}; ++ ++static void virtio_ccw_md_register(void) ++{ ++ type_register_static(&virtio_ccw_md_info); ++} ++type_init(virtio_ccw_md_register) +diff --git a/hw/s390x/virtio-ccw-md.h b/hw/s390x/virtio-ccw-md.h +new file mode 100644 +index 0000000000..39ba864c92 +--- /dev/null ++++ b/hw/s390x/virtio-ccw-md.h +@@ -0,0 +1,44 @@ ++/* ++ * Virtio CCW support for abstract virtio based memory device ++ * ++ * Copyright (C) 2024 Red Hat, Inc. ++ * ++ * Authors: ++ * David Hildenbrand ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef HW_S390X_VIRTIO_CCW_MD_H ++#define HW_S390X_VIRTIO_CCW_MD_H ++ ++#include "virtio-ccw.h" ++#include "qom/object.h" ++ ++/* ++ * virtio-md-ccw: This extends VirtioCcwDevice. ++ */ ++#define TYPE_VIRTIO_MD_CCW "virtio-md-ccw" ++ ++OBJECT_DECLARE_TYPE(VirtIOMDCcw, VirtIOMDCcwClass, VIRTIO_MD_CCW) ++ ++struct VirtIOMDCcwClass { ++ /* private */ ++ VirtIOCCWDeviceClass parent; ++ ++ /* public */ ++ void (*unplug_request_check)(VirtIOMDCcw *vmd, Error **errp); ++}; ++ ++struct VirtIOMDCcw { ++ VirtioCcwDevice parent_obj; ++}; ++ ++void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp); ++void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp); ++void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms, ++ Error **errp); ++void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp); ++ ++#endif /* HW_S390X_VIRTIO_CCW_MD_H */ +diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig +index 0afec2ae92..f4b14e1a44 100644 +--- a/hw/virtio/Kconfig ++++ b/hw/virtio/Kconfig +@@ -25,6 +25,7 @@ config VIRTIO_MMIO + config VIRTIO_CCW + bool + select VIRTIO ++ select VIRTIO_MD_SUPPORTED + + config VIRTIO_BALLOON + bool +-- +2.48.1 + diff --git a/kvm-s390x-virtio-mem-support.patch b/kvm-s390x-virtio-mem-support.patch new file mode 100644 index 0000000..3c7313f --- /dev/null +++ b/kvm-s390x-virtio-mem-support.patch @@ -0,0 +1,459 @@ +From fa68427f55bee8d18d846e03ebf9f1eeb80f274d Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Thu, 19 Dec 2024 15:41:15 +0100 +Subject: [PATCH 23/26] s390x: virtio-mem support + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [23/26] 4c59ba9025ce5ba7686a7f3e01bb70e8c580709f (thuth/qemu-kvm-cs) + +Let's add our virtio-mem-ccw proxy device and wire it up. We should +be supporting everything (e.g., device unplug, "dynamic-memslots") that +we already support for the virtio-pci variant. + +With a Linux guest that supports virtio-mem (and has automatic memory +onlining properly configured) the following example will work: + +1. Start a VM with 4G initial memory and a virtio-mem device with a maximum + capacity of 16GB: + + qemu/build/qemu-system-s390x \ + --enable-kvm \ + -m 4G,maxmem=20G \ + -nographic \ + -smp 8 \ + -hda Fedora-Server-KVM-40-1.14.s390x.qcow2 \ + -chardev socket,id=monitor,path=/var/tmp/monitor,server,nowait \ + -mon chardev=monitor,mode=readline \ + -object memory-backend-ram,id=mem0,size=16G,reserve=off \ + -device virtio-mem-ccw,id=vmem0,memdev=mem0,dynamic-memslots=on + +2. Query the current size of virtio-mem device: + + (qemu) info memory-devices + Memory device [virtio-mem]: "vmem0" + memaddr: 0x100000000 + node: 0 + requested-size: 0 + size: 0 + max-size: 17179869184 + block-size: 1048576 + memdev: /objects/mem0 + +3. Request to grow it to 8GB (hotplug 8GB): + + (qemu) qom-set vmem0 requested-size 8G + (qemu) info memory-devices + Memory device [virtio-mem]: "vmem0" + memaddr: 0x100000000 + node: 0 + requested-size: 8589934592 + size: 8589934592 + max-size: 17179869184 + block-size: 1048576 + memdev: /objects/mem0 + +4. Request to grow to 16GB (hotplug another 8GB): + + (qemu) qom-set vmem0 requested-size 16G + (qemu) info memory-devices + Memory device [virtio-mem]: "vmem0" + memaddr: 0x100000000 + node: 0 + requested-size: 17179869184 + size: 17179869184 + max-size: 17179869184 + block-size: 1048576 + memdev: /objects/mem0 + +5. Try to hotunplug all memory again, shrinking to 0GB: + + (qemu) qom-set vmem0 requested-size 0G + (qemu) info memory-devices + Memory device [virtio-mem]: "vmem0" + memaddr: 0x100000000 + node: 0 + requested-size: 0 + size: 0 + max-size: 17179869184 + block-size: 1048576 + memdev: /objects/mem0 + +6. If it worked, unplug the device + + (qemu) device_del vmem0 + (qemu) info memory-devices + (qemu) object_del mem0 + +7. Hotplug a new device with a smaller capacity and directly size it to 1GB + + (qemu) object_add memory-backend-ram,id=mem0,size=8G,reserve=off + (qemu) device_add virtio-mem-ccw,id=vmem0,memdev=mem0,\ + dynamic-memslots=on,requested-size=1G + (qemu) info memory-devices + Memory device [virtio-mem]: "vmem0" + memaddr: 0x100000000 + node: 0 + requested-size: 1073741824 + size: 1073741824 + max-size: 8589934592 + block-size: 1048576 + memdev: /objects/mem0 + +Trying to use a virtio-mem device backed by hugetlb into a !hugetlb VM +correctly results in the error: + ... Memory device uses a bigger page size than initial memory + +Note that the virtio-mem driver in Linux will supports 1 MiB (pageblock) +granularity. + +Message-ID: <20241219144115.2820241-15-david@redhat.com> +Acked-by: Michael S. Tsirkin +Signed-off-by: David Hildenbrand +(cherry picked from commit aa910c20ec5f3b10551da19e441b3e2b54406e25) +Signed-off-by: Thomas Huth +--- + MAINTAINERS | 2 + + hw/s390x/Kconfig | 1 + + hw/s390x/meson.build | 1 + + hw/s390x/virtio-ccw-mem.c | 226 ++++++++++++++++++++++++++++++++++++++ + hw/s390x/virtio-ccw-mem.h | 34 ++++++ + hw/virtio/virtio-mem.c | 4 +- + 6 files changed, 267 insertions(+), 1 deletion(-) + create mode 100644 hw/s390x/virtio-ccw-mem.c + create mode 100644 hw/s390x/virtio-ccw-mem.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index f21dc3fa75..f7b7ceffc4 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2401,6 +2401,8 @@ W: https://virtio-mem.gitlab.io/ + F: hw/virtio/virtio-mem.c + F: hw/virtio/virtio-mem-pci.h + F: hw/virtio/virtio-mem-pci.c ++F: hw/s390x/virtio-ccw-mem.c ++F: hw/s390x/virtio-ccw-mem.h + F: include/hw/virtio/virtio-mem.h + + virtio-snd +diff --git a/hw/s390x/Kconfig b/hw/s390x/Kconfig +index 3bbf4ae56e..5d57daff77 100644 +--- a/hw/s390x/Kconfig ++++ b/hw/s390x/Kconfig +@@ -15,3 +15,4 @@ config S390_CCW_VIRTIO + select SCLPCONSOLE + select VIRTIO_CCW + select MSI_NONBROKEN ++ select VIRTIO_MEM_SUPPORTED +diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build +index 4431868408..3bbebfd817 100644 +--- a/hw/s390x/meson.build ++++ b/hw/s390x/meson.build +@@ -51,6 +51,7 @@ virtio_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-ccw.c')) + virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-ccw-md.c')) ++virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-ccw-mem.c')) + s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss) + + s390x_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-ccw-md-stubs.c')) +diff --git a/hw/s390x/virtio-ccw-mem.c b/hw/s390x/virtio-ccw-mem.c +new file mode 100644 +index 0000000000..bee0d560cb +--- /dev/null ++++ b/hw/s390x/virtio-ccw-mem.c +@@ -0,0 +1,226 @@ ++/* ++ * virtio-mem CCW implementation ++ * ++ * Copyright (C) 2024 Red Hat, Inc. ++ * ++ * Authors: ++ * David Hildenbrand ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "qapi/error.h" ++#include "qemu/module.h" ++#include "virtio-ccw-mem.h" ++#include "hw/mem/memory-device.h" ++#include "qapi/qapi-events-machine.h" ++#include "qapi/qapi-events-misc.h" ++ ++static void virtio_ccw_mem_realize(VirtioCcwDevice *ccw_dev, Error **errp) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(ccw_dev); ++ DeviceState *vdev = DEVICE(&dev->vdev); ++ ++ qdev_realize(vdev, BUS(&ccw_dev->bus), errp); ++} ++ ++static void virtio_ccw_mem_set_addr(MemoryDeviceState *md, uint64_t addr, ++ Error **errp) ++{ ++ object_property_set_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP, addr, errp); ++} ++ ++static uint64_t virtio_ccw_mem_get_addr(const MemoryDeviceState *md) ++{ ++ return object_property_get_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP, ++ &error_abort); ++} ++ ++static MemoryRegion *virtio_ccw_mem_get_memory_region(MemoryDeviceState *md, ++ Error **errp) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md); ++ VirtIOMEM *vmem = &dev->vdev; ++ VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem); ++ ++ return vmc->get_memory_region(vmem, errp); ++} ++ ++static void virtio_ccw_mem_decide_memslots(MemoryDeviceState *md, ++ unsigned int limit) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md); ++ VirtIOMEM *vmem = VIRTIO_MEM(&dev->vdev); ++ VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem); ++ ++ vmc->decide_memslots(vmem, limit); ++} ++ ++static unsigned int virtio_ccw_mem_get_memslots(MemoryDeviceState *md) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md); ++ VirtIOMEM *vmem = VIRTIO_MEM(&dev->vdev); ++ VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem); ++ ++ return vmc->get_memslots(vmem); ++} ++ ++static uint64_t virtio_ccw_mem_get_plugged_size(const MemoryDeviceState *md, ++ Error **errp) ++{ ++ return object_property_get_uint(OBJECT(md), VIRTIO_MEM_SIZE_PROP, ++ errp); ++} ++ ++static void virtio_ccw_mem_fill_device_info(const MemoryDeviceState *md, ++ MemoryDeviceInfo *info) ++{ ++ VirtioMEMDeviceInfo *vi = g_new0(VirtioMEMDeviceInfo, 1); ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md); ++ VirtIOMEM *vmem = &dev->vdev; ++ VirtIOMEMClass *vpc = VIRTIO_MEM_GET_CLASS(vmem); ++ DeviceState *vdev = DEVICE(md); ++ ++ if (vdev->id) { ++ vi->id = g_strdup(vdev->id); ++ } ++ ++ /* let the real device handle everything else */ ++ vpc->fill_device_info(vmem, vi); ++ ++ info->u.virtio_mem.data = vi; ++ info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM; ++} ++ ++static uint64_t virtio_ccw_mem_get_min_alignment(const MemoryDeviceState *md) ++{ ++ return object_property_get_uint(OBJECT(md), VIRTIO_MEM_BLOCK_SIZE_PROP, ++ &error_abort); ++} ++ ++static void virtio_ccw_mem_size_change_notify(Notifier *notifier, void *data) ++{ ++ VirtIOMEMCcw *dev = container_of(notifier, VirtIOMEMCcw, ++ size_change_notifier); ++ DeviceState *vdev = DEVICE(dev); ++ char *qom_path = object_get_canonical_path(OBJECT(dev)); ++ const uint64_t * const size_p = data; ++ ++ qapi_event_send_memory_device_size_change(vdev->id, *size_p, qom_path); ++ g_free(qom_path); ++} ++ ++static void virtio_ccw_mem_unplug_request_check(VirtIOMDCcw *vmd, Error **errp) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(vmd); ++ VirtIOMEM *vmem = &dev->vdev; ++ VirtIOMEMClass *vpc = VIRTIO_MEM_GET_CLASS(vmem); ++ ++ vpc->unplug_request_check(vmem, errp); ++} ++ ++static void virtio_ccw_mem_get_requested_size(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj); ++ ++ object_property_get(OBJECT(&dev->vdev), name, v, errp); ++} ++ ++static void virtio_ccw_mem_set_requested_size(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj); ++ DeviceState *vdev = DEVICE(obj); ++ ++ /* ++ * If we passed virtio_ccw_mem_unplug_request_check(), making sure that ++ * the requested size is 0, don't allow modifying the requested size ++ * anymore, otherwise the VM might end up hotplugging memory before ++ * handling the unplug request. ++ */ ++ if (vdev->pending_deleted_event) { ++ error_setg(errp, "'%s' cannot be changed if the device is in the" ++ " process of unplug", name); ++ return; ++ } ++ ++ object_property_set(OBJECT(&dev->vdev), name, v, errp); ++} ++ ++static Property virtio_ccw_mem_properties[] = { ++ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, ++ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), ++ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, ++ VIRTIO_CCW_MAX_REV), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void virtio_ccw_mem_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); ++ MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(klass); ++ VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_CLASS(klass); ++ ++ k->realize = virtio_ccw_mem_realize; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ device_class_set_props(dc, virtio_ccw_mem_properties); ++ ++ mdc->get_addr = virtio_ccw_mem_get_addr; ++ mdc->set_addr = virtio_ccw_mem_set_addr; ++ mdc->get_plugged_size = virtio_ccw_mem_get_plugged_size; ++ mdc->get_memory_region = virtio_ccw_mem_get_memory_region; ++ mdc->decide_memslots = virtio_ccw_mem_decide_memslots; ++ mdc->get_memslots = virtio_ccw_mem_get_memslots; ++ mdc->fill_device_info = virtio_ccw_mem_fill_device_info; ++ mdc->get_min_alignment = virtio_ccw_mem_get_min_alignment; ++ ++ vmdc->unplug_request_check = virtio_ccw_mem_unplug_request_check; ++} ++ ++static void virtio_ccw_mem_instance_init(Object *obj) ++{ ++ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj); ++ VirtIOMEMClass *vmc; ++ VirtIOMEM *vmem; ++ ++ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), ++ TYPE_VIRTIO_MEM); ++ ++ dev->size_change_notifier.notify = virtio_ccw_mem_size_change_notify; ++ vmem = &dev->vdev; ++ vmc = VIRTIO_MEM_GET_CLASS(vmem); ++ /* ++ * We never remove the notifier again, as we expect both devices to ++ * disappear at the same time. ++ */ ++ vmc->add_size_change_notifier(vmem, &dev->size_change_notifier); ++ ++ object_property_add_alias(obj, VIRTIO_MEM_BLOCK_SIZE_PROP, ++ OBJECT(&dev->vdev), VIRTIO_MEM_BLOCK_SIZE_PROP); ++ object_property_add_alias(obj, VIRTIO_MEM_SIZE_PROP, OBJECT(&dev->vdev), ++ VIRTIO_MEM_SIZE_PROP); ++ object_property_add(obj, VIRTIO_MEM_REQUESTED_SIZE_PROP, "size", ++ virtio_ccw_mem_get_requested_size, ++ virtio_ccw_mem_set_requested_size, NULL, NULL); ++} ++ ++static const TypeInfo virtio_ccw_mem = { ++ .name = TYPE_VIRTIO_MEM_CCW, ++ .parent = TYPE_VIRTIO_MD_CCW, ++ .instance_size = sizeof(VirtIOMEMCcw), ++ .instance_init = virtio_ccw_mem_instance_init, ++ .class_init = virtio_ccw_mem_class_init, ++}; ++ ++static void virtio_ccw_mem_register_types(void) ++{ ++ type_register_static(&virtio_ccw_mem); ++} ++type_init(virtio_ccw_mem_register_types) +diff --git a/hw/s390x/virtio-ccw-mem.h b/hw/s390x/virtio-ccw-mem.h +new file mode 100644 +index 0000000000..738ab2c744 +--- /dev/null ++++ b/hw/s390x/virtio-ccw-mem.h +@@ -0,0 +1,34 @@ ++/* ++ * Virtio MEM CCW device ++ * ++ * Copyright (C) 2024 Red Hat, Inc. ++ * ++ * Authors: ++ * David Hildenbrand ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef HW_S390X_VIRTIO_CCW_MEM_H ++#define HW_S390X_VIRTIO_CCW_MEM_H ++ ++#include "virtio-ccw-md.h" ++#include "hw/virtio/virtio-mem.h" ++#include "qom/object.h" ++ ++typedef struct VirtIOMEMCcw VirtIOMEMCcw; ++ ++/* ++ * virtio-mem-ccw: This extends VirtIOMDCcw ++ */ ++#define TYPE_VIRTIO_MEM_CCW "virtio-mem-ccw" ++DECLARE_INSTANCE_CHECKER(VirtIOMEMCcw, VIRTIO_MEM_CCW, TYPE_VIRTIO_MEM_CCW) ++ ++struct VirtIOMEMCcw { ++ VirtIOMDCcw parent_obj; ++ VirtIOMEM vdev; ++ Notifier size_change_notifier; ++}; ++ ++#endif /* HW_S390X_VIRTIO_CCW_MEM_H */ +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index 00da98b6e1..c9f8a23bbc 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -61,6 +61,8 @@ static uint32_t virtio_mem_default_thp_size(void) + } else if (qemu_real_host_page_size() == 64 * KiB) { + default_thp_size = 512 * MiB; + } ++#elif defined(__s390x__) ++ default_thp_size = 1 * MiB; + #endif + + return default_thp_size; +@@ -161,7 +163,7 @@ static bool virtio_mem_has_shared_zeropage(RAMBlock *rb) + * necessary (as the section size can change). But it's more likely that the + * section size will rather get smaller and not bigger over time. + */ +-#if defined(TARGET_X86_64) || defined(TARGET_I386) ++#if defined(TARGET_X86_64) || defined(TARGET_I386) || defined(TARGET_S390X) + #define VIRTIO_MEM_USABLE_EXTENT (2 * (128 * MiB)) + #elif defined(TARGET_ARM) + #define VIRTIO_MEM_USABLE_EXTENT (2 * (512 * MiB)) +-- +2.48.1 + diff --git a/kvm-target-s390-Convert-CPU-to-Resettable-interface.patch b/kvm-target-s390-Convert-CPU-to-Resettable-interface.patch new file mode 100644 index 0000000..6b93825 --- /dev/null +++ b/kvm-target-s390-Convert-CPU-to-Resettable-interface.patch @@ -0,0 +1,284 @@ +From 50c4cbbe0a8849dd0c720c6e706498cb0d46f5b3 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 13 Sep 2024 15:31:43 +0100 +Subject: [PATCH 04/26] target/s390: Convert CPU to Resettable interface + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [4/26] 157b29ced6b92ecec5e69f8bc60d0183a0c88fa0 (thuth/qemu-kvm-cs) + +Convert the s390 CPU to the Resettable interface. This is slightly +more involved than the other CPU types were (see commits +9130cade5fc22..d66e64dd006df) because S390 has its own set of +different kinds of reset with different behaviours that it needs to +trigger. + +We handle this by adding these reset types to the Resettable +ResetType enum. Now instead of having an underlying implementation +of reset that is s390-specific and which might be called either +directly or via the DeviceClass::reset method, we can implement only +the Resettable hold phase method, and have the places that need to +trigger an s390-specific reset type do so by calling +resettable_reset(). + +The other option would have been to smuggle in the s390 reset +type via, for instance, a field in the CPU state that we set +in s390_do_cpu_initial_reset() etc and then examined in the +reset method, but doing it this way seems cleaner. + +The motivation for this change is that this is the last caller +of the legacy device_class_set_parent_reset() function, and +removing that will let us clean up some glue code that we added +for the transition to three-phase reset. + +Signed-off-by: Peter Maydell +Reviewed-by: Nina Schoetterl-Glausch +Reviewed-by: Richard Henderson +Acked-by: Thomas Huth +Message-id: 20240830145812.1967042-4-peter.maydell@linaro.org +(cherry picked from commit cf7f61d13f28f32d0b14abb70ce1bd9e41623b2e) +Signed-off-by: Thomas Huth +--- + docs/devel/reset.rst | 10 ++++++++++ + include/hw/resettable.h | 2 ++ + target/s390x/cpu.c | 38 +++++++++++++++++--------------------- + target/s390x/cpu.h | 21 ++++----------------- + target/s390x/sigp.c | 8 ++------ + 5 files changed, 35 insertions(+), 44 deletions(-) + +diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst +index 24ab630465..d2799eba7a 100644 +--- a/docs/devel/reset.rst ++++ b/docs/devel/reset.rst +@@ -44,6 +44,16 @@ The Resettable interface handles reset types with an enum ``ResetType``: + value on each cold reset, such as RNG seed information, and which they + must not reinitialize on a snapshot-load reset. + ++``RESET_TYPE_S390_CPU_NORMAL`` ++ This is only used for S390 CPU objects; it clears interrupts, stops ++ processing, and clears the TLB, but does not touch register contents. ++ ++``RESET_TYPE_S390_CPU_INITIAL`` ++ This is only used for S390 CPU objects; it does everything ++ ``RESET_TYPE_S390_CPU_NORMAL`` does and also clears the PSW, prefix, ++ FPC, timer and control registers. It does not touch gprs, fprs or acrs. ++ ++ + Devices which implement reset methods must treat any unknown ``ResetType`` + as equivalent to ``RESET_TYPE_COLD``; this will reduce the amount of + existing code we need to change if we add more types in future. +diff --git a/include/hw/resettable.h b/include/hw/resettable.h +index 7e249deb8b..83b561fc83 100644 +--- a/include/hw/resettable.h ++++ b/include/hw/resettable.h +@@ -36,6 +36,8 @@ typedef struct ResettableState ResettableState; + typedef enum ResetType { + RESET_TYPE_COLD, + RESET_TYPE_SNAPSHOT_LOAD, ++ RESET_TYPE_S390_CPU_INITIAL, ++ RESET_TYPE_S390_CPU_NORMAL, + } ResetType; + + /* +diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c +index 0fbfcd35d8..4e41a3dff5 100644 +--- a/target/s390x/cpu.c ++++ b/target/s390x/cpu.c +@@ -32,6 +32,7 @@ + #include "sysemu/hw_accel.h" + #include "hw/qdev-properties.h" + #include "hw/qdev-properties-system.h" ++#include "hw/resettable.h" + #include "fpu/softfloat-helpers.h" + #include "disas/capstone.h" + #include "sysemu/tcg.h" +@@ -162,23 +163,25 @@ static void s390_query_cpu_fast(CPUState *cpu, CpuInfoFast *value) + #endif + } + +-/* S390CPUClass::reset() */ +-static void s390_cpu_reset(CPUState *s, cpu_reset_type type) ++/* S390CPUClass Resettable reset_hold phase method */ ++static void s390_cpu_reset_hold(Object *obj, ResetType type) + { +- S390CPU *cpu = S390_CPU(s); ++ S390CPU *cpu = S390_CPU(obj); + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + CPUS390XState *env = &cpu->env; +- DeviceState *dev = DEVICE(s); + +- scc->parent_reset(dev); ++ if (scc->parent_phases.hold) { ++ scc->parent_phases.hold(obj, type); ++ } + cpu->env.sigp_order = 0; + s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); + + switch (type) { +- case S390_CPU_RESET_CLEAR: ++ default: ++ /* RESET_TYPE_COLD: power on or "clear" reset */ + memset(env, 0, offsetof(CPUS390XState, start_initial_reset_fields)); + /* fall through */ +- case S390_CPU_RESET_INITIAL: ++ case RESET_TYPE_S390_CPU_INITIAL: + /* initial reset does not clear everything! */ + memset(&env->start_initial_reset_fields, 0, + offsetof(CPUS390XState, start_normal_reset_fields) - +@@ -203,7 +206,7 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type) + set_float_detect_tininess(float_tininess_before_rounding, + &env->fpu_status); + /* fall through */ +- case S390_CPU_RESET_NORMAL: ++ case RESET_TYPE_S390_CPU_NORMAL: + env->psw.mask &= ~PSW_MASK_RI; + memset(&env->start_normal_reset_fields, 0, + offsetof(CPUS390XState, end_reset_fields) - +@@ -212,20 +215,18 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type) + env->pfault_token = -1UL; + env->bpbc = false; + break; +- default: +- g_assert_not_reached(); + } + + /* Reset state inside the kernel that we cannot access yet from QEMU. */ + if (kvm_enabled()) { + switch (type) { +- case S390_CPU_RESET_CLEAR: ++ default: + kvm_s390_reset_vcpu_clear(cpu); + break; +- case S390_CPU_RESET_INITIAL: ++ case RESET_TYPE_S390_CPU_INITIAL: + kvm_s390_reset_vcpu_initial(cpu); + break; +- case S390_CPU_RESET_NORMAL: ++ case RESET_TYPE_S390_CPU_NORMAL: + kvm_s390_reset_vcpu_normal(cpu); + break; + } +@@ -315,12 +316,6 @@ static Property s390x_cpu_properties[] = { + DEFINE_PROP_END_OF_LIST() + }; + +-static void s390_cpu_reset_full(DeviceState *dev) +-{ +- CPUState *s = CPU(dev); +- return s390_cpu_reset(s, S390_CPU_RESET_CLEAR); +-} +- + #ifdef CONFIG_TCG + #include "hw/core/tcg-cpu-ops.h" + +@@ -383,15 +378,16 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) + S390CPUClass *scc = S390_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(scc); + DeviceClass *dc = DEVICE_CLASS(oc); ++ ResettableClass *rc = RESETTABLE_CLASS(oc); + + device_class_set_parent_realize(dc, s390_cpu_realizefn, + &scc->parent_realize); + device_class_set_props(dc, s390x_cpu_properties); + dc->user_creatable = true; + +- device_class_set_parent_reset(dc, s390_cpu_reset_full, &scc->parent_reset); ++ resettable_class_set_parent_phases(rc, NULL, s390_cpu_reset_hold, NULL, ++ &scc->parent_phases); + +- scc->reset = s390_cpu_reset; + cc->class_by_name = s390_cpu_class_by_name, + cc->has_work = s390_cpu_has_work; + cc->mmu_index = s390x_cpu_mmu_index; +diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h +index d6b75ad0e0..6a64472403 100644 +--- a/target/s390x/cpu.h ++++ b/target/s390x/cpu.h +@@ -177,19 +177,11 @@ struct ArchCPU { + uint32_t irqstate_saved_size; + }; + +-typedef enum cpu_reset_type { +- S390_CPU_RESET_NORMAL, +- S390_CPU_RESET_INITIAL, +- S390_CPU_RESET_CLEAR, +-} cpu_reset_type; +- + /** + * S390CPUClass: + * @parent_realize: The parent class' realize handler. +- * @parent_reset: The parent class' reset handler. ++ * @parent_phases: The parent class' reset phase handlers. + * @load_normal: Performs a load normal. +- * @cpu_reset: Performs a CPU reset. +- * @initial_cpu_reset: Performs an initial CPU reset. + * + * An S/390 CPU model. + */ +@@ -203,9 +195,8 @@ struct S390CPUClass { + const char *desc; + + DeviceRealize parent_realize; +- DeviceReset parent_reset; ++ ResettablePhases parent_phases; + void (*load_normal)(CPUState *cpu); +- void (*reset)(CPUState *cpu, cpu_reset_type type); + }; + + #ifndef CONFIG_USER_ONLY +@@ -872,16 +863,12 @@ static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg) + + static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg) + { +- S390CPUClass *scc = S390_CPU_GET_CLASS(cs); +- +- scc->reset(cs, S390_CPU_RESET_NORMAL); ++ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_NORMAL); + } + + static inline void s390_do_cpu_initial_reset(CPUState *cs, run_on_cpu_data arg) + { +- S390CPUClass *scc = S390_CPU_GET_CLASS(cs); +- +- scc->reset(cs, S390_CPU_RESET_INITIAL); ++ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_INITIAL); + } + + static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg) +diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c +index ad0ad61177..08aaecf12b 100644 +--- a/target/s390x/sigp.c ++++ b/target/s390x/sigp.c +@@ -251,24 +251,20 @@ static void sigp_restart(CPUState *cs, run_on_cpu_data arg) + + static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg) + { +- S390CPU *cpu = S390_CPU(cs); +- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + SigpInfo *si = arg.host_ptr; + + cpu_synchronize_state(cs); +- scc->reset(cs, S390_CPU_RESET_INITIAL); ++ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_INITIAL); + cpu_synchronize_post_reset(cs); + si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; + } + + static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg) + { +- S390CPU *cpu = S390_CPU(cs); +- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + SigpInfo *si = arg.host_ptr; + + cpu_synchronize_state(cs); +- scc->reset(cs, S390_CPU_RESET_NORMAL); ++ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_NORMAL); + cpu_synchronize_post_reset(cs); + si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; + } +-- +2.48.1 + diff --git a/kvm-virtio-kconfig-memory-devices-are-PCI-only.patch b/kvm-virtio-kconfig-memory-devices-are-PCI-only.patch new file mode 100644 index 0000000..0ddc3e9 --- /dev/null +++ b/kvm-virtio-kconfig-memory-devices-are-PCI-only.patch @@ -0,0 +1,87 @@ +From a582cf6f68febba05e20548f643c8be637eab7b8 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Sep 2024 12:16:58 +0200 +Subject: [PATCH 01/26] virtio: kconfig: memory devices are PCI only + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [1/26] 0f0eab06b6f79f84c2e8d4fee28309b3c7c57414 (thuth/qemu-kvm-cs) + +Virtio memory devices rely on PCI BARs to expose the contents of memory. +Because of this they cannot be used (yet) with virtio-mmio or virtio-ccw. +In fact the code that is common to virtio-mem and virtio-pmem, which +is in hw/virtio/virtio-md-pci.c, is only included if CONFIG_VIRTIO_PCI +is set. Reproduce the same condition in the Kconfig file, only allowing +VIRTIO_MEM and VIRTIO_PMEM to be defined if the transport supports it. + +Without this patch it is possible to create a configuration with +CONFIG_VIRTIO_PCI=n and CONFIG_VIRTIO_MEM=y, but that causes a +linking failure. + +Message-ID: <20240906101658.514470-1-pbonzini@redhat.com> +Reported-by: Michael Tokarev +Reviewed-by: David Hildenbrand +Signed-off-by: Paolo Bonzini +Signed-off-by: David Hildenbrand +(cherry picked from commit 8d018fe59a0beff580ac6b3399d642c4277d9dd0) +Signed-off-by: Thomas Huth +--- + hw/virtio/Kconfig | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig +index aa63ff7fd4..0afec2ae92 100644 +--- a/hw/virtio/Kconfig ++++ b/hw/virtio/Kconfig +@@ -16,6 +16,7 @@ config VIRTIO_PCI + default y if PCI_DEVICES + depends on PCI + select VIRTIO ++ select VIRTIO_MD_SUPPORTED + + config VIRTIO_MMIO + bool +@@ -35,10 +36,17 @@ config VIRTIO_CRYPTO + default y + depends on VIRTIO + ++# not all virtio transports support memory devices; if none does, ++# no need to include the code ++config VIRTIO_MD_SUPPORTED ++ bool ++ + config VIRTIO_MD + bool ++ depends on VIRTIO_MD_SUPPORTED + select MEM_DEVICE + ++# selected by the board if it has the required support code + config VIRTIO_PMEM_SUPPORTED + bool + +@@ -46,9 +54,11 @@ config VIRTIO_PMEM + bool + default y + depends on VIRTIO ++ depends on VIRTIO_MD_SUPPORTED + depends on VIRTIO_PMEM_SUPPORTED + select VIRTIO_MD + ++# selected by the board if it has the required support code + config VIRTIO_MEM_SUPPORTED + bool + +@@ -57,6 +67,7 @@ config VIRTIO_MEM + default y + depends on VIRTIO + depends on LINUX ++ depends on VIRTIO_MD_SUPPORTED + depends on VIRTIO_MEM_SUPPORTED + select VIRTIO_MD + +-- +2.48.1 + diff --git a/kvm-virtio-mem-Add-support-for-suspend-wake-up-with-plug.patch b/kvm-virtio-mem-Add-support-for-suspend-wake-up-with-plug.patch new file mode 100644 index 0000000..ba58998 --- /dev/null +++ b/kvm-virtio-mem-Add-support-for-suspend-wake-up-with-plug.patch @@ -0,0 +1,79 @@ +From 001200670ce9076a34419828e7e7ba92f19a80b7 Mon Sep 17 00:00:00 2001 +From: Juraj Marcin +Date: Wed, 4 Sep 2024 12:37:15 +0200 +Subject: [PATCH 08/26] virtio-mem: Add support for suspend+wake-up with + plugged memory + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [8/26] 08e25d41e32b3ac2bf5e0266f9c7e91739eda4d4 (thuth/qemu-kvm-cs) + +Before, the virtio-mem device would unplug all the memory with any reset +of the device, including during the wake-up of the guest from a +suspended state. Due to this, the virtio-mem driver in the Linux kernel +disallowed suspend-to-ram requests in the guest when the +VIRTIO_MEM_F_PERSISTENT_SUSPEND feature is not exposed by QEMU. + +This patch adds the code to skip the reset on wake-up and exposes +theVIRTIO_MEM_F_PERSISTENT_SUSPEND feature to the guest kernel driver +when suspending is possible in QEMU (currently only x86). + +Message-ID: <20240904103722.946194-5-jmarcin@redhat.com> +Reviewed-by: David Hildenbrand +Signed-off-by: Juraj Marcin +Signed-off-by: David Hildenbrand +(cherry picked from commit 1f5f49056d0f140568805d66f33396ed5cd90369) +Signed-off-by: Thomas Huth +--- + hw/virtio/virtio-mem.c | 10 ++++++++++ + hw/virtio/virtio-qmp.c | 3 +++ + 2 files changed, 13 insertions(+) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index 025ae4abac..51642a15ef 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -883,6 +883,9 @@ static uint64_t virtio_mem_get_features(VirtIODevice *vdev, uint64_t features, + if (vmem->unplugged_inaccessible == ON_OFF_AUTO_ON) { + virtio_add_feature(&features, VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE); + } ++ if (qemu_wakeup_suspend_enabled()) { ++ virtio_add_feature(&features, VIRTIO_MEM_F_PERSISTENT_SUSPEND); ++ } + return features; + } + +@@ -1842,6 +1845,13 @@ static void virtio_mem_system_reset_hold(Object *obj, ResetType type) + { + VirtIOMEM *vmem = VIRTIO_MEM(obj); + ++ /* ++ * When waking up from standby/suspend-to-ram, do not unplug any memory. ++ */ ++ if (type == RESET_TYPE_WAKEUP) { ++ return; ++ } ++ + /* + * During usual resets, we will unplug all memory and shrink the usable + * region size. This is, however, not possible in all scenarios. Then, +diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c +index 1dd96ed20f..cccc6fe761 100644 +--- a/hw/virtio/virtio-qmp.c ++++ b/hw/virtio/virtio-qmp.c +@@ -450,6 +450,9 @@ static const qmp_virtio_feature_map_t virtio_mem_feature_map[] = { + FEATURE_ENTRY(VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, \ + "VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE: Unplugged memory cannot be " + "accessed"), ++ FEATURE_ENTRY(VIRTIO_MEM_F_PERSISTENT_SUSPEND, \ ++ "VIRTIO_MEM_F_PERSISTENT_SUSPND: Plugged memory will remain " ++ "plugged when suspending+resuming"), + { -1, "" } + }; + #endif +-- +2.48.1 + diff --git a/kvm-virtio-mem-Use-new-Resettable-framework-instead-of-L.patch b/kvm-virtio-mem-Use-new-Resettable-framework-instead-of-L.patch new file mode 100644 index 0000000..5bb3c9e --- /dev/null +++ b/kvm-virtio-mem-Use-new-Resettable-framework-instead-of-L.patch @@ -0,0 +1,141 @@ +From 6bc0cdecdc736d642bb6c040e07d79a0a3e591ea Mon Sep 17 00:00:00 2001 +From: Juraj Marcin +Date: Wed, 4 Sep 2024 12:37:14 +0200 +Subject: [PATCH 07/26] virtio-mem: Use new Resettable framework instead of + LegacyReset + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [7/26] 31fddbeb4aaf6794b83399a7e2996f01d918d748 (thuth/qemu-kvm-cs) + +LegacyReset does not pass ResetType to the reset callback method, which +the new Resettable framework uses. Due to this, virtio-mem cannot use +the new RESET_TYPE_WAKEUP to skip the reset during wake-up from a +suspended state. + +This patch adds overrides Resettable interface methods in VirtIOMEMClass +to use the new Resettable framework and replaces +qemu_[un]register_reset() calls with qemu_[un]register_resettable(). + +Message-ID: <20240904103722.946194-4-jmarcin@redhat.com> +Reviewed-by: David Hildenbrand +Signed-off-by: Juraj Marcin +Signed-off-by: David Hildenbrand +(cherry picked from commit c009a311e93963860cfba917605a4bf903a06bce) +Signed-off-by: Thomas Huth +--- + hw/virtio/virtio-mem.c | 38 +++++++++++++++++++++------------- + include/hw/virtio/virtio-mem.h | 4 ++++ + 2 files changed, 28 insertions(+), 14 deletions(-) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index ba11aa4646..025ae4abac 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -895,18 +895,6 @@ static int virtio_mem_validate_features(VirtIODevice *vdev) + return 0; + } + +-static void virtio_mem_system_reset(void *opaque) +-{ +- VirtIOMEM *vmem = VIRTIO_MEM(opaque); +- +- /* +- * During usual resets, we will unplug all memory and shrink the usable +- * region size. This is, however, not possible in all scenarios. Then, +- * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL). +- */ +- virtio_mem_unplug_all(vmem); +-} +- + static void virtio_mem_prepare_mr(VirtIOMEM *vmem) + { + const uint64_t region_size = memory_region_size(&vmem->memdev->mr); +@@ -1123,7 +1111,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) + vmstate_register_any(VMSTATE_IF(vmem), + &vmstate_virtio_mem_device_early, vmem); + } +- qemu_register_reset(virtio_mem_system_reset, vmem); ++ qemu_register_resettable(OBJECT(vmem)); + + /* + * Set ourselves as RamDiscardManager before the plug handler maps the +@@ -1143,7 +1131,7 @@ static void virtio_mem_device_unrealize(DeviceState *dev) + * found via an address space anymore. Unset ourselves. + */ + memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); +- qemu_unregister_reset(virtio_mem_system_reset, vmem); ++ qemu_unregister_resettable(OBJECT(vmem)); + if (vmem->early_migration) { + vmstate_unregister(VMSTATE_IF(vmem), &vmstate_virtio_mem_device_early, + vmem); +@@ -1844,12 +1832,31 @@ static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp) + } + } + ++static ResettableState *virtio_mem_get_reset_state(Object *obj) ++{ ++ VirtIOMEM *vmem = VIRTIO_MEM(obj); ++ return &vmem->reset_state; ++} ++ ++static void virtio_mem_system_reset_hold(Object *obj, ResetType type) ++{ ++ VirtIOMEM *vmem = VIRTIO_MEM(obj); ++ ++ /* ++ * During usual resets, we will unplug all memory and shrink the usable ++ * region size. This is, however, not possible in all scenarios. Then, ++ * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL). ++ */ ++ virtio_mem_unplug_all(vmem); ++} ++ + static void virtio_mem_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOMEMClass *vmc = VIRTIO_MEM_CLASS(klass); + RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_CLASS(klass); ++ ResettableClass *rc = RESETTABLE_CLASS(klass); + + device_class_set_props(dc, virtio_mem_properties); + dc->vmsd = &vmstate_virtio_mem; +@@ -1876,6 +1883,9 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data) + rdmc->replay_discarded = virtio_mem_rdm_replay_discarded; + rdmc->register_listener = virtio_mem_rdm_register_listener; + rdmc->unregister_listener = virtio_mem_rdm_unregister_listener; ++ ++ rc->get_state = virtio_mem_get_reset_state; ++ rc->phases.hold = virtio_mem_system_reset_hold; + } + + static const TypeInfo virtio_mem_info = { +diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h +index 5f5b02b8f9..a1af144c28 100644 +--- a/include/hw/virtio/virtio-mem.h ++++ b/include/hw/virtio/virtio-mem.h +@@ -14,6 +14,7 @@ + #define HW_VIRTIO_MEM_H + + #include "standard-headers/linux/virtio_mem.h" ++#include "hw/resettable.h" + #include "hw/virtio/virtio.h" + #include "qapi/qapi-types-misc.h" + #include "sysemu/hostmem.h" +@@ -115,6 +116,9 @@ struct VirtIOMEM { + + /* listeners to notify on plug/unplug activity. */ + QLIST_HEAD(, RamDiscardListener) rdl_list; ++ ++ /* State of the resettable container */ ++ ResettableState reset_state; + }; + + struct VirtIOMEMClass { +-- +2.48.1 + diff --git a/kvm-virtio-mem-don-t-warn-about-THP-sizes-on-a-kernel-wi.patch b/kvm-virtio-mem-don-t-warn-about-THP-sizes-on-a-kernel-wi.patch new file mode 100644 index 0000000..f527a70 --- /dev/null +++ b/kvm-virtio-mem-don-t-warn-about-THP-sizes-on-a-kernel-wi.patch @@ -0,0 +1,59 @@ +From f4052d25199bfce8ce29a173934a805fe1cf7e3e Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Tue, 10 Sep 2024 18:34:33 +0200 +Subject: [PATCH 25/26] virtio-mem: don't warn about THP sizes on a kernel + without THP support + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [25/26] 5dff17ef818722db8f1fa87cff5b7777afc3c814 (thuth/qemu-kvm-cs) + +If the config directory in sysfs does not exist at all, we are dealing +with a system that does not support THPs. Simply use 1 MiB block size +then, instead of warning "Could not detect THP size, falling back to +..." and falling back to the default THP size. + +Cc: "Michael S. Tsirkin" +Cc: Gavin Shan +Cc: Juraj Marcin +Signed-off-by: David Hildenbrand +Message-Id: <20240910163433.2100295-1-david@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 95b717a8154b955de2782305f305b63f357b0576) +Signed-off-by: Thomas Huth +--- + hw/virtio/virtio-mem.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index c9f8a23bbc..4977658312 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -90,6 +90,7 @@ static uint32_t virtio_mem_default_thp_size(void) + static uint32_t thp_size; + + #define HPAGE_PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size" ++#define HPAGE_PATH "/sys/kernel/mm/transparent_hugepage/" + static uint32_t virtio_mem_thp_size(void) + { + gchar *content = NULL; +@@ -100,6 +101,12 @@ static uint32_t virtio_mem_thp_size(void) + return thp_size; + } + ++ /* No THP -> no restrictions. */ ++ if (!g_file_test(HPAGE_PATH, G_FILE_TEST_EXISTS)) { ++ thp_size = VIRTIO_MEM_MIN_BLOCK_SIZE; ++ return thp_size; ++ } ++ + /* + * Try to probe the actual THP size, fallback to (sane but eventually + * incorrect) default sizes. +-- +2.48.1 + diff --git a/kvm-virtio-mem-unplug-memory-only-during-system-resets-n.patch b/kvm-virtio-mem-unplug-memory-only-during-system-resets-n.patch new file mode 100644 index 0000000..cfb49f4 --- /dev/null +++ b/kvm-virtio-mem-unplug-memory-only-during-system-resets-n.patch @@ -0,0 +1,258 @@ +From e5f2bb584154eef665211228f1ac3113e2acc269 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Fri, 25 Oct 2024 12:41:03 +0200 +Subject: [PATCH 09/26] virtio-mem: unplug memory only during system resets, + not device resets + +RH-Author: Thomas Huth +RH-MergeRequest: 351: Enable virtio-mem support on s390x +RH-Jira: RHEL-72977 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Juraj Marcin +RH-Commit: [9/26] 7c5ddd4d3fd0d19caa946bcbe98cb5732404978b (thuth/qemu-kvm-cs) + +We recently converted from the LegacyReset to the new reset framework +in commit c009a311e939 ("virtio-mem: Use new Resettable framework instead +of LegacyReset") to be able to use the ResetType to filter out wakeup +resets. + +However, this change had an undesired implications: as we override the +Resettable interface methods in VirtIOMEMClass, the reset handler will +not only get called during system resets (i.e., qemu_devices_reset()) +but also during any direct or indirect device rests (e.g., +device_cold_reset()). + +Further, we might now receive two reset callbacks during +qemu_devices_reset(), first when reset by a parent and later when reset +directly. + +The memory state of virtio-mem devices is rather special: it's supposed to +be persistent/unchanged during most resets (similar to resetting a hard +disk will not destroy the data), unless actually cold-resetting the whole +system (different to a hard disk where a reboot will not destroy the data): +ripping out system RAM is something guest OSes don't particularly enjoy, +but we want to detect when rebooting to an OS that does not support +virtio-mem and wouldn't be able to detect+use the memory -- and we want +to force-defragment hotplugged memory to also shrink the usable device +memory region. So we rally want to catch system resets to do that. + +On supported targets (e.g., x86), getting a cold reset on the +device/parent triggers is not that easy (but looks like PCI code +might trigger it), so this implication went unnoticed. + +However, with upcoming s390x support it is problematic: during +kdump, s390x triggers a subsystem reset, ending up in +s390_machine_reset() and calling only subsystem_reset() instead of +qemu_devices_reset() -- because it's not a full system reset. + +In subsystem_reset(), s390x performs a device_cold_reset() of any +TYPE_VIRTUAL_CSS_BRIDGE device, which ends up resetting all children, +including the virtio-mem device. Consequently, we wrongly detect a system +reset and unplug all device memory, resulting in hotplugged memory not +getting included in the crash dump -- undesired. + +We really must not mess with hotplugged memory state during simple +device resets. To fix, create+register a new reset object that will only +get triggered during qemu_devices_reset() calls, but not during any other +resets as it is logically not the child of any other object. + +Message-ID: <20241025104103.342188-1-david@redhat.com> +Acked-by: Michael S. Tsirkin +Cc: "Michael S. Tsirkin" +Cc: Juraj Marcin +Cc: Peter Maydell +Signed-off-by: David Hildenbrand +(cherry picked from commit 713484d0389c9d1cbb87eca060361281248b69f5) +Signed-off-by: Thomas Huth +--- + hw/virtio/virtio-mem.c | 103 +++++++++++++++++++++++---------- + include/hw/virtio/virtio-mem.h | 13 ++++- + 2 files changed, 84 insertions(+), 32 deletions(-) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index 51642a15ef..00da98b6e1 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -949,6 +949,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) + VirtIOMEM *vmem = VIRTIO_MEM(dev); + uint64_t page_size; + RAMBlock *rb; ++ Object *obj; + int ret; + + if (!vmem->memdev) { +@@ -1114,7 +1115,28 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) + vmstate_register_any(VMSTATE_IF(vmem), + &vmstate_virtio_mem_device_early, vmem); + } +- qemu_register_resettable(OBJECT(vmem)); ++ ++ /* ++ * We only want to unplug all memory to start with a clean slate when ++ * it is safe for the guest -- during system resets that call ++ * qemu_devices_reset(). ++ * ++ * We'll filter out selected qemu_devices_reset() calls used for other ++ * purposes, like resetting all devices during wakeup from suspend on ++ * x86 based on the reset type passed to qemu_devices_reset(). ++ * ++ * Unplugging all memory during simple device resets can result in the VM ++ * unexpectedly losing RAM, corrupting VM state. ++ * ++ * Simple device resets (or resets triggered by getting a parent device ++ * reset) must not change the state of plugged memory blocks. Therefore, ++ * we need a dedicated reset object that only gets called during ++ * qemu_devices_reset(). ++ */ ++ obj = object_new(TYPE_VIRTIO_MEM_SYSTEM_RESET); ++ vmem->system_reset = VIRTIO_MEM_SYSTEM_RESET(obj); ++ vmem->system_reset->vmem = vmem; ++ qemu_register_resettable(obj); + + /* + * Set ourselves as RamDiscardManager before the plug handler maps the +@@ -1134,7 +1156,10 @@ static void virtio_mem_device_unrealize(DeviceState *dev) + * found via an address space anymore. Unset ourselves. + */ + memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); +- qemu_unregister_resettable(OBJECT(vmem)); ++ ++ qemu_unregister_resettable(OBJECT(vmem->system_reset)); ++ object_unref(OBJECT(vmem->system_reset)); ++ + if (vmem->early_migration) { + vmstate_unregister(VMSTATE_IF(vmem), &vmstate_virtio_mem_device_early, + vmem); +@@ -1835,38 +1860,12 @@ static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp) + } + } + +-static ResettableState *virtio_mem_get_reset_state(Object *obj) +-{ +- VirtIOMEM *vmem = VIRTIO_MEM(obj); +- return &vmem->reset_state; +-} +- +-static void virtio_mem_system_reset_hold(Object *obj, ResetType type) +-{ +- VirtIOMEM *vmem = VIRTIO_MEM(obj); +- +- /* +- * When waking up from standby/suspend-to-ram, do not unplug any memory. +- */ +- if (type == RESET_TYPE_WAKEUP) { +- return; +- } +- +- /* +- * During usual resets, we will unplug all memory and shrink the usable +- * region size. This is, however, not possible in all scenarios. Then, +- * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL). +- */ +- virtio_mem_unplug_all(vmem); +-} +- + static void virtio_mem_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOMEMClass *vmc = VIRTIO_MEM_CLASS(klass); + RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_CLASS(klass); +- ResettableClass *rc = RESETTABLE_CLASS(klass); + + device_class_set_props(dc, virtio_mem_properties); + dc->vmsd = &vmstate_virtio_mem; +@@ -1893,9 +1892,6 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data) + rdmc->replay_discarded = virtio_mem_rdm_replay_discarded; + rdmc->register_listener = virtio_mem_rdm_register_listener; + rdmc->unregister_listener = virtio_mem_rdm_unregister_listener; +- +- rc->get_state = virtio_mem_get_reset_state; +- rc->phases.hold = virtio_mem_system_reset_hold; + } + + static const TypeInfo virtio_mem_info = { +@@ -1918,3 +1914,48 @@ static void virtio_register_types(void) + } + + type_init(virtio_register_types) ++ ++OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(VirtioMemSystemReset, virtio_mem_system_reset, VIRTIO_MEM_SYSTEM_RESET, OBJECT, { TYPE_RESETTABLE_INTERFACE }, { }) ++ ++static void virtio_mem_system_reset_init(Object *obj) ++{ ++} ++ ++static void virtio_mem_system_reset_finalize(Object *obj) ++{ ++} ++ ++static ResettableState *virtio_mem_system_reset_get_state(Object *obj) ++{ ++ VirtioMemSystemReset *vmem_reset = VIRTIO_MEM_SYSTEM_RESET(obj); ++ ++ return &vmem_reset->reset_state; ++} ++ ++static void virtio_mem_system_reset_hold(Object *obj, ResetType type) ++{ ++ VirtioMemSystemReset *vmem_reset = VIRTIO_MEM_SYSTEM_RESET(obj); ++ VirtIOMEM *vmem = vmem_reset->vmem; ++ ++ /* ++ * When waking up from standby/suspend-to-ram, do not unplug any memory. ++ */ ++ if (type == RESET_TYPE_WAKEUP) { ++ return; ++ } ++ ++ /* ++ * During usual resets, we will unplug all memory and shrink the usable ++ * region size. This is, however, not possible in all scenarios. Then, ++ * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL). ++ */ ++ virtio_mem_unplug_all(vmem); ++} ++ ++static void virtio_mem_system_reset_class_init(ObjectClass *klass, void *data) ++{ ++ ResettableClass *rc = RESETTABLE_CLASS(klass); ++ ++ rc->get_state = virtio_mem_system_reset_get_state; ++ rc->phases.hold = virtio_mem_system_reset_hold; ++} +diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h +index a1af144c28..550ce585b2 100644 +--- a/include/hw/virtio/virtio-mem.h ++++ b/include/hw/virtio/virtio-mem.h +@@ -25,6 +25,10 @@ + OBJECT_DECLARE_TYPE(VirtIOMEM, VirtIOMEMClass, + VIRTIO_MEM) + ++#define TYPE_VIRTIO_MEM_SYSTEM_RESET "virtio-mem-system-reset" ++ ++OBJECT_DECLARE_SIMPLE_TYPE(VirtioMemSystemReset, VIRTIO_MEM_SYSTEM_RESET) ++ + #define VIRTIO_MEM_MEMDEV_PROP "memdev" + #define VIRTIO_MEM_NODE_PROP "node" + #define VIRTIO_MEM_SIZE_PROP "size" +@@ -117,8 +121,15 @@ struct VirtIOMEM { + /* listeners to notify on plug/unplug activity. */ + QLIST_HEAD(, RamDiscardListener) rdl_list; + +- /* State of the resettable container */ ++ /* Catch system resets -> qemu_devices_reset() only. */ ++ VirtioMemSystemReset *system_reset; ++}; ++ ++struct VirtioMemSystemReset { ++ Object parent; ++ + ResettableState reset_state; ++ VirtIOMEM *vmem; + }; + + struct VirtIOMEMClass { +-- +2.48.1 + diff --git a/qemu-kvm.spec b/qemu-kvm.spec index 1eb6843..e512267 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -149,7 +149,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version} \ Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 9.1.0 -Release: 17%{?rcrel}%{?dist}%{?cc_suffix} +Release: 18%{?rcrel}%{?dist}%{?cc_suffix} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped # Epoch 15 used for RHEL 8 # Epoch 17 used for RHEL 9 (due to release versioning offset in RHEL 8.5) @@ -493,6 +493,58 @@ Patch160: kvm-vfio-pci-Delete-local-pm_cap.patch Patch161: kvm-pcie-virtio-Remove-redundant-pm_cap.patch # For RHEL-7301 - [intel iommu] VFIO_MAP_DMA failed: Bad address on system_powerdown Patch162: kvm-hw-vfio-pci-Re-order-pre-reset.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch163: kvm-virtio-kconfig-memory-devices-are-PCI-only.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch164: kvm-hw-s390-ccw-device-Convert-to-three-phase-reset.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch165: kvm-hw-s390-virtio-ccw-Convert-to-three-phase-reset.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch166: kvm-target-s390-Convert-CPU-to-Resettable-interface.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch167: kvm-reset-Use-ResetType-for-qemu_devices_reset-and-Machi.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch168: kvm-reset-Add-RESET_TYPE_WAKEUP.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch169: kvm-virtio-mem-Use-new-Resettable-framework-instead-of-L.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch170: kvm-virtio-mem-Add-support-for-suspend-wake-up-with-plug.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch171: kvm-virtio-mem-unplug-memory-only-during-system-resets-n.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch172: kvm-s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch173: kvm-s390x-s390-virtio-hcall-remove-hypercall-registratio.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch174: kvm-s390x-s390-virtio-hcall-prepare-for-more-diag500-hyp.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch175: kvm-s390x-rename-s390-virtio-hcall-to-s390-hypercall.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch176: kvm-s390x-s390-virtio-ccw-move-setting-the-maximum-guest.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch177: kvm-s390x-introduce-s390_get_memory_limit.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch178: kvm-s390x-s390-hypercall-introduce-DIAG500-STORAGE_LIMIT.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch179: kvm-s390x-s390-stattrib-kvm-prepare-for-memory-devices-a.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch180: kvm-s390x-s390-skeys-prepare-for-memory-devices.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch181: kvm-s390x-s390-virtio-ccw-prepare-for-memory-devices.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch182: kvm-s390x-pv-prepare-for-memory-devices.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch183: kvm-s390x-remember-the-maximum-page-size.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch184: kvm-s390x-virtio-ccw-add-support-for-virtio-based-memory.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch185: kvm-s390x-virtio-mem-support.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch186: kvm-hw-virtio-Also-include-md-stubs-in-case-CONFIG_VIRTI.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch187: kvm-virtio-mem-don-t-warn-about-THP-sizes-on-a-kernel-wi.patch +# For RHEL-72977 - [IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part +Patch188: kvm-redhat-Enable-virtio-mem-on-s390x.patch %if %{have_clang} BuildRequires: clang @@ -1561,6 +1613,36 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog +* Mon Apr 14 2025 Jon Maloy - 9.1.0-18 +- kvm-virtio-kconfig-memory-devices-are-PCI-only.patch [RHEL-72977] +- kvm-hw-s390-ccw-device-Convert-to-three-phase-reset.patch [RHEL-72977] +- kvm-hw-s390-virtio-ccw-Convert-to-three-phase-reset.patch [RHEL-72977] +- kvm-target-s390-Convert-CPU-to-Resettable-interface.patch [RHEL-72977] +- kvm-reset-Use-ResetType-for-qemu_devices_reset-and-Machi.patch [RHEL-72977] +- kvm-reset-Add-RESET_TYPE_WAKEUP.patch [RHEL-72977] +- kvm-virtio-mem-Use-new-Resettable-framework-instead-of-L.patch [RHEL-72977] +- kvm-virtio-mem-Add-support-for-suspend-wake-up-with-plug.patch [RHEL-72977] +- kvm-virtio-mem-unplug-memory-only-during-system-resets-n.patch [RHEL-72977] +- kvm-s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch [RHEL-72977] +- kvm-s390x-s390-virtio-hcall-remove-hypercall-registratio.patch [RHEL-72977] +- kvm-s390x-s390-virtio-hcall-prepare-for-more-diag500-hyp.patch [RHEL-72977] +- kvm-s390x-rename-s390-virtio-hcall-to-s390-hypercall.patch [RHEL-72977] +- kvm-s390x-s390-virtio-ccw-move-setting-the-maximum-guest.patch [RHEL-72977] +- kvm-s390x-introduce-s390_get_memory_limit.patch [RHEL-72977] +- kvm-s390x-s390-hypercall-introduce-DIAG500-STORAGE_LIMIT.patch [RHEL-72977] +- kvm-s390x-s390-stattrib-kvm-prepare-for-memory-devices-a.patch [RHEL-72977] +- kvm-s390x-s390-skeys-prepare-for-memory-devices.patch [RHEL-72977] +- kvm-s390x-s390-virtio-ccw-prepare-for-memory-devices.patch [RHEL-72977] +- kvm-s390x-pv-prepare-for-memory-devices.patch [RHEL-72977] +- kvm-s390x-remember-the-maximum-page-size.patch [RHEL-72977] +- kvm-s390x-virtio-ccw-add-support-for-virtio-based-memory.patch [RHEL-72977] +- kvm-s390x-virtio-mem-support.patch [RHEL-72977] +- kvm-hw-virtio-Also-include-md-stubs-in-case-CONFIG_VIRTI.patch [RHEL-72977] +- kvm-virtio-mem-don-t-warn-about-THP-sizes-on-a-kernel-wi.patch [RHEL-72977] +- kvm-redhat-Enable-virtio-mem-on-s390x.patch [RHEL-72977] +- Resolves: RHEL-72977 + ([IBM 9.7 FEAT] KVM: Enable virtio-mem support - qemu part) + * Mon Mar 31 2025 Jon Maloy - 9.1.0-17 - kvm-hw-pci-Rename-has_power-to-enabled.patch [RHEL-7301] - kvm-hw-pci-Basic-support-for-PCI-power-management.patch [RHEL-7301]