mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-05 18:13:26 -04:00
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 <james.clark@linaro.org> Signed-off-by: Oliver Upton <oliver.upton@linux.dev> Link: https://lore.kernel.org/r/20241219224116.3941496-7-oliver.upton@linux.dev Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
committed by
Marc Zyngier
parent
b47ffd13fd
commit
cd9b10102a
@@ -756,6 +756,12 @@ struct kvm_vcpu_arch {
|
||||
struct kvm_guest_debug_arch vcpu_debug_state;
|
||||
struct kvm_guest_debug_arch external_debug_state;
|
||||
|
||||
enum {
|
||||
VCPU_DEBUG_FREE,
|
||||
VCPU_DEBUG_HOST_OWNED,
|
||||
VCPU_DEBUG_GUEST_OWNED,
|
||||
} debug_owner;
|
||||
|
||||
/* VGIC state */
|
||||
struct vgic_cpu vgic_cpu;
|
||||
struct arch_timer_cpu timer_cpu;
|
||||
@@ -1345,10 +1351,15 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu);
|
||||
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
|
||||
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
|
||||
void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
|
||||
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu);
|
||||
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
|
||||
|
||||
#define kvm_vcpu_os_lock_enabled(vcpu) \
|
||||
(!!(__vcpu_sys_reg(vcpu, OSLSR_EL1) & OSLSR_EL1_OSLK))
|
||||
|
||||
#define kvm_host_owns_debug_regs(vcpu) \
|
||||
((vcpu)->arch.debug_owner == VCPU_DEBUG_HOST_OWNED)
|
||||
|
||||
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr);
|
||||
int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
|
||||
|
||||
@@ -598,6 +598,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
|
||||
kvm_vgic_load(vcpu);
|
||||
kvm_timer_vcpu_load(vcpu);
|
||||
kvm_vcpu_load_debug(vcpu);
|
||||
if (has_vhe())
|
||||
kvm_vcpu_load_vhe(vcpu);
|
||||
kvm_arch_vcpu_load_fp(vcpu);
|
||||
|
||||
@@ -317,3 +317,49 @@ void kvm_init_host_debug_data(void)
|
||||
!(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
|
||||
host_data_set_flag(HAS_TRBE);
|
||||
}
|
||||
|
||||
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 mdscr;
|
||||
|
||||
/* Must be called before kvm_vcpu_load_vhe() */
|
||||
KVM_BUG_ON(vcpu_get_flag(vcpu, SYSREGS_ON_CPU), vcpu->kvm);
|
||||
|
||||
/*
|
||||
* Determine which of the possible debug states we're in:
|
||||
*
|
||||
* - VCPU_DEBUG_HOST_OWNED: KVM has taken ownership of the guest's
|
||||
* breakpoint/watchpoint registers, or needs to use MDSCR_EL1 to do
|
||||
* software step or emulate the effects of the OS Lock being enabled.
|
||||
*
|
||||
* - VCPU_DEBUG_GUEST_OWNED: The guest has debug exceptions enabled, and
|
||||
* the breakpoint/watchpoint registers need to be loaded eagerly.
|
||||
*
|
||||
* - VCPU_DEBUG_FREE: Neither of the above apply, no breakpoint/watchpoint
|
||||
* context needs to be loaded on the CPU.
|
||||
*/
|
||||
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
|
||||
vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
|
||||
} else {
|
||||
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
|
||||
|
||||
if (mdscr & (MDSCR_EL1_KDE | MDSCR_EL1_MDE))
|
||||
vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
|
||||
else
|
||||
vcpu->arch.debug_owner = VCPU_DEBUG_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates ownership of the debug registers after a trapped guest access to a
|
||||
* breakpoint/watchpoint register. Host ownership of the debug registers is of
|
||||
* strictly higher priority, and it is the responsibility of the VMM to emulate
|
||||
* guest debug exceptions in this configuration.
|
||||
*/
|
||||
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_host_owns_debug_regs(vcpu))
|
||||
return;
|
||||
|
||||
vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
|
||||
}
|
||||
|
||||
@@ -656,6 +656,7 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
|
||||
if (p->is_write)
|
||||
vcpu_set_flag(vcpu, DEBUG_DIRTY);
|
||||
|
||||
kvm_debug_set_guest_ownership(vcpu);
|
||||
trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
|
||||
|
||||
return true;
|
||||
@@ -684,6 +685,7 @@ static void reg_to_dbg(struct kvm_vcpu *vcpu,
|
||||
val |= (p->regval & (mask >> shift)) << shift;
|
||||
*dbg_reg = val;
|
||||
|
||||
kvm_debug_set_guest_ownership(vcpu);
|
||||
vcpu_set_flag(vcpu, DEBUG_DIRTY);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user