Commit 85acda3b4a27ee3e20c54783a44f307b51912c2b
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) {} |
arch/arm64/Kconfig
... | ... | @@ -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
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 |
virt/kvm/arm/arm.c
... | ... | @@ -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 |