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 {
        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));
 
         * 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) {
                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;