yeahuh / rpms / qemu-kvm

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