xref: /openbmc/linux/arch/arm64/include/asm/kvm_hyp.h (revision fdec2a9ef853172529baaa192673b4cdb9a44fac)
1caab277bSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
213720a56SMarc Zyngier /*
313720a56SMarc Zyngier  * Copyright (C) 2015 - ARM Ltd
413720a56SMarc Zyngier  * Author: Marc Zyngier <marc.zyngier@arm.com>
513720a56SMarc Zyngier  */
613720a56SMarc Zyngier 
713720a56SMarc Zyngier #ifndef __ARM64_KVM_HYP_H__
813720a56SMarc Zyngier #define __ARM64_KVM_HYP_H__
913720a56SMarc Zyngier 
1013720a56SMarc Zyngier #include <linux/compiler.h>
1113720a56SMarc Zyngier #include <linux/kvm_host.h>
121e4448c5SMarc Zyngier #include <asm/alternative.h>
13e329fb75SChristoffer Dall #include <asm/kvm_mmu.h>
1413720a56SMarc Zyngier #include <asm/sysreg.h>
1513720a56SMarc Zyngier 
1613720a56SMarc Zyngier #define __hyp_text __section(.hyp.text) notrace
1713720a56SMarc Zyngier 
1813720a56SMarc Zyngier #define read_sysreg_elx(r,nvh,vh)					\
1913720a56SMarc Zyngier 	({								\
2013720a56SMarc Zyngier 		u64 reg;						\
21*fdec2a9eSDave Martin 		asm volatile(ALTERNATIVE(__mrs_s("%0", r##nvh),	\
22be604c61SKees Cook 					 __mrs_s("%0", r##vh),		\
2313720a56SMarc Zyngier 					 ARM64_HAS_VIRT_HOST_EXTN)	\
2413720a56SMarc Zyngier 			     : "=r" (reg));				\
2513720a56SMarc Zyngier 		reg;							\
2613720a56SMarc Zyngier 	})
2713720a56SMarc Zyngier 
2813720a56SMarc Zyngier #define write_sysreg_elx(v,r,nvh,vh)					\
2913720a56SMarc Zyngier 	do {								\
3013720a56SMarc Zyngier 		u64 __val = (u64)(v);					\
31*fdec2a9eSDave Martin 		asm volatile(ALTERNATIVE(__msr_s(r##nvh, "%x0"),	\
32be604c61SKees Cook 					 __msr_s(r##vh, "%x0"),		\
3313720a56SMarc Zyngier 					 ARM64_HAS_VIRT_HOST_EXTN)	\
3413720a56SMarc Zyngier 					 : : "rZ" (__val));		\
3513720a56SMarc Zyngier 	} while (0)
3613720a56SMarc Zyngier 
3713720a56SMarc Zyngier /*
3813720a56SMarc Zyngier  * Unified accessors for registers that have a different encoding
3913720a56SMarc Zyngier  * between VHE and non-VHE. They must be specified without their "ELx"
40*fdec2a9eSDave Martin  * encoding, but with the SYS_ prefix, as defined in asm/sysreg.h.
4113720a56SMarc Zyngier  */
4213720a56SMarc Zyngier 
4313720a56SMarc Zyngier #define read_sysreg_el0(r)	read_sysreg_elx(r, _EL0, _EL02)
4413720a56SMarc Zyngier #define write_sysreg_el0(v,r)	write_sysreg_elx(v, r, _EL0, _EL02)
4513720a56SMarc Zyngier #define read_sysreg_el1(r)	read_sysreg_elx(r, _EL1, _EL12)
4613720a56SMarc Zyngier #define write_sysreg_el1(v,r)	write_sysreg_elx(v, r, _EL1, _EL12)
47*fdec2a9eSDave Martin #define read_sysreg_el2(r)	read_sysreg_elx(r, _EL2, _EL1)
48*fdec2a9eSDave Martin #define write_sysreg_el2(v,r)	write_sysreg_elx(v, r, _EL2, _EL1)
4913720a56SMarc Zyngier 
5013720a56SMarc Zyngier /**
5113720a56SMarc Zyngier  * hyp_alternate_select - Generates patchable code sequences that are
5213720a56SMarc Zyngier  * used to switch between two implementations of a function, depending
5313720a56SMarc Zyngier  * on the availability of a feature.
5413720a56SMarc Zyngier  *
5513720a56SMarc Zyngier  * @fname: a symbol name that will be defined as a function returning a
5613720a56SMarc Zyngier  * function pointer whose type will match @orig and @alt
5713720a56SMarc Zyngier  * @orig: A pointer to the default function, as returned by @fname when
5813720a56SMarc Zyngier  * @cond doesn't hold
5913720a56SMarc Zyngier  * @alt: A pointer to the alternate function, as returned by @fname
6013720a56SMarc Zyngier  * when @cond holds
6113720a56SMarc Zyngier  * @cond: a CPU feature (as described in asm/cpufeature.h)
6213720a56SMarc Zyngier  */
6313720a56SMarc Zyngier #define hyp_alternate_select(fname, orig, alt, cond)			\
6413720a56SMarc Zyngier typeof(orig) * __hyp_text fname(void)					\
6513720a56SMarc Zyngier {									\
6613720a56SMarc Zyngier 	typeof(alt) *val = orig;					\
6713720a56SMarc Zyngier 	asm volatile(ALTERNATIVE("nop		\n",			\
6813720a56SMarc Zyngier 				 "mov	%0, %1	\n",			\
6913720a56SMarc Zyngier 				 cond)					\
7013720a56SMarc Zyngier 		     : "+r" (val) : "r" (alt));				\
7113720a56SMarc Zyngier 	return val;							\
7213720a56SMarc Zyngier }
7313720a56SMarc Zyngier 
743272f0d0SMarc Zyngier int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
7513720a56SMarc Zyngier 
7613720a56SMarc Zyngier void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
7713720a56SMarc Zyngier void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
782d0e63e0SChristoffer Dall void __vgic_v3_activate_traps(struct kvm_vcpu *vcpu);
792d0e63e0SChristoffer Dall void __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu);
80923a2e30SChristoffer Dall void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
81923a2e30SChristoffer Dall void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
8259da1cbfSMarc Zyngier int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
8313720a56SMarc Zyngier 
84688c50aaSChristoffer Dall void __timer_enable_traps(struct kvm_vcpu *vcpu);
85688c50aaSChristoffer Dall void __timer_disable_traps(struct kvm_vcpu *vcpu);
8613720a56SMarc Zyngier 
874cdecabaSChristoffer Dall void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt);
884cdecabaSChristoffer Dall void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt);
89f837453dSChristoffer Dall void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt);
90f837453dSChristoffer Dall void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt);
91f837453dSChristoffer Dall void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt);
92f837453dSChristoffer Dall void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt);
9313720a56SMarc Zyngier void __sysreg32_save_state(struct kvm_vcpu *vcpu);
9413720a56SMarc Zyngier void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
9513720a56SMarc Zyngier 
96014c4c77SChristoffer Dall void __debug_switch_to_guest(struct kvm_vcpu *vcpu);
97014c4c77SChristoffer Dall void __debug_switch_to_host(struct kvm_vcpu *vcpu);
9813720a56SMarc Zyngier 
9913720a56SMarc Zyngier void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
10013720a56SMarc Zyngier void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
10113720a56SMarc Zyngier 
102a2465629SChristoffer Dall void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
103a2465629SChristoffer Dall void deactivate_traps_vhe_put(void);
104a2465629SChristoffer Dall 
10513720a56SMarc Zyngier u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
10613720a56SMarc Zyngier void __noreturn __hyp_do_panic(unsigned long, ...);
10713720a56SMarc Zyngier 
1089f98ddd6SSuzuki K Poulose /*
1099f98ddd6SSuzuki K Poulose  * Must be called from hyp code running at EL2 with an updated VTTBR
1109f98ddd6SSuzuki K Poulose  * and interrupts disabled.
1119f98ddd6SSuzuki K Poulose  */
1129f98ddd6SSuzuki K Poulose static __always_inline void __hyp_text __load_guest_stage2(struct kvm *kvm)
1139f98ddd6SSuzuki K Poulose {
1147665f3a8SSuzuki K Poulose 	write_sysreg(kvm->arch.vtcr, vtcr_el2);
115e329fb75SChristoffer Dall 	write_sysreg(kvm_get_vttbr(kvm), vttbr_el2);
1161e4448c5SMarc Zyngier 
1171e4448c5SMarc Zyngier 	/*
1181e4448c5SMarc Zyngier 	 * ARM erratum 1165522 requires the actual execution of the above
1191e4448c5SMarc Zyngier 	 * before we can switch to the EL1/EL0 translation regime used by
1201e4448c5SMarc Zyngier 	 * the guest.
1211e4448c5SMarc Zyngier 	 */
1221e4448c5SMarc Zyngier 	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_1165522));
1239f98ddd6SSuzuki K Poulose }
1249f98ddd6SSuzuki K Poulose 
12513720a56SMarc Zyngier #endif /* __ARM64_KVM_HYP_H__ */
12613720a56SMarc Zyngier 
127