| From 25edcc50d76c834479d11fcc7de46f3da4d95121 Mon Sep 17 00:00:00 2001 |
| From: Fabiano Rosas <farosas@linux.ibm.com> |
| Date: Thu, 4 Feb 2021 17:05:17 -0300 |
| Subject: KVM: PPC: Book3S HV: Save and restore FSCR in the P9 path |
| |
| From: Fabiano Rosas <farosas@linux.ibm.com> |
| |
| commit 25edcc50d76c834479d11fcc7de46f3da4d95121 upstream. |
| |
| The Facility Status and Control Register is a privileged SPR that |
| defines the availability of some features in problem state. Since it |
| can be written by the guest, we must restore it to the previous host |
| value after guest exit. |
| |
| This restoration is currently done by taking the value from |
| current->thread.fscr, which in the P9 path is not enough anymore |
| because the guest could context switch the QEMU thread, causing the |
| guest-current value to be saved into the thread struct. |
| |
| The above situation manifested when running a QEMU linked against a |
| libc with System Call Vectored support, which causes scv |
| instructions to be run by QEMU early during the guest boot (during |
| SLOF), at which point the FSCR is 0 due to guest entry. After a few |
| scv calls (1 to a couple hundred), the context switching happens and |
| the QEMU thread runs with the guest value, resulting in a Facility |
| Unavailable interrupt. |
| |
| This patch saves and restores the host value of FSCR in the inner |
| guest entry loop in a way independent of current->thread.fscr. The old |
| way of doing it is still kept in place because it works for the old |
| entry path. |
| |
| Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com> |
| Signed-off-by: Paul Mackerras <paulus@ozlabs.org> |
| Cc: Georgy Yakovlev <gyakovlev@gentoo.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/kvm/book3s_hv.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/arch/powerpc/kvm/book3s_hv.c |
| +++ b/arch/powerpc/kvm/book3s_hv.c |
| @@ -3583,6 +3583,7 @@ static int kvmhv_p9_guest_entry(struct k |
| unsigned long host_tidr = mfspr(SPRN_TIDR); |
| unsigned long host_iamr = mfspr(SPRN_IAMR); |
| unsigned long host_amr = mfspr(SPRN_AMR); |
| + unsigned long host_fscr = mfspr(SPRN_FSCR); |
| s64 dec; |
| u64 tb; |
| int trap, save_pmu; |
| @@ -3726,6 +3727,9 @@ static int kvmhv_p9_guest_entry(struct k |
| if (host_amr != vcpu->arch.amr) |
| mtspr(SPRN_AMR, host_amr); |
| |
| + if (host_fscr != vcpu->arch.fscr) |
| + mtspr(SPRN_FSCR, host_fscr); |
| + |
| msr_check_and_set(MSR_FP | MSR_VEC | MSR_VSX); |
| store_fp_state(&vcpu->arch.fp); |
| #ifdef CONFIG_ALTIVEC |