]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Mar 2016 08:00:10 +0000 (00:00 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Mar 2016 08:00:10 +0000 (00:00 -0800)
added patches:
kvm-s390-fix-memory-overwrites-when-vx-is-disabled.patch
s390-kvm-remove-dependency-on-struct-save_area-definition.patch

queue-4.4/kvm-s390-fix-memory-overwrites-when-vx-is-disabled.patch [new file with mode: 0644]
queue-4.4/s390-kvm-remove-dependency-on-struct-save_area-definition.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/kvm-s390-fix-memory-overwrites-when-vx-is-disabled.patch b/queue-4.4/kvm-s390-fix-memory-overwrites-when-vx-is-disabled.patch
new file mode 100644 (file)
index 0000000..95b91de
--- /dev/null
@@ -0,0 +1,269 @@
+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);
diff --git a/queue-4.4/s390-kvm-remove-dependency-on-struct-save_area-definition.patch b/queue-4.4/s390-kvm-remove-dependency-on-struct-save_area-definition.patch
new file mode 100644 (file)
index 0000000..4ab151e
--- /dev/null
@@ -0,0 +1,85 @@
+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;
+ }
index 57b3ac8fa7963223a923b81eb5217f959ad636e1..de3edf4b7a9db704b17450903a18bbf4d35cc753 100644 (file)
@@ -82,3 +82,5 @@ mm-thp-fix-smp-race-condition-between-thp-page-fault-and-madv_dontneed.patch
 mm-numa-quickly-fail-allocations-for-numa-balancing-on-full-nodes.patch
 genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch
 clocksource-drivers-vt8500-increase-the-minimum-delta.patch
+s390-kvm-remove-dependency-on-struct-save_area-definition.patch
+kvm-s390-fix-memory-overwrites-when-vx-is-disabled.patch