diff mbox series

[RFC,v2,07/69] KVM: TDX: define and export helper functions for KVM TDX support

Message ID 4fe4ce4faf5ad117f81d411deb00ef3b9657c842.1625186503.git.isaku.yamahata@intel.com (mailing list archive)
State New, archived
Headers show
Series KVM: X86: TDX support | expand

Commit Message

Isaku Yamahata July 2, 2021, 10:04 p.m. UTC
From: Sean Christopherson <sean.j.christopherson@intel.com>

NOTE: This is to make this patch series compile.  other patch series that
loads/initializes TDX module will replace this patch.

Define and export four helper functions commly used for for KVM TDX support
and SEAMLDR.  tdx_get_sysinfo(), tdx_seamcall_on_each_pkg(),
tdx_keyid_alloc() and tdx_keyid_free().  The SEAMLDR logic will initializes
at boot phase and KVM TDX will use those function to get system info,
operation of package wide resource and, alloc/free tdx private key ID.

Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
Co-developed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Co-developed-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
---
 arch/x86/Kbuild                     |   1 +
 arch/x86/include/asm/cpufeatures.h  |   2 +
 arch/x86/include/asm/kvm_boot.h     |  30 +++++
 arch/x86/kvm/boot/Makefile          |   6 +
 arch/x86/kvm/boot/seam/tdx_common.c | 167 ++++++++++++++++++++++++++++
 arch/x86/kvm/boot/seam/tdx_common.h |  13 +++
 6 files changed, 219 insertions(+)
 create mode 100644 arch/x86/include/asm/kvm_boot.h
 create mode 100644 arch/x86/kvm/boot/Makefile
 create mode 100644 arch/x86/kvm/boot/seam/tdx_common.c
 create mode 100644 arch/x86/kvm/boot/seam/tdx_common.h

Comments

Wang, Wei W Oct. 9, 2021, 7:50 a.m. UTC | #1
On Saturday, July 3, 2021 6:04 AM, Isaku Yamahata wrote:
> Subject: [RFC PATCH v2 07/69] KVM: TDX: define and export helper functions
> for KVM TDX support
> +/*
> + * Setup one-cpu-per-pkg array to do package-scoped SEAMCALLs. The
> +array is
> + * only necessary if there are multiple packages.
> + */
> +int __init init_package_masters(void)
> +{
> +	int cpu, pkg, nr_filled, nr_pkgs;
> +
> +	nr_pkgs = topology_max_packages();
> +	if (nr_pkgs == 1)
> +		return 0;
> +
> +	tdx_package_masters = kcalloc(nr_pkgs, sizeof(int), GFP_KERNEL);


Where is the corresponding kfree() invoked? (except the one invoked on error conditions below)


> +	if (!tdx_package_masters)
> +		return -ENOMEM;
> +
> +	memset(tdx_package_masters, -1, nr_pkgs * sizeof(int));
> +
> +	nr_filled = 0;
> +	for_each_online_cpu(cpu) {
> +		pkg = topology_physical_package_id(cpu);
> +		if (tdx_package_masters[pkg] >= 0)
> +			continue;
> +
> +		tdx_package_masters[pkg] = cpu;
> +		if (++nr_filled == topology_max_packages())
> +			break;
> +	}
> +
> +	if (WARN_ON(nr_filled != topology_max_packages())) {
> +		kfree(tdx_package_masters);
> +		return -EIO;
> +	}

Best,
Wei
diff mbox series

Patch

diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild
index 30dec019756b..4f35eaad7468 100644
--- a/arch/x86/Kbuild
+++ b/arch/x86/Kbuild
@@ -4,6 +4,7 @@  obj-y += entry/
 obj-$(CONFIG_PERF_EVENTS) += events/
 
 obj-$(CONFIG_KVM) += kvm/
+obj-$(subst m,y,$(CONFIG_KVM)) += kvm/boot/
 
 # Xen paravirtualization support
 obj-$(CONFIG_XEN) += xen/
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index ac37830ae941..fe5cfc013444 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -230,6 +230,8 @@ 
 #define X86_FEATURE_FLEXPRIORITY	( 8*32+ 2) /* Intel FlexPriority */
 #define X86_FEATURE_EPT			( 8*32+ 3) /* Intel Extended Page Table */
 #define X86_FEATURE_VPID		( 8*32+ 4) /* Intel Virtual Processor ID */
+#define X86_FEATURE_SEAM		( 8*32+ 5) /* "" Secure Arbitration Mode */
+#define X86_FEATURE_TDX			( 8*32+ 6) /* Intel Trusted Domain eXtensions */
 
 #define X86_FEATURE_VMMCALL		( 8*32+15) /* Prefer VMMCALL to VMCALL */
 #define X86_FEATURE_XENPV		( 8*32+16) /* "" Xen paravirtual guest */
diff --git a/arch/x86/include/asm/kvm_boot.h b/arch/x86/include/asm/kvm_boot.h
new file mode 100644
index 000000000000..3d58d4109566
--- /dev/null
+++ b/arch/x86/include/asm/kvm_boot.h
@@ -0,0 +1,30 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_X86_KVM_BOOT_H
+#define _ASM_X86_KVM_BOOT_H
+
+#include <linux/cpumask.h>
+#include <linux/mutex.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_KVM_INTEL_TDX
+
+/*
+ * Return pointer to TDX system info (TDSYSINFO_STRUCT) if TDX has been
+ * successfully initialized, or NULL.
+ */
+struct tdsysinfo_struct;
+const struct tdsysinfo_struct *tdx_get_sysinfo(void);
+
+extern u32 tdx_seam_keyid __ro_after_init;
+
+int tdx_seamcall_on_each_pkg(int (*fn)(void *), void *param);
+
+/* TDX keyID allocation functions */
+extern int tdx_keyid_alloc(void);
+extern void tdx_keyid_free(int keyid);
+
+#endif
+
+#endif /* _ASM_X86_KVM_BOOT_H */
diff --git a/arch/x86/kvm/boot/Makefile b/arch/x86/kvm/boot/Makefile
new file mode 100644
index 000000000000..a85eb5af90d5
--- /dev/null
+++ b/arch/x86/kvm/boot/Makefile
@@ -0,0 +1,6 @@ 
+# SPDX-License-Identifier: GPL-2.0
+
+asflags-y += -I$(srctree)/arch/x86/kvm
+ccflags-y += -I$(srctree)/arch/x86/kvm
+
+obj-$(CONFIG_KVM_INTEL_TDX) += seam/tdx_common.o
diff --git a/arch/x86/kvm/boot/seam/tdx_common.c b/arch/x86/kvm/boot/seam/tdx_common.c
new file mode 100644
index 000000000000..d803dbd11693
--- /dev/null
+++ b/arch/x86/kvm/boot/seam/tdx_common.c
@@ -0,0 +1,167 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Common functions/symbols for SEAMLDR and KVM. */
+
+#include <linux/cpuhotplug.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/idr.h>
+
+#include <asm/kvm_boot.h>
+
+#include "vmx/tdx_arch.h"
+
+/*
+ * TDX system information returned by TDSYSINFO.
+ */
+struct tdsysinfo_struct tdx_tdsysinfo;
+
+/* KeyID range reserved to TDX by BIOS */
+u32 tdx_keyids_start;
+u32 tdx_nr_keyids;
+
+u32 tdx_seam_keyid __ro_after_init;
+EXPORT_SYMBOL_GPL(tdx_seam_keyid);
+
+/* TDX keyID pool */
+static DEFINE_IDA(tdx_keyid_pool);
+
+static int *tdx_package_masters __ro_after_init;
+
+static int tdx_starting_cpu(unsigned int cpu)
+{
+	int pkg = topology_physical_package_id(cpu);
+
+	/*
+	 * If this package doesn't have a master CPU for IPI operation, use this
+	 * CPU as package master.
+	 */
+	if (tdx_package_masters && tdx_package_masters[pkg] == -1)
+		tdx_package_masters[pkg] = cpu;
+
+	return 0;
+}
+
+static int tdx_dying_cpu(unsigned int cpu)
+{
+	int pkg = topology_physical_package_id(cpu);
+	int other;
+
+	if (!tdx_package_masters || tdx_package_masters[pkg] != cpu)
+		return 0;
+
+	/*
+	 * If offlining cpu was used as package master, find other online cpu on
+	 * this package.
+	 */
+	tdx_package_masters[pkg] = -1;
+	for_each_online_cpu(other) {
+		if (other == cpu)
+			continue;
+		if (topology_physical_package_id(other) != pkg)
+			continue;
+
+		tdx_package_masters[pkg] = other;
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Setup one-cpu-per-pkg array to do package-scoped SEAMCALLs. The array is
+ * only necessary if there are multiple packages.
+ */
+int __init init_package_masters(void)
+{
+	int cpu, pkg, nr_filled, nr_pkgs;
+
+	nr_pkgs = topology_max_packages();
+	if (nr_pkgs == 1)
+		return 0;
+
+	tdx_package_masters = kcalloc(nr_pkgs, sizeof(int), GFP_KERNEL);
+	if (!tdx_package_masters)
+		return -ENOMEM;
+
+	memset(tdx_package_masters, -1, nr_pkgs * sizeof(int));
+
+	nr_filled = 0;
+	for_each_online_cpu(cpu) {
+		pkg = topology_physical_package_id(cpu);
+		if (tdx_package_masters[pkg] >= 0)
+			continue;
+
+		tdx_package_masters[pkg] = cpu;
+		if (++nr_filled == topology_max_packages())
+			break;
+	}
+
+	if (WARN_ON(nr_filled != topology_max_packages())) {
+		kfree(tdx_package_masters);
+		return -EIO;
+	}
+
+	if (cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "tdx/cpu:starting",
+				      tdx_starting_cpu, tdx_dying_cpu) < 0) {
+		kfree(tdx_package_masters);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int tdx_seamcall_on_each_pkg(int (*fn)(void *), void *param)
+{
+	int ret = 0;
+	int i;
+
+	cpus_read_lock();
+	if (!tdx_package_masters) {
+		ret = fn(param);
+		goto out;
+	}
+
+	for (i = 0; i < topology_max_packages(); i++) {
+		ret = smp_call_on_cpu(tdx_package_masters[i], fn, param, 1);
+		if (ret)
+			break;
+	}
+
+out:
+	cpus_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tdx_seamcall_on_each_pkg);
+
+const struct tdsysinfo_struct *tdx_get_sysinfo(void)
+{
+	if (boot_cpu_has(X86_FEATURE_TDX))
+		return &tdx_tdsysinfo;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(tdx_get_sysinfo);
+
+int tdx_keyid_alloc(void)
+{
+	if (!boot_cpu_has(X86_FEATURE_TDX))
+		return -EINVAL;
+
+	if (WARN_ON_ONCE(!tdx_keyids_start || !tdx_nr_keyids))
+		return -EINVAL;
+
+	/* The first keyID is reserved for the global key. */
+	return ida_alloc_range(&tdx_keyid_pool, tdx_keyids_start + 1,
+			       tdx_keyids_start + tdx_nr_keyids - 1,
+			       GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(tdx_keyid_alloc);
+
+void tdx_keyid_free(int keyid)
+{
+	if (!keyid || keyid < 0)
+		return;
+
+	ida_free(&tdx_keyid_pool, keyid);
+}
+EXPORT_SYMBOL_GPL(tdx_keyid_free);
diff --git a/arch/x86/kvm/boot/seam/tdx_common.h b/arch/x86/kvm/boot/seam/tdx_common.h
new file mode 100644
index 000000000000..6f94ebb2b815
--- /dev/null
+++ b/arch/x86/kvm/boot/seam/tdx_common.h
@@ -0,0 +1,13 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* common functions/symbols used by SEAMLDR and KVM */
+
+#ifndef __BOOT_SEAM_TDX_COMMON_H
+#define __BOOT_SEAM_TDX_COMMON_H
+
+extern struct tdsysinfo_struct tdx_tdsysinfo;
+extern u32 tdx_keyids_start;
+extern u32 tdx_nr_keyids;
+
+int __init init_package_masters(void);
+
+#endif /* __BOOT_SEAM_TDX_COMMON_H */