Skip to content

Commit 2ca3f03

Browse files
author
Marc Zyngier
committed
KVM: arm64: Manage software step state at load/put
KVM takes over the guest's software step state machine if the VMM is debugging the guest, but it does the save/restore fiddling for every guest entry. Note that the only constraint on host usage of software step is that the guest's configuration remains visible to userspace via the ONE_REG ioctls. So, we can cut down on the amount of fiddling by doing this at load/put instead. 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 4ad3a0b commit 2ca3f03

File tree

5 files changed

+48
-129
lines changed

5 files changed

+48
-129
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -764,17 +764,6 @@ struct kvm_vcpu_arch {
764764
struct arch_timer_cpu timer_cpu;
765765
struct kvm_pmu pmu;
766766

767-
/*
768-
* Guest registers we preserve during guest debugging.
769-
*
770-
* These shadow registers are updated by the kvm_handle_sys_reg
771-
* trap handler if the guest accesses or updates them while we
772-
* are using guest debug.
773-
*/
774-
struct {
775-
bool pstate_ss;
776-
} guest_debug_preserved;
777-
778767
/* vcpu power state */
779768
struct kvm_mp_state mp_state;
780769
spinlock_t mp_state_lock;
@@ -924,12 +913,14 @@ struct kvm_vcpu_arch {
924913
#define IN_WFIT __vcpu_single_flag(sflags, BIT(1))
925914
/* vcpu system registers loaded on physical CPU */
926915
#define SYSREGS_ON_CPU __vcpu_single_flag(sflags, BIT(2))
927-
/* Software step state is Active-pending */
928-
#define DBG_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(3))
916+
/* Software step state is Active-pending for external debug */
917+
#define HOST_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(3))
918+
/* Software step state is Active pending for guest debug */
919+
#define GUEST_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(4))
929920
/* PMUSERENR for the guest EL0 is on physical CPU */
930-
#define PMUSERENR_ON_CPU __vcpu_single_flag(sflags, BIT(4))
921+
#define PMUSERENR_ON_CPU __vcpu_single_flag(sflags, BIT(5))
931922
/* WFI instruction trapped */
932-
#define IN_WFI __vcpu_single_flag(sflags, BIT(5))
923+
#define IN_WFI __vcpu_single_flag(sflags, BIT(6))
933924

934925

935926
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
@@ -1341,9 +1332,8 @@ static inline bool kvm_system_needs_idmapped_vectors(void)
13411332
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
13421333

13431334
void kvm_init_host_debug_data(void);
1344-
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
1345-
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
13461335
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu);
1336+
void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu);
13471337
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
13481338
void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val);
13491339

arch/arm64/kvm/arm.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
622622

623623
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
624624
{
625+
kvm_vcpu_put_debug(vcpu);
625626
kvm_arch_vcpu_put_fp(vcpu);
626627
if (has_vhe())
627628
kvm_vcpu_put_vhe(vcpu);
@@ -1181,7 +1182,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
11811182
continue;
11821183
}
11831184

1184-
kvm_arm_setup_debug(vcpu);
11851185
kvm_arch_vcpu_ctxflush_fp(vcpu);
11861186

11871187
/**************************************************************
@@ -1198,8 +1198,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
11981198
* Back from guest
11991199
*************************************************************/
12001200

1201-
kvm_arm_clear_debug(vcpu);
1202-
12031201
/*
12041202
* We must sync the PMU state before the vgic state so
12051203
* that the vgic can properly sample the updated state of the

arch/arm64/kvm/debug.c

Lines changed: 38 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
* Debug and Guest Debug support
44
*
55
* Copyright (C) 2015 - Linaro Ltd
6-
* Author: Alex Bennée <[email protected]>
6+
* Authors: Alex Bennée <[email protected]>
7+
* Oliver Upton <[email protected]>
78
*/
89

910
#include <linux/kvm_host.h>
@@ -14,35 +15,6 @@
1415
#include <asm/kvm_arm.h>
1516
#include <asm/kvm_emulate.h>
1617

17-
18-
/*
19-
* save/restore_guest_debug_regs
20-
*
21-
* For some debug operations we need to tweak some guest registers. As
22-
* a result we need to save the state of those registers before we
23-
* make those modifications.
24-
*
25-
* Guest access to MDSCR_EL1 is trapped by the hypervisor and handled
26-
* after we have restored the preserved value to the main context.
27-
*
28-
* When single-step is enabled by userspace, we tweak PSTATE.SS on every
29-
* guest entry. Preserve PSTATE.SS so we can restore the original value
30-
* for the vcpu after the single-step is disabled.
31-
*/
32-
static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
33-
{
34-
vcpu->arch.guest_debug_preserved.pstate_ss =
35-
(*vcpu_cpsr(vcpu) & DBG_SPSR_SS);
36-
}
37-
38-
static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
39-
{
40-
if (vcpu->arch.guest_debug_preserved.pstate_ss)
41-
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
42-
else
43-
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
44-
}
45-
4618
/**
4719
* kvm_arm_setup_mdcr_el2 - configure vcpu mdcr_el2 value
4820
*
@@ -91,83 +63,6 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
9163
preempt_enable();
9264
}
9365

94-
/**
95-
* kvm_arm_setup_debug - set up debug related stuff
96-
*
97-
* @vcpu: the vcpu pointer
98-
*
99-
* This is called before each entry into the hypervisor to setup any
100-
* debug related registers.
101-
*
102-
* Additionally, KVM only traps guest accesses to the debug registers if
103-
* the guest is not actively using them. Since the guest must not interfere
104-
* with the hardware state when debugging the guest, we must ensure that
105-
* trapping is enabled whenever we are debugging the guest using the
106-
* debug registers.
107-
*/
108-
109-
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
110-
{
111-
/* Check if we need to use the debug registers. */
112-
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
113-
/* Save guest debug state */
114-
save_guest_debug_regs(vcpu);
115-
116-
/*
117-
* Single Step (ARM ARM D2.12.3 The software step state
118-
* machine)
119-
*
120-
* If we are doing Single Step we need to manipulate
121-
* the guest's MDSCR_EL1.SS and PSTATE.SS. Once the
122-
* step has occurred the hypervisor will trap the
123-
* debug exception and we return to userspace.
124-
*
125-
* If the guest attempts to single step its userspace
126-
* we would have to deal with a trapped exception
127-
* while in the guest kernel. Because this would be
128-
* hard to unwind we suppress the guest's ability to
129-
* do so by masking MDSCR_EL.SS.
130-
*
131-
* This confuses guest debuggers which use
132-
* single-step behind the scenes but everything
133-
* returns to normal once the host is no longer
134-
* debugging the system.
135-
*/
136-
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
137-
/*
138-
* If the software step state at the last guest exit
139-
* was Active-pending, we don't set DBG_SPSR_SS so
140-
* that the state is maintained (to not run another
141-
* single-step until the pending Software Step
142-
* exception is taken).
143-
*/
144-
if (!vcpu_get_flag(vcpu, DBG_SS_ACTIVE_PENDING))
145-
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
146-
else
147-
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
148-
}
149-
}
150-
}
151-
152-
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
153-
{
154-
/*
155-
* Restore the guest's debug registers if we were using them.
156-
*/
157-
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
158-
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
159-
if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS))
160-
/*
161-
* Mark the vcpu as ACTIVE_PENDING
162-
* until Software Step exception is taken.
163-
*/
164-
vcpu_set_flag(vcpu, DBG_SS_ACTIVE_PENDING);
165-
}
166-
167-
restore_guest_debug_regs(vcpu);
168-
}
169-
}
170-
17166
void kvm_init_host_debug_data(void)
17267
{
17368
u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
@@ -246,6 +141,22 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
246141
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
247142
vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
248143
setup_external_mdscr(vcpu);
144+
145+
/*
146+
* Steal the guest's single-step state machine if userspace wants
147+
* single-step the guest.
148+
*/
149+
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
150+
if (*vcpu_cpsr(vcpu) & DBG_SPSR_SS)
151+
vcpu_clear_flag(vcpu, GUEST_SS_ACTIVE_PENDING);
152+
else
153+
vcpu_set_flag(vcpu, GUEST_SS_ACTIVE_PENDING);
154+
155+
if (!vcpu_get_flag(vcpu, HOST_SS_ACTIVE_PENDING))
156+
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
157+
else
158+
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
159+
}
249160
} else {
250161
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
251162

@@ -258,6 +169,26 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
258169
kvm_arm_setup_mdcr_el2(vcpu);
259170
}
260171

172+
void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu)
173+
{
174+
if (likely(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)))
175+
return;
176+
177+
/*
178+
* Save the host's software step state and restore the guest's before
179+
* potentially returning to userspace.
180+
*/
181+
if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS))
182+
vcpu_set_flag(vcpu, HOST_SS_ACTIVE_PENDING);
183+
else
184+
vcpu_clear_flag(vcpu, HOST_SS_ACTIVE_PENDING);
185+
186+
if (vcpu_get_flag(vcpu, GUEST_SS_ACTIVE_PENDING))
187+
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
188+
else
189+
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
190+
}
191+
261192
/*
262193
* Updates ownership of the debug registers after a trapped guest access to a
263194
* breakpoint/watchpoint register. Host ownership of the debug registers is of

arch/arm64/kvm/guest.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
924924

925925
if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
926926
vcpu->guest_debug = 0;
927-
vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
927+
vcpu_clear_flag(vcpu, HOST_SS_ACTIVE_PENDING);
928928
return 0;
929929
}
930930

arch/arm64/kvm/handle_exit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
193193
run->debug.arch.far = vcpu->arch.fault.far_el2;
194194
break;
195195
case ESR_ELx_EC_SOFTSTP_LOW:
196-
vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
196+
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
197197
break;
198198
}
199199

0 commit comments

Comments
 (0)