a19a21
From 7ad1c4aaea6cd202449c05fc0034af6b108def4f Mon Sep 17 00:00:00 2001
a19a21
From: Thomas Huth <thuth@redhat.com>
a19a21
Date: Wed, 11 Nov 2020 12:03:14 -0500
a19a21
Subject: [PATCH 14/18] s390: guest support for diagnose 0x318
a19a21
a19a21
RH-Author: Thomas Huth <thuth@redhat.com>
a19a21
Message-id: <20201111120316.707489-11-thuth@redhat.com>
a19a21
Patchwork-id: 99507
a19a21
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 10/12] s390: guest support for diagnose 0x318
a19a21
Bugzilla: 1798506
a19a21
RH-Acked-by: Jens Freimann <jfreimann@redhat.com>
a19a21
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
a19a21
RH-Acked-by: David Hildenbrand <david@redhat.com>
a19a21
a19a21
From: Collin Walling <walling@linux.ibm.com>
a19a21
a19a21
DIAGNOSE 0x318 (diag318) is an s390 instruction that allows the storage
a19a21
of diagnostic information that is collected by the firmware in the case
a19a21
of hardware/firmware service events.
a19a21
a19a21
QEMU handles the instruction by storing the info in the CPU state. A
a19a21
subsequent register sync will communicate the data to the hypervisor.
a19a21
a19a21
QEMU handles the migration via a VM State Description.
a19a21
a19a21
This feature depends on the Extended-Length SCCB (els) feature. If
a19a21
els is not present, then a warning will be printed and the SCLP bit
a19a21
that allows the Linux kernel to execute the instruction will not be
a19a21
set.
a19a21
a19a21
Availability of this instruction is determined by byte 134 (aka fac134)
a19a21
bit 0 of the SCLP Read Info block. This coincidentally expands into the
a19a21
space used for CPU entries, which means VMs running with the diag318
a19a21
capability may not be able to read information regarding all CPUs
a19a21
unless the guest kernel supports an extended-length SCCB.
a19a21
a19a21
This feature is not supported in protected virtualization mode.
a19a21
a19a21
Signed-off-by: Collin Walling <walling@linux.ibm.com>
a19a21
Acked-by: Janosch Frank <frankja@linux.ibm.com>
a19a21
Acked-by: Thomas Huth <thuth@redhat.com>
a19a21
Acked-by: David Hildenbrand <david@redhat.com>
a19a21
Acked-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
a19a21
Message-Id: <20200915194416.107460-9-walling@linux.ibm.com>
a19a21
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
a19a21
(cherry picked from commit fabdada9357b9cfd980c7744ddce47e34600bbef)
a19a21
Signed-off-by: Thomas Huth <thuth@redhat.com>
a19a21
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
a19a21
---
a19a21
 hw/s390x/sclp.c                     |  5 ++++
a19a21
 include/hw/s390x/sclp.h             |  8 ++++++
a19a21
 target/s390x/cpu.h                  |  2 ++
a19a21
 target/s390x/cpu_features.h         |  1 +
a19a21
 target/s390x/cpu_features_def.inc.h |  3 +++
a19a21
 target/s390x/cpu_models.c           |  1 +
a19a21
 target/s390x/gen-features.c         |  1 +
a19a21
 target/s390x/kvm.c                  | 39 +++++++++++++++++++++++++++++
a19a21
 target/s390x/machine.c              | 17 +++++++++++++
a19a21
 9 files changed, 77 insertions(+)
a19a21
a19a21
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
a19a21
index 8d111628e04..2931046f456 100644
a19a21
--- a/hw/s390x/sclp.c
a19a21
+++ b/hw/s390x/sclp.c
a19a21
@@ -139,6 +139,11 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
a19a21
     s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT,
a19a21
                          read_info->conf_char_ext);
a19a21
 
a19a21
+    if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) {
a19a21
+        s390_get_feat_block(S390_FEAT_TYPE_SCLP_FAC134,
a19a21
+                            &read_info->fac134);
a19a21
+    }
a19a21
+
a19a21
     read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
a19a21
                                         SCLP_HAS_IOA_RECONFIG);
a19a21
 
a19a21
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
a19a21
index 62e2aa1d9f1..addd904e5f4 100644
a19a21
--- a/include/hw/s390x/sclp.h
a19a21
+++ b/include/hw/s390x/sclp.h
a19a21
@@ -133,7 +133,15 @@ typedef struct ReadInfo {
a19a21
     uint16_t highest_cpu;
a19a21
     uint8_t  _reserved5[124 - 122];     /* 122-123 */
a19a21
     uint32_t hmfai;
a19a21
+    uint8_t  _reserved7[134 - 128];     /* 128-133 */
a19a21
+    uint8_t  fac134;
a19a21
+    uint8_t  _reserved8[144 - 135];     /* 135-143 */
a19a21
     struct CPUEntry entries[];
a19a21
+    /*
a19a21
+     * When the Extended-Length SCCB (ELS) feature is enabled the
a19a21
+     * start of the entries field begins at an offset denoted by the
a19a21
+     * offset_cpu field, otherwise it's at an offset of 128.
a19a21
+     */
a19a21
 } QEMU_PACKED ReadInfo;
a19a21
 
a19a21
 typedef struct ReadCpuInfo {
a19a21
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
a19a21
index a48e655c4d4..1dc21cd311d 100644
a19a21
--- a/target/s390x/cpu.h
a19a21
+++ b/target/s390x/cpu.h
a19a21
@@ -117,6 +117,8 @@ struct CPUS390XState {
a19a21
     uint16_t external_call_addr;
a19a21
     DECLARE_BITMAP(emergency_signals, S390_MAX_CPUS);
a19a21
 
a19a21
+    uint64_t diag318_info;
a19a21
+
a19a21
     /* Fields up to this point are cleared by a CPU reset */
a19a21
     struct {} end_reset_fields;
a19a21
 
a19a21
diff --git a/target/s390x/cpu_features.h b/target/s390x/cpu_features.h
a19a21
index da695a8346e..f74f7fc3a11 100644
a19a21
--- a/target/s390x/cpu_features.h
a19a21
+++ b/target/s390x/cpu_features.h
a19a21
@@ -23,6 +23,7 @@ typedef enum {
a19a21
     S390_FEAT_TYPE_STFL,
a19a21
     S390_FEAT_TYPE_SCLP_CONF_CHAR,
a19a21
     S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT,
a19a21
+    S390_FEAT_TYPE_SCLP_FAC134,
a19a21
     S390_FEAT_TYPE_SCLP_CPU,
a19a21
     S390_FEAT_TYPE_MISC,
a19a21
     S390_FEAT_TYPE_PLO,
a19a21
diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h
a19a21
index 3548d65a69a..cf7e04ee44f 100644
a19a21
--- a/target/s390x/cpu_features_def.inc.h
a19a21
+++ b/target/s390x/cpu_features_def.inc.h
a19a21
@@ -122,6 +122,9 @@ DEF_FEAT(SIE_CMMA, "cmma", SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-man
a19a21
 DEF_FEAT(SIE_PFMFI, "pfmfi", SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility")
a19a21
 DEF_FEAT(SIE_IBS, "ibs", SCLP_CONF_CHAR_EXT, 10, "SIE: Interlock-and-broadcast-suppression facility")
a19a21
 
a19a21
+/* Features exposed via SCLP SCCB Facilities byte 134 (bit numbers relative to byte-134) */
a19a21
+DEF_FEAT(DIAG_318, "diag318", SCLP_FAC134, 0, "Control program name and version codes")
a19a21
+
a19a21
 /* Features exposed via SCLP CPU info. */
a19a21
 DEF_FEAT(SIE_F2, "sief2", SCLP_CPU, 4, "SIE: interception format 2 (Virtual SIE)")
a19a21
 DEF_FEAT(SIE_SKEY, "skey", SCLP_CPU, 5, "SIE: Storage-key facility")
a19a21
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
a19a21
index be718220d79..bf6a3faba9e 100644
a19a21
--- a/target/s390x/cpu_models.c
a19a21
+++ b/target/s390x/cpu_models.c
a19a21
@@ -823,6 +823,7 @@ static void check_consistency(const S390CPUModel *model)
a19a21
         { S390_FEAT_PTFF_STOE, S390_FEAT_MULTIPLE_EPOCH },
a19a21
         { S390_FEAT_PTFF_STOUE, S390_FEAT_MULTIPLE_EPOCH },
a19a21
         { S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP },
a19a21
+        { S390_FEAT_DIAG_318, S390_FEAT_EXTENDED_LENGTH_SCCB },
a19a21
     };
a19a21
     int i;
a19a21
 
a19a21
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
a19a21
index 6857f657fba..a1f0a6f3c6f 100644
a19a21
--- a/target/s390x/gen-features.c
a19a21
+++ b/target/s390x/gen-features.c
a19a21
@@ -523,6 +523,7 @@ static uint16_t full_GEN12_GA1[] = {
a19a21
     S390_FEAT_AP_FACILITIES_TEST,
a19a21
     S390_FEAT_AP,
a19a21
     S390_FEAT_EXTENDED_LENGTH_SCCB,
a19a21
+    S390_FEAT_DIAG_318,
a19a21
 };
a19a21
 
a19a21
 static uint16_t full_GEN12_GA2[] = {
a19a21
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
a19a21
index ef437acb5c1..e5e190d21c9 100644
a19a21
--- a/target/s390x/kvm.c
a19a21
+++ b/target/s390x/kvm.c
a19a21
@@ -105,6 +105,7 @@
a19a21
 
a19a21
 #define DIAG_TIMEREVENT                 0x288
a19a21
 #define DIAG_IPL                        0x308
a19a21
+#define DIAG_SET_CONTROL_PROGRAM_CODES  0x318
a19a21
 #define DIAG_KVM_HYPERCALL              0x500
a19a21
 #define DIAG_KVM_BREAKPOINT             0x501
a19a21
 
a19a21
@@ -602,6 +603,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
a19a21
         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ETOKEN;
a19a21
     }
a19a21
 
a19a21
+    if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
a19a21
+        cs->kvm_run->s.regs.diag318 = env->diag318_info;
a19a21
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
a19a21
+    }
a19a21
+
a19a21
     /* Finally the prefix */
a19a21
     if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
a19a21
         cs->kvm_run->s.regs.prefix = env->psa;
a19a21
@@ -741,6 +747,10 @@ int kvm_arch_get_registers(CPUState *cs)
a19a21
         }
a19a21
     }
a19a21
 
a19a21
+    if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
a19a21
+        env->diag318_info = cs->kvm_run->s.regs.diag318;
a19a21
+    }
a19a21
+
a19a21
     return 0;
a19a21
 }
a19a21
 
a19a21
@@ -1601,6 +1611,27 @@ static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
a19a21
     return -ENOENT;
a19a21
 }
a19a21
 
a19a21
+static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
a19a21
+{
a19a21
+    uint64_t reg = (run->s390_sieic.ipa & 0x00f0) >> 4;
a19a21
+    uint64_t diag318_info = run->s.regs.gprs[reg];
a19a21
+
a19a21
+    /*
a19a21
+     * DIAG 318 can only be enabled with KVM support. As such, let's
a19a21
+     * ensure a guest cannot execute this instruction erroneously.
a19a21
+     */
a19a21
+    if (!s390_has_feat(S390_FEAT_DIAG_318)) {
a19a21
+        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
a19a21
+    }
a19a21
+
a19a21
+    cpu->env.diag318_info = diag318_info;
a19a21
+
a19a21
+    if (can_sync_regs(CPU(cpu), KVM_SYNC_DIAG318)) {
a19a21
+        run->s.regs.diag318 = diag318_info;
a19a21
+        run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
a19a21
+    }
a19a21
+}
a19a21
+
a19a21
 #define DIAG_KVM_CODE_MASK 0x000000000000ffff
a19a21
 
a19a21
 static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
a19a21
@@ -1620,6 +1651,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
a19a21
     case DIAG_IPL:
a19a21
         kvm_handle_diag_308(cpu, run);
a19a21
         break;
a19a21
+    case DIAG_SET_CONTROL_PROGRAM_CODES:
a19a21
+        handle_diag_318(cpu, run);
a19a21
+        break;
a19a21
     case DIAG_KVM_HYPERCALL:
a19a21
         r = handle_hypercall(cpu, run);
a19a21
         break;
a19a21
@@ -2449,6 +2483,11 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
a19a21
      */
a19a21
     set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features);
a19a21
 
a19a21
+    /* DIAGNOSE 0x318 is not supported under protected virtualization */
a19a21
+    if (!s390_is_pv() && kvm_check_extension(kvm_state, KVM_CAP_S390_DIAG318)) {
a19a21
+        set_bit(S390_FEAT_DIAG_318, model->features);
a19a21
+    }
a19a21
+
a19a21
     /* strip of features that are not part of the maximum model */
a19a21
     bitmap_and(model->features, model->features, model->def->full_feat,
a19a21
                S390_FEAT_MAX);
a19a21
diff --git a/target/s390x/machine.c b/target/s390x/machine.c
a19a21
index 549bb6c2808..5b4e82f1ab9 100644
a19a21
--- a/target/s390x/machine.c
a19a21
+++ b/target/s390x/machine.c
a19a21
@@ -234,6 +234,22 @@ const VMStateDescription vmstate_etoken = {
a19a21
     }
a19a21
 };
a19a21
 
a19a21
+static bool diag318_needed(void *opaque)
a19a21
+{
a19a21
+    return s390_has_feat(S390_FEAT_DIAG_318);
a19a21
+}
a19a21
+
a19a21
+const VMStateDescription vmstate_diag318 = {
a19a21
+    .name = "cpu/diag318",
a19a21
+    .version_id = 1,
a19a21
+    .minimum_version_id = 1,
a19a21
+    .needed = diag318_needed,
a19a21
+    .fields = (VMStateField[]) {
a19a21
+        VMSTATE_UINT64(env.diag318_info, S390CPU),
a19a21
+        VMSTATE_END_OF_LIST()
a19a21
+    }
a19a21
+};
a19a21
+
a19a21
 const VMStateDescription vmstate_s390_cpu = {
a19a21
     .name = "cpu",
a19a21
     .post_load = cpu_post_load,
a19a21
@@ -270,6 +286,7 @@ const VMStateDescription vmstate_s390_cpu = {
a19a21
         &vmstate_gscb,
a19a21
         &vmstate_bpbc,
a19a21
         &vmstate_etoken,
a19a21
+        &vmstate_diag318,
a19a21
         NULL
a19a21
     },
a19a21
 };
a19a21
-- 
a19a21
2.27.0
a19a21