Commit 85acda3b4a27ee3e20c54783a44f307b51912c2b

Authored by Dave Martin
Committed by Marc Zyngier
1 parent 9a6e594869

KVM: arm64: Save host SVE context as appropriate

This patch adds SVE context saving to the hyp FPSIMD context switch
path.  This means that it is no longer necessary to save the host
SVE state in advance of entering the guest, when in use.

In order to avoid adding pointless complexity to the code, VHE is
assumed if SVE is in use.  VHE is an architectural prerequisite for
SVE, so there is no good reason to turn CONFIG_ARM64_VHE off in
kernels that support both SVE and KVM.

Historically, software models exist that can expose the
architecturally invalid configuration of SVE without VHE, so if
this situation is detected at kvm_init() time then KVM will be
disabled.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Showing 6 changed files with 47 additions and 2 deletions Side-by-side Diff

arch/arm/include/asm/kvm_host.h
... ... @@ -280,6 +280,7 @@
280 280  
281 281 struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
282 282  
  283 +static inline bool kvm_arch_check_sve_has_vhe(void) { return true; }
283 284 static inline void kvm_arch_hardware_unsetup(void) {}
284 285 static inline void kvm_arch_sync_events(struct kvm *kvm) {}
285 286 static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
... ... @@ -1130,6 +1130,7 @@
1130 1130 config ARM64_SVE
1131 1131 bool "ARM Scalable Vector Extension support"
1132 1132 default y
  1133 + depends on !KVM || ARM64_VHE
1133 1134 help
1134 1135 The Scalable Vector Extension (SVE) is an extension to the AArch64
1135 1136 execution state which complements and extends the SIMD functionality
... ... @@ -1154,6 +1155,12 @@
1154 1155 fixed. Otherwise, you may experience firmware panics or lockups when
1155 1156 booting the kernel. If unsure and you are not observing these
1156 1157 symptoms, you should assume that it is safe to say Y.
  1158 +
  1159 + CPUs that support SVE are architecturally required to support the
  1160 + Virtualization Host Extensions (VHE), so the kernel makes no
  1161 + provision for supporting SVE alongside KVM without VHE enabled.
  1162 + Thus, you will need to enable CONFIG_ARM64_VHE if you want to support
  1163 + KVM in the same kernel image.
1157 1164  
1158 1165 config ARM64_MODULE_PLTS
1159 1166 bool
arch/arm64/include/asm/kvm_host.h
... ... @@ -405,6 +405,19 @@
405 405 kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
406 406 }
407 407  
  408 +static inline bool kvm_arch_check_sve_has_vhe(void)
  409 +{
  410 + /*
  411 + * The Arm architecture specifies that implementation of SVE
  412 + * requires VHE also to be implemented. The KVM code for arm64
  413 + * relies on this when SVE is present:
  414 + */
  415 + if (system_supports_sve())
  416 + return has_vhe();
  417 + else
  418 + return true;
  419 +}
  420 +
408 421 static inline void kvm_arch_hardware_unsetup(void) {}
409 422 static inline void kvm_arch_sync_events(struct kvm *kvm) {}
410 423 static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
arch/arm64/kvm/fpsimd.c
... ... @@ -59,7 +59,6 @@
59 59 */
60 60 void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
61 61 {
62   - BUG_ON(system_supports_sve());
63 62 BUG_ON(!current->mm);
64 63  
65 64 vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | KVM_ARM64_HOST_SVE_IN_USE);
arch/arm64/kvm/hyp/switch.c
... ... @@ -21,6 +21,7 @@
21 21  
22 22 #include <kvm/arm_psci.h>
23 23  
  24 +#include <asm/cpufeature.h>
24 25 #include <asm/kvm_asm.h>
25 26 #include <asm/kvm_emulate.h>
26 27 #include <asm/kvm_host.h>
... ... @@ -28,6 +29,7 @@
28 29 #include <asm/kvm_mmu.h>
29 30 #include <asm/fpsimd.h>
30 31 #include <asm/debug-monitors.h>
  32 +#include <asm/processor.h>
31 33 #include <asm/thread_info.h>
32 34  
33 35 /* Check whether the FP regs were dirtied while in the host-side run loop: */
... ... @@ -329,6 +331,8 @@
329 331 void __hyp_text __hyp_switch_fpsimd(u64 esr __always_unused,
330 332 struct kvm_vcpu *vcpu)
331 333 {
  334 + struct user_fpsimd_state *host_fpsimd = vcpu->arch.host_fpsimd_state;
  335 +
332 336 if (has_vhe())
333 337 write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
334 338 cpacr_el1);
... ... @@ -339,7 +343,21 @@
339 343 isb();
340 344  
341 345 if (vcpu->arch.flags & KVM_ARM64_FP_HOST) {
342   - __fpsimd_save_state(vcpu->arch.host_fpsimd_state);
  346 + /*
  347 + * In the SVE case, VHE is assumed: it is enforced by
  348 + * Kconfig and kvm_arch_init().
  349 + */
  350 + if (system_supports_sve() &&
  351 + (vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE)) {
  352 + struct thread_struct *thread = container_of(
  353 + host_fpsimd,
  354 + struct thread_struct, uw.fpsimd_state);
  355 +
  356 + sve_save_state(sve_pffr(thread), &host_fpsimd->fpsr);
  357 + } else {
  358 + __fpsimd_save_state(host_fpsimd);
  359 + }
  360 +
343 361 vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
344 362 }
345 363  
... ... @@ -16,6 +16,7 @@
16 16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17 */
18 18  
  19 +#include <linux/bug.h>
19 20 #include <linux/cpu_pm.h>
20 21 #include <linux/errno.h>
21 22 #include <linux/err.h>
... ... @@ -41,6 +42,7 @@
41 42 #include <asm/mman.h>
42 43 #include <asm/tlbflush.h>
43 44 #include <asm/cacheflush.h>
  45 +#include <asm/cpufeature.h>
44 46 #include <asm/virt.h>
45 47 #include <asm/kvm_arm.h>
46 48 #include <asm/kvm_asm.h>
... ... @@ -1571,6 +1573,11 @@
1571 1573  
1572 1574 if (!is_hyp_mode_available()) {
1573 1575 kvm_info("HYP mode not available\n");
  1576 + return -ENODEV;
  1577 + }
  1578 +
  1579 + if (!kvm_arch_check_sve_has_vhe()) {
  1580 + kvm_pr_unimpl("SVE system without VHE unsupported. Broken cpu?");
1574 1581 return -ENODEV;
1575 1582 }
1576 1583