[PATCH 4.4 11/91] KVM: PPC: Book3S HV: Reload HTM registers explicitly

From: Greg Kroah-Hartman
Date: Fri Aug 04 2017 - 20:01:21 EST

4.4-stable review patch. If anyone has any objections, please let me know.


From: Paul Mackerras <paulus@xxxxxxxxxx>

Commit 46a704f8409f ("KVM: PPC: Book3S HV: Preserve userspace HTM
state properly", 2017-06-15) added code which assumes that the kernel
is able to handle a TM (transactional memory) unavailable interrupt
from userspace by reloading the TM-related registers and enabling TM
for the process. That ability was added in the 4.9 kernel; earlier
kernel versions simply panic on getting the TM unavailable interrupt.

Since commit 46a704f8409f has been backported to the 4.4 stable tree
as commit 824b9506e4f2, 4.4.75 and subsequent versions are vulnerable
to a userspace-triggerable panic.

This patch fixes the problem by explicitly reloading the TM-related
registers before returning to userspace, rather than disabling TM
for the process.

Commit 46a704f8409f also failed to enable TM for the kernel, leading
to a TM unavailable interrupt in the kernel, causing an oops. This
fixes that problem too, by enabling TM before accessing the TM
registers. That problem is fixed upstream by the patch "KVM: PPC:
Book3S HV: Enable TM before accessing TM registers".

Fixes: 824b9506e4f2 ("KVM: PPC: Book3S HV: Preserve userspace HTM state properly")
Signed-off-by: Paul Mackerras <paulus@xxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
arch/powerpc/kvm/book3s_hv.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2711,10 +2711,11 @@ static int kvmppc_vcpu_run_hv(struct kvm
run->fail_entry.hardware_entry_failure_reason = 0;
return -EINVAL;
+ /* Enable TM so we can read the TM SPRs */
+ mtmsr(mfmsr() | MSR_TM);
current->thread.tm_tfhar = mfspr(SPRN_TFHAR);
current->thread.tm_tfiar = mfspr(SPRN_TFIAR);
current->thread.tm_texasr = mfspr(SPRN_TEXASR);
- current->thread.regs->msr &= ~MSR_TM;

@@ -2782,6 +2783,19 @@ static int kvmppc_vcpu_run_hv(struct kvm
mtspr(SPRN_VRSAVE, user_vrsave);

+ /*
+ * Since we don't do lazy TM reload, we need to reload
+ * the TM registers here.
+ */
+ if (cpu_has_feature(CPU_FTR_TM) && current->thread.regs &&
+ (current->thread.regs->msr & MSR_TM)) {
+ mtspr(SPRN_TFHAR, current->thread.tm_tfhar);
+ mtspr(SPRN_TFIAR, current->thread.tm_tfiar);
+ mtspr(SPRN_TEXASR, current->thread.tm_texasr);
+ }
vcpu->arch.state = KVMPPC_VCPU_NOTREADY;