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