Skip to content

Commit cd9b101

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: Evaluate debug owner at vcpu_load()
In preparation for tossing the debug_ptr mess, introduce an enumeration to track the ownership of the debug registers while in the guest. Update the owner at vcpu_load() based on whether the host needs to steal the guest's debug context or if breakpoints/watchpoints are actively in use. 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 b47ffd1 commit cd9b101

File tree

4 files changed

+60
-0
lines changed

4 files changed

+60
-0
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,12 @@ struct kvm_vcpu_arch {
756756
struct kvm_guest_debug_arch vcpu_debug_state;
757757
struct kvm_guest_debug_arch external_debug_state;
758758

759+
enum {
760+
VCPU_DEBUG_FREE,
761+
VCPU_DEBUG_HOST_OWNED,
762+
VCPU_DEBUG_GUEST_OWNED,
763+
} debug_owner;
764+
759765
/* VGIC state */
760766
struct vgic_cpu vgic_cpu;
761767
struct arch_timer_cpu timer_cpu;
@@ -1345,10 +1351,15 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu);
13451351
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
13461352
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
13471353
void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
1354+
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu);
1355+
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
13481356

13491357
#define kvm_vcpu_os_lock_enabled(vcpu) \
13501358
(!!(__vcpu_sys_reg(vcpu, OSLSR_EL1) & OSLSR_EL1_OSLK))
13511359

1360+
#define kvm_host_owns_debug_regs(vcpu) \
1361+
((vcpu)->arch.debug_owner == VCPU_DEBUG_HOST_OWNED)
1362+
13521363
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
13531364
struct kvm_device_attr *attr);
13541365
int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,

arch/arm64/kvm/arm.c

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

599599
kvm_vgic_load(vcpu);
600600
kvm_timer_vcpu_load(vcpu);
601+
kvm_vcpu_load_debug(vcpu);
601602
if (has_vhe())
602603
kvm_vcpu_load_vhe(vcpu);
603604
kvm_arch_vcpu_load_fp(vcpu);

arch/arm64/kvm/debug.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,49 @@ void kvm_init_host_debug_data(void)
317317
!(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
318318
host_data_set_flag(HAS_TRBE);
319319
}
320+
321+
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
322+
{
323+
u64 mdscr;
324+
325+
/* Must be called before kvm_vcpu_load_vhe() */
326+
KVM_BUG_ON(vcpu_get_flag(vcpu, SYSREGS_ON_CPU), vcpu->kvm);
327+
328+
/*
329+
* Determine which of the possible debug states we're in:
330+
*
331+
* - VCPU_DEBUG_HOST_OWNED: KVM has taken ownership of the guest's
332+
* breakpoint/watchpoint registers, or needs to use MDSCR_EL1 to do
333+
* software step or emulate the effects of the OS Lock being enabled.
334+
*
335+
* - VCPU_DEBUG_GUEST_OWNED: The guest has debug exceptions enabled, and
336+
* the breakpoint/watchpoint registers need to be loaded eagerly.
337+
*
338+
* - VCPU_DEBUG_FREE: Neither of the above apply, no breakpoint/watchpoint
339+
* context needs to be loaded on the CPU.
340+
*/
341+
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
342+
vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
343+
} else {
344+
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
345+
346+
if (mdscr & (MDSCR_EL1_KDE | MDSCR_EL1_MDE))
347+
vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
348+
else
349+
vcpu->arch.debug_owner = VCPU_DEBUG_FREE;
350+
}
351+
}
352+
353+
/*
354+
* Updates ownership of the debug registers after a trapped guest access to a
355+
* breakpoint/watchpoint register. Host ownership of the debug registers is of
356+
* strictly higher priority, and it is the responsibility of the VMM to emulate
357+
* guest debug exceptions in this configuration.
358+
*/
359+
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu)
360+
{
361+
if (kvm_host_owns_debug_regs(vcpu))
362+
return;
363+
364+
vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
365+
}

arch/arm64/kvm/sys_regs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
656656
if (p->is_write)
657657
vcpu_set_flag(vcpu, DEBUG_DIRTY);
658658

659+
kvm_debug_set_guest_ownership(vcpu);
659660
trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
660661

661662
return true;
@@ -684,6 +685,7 @@ static void reg_to_dbg(struct kvm_vcpu *vcpu,
684685
val |= (p->regval & (mask >> shift)) << shift;
685686
*dbg_reg = val;
686687

688+
kvm_debug_set_guest_ownership(vcpu);
687689
vcpu_set_flag(vcpu, DEBUG_DIRTY);
688690
}
689691

0 commit comments

Comments
 (0)