Skip to content

Commit 83010ac

Browse files
committed
KVM: arm64: Clear PSTATE.SS when the Software Step state was Active-pending
Bugzilla: https://bugzilla.redhat.com/2128973 commit 370531d Author: Reiji Watanabe <reijiw@google.com> Date: Fri Sep 16 18:05:58 2022 -0700 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 <reijiw@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220917010600.532642-3-reijiw@google.com Signed-off-by: Cornelia Huck <cohuck@redhat.com>
1 parent a4e21f2 commit 83010ac

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
@@ -535,6 +535,9 @@ struct kvm_vcpu_arch {
535535
#define IN_WFIT __vcpu_single_flag(sflags, BIT(3))
536536
/* vcpu system registers loaded on physical CPU */
537537
#define SYSREGS_ON_CPU __vcpu_single_flag(sflags, BIT(4))
538+
/* Software step state is Active-pending */
539+
#define DBG_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(5))
540+
538541

539542
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
540543
#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
@@ -188,7 +188,18 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
188188
* debugging the system.
189189
*/
190190
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
191-
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
191+
/*
192+
* If the software step state at the last guest exit
193+
* was Active-pending, we don't set DBG_SPSR_SS so
194+
* that the state is maintained (to not run another
195+
* single-step until the pending Software Step
196+
* exception is taken).
197+
*/
198+
if (!vcpu_get_flag(vcpu, DBG_SS_ACTIVE_PENDING))
199+
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
200+
else
201+
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
202+
192203
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
193204
mdscr |= DBG_MDSCR_SS;
194205
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
@@ -262,6 +273,15 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
262273
* Restore the guest's debug registers if we were using them.
263274
*/
264275
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
276+
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
277+
if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS))
278+
/*
279+
* Mark the vcpu as ACTIVE_PENDING
280+
* until Software Step exception is taken.
281+
*/
282+
vcpu_set_flag(vcpu, DBG_SS_ACTIVE_PENDING);
283+
}
284+
265285
restore_guest_debug_regs(vcpu);
266286

267287
/*

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)