]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: nv: Reinject traps that take effect in Host EL0
authorOliver Upton <oliver.upton@linux.dev>
Fri, 25 Oct 2024 18:23:43 +0000 (18:23 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Thu, 31 Oct 2024 19:00:39 +0000 (19:00 +0000)
Wire up the other end of traps that affect host EL0 by actually
injecting them into the guest hypervisor. Skip over FGT entirely, as a
cursory glance suggests no FGT is effective in host EL0.

Note that kvm_inject_nested() is already equipped for handling
exceptions while the VM is already in a host context.

Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20241025182354.3364124-9-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/kvm/emulate-nested.c

index a601a9305b104f3fb4c4d32746616d71a90bf0d5..bf0c48403f594eb9492f4433f2975dfa3de72494 100644 (file)
@@ -225,6 +225,11 @@ static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
        return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt);
 }
 
+static inline bool vcpu_is_host_el0(const struct kvm_vcpu *vcpu)
+{
+       return is_hyp_ctxt(vcpu) && !vcpu_is_el2(vcpu);
+}
+
 /*
  * The layout of SPSR for an AArch32 state is different when observed from an
  * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
index e1a30d1bcd064877a12191966dfdb2a1cc5aac81..b072098ee44ec33e23225673c53210f48dd13a6d 100644 (file)
@@ -20,6 +20,9 @@ enum trap_behaviour {
        BEHAVE_FORWARD_READ     = BIT(0),
        BEHAVE_FORWARD_WRITE    = BIT(1),
        BEHAVE_FORWARD_RW       = BEHAVE_FORWARD_READ | BEHAVE_FORWARD_WRITE,
+
+       /* Traps that take effect in Host EL0, this is rare! */
+       BEHAVE_FORWARD_IN_HOST_EL0      = BIT(2),
 };
 
 struct trap_bits {
@@ -2128,11 +2131,19 @@ static u64 kvm_get_sysreg_res0(struct kvm *kvm, enum vcpu_sysreg sr)
        return masks->mask[sr - __VNCR_START__].res0;
 }
 
-static bool check_fgt_bit(struct kvm *kvm, bool is_read,
+static bool check_fgt_bit(struct kvm_vcpu *vcpu, bool is_read,
                          u64 val, const union trap_config tc)
 {
+       struct kvm *kvm = vcpu->kvm;
        enum vcpu_sysreg sr;
 
+       /*
+        * KVM doesn't know about any FGTs that apply to the host, and hopefully
+        * that'll remain the case.
+        */
+       if (is_hyp_ctxt(vcpu))
+               return false;
+
        if (tc.pol)
                return (val & BIT(tc.bit));
 
@@ -2209,7 +2220,15 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
         * If we're not nesting, immediately return to the caller, with the
         * sysreg index, should we have it.
         */
-       if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
+       if (!vcpu_has_nv(vcpu))
+               goto local;
+
+       /*
+        * There are a few traps that take effect InHost, but are constrained
+        * to EL0. Don't bother with computing the trap behaviour if the vCPU
+        * isn't in EL0.
+        */
+       if (is_hyp_ctxt(vcpu) && !vcpu_is_host_el0(vcpu))
                goto local;
 
        switch ((enum fgt_group_id)tc.fgt) {
@@ -2255,12 +2274,14 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
                goto local;
        }
 
-       if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu->kvm, is_read,
-                                                       val, tc))
+       if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu, is_read, val, tc))
                goto inject;
 
        b = compute_trap_behaviour(vcpu, tc);
 
+       if (!(b & BEHAVE_FORWARD_IN_HOST_EL0) && vcpu_is_host_el0(vcpu))
+               goto local;
+
        if (((b & BEHAVE_FORWARD_READ) && is_read) ||
            ((b & BEHAVE_FORWARD_WRITE) && !is_read))
                goto inject;