projects/linux·blob master · refs

293 lines · 8.3 KiB

1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Debug and Guest Debug support
4 *
5 * Copyright (C) 2015 - Linaro Ltd
6 * Authors: Alex Bennée <[email protected]>
7 * Oliver Upton <[email protected]>
8 */
9
10#include <linux/kvm_host.h>
11#include <linux/hw_breakpoint.h>
12
13#include <asm/arm_pmuv3.h>
14#include <asm/debug-monitors.h>
15#include <asm/kvm_asm.h>
16#include <asm/kvm_arm.h>
17#include <asm/kvm_emulate.h>
18
19static int cpu_has_spe(u64 dfr0)
20{
21 return cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_PMSVer_SHIFT) &&
22 !(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P);
23}
24
25/**
26 * kvm_arm_setup_mdcr_el2 - configure vcpu mdcr_el2 value
27 *
28 * @vcpu: the vcpu pointer
29 *
30 * This ensures we will trap access to:
31 * - Performance monitors (MDCR_EL2_TPM/MDCR_EL2_TPMCR)
32 * - Debug ROM Address (MDCR_EL2_TDRA)
33 * - OS related registers (MDCR_EL2_TDOSA)
34 * - Statistical profiler (MDCR_EL2_TPMS/MDCR_EL2_E2PB)
35 * - Self-hosted Trace Filter controls (MDCR_EL2_TTRF)
36 * - Self-hosted Trace (MDCR_EL2_TTRF/MDCR_EL2_E2TB)
37 */
38static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
39{
40 preempt_disable();
41
42 /*
43 * This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK
44 * to disable guest access to the profiling and trace buffers
45 */
46 vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN,
47 *host_data_ptr(nr_event_counters));
48 vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
49 MDCR_EL2_TPMS |
50 MDCR_EL2_TTRF |
51 MDCR_EL2_TPMCR |
52 MDCR_EL2_TDRA |
53 MDCR_EL2_TDOSA);
54
55 /* Is the VM being debugged by userspace? */
56 if (vcpu->guest_debug)
57 /* Route all software debug exceptions to EL2 */
58 vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE;
59
60 /*
61 * Trap debug registers if the guest doesn't have ownership of them.
62 */
63 if (!kvm_guest_owns_debug_regs(vcpu))
64 vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
65
66 if (vcpu_has_nv(vcpu))
67 kvm_nested_setup_mdcr_el2(vcpu);
68
69 /* Write MDCR_EL2 directly if we're already at EL2 */
70 if (has_vhe())
71 write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
72
73 preempt_enable();
74}
75
76void kvm_init_host_debug_data(void)
77{
78 u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
79 unsigned int pmuver = cpuid_feature_extract_unsigned_field(dfr0,
80 ID_AA64DFR0_EL1_PMUVer_SHIFT);
81
82 if (pmuv3_implemented(pmuver))
83 *host_data_ptr(nr_event_counters) = FIELD_GET(ARMV8_PMU_PMCR_N,
84 read_sysreg(pmcr_el0));
85
86 *host_data_ptr(debug_brps) = SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, dfr0);
87 *host_data_ptr(debug_wrps) = SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, dfr0);
88
89 if (cpu_has_spe(dfr0))
90 host_data_set_flag(HAS_SPE);
91
92 if (has_vhe())
93 return;
94
95 /* Check if we have BRBE implemented and available at the host */
96 if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_BRBE_SHIFT))
97 host_data_set_flag(HAS_BRBE);
98
99 if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceFilt_SHIFT)) {
100 /* Force disable trace in protected mode in case of no TRBE */
101 if (is_protected_kvm_enabled())
102 host_data_set_flag(EL1_TRACING_CONFIGURED);
103
104 if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceBuffer_SHIFT) &&
105 !(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
106 host_data_set_flag(HAS_TRBE);
107 }
108}
109
110void kvm_debug_init_vhe(void)
111{
112 /* Clear PMSCR_EL1.E{0,1}SPE which reset to UNKNOWN values. */
113 if (host_data_test_flag(HAS_SPE))
114 write_sysreg_el1(0, SYS_PMSCR);
115}
116
117/*
118 * Configures the 'external' MDSCR_EL1 value for the guest, i.e. when the host
119 * has taken over MDSCR_EL1.
120 *
121 * - Userspace is single-stepping the guest, and MDSCR_EL1.SS is forced to 1.
122 *
123 * - Userspace is using the breakpoint/watchpoint registers to debug the
124 * guest, and MDSCR_EL1.MDE is forced to 1.
125 *
126 * - The guest has enabled the OS Lock, and KVM is forcing MDSCR_EL1.MDE to 0,
127 * masking all debug exceptions affected by the OS Lock.
128 */
129static void setup_external_mdscr(struct kvm_vcpu *vcpu)
130{
131 /*
132 * Use the guest's MDSCR_EL1 as a starting point, since there are
133 * several other features controlled by MDSCR_EL1 that are not relevant
134 * to the host.
135 *
136 * Clear the bits that KVM may use which also satisfies emulation of
137 * the OS Lock as MDSCR_EL1.MDE is cleared.
138 */
139 u64 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1) & ~(MDSCR_EL1_SS |
140 MDSCR_EL1_MDE |
141 MDSCR_EL1_KDE);
142
143 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
144 mdscr |= MDSCR_EL1_SS;
145
146 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW)
147 mdscr |= MDSCR_EL1_MDE | MDSCR_EL1_KDE;
148
149 vcpu->arch.external_mdscr_el1 = mdscr;
150}
151
152void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
153{
154 u64 mdscr;
155
156 /* Must be called before kvm_vcpu_load_vhe() */
157 KVM_BUG_ON(vcpu_get_flag(vcpu, SYSREGS_ON_CPU), vcpu->kvm);
158
159 if (has_vhe())
160 *host_data_ptr(host_debug_state.mdcr_el2) = read_sysreg(mdcr_el2);
161
162 /*
163 * Determine which of the possible debug states we're in:
164 *
165 * - VCPU_DEBUG_HOST_OWNED: KVM has taken ownership of the guest's
166 * breakpoint/watchpoint registers, or needs to use MDSCR_EL1 to do
167 * software step or emulate the effects of the OS Lock being enabled.
168 *
169 * - VCPU_DEBUG_GUEST_OWNED: The guest has debug exceptions enabled, and
170 * the breakpoint/watchpoint registers need to be loaded eagerly.
171 *
172 * - VCPU_DEBUG_FREE: Neither of the above apply, no breakpoint/watchpoint
173 * context needs to be loaded on the CPU.
174 */
175 if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
176 vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
177 setup_external_mdscr(vcpu);
178
179 /*
180 * Steal the guest's single-step state machine if userspace wants
181 * single-step the guest.
182 */
183 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
184 if (*vcpu_cpsr(vcpu) & DBG_SPSR_SS)
185 vcpu_clear_flag(vcpu, GUEST_SS_ACTIVE_PENDING);
186 else
187 vcpu_set_flag(vcpu, GUEST_SS_ACTIVE_PENDING);
188
189 if (!vcpu_get_flag(vcpu, HOST_SS_ACTIVE_PENDING))
190 *vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
191 else
192 *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
193 }
194 } else {
195 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
196
197 if (mdscr & (MDSCR_EL1_KDE | MDSCR_EL1_MDE))
198 vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
199 else
200 vcpu->arch.debug_owner = VCPU_DEBUG_FREE;
201 }
202
203 kvm_arm_setup_mdcr_el2(vcpu);
204}
205
206void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu)
207{
208 if (has_vhe())
209 write_sysreg(*host_data_ptr(host_debug_state.mdcr_el2), mdcr_el2);
210
211 if (likely(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)))
212 return;
213
214 /*
215 * Save the host's software step state and restore the guest's before
216 * potentially returning to userspace.
217 */
218 if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS))
219 vcpu_set_flag(vcpu, HOST_SS_ACTIVE_PENDING);
220 else
221 vcpu_clear_flag(vcpu, HOST_SS_ACTIVE_PENDING);
222
223 if (vcpu_get_flag(vcpu, GUEST_SS_ACTIVE_PENDING))
224 *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
225 else
226 *vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
227}
228
229/*
230 * Updates ownership of the debug registers after a trapped guest access to a
231 * breakpoint/watchpoint register. Host ownership of the debug registers is of
232 * strictly higher priority, and it is the responsibility of the VMM to emulate
233 * guest debug exceptions in this configuration.
234 */
235void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu)
236{
237 if (kvm_host_owns_debug_regs(vcpu))
238 return;
239
240 vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
241 kvm_arm_setup_mdcr_el2(vcpu);
242}
243
244void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val)
245{
246 if (val & OSLAR_EL1_OSLK)
247 __vcpu_rmw_sys_reg(vcpu, OSLSR_EL1, |=, OSLSR_EL1_OSLK);
248 else
249 __vcpu_rmw_sys_reg(vcpu, OSLSR_EL1, &=, ~OSLSR_EL1_OSLK);
250
251 preempt_disable();
252 kvm_arch_vcpu_put(vcpu);
253 kvm_arch_vcpu_load(vcpu, smp_processor_id());
254 preempt_enable();
255}
256
257static bool skip_trbe_access(bool skip_condition)
258{
259 return (WARN_ON_ONCE(preemptible()) || skip_condition ||
260 is_protected_kvm_enabled() || !is_kvm_arm_initialised());
261}
262
263void kvm_enable_trbe(void)
264{
265 if (!skip_trbe_access(has_vhe()))
266 host_data_set_flag(TRBE_ENABLED);
267}
268EXPORT_SYMBOL_GPL(kvm_enable_trbe);
269
270void kvm_disable_trbe(void)
271{
272 if (!skip_trbe_access(has_vhe()))
273 host_data_clear_flag(TRBE_ENABLED);
274}
275EXPORT_SYMBOL_GPL(kvm_disable_trbe);
276
277void kvm_tracing_set_el1_configuration(u64 trfcr_while_in_guest)
278{
279 if (skip_trbe_access(false))
280 return;
281
282 if (has_vhe()) {
283 write_sysreg_s(trfcr_while_in_guest, SYS_TRFCR_EL12);
284 return;
285 }
286
287 *host_data_ptr(trfcr_while_in_guest) = trfcr_while_in_guest;
288 if (read_sysreg_s(SYS_TRFCR_EL1) != trfcr_while_in_guest)
289 host_data_set_flag(EL1_TRACING_CONFIGURED);
290 else
291 host_data_clear_flag(EL1_TRACING_CONFIGURED);
292}
293EXPORT_SYMBOL_GPL(kvm_tracing_set_el1_configuration);