Re: [PATCH v6] KVM: arm64: Add early_param to control WFx trapping

Jing Zhang
2024-06-14T16:26:01Z

Hi Colton,

On Thu, May 23, 2024 at 10:41 AM Colton Lewis <coltonlewis@google.com> wrote:
>
> Add an early_params to control WFI and WFE trapping. This is to
> control the degree guests can wait for interrupts on their own without
> being trapped by KVM. Options for each param are trap and notrap. trap
> enables the trap. notrap disables the trap. Note that when enabled,
> traps are allowed but not guaranteed by the CPU architecture. Absent
> an explicitly set policy, default to current behavior: disabling the
> trap if only a single task is running and enabling otherwise.
>
> Signed-off-by: Colton Lewis <coltonlewis@google.com>
> ---
> v6:
> * Rebase to v6.9.1
> * Move decision to enable WFx traps back to vcpu load time
> * Move policy enum to arm.c and mark variable as __read_mostly
> * Add explicit disclaimer traps are not guaranteed even when setting enabled
> * Remove explicit "default" case from early param handling as it is not needed
>
> v5:
> https://lore.kernel.org/kvmarm/20240430181444.670773-1-coltonlewis@google.com/
>
> v4:
> https://lore.kernel.org/kvmarm/20240422181716.237284-1-coltonlewis@google.com/
>
> v3:
> https://lore.kernel.org/kvmarm/20240410175437.793508-1-coltonlewis@google.com/
>
> v2:
> https://lore.kernel.org/kvmarm/20240319164341.1674863-1-coltonlewis@google.com/
>
> v1:
> https://lore.kernel.org/kvmarm/20240129213918.3124494-1-coltonlewis@google.com/
>
> .../admin-guide/kernel-parameters.txt | 18 +++++
> arch/arm64/include/asm/kvm_emulate.h | 16 -----
> arch/arm64/kvm/arm.c | 68 ++++++++++++++++++-
> 3 files changed, 83 insertions(+), 19 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 396137ee018d..f334265a9cfa 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -2693,6 +2693,24 @@
> [KVM,ARM,EARLY] Allow use of GICv4 for direct
> injection of LPIs.
>
> + kvm-arm.wfe_trap_policy=
> + [KVM,ARM] Control when to set WFE instruction trap for
> + KVM VMs. Traps are allowed but not guaranteed by the
> + CPU architecture.
> +
> + trap: set WFE instruction trap
> +
> + notrap: clear WFE instruction trap
> +
> + kvm-arm.wfi_trap_policy=
> + [KVM,ARM] Control when to set WFI instruction trap for
> + KVM VMs. Traps are allowed but not guaranteed by the
> + CPU architecture.
> +
> + trap: set WFI instruction trap
> +
> + notrap: clear WFI instruction trap
> +
> kvm_cma_resv_ratio=n [PPC,EARLY]
> Reserves given percentage from system memory area for
> contiguous memory allocation for KVM hash pagetable
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 975af30af31f..68c4a170b871 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -109,22 +109,6 @@ static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
> return (unsigned long *)&vcpu->arch.hcr_el2;
> }
>
> -static inline void vcpu_clear_wfx_traps(struct kvm_vcpu *vcpu)
> -{
> - vcpu->arch.hcr_el2 &= ~HCR_TWE;
> - if (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) ||
> - vcpu->kvm->arch.vgic.nassgireq)
> - vcpu->arch.hcr_el2 &= ~HCR_TWI;
> - else
> - vcpu->arch.hcr_el2 |= HCR_TWI;
> -}
> -
> -static inline void vcpu_set_wfx_traps(struct kvm_vcpu *vcpu)
> -{
> - vcpu->arch.hcr_el2 |= HCR_TWE;
> - vcpu->arch.hcr_el2 |= HCR_TWI;
> -}
> -
> static inline void vcpu_ptrauth_enable(struct kvm_vcpu *vcpu)
> {
> vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK);
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index c4a0a35e02c7..1cd58ca5d410 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -47,6 +47,15 @@
>
> static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
>
> +enum kvm_wfx_trap_policy {
> + KVM_WFX_NOTRAP_SINGLE_TASK, /* Default option */
> + KVM_WFX_NOTRAP,
> + KVM_WFX_TRAP,
> +};
> +
> +static enum kvm_wfx_trap_policy kvm_wfi_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
> +static enum kvm_wfx_trap_policy kvm_wfe_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
> +
> DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
>
> DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
> @@ -428,6 +437,24 @@ void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
>
> }
>
> +static bool kvm_vcpu_should_clear_twi(struct kvm_vcpu *vcpu)
> +{
> + if (likely(kvm_wfi_trap_policy == KVM_WFX_NOTRAP_SINGLE_TASK))
> + return single_task_running() &&
> + (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) ||
> + vcpu->kvm->arch.vgic.nassgireq);
> +
> + return kvm_wfi_trap_policy == KVM_WFX_NOTRAP;
> +}
> +
> +static bool kvm_vcpu_should_clear_twe(struct kvm_vcpu *vcpu)
> +{
> + if (likely(kvm_wfe_trap_policy == KVM_WFX_NOTRAP_SINGLE_TASK))
> + return single_task_running();
> +
> + return kvm_wfe_trap_policy == KVM_WFX_NOTRAP;
> +}
> +
> void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> {
> struct kvm_s2_mmu *mmu;
> @@ -461,10 +488,15 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
> kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
>
> - if (single_task_running())
> - vcpu_clear_wfx_traps(vcpu);
> + if (kvm_vcpu_should_clear_twe(vcpu))
> + vcpu->arch.hcr_el2 &= ~HCR_TWE;
> + else
> + vcpu->arch.hcr_el2 |= HCR_TWE;
> +
> + if (kvm_vcpu_should_clear_twi(vcpu))
> + vcpu->arch.hcr_el2 &= ~HCR_TWI;
> else
> - vcpu_set_wfx_traps(vcpu);
> + vcpu->arch.hcr_el2 |= HCR_TWI;
>
> if (vcpu_has_ptrauth(vcpu))
> vcpu_ptrauth_disable(vcpu);
> @@ -2663,6 +2695,36 @@ static int __init early_kvm_mode_cfg(char *arg)
> }
> early_param("kvm-arm.mode", early_kvm_mode_cfg);
>
> +static int __init early_kvm_wfx_trap_policy_cfg(char *arg, enum kvm_wfx_trap_policy *p)
> +{
> + if (!arg)
> + return -EINVAL;
> +
> + if (strcmp(arg, "trap") == 0) {
> + *p = KVM_WFX_TRAP;
> + return 0;
> + }
> +
> + if (strcmp(arg, "notrap") == 0) {
> + *p = KVM_WFX_NOTRAP;
> + return 0;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int __init early_kvm_wfi_trap_policy_cfg(char *arg)
> +{
> + return early_kvm_wfx_trap_policy_cfg(arg, &kvm_wfi_trap_policy);
> +}
> +early_param("kvm-arm.wfi_trap_policy", early_kvm_wfi_trap_policy_cfg);
> +
> +static int __init early_kvm_wfe_trap_policy_cfg(char *arg)
> +{
> + return early_kvm_wfx_trap_policy_cfg(arg, &kvm_wfe_trap_policy);
> +}
> +early_param("kvm-arm.wfe_trap_policy", early_kvm_wfe_trap_policy_cfg);
> +
> enum kvm_mode kvm_get_mode(void)
> {
> return kvm_mode;
> --
> 2.45.1.288.g0e0cd299f1-goog
>

Reviewed-by: Jing Zhang <jingzhangos@google.com>

Jing