1
2
3
4
5
6
7
8
9#include <linux/kvm_host.h>
10#include <linux/hw_breakpoint.h>
11
12#include <asm/debug-monitors.h>
13#include <asm/kvm_asm.h>
14#include <asm/kvm_arm.h>
15#include <asm/kvm_emulate.h>
16
17#include "trace.h"
18
19
20#define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \
21 DBG_MDSCR_KDE | \
22 DBG_MDSCR_MDE)
23
24static DEFINE_PER_CPU(u32, mdcr_el2);
25
26
27
28
29
30
31
32
33
34
35
36static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
37{
38 u64 val = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
39
40 vcpu->arch.guest_debug_preserved.mdscr_el1 = val;
41
42 trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
43 vcpu->arch.guest_debug_preserved.mdscr_el1);
44}
45
46static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
47{
48 u64 val = vcpu->arch.guest_debug_preserved.mdscr_el1;
49
50 vcpu_write_sys_reg(vcpu, val, MDSCR_EL1);
51
52 trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
53 vcpu_read_sys_reg(vcpu, MDSCR_EL1));
54}
55
56
57
58
59
60
61
62
63
64
65
66void kvm_arm_init_debug(void)
67{
68 __this_cpu_write(mdcr_el2, kvm_call_hyp_ret(__kvm_get_mdcr_el2));
69}
70
71
72
73
74
75void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
76{
77 vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state;
78}
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
102{
103 bool trap_debug = !(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY);
104 unsigned long mdscr;
105
106 trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
107
108
109
110
111
112 vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK;
113 vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
114 MDCR_EL2_TPMS |
115 MDCR_EL2_TPMCR |
116 MDCR_EL2_TDRA |
117 MDCR_EL2_TDOSA);
118
119
120 if (vcpu->guest_debug) {
121
122 vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE;
123
124
125 save_guest_debug_regs(vcpu);
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
148 *vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
149 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
150 mdscr |= DBG_MDSCR_SS;
151 vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
152 } else {
153 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
154 mdscr &= ~DBG_MDSCR_SS;
155 vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
156 }
157
158 trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
159
160
161
162
163
164
165
166
167
168
169 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
170
171 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
172 mdscr |= DBG_MDSCR_MDE;
173 vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
174
175 vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
176 vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
177 trap_debug = true;
178
179 trace_kvm_arm_set_regset("BKPTS", get_num_brps(),
180 &vcpu->arch.debug_ptr->dbg_bcr[0],
181 &vcpu->arch.debug_ptr->dbg_bvr[0]);
182
183 trace_kvm_arm_set_regset("WAPTS", get_num_wrps(),
184 &vcpu->arch.debug_ptr->dbg_wcr[0],
185 &vcpu->arch.debug_ptr->dbg_wvr[0]);
186 }
187 }
188
189 BUG_ON(!vcpu->guest_debug &&
190 vcpu->arch.debug_ptr != &vcpu->arch.vcpu_debug_state);
191
192
193 if (trap_debug)
194 vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
195
196
197 if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
198 vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
199
200 trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
201 trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_read_sys_reg(vcpu, MDSCR_EL1));
202}
203
204void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
205{
206 trace_kvm_arm_clear_debug(vcpu->guest_debug);
207
208 if (vcpu->guest_debug) {
209 restore_guest_debug_regs(vcpu);
210
211
212
213
214
215 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
216 kvm_arm_reset_debug_ptr(vcpu);
217
218 trace_kvm_arm_set_regset("BKPTS", get_num_brps(),
219 &vcpu->arch.debug_ptr->dbg_bcr[0],
220 &vcpu->arch.debug_ptr->dbg_bvr[0]);
221
222 trace_kvm_arm_set_regset("WAPTS", get_num_wrps(),
223 &vcpu->arch.debug_ptr->dbg_wcr[0],
224 &vcpu->arch.debug_ptr->dbg_wvr[0]);
225 }
226 }
227}
228