--- /dev/null
+From 9abc2a08a7d665b02bdde974fd6c44aae86e923e Mon Sep 17 00:00:00 2001
+From: David Hildenbrand <dahi@linux.vnet.ibm.com>
+Date: Thu, 14 Jan 2016 22:12:47 +0100
+Subject: KVM: s390: fix memory overwrites when vx is disabled
+
+From: David Hildenbrand <dahi@linux.vnet.ibm.com>
+
+commit 9abc2a08a7d665b02bdde974fd6c44aae86e923e upstream.
+
+The kernel now always uses vector registers when available, however KVM
+has special logic if support is really enabled for a guest. If support
+is disabled, guest_fpregs.fregs will only contain memory for the fpu.
+The kernel, however, will store vector registers into that area,
+resulting in crazy memory overwrites.
+
+Simply extending that area is not enough, because the format of the
+registers also changes. We would have to do additional conversions, making
+the code even more complex. Therefore let's directly use one place for
+the vector/fpu registers + fpc (in kvm_run). We just have to convert the
+data properly when accessing it. This makes current code much easier.
+
+Please note that vector/fpu registers are now always stored to
+vcpu->run->s.regs.vrs. Although this data is visible to QEMU and
+used for migration, we only guarantee valid values to user space when
+KVM_SYNC_VRS is set. As that is only the case when we have vector
+register support, we are on the safe side.
+
+Fixes: b5510d9b68c3 ("s390/fpu: always enable the vector facility if it is available")
+Cc: stable@vger.kernel.org # v4.4 d9a3a09af54d s390/kvm: remove dependency on struct save_area definition
+Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
+Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
+[adopt to d9a3a09af54d]
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/include/asm/kvm_host.h | 1
+ arch/s390/kvm/kvm-s390.c | 128 +++++++++++++--------------------------
+ 2 files changed, 43 insertions(+), 86 deletions(-)
+
+--- a/arch/s390/include/asm/kvm_host.h
++++ b/arch/s390/include/asm/kvm_host.h
+@@ -506,7 +506,6 @@ struct kvm_vcpu_arch {
+ struct kvm_s390_sie_block *sie_block;
+ unsigned int host_acrs[NUM_ACRS];
+ struct fpu host_fpregs;
+- struct fpu guest_fpregs;
+ struct kvm_s390_local_interrupt local_int;
+ struct hrtimer ckc_timer;
+ struct kvm_s390_pgm_info pgm;
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -1202,7 +1202,6 @@ void kvm_arch_vcpu_destroy(struct kvm_vc
+
+ if (vcpu->kvm->arch.use_cmma)
+ kvm_s390_vcpu_unsetup_cmma(vcpu);
+- kfree(vcpu->arch.guest_fpregs.fprs);
+ free_page((unsigned long)(vcpu->arch.sie_block));
+
+ kvm_vcpu_uninit(vcpu);
+@@ -1269,44 +1268,18 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *
+ return 0;
+ }
+
+-/*
+- * Backs up the current FP/VX register save area on a particular
+- * destination. Used to switch between different register save
+- * areas.
+- */
+-static inline void save_fpu_to(struct fpu *dst)
+-{
+- dst->fpc = current->thread.fpu.fpc;
+- dst->regs = current->thread.fpu.regs;
+-}
+-
+-/*
+- * Switches the FP/VX register save area from which to lazy
+- * restore register contents.
+- */
+-static inline void load_fpu_from(struct fpu *from)
+-{
+- current->thread.fpu.fpc = from->fpc;
+- current->thread.fpu.regs = from->regs;
+-}
+-
+ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+ {
+ /* Save host register state */
+ save_fpu_regs();
+- save_fpu_to(&vcpu->arch.host_fpregs);
+-
+- if (test_kvm_facility(vcpu->kvm, 129)) {
+- current->thread.fpu.fpc = vcpu->run->s.regs.fpc;
+- /*
+- * Use the register save area in the SIE-control block
+- * for register restore and save in kvm_arch_vcpu_put()
+- */
+- current->thread.fpu.vxrs =
+- (__vector128 *)&vcpu->run->s.regs.vrs;
+- } else
+- load_fpu_from(&vcpu->arch.guest_fpregs);
++ vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc;
++ vcpu->arch.host_fpregs.regs = current->thread.fpu.regs;
+
++ /* Depending on MACHINE_HAS_VX, data stored to vrs either
++ * has vector register or floating point register format.
++ */
++ current->thread.fpu.regs = vcpu->run->s.regs.vrs;
++ current->thread.fpu.fpc = vcpu->run->s.regs.fpc;
+ if (test_fp_ctl(current->thread.fpu.fpc))
+ /* User space provided an invalid FPC, let's clear it */
+ current->thread.fpu.fpc = 0;
+@@ -1322,19 +1295,13 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *
+ atomic_andnot(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
+ gmap_disable(vcpu->arch.gmap);
+
++ /* Save guest register state */
+ save_fpu_regs();
++ vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
+
+- if (test_kvm_facility(vcpu->kvm, 129))
+- /*
+- * kvm_arch_vcpu_load() set up the register save area to
+- * the &vcpu->run->s.regs.vrs and, thus, the vector registers
+- * are already saved. Only the floating-point control must be
+- * copied.
+- */
+- vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
+- else
+- save_fpu_to(&vcpu->arch.guest_fpregs);
+- load_fpu_from(&vcpu->arch.host_fpregs);
++ /* Restore host register state */
++ current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc;
++ current->thread.fpu.regs = vcpu->arch.host_fpregs.regs;
+
+ save_access_regs(vcpu->run->s.regs.acrs);
+ restore_access_regs(vcpu->arch.host_acrs);
+@@ -1352,8 +1319,9 @@ static void kvm_s390_vcpu_initial_reset(
+ memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
+ vcpu->arch.sie_block->gcr[0] = 0xE0UL;
+ vcpu->arch.sie_block->gcr[14] = 0xC2000000UL;
+- vcpu->arch.guest_fpregs.fpc = 0;
+- asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
++ /* make sure the new fpc will be lazily loaded */
++ save_fpu_regs();
++ current->thread.fpu.fpc = 0;
+ vcpu->arch.sie_block->gbea = 1;
+ vcpu->arch.sie_block->pp = 0;
+ vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+@@ -1502,29 +1470,14 @@ struct kvm_vcpu *kvm_arch_vcpu_create(st
+ vcpu->arch.local_int.wq = &vcpu->wq;
+ vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
+
+- /*
+- * Allocate a save area for floating-point registers. If the vector
+- * extension is available, register contents are saved in the SIE
+- * control block. The allocated save area is still required in
+- * particular places, for example, in kvm_s390_vcpu_store_status().
+- */
+- vcpu->arch.guest_fpregs.fprs = kzalloc(sizeof(freg_t) * __NUM_FPRS,
+- GFP_KERNEL);
+- if (!vcpu->arch.guest_fpregs.fprs) {
+- rc = -ENOMEM;
+- goto out_free_sie_block;
+- }
+-
+ rc = kvm_vcpu_init(vcpu, kvm, id);
+ if (rc)
+- goto out_free_fprs;
++ goto out_free_sie_block;
+ VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
+ vcpu->arch.sie_block);
+ trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
+
+ return vcpu;
+-out_free_fprs:
+- kfree(vcpu->arch.guest_fpregs.fprs);
+ out_free_sie_block:
+ free_page((unsigned long)(vcpu->arch.sie_block));
+ out_free_cpu:
+@@ -1737,19 +1690,27 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct
+
+ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+ {
++ /* make sure the new values will be lazily loaded */
++ save_fpu_regs();
+ if (test_fp_ctl(fpu->fpc))
+ return -EINVAL;
+- memcpy(vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
+- vcpu->arch.guest_fpregs.fpc = fpu->fpc;
+- save_fpu_regs();
+- load_fpu_from(&vcpu->arch.guest_fpregs);
++ current->thread.fpu.fpc = fpu->fpc;
++ if (MACHINE_HAS_VX)
++ convert_fp_to_vx(current->thread.fpu.vxrs, (freg_t *)fpu->fprs);
++ else
++ memcpy(current->thread.fpu.fprs, &fpu->fprs, sizeof(fpu->fprs));
+ return 0;
+ }
+
+ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+ {
+- memcpy(&fpu->fprs, vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
+- fpu->fpc = vcpu->arch.guest_fpregs.fpc;
++ /* make sure we have the latest values */
++ save_fpu_regs();
++ if (MACHINE_HAS_VX)
++ convert_vx_to_fp((freg_t *)fpu->fprs, current->thread.fpu.vxrs);
++ else
++ memcpy(fpu->fprs, current->thread.fpu.fprs, sizeof(fpu->fprs));
++ fpu->fpc = current->thread.fpu.fpc;
+ return 0;
+ }
+
+@@ -2269,6 +2230,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_v
+ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa)
+ {
+ unsigned char archmode = 1;
++ freg_t fprs[NUM_FPRS];
+ unsigned int px;
+ u64 clkcomp;
+ int rc;
+@@ -2284,8 +2246,16 @@ int kvm_s390_store_status_unloaded(struc
+ gpa = px;
+ } else
+ gpa -= __LC_FPREGS_SAVE_AREA;
+- rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
+- vcpu->arch.guest_fpregs.fprs, 128);
++
++ /* manually convert vector registers if necessary */
++ if (MACHINE_HAS_VX) {
++ convert_vx_to_fp(fprs, current->thread.fpu.vxrs);
++ rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
++ fprs, 128);
++ } else {
++ rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
++ vcpu->run->s.regs.vrs, 128);
++ }
+ rc |= write_guest_abs(vcpu, gpa + __LC_GPREGS_SAVE_AREA,
+ vcpu->run->s.regs.gprs, 128);
+ rc |= write_guest_abs(vcpu, gpa + __LC_PSW_SAVE_AREA,
+@@ -2293,7 +2263,7 @@ int kvm_s390_store_status_unloaded(struc
+ rc |= write_guest_abs(vcpu, gpa + __LC_PREFIX_SAVE_AREA,
+ &px, 4);
+ rc |= write_guest_abs(vcpu, gpa + __LC_FP_CREG_SAVE_AREA,
+- &vcpu->arch.guest_fpregs.fpc, 4);
++ &vcpu->run->s.regs.fpc, 4);
+ rc |= write_guest_abs(vcpu, gpa + __LC_TOD_PROGREG_SAVE_AREA,
+ &vcpu->arch.sie_block->todpr, 4);
+ rc |= write_guest_abs(vcpu, gpa + __LC_CPU_TIMER_SAVE_AREA,
+@@ -2316,19 +2286,7 @@ int kvm_s390_vcpu_store_status(struct kv
+ * it into the save area
+ */
+ save_fpu_regs();
+- if (test_kvm_facility(vcpu->kvm, 129)) {
+- /*
+- * If the vector extension is available, the vector registers
+- * which overlaps with floating-point registers are saved in
+- * the SIE-control block. Hence, extract the floating-point
+- * registers and the FPC value and store them in the
+- * guest_fpregs structure.
+- */
+- vcpu->arch.guest_fpregs.fpc = current->thread.fpu.fpc;
+- convert_vx_to_fp(vcpu->arch.guest_fpregs.fprs,
+- current->thread.fpu.vxrs);
+- } else
+- save_fpu_to(&vcpu->arch.guest_fpregs);
++ vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
+ save_access_regs(vcpu->run->s.regs.acrs);
+
+ return kvm_s390_store_status_unloaded(vcpu, addr);
--- /dev/null
+From d9a3a09af54d01ab8b0c320580f4f95328d4a7ac Mon Sep 17 00:00:00 2001
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Fri, 23 Oct 2015 09:02:32 +0200
+Subject: s390/kvm: remove dependency on struct save_area definition
+
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+
+commit d9a3a09af54d01ab8b0c320580f4f95328d4a7ac upstream.
+
+Replace the offsets based on the struct area_area with the offset
+constants from asm-offsets.c based on the struct _lowcore.
+
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/s390/kernel/asm-offsets.c | 1 +
+ arch/s390/kvm/kvm-s390.c | 30 +++++++++++++++---------------
+ 2 files changed, 16 insertions(+), 15 deletions(-)
+
+--- a/arch/s390/kernel/asm-offsets.c
++++ b/arch/s390/kernel/asm-offsets.c
+@@ -181,6 +181,7 @@ int main(void)
+ OFFSET(__LC_PSW_SAVE_AREA, _lowcore, psw_save_area);
+ OFFSET(__LC_PREFIX_SAVE_AREA, _lowcore, prefixreg_save_area);
+ OFFSET(__LC_FP_CREG_SAVE_AREA, _lowcore, fpt_creg_save_area);
++ OFFSET(__LC_TOD_PROGREG_SAVE_AREA, _lowcore, tod_progreg_save_area);
+ OFFSET(__LC_CPU_TIMER_SAVE_AREA, _lowcore, cpu_timer_save_area);
+ OFFSET(__LC_CLOCK_COMP_SAVE_AREA, _lowcore, clock_comp_save_area);
+ OFFSET(__LC_AREGS_SAVE_AREA, _lowcore, access_regs_save_area);
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -2273,37 +2273,37 @@ int kvm_s390_store_status_unloaded(struc
+ u64 clkcomp;
+ int rc;
+
++ px = kvm_s390_get_prefix(vcpu);
+ if (gpa == KVM_S390_STORE_STATUS_NOADDR) {
+ if (write_guest_abs(vcpu, 163, &archmode, 1))
+ return -EFAULT;
+- gpa = SAVE_AREA_BASE;
++ gpa = 0;
+ } else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) {
+ if (write_guest_real(vcpu, 163, &archmode, 1))
+ return -EFAULT;
+- gpa = kvm_s390_real_to_abs(vcpu, SAVE_AREA_BASE);
+- }
+- rc = write_guest_abs(vcpu, gpa + offsetof(struct save_area, fp_regs),
++ gpa = px;
++ } else
++ gpa -= __LC_FPREGS_SAVE_AREA;
++ rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
+ vcpu->arch.guest_fpregs.fprs, 128);
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, gp_regs),
++ rc |= write_guest_abs(vcpu, gpa + __LC_GPREGS_SAVE_AREA,
+ vcpu->run->s.regs.gprs, 128);
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, psw),
++ rc |= write_guest_abs(vcpu, gpa + __LC_PSW_SAVE_AREA,
+ &vcpu->arch.sie_block->gpsw, 16);
+- px = kvm_s390_get_prefix(vcpu);
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, pref_reg),
++ rc |= write_guest_abs(vcpu, gpa + __LC_PREFIX_SAVE_AREA,
+ &px, 4);
+- rc |= write_guest_abs(vcpu,
+- gpa + offsetof(struct save_area, fp_ctrl_reg),
++ rc |= write_guest_abs(vcpu, gpa + __LC_FP_CREG_SAVE_AREA,
+ &vcpu->arch.guest_fpregs.fpc, 4);
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, tod_reg),
++ rc |= write_guest_abs(vcpu, gpa + __LC_TOD_PROGREG_SAVE_AREA,
+ &vcpu->arch.sie_block->todpr, 4);
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, timer),
++ rc |= write_guest_abs(vcpu, gpa + __LC_CPU_TIMER_SAVE_AREA,
+ &vcpu->arch.sie_block->cputm, 8);
+ clkcomp = vcpu->arch.sie_block->ckc >> 8;
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, clk_cmp),
++ rc |= write_guest_abs(vcpu, gpa + __LC_CLOCK_COMP_SAVE_AREA,
+ &clkcomp, 8);
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, acc_regs),
++ rc |= write_guest_abs(vcpu, gpa + __LC_AREGS_SAVE_AREA,
+ &vcpu->run->s.regs.acrs, 64);
+- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, ctrl_regs),
++ rc |= write_guest_abs(vcpu, gpa + __LC_CREGS_SAVE_AREA,
+ &vcpu->arch.sie_block->gcr, 128);
+ return rc ? -EFAULT : 0;
+ }