diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index eaac2c8d98b9..4da8f3319917 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -17,6 +17,7 @@
 #include <linux/uaccess.h>
 #include <linux/sched/stat.h>
 
+#include <asm/hfi.h>
 #include <asm/processor.h>
 #include <asm/user.h>
 #include <asm/fpu/xstate.h>
@@ -130,12 +131,77 @@ static inline struct kvm_cpuid_entry2 *cpuid_entry2_find(
 	return NULL;
 }
 
+static int kvm_check_hfi_cpuid(struct kvm_vcpu *vcpu,
+			       struct kvm_cpuid_entry2 *entries,
+			       int nent)
+{
+	struct hfi_features hfi_features;
+	struct kvm_cpuid_entry2 *best = NULL;
+	bool has_hfi;
+	int nr_classes, ret;
+	union cpuid6_ecx ecx;
+	union cpuid6_edx edx;
+	unsigned int data_size;
+
+	best = cpuid_entry2_find(entries, nent, 0x6, 0);
+	if (!best)
+		return 0;
+
+	has_hfi = cpuid_entry_has(best, X86_FEATURE_HFI);
+	if (!has_hfi)
+		return 0;
+
+	/*
+	 * Only the platform with 1 HFI instance (i.e., client platform)
+	 * can enable HFI in Guest. For more information, please refer to
+	 * the comment in kvm_set_cpu_caps().
+	 */
+	if (intel_hfi_max_instances() != 1)
+		return -EINVAL;
+
+	/*
+	 * Currently we haven't supported ITD. HFI is the default feature
+	 * with 1 class.
+	 */
+	nr_classes = 1;
+	ret = intel_hfi_build_virt_features(&hfi_features,
+					    nr_classes,
+					    vcpu->kvm->created_vcpus);
+	if (ret)
+		return ret;
+
+	ecx.full = best->ecx;
+	edx.full = best->edx;
+
+	if (ecx.split.nr_classes != hfi_features.nr_classes)
+		return -EINVAL;
+
+	if (hweight8(edx.split.capabilities.bits) != hfi_features.class_stride)
+		return -EINVAL;
+
+	if (edx.split.table_pages + 1 != hfi_features.nr_table_pages)
+		return -EINVAL;
+
+	/*
+	 * The total size of the row corresponding to index and all
+	 * previous data.
+	 */
+	data_size = hfi_features.hdr_size + (edx.split.index + 1) *
+		    hfi_features.cpu_stride;
+	/* Invalid index. */
+	if (data_size > hfi_features.nr_table_pages << PAGE_SHIFT)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
 			   struct kvm_cpuid_entry2 *entries,
 			   int nent)
 {
 	struct kvm_cpuid_entry2 *best;
 	u64 xfeatures;
+	int ret;
 
 	/*
 	 * The existing code assumes virtual address is 48-bit or 57-bit in the
@@ -155,15 +221,18 @@ static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
 	 * enabling in the FPU, e.g. to expand the guest XSAVE state size.
 	 */
 	best = cpuid_entry2_find(entries, nent, 0xd, 0);
-	if (!best)
-		return 0;
-
-	xfeatures = best->eax | ((u64)best->edx << 32);
-	xfeatures &= XFEATURE_MASK_USER_DYNAMIC;
-	if (!xfeatures)
-		return 0;
+	if (best) {
+		xfeatures = best->eax | ((u64)best->edx << 32);
+		xfeatures &= XFEATURE_MASK_USER_DYNAMIC;
+		if (xfeatures) {
+			ret = fpu_enable_guest_xfd_features(&vcpu->arch.guest_fpu,
+							    xfeatures);
+			if (ret)
+				return ret;
+		}
+	}
 
-	return fpu_enable_guest_xfd_features(&vcpu->arch.guest_fpu, xfeatures);
+	return kvm_check_hfi_cpuid(vcpu, entries, nent);
 }
 
 /* Check whether the supplied CPUID data is equal to what is already set for the vCPU. */
@@ -633,14 +702,27 @@ void kvm_set_cpu_caps(void)
 	);
 
 	/*
-	 * PTS is the dependency of ITD, currently we only use PTS for
-	 * enabling ITD in KVM. Since KVM does not support msr topology at
-	 * present, the emulation of PTS has restrictions on the topology of
-	 * Guest, so we only expose PTS when Host enables ITD.
+	 * PTS and HFI are the dependencies of ITD, currently we only use PTS/HFI
+	 * for enabling ITD in KVM. Since KVM does not support msr topology at
+	 * present, the emulation of PTS/HFI has restrictions on the topology of
+	 * Guest, so we only expose PTS/HFI when Host enables ITD.
+	 *
+	 * We also restrict HFI virtualization support to platforms with only 1 HFI
+	 * instance (i.e., this is the client platform, and ITD is currently a
+	 * client-specific feature), while server platforms with multiple instances
+	 * do not require HFI virtualization. This restriction avoids adding
+	 * additional complex logic to handle notification register updates when
+	 * vCPUs migrate between different HFI instances.
 	 */
-	if (cpu_feature_enabled(X86_FEATURE_ITD)) {
+	if (cpu_feature_enabled(X86_FEATURE_ITD) && intel_hfi_max_instances() == 1) {
 		if (boot_cpu_has(X86_FEATURE_PTS))
 			kvm_cpu_cap_set(X86_FEATURE_PTS);
+		/*
+		 * Set HFI based on hardware capability. Only when the Host has
+		 * the valid HFI instance, KVM can build the virtual HFI table.
+		 */
+		if (intel_hfi_enabled())
+			kvm_cpu_cap_set(X86_FEATURE_HFI);
 	}
 
 	kvm_cpu_cap_mask(CPUID_7_0_EBX,
@@ -986,8 +1068,32 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
 			entry->eax |= 0x4;
 
 		entry->ebx = 0;
-		entry->ecx = 0;
-		entry->edx = 0;
+
+		if (kvm_cpu_cap_has(X86_FEATURE_HFI)) {
+			union cpuid6_ecx ecx;
+			union cpuid6_edx edx;
+
+			ecx.full = 0;
+			edx.full = 0;
+			/* Number of supported HFI classes */
+			ecx.split.nr_classes = 1;
+			/* HFI supports performance and energy efficiency capabilities. */
+			edx.split.capabilities.split.performance = 1;
+			edx.split.capabilities.split.energy_efficiency = 1;
+			/* As default, keep the same HFI table size as host. */
+			edx.split.table_pages = ((union cpuid6_edx)entry->edx).split.table_pages;
+			/*
+			 * Default HFI index = 0. User should be careful that
+			 * the index differ for each CPUs.
+			 */
+			edx.split.index = 0;
+
+			entry->ecx = ecx.full;
+			entry->edx = edx.full;
+		} else {
+			entry->ecx = 0;
+			entry->edx = 0;
+		}
 		break;
 	/* function 7 has additional index. */
 	case 7:
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 9c28d4ea0b2d..636f2bd68546 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -8434,6 +8434,13 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
 		vmx->msr_ia32_feature_control_valid_bits &=
 			~FEAT_CTL_SGX_LC_ENABLED;
 
+	if (guest_cpuid_has(vcpu, X86_FEATURE_HFI) && intel_hfi_enabled()) {
+		struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry_index(vcpu, 0x6, 0);
+
+		if (best)
+			vmx->hfi_table_idx = ((union cpuid6_edx)best->edx).split.index;
+	}
+
 	/* Refresh #PF interception to account for MAXPHYADDR changes. */
 	vmx_update_exception_bitmap(vcpu);
 }
