/* run->fail_entry.hardware_entry_failure_reason codes. */
 #define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED    (1ULL << 0)
 
+enum kvm_smccc_filter_action {
+       KVM_SMCCC_FILTER_HANDLE = 0,
+       KVM_SMCCC_FILTER_DENY,
+
+#ifdef __KERNEL__
+       NR_SMCCC_FILTER_ACTIONS
+#endif
+};
+
 #endif
 
 #endif /* __ARM_KVM_H__ */
 
        val[3] = lower_32_bits(cycles);
 }
 
-static bool kvm_hvc_call_default_allowed(u32 func_id)
+static bool kvm_smccc_default_allowed(u32 func_id)
 {
        switch (func_id) {
        /*
        }
 }
 
-static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
+static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id)
 {
        struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
 
                return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP,
                                &smccc_feat->vendor_hyp_bmap);
        default:
-               return kvm_hvc_call_default_allowed(func_id);
+               return false;
        }
 }
 
+static u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id)
+{
+       if (kvm_smccc_test_fw_bmap(vcpu, func_id) ||
+           kvm_smccc_default_allowed(func_id))
+               return KVM_SMCCC_FILTER_HANDLE;
+
+       return KVM_SMCCC_FILTER_DENY;
+}
+
 int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
 {
        struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
        u32 func_id = smccc_get_function(vcpu);
        u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
        u32 feature;
+       u8 action;
        gpa_t gpa;
 
-       if (!kvm_hvc_call_allowed(vcpu, func_id))
+       action = kvm_smccc_get_action(vcpu, func_id);
+       switch (action) {
+       case KVM_SMCCC_FILTER_HANDLE:
+               break;
+       case KVM_SMCCC_FILTER_DENY:
+               goto out;
+       default:
+               WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action);
                goto out;
+       }
 
        switch (func_id) {
        case ARM_SMCCC_VERSION_FUNC_ID: