|
@@ -23,19 +23,21 @@
|
|
|
|
|
|
#include <asm/kvm_asm.h>
|
|
|
#include <asm/kvm_emulate.h>
|
|
|
+#include <asm/kvm_host.h>
|
|
|
#include <asm/kvm_hyp.h>
|
|
|
#include <asm/kvm_mmu.h>
|
|
|
#include <asm/fpsimd.h>
|
|
|
#include <asm/debug-monitors.h>
|
|
|
+#include <asm/thread_info.h>
|
|
|
|
|
|
-static bool __hyp_text __fpsimd_enabled_nvhe(void)
|
|
|
+/* Check whether the FP regs were dirtied while in the host-side run loop: */
|
|
|
+static bool __hyp_text update_fp_enabled(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
- return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
|
|
|
-}
|
|
|
+ if (vcpu->arch.host_thread_info->flags & _TIF_FOREIGN_FPSTATE)
|
|
|
+ vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED |
|
|
|
+ KVM_ARM64_FP_HOST);
|
|
|
|
|
|
-static bool fpsimd_enabled_vhe(void)
|
|
|
-{
|
|
|
- return !!(read_sysreg(cpacr_el1) & CPACR_EL1_FPEN);
|
|
|
+ return !!(vcpu->arch.flags & KVM_ARM64_FP_ENABLED);
|
|
|
}
|
|
|
|
|
|
/* Save the 32-bit only FPSIMD system register state */
|
|
@@ -92,7 +94,10 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
val = read_sysreg(cpacr_el1);
|
|
|
val |= CPACR_EL1_TTA;
|
|
|
- val &= ~(CPACR_EL1_FPEN | CPACR_EL1_ZEN);
|
|
|
+ val &= ~CPACR_EL1_ZEN;
|
|
|
+ if (!update_fp_enabled(vcpu))
|
|
|
+ val &= ~CPACR_EL1_FPEN;
|
|
|
+
|
|
|
write_sysreg(val, cpacr_el1);
|
|
|
|
|
|
write_sysreg(kvm_get_hyp_vector(), vbar_el1);
|
|
@@ -105,7 +110,10 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
|
|
|
__activate_traps_common(vcpu);
|
|
|
|
|
|
val = CPTR_EL2_DEFAULT;
|
|
|
- val |= CPTR_EL2_TTA | CPTR_EL2_TFP | CPTR_EL2_TZ;
|
|
|
+ val |= CPTR_EL2_TTA | CPTR_EL2_TZ;
|
|
|
+ if (!update_fp_enabled(vcpu))
|
|
|
+ val |= CPTR_EL2_TFP;
|
|
|
+
|
|
|
write_sysreg(val, cptr_el2);
|
|
|
}
|
|
|
|
|
@@ -321,8 +329,6 @@ static bool __hyp_text __skip_instr(struct kvm_vcpu *vcpu)
|
|
|
void __hyp_text __hyp_switch_fpsimd(u64 esr __always_unused,
|
|
|
struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
- kvm_cpu_context_t *host_ctxt;
|
|
|
-
|
|
|
if (has_vhe())
|
|
|
write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
|
|
|
cpacr_el1);
|
|
@@ -332,14 +338,19 @@ void __hyp_text __hyp_switch_fpsimd(u64 esr __always_unused,
|
|
|
|
|
|
isb();
|
|
|
|
|
|
- host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
|
|
|
- __fpsimd_save_state(&host_ctxt->gp_regs.fp_regs);
|
|
|
+ if (vcpu->arch.flags & KVM_ARM64_FP_HOST) {
|
|
|
+ __fpsimd_save_state(vcpu->arch.host_fpsimd_state);
|
|
|
+ vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
|
|
|
+ }
|
|
|
+
|
|
|
__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
|
|
|
|
|
|
/* Skip restoring fpexc32 for AArch64 guests */
|
|
|
if (!(read_sysreg(hcr_el2) & HCR_RW))
|
|
|
write_sysreg(vcpu->arch.ctxt.sys_regs[FPEXC32_EL2],
|
|
|
fpexc32_el2);
|
|
|
+
|
|
|
+ vcpu->arch.flags |= KVM_ARM64_FP_ENABLED;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -418,7 +429,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
struct kvm_cpu_context *host_ctxt;
|
|
|
struct kvm_cpu_context *guest_ctxt;
|
|
|
- bool fp_enabled;
|
|
|
u64 exit_code;
|
|
|
|
|
|
host_ctxt = vcpu->arch.host_cpu_context;
|
|
@@ -440,19 +450,14 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
|
|
|
/* And we're baaack! */
|
|
|
} while (fixup_guest_exit(vcpu, &exit_code));
|
|
|
|
|
|
- fp_enabled = fpsimd_enabled_vhe();
|
|
|
-
|
|
|
sysreg_save_guest_state_vhe(guest_ctxt);
|
|
|
|
|
|
__deactivate_traps(vcpu);
|
|
|
|
|
|
sysreg_restore_host_state_vhe(host_ctxt);
|
|
|
|
|
|
- if (fp_enabled) {
|
|
|
- __fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
|
|
|
- __fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
|
|
|
+ if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED)
|
|
|
__fpsimd_save_fpexc32(vcpu);
|
|
|
- }
|
|
|
|
|
|
__debug_switch_to_host(vcpu);
|
|
|
|
|
@@ -464,7 +469,6 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
struct kvm_cpu_context *host_ctxt;
|
|
|
struct kvm_cpu_context *guest_ctxt;
|
|
|
- bool fp_enabled;
|
|
|
u64 exit_code;
|
|
|
|
|
|
vcpu = kern_hyp_va(vcpu);
|
|
@@ -496,8 +500,6 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
|
|
|
/* And we're baaack! */
|
|
|
} while (fixup_guest_exit(vcpu, &exit_code));
|
|
|
|
|
|
- fp_enabled = __fpsimd_enabled_nvhe();
|
|
|
-
|
|
|
__sysreg_save_state_nvhe(guest_ctxt);
|
|
|
__sysreg32_save_state(vcpu);
|
|
|
__timer_disable_traps(vcpu);
|
|
@@ -508,11 +510,8 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
__sysreg_restore_state_nvhe(host_ctxt);
|
|
|
|
|
|
- if (fp_enabled) {
|
|
|
- __fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
|
|
|
- __fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
|
|
|
+ if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED)
|
|
|
__fpsimd_save_fpexc32(vcpu);
|
|
|
- }
|
|
|
|
|
|
/*
|
|
|
* This must come after restoring the host sysregs, since a non-VHE
|