Skip to content

Commit 4ad3a0b

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: Don't hijack guest context MDSCR_EL1
Stealing MDSCR_EL1 in the guest's kvm_cpu_context for external debugging is rather gross. Just add a field for this instead and let the context switch code pick the correct one based on the debug owner. Tested-by: James Clark <[email protected]> Signed-off-by: Oliver Upton <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]>
1 parent 75a5fba commit 4ad3a0b

File tree

3 files changed

+64
-52
lines changed

3 files changed

+64
-52
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ struct kvm_vcpu_arch {
751751
*/
752752
struct kvm_guest_debug_arch vcpu_debug_state;
753753
struct kvm_guest_debug_arch external_debug_state;
754+
u64 external_mdscr_el1;
754755

755756
enum {
756757
VCPU_DEBUG_FREE,
@@ -771,7 +772,6 @@ struct kvm_vcpu_arch {
771772
* are using guest debug.
772773
*/
773774
struct {
774-
u32 mdscr_el1;
775775
bool pstate_ss;
776776
} guest_debug_preserved;
777777

arch/arm64/kvm/debug.c

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,12 @@
3131
*/
3232
static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
3333
{
34-
u64 val = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
35-
36-
vcpu->arch.guest_debug_preserved.mdscr_el1 = val;
3734
vcpu->arch.guest_debug_preserved.pstate_ss =
3835
(*vcpu_cpsr(vcpu) & DBG_SPSR_SS);
3936
}
4037

4138
static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
4239
{
43-
u64 val = vcpu->arch.guest_debug_preserved.mdscr_el1;
44-
45-
vcpu_write_sys_reg(vcpu, val, MDSCR_EL1);
46-
4740
if (vcpu->arch.guest_debug_preserved.pstate_ss)
4841
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
4942
else
@@ -115,8 +108,6 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
115108

116109
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
117110
{
118-
unsigned long mdscr;
119-
120111
/* Check if we need to use the debug registers. */
121112
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
122113
/* Save guest debug state */
@@ -154,36 +145,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
154145
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
155146
else
156147
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
157-
158-
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
159-
mdscr |= DBG_MDSCR_SS;
160-
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
161-
} else {
162-
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
163-
mdscr &= ~DBG_MDSCR_SS;
164-
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
165-
}
166-
167-
/*
168-
* Enable breakpoints and watchpoints if userspace wants them.
169-
*/
170-
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
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-
/*
176-
* The OS Lock blocks debug exceptions in all ELs when it is
177-
* enabled. If the guest has enabled the OS Lock, constrain its
178-
* effects to the guest. Emulate the behavior by clearing
179-
* MDSCR_EL1.MDE. In so doing, we ensure that host debug
180-
* exceptions are unaffected by guest configuration of the OS
181-
* Lock.
182-
*/
183-
} else if (kvm_vcpu_os_lock_enabled(vcpu)) {
184-
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
185-
mdscr &= ~DBG_MDSCR_MDE;
186-
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
187148
}
188149
}
189150
}
@@ -227,6 +188,41 @@ void kvm_init_host_debug_data(void)
227188
host_data_set_flag(HAS_TRBE);
228189
}
229190

191+
/*
192+
* Configures the 'external' MDSCR_EL1 value for the guest, i.e. when the host
193+
* has taken over MDSCR_EL1.
194+
*
195+
* - Userspace is single-stepping the guest, and MDSCR_EL1.SS is forced to 1.
196+
*
197+
* - Userspace is using the breakpoint/watchpoint registers to debug the
198+
* guest, and MDSCR_EL1.MDE is forced to 1.
199+
*
200+
* - The guest has enabled the OS Lock, and KVM is forcing MDSCR_EL1.MDE to 0,
201+
* masking all debug exceptions affected by the OS Lock.
202+
*/
203+
static void setup_external_mdscr(struct kvm_vcpu *vcpu)
204+
{
205+
/*
206+
* Use the guest's MDSCR_EL1 as a starting point, since there are
207+
* several other features controlled by MDSCR_EL1 that are not relevant
208+
* to the host.
209+
*
210+
* Clear the bits that KVM may use which also satisfies emulation of
211+
* the OS Lock as MDSCR_EL1.MDE is cleared.
212+
*/
213+
u64 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1) & ~(MDSCR_EL1_SS |
214+
MDSCR_EL1_MDE |
215+
MDSCR_EL1_KDE);
216+
217+
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
218+
mdscr |= MDSCR_EL1_SS;
219+
220+
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW)
221+
mdscr |= MDSCR_EL1_MDE | MDSCR_EL1_KDE;
222+
223+
vcpu->arch.external_mdscr_el1 = mdscr;
224+
}
225+
230226
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
231227
{
232228
u64 mdscr;
@@ -249,6 +245,7 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
249245
*/
250246
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
251247
vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
248+
setup_external_mdscr(vcpu);
252249
} else {
253250
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
254251

arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,34 @@
1818

1919
static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt);
2020

21+
static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
22+
{
23+
struct kvm_vcpu *vcpu = ctxt->__hyp_running_vcpu;
24+
25+
if (!vcpu)
26+
vcpu = container_of(ctxt, struct kvm_vcpu, arch.ctxt);
27+
28+
return vcpu;
29+
}
30+
31+
static inline bool ctxt_is_guest(struct kvm_cpu_context *ctxt)
32+
{
33+
return host_data_ptr(host_ctxt) != ctxt;
34+
}
35+
36+
static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
37+
{
38+
struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt);
39+
40+
if (ctxt_is_guest(ctxt) && kvm_host_owns_debug_regs(vcpu))
41+
return &vcpu->arch.external_mdscr_el1;
42+
43+
return &ctxt_sys_reg(ctxt, MDSCR_EL1);
44+
}
45+
2146
static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
2247
{
23-
ctxt_sys_reg(ctxt, MDSCR_EL1) = read_sysreg(mdscr_el1);
48+
*ctxt_mdscr_el1(ctxt) = read_sysreg(mdscr_el1);
2449

2550
// POR_EL0 can affect uaccess, so must be saved/restored early.
2651
if (ctxt_has_s1poe(ctxt))
@@ -33,16 +58,6 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
3358
ctxt_sys_reg(ctxt, TPIDRRO_EL0) = read_sysreg(tpidrro_el0);
3459
}
3560

36-
static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
37-
{
38-
struct kvm_vcpu *vcpu = ctxt->__hyp_running_vcpu;
39-
40-
if (!vcpu)
41-
vcpu = container_of(ctxt, struct kvm_vcpu, arch.ctxt);
42-
43-
return vcpu;
44-
}
45-
4661
static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
4762
{
4863
struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt);
@@ -139,7 +154,7 @@ static inline void __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
139154

140155
static inline void __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
141156
{
142-
write_sysreg(ctxt_sys_reg(ctxt, MDSCR_EL1), mdscr_el1);
157+
write_sysreg(*ctxt_mdscr_el1(ctxt), mdscr_el1);
143158

144159
// POR_EL0 can affect uaccess, so must be saved/restored early.
145160
if (ctxt_has_s1poe(ctxt))

0 commit comments

Comments
 (0)