1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2015 - ARM Ltd
4 * Author: Marc Zyngier <[email protected]>
5 */
6
7 #ifndef __ARM64_KVM_HYP_DEBUG_SR_H__
8 #define __ARM64_KVM_HYP_DEBUG_SR_H__
9
10 #include <linux/compiler.h>
11 #include <linux/kvm_host.h>
12
13 #include <asm/debug-monitors.h>
14 #include <asm/kvm_asm.h>
15 #include <asm/kvm_hyp.h>
16 #include <asm/kvm_mmu.h>
17
18 #define read_debug(r,n) read_sysreg(r##n##_el1)
19 #define write_debug(v,r,n) write_sysreg(v, r##n##_el1)
20
21 #define save_debug(ptr,reg,nr) \
22 switch (nr) { \
23 case 15: ptr[15] = read_debug(reg, 15); \
24 fallthrough; \
25 case 14: ptr[14] = read_debug(reg, 14); \
26 fallthrough; \
27 case 13: ptr[13] = read_debug(reg, 13); \
28 fallthrough; \
29 case 12: ptr[12] = read_debug(reg, 12); \
30 fallthrough; \
31 case 11: ptr[11] = read_debug(reg, 11); \
32 fallthrough; \
33 case 10: ptr[10] = read_debug(reg, 10); \
34 fallthrough; \
35 case 9: ptr[9] = read_debug(reg, 9); \
36 fallthrough; \
37 case 8: ptr[8] = read_debug(reg, 8); \
38 fallthrough; \
39 case 7: ptr[7] = read_debug(reg, 7); \
40 fallthrough; \
41 case 6: ptr[6] = read_debug(reg, 6); \
42 fallthrough; \
43 case 5: ptr[5] = read_debug(reg, 5); \
44 fallthrough; \
45 case 4: ptr[4] = read_debug(reg, 4); \
46 fallthrough; \
47 case 3: ptr[3] = read_debug(reg, 3); \
48 fallthrough; \
49 case 2: ptr[2] = read_debug(reg, 2); \
50 fallthrough; \
51 case 1: ptr[1] = read_debug(reg, 1); \
52 fallthrough; \
53 default: ptr[0] = read_debug(reg, 0); \
54 }
55
56 #define restore_debug(ptr,reg,nr) \
57 switch (nr) { \
58 case 15: write_debug(ptr[15], reg, 15); \
59 fallthrough; \
60 case 14: write_debug(ptr[14], reg, 14); \
61 fallthrough; \
62 case 13: write_debug(ptr[13], reg, 13); \
63 fallthrough; \
64 case 12: write_debug(ptr[12], reg, 12); \
65 fallthrough; \
66 case 11: write_debug(ptr[11], reg, 11); \
67 fallthrough; \
68 case 10: write_debug(ptr[10], reg, 10); \
69 fallthrough; \
70 case 9: write_debug(ptr[9], reg, 9); \
71 fallthrough; \
72 case 8: write_debug(ptr[8], reg, 8); \
73 fallthrough; \
74 case 7: write_debug(ptr[7], reg, 7); \
75 fallthrough; \
76 case 6: write_debug(ptr[6], reg, 6); \
77 fallthrough; \
78 case 5: write_debug(ptr[5], reg, 5); \
79 fallthrough; \
80 case 4: write_debug(ptr[4], reg, 4); \
81 fallthrough; \
82 case 3: write_debug(ptr[3], reg, 3); \
83 fallthrough; \
84 case 2: write_debug(ptr[2], reg, 2); \
85 fallthrough; \
86 case 1: write_debug(ptr[1], reg, 1); \
87 fallthrough; \
88 default: write_debug(ptr[0], reg, 0); \
89 }
90
__vcpu_debug_regs(struct kvm_vcpu * vcpu)91 static struct kvm_guest_debug_arch *__vcpu_debug_regs(struct kvm_vcpu *vcpu)
92 {
93 switch (vcpu->arch.debug_owner) {
94 case VCPU_DEBUG_FREE:
95 WARN_ON_ONCE(1);
96 fallthrough;
97 case VCPU_DEBUG_GUEST_OWNED:
98 return &vcpu->arch.vcpu_debug_state;
99 case VCPU_DEBUG_HOST_OWNED:
100 return &vcpu->arch.external_debug_state;
101 }
102
103 return NULL;
104 }
105
__debug_save_state(struct kvm_guest_debug_arch * dbg,struct kvm_cpu_context * ctxt)106 static void __debug_save_state(struct kvm_guest_debug_arch *dbg,
107 struct kvm_cpu_context *ctxt)
108 {
109 int brps = *host_data_ptr(debug_brps);
110 int wrps = *host_data_ptr(debug_wrps);
111
112 save_debug(dbg->dbg_bcr, dbgbcr, brps);
113 save_debug(dbg->dbg_bvr, dbgbvr, brps);
114 save_debug(dbg->dbg_wcr, dbgwcr, wrps);
115 save_debug(dbg->dbg_wvr, dbgwvr, wrps);
116
117 ctxt_sys_reg(ctxt, MDCCINT_EL1) = read_sysreg(mdccint_el1);
118 }
119
__debug_restore_state(struct kvm_guest_debug_arch * dbg,struct kvm_cpu_context * ctxt)120 static void __debug_restore_state(struct kvm_guest_debug_arch *dbg,
121 struct kvm_cpu_context *ctxt)
122 {
123 int brps = *host_data_ptr(debug_brps);
124 int wrps = *host_data_ptr(debug_wrps);
125
126 restore_debug(dbg->dbg_bcr, dbgbcr, brps);
127 restore_debug(dbg->dbg_bvr, dbgbvr, brps);
128 restore_debug(dbg->dbg_wcr, dbgwcr, wrps);
129 restore_debug(dbg->dbg_wvr, dbgwvr, wrps);
130
131 write_sysreg(ctxt_sys_reg(ctxt, MDCCINT_EL1), mdccint_el1);
132 }
133
__debug_switch_to_guest_common(struct kvm_vcpu * vcpu)134 static inline void __debug_switch_to_guest_common(struct kvm_vcpu *vcpu)
135 {
136 struct kvm_cpu_context *host_ctxt;
137 struct kvm_cpu_context *guest_ctxt;
138 struct kvm_guest_debug_arch *host_dbg;
139 struct kvm_guest_debug_arch *guest_dbg;
140
141 if (!kvm_debug_regs_in_use(vcpu))
142 return;
143
144 host_ctxt = host_data_ptr(host_ctxt);
145 guest_ctxt = &vcpu->arch.ctxt;
146 host_dbg = host_data_ptr(host_debug_state.regs);
147 guest_dbg = __vcpu_debug_regs(vcpu);
148
149 __debug_save_state(host_dbg, host_ctxt);
150 __debug_restore_state(guest_dbg, guest_ctxt);
151 }
152
__debug_switch_to_host_common(struct kvm_vcpu * vcpu)153 static inline void __debug_switch_to_host_common(struct kvm_vcpu *vcpu)
154 {
155 struct kvm_cpu_context *host_ctxt;
156 struct kvm_cpu_context *guest_ctxt;
157 struct kvm_guest_debug_arch *host_dbg;
158 struct kvm_guest_debug_arch *guest_dbg;
159
160 if (!kvm_debug_regs_in_use(vcpu))
161 return;
162
163 host_ctxt = host_data_ptr(host_ctxt);
164 guest_ctxt = &vcpu->arch.ctxt;
165 host_dbg = host_data_ptr(host_debug_state.regs);
166 guest_dbg = __vcpu_debug_regs(vcpu);
167
168 __debug_save_state(guest_dbg, guest_ctxt);
169 __debug_restore_state(host_dbg, host_ctxt);
170 }
171
172 #endif /* __ARM64_KVM_HYP_DEBUG_SR_H__ */
173