Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: KVM: VHE: Implement VHE activate/deactivate_traps

Running the kernel in HYP mode requires the HCR_E2H bit to be set
at all times, and the HCR_TGE bit to be set when running as a host
(and cleared when running as a guest). At the same time, the vector
must be set to the current role of the kernel (either host or
hypervisor), and a couple of system registers differ between VHE
and non-VHE.

We implement these by using another set of alternate functions
that get dynamically patched.

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+53 -8
+2 -1
arch/arm64/include/asm/kvm_arm.h
··· 23 23 #include <asm/types.h> 24 24 25 25 /* Hyp Configuration Register (HCR) bits */ 26 + #define HCR_E2H (UL(1) << 34) 26 27 #define HCR_ID (UL(1) << 33) 27 28 #define HCR_CD (UL(1) << 32) 28 29 #define HCR_RW_SHIFT 31 ··· 82 81 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW) 83 82 #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) 84 83 #define HCR_INT_OVERRIDE (HCR_FMO | HCR_IMO) 85 - 84 + #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) 86 85 87 86 /* Hyp System Control Register (SCTLR_EL2) bits */ 88 87 #define SCTLR_EL2_EE (1 << 25)
+3
arch/arm64/include/asm/kvm_emulate.h
··· 29 29 #include <asm/kvm_mmio.h> 30 30 #include <asm/ptrace.h> 31 31 #include <asm/cputype.h> 32 + #include <asm/virt.h> 32 33 33 34 unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num); 34 35 unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu); ··· 44 43 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) 45 44 { 46 45 vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS; 46 + if (is_kernel_in_hyp_mode()) 47 + vcpu->arch.hcr_el2 |= HCR_E2H; 47 48 if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) 48 49 vcpu->arch.hcr_el2 &= ~HCR_RW; 49 50 }
+48 -7
arch/arm64/kvm/hyp/switch.c
··· 15 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 18 + #include <asm/kvm_asm.h> 19 + 18 20 #include "hyp.h" 19 21 20 22 static bool __hyp_text __fpsimd_enabled_nvhe(void) ··· 38 36 return __fpsimd_is_enabled()(); 39 37 } 40 38 39 + static void __hyp_text __activate_traps_vhe(void) 40 + { 41 + u64 val; 42 + 43 + val = read_sysreg(cpacr_el1); 44 + val |= CPACR_EL1_TTA; 45 + val &= ~CPACR_EL1_FPEN; 46 + write_sysreg(val, cpacr_el1); 47 + 48 + write_sysreg(__kvm_hyp_vector, vbar_el1); 49 + } 50 + 51 + static void __hyp_text __activate_traps_nvhe(void) 52 + { 53 + u64 val; 54 + 55 + val = CPTR_EL2_DEFAULT; 56 + val |= CPTR_EL2_TTA | CPTR_EL2_TFP; 57 + write_sysreg(val, cptr_el2); 58 + } 59 + 60 + static hyp_alternate_select(__activate_traps_arch, 61 + __activate_traps_nvhe, __activate_traps_vhe, 62 + ARM64_HAS_VIRT_HOST_EXTN); 63 + 41 64 static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu) 42 65 { 43 66 u64 val; ··· 82 55 write_sysreg(val, hcr_el2); 83 56 /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */ 84 57 write_sysreg(1 << 15, hstr_el2); 85 - 86 - val = CPTR_EL2_DEFAULT; 87 - val |= CPTR_EL2_TTA | CPTR_EL2_TFP; 88 - write_sysreg(val, cptr_el2); 89 - 90 58 write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2); 59 + __activate_traps_arch()(); 91 60 } 61 + 62 + static void __hyp_text __deactivate_traps_vhe(void) 63 + { 64 + extern char vectors[]; /* kernel exception vectors */ 65 + 66 + write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2); 67 + write_sysreg(CPACR_EL1_FPEN, cpacr_el1); 68 + write_sysreg(vectors, vbar_el1); 69 + } 70 + 71 + static void __hyp_text __deactivate_traps_nvhe(void) 72 + { 73 + write_sysreg(HCR_RW, hcr_el2); 74 + write_sysreg(CPTR_EL2_DEFAULT, cptr_el2); 75 + } 76 + 77 + static hyp_alternate_select(__deactivate_traps_arch, 78 + __deactivate_traps_nvhe, __deactivate_traps_vhe, 79 + ARM64_HAS_VIRT_HOST_EXTN); 92 80 93 81 static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu) 94 82 { 95 - write_sysreg(HCR_RW, hcr_el2); 83 + __deactivate_traps_arch()(); 96 84 write_sysreg(0, hstr_el2); 97 85 write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2); 98 - write_sysreg(CPTR_EL2_DEFAULT, cptr_el2); 99 86 } 100 87 101 88 static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)