[PATCH v2 05/21] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs

Chao Gao posted 21 patches 4 months, 1 week ago
There is a newer version of this series
[PATCH v2 05/21] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
Posted by Chao Gao 4 months, 1 week ago
Software needs to talk with P-SEAMLDR via P-SEAMLDR SEAMCALLs. So, add a
wrapper for P-SEAMLDR SEAMCALLs.

Save and restore the current VMCS using VMPTRST and VMPTRLD instructions
to avoid breaking KVM. Doing so is because P-SEAMLDR SEAMCALLs would
invalidate the current VMCS as documented in Intel® Trust Domain CPU
Architectural Extensions (May 2021 edition) Chapter 2.3 [1]:

  SEAMRET from the P-SEAMLDR clears the current VMCS structure pointed
  to by the current-VMCS pointer. A VMM that invokes the P-SEAMLDR using
  SEAMCALL must reload the current-VMCS, if required, using the VMPTRLD
  instruction.

Disable interrupts to prevent KVM code from interfering with P-SEAMLDR
SEAMCALLs. For example, if a vCPU is scheduled before the current VMCS is
restored, it may encounter an invalid current VMCS, causing its VMX
instruction to fail. Additionally, if KVM sends IPIs to invalidate a
current VMCS and the invalidation occurs right after the current VMCS is
saved, that VMCS will be reloaded after P-SEAMLDR SEAMCALLs, leading to
unexpected behavior.

NMIs are not a problem, as the only scenario where instructions relying on
the current-VMCS are used is during guest PMI handling in KVM. This occurs
immediately after VM exits with IRQ and NMI disabled, ensuring no
interference with P-SEAMLDR SEAMCALLs.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
Link: https://cdrdv2.intel.com/v1/dl/getContent/733582 # [1]
---
v2:
 - don't create a new, inferior framework to save/restore VMCS
 - use human-friendly language, just "current VMCS" rather than
   SDM term "current-VMCS pointer"
 - don't mix guard() with goto
---
 arch/x86/Kconfig                | 10 ++++++
 arch/x86/virt/vmx/tdx/Makefile  |  1 +
 arch/x86/virt/vmx/tdx/seamldr.c | 56 +++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+)
 create mode 100644 arch/x86/virt/vmx/tdx/seamldr.c

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 58d890fe2100..6b47383d2958 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1905,6 +1905,16 @@ config INTEL_TDX_HOST
 
 	  If unsure, say N.
 
+config INTEL_TDX_MODULE_UPDATE
+	bool "Intel TDX module runtime update"
+	depends on TDX_HOST_SERVICES
+	help
+	  This enables the kernel to support TDX module runtime update. This
+	  allows the admin to update the TDX module to the same or any newer
+	  version without the need to terminate running TDX guests.
+
+	  If unsure, say N.
+
 config EFI
 	bool "EFI runtime service support"
 	depends on ACPI
diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
index 90da47eb85ee..26aea3531c36 100644
--- a/arch/x86/virt/vmx/tdx/Makefile
+++ b/arch/x86/virt/vmx/tdx/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y += seamcall.o tdx.o
+obj-$(CONFIG_INTEL_TDX_MODULE_UPDATE) += seamldr.o
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
new file mode 100644
index 000000000000..b99d73f7bb08
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright(c) 2025 Intel Corporation.
+ *
+ * Intel TDX module runtime update
+ */
+#define pr_fmt(fmt)	"seamldr: " fmt
+
+#include <linux/irqflags.h>
+#include <linux/types.h>
+
+#include "seamcall.h"
+
+static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
+{
+	unsigned long flags;
+	u64 vmcs;
+	int ret;
+
+	if (!is_seamldr_call(fn))
+		return -EINVAL;
+
+	/*
+	 * SEAMRET from P-SEAMLDR invalidates the current VMCS.  Save/restore
+	 * the VMCS across P-SEAMLDR SEAMCALLs to avoid clobbering KVM state.
+	 * Disable interrupts as KVM is allowed to do VMREAD/VMWRITE in IRQ
+	 * context (but not NMI context).
+	 */
+	local_irq_save(flags);
+
+	asm goto("1: vmptrst %0\n\t"
+		 _ASM_EXTABLE(1b, %l[error])
+		 : "=m" (vmcs) : : "cc" : error);
+
+	ret = seamldr_prerr(fn, args);
+
+	/*
+	 * Restore the current VMCS pointer.  VMPTSTR "returns" all ones if the
+	 * current VMCS is invalid.
+	 */
+	if (vmcs != -1ULL) {
+		asm goto("1: vmptrld %0\n\t"
+			 "jna %l[error]\n\t"
+			 _ASM_EXTABLE(1b, %l[error])
+			 : : "m" (vmcs) : "cc" : error);
+	}
+
+	local_irq_restore(flags);
+	return ret;
+
+error:
+	local_irq_restore(flags);
+
+	WARN_ONCE(1, "Failed to save/restore the current VMCS");
+	return -EIO;
+}
-- 
2.47.3

Re: [PATCH v2 05/21] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
Posted by Duan, Zhenzhong 3 weeks, 5 days ago
On 10/1/2025 10:52 AM, Chao Gao wrote:
> Software needs to talk with P-SEAMLDR via P-SEAMLDR SEAMCALLs. So, add a
> wrapper for P-SEAMLDR SEAMCALLs.
>
> Save and restore the current VMCS using VMPTRST and VMPTRLD instructions
> to avoid breaking KVM. Doing so is because P-SEAMLDR SEAMCALLs would
> invalidate the current VMCS as documented in Intel® Trust Domain CPU
> Architectural Extensions (May 2021 edition) Chapter 2.3 [1]:
>
>    SEAMRET from the P-SEAMLDR clears the current VMCS structure pointed
>    to by the current-VMCS pointer. A VMM that invokes the P-SEAMLDR using
>    SEAMCALL must reload the current-VMCS, if required, using the VMPTRLD
>    instruction.
>
> Disable interrupts to prevent KVM code from interfering with P-SEAMLDR
> SEAMCALLs. For example, if a vCPU is scheduled before the current VMCS is
> restored, it may encounter an invalid current VMCS, causing its VMX
> instruction to fail. Additionally, if KVM sends IPIs to invalidate a
> current VMCS and the invalidation occurs right after the current VMCS is
> saved, that VMCS will be reloaded after P-SEAMLDR SEAMCALLs, leading to
> unexpected behavior.
>
> NMIs are not a problem, as the only scenario where instructions relying on
> the current-VMCS are used is during guest PMI handling in KVM. This occurs
> immediately after VM exits with IRQ and NMI disabled, ensuring no
> interference with P-SEAMLDR SEAMCALLs.
>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Tested-by: Farrah Chen <farrah.chen@intel.com>
> Link: https://cdrdv2.intel.com/v1/dl/getContent/733582 # [1]
> ---
> v2:
>   - don't create a new, inferior framework to save/restore VMCS
>   - use human-friendly language, just "current VMCS" rather than
>     SDM term "current-VMCS pointer"
>   - don't mix guard() with goto
> ---
>   arch/x86/Kconfig                | 10 ++++++
>   arch/x86/virt/vmx/tdx/Makefile  |  1 +
>   arch/x86/virt/vmx/tdx/seamldr.c | 56 +++++++++++++++++++++++++++++++++
>   3 files changed, 67 insertions(+)
>   create mode 100644 arch/x86/virt/vmx/tdx/seamldr.c
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 58d890fe2100..6b47383d2958 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1905,6 +1905,16 @@ config INTEL_TDX_HOST
>   
>   	  If unsure, say N.
>   
> +config INTEL_TDX_MODULE_UPDATE
> +	bool "Intel TDX module runtime update"
> +	depends on TDX_HOST_SERVICES
> +	help
> +	  This enables the kernel to support TDX module runtime update. This
> +	  allows the admin to update the TDX module to the same or any newer
> +	  version without the need to terminate running TDX guests.
> +
> +	  If unsure, say N.
> +
>   config EFI
>   	bool "EFI runtime service support"
>   	depends on ACPI
> diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
> index 90da47eb85ee..26aea3531c36 100644
> --- a/arch/x86/virt/vmx/tdx/Makefile
> +++ b/arch/x86/virt/vmx/tdx/Makefile
> @@ -1,2 +1,3 @@
>   # SPDX-License-Identifier: GPL-2.0-only
>   obj-y += seamcall.o tdx.o
> +obj-$(CONFIG_INTEL_TDX_MODULE_UPDATE) += seamldr.o

Not clear if seamldr will support other features besides TDX module update,

if yes, maybe more general name CONFIG_INTEL_SEAMLDR?

> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> new file mode 100644
> index 000000000000..b99d73f7bb08
> --- /dev/null
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -0,0 +1,56 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright(c) 2025 Intel Corporation.
> + *
> + * Intel TDX module runtime update
> + */
> +#define pr_fmt(fmt)	"seamldr: " fmt
> +
> +#include <linux/irqflags.h>
> +#include <linux/types.h>
> +
> +#include "seamcall.h"
> +
> +static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
> +{
> +	unsigned long flags;
> +	u64 vmcs;
> +	int ret;
> +
> +	if (!is_seamldr_call(fn))
> +		return -EINVAL;
> +
> +	/*
> +	 * SEAMRET from P-SEAMLDR invalidates the current VMCS.  Save/restore
> +	 * the VMCS across P-SEAMLDR SEAMCALLs to avoid clobbering KVM state.
> +	 * Disable interrupts as KVM is allowed to do VMREAD/VMWRITE in IRQ
> +	 * context (but not NMI context).
> +	 */
> +	local_irq_save(flags);
> +
> +	asm goto("1: vmptrst %0\n\t"
> +		 _ASM_EXTABLE(1b, %l[error])
> +		 : "=m" (vmcs) : : "cc" : error);
> +
> +	ret = seamldr_prerr(fn, args);
> +
> +	/*
> +	 * Restore the current VMCS pointer.  VMPTSTR "returns" all ones if the
> +	 * current VMCS is invalid.
> +	 */
> +	if (vmcs != -1ULL) {
> +		asm goto("1: vmptrld %0\n\t"
> +			 "jna %l[error]\n\t"
> +			 _ASM_EXTABLE(1b, %l[error])
> +			 : : "m" (vmcs) : "cc" : error);
> +	}
> +
> +	local_irq_restore(flags);
> +	return ret;
> +
> +error:
> +	local_irq_restore(flags);
> +
> +	WARN_ONCE(1, "Failed to save/restore the current VMCS");
> +	return -EIO;
> +}
Re: [PATCH v2 05/21] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
Posted by Chao Gao 3 weeks, 4 days ago
>> diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
>> index 90da47eb85ee..26aea3531c36 100644
>> --- a/arch/x86/virt/vmx/tdx/Makefile
>> +++ b/arch/x86/virt/vmx/tdx/Makefile
>> @@ -1,2 +1,3 @@
>>   # SPDX-License-Identifier: GPL-2.0-only
>>   obj-y += seamcall.o tdx.o
>> +obj-$(CONFIG_INTEL_TDX_MODULE_UPDATE) += seamldr.o
>
>Not clear if seamldr will support other features besides TDX module update,
>
>if yes, maybe more general name CONFIG_INTEL_SEAMLDR?

Currently, no other features. So, CONFIG_INTEL_TDX_MODULE_UPDATE should be
good for now. If some new feature emerges, we can add CONFIG_INTEL_SEAMLDR and
make CONFIG_INTEL_TDX_MODULE_UPDATE and new features select it.
Re: [PATCH v2 05/21] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
Posted by Xu Yilun 3 weeks, 6 days ago
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 58d890fe2100..6b47383d2958 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1905,6 +1905,16 @@ config INTEL_TDX_HOST
>  
>  	  If unsure, say N.
>  
> +config INTEL_TDX_MODULE_UPDATE
> +	bool "Intel TDX module runtime update"
> +	depends on TDX_HOST_SERVICES
> +	help
> +	  This enables the kernel to support TDX module runtime update. This
> +	  allows the admin to update the TDX module to the same or any newer
> +	  version without the need to terminate running TDX guests.

I'm wondering if it is better to put this option in
drivers/virt/coco/tdx-host. Just as TDX Connect, the
functionalities/uAPIs are exposed in /sys/devices/faux/tdx_host. Better
the 2 features could have aligned config pattern. The TDX Connect
configuration is here:

  https://lore.kernel.org/all/20251117022311.2443900-4-yilun.xu@linux.intel.com/

> +
> +	  If unsure, say N.
> +
>  config EFI
>  	bool "EFI runtime service support"
>  	depends on ACPI
> diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
> index 90da47eb85ee..26aea3531c36 100644
> --- a/arch/x86/virt/vmx/tdx/Makefile
> +++ b/arch/x86/virt/vmx/tdx/Makefile
> @@ -1,2 +1,3 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  obj-y += seamcall.o tdx.o
> +obj-$(CONFIG_INTEL_TDX_MODULE_UPDATE) += seamldr.o

And I'm wondering if we must disable seamldr core helpers if Update
uAPIs are not selected. TDX core now are expected to expose various
helpers for different features and is it necessary we have to mask
in/out all helpers in such a fine granularity? For example we may not
disable tdh_mem_sept_xx() helpers if KVM_INTEL is not selected.

BTW: We may finally get rid of the dependency between KVM_INTEL & TDX_HOST

-----8<-----
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 80527299f859..e3e90d1fcad3 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1898,7 +1898,6 @@ config INTEL_TDX_HOST
        bool "Intel Trust Domain Extensions (TDX) host support"
        depends on CPU_SUP_INTEL
        depends on X86_64
-       depends on KVM_INTEL
        depends on X86_X2APIC
        select ARCH_KEEP_MEMBLOCK
        depends on CONTIG_ALLOC

[...]

> +static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
> +{
> +	unsigned long flags;
> +	u64 vmcs;
> +	int ret;
> +
> +	if (!is_seamldr_call(fn))
> +		return -EINVAL;
> +
> +	/*
> +	 * SEAMRET from P-SEAMLDR invalidates the current VMCS.  Save/restore
> +	 * the VMCS across P-SEAMLDR SEAMCALLs to avoid clobbering KVM state.
> +	 * Disable interrupts as KVM is allowed to do VMREAD/VMWRITE in IRQ
> +	 * context (but not NMI context).
> +	 */
> +	local_irq_save(flags);
> +
> +	asm goto("1: vmptrst %0\n\t"
> +		 _ASM_EXTABLE(1b, %l[error])
> +		 : "=m" (vmcs) : : "cc" : error);
> +
> +	ret = seamldr_prerr(fn, args);

As I mentioned, just use seamcall_prerr(). This perfectly illustrates the
main difference between normal seamcalls & seamldr_calls - the additional
VMCS handling.

> +
> +	/*
> +	 * Restore the current VMCS pointer.  VMPTSTR "returns" all ones if the
> +	 * current VMCS is invalid.
> +	 */
> +	if (vmcs != -1ULL) {
> +		asm goto("1: vmptrld %0\n\t"
> +			 "jna %l[error]\n\t"
> +			 _ASM_EXTABLE(1b, %l[error])
> +			 : : "m" (vmcs) : "cc" : error);
> +	}
> +
> +	local_irq_restore(flags);
> +	return ret;
> +
> +error:
> +	local_irq_restore(flags);
> +
> +	WARN_ONCE(1, "Failed to save/restore the current VMCS");
> +	return -EIO;
> +}
> -- 
> 2.47.3
>
Re: [PATCH v2 05/21] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
Posted by Chao Gao 3 weeks, 4 days ago
On Tue, Jan 13, 2026 at 07:08:37PM +0800, Xu Yilun wrote:
>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>> index 58d890fe2100..6b47383d2958 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -1905,6 +1905,16 @@ config INTEL_TDX_HOST
>>  
>>  	  If unsure, say N.
>>  
>> +config INTEL_TDX_MODULE_UPDATE
>> +	bool "Intel TDX module runtime update"
>> +	depends on TDX_HOST_SERVICES
>> +	help
>> +	  This enables the kernel to support TDX module runtime update. This
>> +	  allows the admin to update the TDX module to the same or any newer
>> +	  version without the need to terminate running TDX guests.
>
>I'm wondering if it is better to put this option in
>drivers/virt/coco/tdx-host. Just as TDX Connect, the
>functionalities/uAPIs are exposed in /sys/devices/faux/tdx_host. Better
>the 2 features could have aligned config pattern. The TDX Connect
>configuration is here:
>
>  https://lore.kernel.org/all/20251117022311.2443900-4-yilun.xu@linux.intel.com/

Agreed. TDX Connect and Module update should align in this matter.
I will move this kconfig under drivers/virt/coco/tdx-host.

>
>> +
>> +	  If unsure, say N.
>> +
>>  config EFI
>>  	bool "EFI runtime service support"
>>  	depends on ACPI
>> diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
>> index 90da47eb85ee..26aea3531c36 100644
>> --- a/arch/x86/virt/vmx/tdx/Makefile
>> +++ b/arch/x86/virt/vmx/tdx/Makefile
>> @@ -1,2 +1,3 @@
>>  # SPDX-License-Identifier: GPL-2.0-only
>>  obj-y += seamcall.o tdx.o
>> +obj-$(CONFIG_INTEL_TDX_MODULE_UPDATE) += seamldr.o
>
>And I'm wondering if we must disable seamldr core helpers if Update
>uAPIs are not selected. TDX core now are expected to expose various
>helpers for different features and is it necessary we have to mask
>in/out all helpers in such a fine granularity? For example we may not
>disable tdh_mem_sept_xx() helpers if KVM_INTEL is not selected.

I would rather keep this. seamldr.c will have other facilities that are for
updates only. It's better to compile them out if there are no kernel users of
them. I would agree with you if we needed to sprinkle a few #ifdef/#endif
throughout the C file, but that isn't the case as the whole file won't be
compiled.
Re: [PATCH v2 05/21] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
Posted by Binbin Wu 2 months, 2 weeks ago

On 10/1/2025 10:52 AM, Chao Gao wrote:
[...]
>   
> +config INTEL_TDX_MODULE_UPDATE
> +	bool "Intel TDX module runtime update"
> +	depends on TDX_HOST_SERVICES
> +	help
> +	  This enables the kernel to support TDX module runtime update. This
> +	  allows the admin to update the TDX module to the same or any newer

any newer -> any compatible newer ?

> +	  version without the need to terminate running TDX guests.
> +
> +	  If unsure, say N.
> +
>