From a0ad4344984c50939be8c99371af0988551fb776 Mon Sep 17 00:00:00 2001
From: Thomas Huth <thuth@redhat.com>
Date: Fri, 20 Nov 2020 11:46:09 -0500
Subject: [PATCH 17/18] s390/kvm: fix diag318 propagation and reset
 functionality

RH-Author: Thomas Huth <thuth@redhat.com>
Message-id: <20201120114609.408610-2-thuth@redhat.com>
Patchwork-id: 99787
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH 1/1] s390/kvm: fix diag318 propagation and reset functionality
Bugzilla: 1659412
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Acked-by: David Hildenbrand <david@redhat.com>

From: Collin Walling <walling@linux.ibm.com>

The Control Program Name Code (CPNC) portion of the diag318
info must be set within the SIE block of each VCPU in the
configuration. The handler will iterate through each VCPU
and dirty the diag318_info reg to be synced with KVM on a
subsequent sync_regs call.

Additionally, the diag318 info resets must be handled via
userspace. As such, QEMU will reset this value for each
VCPU during a modified clear, load normal, and load clear
reset event.

Fixes: fabdada9357b ("s390: guest support for diagnose 0x318")
Signed-off-by: Collin Walling <walling@linux.ibm.com>
Message-Id: <20201113221022.257054-1-walling@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Janosch Frank <frankja@de.ibm.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
(cherry picked from commit e2c6cd567422bfa563be026b9741a1854aecdc06)
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
---
 hw/s390x/s390-virtio-ccw.c |  4 ++++
 target/s390x/cpu.c         |  7 +++++++
 target/s390x/cpu.h         |  1 +
 target/s390x/kvm-stub.c    |  4 ++++
 target/s390x/kvm.c         | 22 +++++++++++++++++-----
 target/s390x/kvm_s390x.h   |  1 +
 6 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index e6ed13b649a..5905d2b7adc 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -489,6 +489,10 @@ static void s390_machine_reset(MachineState *machine)
     default:
         g_assert_not_reached();
     }
+
+    CPU_FOREACH(t) {
+        run_on_cpu(t, s390_do_cpu_set_diag318, RUN_ON_CPU_HOST_ULONG(0));
+    }
     s390_ipl_clear_reset_request();
 }
 
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 371b91b2d72..820cab96e12 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -445,6 +445,13 @@ void s390_enable_css_support(S390CPU *cpu)
         kvm_s390_enable_css_support(cpu);
     }
 }
+
+void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg)
+{
+    if (kvm_enabled()) {
+        kvm_s390_set_diag318(cs, arg.host_ulong);
+    }
+}
 #endif
 
 static gchar *s390_gdb_arch_name(CPUState *cs)
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 1dc21cd311d..83a23a11b96 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -774,6 +774,7 @@ 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);
+void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg);
 int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
                                 int vq, bool assign);
 #ifndef CONFIG_USER_ONLY
diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c
index aa185017a2a..9970b5a8c70 100644
--- a/target/s390x/kvm-stub.c
+++ b/target/s390x/kvm-stub.c
@@ -120,3 +120,7 @@ void kvm_s390_stop_interrupt(S390CPU *cpu)
 void kvm_s390_restart_interrupt(S390CPU *cpu)
 {
 }
+
+void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info)
+{
+}
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 6edb52f6d25..8d4406124b9 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -1611,10 +1611,23 @@ static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
     return -ENOENT;
 }
 
+void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info)
+{
+    CPUS390XState *env = &S390_CPU(cs)->env;
+
+    /* Feat bit is set only if KVM supports sync for diag318 */
+    if (s390_has_feat(S390_FEAT_DIAG_318)) {
+        env->diag318_info = diag318_info;
+        cs->kvm_run->s.regs.diag318 = diag318_info;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
+    }
+}
+
 static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
 {
     uint64_t reg = (run->s390_sieic.ipa & 0x00f0) >> 4;
     uint64_t diag318_info = run->s.regs.gprs[reg];
+    CPUState *t;
 
     /*
      * DIAG 318 can only be enabled with KVM support. As such, let's
@@ -1622,13 +1635,12 @@ static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
      */
     if (!s390_has_feat(S390_FEAT_DIAG_318)) {
         kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
+        return;
     }
 
-    cpu->env.diag318_info = diag318_info;
-
-    if (can_sync_regs(CPU(cpu), KVM_SYNC_DIAG318)) {
-        run->s.regs.diag318 = diag318_info;
-        run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
+    CPU_FOREACH(t) {
+        run_on_cpu(t, s390_do_cpu_set_diag318,
+                   RUN_ON_CPU_HOST_ULONG(diag318_info));
     }
 }
 
diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h
index 6ab17c81b73..25bbe98b251 100644
--- a/target/s390x/kvm_s390x.h
+++ b/target/s390x/kvm_s390x.h
@@ -45,5 +45,6 @@ void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp);
 void kvm_s390_crypto_reset(void);
 void kvm_s390_restart_interrupt(S390CPU *cpu);
 void kvm_s390_stop_interrupt(S390CPU *cpu);
+void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info);
 
 #endif /* KVM_S390X_H */
-- 
2.27.0

