Blame SOURCES/kvm-s390-sclp-add-extended-length-sccb-support-for-kvm-g.patch

8fced6
From e1a3684f9b08fa9db35331b5c5ad11879f512e90 Mon Sep 17 00:00:00 2001
8fced6
From: Thomas Huth <thuth@redhat.com>
8fced6
Date: Wed, 11 Nov 2020 12:03:11 -0500
8fced6
Subject: [PATCH 11/18] s390/sclp: add extended-length sccb support for kvm
8fced6
 guest
8fced6
8fced6
RH-Author: Thomas Huth <thuth@redhat.com>
8fced6
Message-id: <20201111120316.707489-8-thuth@redhat.com>
8fced6
Patchwork-id: 99504
8fced6
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 07/12] s390/sclp: add extended-length sccb support for kvm guest
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
As more features and facilities are added to the Read SCP Info (RSCPI)
8fced6
response, more space is required to store them. The space used to store
8fced6
these new features intrudes on the space originally used to store CPU
8fced6
entries. This means as more features and facilities are added to the
8fced6
RSCPI response, less space can be used to store CPU entries.
8fced6
8fced6
With the Extended-Length SCCB (ELS) facility, a KVM guest can execute
8fced6
the RSCPI command and determine if the SCCB is large enough to store a
8fced6
complete reponse. If it is not large enough, then the required length
8fced6
will be set in the SCCB header.
8fced6
8fced6
The caller of the SCLP command is responsible for creating a
8fced6
large-enough SCCB to store a complete response. Proper checking should
8fced6
be in place, and the caller should execute the command once-more with
8fced6
the large-enough SCCB.
8fced6
8fced6
This facility also enables an extended SCCB for the Read CPU Info
8fced6
(RCPUI) command.
8fced6
8fced6
When this facility is enabled, the boundary violation response cannot
8fced6
be a result from the RSCPI, RSCPI Forced, or RCPUI commands.
8fced6
8fced6
In order to tolerate kernels that do not yet have full support for this
8fced6
feature, a "fixed" offset to the start of the CPU Entries within the
8fced6
Read SCP Info struct is set to allow for the original 248 max entries
8fced6
when this feature is disabled.
8fced6
8fced6
Additionally, this is introduced as a CPU feature to protect the guest
8fced6
from migrating to a machine that does not support storing an extended
8fced6
SCCB. This could otherwise hinder the VM from being able to read all
8fced6
available CPU entries after migration (such as during re-ipl).
8fced6
8fced6
Signed-off-by: Collin Walling <walling@linux.ibm.com>
8fced6
Reviewed-by: Thomas Huth <thuth@redhat.com>
8fced6
Acked-by: Cornelia Huck <cohuck@redhat.com>
8fced6
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
8fced6
Message-Id: <20200915194416.107460-7-walling@linux.ibm.com>
8fced6
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
8fced6
(cherry picked from commit 1ecd6078f587cfadda8edc93d45b5072e35f2d17)
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                     | 43 +++++++++++++++++++++++++----
8fced6
 include/hw/s390x/sclp.h             |  1 +
8fced6
 target/s390x/cpu_features_def.inc.h |  1 +
8fced6
 target/s390x/gen-features.c         |  1 +
8fced6
 target/s390x/kvm.c                  |  8 ++++++
8fced6
 5 files changed, 48 insertions(+), 6 deletions(-)
8fced6
8fced6
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
8fced6
index 017989b3888..8d111628e04 100644
8fced6
--- a/hw/s390x/sclp.c
8fced6
+++ b/hw/s390x/sclp.c
8fced6
@@ -49,13 +49,30 @@ static inline bool sclp_command_code_valid(uint32_t code)
8fced6
     return false;
8fced6
 }
8fced6
 
8fced6
-static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len)
8fced6
+static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len,
8fced6
+                                 uint32_t code)
8fced6
 {
8fced6
     uint64_t sccb_max_addr = sccb_addr + sccb_len - 1;
8fced6
     uint64_t sccb_boundary = (sccb_addr & PAGE_MASK) + PAGE_SIZE;
8fced6
 
8fced6
-    if (sccb_max_addr < sccb_boundary) {
8fced6
-        return true;
8fced6
+    switch (code & SCLP_CMD_CODE_MASK) {
8fced6
+    case SCLP_CMDW_READ_SCP_INFO:
8fced6
+    case SCLP_CMDW_READ_SCP_INFO_FORCED:
8fced6
+    case SCLP_CMDW_READ_CPU_INFO:
8fced6
+        /*
8fced6
+         * An extended-length SCCB is only allowed for Read SCP/CPU Info and
8fced6
+         * is allowed to exceed the 4k boundary. The respective commands will
8fced6
+         * set the length field to the required length if an insufficient
8fced6
+         * SCCB length is provided.
8fced6
+         */
8fced6
+        if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) {
8fced6
+            return true;
8fced6
+        }
8fced6
+        /* fallthrough */
8fced6
+    default:
8fced6
+        if (sccb_max_addr < sccb_boundary) {
8fced6
+            return true;
8fced6
+        }
8fced6
     }
8fced6
 
8fced6
     return false;
8fced6
@@ -80,6 +97,12 @@ static void prepare_cpu_entries(MachineState *ms, CPUEntry *entry, int *count)
8fced6
 
8fced6
 #define SCCB_REQ_LEN(s, max_cpus) (sizeof(s) + max_cpus * sizeof(CPUEntry))
8fced6
 
8fced6
+static inline bool ext_len_sccb_supported(SCCBHeader header)
8fced6
+{
8fced6
+    return s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) &&
8fced6
+           header.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE;
8fced6
+}
8fced6
+
8fced6
 /* Provide information about the configuration, CPUs and storage */
8fced6
 static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
8fced6
 {
8fced6
@@ -89,10 +112,15 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
8fced6
     int rnsize, rnmax;
8fced6
     IplParameterBlock *ipib = s390_ipl_get_iplb();
8fced6
     int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len);
8fced6
-    int offset_cpu = offsetof(ReadInfo, entries);
8fced6
+    int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ?
8fced6
+                     offsetof(ReadInfo, entries) :
8fced6
+                     SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET;
8fced6
     CPUEntry *entries_start = (void *)sccb + offset_cpu;
8fced6
 
8fced6
     if (be16_to_cpu(sccb->h.length) < required_len) {
8fced6
+        if (ext_len_sccb_supported(sccb->h)) {
8fced6
+            sccb->h.length = cpu_to_be16(required_len);
8fced6
+        }
8fced6
         sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
8fced6
         return;
8fced6
     }
8fced6
@@ -153,6 +181,9 @@ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
8fced6
     int required_len = SCCB_REQ_LEN(ReadCpuInfo, machine->possible_cpus->len);
8fced6
 
8fced6
     if (be16_to_cpu(sccb->h.length) < required_len) {
8fced6
+        if (ext_len_sccb_supported(sccb->h)) {
8fced6
+            sccb->h.length = cpu_to_be16(required_len);
8fced6
+        }
8fced6
         sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
8fced6
         return;
8fced6
     }
8fced6
@@ -249,7 +280,7 @@ int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
8fced6
         goto out_write;
8fced6
     }
8fced6
 
8fced6
-    if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length))) {
8fced6
+    if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length), code)) {
8fced6
         work_sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
8fced6
         goto out_write;
8fced6
     }
8fced6
@@ -302,7 +333,7 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
8fced6
         goto out_write;
8fced6
     }
8fced6
 
8fced6
-    if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length))) {
8fced6
+    if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length), code)) {
8fced6
         work_sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
8fced6
         goto out_write;
8fced6
     }
8fced6
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
8fced6
index 55f53a46540..df2fa4169b0 100644
8fced6
--- a/include/hw/s390x/sclp.h
8fced6
+++ b/include/hw/s390x/sclp.h
8fced6
@@ -110,6 +110,7 @@ typedef struct CPUEntry {
8fced6
     uint8_t reserved1;
8fced6
 } QEMU_PACKED CPUEntry;
8fced6
 
8fced6
+#define SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET     128
8fced6
 typedef struct ReadInfo {
8fced6
     SCCBHeader h;
8fced6
     uint16_t rnmax;
8fced6
diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h
8fced6
index 60db28351d0..3548d65a69a 100644
8fced6
--- a/target/s390x/cpu_features_def.inc.h
8fced6
+++ b/target/s390x/cpu_features_def.inc.h
8fced6
@@ -97,6 +97,7 @@ DEF_FEAT(GUARDED_STORAGE, "gs", STFL, 133, "Guarded-storage facility")
8fced6
 DEF_FEAT(VECTOR_PACKED_DECIMAL, "vxpd", STFL, 134, "Vector packed decimal facility")
8fced6
 DEF_FEAT(VECTOR_ENH, "vxeh", STFL, 135, "Vector enhancements facility")
8fced6
 DEF_FEAT(MULTIPLE_EPOCH, "mepoch", STFL, 139, "Multiple-epoch facility")
8fced6
+DEF_FEAT(EXTENDED_LENGTH_SCCB, "els", STFL, 140, "Extended-length SCCB facility")
8fced6
 DEF_FEAT(TEST_PENDING_EXT_INTERRUPTION, "tpei", STFL, 144, "Test-pending-external-interruption facility")
8fced6
 DEF_FEAT(INSERT_REFERENCE_BITS_MULT, "irbm", STFL, 145, "Insert-reference-bits-multiple facility")
8fced6
 DEF_FEAT(MSA_EXT_8, "msa8-base", STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)")
8fced6
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
8fced6
index 8ddeebc5441..6857f657fba 100644
8fced6
--- a/target/s390x/gen-features.c
8fced6
+++ b/target/s390x/gen-features.c
8fced6
@@ -522,6 +522,7 @@ static uint16_t full_GEN12_GA1[] = {
8fced6
     S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL,
8fced6
     S390_FEAT_AP_FACILITIES_TEST,
8fced6
     S390_FEAT_AP,
8fced6
+    S390_FEAT_EXTENDED_LENGTH_SCCB,
8fced6
 };
8fced6
 
8fced6
 static uint16_t full_GEN12_GA2[] = {
8fced6
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
8fced6
index 0bbf8f81b09..ef437acb5c1 100644
8fced6
--- a/target/s390x/kvm.c
8fced6
+++ b/target/s390x/kvm.c
8fced6
@@ -2441,6 +2441,14 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
8fced6
         KVM_S390_VM_CRYPTO_ENABLE_APIE)) {
8fced6
         set_bit(S390_FEAT_AP, model->features);
8fced6
     }
8fced6
+
8fced6
+    /*
8fced6
+     * Extended-Length SCCB is handled entirely within QEMU.
8fced6
+     * For PV guests this is completely fenced by the Ultravisor, as Service
8fced6
+     * Call error checking and STFLE interpretation are handled via SIE.
8fced6
+     */
8fced6
+    set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features);
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
-- 
8fced6
2.27.0
8fced6