xref: /linux/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h (revision 0ff05136bb0e9b71847eb3a6ea33e512000eb875)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Guest PC manipulation helpers
4  *
5  * Copyright (C) 2012,2013 - ARM Ltd
6  * Copyright (C) 2020 - Google LLC
7  * Author: Marc Zyngier <maz@kernel.org>
8  */
9 
10 #ifndef __ARM64_KVM_HYP_ADJUST_PC_H__
11 #define __ARM64_KVM_HYP_ADJUST_PC_H__
12 
13 #include <asm/kvm_emulate.h>
14 #include <asm/kvm_host.h>
15 
16 #ifdef __KVM_NVHE_HYPERVISOR__
17 #include <nvhe/pkvm.h>
18 
19 /* Under pKVM a host vCPU's ->kvm is host-writable. */
20 static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu)
21 {
22 	if (is_protected_kvm_enabled())
23 		return pkvm_vcpu_get_kvm(vcpu);
24 
25 	return kern_hyp_va(vcpu->kvm);
26 }
27 
28 static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm)
29 {
30 	if (is_protected_kvm_enabled())
31 		pkvm_vcpu_put_kvm(vcpu, kvm);
32 }
33 #else
34 static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu)
35 {
36 	return vcpu->kvm;
37 }
38 
39 static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm)
40 {
41 }
42 #endif
43 
44 static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)
45 {
46 	if (vcpu_mode_is_32bit(vcpu)) {
47 		kvm_skip_instr32(vcpu);
48 	} else {
49 		*vcpu_pc(vcpu) += 4;
50 		*vcpu_cpsr(vcpu) &= ~PSR_BTYPE_MASK;
51 	}
52 
53 	/* advance the singlestep state machine */
54 	*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
55 }
56 
57 /*
58  * Skip an instruction which has been emulated at hyp while most guest sysregs
59  * are live.
60  */
61 static inline void __kvm_skip_instr(struct kvm_vcpu *vcpu)
62 {
63 	*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
64 	*vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR);
65 
66 	kvm_skip_instr(vcpu);
67 
68 	write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
69 	write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
70 }
71 
72 /*
73  * Skip an instruction while host sysregs are live.
74  * Assumes host is always 64-bit.
75  */
76 static inline void kvm_skip_host_instr(void)
77 {
78 	write_sysreg_el2(read_sysreg_el2(SYS_ELR) + 4, SYS_ELR);
79 }
80 
81 /*
82  * Under pKVM, the vCPU __kvm_adjust_pc() adjusts for @vcpu (NULL leaves the
83  * request on @vcpu for its next entry), and the copy of the consumed
84  * PC_UPDATE_REQ back to @vcpu.
85  */
86 #ifdef __KVM_NVHE_HYPERVISOR__
87 struct kvm_vcpu *kvm_adjust_pc_get(struct kvm_vcpu *vcpu);
88 void kvm_adjust_pc_put(struct kvm_vcpu *vcpu, struct kvm_vcpu *target);
89 #else
90 static inline struct kvm_vcpu *kvm_adjust_pc_get(struct kvm_vcpu *vcpu)
91 {
92 	return vcpu;
93 }
94 
95 static inline void kvm_adjust_pc_put(struct kvm_vcpu *vcpu,
96 				     struct kvm_vcpu *target)
97 {
98 }
99 #endif
100 
101 #endif
102