Skip to content

Commit beb470d

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: Use debug_owner to track if debug regs need save/restore
Use the debug owner to determine if the debug regs are in use instead of keeping around the DEBUG_DIRTY flag. Debug registers are now saved/restored after the first trap, regardless of whether it was a read or a write. This also shifts the point at which KVM becomes lazy to vcpu_put() rather than the next exception taken from the guest. 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 803602b commit beb470d

File tree

5 files changed

+7
-55
lines changed

5 files changed

+7
-55
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -917,8 +917,6 @@ struct kvm_vcpu_arch {
917917
#define EXCEPT_AA64_EL2_IRQ __vcpu_except_flags(5)
918918
#define EXCEPT_AA64_EL2_FIQ __vcpu_except_flags(6)
919919
#define EXCEPT_AA64_EL2_SERR __vcpu_except_flags(7)
920-
/* Guest debug is live */
921-
#define DEBUG_DIRTY __vcpu_single_flag(iflags, BIT(4))
922920

923921
/* Physical CPU not in supported_cpus */
924922
#define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(0))
@@ -1356,6 +1354,8 @@ void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
13561354
((vcpu)->arch.debug_owner != VCPU_DEBUG_FREE)
13571355
#define kvm_host_owns_debug_regs(vcpu) \
13581356
((vcpu)->arch.debug_owner == VCPU_DEBUG_HOST_OWNED)
1357+
#define kvm_guest_owns_debug_regs(vcpu) \
1358+
((vcpu)->arch.debug_owner == VCPU_DEBUG_GUEST_OWNED)
13591359

13601360
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
13611361
struct kvm_device_attr *attr);

arch/arm64/kvm/debug.c

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,9 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
8686
vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE;
8787

8888
/*
89-
* Trap debug register access when one of the following is true:
90-
* - Userspace is using the hardware to debug the guest
91-
* (KVM_GUESTDBG_USE_HW is set).
92-
* - The guest is not using debug (DEBUG_DIRTY clear).
93-
* - The guest has enabled the OS Lock (debug exceptions are blocked).
89+
* Trap debug registers if the guest doesn't have ownership of them.
9490
*/
95-
if ((vcpu->guest_debug & KVM_GUESTDBG_USE_HW) ||
96-
!vcpu_get_flag(vcpu, DEBUG_DIRTY) ||
97-
kvm_vcpu_os_lock_enabled(vcpu))
91+
if (!kvm_guest_owns_debug_regs(vcpu))
9892
vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
9993

10094
/* Write MDCR_EL2 directly if we're already at EL2 */
@@ -127,8 +121,7 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu)
127121
* debug related registers.
128122
*
129123
* Additionally, KVM only traps guest accesses to the debug registers if
130-
* the guest is not actively using them (see the DEBUG_DIRTY
131-
* flag on vcpu->arch.iflags). Since the guest must not interfere
124+
* the guest is not actively using them. Since the guest must not interfere
132125
* with the hardware state when debugging the guest, we must ensure that
133126
* trapping is enabled whenever we are debugging the guest using the
134127
* debug registers.
@@ -195,8 +188,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
195188
mdscr |= DBG_MDSCR_MDE;
196189
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
197190

198-
vcpu_set_flag(vcpu, DEBUG_DIRTY);
199-
200191
/*
201192
* The OS Lock blocks debug exceptions in all ELs when it is
202193
* enabled. If the guest has enabled the OS Lock, constrain its
@@ -211,10 +202,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
211202
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
212203
}
213204
}
214-
215-
/* If KDE or MDE are set, perform a full save/restore cycle. */
216-
if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
217-
vcpu_set_flag(vcpu, DEBUG_DIRTY);
218205
}
219206

220207
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ static inline void __debug_switch_to_host_common(struct kvm_vcpu *vcpu)
176176

177177
__debug_save_state(guest_dbg, guest_ctxt);
178178
__debug_restore_state(host_dbg, host_ctxt);
179-
180-
vcpu_clear_flag(vcpu, DEBUG_DIRTY);
181179
}
182180

183181
#endif /* __ARM64_KVM_HYP_DEBUG_SR_H__ */

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ static inline void __sysreg32_save_state(struct kvm_vcpu *vcpu)
283283
__vcpu_sys_reg(vcpu, DACR32_EL2) = read_sysreg(dacr32_el2);
284284
__vcpu_sys_reg(vcpu, IFSR32_EL2) = read_sysreg(ifsr32_el2);
285285

286-
if (has_vhe() || vcpu_get_flag(vcpu, DEBUG_DIRTY))
286+
if (has_vhe() || kvm_debug_regs_in_use(vcpu))
287287
__vcpu_sys_reg(vcpu, DBGVCR32_EL2) = read_sysreg(dbgvcr32_el2);
288288
}
289289

@@ -300,7 +300,7 @@ static inline void __sysreg32_restore_state(struct kvm_vcpu *vcpu)
300300
write_sysreg(__vcpu_sys_reg(vcpu, DACR32_EL2), dacr32_el2);
301301
write_sysreg(__vcpu_sys_reg(vcpu, IFSR32_EL2), ifsr32_el2);
302302

303-
if (has_vhe() || vcpu_get_flag(vcpu, DEBUG_DIRTY))
303+
if (has_vhe() || kvm_debug_regs_in_use(vcpu))
304304
write_sysreg(__vcpu_sys_reg(vcpu, DBGVCR32_EL2), dbgvcr32_el2);
305305
}
306306

arch/arm64/kvm/sys_regs.c

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -621,40 +621,11 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
621621
}
622622
}
623623

624-
/*
625-
* We want to avoid world-switching all the DBG registers all the
626-
* time:
627-
*
628-
* - If we've touched any debug register, it is likely that we're
629-
* going to touch more of them. It then makes sense to disable the
630-
* traps and start doing the save/restore dance
631-
* - If debug is active (DBG_MDSCR_KDE or DBG_MDSCR_MDE set), it is
632-
* then mandatory to save/restore the registers, as the guest
633-
* depends on them.
634-
*
635-
* For this, we use a DIRTY bit, indicating the guest has modified the
636-
* debug registers, used as follow:
637-
*
638-
* On guest entry:
639-
* - If the dirty bit is set (because we're coming back from trapping),
640-
* disable the traps, save host registers, restore guest registers.
641-
* - If debug is actively in use (DBG_MDSCR_KDE or DBG_MDSCR_MDE set),
642-
* set the dirty bit, disable the traps, save host registers,
643-
* restore guest registers.
644-
* - Otherwise, enable the traps
645-
*
646-
* On guest exit:
647-
* - If the dirty bit is set, save guest registers, restore host
648-
* registers and clear the dirty bit. This ensure that the host can
649-
* now use the debug registers.
650-
*/
651624
static bool trap_debug_regs(struct kvm_vcpu *vcpu,
652625
struct sys_reg_params *p,
653626
const struct sys_reg_desc *r)
654627
{
655628
access_rw(vcpu, p, r);
656-
if (p->is_write)
657-
vcpu_set_flag(vcpu, DEBUG_DIRTY);
658629

659630
kvm_debug_set_guest_ownership(vcpu);
660631
return true;
@@ -665,9 +636,6 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
665636
*
666637
* A 32 bit write to a debug register leave top bits alone
667638
* A 32 bit read from a debug register only returns the bottom bits
668-
*
669-
* All writes will set the DEBUG_DIRTY flag to ensure the hyp code
670-
* switches between host and guest values in future.
671639
*/
672640
static void reg_to_dbg(struct kvm_vcpu *vcpu,
673641
struct sys_reg_params *p,
@@ -684,7 +652,6 @@ static void reg_to_dbg(struct kvm_vcpu *vcpu,
684652
*dbg_reg = val;
685653

686654
kvm_debug_set_guest_ownership(vcpu);
687-
vcpu_set_flag(vcpu, DEBUG_DIRTY);
688655
}
689656

690657
static void dbg_to_reg(struct kvm_vcpu *vcpu,

0 commit comments

Comments
 (0)