Commit b7bf7c87 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/debug-6.14 into kvmarm-master/next



* kvm-arm64/debug-6.14:
  : .
  : Large rework of the debug code to make it a bit less horrid,
  : courtesy of Oliver Upton. From the original cover letter:
  :
  : "The debug code has become a bit difficult to reason about, especially
  : all the hacks and bandaids for state tracking + trap configuration.
  :
  : This series reworks the entire mess around using a single enumeration to
  : track the state of the debug registers (free, guest-owned, host-owned),
  : using that to drive trap configuration and save/restore.
  :
  : On top of that, this series wires most of the implementation into vCPU
  : load/put rather than the main KVM_RUN loop. This has been a long time
  : coming for VHE, as a lot of the trap configuration and EL1 state gets
  : loaded into hardware at that point anyway.
  :
  : The save/restore of the debug registers is simplified quite a bit as
  : well. KVM will now restore the registers for *any* access rather than
  : just writes, and keep doing so until the next vcpu_put() instead of
  : dropping it on the floor after the next exception."
  : .
  KVM: arm64: Promote guest ownership for DBGxVR/DBGxCR reads
  KVM: arm64: Fold DBGxVR/DBGxCR accessors into common set
  KVM: arm64: Avoid reading ID_AA64DFR0_EL1 for debug save/restore
  KVM: arm64: nv: Honor MDCR_EL2.TDE routing for debug exceptions
  KVM: arm64: Manage software step state at load/put
  KVM: arm64: Don't hijack guest context MDSCR_EL1
  KVM: arm64: Compute MDCR_EL2 at vcpu_load()
  KVM: arm64: Reload vCPU for accesses to OSLAR_EL1
  KVM: arm64: Use debug_owner to track if debug regs need save/restore
  KVM: arm64: Remove vestiges of debug_ptr
  KVM: arm64: Remove debug tracepoints
  KVM: arm64: Select debug state to save/restore based on debug owner
  KVM: arm64: Clean up KVM_SET_GUEST_DEBUG handler
  KVM: arm64: Evaluate debug owner at vcpu_load()
  KVM: arm64: Write MDCR_EL2 directly from kvm_arm_setup_mdcr_el2()
  KVM: arm64: Move host SME/SVE tracking flags to host data
  KVM: arm64: Track presence of SPE/TRBE in kvm_host_data instead of vCPU
  KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts
  KVM: arm64: Drop MDSCR_EL1_DEBUG_MASK

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents 78d4f34e c4a6ed85
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -53,8 +53,7 @@
enum __kvm_host_smccc_func {
	/* Hypercalls available only prior to pKVM finalisation */
	/* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */
	__KVM_HOST_SMCCC_FUNC___kvm_get_mdcr_el2 = __KVM_HOST_SMCCC_FUNC___kvm_hyp_init + 1,
	__KVM_HOST_SMCCC_FUNC___pkvm_init,
	__KVM_HOST_SMCCC_FUNC___pkvm_init = __KVM_HOST_SMCCC_FUNC___kvm_hyp_init + 1,
	__KVM_HOST_SMCCC_FUNC___pkvm_create_private_mapping,
	__KVM_HOST_SMCCC_FUNC___pkvm_cpu_set_vector,
	__KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs,
@@ -247,8 +246,6 @@ extern void __kvm_adjust_pc(struct kvm_vcpu *vcpu);
extern u64 __vgic_v3_get_gic_config(void);
extern void __vgic_v3_init_lrs(void);

extern u64 __kvm_get_mdcr_el2(void);

#define __KVM_EXTABLE(from, to)						\
	"	.pushsection	__kvm_ex_table, \"a\"\n"		\
	"	.align		3\n"					\
+50 −44
Original line number Diff line number Diff line
@@ -610,6 +610,12 @@ struct cpu_sve_state {
 * field.
 */
struct kvm_host_data {
#define KVM_HOST_DATA_FLAG_HAS_SPE			0
#define KVM_HOST_DATA_FLAG_HAS_TRBE			1
#define KVM_HOST_DATA_FLAG_HOST_SVE_ENABLED		2
#define KVM_HOST_DATA_FLAG_HOST_SME_ENABLED		3
	unsigned long flags;

	struct kvm_cpu_context host_ctxt;

	/*
@@ -652,6 +658,13 @@ struct kvm_host_data {
		/* Values of trap registers for the host before guest entry. */
		u64 mdcr_el2;
	} host_debug_state;

	/* Number of programmable event counters (PMCR_EL0.N) for this CPU */
	unsigned int nr_event_counters;

	/* Number of debug breakpoints/watchpoints for this CPU (minus 1) */
	unsigned int debug_brps;
	unsigned int debug_wrps;
};

struct kvm_host_psci_config {
@@ -739,31 +752,22 @@ struct kvm_vcpu_arch {
	 *
	 * external_debug_state contains the debug values we want to debug the
	 * guest. This is set via the KVM_SET_GUEST_DEBUG ioctl.
	 *
	 * debug_ptr points to the set of debug registers that should be loaded
	 * onto the hardware when running the guest.
	 */
	struct kvm_guest_debug_arch *debug_ptr;
	struct kvm_guest_debug_arch vcpu_debug_state;
	struct kvm_guest_debug_arch external_debug_state;
	u64 external_mdscr_el1;

	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;
	struct kvm_pmu pmu;

	/*
	 * Guest registers we preserve during guest debugging.
	 *
	 * These shadow registers are updated by the kvm_handle_sys_reg
	 * trap handler if the guest accesses or updates them while we
	 * are using guest debug.
	 */
	struct {
		u32	mdscr_el1;
		bool	pstate_ss;
	} guest_debug_preserved;

	/* vcpu power state */
	struct kvm_mp_state mp_state;
	spinlock_t mp_state_lock;
@@ -906,29 +910,21 @@ struct kvm_vcpu_arch {
#define EXCEPT_AA64_EL2_IRQ	__vcpu_except_flags(5)
#define EXCEPT_AA64_EL2_FIQ	__vcpu_except_flags(6)
#define EXCEPT_AA64_EL2_SERR	__vcpu_except_flags(7)
/* Guest debug is live */
#define DEBUG_DIRTY		__vcpu_single_flag(iflags, BIT(4))
/* Save SPE context if active  */
#define DEBUG_STATE_SAVE_SPE	__vcpu_single_flag(iflags, BIT(5))
/* Save TRBE context if active  */
#define DEBUG_STATE_SAVE_TRBE	__vcpu_single_flag(iflags, BIT(6))

/* SVE enabled for host EL0 */
#define HOST_SVE_ENABLED	__vcpu_single_flag(sflags, BIT(0))
/* SME enabled for EL0 */
#define HOST_SME_ENABLED	__vcpu_single_flag(sflags, BIT(1))

/* Physical CPU not in supported_cpus */
#define ON_UNSUPPORTED_CPU	__vcpu_single_flag(sflags, BIT(2))
#define ON_UNSUPPORTED_CPU	__vcpu_single_flag(sflags, BIT(0))
/* WFIT instruction trapped */
#define IN_WFIT			__vcpu_single_flag(sflags, BIT(3))
#define IN_WFIT			__vcpu_single_flag(sflags, BIT(1))
/* vcpu system registers loaded on physical CPU */
#define SYSREGS_ON_CPU		__vcpu_single_flag(sflags, BIT(4))
/* Software step state is Active-pending */
#define DBG_SS_ACTIVE_PENDING	__vcpu_single_flag(sflags, BIT(5))
#define SYSREGS_ON_CPU		__vcpu_single_flag(sflags, BIT(2))
/* Software step state is Active-pending for external debug */
#define HOST_SS_ACTIVE_PENDING	__vcpu_single_flag(sflags, BIT(3))
/* Software step state is Active pending for guest debug */
#define GUEST_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(4))
/* PMUSERENR for the guest EL0 is on physical CPU */
#define PMUSERENR_ON_CPU	__vcpu_single_flag(sflags, BIT(6))
#define PMUSERENR_ON_CPU	__vcpu_single_flag(sflags, BIT(5))
/* WFI instruction trapped */
#define IN_WFI			__vcpu_single_flag(sflags, BIT(7))
#define IN_WFI			__vcpu_single_flag(sflags, BIT(6))


/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
@@ -1307,6 +1303,13 @@ DECLARE_KVM_HYP_PER_CPU(struct kvm_host_data, kvm_host_data);
	 &this_cpu_ptr_hyp_sym(kvm_host_data)->f)
#endif

#define host_data_test_flag(flag)					\
	(test_bit(KVM_HOST_DATA_FLAG_##flag, host_data_ptr(flags)))
#define host_data_set_flag(flag)					\
	set_bit(KVM_HOST_DATA_FLAG_##flag, host_data_ptr(flags))
#define host_data_clear_flag(flag)					\
	clear_bit(KVM_HOST_DATA_FLAG_##flag, host_data_ptr(flags))

/* Check whether the FP regs are owned by the guest */
static inline bool guest_owns_fp_regs(void)
{
@@ -1332,15 +1335,22 @@ static inline bool kvm_system_needs_idmapped_vectors(void)

static inline void kvm_arch_sync_events(struct kvm *kvm) {}

void kvm_arm_init_debug(void);
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_init_host_debug_data(void);
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu);
void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu);
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val);

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

#define kvm_debug_regs_in_use(vcpu)		\
	((vcpu)->arch.debug_owner != VCPU_DEBUG_FREE)
#define kvm_host_owns_debug_regs(vcpu)		\
	((vcpu)->arch.debug_owner == VCPU_DEBUG_HOST_OWNED)
#define kvm_guest_owns_debug_regs(vcpu)		\
	((vcpu)->arch.debug_owner == VCPU_DEBUG_GUEST_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,
@@ -1367,10 +1377,6 @@ static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr)
	return (!has_vhe() && attr->exclude_host);
}

/* Flags for host debug state */
void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu);
void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu);

#ifdef CONFIG_KVM
void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr);
void kvm_clr_pmu_events(u64 clr);
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)
}

extern bool forward_smc_trap(struct kvm_vcpu *vcpu);
extern bool forward_debug_exception(struct kvm_vcpu *vcpu);
extern void kvm_init_nested(struct kvm *kvm);
extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu);
extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu);
+3 −11
Original line number Diff line number Diff line
@@ -476,8 +476,6 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)

	kvm_pmu_vcpu_init(vcpu);

	kvm_arm_reset_debug_ptr(vcpu);

	kvm_arm_pvtime_vcpu_init(&vcpu->arch);

	vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu;
@@ -598,6 +596,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);
@@ -617,15 +616,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)

	vcpu_set_pauth_traps(vcpu);

	kvm_arch_vcpu_load_debug_state_flags(vcpu);

	if (!cpumask_test_cpu(cpu, vcpu->kvm->arch.supported_cpus))
		vcpu_set_on_unsupported_cpu(vcpu);
}

void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
{
	kvm_arch_vcpu_put_debug_state_flags(vcpu);
	kvm_vcpu_put_debug(vcpu);
	kvm_arch_vcpu_put_fp(vcpu);
	if (has_vhe())
		kvm_vcpu_put_vhe(vcpu);
@@ -808,8 +805,6 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)

	kvm_init_mpidr_data(kvm);

	kvm_arm_vcpu_init_debug(vcpu);

	if (likely(irqchip_in_kernel(kvm))) {
		/*
		 * Map the VGIC hardware resources before running a vcpu the
@@ -1187,7 +1182,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
			continue;
		}

		kvm_arm_setup_debug(vcpu);
		kvm_arch_vcpu_ctxflush_fp(vcpu);

		/**************************************************************
@@ -1204,8 +1198,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
		 * Back from guest
		 *************************************************************/

		kvm_arm_clear_debug(vcpu);

		/*
		 * We must sync the PMU state before the vgic state so
		 * that the vgic can properly sample the updated state of the
@@ -2109,6 +2101,7 @@ static void cpu_set_hyp_vector(void)
static void cpu_hyp_init_context(void)
{
	kvm_init_host_cpu_context(host_data_ptr(host_ctxt));
	kvm_init_host_debug_data();

	if (!is_kernel_in_hyp_mode())
		cpu_init_hyp_mode();
@@ -2117,7 +2110,6 @@ static void cpu_hyp_init_context(void)
static void cpu_hyp_init_features(void)
{
	cpu_set_hyp_vector();
	kvm_arm_init_debug();

	if (is_kernel_in_hyp_mode())
		kvm_timer_init_vhe();
+128 −252
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@
 * Debug and Guest Debug support
 *
 * Copyright (C) 2015 - Linaro Ltd
 * Author: Alex Bennée <alex.bennee@linaro.org>
 * Authors: Alex Bennée <alex.bennee@linaro.org>
 * 	    Oliver Upton <oliver.upton@linux.dev>
 */

#include <linux/kvm_host.h>
@@ -14,72 +15,6 @@
#include <asm/kvm_arm.h>
#include <asm/kvm_emulate.h>

#include "trace.h"

/* These are the bits of MDSCR_EL1 we may manipulate */
#define MDSCR_EL1_DEBUG_MASK	(DBG_MDSCR_SS | \
				DBG_MDSCR_KDE | \
				DBG_MDSCR_MDE)

static DEFINE_PER_CPU(u64, mdcr_el2);

/*
 * save/restore_guest_debug_regs
 *
 * For some debug operations we need to tweak some guest registers. As
 * a result we need to save the state of those registers before we
 * make those modifications.
 *
 * Guest access to MDSCR_EL1 is trapped by the hypervisor and handled
 * after we have restored the preserved value to the main context.
 *
 * When single-step is enabled by userspace, we tweak PSTATE.SS on every
 * guest entry. Preserve PSTATE.SS so we can restore the original value
 * for the vcpu after the single-step is disabled.
 */
static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
{
	u64 val = vcpu_read_sys_reg(vcpu, MDSCR_EL1);

	vcpu->arch.guest_debug_preserved.mdscr_el1 = val;

	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
				vcpu->arch.guest_debug_preserved.mdscr_el1);

	vcpu->arch.guest_debug_preserved.pstate_ss =
					(*vcpu_cpsr(vcpu) & DBG_SPSR_SS);
}

static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
{
	u64 val = vcpu->arch.guest_debug_preserved.mdscr_el1;

	vcpu_write_sys_reg(vcpu, val, MDSCR_EL1);

	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
				vcpu_read_sys_reg(vcpu, MDSCR_EL1));

	if (vcpu->arch.guest_debug_preserved.pstate_ss)
		*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
	else
		*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
}

/**
 * kvm_arm_init_debug - grab what we need for debug
 *
 * Currently the sole task of this function is to retrieve the initial
 * value of mdcr_el2 so we can preserve MDCR_EL2.HPMN which has
 * presumably been set-up by some knowledgeable bootcode.
 *
 * It is called once per-cpu during CPU hyp initialisation.
 */

void kvm_arm_init_debug(void)
{
	__this_cpu_write(mdcr_el2, kvm_call_hyp_ret(__kvm_get_mdcr_el2));
}

/**
 * kvm_arm_setup_mdcr_el2 - configure vcpu mdcr_el2 value
 *
@@ -95,11 +30,14 @@ void kvm_arm_init_debug(void)
 */
static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
{
	preempt_disable();

	/*
	 * This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK
	 * to disable guest access to the profiling and trace buffers
	 */
	vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK;
	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN,
					 *host_data_ptr(nr_event_counters));
	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
				MDCR_EL2_TPMS |
				MDCR_EL2_TTRF |
@@ -113,233 +51,171 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE;

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

	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
}
	/* Write MDCR_EL2 directly if we're already at EL2 */
	if (has_vhe())
		write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);

/**
 * kvm_arm_vcpu_init_debug - setup vcpu debug traps
 *
 * @vcpu:	the vcpu pointer
 *
 * Set vcpu initial mdcr_el2 value.
 */
void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu)
{
	preempt_disable();
	kvm_arm_setup_mdcr_el2(vcpu);
	preempt_enable();
}

/**
 * kvm_arm_reset_debug_ptr - reset the debug ptr to point to the vcpu state
 * @vcpu:	the vcpu pointer
 */

void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
void kvm_init_host_debug_data(void)
{
	vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state;
}
	u64 dfr0 = read_sysreg(id_aa64dfr0_el1);

/**
 * kvm_arm_setup_debug - set up debug related stuff
 *
 * @vcpu:	the vcpu pointer
 *
 * This is called before each entry into the hypervisor to setup any
 * debug related registers.
 *
 * Additionally, KVM only traps guest accesses to the debug registers if
 * the guest is not actively using them (see the DEBUG_DIRTY
 * flag on vcpu->arch.iflags).  Since the guest must not interfere
 * with the hardware state when debugging the guest, we must ensure that
 * trapping is enabled whenever we are debugging the guest using the
 * debug registers.
 */
	if (cpuid_feature_extract_signed_field(dfr0, ID_AA64DFR0_EL1_PMUVer_SHIFT) > 0)
		*host_data_ptr(nr_event_counters) = FIELD_GET(ARMV8_PMU_PMCR_N,
							      read_sysreg(pmcr_el0));

void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
{
	unsigned long mdscr, orig_mdcr_el2 = vcpu->arch.mdcr_el2;
	*host_data_ptr(debug_brps) = SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, dfr0);
	*host_data_ptr(debug_wrps) = SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, dfr0);

	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
	if (has_vhe())
		return;

	kvm_arm_setup_mdcr_el2(vcpu);
	if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_PMSVer_SHIFT) &&
	    !(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P))
		host_data_set_flag(HAS_SPE);

	/* Check if we need to use the debug registers. */
	if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
		/* Save guest debug state */
		save_guest_debug_regs(vcpu);
	if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceBuffer_SHIFT) &&
	    !(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
		host_data_set_flag(HAS_TRBE);
}

/*
		 * Single Step (ARM ARM D2.12.3 The software step state
		 * machine)
 * Configures the 'external' MDSCR_EL1 value for the guest, i.e. when the host
 * has taken over MDSCR_EL1.
 *
		 * If we are doing Single Step we need to manipulate
		 * the guest's MDSCR_EL1.SS and PSTATE.SS. Once the
		 * step has occurred the hypervisor will trap the
		 * debug exception and we return to userspace.
 *  - Userspace is single-stepping the guest, and MDSCR_EL1.SS is forced to 1.
 *
		 * If the guest attempts to single step its userspace
		 * we would have to deal with a trapped exception
		 * while in the guest kernel. Because this would be
		 * hard to unwind we suppress the guest's ability to
		 * do so by masking MDSCR_EL.SS.
 *  - Userspace is using the breakpoint/watchpoint registers to debug the
 *    guest, and MDSCR_EL1.MDE is forced to 1.
 *
		 * This confuses guest debuggers which use
		 * single-step behind the scenes but everything
		 * returns to normal once the host is no longer
		 * debugging the system.
 *  - The guest has enabled the OS Lock, and KVM is forcing MDSCR_EL1.MDE to 0,
 *    masking all debug exceptions affected by the OS Lock.
 */
		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
static void setup_external_mdscr(struct kvm_vcpu *vcpu)
{
	/*
			 * If the software step state at the last guest exit
			 * was Active-pending, we don't set DBG_SPSR_SS so
			 * that the state is maintained (to not run another
			 * single-step until the pending Software Step
			 * exception is taken).
	 * Use the guest's MDSCR_EL1 as a starting point, since there are
	 * several other features controlled by MDSCR_EL1 that are not relevant
	 * to the host.
	 *
	 * Clear the bits that KVM may use which also satisfies emulation of
	 * the OS Lock as MDSCR_EL1.MDE is cleared.
	 */
			if (!vcpu_get_flag(vcpu, DBG_SS_ACTIVE_PENDING))
				*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
			else
				*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
	u64 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1) & ~(MDSCR_EL1_SS |
							   MDSCR_EL1_MDE |
							   MDSCR_EL1_KDE);

			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
			mdscr |= DBG_MDSCR_SS;
			vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
		} else {
			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
			mdscr &= ~DBG_MDSCR_SS;
			vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
		mdscr |= MDSCR_EL1_SS;

	if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW)
		mdscr |= MDSCR_EL1_MDE | MDSCR_EL1_KDE;

	vcpu->arch.external_mdscr_el1 = mdscr;
}

		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
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);

	/*
		 * HW Breakpoints and watchpoints
	 * 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.
	 *
		 * We simply switch the debug_ptr to point to our new
		 * external_debug_state which has been populated by the
		 * debug ioctl. The existing DEBUG_DIRTY mechanism ensures
		 * the registers are updated on the world switch.
	 *  - 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_GUESTDBG_USE_HW) {
			/* Enable breakpoints/watchpoints */
			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
			mdscr |= DBG_MDSCR_MDE;
			vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);

			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
			vcpu_set_flag(vcpu, DEBUG_DIRTY);

			trace_kvm_arm_set_regset("BKPTS", get_num_brps(),
						&vcpu->arch.debug_ptr->dbg_bcr[0],
						&vcpu->arch.debug_ptr->dbg_bvr[0]);

			trace_kvm_arm_set_regset("WAPTS", get_num_wrps(),
						&vcpu->arch.debug_ptr->dbg_wcr[0],
						&vcpu->arch.debug_ptr->dbg_wvr[0]);
	if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
		vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
		setup_external_mdscr(vcpu);

		/*
		 * The OS Lock blocks debug exceptions in all ELs when it is
		 * enabled. If the guest has enabled the OS Lock, constrain its
		 * effects to the guest. Emulate the behavior by clearing
		 * MDSCR_EL1.MDE. In so doing, we ensure that host debug
		 * exceptions are unaffected by guest configuration of the OS
		 * Lock.
		 * Steal the guest's single-step state machine if userspace wants
		 * single-step the guest.
		 */
		} else if (kvm_vcpu_os_lock_enabled(vcpu)) {
			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
			mdscr &= ~DBG_MDSCR_MDE;
			vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
		}
	}

	BUG_ON(!vcpu->guest_debug &&
		vcpu->arch.debug_ptr != &vcpu->arch.vcpu_debug_state);
		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
			if (*vcpu_cpsr(vcpu) & DBG_SPSR_SS)
				vcpu_clear_flag(vcpu, GUEST_SS_ACTIVE_PENDING);
			else
				vcpu_set_flag(vcpu, GUEST_SS_ACTIVE_PENDING);

	/* If KDE or MDE are set, perform a full save/restore cycle. */
	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
		vcpu_set_flag(vcpu, DEBUG_DIRTY);
			if (!vcpu_get_flag(vcpu, HOST_SS_ACTIVE_PENDING))
				*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
			else
				*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
		}
	} else {
		mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);

	/* Write mdcr_el2 changes since vcpu_load on VHE systems */
	if (has_vhe() && orig_mdcr_el2 != vcpu->arch.mdcr_el2)
		write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
		if (mdscr & (MDSCR_EL1_KDE | MDSCR_EL1_MDE))
			vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
		else
			vcpu->arch.debug_owner = VCPU_DEBUG_FREE;
	}

	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_read_sys_reg(vcpu, MDSCR_EL1));
	kvm_arm_setup_mdcr_el2(vcpu);
}

void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu)
{
	trace_kvm_arm_clear_debug(vcpu->guest_debug);
	if (likely(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)))
		return;

	/*
	 * Restore the guest's debug registers if we were using them.
	 * Save the host's software step state and restore the guest's before
	 * potentially returning to userspace.
	 */
	if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
	if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS))
				/*
				 * Mark the vcpu as ACTIVE_PENDING
				 * until Software Step exception is taken.
				 */
				vcpu_set_flag(vcpu, DBG_SS_ACTIVE_PENDING);
		}
		vcpu_set_flag(vcpu, HOST_SS_ACTIVE_PENDING);
	else
		vcpu_clear_flag(vcpu, HOST_SS_ACTIVE_PENDING);

		restore_guest_debug_regs(vcpu);
	if (vcpu_get_flag(vcpu, GUEST_SS_ACTIVE_PENDING))
		*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
	else
		*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
}

/*
		 * If we were using HW debug we need to restore the
		 * debug_ptr to the guest debug state.
 * 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.
 */
		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
			kvm_arm_reset_debug_ptr(vcpu);

			trace_kvm_arm_set_regset("BKPTS", get_num_brps(),
						&vcpu->arch.debug_ptr->dbg_bcr[0],
						&vcpu->arch.debug_ptr->dbg_bvr[0]);

			trace_kvm_arm_set_regset("WAPTS", get_num_wrps(),
						&vcpu->arch.debug_ptr->dbg_wcr[0],
						&vcpu->arch.debug_ptr->dbg_wvr[0]);
		}
	}
}

void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu)
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu)
{
	u64 dfr0;

	/* For VHE, there is nothing to do */
	if (has_vhe())
	if (kvm_host_owns_debug_regs(vcpu))
		return;

	dfr0 = read_sysreg(id_aa64dfr0_el1);
	/*
	 * If SPE is present on this CPU and is available at current EL,
	 * we may need to check if the host state needs to be saved.
	 */
	if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_PMSVer_SHIFT) &&
	    !(read_sysreg_s(SYS_PMBIDR_EL1) & BIT(PMBIDR_EL1_P_SHIFT)))
		vcpu_set_flag(vcpu, DEBUG_STATE_SAVE_SPE);

	/* Check if we have TRBE implemented and available at the host */
	if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_TraceBuffer_SHIFT) &&
	    !(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_EL1_P))
		vcpu_set_flag(vcpu, DEBUG_STATE_SAVE_TRBE);
	vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
	kvm_arm_setup_mdcr_el2(vcpu);
}

void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu)
void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val)
{
	vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_SPE);
	vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_TRBE);
	if (val & OSLAR_EL1_OSLK)
		__vcpu_sys_reg(vcpu, OSLSR_EL1) |= OSLSR_EL1_OSLK;
	else
		__vcpu_sys_reg(vcpu, OSLSR_EL1) &= ~OSLSR_EL1_OSLK;

	preempt_disable();
	kvm_arch_vcpu_put(vcpu);
	kvm_arch_vcpu_load(vcpu, smp_processor_id());
	preempt_enable();
}
Loading