summaryrefslogtreecommitdiffstats
path: root/hw/s390x/sclp.c
diff options
context:
space:
mode:
authorCollin Walling2020-09-15 21:44:14 +0200
committerCornelia Huck2020-10-02 13:52:49 +0200
commit1ecd6078f587cfadda8edc93d45b5072e35f2d17 (patch)
tree320552daf52ca0472da553ef67c103431b0017de /hw/s390x/sclp.c
parents390/sclp: use cpu offset to locate cpu entries (diff)
downloadqemu-1ecd6078f587cfadda8edc93d45b5072e35f2d17.tar.gz
qemu-1ecd6078f587cfadda8edc93d45b5072e35f2d17.tar.xz
qemu-1ecd6078f587cfadda8edc93d45b5072e35f2d17.zip
s390/sclp: add extended-length sccb support for kvm guest
As more features and facilities are added to the Read SCP Info (RSCPI) response, more space is required to store them. The space used to store these new features intrudes on the space originally used to store CPU entries. This means as more features and facilities are added to the RSCPI response, less space can be used to store CPU entries. With the Extended-Length SCCB (ELS) facility, a KVM guest can execute the RSCPI command and determine if the SCCB is large enough to store a complete reponse. If it is not large enough, then the required length will be set in the SCCB header. The caller of the SCLP command is responsible for creating a large-enough SCCB to store a complete response. Proper checking should be in place, and the caller should execute the command once-more with the large-enough SCCB. This facility also enables an extended SCCB for the Read CPU Info (RCPUI) command. When this facility is enabled, the boundary violation response cannot be a result from the RSCPI, RSCPI Forced, or RCPUI commands. In order to tolerate kernels that do not yet have full support for this feature, a "fixed" offset to the start of the CPU Entries within the Read SCP Info struct is set to allow for the original 248 max entries when this feature is disabled. Additionally, this is introduced as a CPU feature to protect the guest from migrating to a machine that does not support storing an extended SCCB. This could otherwise hinder the VM from being able to read all available CPU entries after migration (such as during re-ipl). Signed-off-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Acked-by: Cornelia Huck <cohuck@redhat.com> Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Message-Id: <20200915194416.107460-7-walling@linux.ibm.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Diffstat (limited to 'hw/s390x/sclp.c')
-rw-r--r--hw/s390x/sclp.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 1df67c99bf..caf40f41b6 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -49,13 +49,30 @@ static inline bool sclp_command_code_valid(uint32_t code)
return false;
}
-static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len)
+static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len,
+ uint32_t code)
{
uint64_t sccb_max_addr = sccb_addr + sccb_len - 1;
uint64_t sccb_boundary = (sccb_addr & PAGE_MASK) + PAGE_SIZE;
- if (sccb_max_addr < sccb_boundary) {
- return true;
+ switch (code & SCLP_CMD_CODE_MASK) {
+ case SCLP_CMDW_READ_SCP_INFO:
+ case SCLP_CMDW_READ_SCP_INFO_FORCED:
+ case SCLP_CMDW_READ_CPU_INFO:
+ /*
+ * An extended-length SCCB is only allowed for Read SCP/CPU Info and
+ * is allowed to exceed the 4k boundary. The respective commands will
+ * set the length field to the required length if an insufficient
+ * SCCB length is provided.
+ */
+ if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) {
+ return true;
+ }
+ /* fallthrough */
+ default:
+ if (sccb_max_addr < sccb_boundary) {
+ return true;
+ }
}
return false;
@@ -80,6 +97,12 @@ static void prepare_cpu_entries(MachineState *ms, CPUEntry *entry, int *count)
#define SCCB_REQ_LEN(s, max_cpus) (sizeof(s) + max_cpus * sizeof(CPUEntry))
+static inline bool ext_len_sccb_supported(SCCBHeader header)
+{
+ return s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) &&
+ header.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE;
+}
+
/* Provide information about the configuration, CPUs and storage */
static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
{
@@ -89,10 +112,15 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
int rnsize, rnmax;
IplParameterBlock *ipib = s390_ipl_get_iplb();
int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len);
- int offset_cpu = offsetof(ReadInfo, entries);
+ int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ?
+ offsetof(ReadInfo, entries) :
+ SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET;
CPUEntry *entries_start = (void *)sccb + offset_cpu;
if (be16_to_cpu(sccb->h.length) < required_len) {
+ if (ext_len_sccb_supported(sccb->h)) {
+ sccb->h.length = cpu_to_be16(required_len);
+ }
sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
return;
}
@@ -153,6 +181,9 @@ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
int required_len = SCCB_REQ_LEN(ReadCpuInfo, machine->possible_cpus->len);
if (be16_to_cpu(sccb->h.length) < required_len) {
+ if (ext_len_sccb_supported(sccb->h)) {
+ sccb->h.length = cpu_to_be16(required_len);
+ }
sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
return;
}
@@ -249,7 +280,7 @@ int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
goto out_write;
}
- if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length))) {
+ if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length), code)) {
work_sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
goto out_write;
}
@@ -302,7 +333,7 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
goto out_write;
}
- if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length))) {
+ if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length), code)) {
work_sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
goto out_write;
}