Skip to content

Commit

Permalink
Merge branch kvm-arm64/debug-6.14 into kvmarm-master/next
Browse files Browse the repository at this point in the history
* 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: Marc Zyngier <maz@kernel.org>
  • Loading branch information
Marc Zyngier committed Jan 12, 2025
2 parents 78d4f34 + c4a6ed8 commit b7bf7c8
Show file tree
Hide file tree
Showing 16 changed files with 350 additions and 650 deletions.
5 changes: 1 addition & 4 deletions arch/arm64/include/asm/kvm_asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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" \
Expand Down
94 changes: 50 additions & 44 deletions arch/arm64/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down Expand Up @@ -642,7 +648,7 @@ struct kvm_host_data {
* host_debug_state contains the host registers which are
* saved and restored during world switches.
*/
struct {
struct {
/* {Break,watch}point registers */
struct kvm_guest_debug_arch regs;
/* Statistical profiling extension */
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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() */
Expand Down Expand Up @@ -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)
{
Expand All @@ -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,
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/include/asm/kvm_nested.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 3 additions & 11 deletions arch/arm64/kvm/arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

/**************************************************************
Expand All @@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down
Loading

0 comments on commit b7bf7c8

Please sign in to comment.