]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: nv: Respect virtual HCR_EL2.TWx setting
authorJintack Lim <jintack.lim@linaro.org>
Tue, 25 Feb 2025 17:29:25 +0000 (17:29 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Mon, 3 Mar 2025 22:57:10 +0000 (14:57 -0800)
Forward exceptions due to WFI or WFE instructions to the virtual EL2 if
they are not coming from the virtual EL2 and virtual HCR_EL2.TWx is set.

Signed-off-by: Jintack Lim <jintack.lim@linaro.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250225172930.1850838-12-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/kvm/handle_exit.c

index 78ec1ef2cfe82ac31b19cc26ece0d94cea19b46c..d4e4212ff5967493825efb2ced96aef49b368c9d 100644 (file)
@@ -275,6 +275,19 @@ static __always_inline u64 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.fault.esr_el2;
 }
 
+static inline bool guest_hyp_wfx_traps_enabled(const struct kvm_vcpu *vcpu)
+{
+       u64 esr = kvm_vcpu_get_esr(vcpu);
+       bool is_wfe = !!(esr & ESR_ELx_WFx_ISS_WFE);
+       u64 hcr_el2 = __vcpu_sys_reg(vcpu, HCR_EL2);
+
+       if (!vcpu_has_nv(vcpu) || vcpu_is_el2(vcpu))
+               return false;
+
+       return ((is_wfe && (hcr_el2 & HCR_TWE)) ||
+               (!is_wfe && (hcr_el2 & HCR_TWI)));
+}
+
 static __always_inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
 {
        u64 esr = kvm_vcpu_get_esr(vcpu);
index 512d152233ff20eb6c65abbf731b4bcb543a7d07..b73dc26bc44b410903e2423551d61d4e65fd7e1e 100644 (file)
@@ -129,8 +129,12 @@ static int kvm_handle_fpasimd(struct kvm_vcpu *vcpu)
 static int kvm_handle_wfx(struct kvm_vcpu *vcpu)
 {
        u64 esr = kvm_vcpu_get_esr(vcpu);
+       bool is_wfe = !!(esr & ESR_ELx_WFx_ISS_WFE);
 
-       if (esr & ESR_ELx_WFx_ISS_WFE) {
+       if (guest_hyp_wfx_traps_enabled(vcpu))
+               return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
+
+       if (is_wfe) {
                trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true);
                vcpu->stat.wfe_exit_stat++;
        } else {