Skip to content

Commit 370531d

Browse files
reijiw-kvmMarc Zyngier
authored andcommitted
KVM: arm64: Clear PSTATE.SS when the Software Step state was Active-pending
While userspace enables single-step, if the Software Step state at the last guest exit was "Active-pending", clear PSTATE.SS on guest entry to restore the state. Currently, KVM sets PSTATE.SS to 1 on every guest entry while userspace enables single-step for the vCPU (with KVM_GUESTDBG_SINGLESTEP). It means KVM always makes the vCPU's Software Step state "Active-not-pending" on the guest entry, which lets the VCPU perform single-step (then Software Step exception is taken). This could cause extra single-step (without returning to userspace) if the Software Step state at the last guest exit was "Active-pending" (i.e. the last exit was triggered by an asynchronous exception after the single-step is performed, but before the Software Step exception is taken. See "Figure D2-3 Software step state machine" and "D2.12.7 Behavior in the active-pending state" in ARM DDI 0487I.a for more info about this behavior). Fix this by clearing PSTATE.SS on guest entry if the Software Step state at the last exit was "Active-pending" so that KVM restore the state (and the exception is taken before further single-step is performed). Fixes: 337b99b ("KVM: arm64: guest debug, add support for single-step") Signed-off-by: Reiji Watanabe <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 34fbdee commit 370531d

File tree

4 files changed

+32
-2
lines changed

4 files changed

+32
-2
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,9 @@ struct kvm_vcpu_arch {
536536
#define IN_WFIT __vcpu_single_flag(sflags, BIT(3))
537537
/* vcpu system registers loaded on physical CPU */
538538
#define SYSREGS_ON_CPU __vcpu_single_flag(sflags, BIT(4))
539+
/* Software step state is Active-pending */
540+
#define DBG_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(5))
541+
539542

540543
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
541544
#define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \

arch/arm64/kvm/debug.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,18 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
200200
* debugging the system.
201201
*/
202202
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
203-
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
203+
/*
204+
* If the software step state at the last guest exit
205+
* was Active-pending, we don't set DBG_SPSR_SS so
206+
* that the state is maintained (to not run another
207+
* single-step until the pending Software Step
208+
* exception is taken).
209+
*/
210+
if (!vcpu_get_flag(vcpu, DBG_SS_ACTIVE_PENDING))
211+
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
212+
else
213+
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
214+
204215
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
205216
mdscr |= DBG_MDSCR_SS;
206217
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
@@ -274,6 +285,15 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
274285
* Restore the guest's debug registers if we were using them.
275286
*/
276287
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
288+
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
289+
if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS))
290+
/*
291+
* Mark the vcpu as ACTIVE_PENDING
292+
* until Software Step exception is taken.
293+
*/
294+
vcpu_set_flag(vcpu, DBG_SS_ACTIVE_PENDING);
295+
}
296+
277297
restore_guest_debug_regs(vcpu);
278298

279299
/*

arch/arm64/kvm/guest.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
937937
} else {
938938
/* If not enabled clear all flags */
939939
vcpu->guest_debug = 0;
940+
vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
940941
}
941942

942943
out:

arch/arm64/kvm/handle_exit.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,14 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
152152
run->debug.arch.hsr_high = upper_32_bits(esr);
153153
run->flags = KVM_DEBUG_ARCH_HSR_HIGH_VALID;
154154

155-
if (ESR_ELx_EC(esr) == ESR_ELx_EC_WATCHPT_LOW)
155+
switch (ESR_ELx_EC(esr)) {
156+
case ESR_ELx_EC_WATCHPT_LOW:
156157
run->debug.arch.far = vcpu->arch.fault.far_el2;
158+
break;
159+
case ESR_ELx_EC_SOFTSTP_LOW:
160+
vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
161+
break;
162+
}
157163

158164
return 0;
159165
}

0 commit comments

Comments
 (0)