* [PATCH v2 01/16] KVM: arm64: Drop MDSCR_EL1_DEBUG_MASK
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 02/16] KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts Oliver Upton
` (15 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
Nothing is using this macro, get rid of it.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/kvm/debug.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index ce8886122ed3..587e9eb4372e 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -16,11 +16,6 @@
#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);
/*
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 02/16] KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
2024-11-15 22:49 ` [PATCH v2 01/16] KVM: arm64: Drop MDSCR_EL1_DEBUG_MASK Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-28 19:35 ` Colton Lewis
2024-11-15 22:49 ` [PATCH v2 03/16] KVM: arm64: Track presence of SPE/TRBE in kvm_host_data instead of vCPU Oliver Upton
` (14 subsequent siblings)
16 siblings, 1 reply; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
KVM caches MDCR_EL2 on a per-CPU basis in order to preserve the
configuration of MDCR_EL2.HPMN while running a guest. This is a bit
gross, since we're relying on some baked configuration rather than the
hardware definition of implemented counters.
Discover the number of implemented counters by reading PMCR_EL0.N
instead. This works because:
- In VHE the kernel runs at EL2, and N always returns the number of
counters implemented in hardware
- In {n,h}VHE, the EL2 setup code programs MDCR_EL2.HPMN with the EL2
view of PMCR_EL0.N for the host
Lastly, avoid traps under nested virtualization by saving PMCR_EL0.N in
host data.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_asm.h | 5 +----
arch/arm64/include/asm/kvm_host.h | 7 +++++--
arch/arm64/kvm/arm.c | 2 +-
arch/arm64/kvm/debug.c | 29 +++++++++++------------------
arch/arm64/kvm/hyp/nvhe/debug-sr.c | 5 -----
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 ------
arch/arm64/kvm/hyp/vhe/debug-sr.c | 5 -----
7 files changed, 18 insertions(+), 41 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index ca2590344313..063185c202ce 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -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" \
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f333b189fb43..ad514434f3fe 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -642,7 +642,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 */
@@ -652,6 +652,9 @@ 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;
};
struct kvm_host_psci_config {
@@ -1332,7 +1335,7 @@ 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_init_host_debug_data(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);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index a102c3aebdbc..ab1bf9ccf385 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2109,6 +2109,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 +2118,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();
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 587e9eb4372e..d8ea6fe6a2a2 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -16,8 +16,6 @@
#include "trace.h"
-static DEFINE_PER_CPU(u64, mdcr_el2);
-
/*
* save/restore_guest_debug_regs
*
@@ -60,21 +58,6 @@ static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
*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
*
@@ -94,7 +77,8 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
* 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 |
@@ -338,3 +322,12 @@ void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu)
vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_SPE);
vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_TRBE);
}
+
+void kvm_init_host_debug_data(void)
+{
+ u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
+
+ 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));
+}
diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
index 53efda0235cf..1e2a26d0196e 100644
--- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
@@ -106,8 +106,3 @@ void __debug_switch_to_host(struct kvm_vcpu *vcpu)
{
__debug_switch_to_host_common(vcpu);
}
-
-u64 __kvm_get_mdcr_el2(void)
-{
- return read_sysreg(mdcr_el2);
-}
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 6aa0b13d86e5..16f5da3a884a 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -264,11 +264,6 @@ static void handle___vgic_v3_init_lrs(struct kvm_cpu_context *host_ctxt)
__vgic_v3_init_lrs();
}
-static void handle___kvm_get_mdcr_el2(struct kvm_cpu_context *host_ctxt)
-{
- cpu_reg(host_ctxt, 1) = __kvm_get_mdcr_el2();
-}
-
static void handle___vgic_v3_save_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1);
@@ -384,7 +379,6 @@ typedef void (*hcall_t)(struct kvm_cpu_context *);
static const hcall_t host_hcall[] = {
/* ___kvm_hyp_init */
- HANDLE_FUNC(__kvm_get_mdcr_el2),
HANDLE_FUNC(__pkvm_init),
HANDLE_FUNC(__pkvm_create_private_mapping),
HANDLE_FUNC(__pkvm_cpu_set_vector),
diff --git a/arch/arm64/kvm/hyp/vhe/debug-sr.c b/arch/arm64/kvm/hyp/vhe/debug-sr.c
index 289689b2682d..0100339b09e0 100644
--- a/arch/arm64/kvm/hyp/vhe/debug-sr.c
+++ b/arch/arm64/kvm/hyp/vhe/debug-sr.c
@@ -19,8 +19,3 @@ void __debug_switch_to_host(struct kvm_vcpu *vcpu)
{
__debug_switch_to_host_common(vcpu);
}
-
-u64 __kvm_get_mdcr_el2(void)
-{
- return read_sysreg(mdcr_el2);
-}
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v2 02/16] KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts
2024-11-15 22:49 ` [PATCH v2 02/16] KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts Oliver Upton
@ 2024-11-28 19:35 ` Colton Lewis
2024-11-29 7:26 ` Oliver Upton
0 siblings, 1 reply; 22+ messages in thread
From: Colton Lewis @ 2024-11-28 19:35 UTC (permalink / raw)
To: Oliver Upton
Cc: kvmarm, maz, joey.gouly, suzuki.poulose, yuzenghui, mizhang,
alexandru.elisei, oliver.upton
Hey Oliver,
Oliver Upton <oliver.upton@linux.dev> writes:
> KVM caches MDCR_EL2 on a per-CPU basis in order to preserve the
> configuration of MDCR_EL2.HPMN while running a guest. This is a bit
> gross, since we're relying on some baked configuration rather than the
> hardware definition of implemented counters.
> Discover the number of implemented counters by reading PMCR_EL0.N
> instead. This works because:
> - In VHE the kernel runs at EL2, and N always returns the number of
> counters implemented in hardware
> - In {n,h}VHE, the EL2 setup code programs MDCR_EL2.HPMN with the EL2
> view of PMCR_EL0.N for the host
> Lastly, avoid traps under nested virtualization by saving PMCR_EL0.N in
> host data.
> Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
> ---
> arch/arm64/include/asm/kvm_asm.h | 5 +----
> arch/arm64/include/asm/kvm_host.h | 7 +++++--
> arch/arm64/kvm/arm.c | 2 +-
> arch/arm64/kvm/debug.c | 29 +++++++++++------------------
> arch/arm64/kvm/hyp/nvhe/debug-sr.c | 5 -----
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 ------
> arch/arm64/kvm/hyp/vhe/debug-sr.c | 5 -----
> 7 files changed, 18 insertions(+), 41 deletions(-)
> diff --git a/arch/arm64/include/asm/kvm_asm.h
> b/arch/arm64/include/asm/kvm_asm.h
> index ca2590344313..063185c202ce 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -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" \
> diff --git a/arch/arm64/include/asm/kvm_host.h
> b/arch/arm64/include/asm/kvm_host.h
> index f333b189fb43..ad514434f3fe 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -642,7 +642,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 */
> @@ -652,6 +652,9 @@ 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;
> };
> struct kvm_host_psci_config {
> @@ -1332,7 +1335,7 @@ 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_init_host_debug_data(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);
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index a102c3aebdbc..ab1bf9ccf385 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -2109,6 +2109,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 +2118,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();
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index 587e9eb4372e..d8ea6fe6a2a2 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -16,8 +16,6 @@
> #include "trace.h"
> -static DEFINE_PER_CPU(u64, mdcr_el2);
> -
> /*
> * save/restore_guest_debug_regs
> *
> @@ -60,21 +58,6 @@ static void restore_guest_debug_regs(struct kvm_vcpu
> *vcpu)
> *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
> *
> @@ -94,7 +77,8 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu
> *vcpu)
> * 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,
MDCR_EL2_HPMN is not defined
> + *host_data_ptr(nr_event_counters));
> vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
> MDCR_EL2_TPMS |
> MDCR_EL2_TTRF |
> @@ -338,3 +322,12 @@ void kvm_arch_vcpu_put_debug_state_flags(struct
> kvm_vcpu *vcpu)
> vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_SPE);
> vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_TRBE);
> }
> +
> +void kvm_init_host_debug_data(void)
> +{
> + u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
> +
> + 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));
> +}
> diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c
> b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
> index 53efda0235cf..1e2a26d0196e 100644
> --- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c
> +++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
> @@ -106,8 +106,3 @@ void __debug_switch_to_host(struct kvm_vcpu *vcpu)
> {
> __debug_switch_to_host_common(vcpu);
> }
> -
> -u64 __kvm_get_mdcr_el2(void)
> -{
> - return read_sysreg(mdcr_el2);
> -}
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 6aa0b13d86e5..16f5da3a884a 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -264,11 +264,6 @@ static void handle___vgic_v3_init_lrs(struct
> kvm_cpu_context *host_ctxt)
> __vgic_v3_init_lrs();
> }
> -static void handle___kvm_get_mdcr_el2(struct kvm_cpu_context *host_ctxt)
> -{
> - cpu_reg(host_ctxt, 1) = __kvm_get_mdcr_el2();
> -}
> -
> static void handle___vgic_v3_save_vmcr_aprs(struct kvm_cpu_context
> *host_ctxt)
> {
> DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1);
> @@ -384,7 +379,6 @@ typedef void (*hcall_t)(struct kvm_cpu_context *);
> static const hcall_t host_hcall[] = {
> /* ___kvm_hyp_init */
> - HANDLE_FUNC(__kvm_get_mdcr_el2),
> HANDLE_FUNC(__pkvm_init),
> HANDLE_FUNC(__pkvm_create_private_mapping),
> HANDLE_FUNC(__pkvm_cpu_set_vector),
> diff --git a/arch/arm64/kvm/hyp/vhe/debug-sr.c
> b/arch/arm64/kvm/hyp/vhe/debug-sr.c
> index 289689b2682d..0100339b09e0 100644
> --- a/arch/arm64/kvm/hyp/vhe/debug-sr.c
> +++ b/arch/arm64/kvm/hyp/vhe/debug-sr.c
> @@ -19,8 +19,3 @@ void __debug_switch_to_host(struct kvm_vcpu *vcpu)
> {
> __debug_switch_to_host_common(vcpu);
> }
> -
> -u64 __kvm_get_mdcr_el2(void)
> -{
> - return read_sysreg(mdcr_el2);
> -}
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v2 02/16] KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts
2024-11-28 19:35 ` Colton Lewis
@ 2024-11-29 7:26 ` Oliver Upton
0 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-29 7:26 UTC (permalink / raw)
To: Colton Lewis
Cc: kvmarm, maz, joey.gouly, suzuki.poulose, yuzenghui, mizhang,
alexandru.elisei
Hi Colton,
On Thu, Nov 28, 2024 at 07:35:10PM +0000, Colton Lewis wrote:
> Oliver Upton <oliver.upton@linux.dev> writes:
> > -/**
> > - * 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
> > *
> > @@ -94,7 +77,8 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu
> > *vcpu)
> > * 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,
>
> MDCR_EL2_HPMN is not defined
As of commit 641630313e9c ("arm64: sysreg: Migrate MDCR_EL2 definition to
table") the field definitions for MDCR_EL2 are generated from the sysreg
table.
The generated header defines this macro.
--
Thanks,
Oliver
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v2 03/16] KVM: arm64: Track presence of SPE/TRBE in kvm_host_data instead of vCPU
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
2024-11-15 22:49 ` [PATCH v2 01/16] KVM: arm64: Drop MDSCR_EL1_DEBUG_MASK Oliver Upton
2024-11-15 22:49 ` [PATCH v2 02/16] KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-22 11:15 ` James Clark
2024-11-15 22:49 ` [PATCH v2 04/16] KVM: arm64: Move host SME/SVE tracking flags to host data Oliver Upton
` (13 subsequent siblings)
16 siblings, 1 reply; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
Add flags to kvm_host_data to track if SPE/TRBE is present +
programmable on a per-CPU basis. Set the flags up at init rather than
vcpu_load() as the programmability of these buffers is unlikely to
change.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 19 +++++++++-------
arch/arm64/kvm/arm.c | 3 ---
arch/arm64/kvm/debug.c | 36 ++++++++----------------------
arch/arm64/kvm/hyp/nvhe/debug-sr.c | 8 +++----
4 files changed, 24 insertions(+), 42 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ad514434f3fe..7e3478386351 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -610,6 +610,10 @@ 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
+ unsigned long flags;
+
struct kvm_cpu_context host_ctxt;
/*
@@ -911,10 +915,6 @@ struct kvm_vcpu_arch {
#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))
@@ -1310,6 +1310,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)
{
@@ -1370,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);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index ab1bf9ccf385..3822774840e1 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -617,15 +617,12 @@ 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_arch_vcpu_put_fp(vcpu);
if (has_vhe())
kvm_vcpu_put_vhe(vcpu);
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index d8ea6fe6a2a2..1ee2fd765b62 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -294,40 +294,22 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
}
}
-void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu)
+void kvm_init_host_debug_data(void)
{
- u64 dfr0;
+ u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
+
+ 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));
- /* For VHE, there is nothing to do */
if (has_vhe())
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);
+ !(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P))
+ host_data_set_flag(HAS_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);
-}
-
-void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu)
-{
- vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_SPE);
- vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_TRBE);
-}
-
-void kvm_init_host_debug_data(void)
-{
- u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
-
- 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));
+ host_data_set_flag(HAS_TRBE);
}
diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
index 1e2a26d0196e..858bb38e273f 100644
--- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
@@ -82,10 +82,10 @@ static void __debug_restore_trace(u64 trfcr_el1)
void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
{
/* Disable and flush SPE data generation */
- if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
+ if (host_data_test_flag(HAS_SPE))
__debug_save_spe(host_data_ptr(host_debug_state.pmscr_el1));
/* Disable and flush Self-Hosted Trace generation */
- if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
+ if (host_data_test_flag(HAS_TRBE))
__debug_save_trace(host_data_ptr(host_debug_state.trfcr_el1));
}
@@ -96,9 +96,9 @@ void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
{
- if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
+ if (host_data_test_flag(HAS_SPE))
__debug_restore_spe(*host_data_ptr(host_debug_state.pmscr_el1));
- if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
+ if (host_data_test_flag(HAS_TRBE))
__debug_restore_trace(*host_data_ptr(host_debug_state.trfcr_el1));
}
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v2 03/16] KVM: arm64: Track presence of SPE/TRBE in kvm_host_data instead of vCPU
2024-11-15 22:49 ` [PATCH v2 03/16] KVM: arm64: Track presence of SPE/TRBE in kvm_host_data instead of vCPU Oliver Upton
@ 2024-11-22 11:15 ` James Clark
0 siblings, 0 replies; 22+ messages in thread
From: James Clark @ 2024-11-22 11:15 UTC (permalink / raw)
To: Oliver Upton, kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei
On 15/11/2024 10:49 pm, Oliver Upton wrote:
> Add flags to kvm_host_data to track if SPE/TRBE is present +
> programmable on a per-CPU basis. Set the flags up at init rather than
> vcpu_load() as the programmability of these buffers is unlikely to
> change.
>
> Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Reviewed-by: James Clark <james.clark@linaro.org>
> ---
> arch/arm64/include/asm/kvm_host.h | 19 +++++++++-------
> arch/arm64/kvm/arm.c | 3 ---
> arch/arm64/kvm/debug.c | 36 ++++++++----------------------
> arch/arm64/kvm/hyp/nvhe/debug-sr.c | 8 +++----
> 4 files changed, 24 insertions(+), 42 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ad514434f3fe..7e3478386351 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -610,6 +610,10 @@ 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
> + unsigned long flags;
> +
> struct kvm_cpu_context host_ctxt;
>
> /*
> @@ -911,10 +915,6 @@ struct kvm_vcpu_arch {
> #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))
> @@ -1310,6 +1310,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)
> {
> @@ -1370,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);
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index ab1bf9ccf385..3822774840e1 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -617,15 +617,12 @@ 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_arch_vcpu_put_fp(vcpu);
> if (has_vhe())
> kvm_vcpu_put_vhe(vcpu);
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index d8ea6fe6a2a2..1ee2fd765b62 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -294,40 +294,22 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
> }
> }
>
> -void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu)
> +void kvm_init_host_debug_data(void)
> {
> - u64 dfr0;
> + u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
> +
> + 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));
>
> - /* For VHE, there is nothing to do */
> if (has_vhe())
> 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);
> + !(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P))
> + host_data_set_flag(HAS_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);
> -}
> -
> -void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu)
> -{
> - vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_SPE);
> - vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_TRBE);
> -}
> -
> -void kvm_init_host_debug_data(void)
> -{
> - u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
> -
> - 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));
> + host_data_set_flag(HAS_TRBE);
> }
> diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
> index 1e2a26d0196e..858bb38e273f 100644
> --- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c
> +++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
> @@ -82,10 +82,10 @@ static void __debug_restore_trace(u64 trfcr_el1)
> void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
> {
> /* Disable and flush SPE data generation */
> - if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
> + if (host_data_test_flag(HAS_SPE))
> __debug_save_spe(host_data_ptr(host_debug_state.pmscr_el1));
> /* Disable and flush Self-Hosted Trace generation */
> - if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
> + if (host_data_test_flag(HAS_TRBE))
> __debug_save_trace(host_data_ptr(host_debug_state.trfcr_el1));
> }
>
> @@ -96,9 +96,9 @@ void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
>
> void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
> {
> - if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
> + if (host_data_test_flag(HAS_SPE))
> __debug_restore_spe(*host_data_ptr(host_debug_state.pmscr_el1));
> - if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
> + if (host_data_test_flag(HAS_TRBE))
> __debug_restore_trace(*host_data_ptr(host_debug_state.trfcr_el1));
> }
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v2 04/16] KVM: arm64: Move host SME/SVE tracking flags to host data
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (2 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 03/16] KVM: arm64: Track presence of SPE/TRBE in kvm_host_data instead of vCPU Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 05/16] KVM: arm64: Evaluate debug owner at vcpu_load() Oliver Upton
` (12 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
The SME/SVE state tracking flags have no business in the vCPU. Move them
to kvm_host_data.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 22 ++++++++++------------
arch/arm64/kvm/fpsimd.c | 12 ++++++------
2 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 7e3478386351..1ec025181de0 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -610,8 +610,10 @@ 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_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;
@@ -916,22 +918,18 @@ struct kvm_vcpu_arch {
/* Guest debug is live */
#define DEBUG_DIRTY __vcpu_single_flag(iflags, BIT(4))
-/* 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))
+#define SYSREGS_ON_CPU __vcpu_single_flag(sflags, BIT(2))
/* Software step state is Active-pending */
-#define DBG_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(5))
+#define DBG_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(3))
/* 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(4))
/* WFI instruction trapped */
-#define IN_WFI __vcpu_single_flag(sflags, BIT(7))
+#define IN_WFI __vcpu_single_flag(sflags, BIT(5))
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index ea5484ce1f3b..0e0f37d1990a 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -65,14 +65,14 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
*host_data_ptr(fpsimd_state) = kern_hyp_va(¤t->thread.uw.fpsimd_state);
*host_data_ptr(fpmr_ptr) = kern_hyp_va(¤t->thread.uw.fpmr);
- vcpu_clear_flag(vcpu, HOST_SVE_ENABLED);
+ host_data_clear_flag(HOST_SVE_ENABLED);
if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN)
- vcpu_set_flag(vcpu, HOST_SVE_ENABLED);
+ host_data_set_flag(HOST_SVE_ENABLED);
if (system_supports_sme()) {
- vcpu_clear_flag(vcpu, HOST_SME_ENABLED);
+ host_data_clear_flag(HOST_SME_ENABLED);
if (read_sysreg(cpacr_el1) & CPACR_EL1_SMEN_EL0EN)
- vcpu_set_flag(vcpu, HOST_SME_ENABLED);
+ host_data_set_flag(HOST_SME_ENABLED);
/*
* If PSTATE.SM is enabled then save any pending FP
@@ -168,7 +168,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
*/
if (has_vhe() && system_supports_sme()) {
/* Also restore EL0 state seen on entry */
- if (vcpu_get_flag(vcpu, HOST_SME_ENABLED))
+ if (host_data_test_flag(HOST_SME_ENABLED))
sysreg_clear_set(CPACR_EL1, 0, CPACR_ELx_SMEN);
else
sysreg_clear_set(CPACR_EL1,
@@ -227,7 +227,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
* for EL0. To avoid spurious traps, restore the trap state
* seen by kvm_arch_vcpu_load_fp():
*/
- if (vcpu_get_flag(vcpu, HOST_SVE_ENABLED))
+ if (host_data_test_flag(HOST_SVE_ENABLED))
sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_ZEN_EL0EN);
else
sysreg_clear_set(CPACR_EL1, CPACR_EL1_ZEN_EL0EN, 0);
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 05/16] KVM: arm64: Evaluate debug owner at vcpu_load()
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (3 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 04/16] KVM: arm64: Move host SME/SVE tracking flags to host data Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 06/16] KVM: arm64: Clean up KVM_SET_GUEST_DEBUG handler Oliver Upton
` (11 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
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.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 11 ++++++++
arch/arm64/kvm/arm.c | 1 +
arch/arm64/kvm/debug.c | 47 +++++++++++++++++++++++++++++++
arch/arm64/kvm/sys_regs.c | 2 ++
4 files changed, 61 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 1ec025181de0..d2e4c33427bf 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -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,
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 3822774840e1..a068337da52a 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -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);
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 1ee2fd765b62..da297cc92ed5 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -313,3 +313,50 @@ 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;
+
+ WARN_ON_ONCE(vcpu->arch.debug_owner == VCPU_DEBUG_GUEST_OWNED);
+ vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
+}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 83c6b4a07ef5..b17cd93c1c8d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -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;
@@ -709,6 +710,7 @@ static bool trap_bvr(struct kvm_vcpu *vcpu,
else
dbg_to_reg(vcpu, p, rd, dbg_reg);
+ kvm_debug_set_guest_ownership(vcpu);
trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg);
return true;
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 06/16] KVM: arm64: Clean up KVM_SET_GUEST_DEBUG handler
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (4 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 05/16] KVM: arm64: Evaluate debug owner at vcpu_load() Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 07/16] KVM: arm64: Select debug state to save/restore based on debug owner Oliver Upton
` (10 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
No particular reason other than it isn't nice to look at.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/kvm/guest.c | 29 +++++++++++------------------
1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 962f985977c2..af612ea20b71 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -917,31 +917,24 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
struct kvm_guest_debug *dbg)
{
- int ret = 0;
-
trace_kvm_set_guest_debug(vcpu, dbg->control);
- if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) {
- ret = -EINVAL;
- goto out;
- }
-
- if (dbg->control & KVM_GUESTDBG_ENABLE) {
- vcpu->guest_debug = dbg->control;
-
- /* Hardware assisted Break and Watch points */
- if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
- vcpu->arch.external_debug_state = dbg->arch;
- }
+ if (dbg->control & ~KVM_GUESTDBG_VALID_MASK)
+ return -EINVAL;
- } else {
- /* If not enabled clear all flags */
+ if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
vcpu->guest_debug = 0;
vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
+ return 0;
}
-out:
- return ret;
+ vcpu->guest_debug = dbg->control;
+
+ /* Hardware assisted Break and Watch points */
+ if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW)
+ vcpu->arch.external_debug_state = dbg->arch;
+
+ return 0;
}
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 07/16] KVM: arm64: Select debug state to save/restore based on debug owner
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (5 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 06/16] KVM: arm64: Clean up KVM_SET_GUEST_DEBUG handler Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 08/16] KVM: arm64: Remove debug tracepoints Oliver Upton
` (9 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
Select the set of debug registers to use based on the owner rather than
relying on debug_ptr. Besides the code cleanup, this allows us to
eliminate a couple instances kern_hyp_va() as well.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 2 ++
arch/arm64/kvm/hyp/include/hyp/debug-sr.h | 23 +++++++++++++++++++----
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index d2e4c33427bf..8b3143b75eb7 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1357,6 +1357,8 @@ 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_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)
diff --git a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
index d00093699aaf..9e3051225039 100644
--- a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
@@ -88,6 +88,21 @@
default: write_debug(ptr[0], reg, 0); \
}
+static struct kvm_guest_debug_arch *__vcpu_debug_regs(struct kvm_vcpu *vcpu)
+{
+ switch (vcpu->arch.debug_owner) {
+ case VCPU_DEBUG_FREE:
+ WARN_ON_ONCE(1);
+ fallthrough;
+ case VCPU_DEBUG_GUEST_OWNED:
+ return &vcpu->arch.vcpu_debug_state;
+ case VCPU_DEBUG_HOST_OWNED:
+ return &vcpu->arch.external_debug_state;
+ }
+
+ return NULL;
+}
+
static void __debug_save_state(struct kvm_guest_debug_arch *dbg,
struct kvm_cpu_context *ctxt)
{
@@ -132,13 +147,13 @@ static inline void __debug_switch_to_guest_common(struct kvm_vcpu *vcpu)
struct kvm_guest_debug_arch *host_dbg;
struct kvm_guest_debug_arch *guest_dbg;
- if (!vcpu_get_flag(vcpu, DEBUG_DIRTY))
+ if (!kvm_debug_regs_in_use(vcpu))
return;
host_ctxt = host_data_ptr(host_ctxt);
guest_ctxt = &vcpu->arch.ctxt;
host_dbg = host_data_ptr(host_debug_state.regs);
- guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
+ guest_dbg = __vcpu_debug_regs(vcpu);
__debug_save_state(host_dbg, host_ctxt);
__debug_restore_state(guest_dbg, guest_ctxt);
@@ -151,13 +166,13 @@ static inline void __debug_switch_to_host_common(struct kvm_vcpu *vcpu)
struct kvm_guest_debug_arch *host_dbg;
struct kvm_guest_debug_arch *guest_dbg;
- if (!vcpu_get_flag(vcpu, DEBUG_DIRTY))
+ if (!kvm_debug_regs_in_use(vcpu))
return;
host_ctxt = host_data_ptr(host_ctxt);
guest_ctxt = &vcpu->arch.ctxt;
host_dbg = host_data_ptr(host_debug_state.regs);
- guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
+ guest_dbg = __vcpu_debug_regs(vcpu);
__debug_save_state(guest_dbg, guest_ctxt);
__debug_restore_state(host_dbg, host_ctxt);
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 08/16] KVM: arm64: Remove debug tracepoints
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (6 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 07/16] KVM: arm64: Select debug state to save/restore based on debug owner Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 09/16] KVM: arm64: Remove vestiges of debug_ptr Oliver Upton
` (8 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
The debug tracepoints are a useless firehose of information that track
implementation detail rather than well-defined events. These are going
to be rather difficult to uphold now that the implementation is getting
redone, so throw them out instead of bending over backwards.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/kvm/debug.c | 30 ------------
arch/arm64/kvm/sys_regs.c | 11 -----
arch/arm64/kvm/trace_handle_exit.h | 75 ------------------------------
3 files changed, 116 deletions(-)
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index da297cc92ed5..0993fc02647c 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -14,7 +14,6 @@
#include <asm/kvm_arm.h>
#include <asm/kvm_emulate.h>
-#include "trace.h"
/*
* save/restore_guest_debug_regs
@@ -35,10 +34,6 @@ 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);
}
@@ -49,9 +44,6 @@ static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
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
@@ -102,8 +94,6 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
!vcpu_get_flag(vcpu, DEBUG_DIRTY) ||
kvm_vcpu_os_lock_enabled(vcpu))
vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
-
- trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
}
/**
@@ -201,8 +191,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
}
- trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
-
/*
* HW Breakpoints and watchpoints
*
@@ -220,14 +208,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
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]);
-
/*
* The OS Lock blocks debug exceptions in all ELs when it is
* enabled. If the guest has enabled the OS Lock, constrain its
@@ -253,8 +233,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
/* 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);
-
- trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_read_sys_reg(vcpu, MDSCR_EL1));
}
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
@@ -282,14 +260,6 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
*/
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]);
}
}
}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b17cd93c1c8d..f84306b11261 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -657,8 +657,6 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
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;
}
@@ -711,8 +709,6 @@ static bool trap_bvr(struct kvm_vcpu *vcpu,
dbg_to_reg(vcpu, p, rd, dbg_reg);
kvm_debug_set_guest_ownership(vcpu);
- trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg);
-
return true;
}
@@ -748,8 +744,6 @@ static bool trap_bcr(struct kvm_vcpu *vcpu,
else
dbg_to_reg(vcpu, p, rd, dbg_reg);
- trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg);
-
return true;
}
@@ -785,9 +779,6 @@ static bool trap_wvr(struct kvm_vcpu *vcpu,
else
dbg_to_reg(vcpu, p, rd, dbg_reg);
- trace_trap_reg(__func__, rd->CRm, p->is_write,
- vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]);
-
return true;
}
@@ -823,8 +814,6 @@ static bool trap_wcr(struct kvm_vcpu *vcpu,
else
dbg_to_reg(vcpu, p, rd, dbg_reg);
- trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg);
-
return true;
}
diff --git a/arch/arm64/kvm/trace_handle_exit.h b/arch/arm64/kvm/trace_handle_exit.h
index 064a58c19f48..f85415db7713 100644
--- a/arch/arm64/kvm/trace_handle_exit.h
+++ b/arch/arm64/kvm/trace_handle_exit.h
@@ -46,38 +46,6 @@ TRACE_EVENT(kvm_hvc_arm64,
__entry->vcpu_pc, __entry->r0, __entry->imm)
);
-TRACE_EVENT(kvm_arm_setup_debug,
- TP_PROTO(struct kvm_vcpu *vcpu, __u32 guest_debug),
- TP_ARGS(vcpu, guest_debug),
-
- TP_STRUCT__entry(
- __field(struct kvm_vcpu *, vcpu)
- __field(__u32, guest_debug)
- ),
-
- TP_fast_assign(
- __entry->vcpu = vcpu;
- __entry->guest_debug = guest_debug;
- ),
-
- TP_printk("vcpu: %p, flags: 0x%08x", __entry->vcpu, __entry->guest_debug)
-);
-
-TRACE_EVENT(kvm_arm_clear_debug,
- TP_PROTO(__u32 guest_debug),
- TP_ARGS(guest_debug),
-
- TP_STRUCT__entry(
- __field(__u32, guest_debug)
- ),
-
- TP_fast_assign(
- __entry->guest_debug = guest_debug;
- ),
-
- TP_printk("flags: 0x%08x", __entry->guest_debug)
-);
-
/*
* The dreg32 name is a leftover from a distant past. This will really
* output a 64bit value...
@@ -99,49 +67,6 @@ TRACE_EVENT(kvm_arm_set_dreg32,
TP_printk("%s: 0x%llx", __entry->name, __entry->value)
);
-TRACE_DEFINE_SIZEOF(__u64);
-
-TRACE_EVENT(kvm_arm_set_regset,
- TP_PROTO(const char *type, int len, __u64 *control, __u64 *value),
- TP_ARGS(type, len, control, value),
- TP_STRUCT__entry(
- __field(const char *, name)
- __field(int, len)
- __array(u64, ctrls, 16)
- __array(u64, values, 16)
- ),
- TP_fast_assign(
- __entry->name = type;
- __entry->len = len;
- memcpy(__entry->ctrls, control, len << 3);
- memcpy(__entry->values, value, len << 3);
- ),
- TP_printk("%d %s CTRL:%s VALUE:%s", __entry->len, __entry->name,
- __print_array(__entry->ctrls, __entry->len, sizeof(__u64)),
- __print_array(__entry->values, __entry->len, sizeof(__u64)))
-);
-
-TRACE_EVENT(trap_reg,
- TP_PROTO(const char *fn, int reg, bool is_write, u64 write_value),
- TP_ARGS(fn, reg, is_write, write_value),
-
- TP_STRUCT__entry(
- __field(const char *, fn)
- __field(int, reg)
- __field(bool, is_write)
- __field(u64, write_value)
- ),
-
- TP_fast_assign(
- __entry->fn = fn;
- __entry->reg = reg;
- __entry->is_write = is_write;
- __entry->write_value = write_value;
- ),
-
- TP_printk("%s %s reg %d (0x%016llx)", __entry->fn, __entry->is_write?"write to":"read from", __entry->reg, __entry->write_value)
-);
-
TRACE_EVENT(kvm_handle_sys_reg,
TP_PROTO(unsigned long hsr),
TP_ARGS(hsr),
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 09/16] KVM: arm64: Remove vestiges of debug_ptr
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (7 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 08/16] KVM: arm64: Remove debug tracepoints Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 10/16] KVM: arm64: Use debug_owner to track if debug regs need save/restore Oliver Upton
` (7 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
Delete the remnants of debug_ptr now that debug registers are selected
based on the debug owner instead.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 5 -----
arch/arm64/kvm/arm.c | 2 --
arch/arm64/kvm/debug.c | 30 +-----------------------------
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 2 --
4 files changed, 1 insertion(+), 38 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 8b3143b75eb7..f1da34e1bc32 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -748,11 +748,7 @@ 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;
@@ -1350,7 +1346,6 @@ void kvm_init_host_debug_data(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_vcpu_load_debug(struct kvm_vcpu *vcpu);
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index a068337da52a..44a6093b0d9e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -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;
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 0993fc02647c..65c5871603c2 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -110,16 +110,6 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *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)
-{
- vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state;
-}
-
/**
* kvm_arm_setup_debug - set up debug related stuff
*
@@ -192,20 +182,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
}
/*
- * HW Breakpoints and watchpoints
- *
- * 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.
+ * Enable breakpoints and watchpoints if userspace wants them.
*/
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);
/*
@@ -223,9 +206,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
}
}
- BUG_ON(!vcpu->guest_debug &&
- vcpu->arch.debug_ptr != &vcpu->arch.vcpu_debug_state);
-
/* 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);
@@ -253,14 +233,6 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
}
restore_guest_debug_regs(vcpu);
-
- /*
- * If we were using HW debug we need to restore the
- * debug_ptr to the guest debug state.
- */
- if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
- kvm_arm_reset_debug_ptr(vcpu);
- }
}
}
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 16f5da3a884a..f98ef98af183 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -112,8 +112,6 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
hyp_vcpu->vcpu.arch.iflags = host_vcpu->arch.iflags;
- hyp_vcpu->vcpu.arch.debug_ptr = kern_hyp_va(host_vcpu->arch.debug_ptr);
-
hyp_vcpu->vcpu.arch.vsesr_el2 = host_vcpu->arch.vsesr_el2;
hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3 = host_vcpu->arch.vgic_cpu.vgic_v3;
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 10/16] KVM: arm64: Use debug_owner to track if debug regs need save/restore
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (8 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 09/16] KVM: arm64: Remove vestiges of debug_ptr Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 11/16] KVM: arm64: Reload vCPU for accesses to OSLAR_EL1 Oliver Upton
` (6 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
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.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 4 +--
arch/arm64/kvm/debug.c | 19 ++-----------
arch/arm64/kvm/hyp/include/hyp/debug-sr.h | 2 --
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 4 +--
arch/arm64/kvm/sys_regs.c | 33 ----------------------
5 files changed, 7 insertions(+), 55 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f1da34e1bc32..eab3b95107f9 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -917,8 +917,6 @@ 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))
/* Physical CPU not in supported_cpus */
#define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(0))
@@ -1356,6 +1354,8 @@ void kvm_debug_set_guest_ownership(struct kvm_vcpu *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);
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 65c5871603c2..54c93b37a06a 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -84,15 +84,9 @@ 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;
}
@@ -119,8 +113,7 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu)
* 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
+ * the guest is not actively using them. 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.
@@ -189,8 +182,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
mdscr |= DBG_MDSCR_MDE;
vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
- vcpu_set_flag(vcpu, DEBUG_DIRTY);
-
/*
* The OS Lock blocks debug exceptions in all ELs when it is
* enabled. If the guest has enabled the OS Lock, constrain its
@@ -206,10 +197,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
}
}
- /* 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);
-
/* 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);
diff --git a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
index 9e3051225039..c14586d87361 100644
--- a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
@@ -176,8 +176,6 @@ static inline void __debug_switch_to_host_common(struct kvm_vcpu *vcpu)
__debug_save_state(guest_dbg, guest_ctxt);
__debug_restore_state(host_dbg, host_ctxt);
-
- vcpu_clear_flag(vcpu, DEBUG_DIRTY);
}
#endif /* __ARM64_KVM_HYP_DEBUG_SR_H__ */
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index a651c43ad679..a998b2f6abcb 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -283,7 +283,7 @@ static inline void __sysreg32_save_state(struct kvm_vcpu *vcpu)
__vcpu_sys_reg(vcpu, DACR32_EL2) = read_sysreg(dacr32_el2);
__vcpu_sys_reg(vcpu, IFSR32_EL2) = read_sysreg(ifsr32_el2);
- if (has_vhe() || vcpu_get_flag(vcpu, DEBUG_DIRTY))
+ if (has_vhe() || kvm_debug_regs_in_use(vcpu))
__vcpu_sys_reg(vcpu, DBGVCR32_EL2) = read_sysreg(dbgvcr32_el2);
}
@@ -300,7 +300,7 @@ static inline void __sysreg32_restore_state(struct kvm_vcpu *vcpu)
write_sysreg(__vcpu_sys_reg(vcpu, DACR32_EL2), dacr32_el2);
write_sysreg(__vcpu_sys_reg(vcpu, IFSR32_EL2), ifsr32_el2);
- if (has_vhe() || vcpu_get_flag(vcpu, DEBUG_DIRTY))
+ if (has_vhe() || kvm_debug_regs_in_use(vcpu))
write_sysreg(__vcpu_sys_reg(vcpu, DBGVCR32_EL2), dbgvcr32_el2);
}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f84306b11261..5b8982bcc0bb 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -621,40 +621,12 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
}
}
-/*
- * We want to avoid world-switching all the DBG registers all the
- * time:
- *
- * - If we've touched any debug register, it is likely that we're
- * going to touch more of them. It then makes sense to disable the
- * traps and start doing the save/restore dance
- * - If debug is active (DBG_MDSCR_KDE or DBG_MDSCR_MDE set), it is
- * then mandatory to save/restore the registers, as the guest
- * depends on them.
- *
- * For this, we use a DIRTY bit, indicating the guest has modified the
- * debug registers, used as follow:
- *
- * On guest entry:
- * - If the dirty bit is set (because we're coming back from trapping),
- * disable the traps, save host registers, restore guest registers.
- * - If debug is actively in use (DBG_MDSCR_KDE or DBG_MDSCR_MDE set),
- * set the dirty bit, disable the traps, save host registers,
- * restore guest registers.
- * - Otherwise, enable the traps
- *
- * On guest exit:
- * - If the dirty bit is set, save guest registers, restore host
- * registers and clear the dirty bit. This ensure that the host can
- * now use the debug registers.
- */
static bool trap_debug_regs(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
access_rw(vcpu, p, r);
if (p->is_write)
- vcpu_set_flag(vcpu, DEBUG_DIRTY);
kvm_debug_set_guest_ownership(vcpu);
return true;
@@ -665,9 +637,6 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
*
* A 32 bit write to a debug register leave top bits alone
* A 32 bit read from a debug register only returns the bottom bits
- *
- * All writes will set the DEBUG_DIRTY flag to ensure the hyp code
- * switches between host and guest values in future.
*/
static void reg_to_dbg(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
@@ -682,8 +651,6 @@ static void reg_to_dbg(struct kvm_vcpu *vcpu,
val &= ~mask;
val |= (p->regval & (mask >> shift)) << shift;
*dbg_reg = val;
-
- vcpu_set_flag(vcpu, DEBUG_DIRTY);
}
static void dbg_to_reg(struct kvm_vcpu *vcpu,
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 11/16] KVM: arm64: Reload vCPU for accesses to OSLAR_EL1
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (9 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 10/16] KVM: arm64: Use debug_owner to track if debug regs need save/restore Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 12/16] KVM: arm64: Compute MDCR_EL2 at vcpu_load() Oliver Upton
` (5 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
KVM takes ownership of the debug regs if the guest enables the OS lock,
as it needs to use MDSCR_EL1 to mask debug exceptions. Just reload the
vCPU if the guest toggles the OS lock, relying on kvm_vcpu_load_debug()
to update the debug owner and get the right trap configuration in place.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 1 +
arch/arm64/kvm/debug.c | 13 +++++++++++++
arch/arm64/kvm/sys_regs.c | 9 +--------
3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index eab3b95107f9..ee1f454843a8 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1346,6 +1346,7 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
void kvm_vcpu_load_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))
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 54c93b37a06a..91f484a566e4 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -289,3 +289,16 @@ void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu)
WARN_ON_ONCE(vcpu->arch.debug_owner == VCPU_DEBUG_GUEST_OWNED);
vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
}
+
+void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val)
+{
+ 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();
+}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 5b8982bcc0bb..15e427c5fc4f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -570,17 +570,10 @@ static bool trap_oslar_el1(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
- u64 oslsr;
-
if (!p->is_write)
return read_from_write_only(vcpu, p, r);
- /* Forward the OSLK bit to OSLSR */
- oslsr = __vcpu_sys_reg(vcpu, OSLSR_EL1) & ~OSLSR_EL1_OSLK;
- if (p->regval & OSLAR_EL1_OSLK)
- oslsr |= OSLSR_EL1_OSLK;
-
- __vcpu_sys_reg(vcpu, OSLSR_EL1) = oslsr;
+ kvm_debug_handle_oslar(vcpu, p->regval);
return true;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 12/16] KVM: arm64: Compute MDCR_EL2 at vcpu_load()
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (10 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 11/16] KVM: arm64: Reload vCPU for accesses to OSLAR_EL1 Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 13/16] KVM: arm64: Don't hijack guest context MDSCR_EL1 Oliver Upton
` (4 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
KVM has picked up several hacks to cope with vcpu->arch.mdcr_el2 needing
to be prepared before vcpu_load(), which is when it gets programmed
into hardware on VHE.
Now that the flows for reprogramming MDCR_EL2 have been simplified, move
that computation to vcpu_load().
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 1 -
arch/arm64/kvm/arm.c | 2 --
arch/arm64/kvm/debug.c | 28 +++++++---------------------
3 files changed, 7 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ee1f454843a8..36f30a57f59a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1341,7 +1341,6 @@ static inline bool kvm_system_needs_idmapped_vectors(void)
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
void kvm_init_host_debug_data(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_vcpu_load_debug(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 44a6093b0d9e..ec581aeb41f9 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -804,8 +804,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
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 91f484a566e4..a59f97c1869f 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -90,20 +90,6 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
}
-/**
- * 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_setup_debug - set up debug related stuff
*
@@ -121,12 +107,10 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu)
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
{
- unsigned long mdscr, orig_mdcr_el2 = vcpu->arch.mdcr_el2;
+ unsigned long mdscr;
trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
- kvm_arm_setup_mdcr_el2(vcpu);
-
/* Check if we need to use the debug registers. */
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
/* Save guest debug state */
@@ -196,10 +180,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
vcpu_write_sys_reg(vcpu, mdscr, 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);
}
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
@@ -273,6 +253,8 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
else
vcpu->arch.debug_owner = VCPU_DEBUG_FREE;
}
+
+ kvm_arm_setup_mdcr_el2(vcpu);
}
/*
@@ -288,6 +270,10 @@ void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu)
WARN_ON_ONCE(vcpu->arch.debug_owner == VCPU_DEBUG_GUEST_OWNED);
vcpu->arch.debug_owner = VCPU_DEBUG_GUEST_OWNED;
+ kvm_arm_setup_mdcr_el2(vcpu);
+
+ if (has_vhe())
+ write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
}
void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val)
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 13/16] KVM: arm64: Don't hijack guest context MDSCR_EL1
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (11 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 12/16] KVM: arm64: Compute MDCR_EL2 at vcpu_load() Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 14/16] KVM: arm64: Manage software step state at load/put Oliver Upton
` (3 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
Stealing MDSCR_EL1 in the guest's kvm_cpu_context for external debugging
is rather gross. Just add a field for this instead and let the context
switch code pick the correct one based on the debug owner.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 2 +-
arch/arm64/kvm/debug.c | 73 +++++++++++-----------
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 39 ++++++++----
3 files changed, 64 insertions(+), 50 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 36f30a57f59a..041a9f1eaa09 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -751,6 +751,7 @@ struct kvm_vcpu_arch {
*/
struct kvm_guest_debug_arch vcpu_debug_state;
struct kvm_guest_debug_arch external_debug_state;
+ u64 external_mdscr_el1;
enum {
VCPU_DEBUG_FREE,
@@ -771,7 +772,6 @@ struct kvm_vcpu_arch {
* are using guest debug.
*/
struct {
- u32 mdscr_el1;
bool pstate_ss;
} guest_debug_preserved;
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index a59f97c1869f..f919ef81f4f7 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -31,19 +31,12 @@
*/
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;
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);
-
if (vcpu->arch.guest_debug_preserved.pstate_ss)
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
else
@@ -148,36 +141,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
*vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
else
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
-
- 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);
- }
-
- /*
- * Enable breakpoints and watchpoints if userspace wants them.
- */
- if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
- mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
- mdscr |= DBG_MDSCR_MDE;
- vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
-
- /*
- * 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.
- */
- } 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);
}
}
}
@@ -223,6 +186,41 @@ void kvm_init_host_debug_data(void)
host_data_set_flag(HAS_TRBE);
}
+/*
+ * Configures the 'external' MDSCR_EL1 value for the guest, i.e. when the host
+ * has taken over MDSCR_EL1.
+ *
+ * - Userspace is single-stepping the guest, and MDSCR_EL1.SS is forced to 1.
+ *
+ * - Userspace is using the breakpoint/watchpoint registers to debug the
+ * guest, and MDSCR_EL1.MDE is forced to 1.
+ *
+ * - 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.
+ */
+static void setup_external_mdscr(struct kvm_vcpu *vcpu)
+{
+ /*
+ * 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.
+ */
+ u64 mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1) & ~(MDSCR_EL1_SS |
+ MDSCR_EL1_MDE |
+ MDSCR_EL1_KDE);
+
+ 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;
+}
+
void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
{
u64 mdscr;
@@ -245,6 +243,7 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
*/
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
+ setup_external_mdscr(vcpu);
} else {
mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index a998b2f6abcb..76ff095c6b6e 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -18,9 +18,34 @@
static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt);
+static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
+{
+ struct kvm_vcpu *vcpu = ctxt->__hyp_running_vcpu;
+
+ if (!vcpu)
+ vcpu = container_of(ctxt, struct kvm_vcpu, arch.ctxt);
+
+ return vcpu;
+}
+
+static inline bool ctxt_is_guest(struct kvm_cpu_context *ctxt)
+{
+ return host_data_ptr(host_ctxt) != ctxt;
+}
+
+static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
+{
+ struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt);
+
+ if (ctxt_is_guest(ctxt) && kvm_host_owns_debug_regs(vcpu))
+ return &vcpu->arch.external_mdscr_el1;
+
+ return &ctxt_sys_reg(ctxt, MDSCR_EL1);
+}
+
static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
{
- ctxt_sys_reg(ctxt, MDSCR_EL1) = read_sysreg(mdscr_el1);
+ *ctxt_mdscr_el1(ctxt) = read_sysreg(mdscr_el1);
// POR_EL0 can affect uaccess, so must be saved/restored early.
if (ctxt_has_s1poe(ctxt))
@@ -33,16 +58,6 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
ctxt_sys_reg(ctxt, TPIDRRO_EL0) = read_sysreg(tpidrro_el0);
}
-static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
-{
- struct kvm_vcpu *vcpu = ctxt->__hyp_running_vcpu;
-
- if (!vcpu)
- vcpu = container_of(ctxt, struct kvm_vcpu, arch.ctxt);
-
- return vcpu;
-}
-
static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
{
struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt);
@@ -139,7 +154,7 @@ static inline void __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
static inline void __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
{
- write_sysreg(ctxt_sys_reg(ctxt, MDSCR_EL1), mdscr_el1);
+ write_sysreg(*ctxt_mdscr_el1(ctxt), mdscr_el1);
// POR_EL0 can affect uaccess, so must be saved/restored early.
if (ctxt_has_s1poe(ctxt))
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 14/16] KVM: arm64: Manage software step state at load/put
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (12 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 13/16] KVM: arm64: Don't hijack guest context MDSCR_EL1 Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 15/16] KVM: arm64: nv: Honor MDCR_EL2.TDE routing for debug exceptions Oliver Upton
` (2 subsequent siblings)
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
KVM takes over the guest's software step state machine if the VMM is
debugging the guest, but it does the save/restore fiddling for every
guest entry.
Note that the only constraint on host usage of software step is that the
guest's configuration remains visible to userspace via the ONE_REG
ioctls. So, we can cut down on the amount of fiddling by doing this at
load/put instead.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 24 ++---
arch/arm64/kvm/arm.c | 4 +-
arch/arm64/kvm/debug.c | 151 ++++++++----------------------
arch/arm64/kvm/guest.c | 2 +-
arch/arm64/kvm/handle_exit.c | 2 +-
5 files changed, 48 insertions(+), 135 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 041a9f1eaa09..60bbca22c492 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -764,17 +764,6 @@ struct kvm_vcpu_arch {
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 {
- bool pstate_ss;
- } guest_debug_preserved;
-
/* vcpu power state */
struct kvm_mp_state mp_state;
spinlock_t mp_state_lock;
@@ -924,12 +913,14 @@ struct kvm_vcpu_arch {
#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(2))
-/* Software step state is Active-pending */
-#define DBG_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(3))
+/* 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(4))
+#define PMUSERENR_ON_CPU __vcpu_single_flag(sflags, BIT(5))
/* WFI instruction trapped */
-#define IN_WFI __vcpu_single_flag(sflags, BIT(5))
+#define IN_WFI __vcpu_single_flag(sflags, BIT(6))
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
@@ -1341,9 +1332,8 @@ static inline bool kvm_system_needs_idmapped_vectors(void)
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
void kvm_init_host_debug_data(void);
-void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
-void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
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);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index ec581aeb41f9..563cd0b626b9 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -622,6 +622,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
{
+ kvm_vcpu_put_debug(vcpu);
kvm_arch_vcpu_put_fp(vcpu);
if (has_vhe())
kvm_vcpu_put_vhe(vcpu);
@@ -1181,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);
/**************************************************************
@@ -1198,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
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index f919ef81f4f7..91e272dc7215 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -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,35 +15,6 @@
#include <asm/kvm_arm.h>
#include <asm/kvm_emulate.h>
-
-/*
- * 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)
-{
- vcpu->arch.guest_debug_preserved.pstate_ss =
- (*vcpu_cpsr(vcpu) & DBG_SPSR_SS);
-}
-
-static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
-{
- if (vcpu->arch.guest_debug_preserved.pstate_ss)
- *vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
- else
- *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
-}
-
/**
* kvm_arm_setup_mdcr_el2 - configure vcpu mdcr_el2 value
*
@@ -83,89 +55,6 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
}
-/**
- * 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. 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.
- */
-
-void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
-{
- unsigned long mdscr;
-
- trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
-
- /* 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);
-
- /*
- * Single Step (ARM ARM D2.12.3 The software step state
- * machine)
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
- if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
- /*
- * 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).
- */
- if (!vcpu_get_flag(vcpu, DBG_SS_ACTIVE_PENDING))
- *vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
- else
- *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
- }
- }
-}
-
-void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
-{
- trace_kvm_arm_clear_debug(vcpu->guest_debug);
-
- /*
- * Restore the guest's debug registers if we were using them.
- */
- 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);
- }
-
- restore_guest_debug_regs(vcpu);
- }
-}
-
void kvm_init_host_debug_data(void)
{
u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
@@ -244,6 +133,22 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
vcpu->arch.debug_owner = VCPU_DEBUG_HOST_OWNED;
setup_external_mdscr(vcpu);
+
+ /*
+ * Steal the guest's single-step state machine if userspace wants
+ * single-step the guest.
+ */
+ 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 (!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);
@@ -256,6 +161,26 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu)
kvm_arm_setup_mdcr_el2(vcpu);
}
+void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu)
+{
+ if (likely(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)))
+ return;
+
+ /*
+ * Save the host's software step state and restore the guest's before
+ * potentially returning to userspace.
+ */
+ if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS))
+ vcpu_set_flag(vcpu, HOST_SS_ACTIVE_PENDING);
+ else
+ vcpu_clear_flag(vcpu, HOST_SS_ACTIVE_PENDING);
+
+ if (vcpu_get_flag(vcpu, GUEST_SS_ACTIVE_PENDING))
+ *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
+ else
+ *vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
+}
+
/*
* Updates ownership of the debug registers after a trapped guest access to a
* breakpoint/watchpoint register. Host ownership of the debug registers is of
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index af612ea20b71..a8c40d6fb161 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -924,7 +924,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
vcpu->guest_debug = 0;
- vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
+ vcpu_clear_flag(vcpu, HOST_SS_ACTIVE_PENDING);
return 0;
}
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index d7c2990e7c9e..1e302f0c8903 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -193,7 +193,7 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
run->debug.arch.far = vcpu->arch.fault.far_el2;
break;
case ESR_ELx_EC_SOFTSTP_LOW:
- vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
+ *vcpu_cpsr(vcpu) |= DBG_SPSR_SS;
break;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 15/16] KVM: arm64: nv: Honor MDCR_EL2.TDE routing for debug exceptions
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (13 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 14/16] KVM: arm64: Manage software step state at load/put Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-15 22:49 ` [PATCH v2 16/16] KVM: arm64: Avoid reading ID_AA64DFR0_EL1 for debug save/restore Oliver Upton
2024-11-22 11:08 ` [PATCH v2 00/16] KVM: arm64: Debug cleanups James Clark
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
Inject debug exceptions into vEL2 if MDCR_EL2.TDE is set.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_nested.h | 1 +
arch/arm64/kvm/emulate-nested.c | 23 +++++++++++++++++++----
arch/arm64/kvm/handle_exit.c | 3 +++
3 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h
index 233e65522716..ec6e28d63d26 100644
--- a/arch/arm64/include/asm/kvm_nested.h
+++ b/arch/arm64/include/asm/kvm_nested.h
@@ -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);
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 1ffbfd1c3cf2..e37fb598cc24 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2345,14 +2345,14 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
return true;
}
-static bool forward_traps(struct kvm_vcpu *vcpu, u64 control_bit)
+static bool __forward_traps(struct kvm_vcpu *vcpu, unsigned int reg, u64 control_bit)
{
bool control_bit_set;
if (!vcpu_has_nv(vcpu))
return false;
- control_bit_set = __vcpu_sys_reg(vcpu, HCR_EL2) & control_bit;
+ control_bit_set = __vcpu_sys_reg(vcpu, reg) & control_bit;
if (!is_hyp_ctxt(vcpu) && control_bit_set) {
kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
return true;
@@ -2360,9 +2360,24 @@ static bool forward_traps(struct kvm_vcpu *vcpu, u64 control_bit)
return false;
}
+static bool forward_hcr_traps(struct kvm_vcpu *vcpu, u64 control_bit)
+{
+ return __forward_traps(vcpu, HCR_EL2, control_bit);
+}
+
bool forward_smc_trap(struct kvm_vcpu *vcpu)
{
- return forward_traps(vcpu, HCR_TSC);
+ return forward_hcr_traps(vcpu, HCR_TSC);
+}
+
+static bool forward_mdcr_traps(struct kvm_vcpu *vcpu, u64 control_bit)
+{
+ return __forward_traps(vcpu, MDCR_EL2, control_bit);
+}
+
+bool forward_debug_exception(struct kvm_vcpu *vcpu)
+{
+ return forward_mdcr_traps(vcpu, MDCR_EL2_TDE);
}
static u64 kvm_check_illegal_exception_return(struct kvm_vcpu *vcpu, u64 spsr)
@@ -2406,7 +2421,7 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu)
* Forward this trap to the virtual EL2 if the virtual
* HCR_EL2.NV bit is set and this is coming from !EL2.
*/
- if (forward_traps(vcpu, HCR_NV))
+ if (forward_hcr_traps(vcpu, HCR_NV))
return;
spsr = vcpu_read_sys_reg(vcpu, SPSR_EL2);
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 1e302f0c8903..684f334914da 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -183,6 +183,9 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
struct kvm_run *run = vcpu->run;
u64 esr = kvm_vcpu_get_esr(vcpu);
+ if (forward_debug_exception(vcpu))
+ return 1;
+
run->exit_reason = KVM_EXIT_DEBUG;
run->debug.arch.hsr = lower_32_bits(esr);
run->debug.arch.hsr_high = upper_32_bits(esr);
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v2 16/16] KVM: arm64: Avoid reading ID_AA64DFR0_EL1 for debug save/restore
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (14 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 15/16] KVM: arm64: nv: Honor MDCR_EL2.TDE routing for debug exceptions Oliver Upton
@ 2024-11-15 22:49 ` Oliver Upton
2024-11-22 11:08 ` [PATCH v2 00/16] KVM: arm64: Debug cleanups James Clark
16 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-15 22:49 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei, Oliver Upton
Similar to other per-CPU profiling/debug features we handle, store the
number of breakpoints/watchpoints in kvm_host_data to avoid reading the
ID register 4 times on every guest entry/exit. And if you're in the
nested virt business that's quite a few avoidable exits to the L0
hypervisor.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/include/asm/kvm_host.h | 4 ++++
arch/arm64/kvm/debug.c | 3 +++
arch/arm64/kvm/hyp/include/hyp/debug-sr.h | 17 ++++-------------
3 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 60bbca22c492..8bc0ec151684 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -661,6 +661,10 @@ struct kvm_host_data {
/* 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 {
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 91e272dc7215..46dbeabd6833 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -63,6 +63,9 @@ void kvm_init_host_debug_data(void)
*host_data_ptr(nr_event_counters) = FIELD_GET(ARMV8_PMU_PMCR_N,
read_sysreg(pmcr_el0));
+ *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);
+
if (has_vhe())
return;
diff --git a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
index c14586d87361..502a5b73ee70 100644
--- a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h
@@ -106,12 +106,8 @@ static struct kvm_guest_debug_arch *__vcpu_debug_regs(struct kvm_vcpu *vcpu)
static void __debug_save_state(struct kvm_guest_debug_arch *dbg,
struct kvm_cpu_context *ctxt)
{
- u64 aa64dfr0;
- int brps, wrps;
-
- aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
- brps = (aa64dfr0 >> 12) & 0xf;
- wrps = (aa64dfr0 >> 20) & 0xf;
+ int brps = *host_data_ptr(debug_brps);
+ int wrps = *host_data_ptr(debug_wrps);
save_debug(dbg->dbg_bcr, dbgbcr, brps);
save_debug(dbg->dbg_bvr, dbgbvr, brps);
@@ -124,13 +120,8 @@ static void __debug_save_state(struct kvm_guest_debug_arch *dbg,
static void __debug_restore_state(struct kvm_guest_debug_arch *dbg,
struct kvm_cpu_context *ctxt)
{
- u64 aa64dfr0;
- int brps, wrps;
-
- aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
-
- brps = (aa64dfr0 >> 12) & 0xf;
- wrps = (aa64dfr0 >> 20) & 0xf;
+ int brps = *host_data_ptr(debug_brps);
+ int wrps = *host_data_ptr(debug_wrps);
restore_debug(dbg->dbg_bcr, dbgbcr, brps);
restore_debug(dbg->dbg_bvr, dbgbvr, brps);
--
2.39.5
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v2 00/16] KVM: arm64: Debug cleanups
2024-11-15 22:49 [PATCH v2 00/16] KVM: arm64: Debug cleanups Oliver Upton
` (15 preceding siblings ...)
2024-11-15 22:49 ` [PATCH v2 16/16] KVM: arm64: Avoid reading ID_AA64DFR0_EL1 for debug save/restore Oliver Upton
@ 2024-11-22 11:08 ` James Clark
2024-11-30 3:08 ` Oliver Upton
16 siblings, 1 reply; 22+ messages in thread
From: James Clark @ 2024-11-22 11:08 UTC (permalink / raw)
To: Oliver Upton, kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei
On 15/11/2024 10:49 pm, Oliver Upton wrote:
> Second pass at cleaning up the mess of debug support / trap
> configuration we have.
>
> Marc, I haven't yet gotten around to moving the per-CPU value of
> mdcr_el2 into kvm_host_data. If you're alright with it, I'd like
> to clean up the configuration + storage of all the trap registers
> in a separate series, especially the pKVM bits of it.
>
> Tested the userspace-facing parts by single-stepping + setting
> breakpoints for a guest using QEMU's gdbstub. Tested the guest-facing
> side of things with the debug-exceptions selftest.
>
Hi Oliver,
I get this bug when running the selftests, but the tests themselves seem
to pass ok:
[ 105.534801] BUG: using smp_processor_id() in preemptible [00000000]
code: debug-exception/1046
[ 105.543466] caller is debug_smp_processor_id+0x20/0x30
[ 105.543470] CPU: 3 UID: 0 PID: 1046 Comm: debug-exception Not tainted
6.12.0-rc5+ #144
[ 105.543473] Call trace:
[ 105.543474] dump_backtrace+0x100/0x158
[ 105.543476] show_stack+0x24/0x38
[ 105.543477] dump_stack_lvl+0x3c/0x98
[ 105.543480] dump_stack+0x18/0x28
[ 105.543482] check_preemption_disabled+0xe0/0xe8
[ 105.543485] debug_smp_processor_id+0x20/0x30
[ 105.543488] kvm_debug_set_guest_ownership+0x48/0x130
[ 105.543490] trap_debug_regs+0x4c/0x88
[ 105.543492] perform_access+0x94/0x1b0
[ 105.543494] kvm_handle_sys_reg+0x12c/0x228
[ 105.543497] handle_exit+0x9c/0x158
[ 105.543498] kvm_arch_vcpu_ioctl_run+0x53c/0xa68
[ 105.543501] kvm_vcpu_ioctl+0x754/0x8a0
[ 105.543503] __arm64_sys_ioctl+0x9c/0xe0
[ 105.543505] invoke_syscall+0x4c/0x110
[ 105.543508] el0_svc_common+0xb8/0xf0
[ 105.543511] do_el0_svc+0x28/0x40
[ 105.543514] el0_svc+0x4c/0xc0
[ 105.543517] el0t_64_sync_handler+0x84/0x100
[ 105.543519] el0t_64_sync+0x190/0x198
> v1 -> v2:
> - Route debug exceptions to vEL2 if MDCR_EL2.TDE=1
> - Avoid reading ID_AA64DFR0_EL1 a bunch for debug save/restore
> - Set up HPMN with the right mask (Suzuki)
> - Minor cleanups on host_data_*_flag() helpers (Marc)
> - Squash patches responsible for updating debug_owner into 1 (Marc)
> - Un-macro a few things I needed macro'ed in v0 (Marc)
> - Completely rip out the debug tracepoints (Marc)
> - Add new documentation for debug_owner, 'external' debug behaviors
> (Marc)
>
> Oliver Upton (16):
> KVM: arm64: Drop MDSCR_EL1_DEBUG_MASK
> KVM: arm64: Get rid of __kvm_get_mdcr_el2() and related warts
> KVM: arm64: Track presence of SPE/TRBE in kvm_host_data instead of
> vCPU
> KVM: arm64: Move host SME/SVE tracking flags to host data
> KVM: arm64: Evaluate debug owner at vcpu_load()
> KVM: arm64: Clean up KVM_SET_GUEST_DEBUG handler
> KVM: arm64: Select debug state to save/restore based on debug owner
> KVM: arm64: Remove debug tracepoints
> KVM: arm64: Remove vestiges of debug_ptr
> KVM: arm64: Use debug_owner to track if debug regs need save/restore
> KVM: arm64: Reload vCPU for accesses to OSLAR_EL1
> KVM: arm64: Compute MDCR_EL2 at vcpu_load()
> KVM: arm64: Don't hijack guest context MDSCR_EL1
> KVM: arm64: Manage software step state at load/put
> KVM: arm64: nv: Honor MDCR_EL2.TDE routing for debug exceptions
> KVM: arm64: Avoid reading ID_AA64DFR0_EL1 for debug save/restore
>
> arch/arm64/include/asm/kvm_asm.h | 5 +-
> arch/arm64/include/asm/kvm_host.h | 94 +++---
> arch/arm64/include/asm/kvm_nested.h | 1 +
> arch/arm64/kvm/arm.c | 14 +-
> arch/arm64/kvm/debug.c | 376 +++++++--------------
> arch/arm64/kvm/emulate-nested.c | 23 +-
> arch/arm64/kvm/fpsimd.c | 12 +-
> arch/arm64/kvm/guest.c | 31 +-
> arch/arm64/kvm/handle_exit.c | 5 +-
> arch/arm64/kvm/hyp/include/hyp/debug-sr.h | 42 +--
> arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 43 ++-
> arch/arm64/kvm/hyp/nvhe/debug-sr.c | 13 +-
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 8 -
> arch/arm64/kvm/hyp/vhe/debug-sr.c | 5 -
> arch/arm64/kvm/sys_regs.c | 55 +--
> arch/arm64/kvm/trace_handle_exit.h | 75 ----
> 16 files changed, 279 insertions(+), 523 deletions(-)
>
>
> base-commit: 60ad25e14ab5a4e56c8bf7f7d6846eacb9cd53df
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v2 00/16] KVM: arm64: Debug cleanups
2024-11-22 11:08 ` [PATCH v2 00/16] KVM: arm64: Debug cleanups James Clark
@ 2024-11-30 3:08 ` Oliver Upton
0 siblings, 0 replies; 22+ messages in thread
From: Oliver Upton @ 2024-11-30 3:08 UTC (permalink / raw)
To: James Clark
Cc: kvmarm, Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Mingwei Zhang, Colton Lewis, Alexandru Elisei
Hey James,
On Fri, Nov 22, 2024 at 11:08:22AM +0000, James Clark wrote:
>
>
> On 15/11/2024 10:49 pm, Oliver Upton wrote:
> > Second pass at cleaning up the mess of debug support / trap
> > configuration we have.
> >
> > Marc, I haven't yet gotten around to moving the per-CPU value of
> > mdcr_el2 into kvm_host_data. If you're alright with it, I'd like
> > to clean up the configuration + storage of all the trap registers
> > in a separate series, especially the pKVM bits of it.
> >
> > Tested the userspace-facing parts by single-stepping + setting
> > breakpoints for a guest using QEMU's gdbstub. Tested the guest-facing
> > side of things with the debug-exceptions selftest.
> >
>
> Hi Oliver,
>
> I get this bug when running the selftests, but the tests themselves seem to
> pass ok:
Thanks for taking the series for a spin!
Yeah, this is a pretty damn obvious one, since kvm_arm_setup_mdcr_el2()
dereferences per-CPU data. I'll clean that up in v3.
--
Thanks,
Oliver
^ permalink raw reply [flat|nested] 22+ messages in thread