linux-kselftest.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 00/19] TDX KVM selftests
@ 2025-08-21  4:28 Sagi Shahar
  2025-08-21  4:28 ` [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type() Sagi Shahar
                   ` (18 more replies)
  0 siblings, 19 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:28 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

This is v9 of the TDX selftests.

Thanks everyone for the thorough review on v8 [1]. I tried addressing
all the comments. I'm terribly sorry if I missed something.

The original v8 series [1] was split to make reviewing the test framework
changes easier. This series includes the original patches up to the TDX
lifecycle test which is the first TDX selftest in the series.

This series is based on v6.17-rc2

Changes from v8:
- Rebased on top of v6.17-rc2
- Drop several patches which are no longer needed now that TDX support
  is integrated into the common flow.
- Split several patches to make reviewing easier.
- Massive refactor compared to v8 to pull TDX special handling into
  __vm_create() and vm_vcpu_add() instead of creating separate functions
  for TDX.
- Use kbuild to expose values from c to assembly code.
- Move setup of the reset vectors to c code as suggested by Sean.
- Drop redundant cpuid masking functions which are no longer necessary.
- Initialize TDX protected pages one at a time instead of allocating
  large chinks of memory.
- Add UCALL support for TDX to align with the rest of the selftests.
- Minor fixes to kselftest_harness.h and virt_map() that were identified
  as part of this work.

[1] https://lore.kernel.org/lkml/20250807201628.1185915-1-sagis@google.com/

Ackerley Tng (2):
  KVM: selftests: Add helpers to init TDX memory and finalize VM
  KVM: selftests: Add ucall support for TDX

Erdem Aktas (2):
  KVM: selftests: Add TDX boot code
  KVM: selftests: Add support for TDX TDCALL from guest

Isaku Yamahata (2):
  KVM: selftests: Update kvm_init_vm_address_properties() for TDX
  KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs'
    attribute configuration

Sagi Shahar (13):
  KVM: selftests: Include overflow.h instead of redefining
    is_signed_type()
  KVM: selftests: Allocate pgd in virt_map() as necessary
  KVM: selftests: Expose functions to get default sregs values
  KVM: selftests: Expose function to allocate guest vCPU stack
  KVM: selftests: Expose segment definitons to assembly files
  KVM: selftests: Add kbuild definitons
  KVM: selftests: Define structs to pass parameters to TDX boot code
  KVM: selftests: Set up TDX boot code region
  KVM: selftests: Set up TDX boot parameters region
  KVM: selftests: Add helper to initialize TDX VM
  KVM: selftests: Hook TDX support to vm and vcpu creation
  KVM: selftests: Add wrapper for TDX MMIO from guest
  KVM: selftests: Add TDX lifecycle test

 tools/include/linux/kbuild.h                  |  18 +
 tools/testing/selftests/kselftest_harness.h   |   3 +-
 tools/testing/selftests/kvm/Makefile.kvm      |  32 ++
 .../selftests/kvm/include/x86/processor.h     |   8 +
 .../selftests/kvm/include/x86/processor_asm.h |  12 +
 .../selftests/kvm/include/x86/tdx/td_boot.h   |  81 ++++
 .../kvm/include/x86/tdx/td_boot_asm.h         |  16 +
 .../selftests/kvm/include/x86/tdx/tdcall.h    |  34 ++
 .../selftests/kvm/include/x86/tdx/tdx.h       |  14 +
 .../selftests/kvm/include/x86/tdx/tdx_util.h  |  86 ++++
 .../testing/selftests/kvm/include/x86/ucall.h |   4 +-
 tools/testing/selftests/kvm/lib/kvm_util.c    |  25 +-
 .../testing/selftests/kvm/lib/x86/processor.c | 122 ++++--
 .../selftests/kvm/lib/x86/tdx/td_boot.S       |  60 +++
 .../kvm/lib/x86/tdx/td_boot_offsets.c         |  21 +
 .../selftests/kvm/lib/x86/tdx/tdcall.S        |  93 +++++
 .../kvm/lib/x86/tdx/tdcall_offsets.c          |  16 +
 tools/testing/selftests/kvm/lib/x86/tdx/tdx.c |  22 +
 .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 391 ++++++++++++++++++
 tools/testing/selftests/kvm/lib/x86/ucall.c   |  45 +-
 tools/testing/selftests/kvm/x86/tdx_vm_test.c |  31 ++
 21 files changed, 1095 insertions(+), 39 deletions(-)
 create mode 100644 tools/include/linux/kbuild.h
 create mode 100644 tools/testing/selftests/kvm/include/x86/processor_asm.h
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdcall.h
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx.h
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdcall.S
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdcall_offsets.c
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdx.c
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
 create mode 100644 tools/testing/selftests/kvm/x86/tdx_vm_test.c

-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply	[flat|nested] 62+ messages in thread

* [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type()
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
@ 2025-08-21  4:28 ` Sagi Shahar
  2025-08-21 14:16   ` Sean Christopherson
  2025-08-21 14:37   ` Ira Weiny
  2025-08-21  4:28 ` [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary Sagi Shahar
                   ` (17 subsequent siblings)
  18 siblings, 2 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:28 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Redefinition of is_signed_type() causes compilation warning for tests
which use kselftest_harness. Replace the definition with linux/overflow.h

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kselftest_harness.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
index 2925e47db995..a580a0d33c65 100644
--- a/tools/testing/selftests/kselftest_harness.h
+++ b/tools/testing/selftests/kselftest_harness.h
@@ -56,6 +56,7 @@
 #include <asm/types.h>
 #include <ctype.h>
 #include <errno.h>
+#include <linux/overflow.h>
 #include <linux/unistd.h>
 #include <poll.h>
 #include <stdbool.h>
@@ -751,8 +752,6 @@
 	for (; _metadata->trigger; _metadata->trigger = \
 			__bail(_assert, _metadata))
 
-#define is_signed_type(var)       (!!(((__typeof__(var))(-1)) < (__typeof__(var))1))
-
 #define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \
 	/* Avoid multiple evaluation of the cases */ \
 	__typeof__(_expected) __exp = (_expected); \
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
  2025-08-21  4:28 ` [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type() Sagi Shahar
@ 2025-08-21  4:28 ` Sagi Shahar
  2025-08-21 14:45   ` Ira Weiny
  2025-08-26  2:36   ` Binbin Wu
  2025-08-21  4:28 ` [PATCH v9 03/19] KVM: selftests: Expose functions to get default sregs values Sagi Shahar
                   ` (16 subsequent siblings)
  18 siblings, 2 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:28 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

If virt_map() is called before any call to ____vm_vaddr_alloc() it
will create the mapping using an invalid pgd.

Add call to virt_pgd_alloc() as part of virt_map() before creating the
mapping, similarly to ____vm_vaddr_alloc()

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/lib/kvm_util.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index c3f5142b0a54..b4c8702ba4bd 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1609,6 +1609,7 @@ void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 	TEST_ASSERT(vaddr + size > vaddr, "Vaddr overflow");
 	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
 
+	virt_pgd_alloc(vm);
 	while (npages--) {
 		virt_pg_map(vm, vaddr, paddr);
 		sparsebit_set(vm->vpages_mapped, vaddr >> vm->page_shift);
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 03/19] KVM: selftests: Expose functions to get default sregs values
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
  2025-08-21  4:28 ` [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type() Sagi Shahar
  2025-08-21  4:28 ` [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary Sagi Shahar
@ 2025-08-21  4:28 ` Sagi Shahar
  2025-08-26  2:36   ` Binbin Wu
  2025-08-21  4:28 ` [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack Sagi Shahar
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:28 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

TDX can't set sregs values directly using KVM_SET_SREGS. Expose the
default values of certain sregs used by TDX VMs so they can be set
manually.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/include/x86/processor.h     |  6 +++
 .../testing/selftests/kvm/lib/x86/processor.c | 41 +++++++++++++++----
 2 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 2efb05c2f2fb..5c16507f9b2d 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1026,6 +1026,12 @@ static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries)
 
 void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid);
 
+uint16_t kvm_get_default_idt_limit(void);
+uint16_t kvm_get_default_gdt_limit(void);
+uint64_t kvm_get_default_cr0(void);
+uint64_t kvm_get_default_cr4(void);
+uint64_t kvm_get_default_efer(void);
+
 static inline void vcpu_get_cpuid(struct kvm_vcpu *vcpu)
 {
 	vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid);
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index d4c19ac885a9..b2a4b11ac8c0 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -488,6 +488,35 @@ static void kvm_seg_set_tss_64bit(vm_vaddr_t base, struct kvm_segment *segp)
 	segp->present = 1;
 }
 
+uint16_t kvm_get_default_idt_limit(void)
+{
+	return NUM_INTERRUPTS * sizeof(struct idt_entry) - 1;
+}
+
+uint16_t kvm_get_default_gdt_limit(void)
+{
+	return getpagesize() - 1;
+}
+
+uint64_t kvm_get_default_cr0(void)
+{
+	return X86_CR0_PE | X86_CR0_NE | X86_CR0_PG;
+}
+
+uint64_t kvm_get_default_cr4(void)
+{
+	uint64_t cr4 = X86_CR4_PAE | X86_CR4_OSFXSR;
+
+	if (kvm_cpu_has(X86_FEATURE_XSAVE))
+		cr4 |= X86_CR4_OSXSAVE;
+	return cr4;
+}
+
+uint64_t kvm_get_default_efer(void)
+{
+	return EFER_LME | EFER_LMA | EFER_NX;
+}
+
 static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 {
 	struct kvm_sregs sregs;
@@ -498,15 +527,13 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 	vcpu_sregs_get(vcpu, &sregs);
 
 	sregs.idt.base = vm->arch.idt;
-	sregs.idt.limit = NUM_INTERRUPTS * sizeof(struct idt_entry) - 1;
+	sregs.idt.limit = kvm_get_default_idt_limit();
 	sregs.gdt.base = vm->arch.gdt;
-	sregs.gdt.limit = getpagesize() - 1;
+	sregs.gdt.limit = kvm_get_default_gdt_limit();
 
-	sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG;
-	sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR;
-	if (kvm_cpu_has(X86_FEATURE_XSAVE))
-		sregs.cr4 |= X86_CR4_OSXSAVE;
-	sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX);
+	sregs.cr0 = kvm_get_default_cr0();
+	sregs.cr4 |= kvm_get_default_cr4();
+	sregs.efer |= kvm_get_default_efer();
 
 	kvm_seg_set_unusable(&sregs.ldt);
 	kvm_seg_set_kernel_code_64bit(&sregs.cs);
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (2 preceding siblings ...)
  2025-08-21  4:28 ` [PATCH v9 03/19] KVM: selftests: Expose functions to get default sregs values Sagi Shahar
@ 2025-08-21  4:28 ` Sagi Shahar
  2025-08-21 22:00   ` Ira Weiny
  2025-08-26  5:39   ` Binbin Wu
  2025-08-21  4:28 ` [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Sagi Shahar
                   ` (14 subsequent siblings)
  18 siblings, 2 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:28 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

TDX guests' registers cannot be initialized directly using
vcpu_regs_set(), hence the stack pointer needs to be initialized by
the guest itself, running boot code beginning at the reset vector.

Expose the function to allocate the guest stack so that TDX
initialization code can allocate it itself and skip the allocation in
vm_arch_vcpu_add() in that case.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/include/x86/processor.h       |  2 ++
 tools/testing/selftests/kvm/lib/x86/processor.c | 17 ++++++++++++-----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 5c16507f9b2d..8fcc5118683e 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1111,6 +1111,8 @@ static inline void vcpu_clear_cpuid_feature(struct kvm_vcpu *vcpu,
 	vcpu_set_or_clear_cpuid_feature(vcpu, feature, false);
 }
 
+vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm);
+
 uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index);
 int _vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, uint64_t msr_value);
 
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index b2a4b11ac8c0..1eae92957456 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -687,12 +687,9 @@ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
 	vcpu_regs_set(vcpu, &regs);
 }
 
-struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
+vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
 {
-	struct kvm_mp_state mp_state;
-	struct kvm_regs regs;
 	vm_vaddr_t stack_vaddr;
-	struct kvm_vcpu *vcpu;
 
 	stack_vaddr = __vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(),
 				       DEFAULT_GUEST_STACK_VADDR_MIN,
@@ -713,6 +710,15 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
 		    "__vm_vaddr_alloc() did not provide a page-aligned address");
 	stack_vaddr -= 8;
 
+	return stack_vaddr;
+}
+
+struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
+{
+	struct kvm_mp_state mp_state;
+	struct kvm_regs regs;
+	struct kvm_vcpu *vcpu;
+
 	vcpu = __vm_vcpu_add(vm, vcpu_id);
 	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
 	vcpu_init_sregs(vm, vcpu);
@@ -721,7 +727,8 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
 	/* Setup guest general purpose registers */
 	vcpu_regs_get(vcpu, &regs);
 	regs.rflags = regs.rflags | 0x2;
-	regs.rsp = stack_vaddr;
+	if (vm->type != KVM_X86_TDX_VM)
+		regs.rsp = kvm_allocate_vcpu_stack(vm);
 	vcpu_regs_set(vcpu, &regs);
 
 	/* Setup the MP state */
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (3 preceding siblings ...)
  2025-08-21  4:28 ` [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack Sagi Shahar
@ 2025-08-21  4:28 ` Sagi Shahar
  2025-08-21 22:05   ` Ira Weiny
  2025-08-26  5:51   ` Binbin Wu
  2025-08-21  4:28 ` [PATCH v9 06/19] KVM: selftests: Expose segment definitons to assembly files Sagi Shahar
                   ` (13 subsequent siblings)
  18 siblings, 2 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:28 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm, Adrian Hunter

From: Isaku Yamahata <isaku.yamahata@intel.com>

Let kvm_init_vm_address_properties() initialize vm->arch.{s_bit, tag_mask}
similar to SEV.

TDX sets the shared bit based on the guest physical address width and
currently supports 48 and 52 widths.

Co-developed-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Co-developed-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/include/x86/tdx/tdx_util.h       | 14 ++++++++++++++
 tools/testing/selftests/kvm/lib/x86/processor.c    | 12 ++++++++++--
 2 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h

diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
new file mode 100644
index 000000000000..286d5e3c24b1
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTESTS_TDX_TDX_UTIL_H
+#define SELFTESTS_TDX_TDX_UTIL_H
+
+#include <stdbool.h>
+
+#include "kvm_util.h"
+
+static inline bool is_tdx_vm(struct kvm_vm *vm)
+{
+	return vm->type == KVM_X86_TDX_VM;
+}
+
+#endif // SELFTESTS_TDX_TDX_UTIL_H
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 1eae92957456..6dbf40cbbc2a 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -8,6 +8,7 @@
 #include "kvm_util.h"
 #include "processor.h"
 #include "sev.h"
+#include "tdx/tdx_util.h"
 
 #ifndef NUM_INTERRUPTS
 #define NUM_INTERRUPTS 256
@@ -1190,12 +1191,19 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
 
 void kvm_init_vm_address_properties(struct kvm_vm *vm)
 {
+	uint32_t gpa_bits = kvm_cpu_property(X86_PROPERTY_GUEST_MAX_PHY_ADDR);
+
+	vm->arch.sev_fd = -1;
+
 	if (is_sev_vm(vm)) {
 		vm->arch.sev_fd = open_sev_dev_path_or_exit();
 		vm->arch.c_bit = BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT));
 		vm->gpa_tag_mask = vm->arch.c_bit;
-	} else {
-		vm->arch.sev_fd = -1;
+	} else if (is_tdx_vm(vm)) {
+		TEST_ASSERT(gpa_bits == 48 || gpa_bits == 52,
+			    "TDX: bad X86_PROPERTY_GUEST_MAX_PHY_ADDR value: %u", gpa_bits);
+		vm->arch.s_bit = 1ULL << (gpa_bits - 1);
+		vm->gpa_tag_mask = vm->arch.s_bit;
 	}
 }
 
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 06/19] KVM: selftests: Expose segment definitons to assembly files
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (4 preceding siblings ...)
  2025-08-21  4:28 ` [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Sagi Shahar
@ 2025-08-21  4:28 ` Sagi Shahar
  2025-08-21 20:04   ` Ira Weiny
  2025-08-21  4:29 ` [PATCH v9 07/19] KVM: selftests: Add kbuild definitons Sagi Shahar
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:28 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Move kernel segment definitons to a separate file which can be included
from assembly files.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/include/x86/processor_asm.h        | 12 ++++++++++++
 tools/testing/selftests/kvm/lib/x86/processor.c      |  5 +----
 2 files changed, 13 insertions(+), 4 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/include/x86/processor_asm.h

diff --git a/tools/testing/selftests/kvm/include/x86/processor_asm.h b/tools/testing/selftests/kvm/include/x86/processor_asm.h
new file mode 100644
index 000000000000..7e5386a85ca8
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/x86/processor_asm.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Used for storing defines used by both processor.c and assembly code.
+ */
+#ifndef SELFTEST_KVM_PROCESSOR_ASM_H
+#define SELFTEST_KVM_PROCESSOR_ASM_H
+
+#define KERNEL_CS	0x8
+#define KERNEL_DS	0x10
+#define KERNEL_TSS	0x18
+
+#endif  // SELFTEST_KVM_PROCESSOR_ASM_H
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 6dbf40cbbc2a..4802fc81bea7 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -7,6 +7,7 @@
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
+#include "processor_asm.h"
 #include "sev.h"
 #include "tdx/tdx_util.h"
 
@@ -14,10 +15,6 @@
 #define NUM_INTERRUPTS 256
 #endif
 
-#define KERNEL_CS	0x8
-#define KERNEL_DS	0x10
-#define KERNEL_TSS	0x18
-
 vm_vaddr_t exception_handlers;
 bool host_cpu_is_amd;
 bool host_cpu_is_intel;
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 07/19] KVM: selftests: Add kbuild definitons
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (5 preceding siblings ...)
  2025-08-21  4:28 ` [PATCH v9 06/19] KVM: selftests: Expose segment definitons to assembly files Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-21  4:29 ` [PATCH v9 08/19] KVM: selftests: Define structs to pass parameters to TDX boot code Sagi Shahar
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Add kbuild.h that can be used by files under tools/

Definitions are taken from the original definitions at
include/linux/kbuild.h

This is needed to expose values from c code to assembly code.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/include/linux/kbuild.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 tools/include/linux/kbuild.h

diff --git a/tools/include/linux/kbuild.h b/tools/include/linux/kbuild.h
new file mode 100644
index 000000000000..62e20ba9380e
--- /dev/null
+++ b/tools/include/linux/kbuild.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __TOOLS_LINUX_KBUILD_H
+#define __TOOLS_LINUX_KBUILD_H
+
+#include <stddef.h>
+
+#define DEFINE(sym, val) \
+	asm volatile("\n.ascii \"->" #sym " %0 " #val "\"" : : "i" (val))
+
+#define BLANK() asm volatile("\n.ascii \"->\"" : : )
+
+#define OFFSET(sym, str, mem) \
+	DEFINE(sym, offsetof(struct str, mem))
+
+#define COMMENT(x) \
+	asm volatile("\n.ascii \"->#" x "\"")
+
+#endif /* __TOOLS_LINUX_KBUILD_H */
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 08/19] KVM: selftests: Define structs to pass parameters to TDX boot code
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (6 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 07/19] KVM: selftests: Add kbuild definitons Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-26  6:52   ` Binbin Wu
  2025-08-21  4:29 ` [PATCH v9 09/19] KVM: selftests: Add " Sagi Shahar
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

TDX registers are inaccesible to KVM. Therefore we need a different
mechanism to load boot parameters for TDX code. TDX boot code will read
the registers values from memory and set the registers manually.

This patch defines the data structures used to communicate between c
code and the TDX assembly boot code which will be added in a later
patch.

Use kbuild.h to expose the offsets into the structs from c code to
assembly code.

Co-developed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      | 18 +++++
 .../selftests/kvm/include/x86/tdx/td_boot.h   | 76 +++++++++++++++++++
 .../kvm/lib/x86/tdx/td_boot_offsets.c         | 21 +++++
 3 files changed, 115 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index f6fe7a07a0a2..f4686445c197 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -19,6 +19,8 @@ LIBKVM += lib/userfaultfd_util.c
 
 LIBKVM_STRING += lib/string_override.c
 
+LIBKVM_ASM_DEFS += lib/x86/tdx/td_boot_offsets.c
+
 LIBKVM_x86 += lib/x86/apic.c
 LIBKVM_x86 += lib/x86/handlers.S
 LIBKVM_x86 += lib/x86/hyperv.c
@@ -229,6 +231,10 @@ OVERRIDE_TARGETS = 1
 include ../lib.mk
 include ../cgroup/lib/libcgroup.mk
 
+# Enable Kbuild tools.
+include $(top_srcdir)/scripts/Kbuild.include
+include $(top_srcdir)/scripts/Makefile.lib
+
 INSTALL_HDR_PATH = $(top_srcdir)/usr
 LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/
 LINUX_TOOL_INCLUDE = $(top_srcdir)/tools/include
@@ -281,6 +287,7 @@ LIBKVM_S := $(filter %.S,$(LIBKVM))
 LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C))
 LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S))
 LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING))
+LIBKVM_ASM_DEFS_OBJ += $(patsubst %.c, $(OUTPUT)/%.s, $(LIBKVM_ASM_DEFS))
 LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ) $(LIBCGROUP_O)
 SPLIT_TEST_GEN_PROGS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS))
 SPLIT_TEST_GEN_OBJ := $(patsubst %, $(OUTPUT)/$(ARCH)/%.o, $(SPLIT_TESTS))
@@ -307,6 +314,7 @@ $(SPLIT_TEST_GEN_OBJ): $(OUTPUT)/$(ARCH)/%.o: $(ARCH)/%.c
 
 EXTRA_CLEAN += $(GEN_HDRS) \
 	       $(LIBKVM_OBJS) \
+	       $(LIBKVM_ASM_DEFS_OBJ) \
 	       $(SPLIT_TEST_GEN_OBJ) \
 	       $(TEST_DEP_FILES) \
 	       $(TEST_GEN_OBJ) \
@@ -318,18 +326,28 @@ $(LIBKVM_C_OBJ): $(OUTPUT)/%.o: %.c $(GEN_HDRS)
 $(LIBKVM_S_OBJ): $(OUTPUT)/%.o: %.S $(GEN_HDRS)
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
 
+$(LIBKVM_ASM_DEFS_OBJ): $(OUTPUT)/%.s: %.c FORCE
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -S $< -o $@
+
 # Compile the string overrides as freestanding to prevent the compiler from
 # generating self-referential code, e.g. without "freestanding" the compiler may
 # "optimize" memcmp() by invoking memcmp(), thus causing infinite recursion.
 $(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@
 
+$(OUTPUT)/include/x86/tdx/td_boot_offsets.h: $(OUTPUT)/lib/x86/tdx/td_boot_offsets.s FORCE
+	$(call filechk,offsets,__TDX_BOOT_OFFSETS_H__)
+
+EXTRA_CLEAN += $(OUTPUT)/include/x86/tdx/td_boot_offsets.h
+
 $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS))))
 $(SPLIT_TEST_GEN_OBJ): $(GEN_HDRS)
 $(TEST_GEN_PROGS): $(LIBKVM_OBJS)
 $(TEST_GEN_PROGS_EXTENDED): $(LIBKVM_OBJS)
 $(TEST_GEN_OBJ): $(GEN_HDRS)
 
+FORCE:
+
 cscope: include_paths = $(LINUX_TOOL_INCLUDE) $(LINUX_HDR_PATH) include lib ..
 cscope:
 	$(RM) cscope.*
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
new file mode 100644
index 000000000000..5cce671586e9
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_TDX_TD_BOOT_H
+#define SELFTEST_TDX_TD_BOOT_H
+
+#include <stdint.h>
+
+#include <linux/compiler.h>
+#include <linux/sizes.h>
+
+/*
+ * Layout for boot section (not to scale)
+ *
+ *                                   GPA
+ * _________________________________ 0x1_0000_0000 (4GB)
+ * |   Boot code trampoline    |
+ * |___________________________|____ 0x0_ffff_fff0: Reset vector (16B below 4GB)
+ * |   Boot code               |
+ * |___________________________|____ td_boot will be copied here, so that the
+ * |                           |     jmp to td_boot is exactly at the reset vector
+ * |   Empty space             |
+ * |                           |
+ * |───────────────────────────|
+ * |                           |
+ * |                           |
+ * |   Boot parameters         |
+ * |                           |
+ * |                           |
+ * |___________________________|____ 0x0_ffff_0000: TD_BOOT_PARAMETERS_GPA
+ */
+#define FOUR_GIGABYTES_GPA (SZ_4G)
+
+/*
+ * The exact memory layout for LGDT or LIDT instructions.
+ */
+struct __packed td_boot_parameters_dtr {
+	uint16_t limit;
+	uint32_t base;
+};
+
+/*
+ * Allows each vCPU to be initialized with different eip and esp.
+ *
+ * __packed is used since the offsets are hardcoded in td_boot.S
+ *
+ * TODO: Replace hardcoded offsets with OFFSET(). This requires getting the
+ * neccesry Kbuild scripts working in KVM selftests.
+ */
+struct td_per_vcpu_parameters {
+	uint32_t esp_gva;
+	uint64_t guest_code;
+};
+
+/*
+ * Boot parameters for the TD.
+ *
+ * Unlike a regular VM, KVM cannot set registers such as esp, eip, etc
+ * before boot, so to run selftests, these registers' values have to be
+ * initialized by the TD.
+ *
+ * This struct is loaded in TD private memory at TD_BOOT_PARAMETERS_GPA.
+ *
+ * The TD boot code will read off parameters from this struct and set up the
+ * vCPU for executing selftests.
+ *
+ * __packed is used since the offsets are hardcoded in td_boot.S
+ */
+struct td_boot_parameters {
+	uint32_t cr0;
+	uint32_t cr3;
+	uint32_t cr4;
+	struct td_boot_parameters_dtr gdtr;
+	struct td_boot_parameters_dtr idtr;
+	struct td_per_vcpu_parameters per_vcpu[];
+};
+
+#endif /* SELFTEST_TDX_TD_BOOT_H */
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c
new file mode 100644
index 000000000000..7f76a3585b99
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+#define COMPILE_OFFSETS
+
+#include <linux/kbuild.h>
+
+#include "tdx/td_boot.h"
+
+static void __attribute__((used)) common(void)
+{
+	OFFSET(TD_BOOT_PARAMETERS_CR0, td_boot_parameters, cr0);
+	OFFSET(TD_BOOT_PARAMETERS_CR3, td_boot_parameters, cr3);
+	OFFSET(TD_BOOT_PARAMETERS_CR4, td_boot_parameters, cr4);
+	OFFSET(TD_BOOT_PARAMETERS_GDT, td_boot_parameters, gdtr);
+	OFFSET(TD_BOOT_PARAMETERS_IDT, td_boot_parameters, idtr);
+	OFFSET(TD_BOOT_PARAMETERS_PER_VCPU, td_boot_parameters, per_vcpu);
+	OFFSET(TD_PER_VCPU_PARAMETERS_ESP_GVA, td_per_vcpu_parameters, esp_gva);
+	OFFSET(TD_PER_VCPU_PARAMETERS_GUEST_CODE, td_per_vcpu_parameters,
+	       guest_code);
+	DEFINE(SIZEOF_TD_PER_VCPU_PARAMETERS,
+	       sizeof(struct td_per_vcpu_parameters));
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 09/19] KVM: selftests: Add TDX boot code
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (7 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 08/19] KVM: selftests: Define structs to pass parameters to TDX boot code Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-21  4:29 ` [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region Sagi Shahar
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

From: Erdem Aktas <erdemaktas@google.com>

Add code to boot a TDX test VM. Since TDX registers are inaccesible to
KVM, the boot code loads the relevant values from memory into the
registers before jumping to the guest code.

Signed-off-by: Erdem Aktas <erdemaktas@google.com>
Co-developed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Co-developed-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  3 +
 .../selftests/kvm/include/x86/tdx/td_boot.h   |  5 ++
 .../kvm/include/x86/tdx/td_boot_asm.h         | 16 +++++
 .../selftests/kvm/lib/x86/tdx/td_boot.S       | 60 +++++++++++++++++++
 4 files changed, 84 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index f4686445c197..03754ce2e983 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -31,6 +31,7 @@ LIBKVM_x86 += lib/x86/sev.c
 LIBKVM_x86 += lib/x86/svm.c
 LIBKVM_x86 += lib/x86/ucall.c
 LIBKVM_x86 += lib/x86/vmx.c
+LIBKVM_x86 += lib/x86/tdx/td_boot.S
 
 LIBKVM_arm64 += lib/arm64/gic.c
 LIBKVM_arm64 += lib/arm64/gic_v3.c
@@ -335,6 +336,8 @@ $(LIBKVM_ASM_DEFS_OBJ): $(OUTPUT)/%.s: %.c FORCE
 $(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@
 
+$(OUTPUT)/lib/x86/tdx/td_boot.o: $(OUTPUT)/include/x86/tdx/td_boot_offsets.h
+
 $(OUTPUT)/include/x86/tdx/td_boot_offsets.h: $(OUTPUT)/lib/x86/tdx/td_boot_offsets.s FORCE
 	$(call filechk,offsets,__TDX_BOOT_OFFSETS_H__)
 
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
index 5cce671586e9..65ccc65efaeb 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
@@ -73,4 +73,9 @@ struct td_boot_parameters {
 	struct td_per_vcpu_parameters per_vcpu[];
 };
 
+void td_boot(void);
+void td_boot_code_end(void);
+
+#define TD_BOOT_CODE_SIZE (td_boot_code_end - td_boot)
+
 #endif /* SELFTEST_TDX_TD_BOOT_H */
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h b/tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h
new file mode 100644
index 000000000000..10b4b527595c
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_TDX_TD_BOOT_ASM_H
+#define SELFTEST_TDX_TD_BOOT_ASM_H
+
+/*
+ * GPA where TD boot parameters will be loaded.
+ *
+ * TD_BOOT_PARAMETERS_GPA is arbitrarily chosen to
+ *
+ * + be within the 4GB address space
+ * + provide enough contiguous memory for the struct td_boot_parameters such
+ *   that there is one struct td_per_vcpu_parameters for KVM_MAX_VCPUS
+ */
+#define TD_BOOT_PARAMETERS_GPA 0xffff0000
+
+#endif  // SELFTEST_TDX_TD_BOOT_ASM_H
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S
new file mode 100644
index 000000000000..7aa33caa9a78
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include "tdx/td_boot_asm.h"
+#include "tdx/td_boot_offsets.h"
+#include "processor_asm.h"
+
+.code32
+
+.globl td_boot
+td_boot:
+	/* In this procedure, edi is used as a temporary register. */
+	cli
+
+	/* Paging is off. */
+
+	movl $TD_BOOT_PARAMETERS_GPA, %ebx
+
+	/*
+	 * Find the address of struct td_per_vcpu_parameters for this
+	 * vCPU based on esi (TDX spec: initialized with vCPU id). Put
+	 * struct address into register for indirect addressing.
+	 */
+	movl $SIZEOF_TD_PER_VCPU_PARAMETERS, %eax
+	mul %esi
+	leal TD_BOOT_PARAMETERS_PER_VCPU(%ebx), %edi
+	addl %edi, %eax
+
+	/* Setup stack. */
+	movl TD_PER_VCPU_PARAMETERS_ESP_GVA(%eax), %esp
+
+	/* Setup GDT. */
+	leal TD_BOOT_PARAMETERS_GDT(%ebx), %edi
+	lgdt (%edi)
+
+	/* Setup IDT. */
+	leal TD_BOOT_PARAMETERS_IDT(%ebx), %edi
+	lidt (%edi)
+
+	/*
+	 * Set up control registers (There are no instructions to mov from
+	 * memory to control registers, hence use edi as a scratch register).
+	 */
+	movl TD_BOOT_PARAMETERS_CR4(%ebx), %edi
+	movl %edi, %cr4
+	movl TD_BOOT_PARAMETERS_CR3(%ebx), %edi
+	movl %edi, %cr3
+	movl TD_BOOT_PARAMETERS_CR0(%ebx), %edi
+	movl %edi, %cr0
+
+	/* Switching to 64bit mode after ljmp and then jump to guest code */
+	ljmp $(KERNEL_CS),$1f
+1:
+	jmp *TD_PER_VCPU_PARAMETERS_GUEST_CODE(%eax)
+
+/* Leave marker so size of td_boot code can be computed. */
+.globl td_boot_code_end
+td_boot_code_end:
+
+/* Disable executable stack. */
+.section .note.GNU-stack,"",%progbits
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (8 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 09/19] KVM: selftests: Add " Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-25  5:32   ` Yan Zhao
  2025-08-21  4:29 ` [PATCH v9 11/19] KVM: selftests: Set up TDX boot parameters region Sagi Shahar
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Add memory for TDX boot code in a separate memslot.

Use virt_map() to get identity map in this memory region to allow for
seamless transition from paging disabled to paging enabled code.

Copy the boot code into the memory region and set up the reset vectors
at this point. While it's possible to separate the memory allocation and
boot code initialization into separate functions, having all the
calculations for memory size and offsets in one place simplifies the
code and avoids duplications.

Handcode the reset vector as suggested by Sean Christopherson.

Suggested-by: Sean Christopherson <seanjc@google.com>
Co-developed-by: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  1 +
 .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
 .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 54 +++++++++++++++++++
 3 files changed, 57 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 03754ce2e983..c42b579fb7c5 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -31,6 +31,7 @@ LIBKVM_x86 += lib/x86/sev.c
 LIBKVM_x86 += lib/x86/svm.c
 LIBKVM_x86 += lib/x86/ucall.c
 LIBKVM_x86 += lib/x86/vmx.c
+LIBKVM_x86 += lib/x86/tdx/tdx_util.c
 LIBKVM_x86 += lib/x86/tdx/td_boot.S
 
 LIBKVM_arm64 += lib/arm64/gic.c
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
index 286d5e3c24b1..ec05bcd59145 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -11,4 +11,6 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
 	return vm->type == KVM_X86_TDX_VM;
 }
 
+void vm_tdx_setup_boot_code_region(struct kvm_vm *vm);
+
 #endif // SELFTESTS_TDX_TDX_UTIL_H
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
new file mode 100644
index 000000000000..15833b9eb5d5
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <stdint.h>
+
+#include "kvm_util.h"
+#include "processor.h"
+#include "tdx/td_boot.h"
+#include "tdx/tdx_util.h"
+
+/* Arbitrarily selected to avoid overlaps with anything else */
+#define TD_BOOT_CODE_SLOT	20
+
+#define X86_RESET_VECTOR	0xfffffff0ul
+#define X86_RESET_VECTOR_SIZE	16
+
+void vm_tdx_setup_boot_code_region(struct kvm_vm *vm)
+{
+	size_t total_code_size = TD_BOOT_CODE_SIZE + X86_RESET_VECTOR_SIZE;
+	vm_paddr_t boot_code_gpa = X86_RESET_VECTOR - TD_BOOT_CODE_SIZE;
+	vm_paddr_t alloc_gpa = round_down(boot_code_gpa, PAGE_SIZE);
+	size_t nr_pages = DIV_ROUND_UP(total_code_size, PAGE_SIZE);
+	vm_paddr_t gpa;
+	uint8_t *hva;
+
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    alloc_gpa,
+				    TD_BOOT_CODE_SLOT, nr_pages,
+				    KVM_MEM_GUEST_MEMFD);
+
+	gpa = vm_phy_pages_alloc(vm, nr_pages, alloc_gpa, TD_BOOT_CODE_SLOT);
+	TEST_ASSERT(gpa == alloc_gpa, "Failed vm_phy_pages_alloc\n");
+
+	virt_map(vm, alloc_gpa, alloc_gpa, nr_pages);
+	hva = addr_gpa2hva(vm, boot_code_gpa);
+	memcpy(hva, td_boot, TD_BOOT_CODE_SIZE);
+
+	hva += TD_BOOT_CODE_SIZE;
+	TEST_ASSERT(hva == addr_gpa2hva(vm, X86_RESET_VECTOR),
+		    "Expected RESET vector at hva 0x%lx, got %lx",
+		    (unsigned long)addr_gpa2hva(vm, X86_RESET_VECTOR), (unsigned long)hva);
+
+	/*
+	 * Handcode "JMP rel8" at the RESET vector to jump back to the TD boot
+	 * code, as there are only 16 bytes at the RESET vector before RIP will
+	 * wrap back to zero.  Insert a trailing int3 so that the vCPU crashes
+	 * in case the JMP somehow falls through.  Note!  The target address is
+	 * relative to the end of the instruction!
+	 */
+	TEST_ASSERT(TD_BOOT_CODE_SIZE < 256,
+		    "TD boot code not addressable by 'JMP rel8'");
+	hva[0] = 0xeb;
+	hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;
+	hva[2] = 0xcc;
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 11/19] KVM: selftests: Set up TDX boot parameters region
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (9 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-26  8:36   ` Binbin Wu
  2025-08-21  4:29 ` [PATCH v9 12/19] KVM: selftests: Add helper to initialize TDX VM Sagi Shahar
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Allocate memory for TDX boot parameters and define the utility functions
necessary to fill this memory with the boot parameters.

Co-developed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/include/x86/tdx/tdx_util.h  |  4 +
 .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 73 +++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
index ec05bcd59145..dafdc7e46abe 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -12,5 +12,9 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
 }
 
 void vm_tdx_setup_boot_code_region(struct kvm_vm *vm);
+void vm_tdx_setup_boot_parameters_region(struct kvm_vm *vm, uint32_t nr_runnable_vcpus);
+void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
+void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
+void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
 
 #endif // SELFTESTS_TDX_TDX_UTIL_H
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
index 15833b9eb5d5..52dc25e0cce4 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -5,10 +5,12 @@
 #include "kvm_util.h"
 #include "processor.h"
 #include "tdx/td_boot.h"
+#include "tdx/td_boot_asm.h"
 #include "tdx/tdx_util.h"
 
 /* Arbitrarily selected to avoid overlaps with anything else */
 #define TD_BOOT_CODE_SLOT	20
+#define TD_BOOT_PARAMETERS_SLOT	21
 
 #define X86_RESET_VECTOR	0xfffffff0ul
 #define X86_RESET_VECTOR_SIZE	16
@@ -52,3 +54,74 @@ void vm_tdx_setup_boot_code_region(struct kvm_vm *vm)
 	hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;
 	hva[2] = 0xcc;
 }
+
+void vm_tdx_setup_boot_parameters_region(struct kvm_vm *vm, uint32_t nr_runnable_vcpus)
+{
+	size_t boot_params_size =
+		sizeof(struct td_boot_parameters) +
+		nr_runnable_vcpus * sizeof(struct td_per_vcpu_parameters);
+	int npages = DIV_ROUND_UP(boot_params_size, PAGE_SIZE);
+	vm_paddr_t gpa;
+
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    TD_BOOT_PARAMETERS_GPA,
+				    TD_BOOT_PARAMETERS_SLOT, npages,
+				    KVM_MEM_GUEST_MEMFD);
+	gpa = vm_phy_pages_alloc(vm, npages, TD_BOOT_PARAMETERS_GPA, TD_BOOT_PARAMETERS_SLOT);
+	TEST_ASSERT(gpa == TD_BOOT_PARAMETERS_GPA, "Failed vm_phy_pages_alloc\n");
+
+	virt_map(vm, TD_BOOT_PARAMETERS_GPA, TD_BOOT_PARAMETERS_GPA, npages);
+}
+
+void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm)
+{
+	struct td_boot_parameters *params =
+		addr_gpa2hva(vm, TD_BOOT_PARAMETERS_GPA);
+	uint32_t cr4;
+
+	TEST_ASSERT_EQ(vm->mode, VM_MODE_PXXV48_4K);
+
+	cr4 = kvm_get_default_cr4();
+
+	/* TDX spec 11.6.2: CR4 bit MCE is fixed to 1 */
+	cr4 |= X86_CR4_MCE;
+
+	/* Set this because UEFI also sets this up, to handle XMM exceptions */
+	cr4 |= X86_CR4_OSXMMEXCPT;
+
+	/* TDX spec 11.6.2: CR4 bit VMXE and SMXE are fixed to 0 */
+	cr4 &= ~(X86_CR4_VMXE | X86_CR4_SMXE);
+
+	/* Set parameters! */
+	params->cr0 = kvm_get_default_cr0();
+	params->cr3 = vm->pgd;
+	params->cr4 = cr4;
+	params->idtr.base = vm->arch.idt;
+	params->idtr.limit = kvm_get_default_idt_limit();
+	params->gdtr.base = vm->arch.gdt;
+	params->gdtr.limit = kvm_get_default_gdt_limit();
+
+	TEST_ASSERT(params->cr0 != 0, "cr0 should not be 0");
+	TEST_ASSERT(params->cr3 != 0, "cr3 should not be 0");
+	TEST_ASSERT(params->cr4 != 0, "cr4 should not be 0");
+	TEST_ASSERT(params->gdtr.base != 0, "gdt base address should not be 0");
+	TEST_ASSERT(params->idtr.base != 0, "idt base address should not be 0");
+}
+
+void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+	struct td_boot_parameters *params =
+		addr_gpa2hva(vm, TD_BOOT_PARAMETERS_GPA);
+	struct td_per_vcpu_parameters *vcpu_params =
+		&params->per_vcpu[vcpu->id];
+
+	vcpu_params->esp_gva = kvm_allocate_vcpu_stack(vm);
+}
+
+void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
+{
+	struct td_boot_parameters *params = addr_gpa2hva(vcpu->vm, TD_BOOT_PARAMETERS_GPA);
+	struct td_per_vcpu_parameters *vcpu_params = &params->per_vcpu[vcpu->id];
+
+	vcpu_params->guest_code = (uint64_t)guest_code;
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 12/19] KVM: selftests: Add helper to initialize TDX VM
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (10 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 11/19] KVM: selftests: Set up TDX boot parameters region Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-21  4:29 ` [PATCH v9 13/19] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration Sagi Shahar
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

KVM_TDX_INIT_VM needs to be called after KVM_CREATE_VM and before
creating any VCPUs, thus before KVM_SET_CPUID2. KVM_TDX_INIT_VM accepts
the CPUID values directly.

Since KVM_GET_CPUID2 can't be used at this point, calculate the CPUID
values manually by using kvm_get_supported_cpuid() and filter the
returned CPUIDs against the supported CPUID values read from the TDX
module.

Co-developed-by: Isaku Yamahata <isaku.yamahata@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Co-developed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/include/x86/tdx/tdx_util.h  |  54 +++++++
 .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 132 ++++++++++++++++++
 2 files changed, 186 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
index dafdc7e46abe..a2509959c7ce 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -11,6 +11,60 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
 	return vm->type == KVM_X86_TDX_VM;
 }
 
+/*
+ * TDX ioctls
+ */
+
+#define __vm_tdx_vm_ioctl(vm, cmd, metadata, arg)			\
+({									\
+	int r;								\
+									\
+	union {								\
+		struct kvm_tdx_cmd c;					\
+		unsigned long raw;					\
+	} tdx_cmd = { .c = {						\
+		.id = (cmd),						\
+		.flags = (uint32_t)(metadata),				\
+		.data = (uint64_t)(arg),				\
+	} };								\
+									\
+	r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw);	\
+	r ?: tdx_cmd.c.hw_error;					\
+})
+
+#define vm_tdx_vm_ioctl(vm, cmd, flags, arg)				\
+({									\
+	int ret = __vm_tdx_vm_ioctl(vm, cmd, flags, arg);		\
+									\
+	__TEST_ASSERT_VM_VCPU_IOCTL(!ret, #cmd,	ret, vm);		\
+})
+
+#define __vm_tdx_vcpu_ioctl(vcpu, cmd, metadata, arg)			\
+({									\
+	int r;								\
+									\
+	union {								\
+		struct kvm_tdx_cmd c;					\
+		unsigned long raw;					\
+	} tdx_cmd = { .c = {						\
+		.id = (cmd),						\
+		.flags = (uint32_t)(metadata),				\
+		.data = (uint64_t)(arg),				\
+	} };								\
+									\
+	r = __vcpu_ioctl(vcpu, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw);	\
+	r ?: tdx_cmd.c.hw_error;					\
+})
+
+#define vm_tdx_vcpu_ioctl(vcpu, cmd, flags, arg)			\
+({									\
+	int ret = __vm_tdx_vcpu_ioctl(vcpu, cmd, flags, arg);		\
+									\
+	__TEST_ASSERT_VM_VCPU_IOCTL(!ret, #cmd, ret, (vcpu)->vm);	\
+})
+
+void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes);
+
 void vm_tdx_setup_boot_code_region(struct kvm_vm *vm);
 void vm_tdx_setup_boot_parameters_region(struct kvm_vm *vm, uint32_t nr_runnable_vcpus);
 void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
index 52dc25e0cce4..3869756a5641 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -125,3 +125,135 @@ void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
 
 	vcpu_params->guest_code = (uint64_t)guest_code;
 }
+
+static struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm *vm)
+{
+	struct kvm_tdx_capabilities *tdx_cap = NULL;
+	int nr_cpuid_configs = 4;
+	int rc = -1;
+	int i;
+
+	do {
+		nr_cpuid_configs *= 2;
+
+		tdx_cap = realloc(tdx_cap, sizeof(*tdx_cap) +
+					   sizeof(tdx_cap->cpuid) +
+					   (sizeof(struct kvm_cpuid_entry2) * nr_cpuid_configs));
+		TEST_ASSERT(tdx_cap,
+			    "Could not allocate memory for tdx capability nr_cpuid_configs %d\n",
+			    nr_cpuid_configs);
+
+		tdx_cap->cpuid.nent = nr_cpuid_configs;
+		rc = __vm_tdx_vm_ioctl(vm, KVM_TDX_CAPABILITIES, 0, tdx_cap);
+	} while (rc < 0 && errno == E2BIG);
+
+	TEST_ASSERT(rc == 0, "KVM_TDX_CAPABILITIES failed: %d %d",
+		    rc, errno);
+
+	pr_debug("tdx_cap: supported_attrs: 0x%016llx\n"
+		 "tdx_cap: supported_xfam 0x%016llx\n",
+		 tdx_cap->supported_attrs, tdx_cap->supported_xfam);
+
+	for (i = 0; i < tdx_cap->cpuid.nent; i++) {
+		const struct kvm_cpuid_entry2 *config = &tdx_cap->cpuid.entries[i];
+
+		pr_debug("cpuid config[%d]: leaf 0x%x sub_leaf 0x%x eax 0x%08x ebx 0x%08x ecx 0x%08x edx 0x%08x\n",
+			 i, config->function, config->index,
+			 config->eax, config->ebx, config->ecx, config->edx);
+	}
+
+	return tdx_cap;
+}
+
+static struct kvm_cpuid_entry2 *tdx_find_cpuid_config(struct kvm_tdx_capabilities *cap,
+						      uint32_t leaf, uint32_t sub_leaf)
+{
+	struct kvm_cpuid_entry2 *config;
+	uint32_t i;
+
+	for (i = 0; i < cap->cpuid.nent; i++) {
+		config = &cap->cpuid.entries[i];
+
+		if (config->function == leaf && config->index == sub_leaf)
+			return config;
+	}
+
+	return NULL;
+}
+
+/*
+ * Filter CPUID based on TDX supported capabilities
+ *
+ * Input Args:
+ *   vm - Virtual Machine
+ *   cpuid_data - CPUID fileds to filter
+ *
+ * Output Args: None
+ *
+ * Return: None
+ *
+ * For each CPUID leaf, filter out non-supported bits based on the capabilities reported
+ * by the TDX module
+ */
+static void vm_tdx_filter_cpuid(struct kvm_vm *vm,
+				struct kvm_cpuid2 *cpuid_data)
+{
+	struct kvm_tdx_capabilities *tdx_cap;
+	struct kvm_cpuid_entry2 *config;
+	struct kvm_cpuid_entry2 *e;
+	int i;
+
+	tdx_cap = tdx_read_capabilities(vm);
+
+	i = 0;
+	while (i < cpuid_data->nent) {
+		e = cpuid_data->entries + i;
+		config = tdx_find_cpuid_config(tdx_cap, e->function, e->index);
+
+		if (!config) {
+			int left = cpuid_data->nent - i - 1;
+
+			if (left > 0)
+				memmove(cpuid_data->entries + i,
+					cpuid_data->entries + i + 1,
+					sizeof(*cpuid_data->entries) * left);
+			cpuid_data->nent--;
+			continue;
+		}
+
+		e->eax &= config->eax;
+		e->ebx &= config->ebx;
+		e->ecx &= config->ecx;
+		e->edx &= config->edx;
+
+		i++;
+	}
+
+	free(tdx_cap);
+}
+
+void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
+{
+	struct kvm_tdx_init_vm *init_vm;
+	const struct kvm_cpuid2 *tmp;
+	struct kvm_cpuid2 *cpuid;
+
+	tmp = kvm_get_supported_cpuid();
+
+	cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
+	memcpy(cpuid, tmp, kvm_cpuid2_size(tmp->nent));
+	vm_tdx_filter_cpuid(vm, cpuid);
+
+	init_vm = calloc(1, sizeof(*init_vm) +
+			 sizeof(init_vm->cpuid.entries[0]) * cpuid->nent);
+	TEST_ASSERT(init_vm, "init_vm allocation failed");
+
+	memcpy(&init_vm->cpuid, cpuid, kvm_cpuid2_size(cpuid->nent));
+	free(cpuid);
+
+	init_vm->attributes = attributes;
+
+	vm_tdx_vm_ioctl(vm, KVM_TDX_INIT_VM, 0, init_vm);
+
+	free(init_vm);
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 13/19] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (11 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 12/19] KVM: selftests: Add helper to initialize TDX VM Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-26  9:22   ` Binbin Wu
  2025-08-21  4:29 ` [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM Sagi Shahar
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

From: Isaku Yamahata <isaku.yamahata@intel.com>

This also exercises the KVM_TDX_CAPABILITIES ioctl.

Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Co-developed-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/lib/x86/tdx/tdx_util.c        | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
index 3869756a5641..d8eab99d9333 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -232,6 +232,21 @@ static void vm_tdx_filter_cpuid(struct kvm_vm *vm,
 	free(tdx_cap);
 }
 
+static void tdx_check_attributes(struct kvm_vm *vm, uint64_t attributes)
+{
+	struct kvm_tdx_capabilities *tdx_cap;
+
+	tdx_cap = tdx_read_capabilities(vm);
+
+	/* TDX spec: any bits 0 in supported_attrs must be 0 in attributes */
+	TEST_ASSERT_EQ(attributes & ~tdx_cap->supported_attrs, 0);
+
+	/* TDX spec: any bits 1 in attributes must be 1 in supported_attrs */
+	TEST_ASSERT_EQ(attributes & tdx_cap->supported_attrs, attributes);
+
+	free(tdx_cap);
+}
+
 void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
 {
 	struct kvm_tdx_init_vm *init_vm;
@@ -251,6 +266,8 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
 	memcpy(&init_vm->cpuid, cpuid, kvm_cpuid2_size(cpuid->nent));
 	free(cpuid);
 
+	tdx_check_attributes(vm, attributes);
+
 	init_vm->attributes = attributes;
 
 	vm_tdx_vm_ioctl(vm, KVM_TDX_INIT_VM, 0, init_vm);
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (12 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 13/19] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-25  8:40   ` Yan Zhao
  2025-08-21  4:29 ` [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation Sagi Shahar
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

From: Ackerley Tng <ackerleytng@google.com>

TDX protected memory needs to be measured and encrypted before it can be
used by the guest. Traverse the VM's memory regions and initialize all
the protected ranges by calling KVM_TDX_INIT_MEM_REGION.

Once all the memory is initialized, the VM can be finalized by calling
KVM_TDX_FINALIZE_VM.

Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Co-developed-by: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Erdem Aktas <erdemaktas@google.com>
Co-developed-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
 .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 97 +++++++++++++++++++
 2 files changed, 99 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
index a2509959c7ce..2467b6c35557 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -71,4 +71,6 @@ void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
 void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
 void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
 
+void vm_tdx_finalize(struct kvm_vm *vm);
+
 #endif // SELFTESTS_TDX_TDX_UTIL_H
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
index d8eab99d9333..4024587ed3c2 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -274,3 +274,100 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
 
 	free(init_vm);
 }
+
+static void tdx_init_mem_region(struct kvm_vm *vm, void *source_pages,
+				uint64_t gpa, uint64_t size)
+{
+	uint32_t metadata = KVM_TDX_MEASURE_MEMORY_REGION;
+	struct kvm_tdx_init_mem_region mem_region = {
+		.source_addr = (uint64_t)source_pages,
+		.gpa = gpa,
+		.nr_pages = size / PAGE_SIZE,
+	};
+	struct kvm_vcpu *vcpu;
+
+	vcpu = list_first_entry_or_null(&vm->vcpus, struct kvm_vcpu, list);
+
+	TEST_ASSERT((mem_region.nr_pages > 0) &&
+		    ((mem_region.nr_pages * PAGE_SIZE) == size),
+		    "Cannot add partial pages to the guest memory.\n");
+	TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) == 0,
+		    "Source memory buffer is not page aligned\n");
+	vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region);
+}
+
+static void tdx_init_pages(struct kvm_vm *vm, void *hva, uint64_t gpa,
+			   uint64_t size)
+{
+	void *scratch_page = calloc(1, PAGE_SIZE);
+	uint64_t nr_pages = size / PAGE_SIZE;
+	int i;
+
+	TEST_ASSERT(scratch_page,
+		    "Could not allocate memory for loading memory region");
+
+	for (i = 0; i < nr_pages; i++) {
+		memcpy(scratch_page, hva, PAGE_SIZE);
+
+		tdx_init_mem_region(vm, scratch_page, gpa, PAGE_SIZE);
+
+		hva += PAGE_SIZE;
+		gpa += PAGE_SIZE;
+	}
+
+	free(scratch_page);
+}
+
+static void load_td_private_memory(struct kvm_vm *vm)
+{
+	struct userspace_mem_region *region;
+	int ctr;
+
+	hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
+		const struct sparsebit *protected_pages = region->protected_phy_pages;
+		const vm_paddr_t gpa_base = region->region.guest_phys_addr;
+		const uint64_t hva_base = region->region.userspace_addr;
+		const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
+
+		sparsebit_idx_t i;
+		sparsebit_idx_t j;
+
+		if (!sparsebit_any_set(protected_pages))
+			continue;
+
+		sparsebit_for_each_set_range(protected_pages, i, j) {
+			const uint64_t size_to_load = (j - i + 1) * vm->page_size;
+			const uint64_t offset =
+				(i - lowest_page_in_region) * vm->page_size;
+			const uint64_t hva = hva_base + offset;
+			const uint64_t gpa = gpa_base + offset;
+
+			vm_set_memory_attributes(vm, gpa, size_to_load,
+						 KVM_MEMORY_ATTRIBUTE_PRIVATE);
+
+			/*
+			 * Here, memory is being loaded from hva to gpa. If the memory
+			 * mapped to hva is also used to back gpa, then a copy has to be
+			 * made just for loading, since KVM_TDX_INIT_MEM_REGION ioctl
+			 * cannot encrypt memory in place.
+			 *
+			 * To determine if memory mapped to hva is also used to back
+			 * gpa, use a heuristic:
+			 *
+			 * If this memslot has guest_memfd, then this memslot should
+			 * have memory backed from two sources: hva for shared memory
+			 * and gpa will be backed by guest_memfd.
+			 */
+			if (region->region.guest_memfd == -1)
+				tdx_init_pages(vm, (void *)hva, gpa, size_to_load);
+			else
+				tdx_init_mem_region(vm, (void *)hva, gpa, size_to_load);
+		}
+	}
+}
+
+void vm_tdx_finalize(struct kvm_vm *vm)
+{
+	load_td_private_memory(vm);
+	vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (13 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-26  8:28   ` Chenyi Qiang
  2025-08-26 17:31   ` Sean Christopherson
  2025-08-21  4:29 ` [PATCH v9 16/19] KVM: selftests: Add support for TDX TDCALL from guest Sagi Shahar
                   ` (3 subsequent siblings)
  18 siblings, 2 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

TDX require special handling for VM and VCPU initialization for various
reasons:
- Special ioctlss for creating VM and VCPU.
- TDX registers are inaccessible to KVM.
- TDX require special boot code trampoline for loading parameters.
- TDX only supports KVM_CAP_SPLIT_IRQCHIP.

Hook this special handling into __vm_create() and vm_arch_vcpu_add()
using the utility functions added in previous patches.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/lib/kvm_util.c    | 24 ++++++++-
 .../testing/selftests/kvm/lib/x86/processor.c | 49 ++++++++++++++-----
 2 files changed, 61 insertions(+), 12 deletions(-)

diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index b4c8702ba4bd..d9f0ff97770d 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 2018, Google LLC.
  */
+#include "tdx/tdx_util.h"
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
@@ -465,7 +466,7 @@ void kvm_set_files_rlimit(uint32_t nr_vcpus)
 static bool is_guest_memfd_required(struct vm_shape shape)
 {
 #ifdef __x86_64__
-	return shape.type == KVM_X86_SNP_VM;
+	return (shape.type == KVM_X86_SNP_VM || shape.type == KVM_X86_TDX_VM);
 #else
 	return false;
 #endif
@@ -499,6 +500,12 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
 	for (i = 0; i < NR_MEM_REGIONS; i++)
 		vm->memslots[i] = 0;
 
+	if (is_tdx_vm(vm)) {
+		/* Setup additional mem regions for TDX. */
+		vm_tdx_setup_boot_code_region(vm);
+		vm_tdx_setup_boot_parameters_region(vm, nr_runnable_vcpus);
+	}
+
 	kvm_vm_elf_load(vm, program_invocation_name);
 
 	/*
@@ -1728,11 +1735,26 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa)
 	return (void *) ((uintptr_t) region->host_alias + offset);
 }
 
+static bool is_split_irqchip_required(struct kvm_vm *vm)
+{
+#ifdef __x86_64__
+	return is_tdx_vm(vm);
+#else
+	return false;
+#endif
+}
+
 /* Create an interrupt controller chip for the specified VM. */
 void vm_create_irqchip(struct kvm_vm *vm)
 {
 	int r;
 
+	if (is_split_irqchip_required(vm)) {
+		vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
+		vm->has_irqchip = true;
+		return;
+	}
+
 	/*
 	 * Allocate a fully in-kernel IRQ chip by default, but fall back to a
 	 * split model (x86 only) if that fails (KVM x86 allows compiling out
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 4802fc81bea7..5cf14f09c1b6 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -670,6 +670,11 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm)
 		vm_sev_ioctl(vm, KVM_SEV_INIT2, &init);
 	}
 
+	if (is_tdx_vm(vm)) {
+		vm_tdx_init_vm(vm, 0);
+		vm_tdx_load_common_boot_parameters(vm);
+	}
+
 	r = __vm_ioctl(vm, KVM_GET_TSC_KHZ, NULL);
 	TEST_ASSERT(r > 0, "KVM_GET_TSC_KHZ did not provide a valid TSC frequency.");
 	guest_tsc_khz = r;
@@ -680,9 +685,13 @@ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
 {
 	struct kvm_regs regs;
 
-	vcpu_regs_get(vcpu, &regs);
-	regs.rip = (unsigned long) guest_code;
-	vcpu_regs_set(vcpu, &regs);
+	if (is_tdx_vm(vcpu->vm))
+		vm_tdx_set_vcpu_entry_point(vcpu, guest_code);
+	else {
+		vcpu_regs_get(vcpu, &regs);
+		regs.rip = (unsigned long) guest_code;
+		vcpu_regs_set(vcpu, &regs);
+	}
 }
 
 vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
@@ -711,6 +720,19 @@ vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
 	return stack_vaddr;
 }
 
+static void vm_tdx_vcpu_add(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid2 *cpuid;
+
+	cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
+	vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_GET_CPUID, 0, cpuid);
+	vcpu_init_cpuid(vcpu, cpuid);
+	free(cpuid);
+	vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_VCPU, 0, NULL);
+
+	vm_tdx_load_vcpu_boot_parameters(vm, vcpu);
+}
+
 struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
 {
 	struct kvm_mp_state mp_state;
@@ -718,16 +740,21 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
 	struct kvm_vcpu *vcpu;
 
 	vcpu = __vm_vcpu_add(vm, vcpu_id);
-	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
-	vcpu_init_sregs(vm, vcpu);
-	vcpu_init_xcrs(vm, vcpu);
 
-	/* Setup guest general purpose registers */
-	vcpu_regs_get(vcpu, &regs);
-	regs.rflags = regs.rflags | 0x2;
-	if (vm->type != KVM_X86_TDX_VM)
+	if (is_tdx_vm(vm)) {
+		vm_tdx_vcpu_add(vm, vcpu);
+	} else {
+		vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
+
+		vcpu_init_sregs(vm, vcpu);
+		vcpu_init_xcrs(vm, vcpu);
+
+		/* Setup guest general purpose registers */
+		vcpu_regs_get(vcpu, &regs);
+		regs.rflags = regs.rflags | 0x2;
 		regs.rsp = kvm_allocate_vcpu_stack(vm);
-	vcpu_regs_set(vcpu, &regs);
+		vcpu_regs_set(vcpu, &regs);
+	}
 
 	/* Setup the MP state */
 	mp_state.mp_state = 0;
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 16/19] KVM: selftests: Add support for TDX TDCALL from guest
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (14 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-21  4:29 ` [PATCH v9 17/19] KVM: selftests: Add wrapper for TDX MMIO " Sagi Shahar
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

From: Erdem Aktas <erdemaktas@google.com>

Add support for TDX guests to issue TDCALLs to the TDX module.

Signed-off-by: Erdem Aktas <erdemaktas@google.com>
Co-developed-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  8 ++
 .../selftests/kvm/include/x86/tdx/tdcall.h    | 34 +++++++
 .../selftests/kvm/lib/x86/tdx/tdcall.S        | 93 +++++++++++++++++++
 .../kvm/lib/x86/tdx/tdcall_offsets.c          | 16 ++++
 4 files changed, 151 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdcall.h
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdcall.S
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdcall_offsets.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index c42b579fb7c5..1f541c0d4fe1 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -20,6 +20,7 @@ LIBKVM += lib/userfaultfd_util.c
 LIBKVM_STRING += lib/string_override.c
 
 LIBKVM_ASM_DEFS += lib/x86/tdx/td_boot_offsets.c
+LIBKVM_ASM_DEFS += lib/x86/tdx/tdcall_offsets.c
 
 LIBKVM_x86 += lib/x86/apic.c
 LIBKVM_x86 += lib/x86/handlers.S
@@ -33,6 +34,7 @@ LIBKVM_x86 += lib/x86/ucall.c
 LIBKVM_x86 += lib/x86/vmx.c
 LIBKVM_x86 += lib/x86/tdx/tdx_util.c
 LIBKVM_x86 += lib/x86/tdx/td_boot.S
+LIBKVM_x86 += lib/x86/tdx/tdcall.S
 
 LIBKVM_arm64 += lib/arm64/gic.c
 LIBKVM_arm64 += lib/arm64/gic_v3.c
@@ -342,7 +344,13 @@ $(OUTPUT)/lib/x86/tdx/td_boot.o: $(OUTPUT)/include/x86/tdx/td_boot_offsets.h
 $(OUTPUT)/include/x86/tdx/td_boot_offsets.h: $(OUTPUT)/lib/x86/tdx/td_boot_offsets.s FORCE
 	$(call filechk,offsets,__TDX_BOOT_OFFSETS_H__)
 
+$(OUTPUT)/lib/x86/tdx/tdcall.o: $(OUTPUT)/include/x86/tdx/tdcall_offsets.h
+
+$(OUTPUT)/include/x86/tdx/tdcall_offsets.h: $(OUTPUT)/lib/x86/tdx/tdcall_offsets.s FORCE
+	$(call filechk,offsets,__TDCALL__OFFSETS_H__)
+
 EXTRA_CLEAN += $(OUTPUT)/include/x86/tdx/td_boot_offsets.h
+EXTRA_CLEAN += $(OUTPUT)/include/x86/tdx/tdcall_offsets.h
 
 $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS))))
 $(SPLIT_TEST_GEN_OBJ): $(GEN_HDRS)
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdcall.h b/tools/testing/selftests/kvm/include/x86/tdx/tdcall.h
new file mode 100644
index 000000000000..60c70646f876
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdcall.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Adapted from arch/x86/include/asm/shared/tdx.h */
+
+#ifndef SELFTESTS_TDX_TDCALL_H
+#define SELFTESTS_TDX_TDCALL_H
+
+#include <linux/bits.h>
+
+#define TDX_TDCALL_HAS_OUTPUT BIT(0)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+/*
+ * Used in __tdx_tdcall() to pass down and get back registers' values of
+ * the TDCALL instruction when requesting services from the VMM.
+ *
+ * This is a software only structure and not part of the TDX module/VMM ABI.
+ */
+struct tdx_tdcall_args {
+	u64 r10;
+	u64 r11;
+	u64 r12;
+	u64 r13;
+	u64 r14;
+	u64 r15;
+};
+
+/* Used to request services from the VMM */
+u64 __tdx_tdcall(struct tdx_tdcall_args *args, unsigned long flags);
+
+#endif // __ASSEMBLY__
+#endif // SELFTESTS_TDX_TDCALL_H
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdcall.S b/tools/testing/selftests/kvm/lib/x86/tdx/tdcall.S
new file mode 100644
index 000000000000..05869e86b9d8
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdcall.S
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Adapted from arch/x86/virt/vmx/tdx/tdxcall.S */
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include <linux/bits.h>
+#include "tdx/tdcall.h"
+#include "tdx/tdcall_offsets.h"
+
+/*
+ * TDCALL is supported in Binutils >= 2.36, add it for older version.
+ */
+#define tdcall		.byte 0x66,0x0f,0x01,0xcc
+
+/*
+ * Bitmasks of exposed registers (with VMM).
+ */
+#define TDX_R10		BIT(10)
+#define TDX_R11		BIT(11)
+#define TDX_R12		BIT(12)
+#define TDX_R13		BIT(13)
+#define TDX_R14		BIT(14)
+#define TDX_R15		BIT(15)
+
+/*
+ * These registers are clobbered to hold arguments for each
+ * TDVMCALL. They are safe to expose to the VMM.
+ * Each bit in this mask represents a register ID. Bit field
+ * details can be found in TDX GHCI specification, section
+ * titled "TDCALL [TDG.VP.VMCALL] leaf".
+ */
+#define TDVMCALL_EXPOSE_REGS_MASK    \
+         (TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15)
+
+.code64
+.section .text
+
+.globl __tdx_tdcall
+.type __tdx_tdcall, @function
+__tdx_tdcall:
+	/* Set up stack frame */
+	push %rbp
+	movq %rsp, %rbp
+
+	/* Save callee-saved GPRs as mandated by the x86_64 ABI */
+	push %r15
+	push %r14
+	push %r13
+	push %r12
+
+	/* Mangle function call ABI into TDCALL ABI: */
+	/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
+	xor %eax, %eax
+
+	/* Copy tdcall registers from arg struct: */
+	movq TDX_TDCALL_R10(%rdi), %r10
+	movq TDX_TDCALL_R11(%rdi), %r11
+	movq TDX_TDCALL_R12(%rdi), %r12
+	movq TDX_TDCALL_R13(%rdi), %r13
+	movq TDX_TDCALL_R14(%rdi), %r14
+	movq TDX_TDCALL_R15(%rdi), %r15
+
+	movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
+
+	tdcall
+
+	/* TDVMCALL leaf return code is in R10 */
+	movq %r10, %rax
+
+	/* Copy tdcall result registers to arg struct if needed */
+	testq $TDX_TDCALL_HAS_OUTPUT, %rsi
+	jz .Lout
+
+	movq %r10, TDX_TDCALL_R10(%rdi)
+	movq %r11, TDX_TDCALL_R11(%rdi)
+	movq %r12, TDX_TDCALL_R12(%rdi)
+	movq %r13, TDX_TDCALL_R13(%rdi)
+	movq %r14, TDX_TDCALL_R14(%rdi)
+	movq %r15, TDX_TDCALL_R15(%rdi)
+.Lout:
+	/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
+	pop %r12
+	pop %r13
+	pop %r14
+	pop %r15
+
+	pop %rbp
+	ret
+
+/* Disable executable stack */
+.section .note.GNU-stack,"",%progbits
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdcall_offsets.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdcall_offsets.c
new file mode 100644
index 000000000000..dcd4457be6e5
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdcall_offsets.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+#define COMPILE_OFFSETS
+
+#include <linux/kbuild.h>
+
+#include "tdx/tdcall.h"
+
+static void __attribute__((used)) common(void)
+{
+	OFFSET(TDX_TDCALL_R10, tdx_tdcall_args, r10);
+	OFFSET(TDX_TDCALL_R11, tdx_tdcall_args, r11);
+	OFFSET(TDX_TDCALL_R12, tdx_tdcall_args, r12);
+	OFFSET(TDX_TDCALL_R13, tdx_tdcall_args, r13);
+	OFFSET(TDX_TDCALL_R14, tdx_tdcall_args, r14);
+	OFFSET(TDX_TDCALL_R15, tdx_tdcall_args, r15);
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 17/19] KVM: selftests: Add wrapper for TDX MMIO from guest
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (15 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 16/19] KVM: selftests: Add support for TDX TDCALL from guest Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-21  4:29 ` [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX Sagi Shahar
  2025-08-21  4:29 ` [PATCH v9 19/19] KVM: selftests: Add TDX lifecycle test Sagi Shahar
  18 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Add utility function to issue MMIO TDCALL from TDX guests.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  1 +
 .../selftests/kvm/include/x86/tdx/tdx.h       | 14 ++++++++++++
 tools/testing/selftests/kvm/lib/x86/tdx/tdx.c | 22 +++++++++++++++++++
 3 files changed, 37 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx.h
 create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdx.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 1f541c0d4fe1..8d1aaebd746e 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -35,6 +35,7 @@ LIBKVM_x86 += lib/x86/vmx.c
 LIBKVM_x86 += lib/x86/tdx/tdx_util.c
 LIBKVM_x86 += lib/x86/tdx/td_boot.S
 LIBKVM_x86 += lib/x86/tdx/tdcall.S
+LIBKVM_x86 += lib/x86/tdx/tdx.c
 
 LIBKVM_arm64 += lib/arm64/gic.c
 LIBKVM_arm64 += lib/arm64/gic_v3.c
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx.h
new file mode 100644
index 000000000000..22b096402998
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTESTS_TDX_TDX_H
+#define SELFTESTS_TDX_TDX_H
+
+#include <stdint.h>
+
+/* MMIO direction */
+#define MMIO_READ	0
+#define MMIO_WRITE	1
+
+uint64_t tdg_vp_vmcall_ve_request_mmio_write(uint64_t address, uint64_t size,
+					     uint64_t data_in);
+
+#endif // SELFTESTS_TDX_TDX_H
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx.c
new file mode 100644
index 000000000000..12df30ac1ceb
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "tdx/tdcall.h"
+#include "tdx/tdx.h"
+
+#define TDG_VP_VMCALL 0
+
+#define TDG_VP_VMCALL_VE_REQUEST_MMIO	48
+
+uint64_t tdg_vp_vmcall_ve_request_mmio_write(uint64_t address, uint64_t size,
+					     uint64_t data_in)
+{
+	struct tdx_tdcall_args args = {
+		.r11 = TDG_VP_VMCALL_VE_REQUEST_MMIO,
+		.r12 = size,
+		.r13 = MMIO_WRITE,
+		.r14 = address,
+		.r15 = data_in,
+	};
+
+	return __tdx_tdcall(&args, 0);
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (16 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 17/19] KVM: selftests: Add wrapper for TDX MMIO " Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  2025-08-27  7:18   ` Binbin Wu
  2025-08-21  4:29 ` [PATCH v9 19/19] KVM: selftests: Add TDX lifecycle test Sagi Shahar
  18 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

From: Ackerley Tng <ackerleytng@google.com>

ucalls for non-Coco VMs work by having the guest write to the rdi
register, then perform an io instruction to exit to the host. The host
then reads rdi using kvm_get_regs().

CPU registers can't be read using kvm_get_regs() for TDX, so TDX
guests use MMIO to pass the struct ucall's hva to the host. MMIO was
chosen because it is one of the simplest (hence unlikely to fail)
mechanisms that support passing 8 bytes from guest to host.

Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Co-developed-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 .../testing/selftests/kvm/include/x86/ucall.h |  4 +-
 tools/testing/selftests/kvm/lib/x86/ucall.c   | 45 ++++++++++++++++---
 2 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/ucall.h b/tools/testing/selftests/kvm/include/x86/ucall.h
index d3825dcc3cd9..0494a4a21557 100644
--- a/tools/testing/selftests/kvm/include/x86/ucall.h
+++ b/tools/testing/selftests/kvm/include/x86/ucall.h
@@ -6,8 +6,6 @@
 
 #define UCALL_EXIT_REASON       KVM_EXIT_IO
 
-static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa)
-{
-}
+void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa);
 
 #endif
diff --git a/tools/testing/selftests/kvm/lib/x86/ucall.c b/tools/testing/selftests/kvm/lib/x86/ucall.c
index 1265cecc7dd1..0ad24baaa3c4 100644
--- a/tools/testing/selftests/kvm/lib/x86/ucall.c
+++ b/tools/testing/selftests/kvm/lib/x86/ucall.c
@@ -5,11 +5,34 @@
  * Copyright (C) 2018, Red Hat, Inc.
  */
 #include "kvm_util.h"
+#include "tdx/tdx.h"
 
 #define UCALL_PIO_PORT ((uint16_t)0x1000)
 
+static uint8_t vm_type;
+static vm_paddr_t host_ucall_mmio_gpa;
+static vm_paddr_t ucall_mmio_gpa;
+
+void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa)
+{
+	vm_type = vm->type;
+	sync_global_to_guest(vm, vm_type);
+
+	host_ucall_mmio_gpa = ucall_mmio_gpa = mmio_gpa;
+
+	if (vm_type == KVM_X86_TDX_VM)
+		ucall_mmio_gpa |= vm->arch.s_bit;
+
+	sync_global_to_guest(vm, ucall_mmio_gpa);
+}
+
 void ucall_arch_do_ucall(vm_vaddr_t uc)
 {
+	if (vm_type == KVM_X86_TDX_VM) {
+		tdg_vp_vmcall_ve_request_mmio_write(ucall_mmio_gpa, 8, uc);
+		return;
+	}
+
 	/*
 	 * FIXME: Revert this hack (the entire commit that added it) once nVMX
 	 * preserves L2 GPRs across a nested VM-Exit.  If a ucall from L2, e.g.
@@ -46,11 +69,23 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
 {
 	struct kvm_run *run = vcpu->run;
 
-	if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
-		struct kvm_regs regs;
+	switch (vm_type) {
+	case KVM_X86_TDX_VM:
+		if (vcpu->run->exit_reason == KVM_EXIT_MMIO &&
+		    vcpu->run->mmio.phys_addr == host_ucall_mmio_gpa &&
+		    vcpu->run->mmio.len == 8 && vcpu->run->mmio.is_write) {
+			uint64_t data = *(uint64_t *)vcpu->run->mmio.data;
+
+			return (void *)data;
+		}
+		return NULL;
+	default:
+		if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
+			struct kvm_regs regs;
 
-		vcpu_regs_get(vcpu, &regs);
-		return (void *)regs.rdi;
+			vcpu_regs_get(vcpu, &regs);
+			return (void *)regs.rdi;
+		}
+		return NULL;
 	}
-	return NULL;
 }
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v9 19/19] KVM: selftests: Add TDX lifecycle test
  2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
                   ` (17 preceding siblings ...)
  2025-08-21  4:29 ` [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX Sagi Shahar
@ 2025-08-21  4:29 ` Sagi Shahar
  18 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21  4:29 UTC (permalink / raw)
  To: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Sagi Shahar, Roger Wang, Binbin Wu,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Adding a test to verify TDX lifecycle by creating a simple TD.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  1 +
 .../selftests/kvm/include/x86/tdx/tdx_util.h  | 10 ++++++
 .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 18 +++++++++++
 tools/testing/selftests/kvm/x86/tdx_vm_test.c | 31 +++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/x86/tdx_vm_test.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 8d1aaebd746e..86c101fbe1a0 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -155,6 +155,7 @@ TEST_GEN_PROGS_x86 += rseq_test
 TEST_GEN_PROGS_x86 += steal_time
 TEST_GEN_PROGS_x86 += system_counter_offset_test
 TEST_GEN_PROGS_x86 += pre_fault_memory_test
+TEST_GEN_PROGS_x86 += x86/tdx_vm_test
 
 # Compiled outputs used by test targets
 TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
index 2467b6c35557..775ca249f74d 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -11,6 +11,14 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
 	return vm->type == KVM_X86_TDX_VM;
 }
 
+/*
+ * Verify that TDX is supported by KVM.
+ */
+static inline bool is_tdx_enabled(void)
+{
+	return !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_TDX_VM));
+}
+
 /*
  * TDX ioctls
  */
@@ -72,5 +80,7 @@ void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
 void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
 
 void vm_tdx_finalize(struct kvm_vm *vm);
+struct kvm_vm *vm_tdx_create_with_one_vcpu(void *guest_code,
+					   struct kvm_vcpu **vcpu);
 
 #endif // SELFTESTS_TDX_TDX_UTIL_H
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
index 4024587ed3c2..8b18f1a8da62 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -371,3 +371,21 @@ void vm_tdx_finalize(struct kvm_vm *vm)
 	load_td_private_memory(vm);
 	vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
 }
+
+struct kvm_vm *vm_tdx_create_with_one_vcpu(void *guest_code,
+					   struct kvm_vcpu **vcpu)
+{
+	struct vm_shape shape = {
+		.mode = VM_MODE_DEFAULT,
+		.type = KVM_X86_TDX_VM,
+	};
+	struct kvm_vm *vm;
+	struct kvm_vcpu *vcpus[1];
+
+	vm = __vm_create_with_vcpus(shape, 1, 0, guest_code, vcpus);
+	*vcpu = vcpus[0];
+
+	vm_tdx_finalize(vm);
+
+	return vm;
+}
diff --git a/tools/testing/selftests/kvm/x86/tdx_vm_test.c b/tools/testing/selftests/kvm/x86/tdx_vm_test.c
new file mode 100644
index 000000000000..a9ee489eea1a
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/tdx_vm_test.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "kvm_util.h"
+#include "tdx/tdx_util.h"
+#include "ucall_common.h"
+#include "kselftest_harness.h"
+
+static void guest_code_lifecycle(void)
+{
+	GUEST_DONE();
+}
+
+TEST(verify_td_lifecycle)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct ucall uc;
+
+	vm = vm_tdx_create_with_one_vcpu(guest_code_lifecycle, &vcpu);
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_DONE);
+
+	kvm_vm_free(vm);
+}
+
+int main(int argc, char **argv)
+{
+	TEST_REQUIRE(is_tdx_enabled());
+	return test_harness_run(argc, argv);
+}
-- 
2.51.0.rc1.193.gad69d77794-goog


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type()
  2025-08-21  4:28 ` [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type() Sagi Shahar
@ 2025-08-21 14:16   ` Sean Christopherson
  2025-08-21 14:37   ` Ira Weiny
  1 sibling, 0 replies; 62+ messages in thread
From: Sean Christopherson @ 2025-08-21 14:16 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Ackerley Tng,
	Ryan Afranji, Andrew Jones, Isaku Yamahata, Erdem Aktas,
	Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Wed, Aug 20, 2025, Sagi Shahar wrote:
> Redefinition of is_signed_type() causes compilation warning for tests
> which use kselftest_harness. Replace the definition with linux/overflow.h

Heh, tried that:

https://lore.kernel.org/all/18f2ea68-0f7c-465e-917e-e079335995c1@sirena.org.uk

There's now a fix in kvm-x86/fixes and thus kvm-x86/next, so if you base something
off kvm-x86/next, the warnings should be gone.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type()
  2025-08-21  4:28 ` [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type() Sagi Shahar
  2025-08-21 14:16   ` Sean Christopherson
@ 2025-08-21 14:37   ` Ira Weiny
  2025-08-21 14:42     ` Sean Christopherson
  1 sibling, 1 reply; 62+ messages in thread
From: Ira Weiny @ 2025-08-21 14:37 UTC (permalink / raw)
  To: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Sean Christopherson, Ackerley Tng, Ryan Afranji, Andrew Jones,
	Isaku Yamahata, Erdem Aktas, Rick Edgecombe, Roger Wang,
	Binbin Wu, Oliver Upton, Pratik R. Sampat, Reinette Chatre,
	Ira Weiny, Chao Gao, Chenyi Qiang, Kees Cook
  Cc: linux-kernel, kvm, linux-kselftest

Need to add the selftest folks.

+ linux-kselftest@vger.kernel.org
+ Kees Cook <kees@kernel.org>
+ Shuah Khan <shuah@kernel.org>

Sagi Shahar wrote:
> Redefinition of is_signed_type() causes compilation warning for tests
> which use kselftest_harness. Replace the definition with linux/overflow.h
> 
> Signed-off-by: Sagi Shahar <sagis@google.com>

Thanks!  I've seen this as well and it fixes the warning for me as well.
It might be worth picking up separate from this series depending on what
the selftest folks say.

Tested-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>

> ---
>  tools/testing/selftests/kselftest_harness.h | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
> index 2925e47db995..a580a0d33c65 100644
> --- a/tools/testing/selftests/kselftest_harness.h
> +++ b/tools/testing/selftests/kselftest_harness.h
> @@ -56,6 +56,7 @@
>  #include <asm/types.h>
>  #include <ctype.h>
>  #include <errno.h>
> +#include <linux/overflow.h>
>  #include <linux/unistd.h>
>  #include <poll.h>
>  #include <stdbool.h>
> @@ -751,8 +752,6 @@
>  	for (; _metadata->trigger; _metadata->trigger = \
>  			__bail(_assert, _metadata))
>  
> -#define is_signed_type(var)       (!!(((__typeof__(var))(-1)) < (__typeof__(var))1))
> -
>  #define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \
>  	/* Avoid multiple evaluation of the cases */ \
>  	__typeof__(_expected) __exp = (_expected); \
> -- 
> 2.51.0.rc1.193.gad69d77794-goog
> 



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type()
  2025-08-21 14:37   ` Ira Weiny
@ 2025-08-21 14:42     ` Sean Christopherson
  0 siblings, 0 replies; 62+ messages in thread
From: Sean Christopherson @ 2025-08-21 14:42 UTC (permalink / raw)
  To: Ira Weiny
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Chao Gao, Chenyi Qiang,
	Kees Cook, linux-kernel, kvm

On Thu, Aug 21, 2025, Ira Weiny wrote:
> Need to add the selftest folks.
> 
> + linux-kselftest@vger.kernel.org
> + Kees Cook <kees@kernel.org>
> + Shuah Khan <shuah@kernel.org>
> 
> Sagi Shahar wrote:
> > Redefinition of is_signed_type() causes compilation warning for tests
> > which use kselftest_harness. Replace the definition with linux/overflow.h
> > 
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> 
> Thanks!  I've seen this as well and it fixes the warning for me as well.
> It might be worth picking up separate from this series depending on what
> the selftest folks say.

Again[1], I already have a fix applied and will send it to Paolo today.  And simply
including overflow.h doesn't work[2] because not all selftests add tools/include to
their include path.

I appreciate the enthusiastic though!

[1] https://lore.kernel.org/all/aKcqRFWuGZQQ3v3y@google.com
[2] https://lore.kernel.org/all/18f2ea68-0f7c-465e-917e-e079335995c1@sirena.org.uk

> 
> Tested-by: Ira Weiny <ira.weiny@intel.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> 
> > ---
> >  tools/testing/selftests/kselftest_harness.h | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
> > index 2925e47db995..a580a0d33c65 100644
> > --- a/tools/testing/selftests/kselftest_harness.h
> > +++ b/tools/testing/selftests/kselftest_harness.h
> > @@ -56,6 +56,7 @@
> >  #include <asm/types.h>
> >  #include <ctype.h>
> >  #include <errno.h>
> > +#include <linux/overflow.h>
> >  #include <linux/unistd.h>
> >  #include <poll.h>
> >  #include <stdbool.h>
> > @@ -751,8 +752,6 @@
> >  	for (; _metadata->trigger; _metadata->trigger = \
> >  			__bail(_assert, _metadata))
> >  
> > -#define is_signed_type(var)       (!!(((__typeof__(var))(-1)) < (__typeof__(var))1))
> > -
> >  #define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \
> >  	/* Avoid multiple evaluation of the cases */ \
> >  	__typeof__(_expected) __exp = (_expected); \
> > -- 
> > 2.51.0.rc1.193.gad69d77794-goog
> > 
> 
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary
  2025-08-21  4:28 ` [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary Sagi Shahar
@ 2025-08-21 14:45   ` Ira Weiny
  2025-08-26  2:36   ` Binbin Wu
  1 sibling, 0 replies; 62+ messages in thread
From: Ira Weiny @ 2025-08-21 14:45 UTC (permalink / raw)
  To: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Sean Christopherson, Ackerley Tng, Ryan Afranji, Andrew Jones,
	Isaku Yamahata, Erdem Aktas, Rick Edgecombe, Roger Wang,
	Binbin Wu, Oliver Upton, Pratik R. Sampat, Reinette Chatre,
	Ira Weiny, Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Sagi Shahar wrote:
> If virt_map() is called before any call to ____vm_vaddr_alloc() it
> will create the mapping using an invalid pgd.
> 
> Add call to virt_pgd_alloc() as part of virt_map() before creating the
> mapping, similarly to ____vm_vaddr_alloc()
> 
> Signed-off-by: Sagi Shahar <sagis@google.com>

Reviewed-by: Ira Weiny <ira.weiny@intel.com>

> ---
>  tools/testing/selftests/kvm/lib/kvm_util.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index c3f5142b0a54..b4c8702ba4bd 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -1609,6 +1609,7 @@ void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
>  	TEST_ASSERT(vaddr + size > vaddr, "Vaddr overflow");
>  	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
>  
> +	virt_pgd_alloc(vm);
>  	while (npages--) {
>  		virt_pg_map(vm, vaddr, paddr);
>  		sparsebit_set(vm->vpages_mapped, vaddr >> vm->page_shift);
> -- 
> 2.51.0.rc1.193.gad69d77794-goog
> 



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 06/19] KVM: selftests: Expose segment definitons to assembly files
  2025-08-21  4:28 ` [PATCH v9 06/19] KVM: selftests: Expose segment definitons to assembly files Sagi Shahar
@ 2025-08-21 20:04   ` Ira Weiny
  0 siblings, 0 replies; 62+ messages in thread
From: Ira Weiny @ 2025-08-21 20:04 UTC (permalink / raw)
  To: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Sean Christopherson, Ackerley Tng, Ryan Afranji, Andrew Jones,
	Isaku Yamahata, Erdem Aktas, Rick Edgecombe, Roger Wang,
	Binbin Wu, Oliver Upton, Pratik R. Sampat, Reinette Chatre,
	Ira Weiny, Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

NIT:

Sagi Shahar wrote:
> Move kernel segment definitons to a separate file which can be included
                      ^^^^^^^^^^
		      definitions

And in the subject.

Otherwise seems reasonable.

Reviewed-by: Ira Weiny <ira.weiny@intel.com>

> from assembly files.
> 
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>  .../selftests/kvm/include/x86/processor_asm.h        | 12 ++++++++++++
>  tools/testing/selftests/kvm/lib/x86/processor.c      |  5 +----
>  2 files changed, 13 insertions(+), 4 deletions(-)
>  create mode 100644 tools/testing/selftests/kvm/include/x86/processor_asm.h
> 
> diff --git a/tools/testing/selftests/kvm/include/x86/processor_asm.h b/tools/testing/selftests/kvm/include/x86/processor_asm.h
> new file mode 100644
> index 000000000000..7e5386a85ca8
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/include/x86/processor_asm.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Used for storing defines used by both processor.c and assembly code.
> + */
> +#ifndef SELFTEST_KVM_PROCESSOR_ASM_H
> +#define SELFTEST_KVM_PROCESSOR_ASM_H
> +
> +#define KERNEL_CS	0x8
> +#define KERNEL_DS	0x10
> +#define KERNEL_TSS	0x18
> +
> +#endif  // SELFTEST_KVM_PROCESSOR_ASM_H
> diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> index 6dbf40cbbc2a..4802fc81bea7 100644
> --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> @@ -7,6 +7,7 @@
>  #include "test_util.h"
>  #include "kvm_util.h"
>  #include "processor.h"
> +#include "processor_asm.h"
>  #include "sev.h"
>  #include "tdx/tdx_util.h"
>  
> @@ -14,10 +15,6 @@
>  #define NUM_INTERRUPTS 256
>  #endif
>  
> -#define KERNEL_CS	0x8
> -#define KERNEL_DS	0x10
> -#define KERNEL_TSS	0x18
> -
>  vm_vaddr_t exception_handlers;
>  bool host_cpu_is_amd;
>  bool host_cpu_is_intel;
> -- 
> 2.51.0.rc1.193.gad69d77794-goog
> 



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack
  2025-08-21  4:28 ` [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack Sagi Shahar
@ 2025-08-21 22:00   ` Ira Weiny
  2025-08-21 22:24     ` Sagi Shahar
  2025-08-26  5:39   ` Binbin Wu
  1 sibling, 1 reply; 62+ messages in thread
From: Ira Weiny @ 2025-08-21 22:00 UTC (permalink / raw)
  To: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Sean Christopherson, Ackerley Tng, Ryan Afranji, Andrew Jones,
	Isaku Yamahata, Erdem Aktas, Rick Edgecombe, Roger Wang,
	Binbin Wu, Oliver Upton, Pratik R. Sampat, Reinette Chatre,
	Ira Weiny, Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm

Sagi Shahar wrote:

[snip]

> diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> index b2a4b11ac8c0..1eae92957456 100644
> --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> @@ -687,12 +687,9 @@ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
>  	vcpu_regs_set(vcpu, &regs);
>  }
>  
> -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
>  {
> -	struct kvm_mp_state mp_state;
> -	struct kvm_regs regs;
>  	vm_vaddr_t stack_vaddr;
> -	struct kvm_vcpu *vcpu;
>  
>  	stack_vaddr = __vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(),
>  				       DEFAULT_GUEST_STACK_VADDR_MIN,
> @@ -713,6 +710,15 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
>  		    "__vm_vaddr_alloc() did not provide a page-aligned address");
>  	stack_vaddr -= 8;
>  
> +	return stack_vaddr;
> +}
> +
> +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> +{
> +	struct kvm_mp_state mp_state;
> +	struct kvm_regs regs;
> +	struct kvm_vcpu *vcpu;
> +
>  	vcpu = __vm_vcpu_add(vm, vcpu_id);
>  	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
>  	vcpu_init_sregs(vm, vcpu);
> @@ -721,7 +727,8 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
>  	/* Setup guest general purpose registers */
>  	vcpu_regs_get(vcpu, &regs);
>  	regs.rflags = regs.rflags | 0x2;
> -	regs.rsp = stack_vaddr;
> +	if (vm->type != KVM_X86_TDX_VM)
> +		regs.rsp = kvm_allocate_vcpu_stack(vm);

At this point in the series vm->type can't be KVM_X86_TDX_VM correct?

So that makes this safe during bisect?

Ira

>  	vcpu_regs_set(vcpu, &regs);
>  
>  	/* Setup the MP state */
> -- 
> 2.51.0.rc1.193.gad69d77794-goog
> 



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
  2025-08-21  4:28 ` [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Sagi Shahar
@ 2025-08-21 22:05   ` Ira Weiny
  2025-08-21 22:30     ` Sagi Shahar
  2025-08-26  5:51   ` Binbin Wu
  1 sibling, 1 reply; 62+ messages in thread
From: Ira Weiny @ 2025-08-21 22:05 UTC (permalink / raw)
  To: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Sean Christopherson, Ackerley Tng, Ryan Afranji, Andrew Jones,
	Isaku Yamahata, Erdem Aktas, Rick Edgecombe, Roger Wang,
	Binbin Wu, Oliver Upton, Pratik R. Sampat, Reinette Chatre,
	Ira Weiny, Chao Gao, Chenyi Qiang
  Cc: linux-kernel, kvm, Adrian Hunter

Sagi Shahar wrote:
> From: Isaku Yamahata <isaku.yamahata@intel.com>
> 
> Let kvm_init_vm_address_properties() initialize vm->arch.{s_bit, tag_mask}
> similar to SEV.
> 
> TDX sets the shared bit based on the guest physical address width and
> currently supports 48 and 52 widths.
> 
> Co-developed-by: Adrian Hunter <adrian.hunter@intel.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> Co-developed-by: Sagi Shahar <sagis@google.com>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>  .../selftests/kvm/include/x86/tdx/tdx_util.h       | 14 ++++++++++++++
>  tools/testing/selftests/kvm/lib/x86/processor.c    | 12 ++++++++++--
>  2 files changed, 24 insertions(+), 2 deletions(-)
>  create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> 
> diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> new file mode 100644
> index 000000000000..286d5e3c24b1
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef SELFTESTS_TDX_TDX_UTIL_H
> +#define SELFTESTS_TDX_TDX_UTIL_H
> +
> +#include <stdbool.h>
> +
> +#include "kvm_util.h"
> +
> +static inline bool is_tdx_vm(struct kvm_vm *vm)
> +{
> +	return vm->type == KVM_X86_TDX_VM;
> +}

NIT: Might have been better to define this in 4/19 and use it there.  But
looks like that logic is changed later on somewhere.  So...  meh.

Ira

[snip]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack
  2025-08-21 22:00   ` Ira Weiny
@ 2025-08-21 22:24     ` Sagi Shahar
  0 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21 22:24 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Chao Gao, Chenyi Qiang,
	linux-kernel, kvm

On Thu, Aug 21, 2025 at 4:58 PM Ira Weiny <ira.weiny@intel.com> wrote:
>
> Sagi Shahar wrote:
>
> [snip]
>
> > diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> > index b2a4b11ac8c0..1eae92957456 100644
> > --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> > +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> > @@ -687,12 +687,9 @@ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
> >       vcpu_regs_set(vcpu, &regs);
> >  }
> >
> > -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> > +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
> >  {
> > -     struct kvm_mp_state mp_state;
> > -     struct kvm_regs regs;
> >       vm_vaddr_t stack_vaddr;
> > -     struct kvm_vcpu *vcpu;
> >
> >       stack_vaddr = __vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(),
> >                                      DEFAULT_GUEST_STACK_VADDR_MIN,
> > @@ -713,6 +710,15 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> >                   "__vm_vaddr_alloc() did not provide a page-aligned address");
> >       stack_vaddr -= 8;
> >
> > +     return stack_vaddr;
> > +}
> > +
> > +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> > +{
> > +     struct kvm_mp_state mp_state;
> > +     struct kvm_regs regs;
> > +     struct kvm_vcpu *vcpu;
> > +
> >       vcpu = __vm_vcpu_add(vm, vcpu_id);
> >       vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
> >       vcpu_init_sregs(vm, vcpu);
> > @@ -721,7 +727,8 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> >       /* Setup guest general purpose registers */
> >       vcpu_regs_get(vcpu, &regs);
> >       regs.rflags = regs.rflags | 0x2;
> > -     regs.rsp = stack_vaddr;
> > +     if (vm->type != KVM_X86_TDX_VM)
> > +             regs.rsp = kvm_allocate_vcpu_stack(vm);
>
> At this point in the series vm->type can't be KVM_X86_TDX_VM correct?
>
> So that makes this safe during bisect?
>

I double checked and no one is creating VMs with KVM_X86_TDX_VM. The
first test that sets KVM_X86_TDX_VM is the last patch in the series.

> Ira
>
> >       vcpu_regs_set(vcpu, &regs);
> >
> >       /* Setup the MP state */
> > --
> > 2.51.0.rc1.193.gad69d77794-goog
> >
>
>

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
  2025-08-21 22:05   ` Ira Weiny
@ 2025-08-21 22:30     ` Sagi Shahar
  0 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-21 22:30 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Chao Gao, Chenyi Qiang,
	linux-kernel, kvm, Adrian Hunter

On Thu, Aug 21, 2025 at 5:03 PM Ira Weiny <ira.weiny@intel.com> wrote:
>
> Sagi Shahar wrote:
> > From: Isaku Yamahata <isaku.yamahata@intel.com>
> >
> > Let kvm_init_vm_address_properties() initialize vm->arch.{s_bit, tag_mask}
> > similar to SEV.
> >
> > TDX sets the shared bit based on the guest physical address width and
> > currently supports 48 and 52 widths.
> >
> > Co-developed-by: Adrian Hunter <adrian.hunter@intel.com>
> > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> > Co-developed-by: Sagi Shahar <sagis@google.com>
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >  .../selftests/kvm/include/x86/tdx/tdx_util.h       | 14 ++++++++++++++
> >  tools/testing/selftests/kvm/lib/x86/processor.c    | 12 ++++++++++--
> >  2 files changed, 24 insertions(+), 2 deletions(-)
> >  create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> >
> > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > new file mode 100644
> > index 000000000000..286d5e3c24b1
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > @@ -0,0 +1,14 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +#ifndef SELFTESTS_TDX_TDX_UTIL_H
> > +#define SELFTESTS_TDX_TDX_UTIL_H
> > +
> > +#include <stdbool.h>
> > +
> > +#include "kvm_util.h"
> > +
> > +static inline bool is_tdx_vm(struct kvm_vm *vm)
> > +{
> > +     return vm->type == KVM_X86_TDX_VM;
> > +}
>
> NIT: Might have been better to define this in 4/19 and use it there.  But
> looks like that logic is changed later on somewhere.  So...  meh.

We can skip the check for KVM_X86_TDX_VM entirely in 4/19 since like
you said, it's replaced with something different later on.

>
> Ira
>
> [snip]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region
  2025-08-21  4:29 ` [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region Sagi Shahar
@ 2025-08-25  5:32   ` Yan Zhao
  2025-08-26 16:38     ` Sean Christopherson
  0 siblings, 1 reply; 62+ messages in thread
From: Yan Zhao @ 2025-08-25  5:32 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Wed, Aug 20, 2025 at 09:29:03PM -0700, Sagi Shahar wrote:
> Add memory for TDX boot code in a separate memslot.
> 
> Use virt_map() to get identity map in this memory region to allow for
> seamless transition from paging disabled to paging enabled code.
> 
> Copy the boot code into the memory region and set up the reset vectors
> at this point. While it's possible to separate the memory allocation and
> boot code initialization into separate functions, having all the
> calculations for memory size and offsets in one place simplifies the
> code and avoids duplications.
> 
> Handcode the reset vector as suggested by Sean Christopherson.
> 
> Suggested-by: Sean Christopherson <seanjc@google.com>
> Co-developed-by: Erdem Aktas <erdemaktas@google.com>
> Signed-off-by: Erdem Aktas <erdemaktas@google.com>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>  tools/testing/selftests/kvm/Makefile.kvm      |  1 +
>  .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
>  .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 54 +++++++++++++++++++
>  3 files changed, 57 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> 
> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> index 03754ce2e983..c42b579fb7c5 100644
> --- a/tools/testing/selftests/kvm/Makefile.kvm
> +++ b/tools/testing/selftests/kvm/Makefile.kvm
> @@ -31,6 +31,7 @@ LIBKVM_x86 += lib/x86/sev.c
>  LIBKVM_x86 += lib/x86/svm.c
>  LIBKVM_x86 += lib/x86/ucall.c
>  LIBKVM_x86 += lib/x86/vmx.c
> +LIBKVM_x86 += lib/x86/tdx/tdx_util.c
>  LIBKVM_x86 += lib/x86/tdx/td_boot.S
>  
>  LIBKVM_arm64 += lib/arm64/gic.c
> diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> index 286d5e3c24b1..ec05bcd59145 100644
> --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> @@ -11,4 +11,6 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
>  	return vm->type == KVM_X86_TDX_VM;
>  }
>  
> +void vm_tdx_setup_boot_code_region(struct kvm_vm *vm);
> +
>  #endif // SELFTESTS_TDX_TDX_UTIL_H
> diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> new file mode 100644
> index 000000000000..15833b9eb5d5
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> @@ -0,0 +1,54 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <stdint.h>
> +
> +#include "kvm_util.h"
> +#include "processor.h"
> +#include "tdx/td_boot.h"
> +#include "tdx/tdx_util.h"
> +
> +/* Arbitrarily selected to avoid overlaps with anything else */
> +#define TD_BOOT_CODE_SLOT	20
> +
> +#define X86_RESET_VECTOR	0xfffffff0ul
> +#define X86_RESET_VECTOR_SIZE	16
> +
> +void vm_tdx_setup_boot_code_region(struct kvm_vm *vm)
> +{
> +	size_t total_code_size = TD_BOOT_CODE_SIZE + X86_RESET_VECTOR_SIZE;
> +	vm_paddr_t boot_code_gpa = X86_RESET_VECTOR - TD_BOOT_CODE_SIZE;
> +	vm_paddr_t alloc_gpa = round_down(boot_code_gpa, PAGE_SIZE);
> +	size_t nr_pages = DIV_ROUND_UP(total_code_size, PAGE_SIZE);
> +	vm_paddr_t gpa;
> +	uint8_t *hva;
> +
> +	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
> +				    alloc_gpa,
> +				    TD_BOOT_CODE_SLOT, nr_pages,
> +				    KVM_MEM_GUEST_MEMFD);
> +
> +	gpa = vm_phy_pages_alloc(vm, nr_pages, alloc_gpa, TD_BOOT_CODE_SLOT);
> +	TEST_ASSERT(gpa == alloc_gpa, "Failed vm_phy_pages_alloc\n");
> +
> +	virt_map(vm, alloc_gpa, alloc_gpa, nr_pages);
> +	hva = addr_gpa2hva(vm, boot_code_gpa);
> +	memcpy(hva, td_boot, TD_BOOT_CODE_SIZE);
> +
> +	hva += TD_BOOT_CODE_SIZE;
> +	TEST_ASSERT(hva == addr_gpa2hva(vm, X86_RESET_VECTOR),
> +		    "Expected RESET vector at hva 0x%lx, got %lx",
> +		    (unsigned long)addr_gpa2hva(vm, X86_RESET_VECTOR), (unsigned long)hva);
> +
> +	/*
> +	 * Handcode "JMP rel8" at the RESET vector to jump back to the TD boot
> +	 * code, as there are only 16 bytes at the RESET vector before RIP will
> +	 * wrap back to zero.  Insert a trailing int3 so that the vCPU crashes
> +	 * in case the JMP somehow falls through.  Note!  The target address is
> +	 * relative to the end of the instruction!
> +	 */
> +	TEST_ASSERT(TD_BOOT_CODE_SIZE < 256,
Looks TD_BOOT_CODE_SIZE needs to be <= 126, as the jump range is limited to -128
to +127 for JMP rel8.

> +		    "TD boot code not addressable by 'JMP rel8'");
> +	hva[0] = 0xeb;
> +	hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;
> +	hva[2] = 0xcc;
> +}
> -- 
> 2.51.0.rc1.193.gad69d77794-goog
> 
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM
  2025-08-21  4:29 ` [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM Sagi Shahar
@ 2025-08-25  8:40   ` Yan Zhao
  2025-08-25 19:02     ` Sagi Shahar
  0 siblings, 1 reply; 62+ messages in thread
From: Yan Zhao @ 2025-08-25  8:40 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Wed, Aug 20, 2025 at 09:29:07PM -0700, Sagi Shahar wrote:
> From: Ackerley Tng <ackerleytng@google.com>
> 
> TDX protected memory needs to be measured and encrypted before it can be
> used by the guest. Traverse the VM's memory regions and initialize all
> the protected ranges by calling KVM_TDX_INIT_MEM_REGION.
> 
> Once all the memory is initialized, the VM can be finalized by calling
> KVM_TDX_FINALIZE_VM.
> 
> Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> Co-developed-by: Erdem Aktas <erdemaktas@google.com>
> Signed-off-by: Erdem Aktas <erdemaktas@google.com>
> Co-developed-by: Sagi Shahar <sagis@google.com>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>  .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
>  .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 97 +++++++++++++++++++
>  2 files changed, 99 insertions(+)
> 
> diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> index a2509959c7ce..2467b6c35557 100644
> --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> @@ -71,4 +71,6 @@ void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
>  void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
>  void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
>  
> +void vm_tdx_finalize(struct kvm_vm *vm);
> +
>  #endif // SELFTESTS_TDX_TDX_UTIL_H
> diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> index d8eab99d9333..4024587ed3c2 100644
> --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> @@ -274,3 +274,100 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
>  
>  	free(init_vm);
>  }
> +
> +static void tdx_init_mem_region(struct kvm_vm *vm, void *source_pages,
> +				uint64_t gpa, uint64_t size)
> +{
> +	uint32_t metadata = KVM_TDX_MEASURE_MEMORY_REGION;
> +	struct kvm_tdx_init_mem_region mem_region = {
> +		.source_addr = (uint64_t)source_pages,
> +		.gpa = gpa,
> +		.nr_pages = size / PAGE_SIZE,
> +	};
> +	struct kvm_vcpu *vcpu;
> +
> +	vcpu = list_first_entry_or_null(&vm->vcpus, struct kvm_vcpu, list);
> +
> +	TEST_ASSERT((mem_region.nr_pages > 0) &&
> +		    ((mem_region.nr_pages * PAGE_SIZE) == size),
> +		    "Cannot add partial pages to the guest memory.\n");
> +	TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) == 0,
> +		    "Source memory buffer is not page aligned\n");
> +	vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region);
> +}
> +
> +static void tdx_init_pages(struct kvm_vm *vm, void *hva, uint64_t gpa,
> +			   uint64_t size)
> +{
> +	void *scratch_page = calloc(1, PAGE_SIZE);
> +	uint64_t nr_pages = size / PAGE_SIZE;
> +	int i;
> +
> +	TEST_ASSERT(scratch_page,
> +		    "Could not allocate memory for loading memory region");
> +
> +	for (i = 0; i < nr_pages; i++) {
> +		memcpy(scratch_page, hva, PAGE_SIZE);
> +
> +		tdx_init_mem_region(vm, scratch_page, gpa, PAGE_SIZE);
> +
> +		hva += PAGE_SIZE;
> +		gpa += PAGE_SIZE;
> +	}
> +
> +	free(scratch_page);
> +}
> +
> +static void load_td_private_memory(struct kvm_vm *vm)
> +{
> +	struct userspace_mem_region *region;
> +	int ctr;
> +
> +	hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
> +		const struct sparsebit *protected_pages = region->protected_phy_pages;
> +		const vm_paddr_t gpa_base = region->region.guest_phys_addr;
> +		const uint64_t hva_base = region->region.userspace_addr;
> +		const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
> +
> +		sparsebit_idx_t i;
> +		sparsebit_idx_t j;
> +
> +		if (!sparsebit_any_set(protected_pages))
> +			continue;
> +
> +		sparsebit_for_each_set_range(protected_pages, i, j) {
> +			const uint64_t size_to_load = (j - i + 1) * vm->page_size;
> +			const uint64_t offset =
> +				(i - lowest_page_in_region) * vm->page_size;
> +			const uint64_t hva = hva_base + offset;
> +			const uint64_t gpa = gpa_base + offset;
> +
> +			vm_set_memory_attributes(vm, gpa, size_to_load,
> +						 KVM_MEMORY_ATTRIBUTE_PRIVATE);
> +
> +			/*
> +			 * Here, memory is being loaded from hva to gpa. If the memory
> +			 * mapped to hva is also used to back gpa, then a copy has to be
> +			 * made just for loading, since KVM_TDX_INIT_MEM_REGION ioctl
> +			 * cannot encrypt memory in place.
> +			 *
> +			 * To determine if memory mapped to hva is also used to back
> +			 * gpa, use a heuristic:
> +			 *
> +			 * If this memslot has guest_memfd, then this memslot should
> +			 * have memory backed from two sources: hva for shared memory
> +			 * and gpa will be backed by guest_memfd.
> +			 */
> +			if (region->region.guest_memfd == -1)
Why to pass !guest_memfd region to tdx_init_mem_region()? 


> +				tdx_init_pages(vm, (void *)hva, gpa, size_to_load);
> +			else
> +				tdx_init_mem_region(vm, (void *)hva, gpa, size_to_load);
> +		}
> +	}
> +}
> +
> +void vm_tdx_finalize(struct kvm_vm *vm)
> +{
> +	load_td_private_memory(vm);
> +	vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
> +}
> -- 
> 2.51.0.rc1.193.gad69d77794-goog
> 
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM
  2025-08-25  8:40   ` Yan Zhao
@ 2025-08-25 19:02     ` Sagi Shahar
  2025-08-26  1:07       ` Yan Zhao
  0 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-25 19:02 UTC (permalink / raw)
  To: Yan Zhao
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Mon, Aug 25, 2025 at 3:41 AM Yan Zhao <yan.y.zhao@intel.com> wrote:
>
> On Wed, Aug 20, 2025 at 09:29:07PM -0700, Sagi Shahar wrote:
> > From: Ackerley Tng <ackerleytng@google.com>
> >
> > TDX protected memory needs to be measured and encrypted before it can be
> > used by the guest. Traverse the VM's memory regions and initialize all
> > the protected ranges by calling KVM_TDX_INIT_MEM_REGION.
> >
> > Once all the memory is initialized, the VM can be finalized by calling
> > KVM_TDX_FINALIZE_VM.
> >
> > Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> > Co-developed-by: Erdem Aktas <erdemaktas@google.com>
> > Signed-off-by: Erdem Aktas <erdemaktas@google.com>
> > Co-developed-by: Sagi Shahar <sagis@google.com>
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >  .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
> >  .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 97 +++++++++++++++++++
> >  2 files changed, 99 insertions(+)
> >
> > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > index a2509959c7ce..2467b6c35557 100644
> > --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > @@ -71,4 +71,6 @@ void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
> >  void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
> >  void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
> >
> > +void vm_tdx_finalize(struct kvm_vm *vm);
> > +
> >  #endif // SELFTESTS_TDX_TDX_UTIL_H
> > diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > index d8eab99d9333..4024587ed3c2 100644
> > --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > @@ -274,3 +274,100 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
> >
> >       free(init_vm);
> >  }
> > +
> > +static void tdx_init_mem_region(struct kvm_vm *vm, void *source_pages,
> > +                             uint64_t gpa, uint64_t size)
> > +{
> > +     uint32_t metadata = KVM_TDX_MEASURE_MEMORY_REGION;
> > +     struct kvm_tdx_init_mem_region mem_region = {
> > +             .source_addr = (uint64_t)source_pages,
> > +             .gpa = gpa,
> > +             .nr_pages = size / PAGE_SIZE,
> > +     };
> > +     struct kvm_vcpu *vcpu;
> > +
> > +     vcpu = list_first_entry_or_null(&vm->vcpus, struct kvm_vcpu, list);
> > +
> > +     TEST_ASSERT((mem_region.nr_pages > 0) &&
> > +                 ((mem_region.nr_pages * PAGE_SIZE) == size),
> > +                 "Cannot add partial pages to the guest memory.\n");
> > +     TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) == 0,
> > +                 "Source memory buffer is not page aligned\n");
> > +     vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region);
> > +}
> > +
> > +static void tdx_init_pages(struct kvm_vm *vm, void *hva, uint64_t gpa,
> > +                        uint64_t size)
> > +{
> > +     void *scratch_page = calloc(1, PAGE_SIZE);
> > +     uint64_t nr_pages = size / PAGE_SIZE;
> > +     int i;
> > +
> > +     TEST_ASSERT(scratch_page,
> > +                 "Could not allocate memory for loading memory region");
> > +
> > +     for (i = 0; i < nr_pages; i++) {
> > +             memcpy(scratch_page, hva, PAGE_SIZE);
> > +
> > +             tdx_init_mem_region(vm, scratch_page, gpa, PAGE_SIZE);
> > +
> > +             hva += PAGE_SIZE;
> > +             gpa += PAGE_SIZE;
> > +     }
> > +
> > +     free(scratch_page);
> > +}
> > +
> > +static void load_td_private_memory(struct kvm_vm *vm)
> > +{
> > +     struct userspace_mem_region *region;
> > +     int ctr;
> > +
> > +     hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
> > +             const struct sparsebit *protected_pages = region->protected_phy_pages;
> > +             const vm_paddr_t gpa_base = region->region.guest_phys_addr;
> > +             const uint64_t hva_base = region->region.userspace_addr;
> > +             const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
> > +
> > +             sparsebit_idx_t i;
> > +             sparsebit_idx_t j;
> > +
> > +             if (!sparsebit_any_set(protected_pages))
> > +                     continue;
> > +
> > +             sparsebit_for_each_set_range(protected_pages, i, j) {
> > +                     const uint64_t size_to_load = (j - i + 1) * vm->page_size;
> > +                     const uint64_t offset =
> > +                             (i - lowest_page_in_region) * vm->page_size;
> > +                     const uint64_t hva = hva_base + offset;
> > +                     const uint64_t gpa = gpa_base + offset;
> > +
> > +                     vm_set_memory_attributes(vm, gpa, size_to_load,
> > +                                              KVM_MEMORY_ATTRIBUTE_PRIVATE);
> > +
> > +                     /*
> > +                      * Here, memory is being loaded from hva to gpa. If the memory
> > +                      * mapped to hva is also used to back gpa, then a copy has to be
> > +                      * made just for loading, since KVM_TDX_INIT_MEM_REGION ioctl
> > +                      * cannot encrypt memory in place.
> > +                      *
> > +                      * To determine if memory mapped to hva is also used to back
> > +                      * gpa, use a heuristic:
> > +                      *
> > +                      * If this memslot has guest_memfd, then this memslot should
> > +                      * have memory backed from two sources: hva for shared memory
> > +                      * and gpa will be backed by guest_memfd.
> > +                      */
> > +                     if (region->region.guest_memfd == -1)
> Why to pass !guest_memfd region to tdx_init_mem_region()?
>

Not sure I understand your comment.

>
> > +                             tdx_init_pages(vm, (void *)hva, gpa, size_to_load);
> > +                     else
> > +                             tdx_init_mem_region(vm, (void *)hva, gpa, size_to_load);
> > +             }
> > +     }
> > +}
> > +
> > +void vm_tdx_finalize(struct kvm_vm *vm)
> > +{
> > +     load_td_private_memory(vm);
> > +     vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
> > +}
> > --
> > 2.51.0.rc1.193.gad69d77794-goog
> >
> >

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM
  2025-08-25 19:02     ` Sagi Shahar
@ 2025-08-26  1:07       ` Yan Zhao
  2025-08-27  2:24         ` Binbin Wu
  0 siblings, 1 reply; 62+ messages in thread
From: Yan Zhao @ 2025-08-26  1:07 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Mon, Aug 25, 2025 at 02:02:00PM -0500, Sagi Shahar wrote:
> On Mon, Aug 25, 2025 at 3:41 AM Yan Zhao <yan.y.zhao@intel.com> wrote:
> >
> > On Wed, Aug 20, 2025 at 09:29:07PM -0700, Sagi Shahar wrote:
> > > From: Ackerley Tng <ackerleytng@google.com>
> > >
> > > TDX protected memory needs to be measured and encrypted before it can be
> > > used by the guest. Traverse the VM's memory regions and initialize all
> > > the protected ranges by calling KVM_TDX_INIT_MEM_REGION.
> > >
> > > Once all the memory is initialized, the VM can be finalized by calling
> > > KVM_TDX_FINALIZE_VM.
> > >
> > > Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> > > Co-developed-by: Erdem Aktas <erdemaktas@google.com>
> > > Signed-off-by: Erdem Aktas <erdemaktas@google.com>
> > > Co-developed-by: Sagi Shahar <sagis@google.com>
> > > Signed-off-by: Sagi Shahar <sagis@google.com>
> > > ---
> > >  .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
> > >  .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 97 +++++++++++++++++++
> > >  2 files changed, 99 insertions(+)
> > >
> > > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > index a2509959c7ce..2467b6c35557 100644
> > > --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > @@ -71,4 +71,6 @@ void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
> > >  void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
> > >  void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
> > >
> > > +void vm_tdx_finalize(struct kvm_vm *vm);
> > > +
> > >  #endif // SELFTESTS_TDX_TDX_UTIL_H
> > > diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > index d8eab99d9333..4024587ed3c2 100644
> > > --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > @@ -274,3 +274,100 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
> > >
> > >       free(init_vm);
> > >  }
> > > +
> > > +static void tdx_init_mem_region(struct kvm_vm *vm, void *source_pages,
> > > +                             uint64_t gpa, uint64_t size)
> > > +{
> > > +     uint32_t metadata = KVM_TDX_MEASURE_MEMORY_REGION;
> > > +     struct kvm_tdx_init_mem_region mem_region = {
> > > +             .source_addr = (uint64_t)source_pages,
> > > +             .gpa = gpa,
> > > +             .nr_pages = size / PAGE_SIZE,
> > > +     };
> > > +     struct kvm_vcpu *vcpu;
> > > +
> > > +     vcpu = list_first_entry_or_null(&vm->vcpus, struct kvm_vcpu, list);
> > > +
> > > +     TEST_ASSERT((mem_region.nr_pages > 0) &&
> > > +                 ((mem_region.nr_pages * PAGE_SIZE) == size),
> > > +                 "Cannot add partial pages to the guest memory.\n");
> > > +     TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) == 0,
> > > +                 "Source memory buffer is not page aligned\n");
> > > +     vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region);
> > > +}
> > > +
> > > +static void tdx_init_pages(struct kvm_vm *vm, void *hva, uint64_t gpa,
> > > +                        uint64_t size)
> > > +{
> > > +     void *scratch_page = calloc(1, PAGE_SIZE);
> > > +     uint64_t nr_pages = size / PAGE_SIZE;
> > > +     int i;
> > > +
> > > +     TEST_ASSERT(scratch_page,
> > > +                 "Could not allocate memory for loading memory region");
> > > +
> > > +     for (i = 0; i < nr_pages; i++) {
> > > +             memcpy(scratch_page, hva, PAGE_SIZE);
> > > +
> > > +             tdx_init_mem_region(vm, scratch_page, gpa, PAGE_SIZE);
> > > +
> > > +             hva += PAGE_SIZE;
> > > +             gpa += PAGE_SIZE;
> > > +     }
> > > +
> > > +     free(scratch_page);
> > > +}
> > > +
> > > +static void load_td_private_memory(struct kvm_vm *vm)
> > > +{
> > > +     struct userspace_mem_region *region;
> > > +     int ctr;
> > > +
> > > +     hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
> > > +             const struct sparsebit *protected_pages = region->protected_phy_pages;
> > > +             const vm_paddr_t gpa_base = region->region.guest_phys_addr;
> > > +             const uint64_t hva_base = region->region.userspace_addr;
> > > +             const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
> > > +
> > > +             sparsebit_idx_t i;
> > > +             sparsebit_idx_t j;
> > > +
> > > +             if (!sparsebit_any_set(protected_pages))
> > > +                     continue;
> > > +
> > > +             sparsebit_for_each_set_range(protected_pages, i, j) {
> > > +                     const uint64_t size_to_load = (j - i + 1) * vm->page_size;
> > > +                     const uint64_t offset =
> > > +                             (i - lowest_page_in_region) * vm->page_size;
> > > +                     const uint64_t hva = hva_base + offset;
> > > +                     const uint64_t gpa = gpa_base + offset;
> > > +
> > > +                     vm_set_memory_attributes(vm, gpa, size_to_load,
> > > +                                              KVM_MEMORY_ATTRIBUTE_PRIVATE);
> > > +
> > > +                     /*
> > > +                      * Here, memory is being loaded from hva to gpa. If the memory
> > > +                      * mapped to hva is also used to back gpa, then a copy has to be
> > > +                      * made just for loading, since KVM_TDX_INIT_MEM_REGION ioctl
> > > +                      * cannot encrypt memory in place.
> > > +                      *
> > > +                      * To determine if memory mapped to hva is also used to back
> > > +                      * gpa, use a heuristic:
> > > +                      *
> > > +                      * If this memslot has guest_memfd, then this memslot should
> > > +                      * have memory backed from two sources: hva for shared memory
> > > +                      * and gpa will be backed by guest_memfd.
> > > +                      */
> > > +                     if (region->region.guest_memfd == -1)
> > Why to pass !guest_memfd region to tdx_init_mem_region()?
> >
> 
> Not sure I understand your comment.

From the implementation of tdx_init_pages(), it also invokes
tdx_init_mem_region(), which further invokes ioctl KVM_TDX_INIT_MEM_REGION.

However, if the region is with guest_memfd == -1, the ioctl
KVM_TDX_INIT_MEM_REGION should fail as kvm_gmem_populate() won't succeed.

So, I'm wondering why there's a need to for the case of
"region->region.guest_memfd == -1".

Or anything I missed?

> > > +                             tdx_init_pages(vm, (void *)hva, gpa, size_to_load);
> > > +                     else
> > > +                             tdx_init_mem_region(vm, (void *)hva, gpa, size_to_load);
> > > +             }
> > > +     }
> > > +}
> > > +
> > > +void vm_tdx_finalize(struct kvm_vm *vm)
> > > +{
> > > +     load_td_private_memory(vm);
> > > +     vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
> > > +}
> > > --
> > > 2.51.0.rc1.193.gad69d77794-goog
> > >
> > >

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 03/19] KVM: selftests: Expose functions to get default sregs values
  2025-08-21  4:28 ` [PATCH v9 03/19] KVM: selftests: Expose functions to get default sregs values Sagi Shahar
@ 2025-08-26  2:36   ` Binbin Wu
  2025-08-26 14:05     ` Sean Christopherson
  0 siblings, 1 reply; 62+ messages in thread
From: Binbin Wu @ 2025-08-26  2:36 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> TDX can't set sregs values directly using KVM_SET_SREGS. Expose the
> default values of certain sregs used by TDX VMs so they can be set
> manually.
>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>   .../selftests/kvm/include/x86/processor.h     |  6 +++
>   .../testing/selftests/kvm/lib/x86/processor.c | 41 +++++++++++++++----
>   2 files changed, 40 insertions(+), 7 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
> index 2efb05c2f2fb..5c16507f9b2d 100644
> --- a/tools/testing/selftests/kvm/include/x86/processor.h
> +++ b/tools/testing/selftests/kvm/include/x86/processor.h
> @@ -1026,6 +1026,12 @@ static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries)
>   
>   void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid);
>   
> +uint16_t kvm_get_default_idt_limit(void);
> +uint16_t kvm_get_default_gdt_limit(void);
> +uint64_t kvm_get_default_cr0(void);
> +uint64_t kvm_get_default_cr4(void);
> +uint64_t kvm_get_default_efer(void);
Can these be defined in the header file as static inline?

> +
>   static inline void vcpu_get_cpuid(struct kvm_vcpu *vcpu)
>   {
>   	vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid);
> diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> index d4c19ac885a9..b2a4b11ac8c0 100644
> --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> @@ -488,6 +488,35 @@ static void kvm_seg_set_tss_64bit(vm_vaddr_t base, struct kvm_segment *segp)
>   	segp->present = 1;
>   }
>   
> +uint16_t kvm_get_default_idt_limit(void)
> +{
> +	return NUM_INTERRUPTS * sizeof(struct idt_entry) - 1;
> +}
> +
> +uint16_t kvm_get_default_gdt_limit(void)
> +{
> +	return getpagesize() - 1;
> +}
> +
> +uint64_t kvm_get_default_cr0(void)
> +{
> +	return X86_CR0_PE | X86_CR0_NE | X86_CR0_PG;
> +}
> +
> +uint64_t kvm_get_default_cr4(void)
> +{
> +	uint64_t cr4 = X86_CR4_PAE | X86_CR4_OSFXSR;
> +
> +	if (kvm_cpu_has(X86_FEATURE_XSAVE))
> +		cr4 |= X86_CR4_OSXSAVE;
> +	return cr4;
> +}
> +
> +uint64_t kvm_get_default_efer(void)
> +{
> +	return EFER_LME | EFER_LMA | EFER_NX;
> +}
> +
>   static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
>   {
>   	struct kvm_sregs sregs;
> @@ -498,15 +527,13 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
>   	vcpu_sregs_get(vcpu, &sregs);
>   
>   	sregs.idt.base = vm->arch.idt;
> -	sregs.idt.limit = NUM_INTERRUPTS * sizeof(struct idt_entry) - 1;
> +	sregs.idt.limit = kvm_get_default_idt_limit();
>   	sregs.gdt.base = vm->arch.gdt;
> -	sregs.gdt.limit = getpagesize() - 1;
> +	sregs.gdt.limit = kvm_get_default_gdt_limit();
>   
> -	sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG;
> -	sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR;
> -	if (kvm_cpu_has(X86_FEATURE_XSAVE))
> -		sregs.cr4 |= X86_CR4_OSXSAVE;
> -	sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX);
> +	sregs.cr0 = kvm_get_default_cr0();
> +	sregs.cr4 |= kvm_get_default_cr4();
> +	sregs.efer |= kvm_get_default_efer();
>   
>   	kvm_seg_set_unusable(&sregs.ldt);
>   	kvm_seg_set_kernel_code_64bit(&sregs.cs);


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary
  2025-08-21  4:28 ` [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary Sagi Shahar
  2025-08-21 14:45   ` Ira Weiny
@ 2025-08-26  2:36   ` Binbin Wu
  1 sibling, 0 replies; 62+ messages in thread
From: Binbin Wu @ 2025-08-26  2:36 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> If virt_map() is called before any call to ____vm_vaddr_alloc() it
> will create the mapping using an invalid pgd.
>
> Add call to virt_pgd_alloc() as part of virt_map() before creating the
> mapping, similarly to ____vm_vaddr_alloc()
>
> Signed-off-by: Sagi Shahar <sagis@google.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>

> ---
>   tools/testing/selftests/kvm/lib/kvm_util.c | 1 +
>   1 file changed, 1 insertion(+)
>
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index c3f5142b0a54..b4c8702ba4bd 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -1609,6 +1609,7 @@ void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
>   	TEST_ASSERT(vaddr + size > vaddr, "Vaddr overflow");
>   	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
>   
> +	virt_pgd_alloc(vm);
>   	while (npages--) {
>   		virt_pg_map(vm, vaddr, paddr);
>   		sparsebit_set(vm->vpages_mapped, vaddr >> vm->page_shift);


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack
  2025-08-21  4:28 ` [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack Sagi Shahar
  2025-08-21 22:00   ` Ira Weiny
@ 2025-08-26  5:39   ` Binbin Wu
  2025-08-26 16:00     ` Sagi Shahar
  2025-08-26 17:16     ` Sean Christopherson
  1 sibling, 2 replies; 62+ messages in thread
From: Binbin Wu @ 2025-08-26  5:39 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> TDX guests' registers cannot be initialized directly using
> vcpu_regs_set(), hence the stack pointer needs to be initialized by
> the guest itself, running boot code beginning at the reset vector.
>
> Expose the function to allocate the guest stack so that TDX
> initialization code can allocate it itself and skip the allocation in
> vm_arch_vcpu_add() in that case.
>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>   .../selftests/kvm/include/x86/processor.h       |  2 ++
>   tools/testing/selftests/kvm/lib/x86/processor.c | 17 ++++++++++++-----
>   2 files changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
> index 5c16507f9b2d..8fcc5118683e 100644
> --- a/tools/testing/selftests/kvm/include/x86/processor.h
> +++ b/tools/testing/selftests/kvm/include/x86/processor.h
> @@ -1111,6 +1111,8 @@ static inline void vcpu_clear_cpuid_feature(struct kvm_vcpu *vcpu,
>   	vcpu_set_or_clear_cpuid_feature(vcpu, feature, false);
>   }
>   
> +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm);
> +
>   uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index);
>   int _vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, uint64_t msr_value);
>   
> diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> index b2a4b11ac8c0..1eae92957456 100644
> --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> @@ -687,12 +687,9 @@ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
>   	vcpu_regs_set(vcpu, &regs);
>   }
>   
> -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
>   {
> -	struct kvm_mp_state mp_state;
> -	struct kvm_regs regs;
>   	vm_vaddr_t stack_vaddr;
> -	struct kvm_vcpu *vcpu;
>   
>   	stack_vaddr = __vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(),
>   				       DEFAULT_GUEST_STACK_VADDR_MIN,
> @@ -713,6 +710,15 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
>   		    "__vm_vaddr_alloc() did not provide a page-aligned address");
>   	stack_vaddr -= 8;
>   
> +	return stack_vaddr;
> +}
> +
> +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> +{
> +	struct kvm_mp_state mp_state;
> +	struct kvm_regs regs;
> +	struct kvm_vcpu *vcpu;
> +
>   	vcpu = __vm_vcpu_add(vm, vcpu_id);
>   	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
>   	vcpu_init_sregs(vm, vcpu);
> @@ -721,7 +727,8 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
>   	/* Setup guest general purpose registers */
>   	vcpu_regs_get(vcpu, &regs);
>   	regs.rflags = regs.rflags | 0x2;
> -	regs.rsp = stack_vaddr;
> +	if (vm->type != KVM_X86_TDX_VM)
> +		regs.rsp = kvm_allocate_vcpu_stack(vm);

I am wondering if this could be more generic.
I.e, make vcpu_regs_get() return the error code.
If vcpu_regs_get() failed (for TDX, since it's guest state is protected, the
ioctl will return -EINVAL), the vcpu_regs_set(), including the allocation for
the vcpu stack, could be skipped.

>   	vcpu_regs_set(vcpu, &regs);
>   
>   	/* Setup the MP state */


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
  2025-08-21  4:28 ` [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Sagi Shahar
  2025-08-21 22:05   ` Ira Weiny
@ 2025-08-26  5:51   ` Binbin Wu
  2025-08-26 16:04     ` Sagi Shahar
  1 sibling, 1 reply; 62+ messages in thread
From: Binbin Wu @ 2025-08-26  5:51 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm, Adrian Hunter



On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> From: Isaku Yamahata <isaku.yamahata@intel.com>
>
> Let kvm_init_vm_address_properties() initialize vm->arch.{s_bit, tag_mask}
> similar to SEV.
>
> TDX sets the shared bit based on the guest physical address width and
> currently supports 48 and 52 widths.
>
> Co-developed-by: Adrian Hunter <adrian.hunter@intel.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> Co-developed-by: Sagi Shahar <sagis@google.com>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>   .../selftests/kvm/include/x86/tdx/tdx_util.h       | 14 ++++++++++++++
>   tools/testing/selftests/kvm/lib/x86/processor.c    | 12 ++++++++++--
>   2 files changed, 24 insertions(+), 2 deletions(-)
>   create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
>
> diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> new file mode 100644
> index 000000000000..286d5e3c24b1
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef SELFTESTS_TDX_TDX_UTIL_H
> +#define SELFTESTS_TDX_TDX_UTIL_H
> +
> +#include <stdbool.h>
> +
> +#include "kvm_util.h"
> +
> +static inline bool is_tdx_vm(struct kvm_vm *vm)
> +{
> +	return vm->type == KVM_X86_TDX_VM;
> +}

If the branch "vm->type != KVM_X86_TDX_VM" in patch 04/19
is still needed, this helper could be added earlier and used instead of
open code.

> +
> +#endif // SELFTESTS_TDX_TDX_UTIL_H
> diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> index 1eae92957456..6dbf40cbbc2a 100644
> --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> @@ -8,6 +8,7 @@
>   #include "kvm_util.h"
>   #include "processor.h"
>   #include "sev.h"
> +#include "tdx/tdx_util.h"
>   
>   #ifndef NUM_INTERRUPTS
>   #define NUM_INTERRUPTS 256
> @@ -1190,12 +1191,19 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
>   
>   void kvm_init_vm_address_properties(struct kvm_vm *vm)
>   {
> +	uint32_t gpa_bits = kvm_cpu_property(X86_PROPERTY_GUEST_MAX_PHY_ADDR);
> +
> +	vm->arch.sev_fd = -1;
> +
>   	if (is_sev_vm(vm)) {
>   		vm->arch.sev_fd = open_sev_dev_path_or_exit();
>   		vm->arch.c_bit = BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT));
>   		vm->gpa_tag_mask = vm->arch.c_bit;
> -	} else {
> -		vm->arch.sev_fd = -1;
> +	} else if (is_tdx_vm(vm)) {
> +		TEST_ASSERT(gpa_bits == 48 || gpa_bits == 52,
> +			    "TDX: bad X86_PROPERTY_GUEST_MAX_PHY_ADDR value: %u", gpa_bits);
> +		vm->arch.s_bit = 1ULL << (gpa_bits - 1);

Nit: Use BIT_ULL().

> +		vm->gpa_tag_mask = vm->arch.s_bit;
>   	}
>   }
>   


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 08/19] KVM: selftests: Define structs to pass parameters to TDX boot code
  2025-08-21  4:29 ` [PATCH v9 08/19] KVM: selftests: Define structs to pass parameters to TDX boot code Sagi Shahar
@ 2025-08-26  6:52   ` Binbin Wu
  2025-08-26 16:10     ` Sagi Shahar
  0 siblings, 1 reply; 62+ messages in thread
From: Binbin Wu @ 2025-08-26  6:52 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 8/21/2025 12:29 PM, Sagi Shahar wrote:
[...]
> +
> +/*
> + * Allows each vCPU to be initialized with different eip and esp.
> + *
> + * __packed is used since the offsets are hardcoded in td_boot.S
> + *
> + * TODO: Replace hardcoded offsets with OFFSET(). This requires getting the
> + * neccesry Kbuild scripts working in KVM selftests.
neccesry -> necessary

Also, are the comments about "__packed" and "TODO" out dated?

> + */
> +struct td_per_vcpu_parameters {
> +	uint32_t esp_gva;
> +	uint64_t guest_code;
> +};
> +
> +/*
> + * Boot parameters for the TD.
> + *
> + * Unlike a regular VM, KVM cannot set registers such as esp, eip, etc
> + * before boot, so to run selftests, these registers' values have to be
> + * initialized by the TD.
> + *
> + * This struct is loaded in TD private memory at TD_BOOT_PARAMETERS_GPA.
> + *
> + * The TD boot code will read off parameters from this struct and set up the
> + * vCPU for executing selftests.
> + *
> + * __packed is used since the offsets are hardcoded in td_boot.S
Same as above for "__packed".

> + */
>
[...]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-21  4:29 ` [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation Sagi Shahar
@ 2025-08-26  8:28   ` Chenyi Qiang
  2025-08-26 16:12     ` Sagi Shahar
  2025-08-26 17:31   ` Sean Christopherson
  1 sibling, 1 reply; 62+ messages in thread
From: Chenyi Qiang @ 2025-08-26  8:28 UTC (permalink / raw)
  To: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Sean Christopherson, Ackerley Tng, Ryan Afranji, Andrew Jones,
	Isaku Yamahata, Erdem Aktas, Rick Edgecombe, Roger Wang,
	Binbin Wu, Oliver Upton, Pratik R. Sampat, Reinette Chatre,
	Ira Weiny, Chao Gao
  Cc: linux-kernel, kvm



On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> TDX require special handling for VM and VCPU initialization for various

s/require/requires

> reasons:
> - Special ioctlss for creating VM and VCPU.

s/ioctlss/ioctls

> - TDX registers are inaccessible to KVM.
> - TDX require special boot code trampoline for loading parameters.

s/require/requires

> - TDX only supports KVM_CAP_SPLIT_IRQCHIP.
> 
> Hook this special handling into __vm_create() and vm_arch_vcpu_add()
> using the utility functions added in previous patches.
> 
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>  tools/testing/selftests/kvm/lib/kvm_util.c    | 24 ++++++++-
>  .../testing/selftests/kvm/lib/x86/processor.c | 49 ++++++++++++++-----
>  2 files changed, 61 insertions(+), 12 deletions(-)
> 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 11/19] KVM: selftests: Set up TDX boot parameters region
  2025-08-21  4:29 ` [PATCH v9 11/19] KVM: selftests: Set up TDX boot parameters region Sagi Shahar
@ 2025-08-26  8:36   ` Binbin Wu
  2025-08-26 16:17     ` Sagi Shahar
  0 siblings, 1 reply; 62+ messages in thread
From: Binbin Wu @ 2025-08-26  8:36 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> Allocate memory for TDX boot parameters and define the utility functions
> necessary to fill this memory with the boot parameters.
>
> Co-developed-by: Ackerley Tng <ackerleytng@google.com>
> Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>   .../selftests/kvm/include/x86/tdx/tdx_util.h  |  4 +
>   .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 73 +++++++++++++++++++
>   2 files changed, 77 insertions(+)
>
> diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> index ec05bcd59145..dafdc7e46abe 100644
> --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> @@ -12,5 +12,9 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
>   }
>   
>   void vm_tdx_setup_boot_code_region(struct kvm_vm *vm);
> +void vm_tdx_setup_boot_parameters_region(struct kvm_vm *vm, uint32_t nr_runnable_vcpus);
> +void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
> +void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
> +void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
>   
>   #endif // SELFTESTS_TDX_TDX_UTIL_H
> diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> index 15833b9eb5d5..52dc25e0cce4 100644
> --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> @@ -5,10 +5,12 @@
>   #include "kvm_util.h"
>   #include "processor.h"
>   #include "tdx/td_boot.h"
> +#include "tdx/td_boot_asm.h"
>   #include "tdx/tdx_util.h"
>   
>   /* Arbitrarily selected to avoid overlaps with anything else */
>   #define TD_BOOT_CODE_SLOT	20
> +#define TD_BOOT_PARAMETERS_SLOT	21
>   
>   #define X86_RESET_VECTOR	0xfffffff0ul
>   #define X86_RESET_VECTOR_SIZE	16
> @@ -52,3 +54,74 @@ void vm_tdx_setup_boot_code_region(struct kvm_vm *vm)
>   	hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;
>   	hva[2] = 0xcc;
>   }
> +
> +void vm_tdx_setup_boot_parameters_region(struct kvm_vm *vm, uint32_t nr_runnable_vcpus)
> +{
> +	size_t boot_params_size =
> +		sizeof(struct td_boot_parameters) +
> +		nr_runnable_vcpus * sizeof(struct td_per_vcpu_parameters);
> +	int npages = DIV_ROUND_UP(boot_params_size, PAGE_SIZE);
> +	vm_paddr_t gpa;
> +
> +	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
> +				    TD_BOOT_PARAMETERS_GPA,
> +				    TD_BOOT_PARAMETERS_SLOT, npages,
> +				    KVM_MEM_GUEST_MEMFD);
> +	gpa = vm_phy_pages_alloc(vm, npages, TD_BOOT_PARAMETERS_GPA, TD_BOOT_PARAMETERS_SLOT);
> +	TEST_ASSERT(gpa == TD_BOOT_PARAMETERS_GPA, "Failed vm_phy_pages_alloc\n");
> +
> +	virt_map(vm, TD_BOOT_PARAMETERS_GPA, TD_BOOT_PARAMETERS_GPA, npages);
> +}
> +
> +void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm)
> +{
> +	struct td_boot_parameters *params =
> +		addr_gpa2hva(vm, TD_BOOT_PARAMETERS_GPA);
> +	uint32_t cr4;
> +
> +	TEST_ASSERT_EQ(vm->mode, VM_MODE_PXXV48_4K);
> +
> +	cr4 = kvm_get_default_cr4();
> +
> +	/* TDX spec 11.6.2: CR4 bit MCE is fixed to 1 */
> +	cr4 |= X86_CR4_MCE;
> +
> +	/* Set this because UEFI also sets this up, to handle XMM exceptions */
> +	cr4 |= X86_CR4_OSXMMEXCPT;
> +
> +	/* TDX spec 11.6.2: CR4 bit VMXE and SMXE are fixed to 0 */
> +	cr4 &= ~(X86_CR4_VMXE | X86_CR4_SMXE);
> +
> +	/* Set parameters! */
> +	params->cr0 = kvm_get_default_cr0();
> +	params->cr3 = vm->pgd;
> +	params->cr4 = cr4;
> +	params->idtr.base = vm->arch.idt;
> +	params->idtr.limit = kvm_get_default_idt_limit();
> +	params->gdtr.base = vm->arch.gdt;
> +	params->gdtr.limit = kvm_get_default_gdt_limit();
> +
> +	TEST_ASSERT(params->cr0 != 0, "cr0 should not be 0");
> +	TEST_ASSERT(params->cr3 != 0, "cr3 should not be 0");
> +	TEST_ASSERT(params->cr4 != 0, "cr4 should not be 0");
> +	TEST_ASSERT(params->gdtr.base != 0, "gdt base address should not be 0");
> +	TEST_ASSERT(params->idtr.base != 0, "idt base address should not be 0");
> +}
> +
> +void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
> +{
> +	struct td_boot_parameters *params =
> +		addr_gpa2hva(vm, TD_BOOT_PARAMETERS_GPA);
> +	struct td_per_vcpu_parameters *vcpu_params =
> +		&params->per_vcpu[vcpu->id];

Nit: Better to align the style on whether wrap or not due to max characters per
line

> +
> +	vcpu_params->esp_gva = kvm_allocate_vcpu_stack(vm);
> +}
> +
> +void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
> +{
> +	struct td_boot_parameters *params = addr_gpa2hva(vcpu->vm, TD_BOOT_PARAMETERS_GPA);
> +	struct td_per_vcpu_parameters *vcpu_params = &params->per_vcpu[vcpu->id];
> +
> +	vcpu_params->guest_code = (uint64_t)guest_code;
> +}


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 13/19] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration
  2025-08-21  4:29 ` [PATCH v9 13/19] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration Sagi Shahar
@ 2025-08-26  9:22   ` Binbin Wu
  0 siblings, 0 replies; 62+ messages in thread
From: Binbin Wu @ 2025-08-26  9:22 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> From: Isaku Yamahata <isaku.yamahata@intel.com>
>
> This also exercises the KVM_TDX_CAPABILITIES ioctl.

That commit message should describe what the patch does instead of relying on
the title/short log.

>
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> Co-developed-by: Sagi Shahar <sagis@google.com>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>   .../selftests/kvm/lib/x86/tdx/tdx_util.c        | 17 +++++++++++++++++
>   1 file changed, 17 insertions(+)
>
> diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> index 3869756a5641..d8eab99d9333 100644
> --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> @@ -232,6 +232,21 @@ static void vm_tdx_filter_cpuid(struct kvm_vm *vm,
>   	free(tdx_cap);
>   }
>   
> +static void tdx_check_attributes(struct kvm_vm *vm, uint64_t attributes)
> +{
> +	struct kvm_tdx_capabilities *tdx_cap;
> +
> +	tdx_cap = tdx_read_capabilities(vm);
> +
> +	/* TDX spec: any bits 0 in supported_attrs must be 0 in attributes */
> +	TEST_ASSERT_EQ(attributes & ~tdx_cap->supported_attrs, 0);
> +
> +	/* TDX spec: any bits 1 in attributes must be 1 in supported_attrs */

The comments are not accurate.

The descriptions in TDX spec are for ATTRIBUTES_ FIXED0 and ATTRIBUTES_ FIXED1.
They are related to tdx_cap->supported_attrs returned by KVM, but they are not
the same.


> +	TEST_ASSERT_EQ(attributes & tdx_cap->supported_attrs, attributes);
> +
> +	free(tdx_cap);
> +}
> +
>   void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
>   {
>   	struct kvm_tdx_init_vm *init_vm;
> @@ -251,6 +266,8 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
>   	memcpy(&init_vm->cpuid, cpuid, kvm_cpuid2_size(cpuid->nent));
>   	free(cpuid);
>   
> +	tdx_check_attributes(vm, attributes);
> +
>   	init_vm->attributes = attributes;
>   
>   	vm_tdx_vm_ioctl(vm, KVM_TDX_INIT_VM, 0, init_vm);


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 03/19] KVM: selftests: Expose functions to get default sregs values
  2025-08-26  2:36   ` Binbin Wu
@ 2025-08-26 14:05     ` Sean Christopherson
  0 siblings, 0 replies; 62+ messages in thread
From: Sean Christopherson @ 2025-08-26 14:05 UTC (permalink / raw)
  To: Binbin Wu
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Tue, Aug 26, 2025, Binbin Wu wrote:
> On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> > TDX can't set sregs values directly using KVM_SET_SREGS. Expose the
> > default values of certain sregs used by TDX VMs so they can be set
> > manually.
> > 
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >   .../selftests/kvm/include/x86/processor.h     |  6 +++
> >   .../testing/selftests/kvm/lib/x86/processor.c | 41 +++++++++++++++----
> >   2 files changed, 40 insertions(+), 7 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
> > index 2efb05c2f2fb..5c16507f9b2d 100644
> > --- a/tools/testing/selftests/kvm/include/x86/processor.h
> > +++ b/tools/testing/selftests/kvm/include/x86/processor.h
> > @@ -1026,6 +1026,12 @@ static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries)
> >   void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid);
> > +uint16_t kvm_get_default_idt_limit(void);
> > +uint16_t kvm_get_default_gdt_limit(void);
> > +uint64_t kvm_get_default_cr0(void);
> > +uint64_t kvm_get_default_cr4(void);
> > +uint64_t kvm_get_default_efer(void);
> Can these be defined in the header file as static inline?

Yes please.  Performance isn't a concern, but as a developer, it's nice to not
have to bounce to a definition to find such simple information.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack
  2025-08-26  5:39   ` Binbin Wu
@ 2025-08-26 16:00     ` Sagi Shahar
  2025-08-26 17:16     ` Sean Christopherson
  1 sibling, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 16:00 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Tue, Aug 26, 2025 at 12:39 AM Binbin Wu <binbin.wu@linux.intel.com> wrote:
>
>
>
> On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> > TDX guests' registers cannot be initialized directly using
> > vcpu_regs_set(), hence the stack pointer needs to be initialized by
> > the guest itself, running boot code beginning at the reset vector.
> >
> > Expose the function to allocate the guest stack so that TDX
> > initialization code can allocate it itself and skip the allocation in
> > vm_arch_vcpu_add() in that case.
> >
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >   .../selftests/kvm/include/x86/processor.h       |  2 ++
> >   tools/testing/selftests/kvm/lib/x86/processor.c | 17 ++++++++++++-----
> >   2 files changed, 14 insertions(+), 5 deletions(-)
> >
> > diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
> > index 5c16507f9b2d..8fcc5118683e 100644
> > --- a/tools/testing/selftests/kvm/include/x86/processor.h
> > +++ b/tools/testing/selftests/kvm/include/x86/processor.h
> > @@ -1111,6 +1111,8 @@ static inline void vcpu_clear_cpuid_feature(struct kvm_vcpu *vcpu,
> >       vcpu_set_or_clear_cpuid_feature(vcpu, feature, false);
> >   }
> >
> > +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm);
> > +
> >   uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index);
> >   int _vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, uint64_t msr_value);
> >
> > diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> > index b2a4b11ac8c0..1eae92957456 100644
> > --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> > +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> > @@ -687,12 +687,9 @@ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
> >       vcpu_regs_set(vcpu, &regs);
> >   }
> >
> > -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> > +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
> >   {
> > -     struct kvm_mp_state mp_state;
> > -     struct kvm_regs regs;
> >       vm_vaddr_t stack_vaddr;
> > -     struct kvm_vcpu *vcpu;
> >
> >       stack_vaddr = __vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(),
> >                                      DEFAULT_GUEST_STACK_VADDR_MIN,
> > @@ -713,6 +710,15 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> >                   "__vm_vaddr_alloc() did not provide a page-aligned address");
> >       stack_vaddr -= 8;
> >
> > +     return stack_vaddr;
> > +}
> > +
> > +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> > +{
> > +     struct kvm_mp_state mp_state;
> > +     struct kvm_regs regs;
> > +     struct kvm_vcpu *vcpu;
> > +
> >       vcpu = __vm_vcpu_add(vm, vcpu_id);
> >       vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
> >       vcpu_init_sregs(vm, vcpu);
> > @@ -721,7 +727,8 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> >       /* Setup guest general purpose registers */
> >       vcpu_regs_get(vcpu, &regs);
> >       regs.rflags = regs.rflags | 0x2;
> > -     regs.rsp = stack_vaddr;
> > +     if (vm->type != KVM_X86_TDX_VM)
> > +             regs.rsp = kvm_allocate_vcpu_stack(vm);
>
> I am wondering if this could be more generic.
> I.e, make vcpu_regs_get() return the error code.
> If vcpu_regs_get() failed (for TDX, since it's guest state is protected, the
> ioctl will return -EINVAL), the vcpu_regs_set(), including the allocation for
> the vcpu stack, could be skipped.
>

I'm dropping this check and only keeping the check from "KVM:
selftests: Hook TDX support to vm and vcpu creation" which looks like
this:

if (is_tdx_vm(vm)) {
        vm_tdx_vcpu_add(vm, vcpu);
} else {
        vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());

        vcpu_init_sregs(vm, vcpu);
        vcpu_init_xcrs(vm, vcpu);

        /* Setup guest general purpose registers */
        vcpu_regs_get(vcpu, &regs);
        regs.rflags = regs.rflags | 0x2;
        regs.rsp = kvm_allocate_vcpu_stack(vm);
        vcpu_regs_set(vcpu, &regs);
}

Since there are other differences specific to TDX I think this is
cleaner than trying to handle kvm_allocate_vcpu_stack() individually.

> >       vcpu_regs_set(vcpu, &regs);
> >
> >       /* Setup the MP state */
>

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
  2025-08-26  5:51   ` Binbin Wu
@ 2025-08-26 16:04     ` Sagi Shahar
  0 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 16:04 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm, Adrian Hunter

On Tue, Aug 26, 2025 at 12:51 AM Binbin Wu <binbin.wu@linux.intel.com> wrote:
>
>
>
> On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> > From: Isaku Yamahata <isaku.yamahata@intel.com>
> >
> > Let kvm_init_vm_address_properties() initialize vm->arch.{s_bit, tag_mask}
> > similar to SEV.
> >
> > TDX sets the shared bit based on the guest physical address width and
> > currently supports 48 and 52 widths.
> >
> > Co-developed-by: Adrian Hunter <adrian.hunter@intel.com>
> > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> > Co-developed-by: Sagi Shahar <sagis@google.com>
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >   .../selftests/kvm/include/x86/tdx/tdx_util.h       | 14 ++++++++++++++
> >   tools/testing/selftests/kvm/lib/x86/processor.c    | 12 ++++++++++--
> >   2 files changed, 24 insertions(+), 2 deletions(-)
> >   create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> >
> > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > new file mode 100644
> > index 000000000000..286d5e3c24b1
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > @@ -0,0 +1,14 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +#ifndef SELFTESTS_TDX_TDX_UTIL_H
> > +#define SELFTESTS_TDX_TDX_UTIL_H
> > +
> > +#include <stdbool.h>
> > +
> > +#include "kvm_util.h"
> > +
> > +static inline bool is_tdx_vm(struct kvm_vm *vm)
> > +{
> > +     return vm->type == KVM_X86_TDX_VM;
> > +}
>
> If the branch "vm->type != KVM_X86_TDX_VM" in patch 04/19
> is still needed, this helper could be added earlier and used instead of
> open code.
>

I'm dropping the check in 04/19. See my response to Ira.

> > +
> > +#endif // SELFTESTS_TDX_TDX_UTIL_H
> > diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> > index 1eae92957456..6dbf40cbbc2a 100644
> > --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> > +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> > @@ -8,6 +8,7 @@
> >   #include "kvm_util.h"
> >   #include "processor.h"
> >   #include "sev.h"
> > +#include "tdx/tdx_util.h"
> >
> >   #ifndef NUM_INTERRUPTS
> >   #define NUM_INTERRUPTS 256
> > @@ -1190,12 +1191,19 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
> >
> >   void kvm_init_vm_address_properties(struct kvm_vm *vm)
> >   {
> > +     uint32_t gpa_bits = kvm_cpu_property(X86_PROPERTY_GUEST_MAX_PHY_ADDR);
> > +
> > +     vm->arch.sev_fd = -1;
> > +
> >       if (is_sev_vm(vm)) {
> >               vm->arch.sev_fd = open_sev_dev_path_or_exit();
> >               vm->arch.c_bit = BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT));
> >               vm->gpa_tag_mask = vm->arch.c_bit;
> > -     } else {
> > -             vm->arch.sev_fd = -1;
> > +     } else if (is_tdx_vm(vm)) {
> > +             TEST_ASSERT(gpa_bits == 48 || gpa_bits == 52,
> > +                         "TDX: bad X86_PROPERTY_GUEST_MAX_PHY_ADDR value: %u", gpa_bits);
> > +             vm->arch.s_bit = 1ULL << (gpa_bits - 1);
>
> Nit: Use BIT_ULL().
>

ACK, Will update in next version.

> > +             vm->gpa_tag_mask = vm->arch.s_bit;
> >       }
> >   }
> >
>

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 08/19] KVM: selftests: Define structs to pass parameters to TDX boot code
  2025-08-26  6:52   ` Binbin Wu
@ 2025-08-26 16:10     ` Sagi Shahar
  0 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 16:10 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Tue, Aug 26, 2025 at 1:52 AM Binbin Wu <binbin.wu@linux.intel.com> wrote:
>
>
>
> On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> [...]
> > +
> > +/*
> > + * Allows each vCPU to be initialized with different eip and esp.
> > + *
> > + * __packed is used since the offsets are hardcoded in td_boot.S
> > + *
> > + * TODO: Replace hardcoded offsets with OFFSET(). This requires getting the
> > + * neccesry Kbuild scripts working in KVM selftests.
> neccesry -> necessary
>
> Also, are the comments about "__packed" and "TODO" out dated?
>

Thanks, I forgot to update those.

> > + */
> > +struct td_per_vcpu_parameters {
> > +     uint32_t esp_gva;
> > +     uint64_t guest_code;
> > +};
> > +
> > +/*
> > + * Boot parameters for the TD.
> > + *
> > + * Unlike a regular VM, KVM cannot set registers such as esp, eip, etc
> > + * before boot, so to run selftests, these registers' values have to be
> > + * initialized by the TD.
> > + *
> > + * This struct is loaded in TD private memory at TD_BOOT_PARAMETERS_GPA.
> > + *
> > + * The TD boot code will read off parameters from this struct and set up the
> > + * vCPU for executing selftests.
> > + *
> > + * __packed is used since the offsets are hardcoded in td_boot.S
> Same as above for "__packed".
>
> > + */
> >
> [...]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-26  8:28   ` Chenyi Qiang
@ 2025-08-26 16:12     ` Sagi Shahar
  0 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 16:12 UTC (permalink / raw)
  To: Chenyi Qiang
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	linux-kernel, kvm

On Tue, Aug 26, 2025 at 3:28 AM Chenyi Qiang <chenyi.qiang@intel.com> wrote:
>
>
>
> On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> > TDX require special handling for VM and VCPU initialization for various
>
> s/require/requires
>
> > reasons:
> > - Special ioctlss for creating VM and VCPU.
>
> s/ioctlss/ioctls
>
> > - TDX registers are inaccessible to KVM.
> > - TDX require special boot code trampoline for loading parameters.
>
> s/require/requires
>

ACK

> > - TDX only supports KVM_CAP_SPLIT_IRQCHIP.
> >
> > Hook this special handling into __vm_create() and vm_arch_vcpu_add()
> > using the utility functions added in previous patches.
> >
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >  tools/testing/selftests/kvm/lib/kvm_util.c    | 24 ++++++++-
> >  .../testing/selftests/kvm/lib/x86/processor.c | 49 ++++++++++++++-----
> >  2 files changed, 61 insertions(+), 12 deletions(-)
> >
>

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 11/19] KVM: selftests: Set up TDX boot parameters region
  2025-08-26  8:36   ` Binbin Wu
@ 2025-08-26 16:17     ` Sagi Shahar
  0 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 16:17 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Tue, Aug 26, 2025 at 3:36 AM Binbin Wu <binbin.wu@linux.intel.com> wrote:
>
>
>
> On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> > Allocate memory for TDX boot parameters and define the utility functions
> > necessary to fill this memory with the boot parameters.
> >
> > Co-developed-by: Ackerley Tng <ackerleytng@google.com>
> > Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >   .../selftests/kvm/include/x86/tdx/tdx_util.h  |  4 +
> >   .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 73 +++++++++++++++++++
> >   2 files changed, 77 insertions(+)
> >
> > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > index ec05bcd59145..dafdc7e46abe 100644
> > --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > @@ -12,5 +12,9 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
> >   }
> >
> >   void vm_tdx_setup_boot_code_region(struct kvm_vm *vm);
> > +void vm_tdx_setup_boot_parameters_region(struct kvm_vm *vm, uint32_t nr_runnable_vcpus);
> > +void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
> > +void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
> > +void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
> >
> >   #endif // SELFTESTS_TDX_TDX_UTIL_H
> > diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > index 15833b9eb5d5..52dc25e0cce4 100644
> > --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > @@ -5,10 +5,12 @@
> >   #include "kvm_util.h"
> >   #include "processor.h"
> >   #include "tdx/td_boot.h"
> > +#include "tdx/td_boot_asm.h"
> >   #include "tdx/tdx_util.h"
> >
> >   /* Arbitrarily selected to avoid overlaps with anything else */
> >   #define TD_BOOT_CODE_SLOT   20
> > +#define TD_BOOT_PARAMETERS_SLOT      21
> >
> >   #define X86_RESET_VECTOR    0xfffffff0ul
> >   #define X86_RESET_VECTOR_SIZE       16
> > @@ -52,3 +54,74 @@ void vm_tdx_setup_boot_code_region(struct kvm_vm *vm)
> >       hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;
> >       hva[2] = 0xcc;
> >   }
> > +
> > +void vm_tdx_setup_boot_parameters_region(struct kvm_vm *vm, uint32_t nr_runnable_vcpus)
> > +{
> > +     size_t boot_params_size =
> > +             sizeof(struct td_boot_parameters) +
> > +             nr_runnable_vcpus * sizeof(struct td_per_vcpu_parameters);
> > +     int npages = DIV_ROUND_UP(boot_params_size, PAGE_SIZE);
> > +     vm_paddr_t gpa;
> > +
> > +     vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
> > +                                 TD_BOOT_PARAMETERS_GPA,
> > +                                 TD_BOOT_PARAMETERS_SLOT, npages,
> > +                                 KVM_MEM_GUEST_MEMFD);
> > +     gpa = vm_phy_pages_alloc(vm, npages, TD_BOOT_PARAMETERS_GPA, TD_BOOT_PARAMETERS_SLOT);
> > +     TEST_ASSERT(gpa == TD_BOOT_PARAMETERS_GPA, "Failed vm_phy_pages_alloc\n");
> > +
> > +     virt_map(vm, TD_BOOT_PARAMETERS_GPA, TD_BOOT_PARAMETERS_GPA, npages);
> > +}
> > +
> > +void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm)
> > +{
> > +     struct td_boot_parameters *params =
> > +             addr_gpa2hva(vm, TD_BOOT_PARAMETERS_GPA);
> > +     uint32_t cr4;
> > +
> > +     TEST_ASSERT_EQ(vm->mode, VM_MODE_PXXV48_4K);
> > +
> > +     cr4 = kvm_get_default_cr4();
> > +
> > +     /* TDX spec 11.6.2: CR4 bit MCE is fixed to 1 */
> > +     cr4 |= X86_CR4_MCE;
> > +
> > +     /* Set this because UEFI also sets this up, to handle XMM exceptions */
> > +     cr4 |= X86_CR4_OSXMMEXCPT;
> > +
> > +     /* TDX spec 11.6.2: CR4 bit VMXE and SMXE are fixed to 0 */
> > +     cr4 &= ~(X86_CR4_VMXE | X86_CR4_SMXE);
> > +
> > +     /* Set parameters! */
> > +     params->cr0 = kvm_get_default_cr0();
> > +     params->cr3 = vm->pgd;
> > +     params->cr4 = cr4;
> > +     params->idtr.base = vm->arch.idt;
> > +     params->idtr.limit = kvm_get_default_idt_limit();
> > +     params->gdtr.base = vm->arch.gdt;
> > +     params->gdtr.limit = kvm_get_default_gdt_limit();
> > +
> > +     TEST_ASSERT(params->cr0 != 0, "cr0 should not be 0");
> > +     TEST_ASSERT(params->cr3 != 0, "cr3 should not be 0");
> > +     TEST_ASSERT(params->cr4 != 0, "cr4 should not be 0");
> > +     TEST_ASSERT(params->gdtr.base != 0, "gdt base address should not be 0");
> > +     TEST_ASSERT(params->idtr.base != 0, "idt base address should not be 0");
> > +}
> > +
> > +void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
> > +{
> > +     struct td_boot_parameters *params =
> > +             addr_gpa2hva(vm, TD_BOOT_PARAMETERS_GPA);
> > +     struct td_per_vcpu_parameters *vcpu_params =
> > +             &params->per_vcpu[vcpu->id];
>
> Nit: Better to align the style on whether wrap or not due to max characters per
> line
>

Thanks, going to wrap in both functions.

> > +
> > +     vcpu_params->esp_gva = kvm_allocate_vcpu_stack(vm);
> > +}
> > +
> > +void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
> > +{
> > +     struct td_boot_parameters *params = addr_gpa2hva(vcpu->vm, TD_BOOT_PARAMETERS_GPA);
> > +     struct td_per_vcpu_parameters *vcpu_params = &params->per_vcpu[vcpu->id];
> > +
> > +     vcpu_params->guest_code = (uint64_t)guest_code;
> > +}
>

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region
  2025-08-25  5:32   ` Yan Zhao
@ 2025-08-26 16:38     ` Sean Christopherson
  2025-08-27  1:36       ` Yan Zhao
  0 siblings, 1 reply; 62+ messages in thread
From: Sean Christopherson @ 2025-08-26 16:38 UTC (permalink / raw)
  To: Yan Zhao
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Mon, Aug 25, 2025, Yan Zhao wrote:
> > +	/*
> > +	 * Handcode "JMP rel8" at the RESET vector to jump back to the TD boot
> > +	 * code, as there are only 16 bytes at the RESET vector before RIP will
> > +	 * wrap back to zero.  Insert a trailing int3 so that the vCPU crashes
> > +	 * in case the JMP somehow falls through.  Note!  The target address is
> > +	 * relative to the end of the instruction!
> > +	 */
> > +	TEST_ASSERT(TD_BOOT_CODE_SIZE < 256,
> Looks TD_BOOT_CODE_SIZE needs to be <= 126, as the jump range is limited to -128
> to +127 for JMP rel8.

Gah, I managed to forget that relative targets obviously need to be signed values,
and I also forgot to account for the size of the JMP in the assert.  Go me.

Maybe express this as:

	TEST_ASSERT(TD_BOOT_CODE_SIZE + 2 < 128,
		    "TD boot code not addressable by 'JMP rel8'");
	
> > +		    "TD boot code not addressable by 'JMP rel8'");
> > +	hva[0] = 0xeb;
> > +	hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;

I think I lucked into getting this right though?

> > +	hva[2] = 0xcc;
> > +}
> > -- 
> > 2.51.0.rc1.193.gad69d77794-goog
> > 
> > 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack
  2025-08-26  5:39   ` Binbin Wu
  2025-08-26 16:00     ` Sagi Shahar
@ 2025-08-26 17:16     ` Sean Christopherson
  1 sibling, 0 replies; 62+ messages in thread
From: Sean Christopherson @ 2025-08-26 17:16 UTC (permalink / raw)
  To: Binbin Wu
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Tue, Aug 26, 2025, Binbin Wu wrote:
> 
> 
> On 8/21/2025 12:28 PM, Sagi Shahar wrote:
> > TDX guests' registers cannot be initialized directly using
> > vcpu_regs_set(), hence the stack pointer needs to be initialized by
> > the guest itself, running boot code beginning at the reset vector.
> > 
> > Expose the function to allocate the guest stack so that TDX
> > initialization code can allocate it itself and skip the allocation in
> > vm_arch_vcpu_add() in that case.
> > 
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >   .../selftests/kvm/include/x86/processor.h       |  2 ++
> >   tools/testing/selftests/kvm/lib/x86/processor.c | 17 ++++++++++++-----
> >   2 files changed, 14 insertions(+), 5 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
> > index 5c16507f9b2d..8fcc5118683e 100644
> > --- a/tools/testing/selftests/kvm/include/x86/processor.h
> > +++ b/tools/testing/selftests/kvm/include/x86/processor.h
> > @@ -1111,6 +1111,8 @@ static inline void vcpu_clear_cpuid_feature(struct kvm_vcpu *vcpu,
> >   	vcpu_set_or_clear_cpuid_feature(vcpu, feature, false);
> >   }
> > +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm);
> > +
> >   uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index);
> >   int _vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, uint64_t msr_value);
> > diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
> > index b2a4b11ac8c0..1eae92957456 100644
> > --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> > +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> > @@ -687,12 +687,9 @@ void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
> >   	vcpu_regs_set(vcpu, &regs);
> >   }
> > -struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> > +vm_vaddr_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
> >   {
> > -	struct kvm_mp_state mp_state;
> > -	struct kvm_regs regs;
> >   	vm_vaddr_t stack_vaddr;
> > -	struct kvm_vcpu *vcpu;
> >   	stack_vaddr = __vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(),
> >   				       DEFAULT_GUEST_STACK_VADDR_MIN,
> > @@ -713,6 +710,15 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> >   		    "__vm_vaddr_alloc() did not provide a page-aligned address");
> >   	stack_vaddr -= 8;
> > +	return stack_vaddr;
> > +}
> > +
> > +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> > +{
> > +	struct kvm_mp_state mp_state;
> > +	struct kvm_regs regs;
> > +	struct kvm_vcpu *vcpu;
> > +
> >   	vcpu = __vm_vcpu_add(vm, vcpu_id);
> >   	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
> >   	vcpu_init_sregs(vm, vcpu);
> > @@ -721,7 +727,8 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
> >   	/* Setup guest general purpose registers */
> >   	vcpu_regs_get(vcpu, &regs);
> >   	regs.rflags = regs.rflags | 0x2;
> > -	regs.rsp = stack_vaddr;
> > +	if (vm->type != KVM_X86_TDX_VM)
> > +		regs.rsp = kvm_allocate_vcpu_stack(vm);
> 
> I am wondering if this could be more generic.
> I.e, make vcpu_regs_get() return the error code.

It would need to be a double-underscores variant, i.e. __vcpu_regs_get().  But
even then, I don't think it's worth getting that clever, because then to ensure
selftests aren't hitting KVM bugs, we'd want to assert that failure only occurs
for a TDX VM, i.e. we'd end up with:

	if (__vcpu_regs_get(vcpu, &regs)) {
		TEST_ASERT(is_tdx_vm(vm), "blah blah blah"
	} else {

	}

which doesn't really "save" anything relative to Sagi's proposed version of:

	if (is_tdx_vm(vm)) {
        	vm_tdx_vcpu_add(vm, vcpu);
	} else {
        	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());

	        vcpu_init_sregs(vm, vcpu);
	        vcpu_init_xcrs(vm, vcpu);

        	/* Setup guest general purpose registers */
	        vcpu_regs_get(vcpu, &regs);
	        regs.rflags = regs.rflags | 0x2;
	        regs.rsp = kvm_allocate_vcpu_stack(vm);
	        vcpu_regs_set(vcpu, &regs);
	}

> If vcpu_regs_get() failed (for TDX, since it's guest state is protected, the
> ioctl will return -EINVAL), the vcpu_regs_set(), including the allocation for
> the vcpu stack, could be skipped.
> 
> >   	vcpu_regs_set(vcpu, &regs);
> >   	/* Setup the MP state */
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-21  4:29 ` [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation Sagi Shahar
  2025-08-26  8:28   ` Chenyi Qiang
@ 2025-08-26 17:31   ` Sean Christopherson
  2025-08-26 20:16     ` Ira Weiny
  1 sibling, 1 reply; 62+ messages in thread
From: Sean Christopherson @ 2025-08-26 17:31 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Ackerley Tng,
	Ryan Afranji, Andrew Jones, Isaku Yamahata, Erdem Aktas,
	Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Wed, Aug 20, 2025, Sagi Shahar wrote:
> TDX require special handling for VM and VCPU initialization for various
> reasons:
> - Special ioctlss for creating VM and VCPU.
> - TDX registers are inaccessible to KVM.
> - TDX require special boot code trampoline for loading parameters.
> - TDX only supports KVM_CAP_SPLIT_IRQCHIP.

Please split this up and elaborate at least a little bit on why each flow needs
special handling for TDX.  Even for someone like me who is fairly familiar with
TDX, there's too much "Trust me bro" and not enough explanation of why selftests
really need all of these special paths for TDX.

At least four patches, one for each of your bullet points.  Probably 5 or 6, as
I think the CPUID handling warrants its own patch.

> Hook this special handling into __vm_create() and vm_arch_vcpu_add()
> using the utility functions added in previous patches.
>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>  tools/testing/selftests/kvm/lib/kvm_util.c    | 24 ++++++++-
>  .../testing/selftests/kvm/lib/x86/processor.c | 49 ++++++++++++++-----
>  2 files changed, 61 insertions(+), 12 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index b4c8702ba4bd..d9f0ff97770d 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -4,6 +4,7 @@
>   *
>   * Copyright (C) 2018, Google LLC.
>   */
> +#include "tdx/tdx_util.h"
>  #include "test_util.h"
>  #include "kvm_util.h"
>  #include "processor.h"
> @@ -465,7 +466,7 @@ void kvm_set_files_rlimit(uint32_t nr_vcpus)
>  static bool is_guest_memfd_required(struct vm_shape shape)
>  {
>  #ifdef __x86_64__
> -	return shape.type == KVM_X86_SNP_VM;
> +	return (shape.type == KVM_X86_SNP_VM || shape.type == KVM_X86_TDX_VM);
>  #else
>  	return false;
>  #endif
> @@ -499,6 +500,12 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
>  	for (i = 0; i < NR_MEM_REGIONS; i++)
>  		vm->memslots[i] = 0;
>  
> +	if (is_tdx_vm(vm)) {
> +		/* Setup additional mem regions for TDX. */
> +		vm_tdx_setup_boot_code_region(vm);
> +		vm_tdx_setup_boot_parameters_region(vm, nr_runnable_vcpus);
> +	}
> +
>  	kvm_vm_elf_load(vm, program_invocation_name);
>  
>  	/*
> @@ -1728,11 +1735,26 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa)
>  	return (void *) ((uintptr_t) region->host_alias + offset);
>  }
>  
> +static bool is_split_irqchip_required(struct kvm_vm *vm)
> +{
> +#ifdef __x86_64__
> +	return is_tdx_vm(vm);
> +#else
> +	return false;
> +#endif
> +}
> +
>  /* Create an interrupt controller chip for the specified VM. */
>  void vm_create_irqchip(struct kvm_vm *vm)
>  {
>  	int r;
>  
> +	if (is_split_irqchip_required(vm)) {
> +		vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> +		vm->has_irqchip = true;
> +		return;
> +	}

Ugh.  IMO, this is a KVM bug.  Allowing KVM_CREATE_IRQCHIP for a TDX VM is simply
wrong.  It _can't_ work.  Waiting until KVM_CREATE_VCPU to fail setup is terrible
ABI.

If we stretch the meaning of ENOTTY a bit and return that when trying to create
a fully in-kernel IRQCHIP for a TDX VM, then the selftests code Just Works thanks
to the code below, which handles the scenario where KVM was be built without
support for in-kernel I/O APIC (and PIC and PIT).

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-26 17:31   ` Sean Christopherson
@ 2025-08-26 20:16     ` Ira Weiny
  2025-08-26 20:29       ` Sagi Shahar
  0 siblings, 1 reply; 62+ messages in thread
From: Ira Weiny @ 2025-08-26 20:16 UTC (permalink / raw)
  To: Sean Christopherson, Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Ackerley Tng,
	Ryan Afranji, Andrew Jones, Isaku Yamahata, Erdem Aktas,
	Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

Sean Christopherson wrote:
> On Wed, Aug 20, 2025, Sagi Shahar wrote:
> > TDX require special handling for VM and VCPU initialization for various
> > reasons:
> > - Special ioctlss for creating VM and VCPU.
> > - TDX registers are inaccessible to KVM.
> > - TDX require special boot code trampoline for loading parameters.
> > - TDX only supports KVM_CAP_SPLIT_IRQCHIP.
> 
> Please split this up and elaborate at least a little bit on why each flow needs
> special handling for TDX.  Even for someone like me who is fairly familiar with
> TDX, there's too much "Trust me bro" and not enough explanation of why selftests
> really need all of these special paths for TDX.
> 
> At least four patches, one for each of your bullet points.  Probably 5 or 6, as
> I think the CPUID handling warrants its own patch.
> 
> > Hook this special handling into __vm_create() and vm_arch_vcpu_add()
> > using the utility functions added in previous patches.
> >
> > Signed-off-by: Sagi Shahar <sagis@google.com>
> > ---
> >  tools/testing/selftests/kvm/lib/kvm_util.c    | 24 ++++++++-
> >  .../testing/selftests/kvm/lib/x86/processor.c | 49 ++++++++++++++-----
> >  2 files changed, 61 insertions(+), 12 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> > index b4c8702ba4bd..d9f0ff97770d 100644
> > --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> > +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> > @@ -4,6 +4,7 @@
> >   *
> >   * Copyright (C) 2018, Google LLC.
> >   */
> > +#include "tdx/tdx_util.h"
> >  #include "test_util.h"
> >  #include "kvm_util.h"
> >  #include "processor.h"
> > @@ -465,7 +466,7 @@ void kvm_set_files_rlimit(uint32_t nr_vcpus)
> >  static bool is_guest_memfd_required(struct vm_shape shape)
> >  {
> >  #ifdef __x86_64__
> > -	return shape.type == KVM_X86_SNP_VM;
> > +	return (shape.type == KVM_X86_SNP_VM || shape.type == KVM_X86_TDX_VM);
> >  #else
> >  	return false;
> >  #endif
> > @@ -499,6 +500,12 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
> >  	for (i = 0; i < NR_MEM_REGIONS; i++)
> >  		vm->memslots[i] = 0;
> >  
> > +	if (is_tdx_vm(vm)) {
> > +		/* Setup additional mem regions for TDX. */
> > +		vm_tdx_setup_boot_code_region(vm);
> > +		vm_tdx_setup_boot_parameters_region(vm, nr_runnable_vcpus);
> > +	}
> > +
> >  	kvm_vm_elf_load(vm, program_invocation_name);
> >  
> >  	/*
> > @@ -1728,11 +1735,26 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa)
> >  	return (void *) ((uintptr_t) region->host_alias + offset);
> >  }
> >  
> > +static bool is_split_irqchip_required(struct kvm_vm *vm)
> > +{
> > +#ifdef __x86_64__
> > +	return is_tdx_vm(vm);
> > +#else
> > +	return false;
> > +#endif
> > +}
> > +
> >  /* Create an interrupt controller chip for the specified VM. */
> >  void vm_create_irqchip(struct kvm_vm *vm)
> >  {
> >  	int r;
> >  
> > +	if (is_split_irqchip_required(vm)) {
> > +		vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> > +		vm->has_irqchip = true;
> > +		return;
> > +	}
> 
> Ugh.  IMO, this is a KVM bug.  Allowing KVM_CREATE_IRQCHIP for a TDX VM is simply
> wrong.  It _can't_ work.  Waiting until KVM_CREATE_VCPU to fail setup is terrible
> ABI.
> 
> If we stretch the meaning of ENOTTY a bit and return that when trying to create
> a fully in-kernel IRQCHIP for a TDX VM, then the selftests code Just Works thanks
> to the code below, which handles the scenario where KVM was be built without
         ^^^^^^^^^^

I'm not following.  Was there supposed to be a patch attached?

Ira

> support for in-kernel I/O APIC (and PIC and PIT).



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-26 20:16     ` Ira Weiny
@ 2025-08-26 20:29       ` Sagi Shahar
  2025-08-26 20:30         ` Sagi Shahar
  0 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 20:29 UTC (permalink / raw)
  To: Ira Weiny
  Cc: Sean Christopherson, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Chao Gao, Chenyi Qiang,
	linux-kernel, kvm

On Tue, Aug 26, 2025 at 3:14 PM Ira Weiny <ira.weiny@intel.com> wrote:
>
> Sean Christopherson wrote:
> > On Wed, Aug 20, 2025, Sagi Shahar wrote:
> > > TDX require special handling for VM and VCPU initialization for various
> > > reasons:
> > > - Special ioctlss for creating VM and VCPU.
> > > - TDX registers are inaccessible to KVM.
> > > - TDX require special boot code trampoline for loading parameters.
> > > - TDX only supports KVM_CAP_SPLIT_IRQCHIP.
> >
> > Please split this up and elaborate at least a little bit on why each flow needs
> > special handling for TDX.  Even for someone like me who is fairly familiar with
> > TDX, there's too much "Trust me bro" and not enough explanation of why selftests
> > really need all of these special paths for TDX.
> >
> > At least four patches, one for each of your bullet points.  Probably 5 or 6, as
> > I think the CPUID handling warrants its own patch.
> >
> > > Hook this special handling into __vm_create() and vm_arch_vcpu_add()
> > > using the utility functions added in previous patches.
> > >
> > > Signed-off-by: Sagi Shahar <sagis@google.com>
> > > ---
> > >  tools/testing/selftests/kvm/lib/kvm_util.c    | 24 ++++++++-
> > >  .../testing/selftests/kvm/lib/x86/processor.c | 49 ++++++++++++++-----
> > >  2 files changed, 61 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> > > index b4c8702ba4bd..d9f0ff97770d 100644
> > > --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> > > +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> > > @@ -4,6 +4,7 @@
> > >   *
> > >   * Copyright (C) 2018, Google LLC.
> > >   */
> > > +#include "tdx/tdx_util.h"
> > >  #include "test_util.h"
> > >  #include "kvm_util.h"
> > >  #include "processor.h"
> > > @@ -465,7 +466,7 @@ void kvm_set_files_rlimit(uint32_t nr_vcpus)
> > >  static bool is_guest_memfd_required(struct vm_shape shape)
> > >  {
> > >  #ifdef __x86_64__
> > > -   return shape.type == KVM_X86_SNP_VM;
> > > +   return (shape.type == KVM_X86_SNP_VM || shape.type == KVM_X86_TDX_VM);
> > >  #else
> > >     return false;
> > >  #endif
> > > @@ -499,6 +500,12 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
> > >     for (i = 0; i < NR_MEM_REGIONS; i++)
> > >             vm->memslots[i] = 0;
> > >
> > > +   if (is_tdx_vm(vm)) {
> > > +           /* Setup additional mem regions for TDX. */
> > > +           vm_tdx_setup_boot_code_region(vm);
> > > +           vm_tdx_setup_boot_parameters_region(vm, nr_runnable_vcpus);
> > > +   }
> > > +
> > >     kvm_vm_elf_load(vm, program_invocation_name);
> > >
> > >     /*
> > > @@ -1728,11 +1735,26 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa)
> > >     return (void *) ((uintptr_t) region->host_alias + offset);
> > >  }
> > >
> > > +static bool is_split_irqchip_required(struct kvm_vm *vm)
> > > +{
> > > +#ifdef __x86_64__
> > > +   return is_tdx_vm(vm);
> > > +#else
> > > +   return false;
> > > +#endif
> > > +}
> > > +
> > >  /* Create an interrupt controller chip for the specified VM. */
> > >  void vm_create_irqchip(struct kvm_vm *vm)
> > >  {
> > >     int r;
> > >
> > > +   if (is_split_irqchip_required(vm)) {
> > > +           vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> > > +           vm->has_irqchip = true;
> > > +           return;
> > > +   }
> >
> > Ugh.  IMO, this is a KVM bug.  Allowing KVM_CREATE_IRQCHIP for a TDX VM is simply
> > wrong.  It _can't_ work.  Waiting until KVM_CREATE_VCPU to fail setup is terrible
> > ABI.
> >
> > If we stretch the meaning of ENOTTY a bit and return that when trying to create
> > a fully in-kernel IRQCHIP for a TDX VM, then the selftests code Just Works thanks
> > to the code below, which handles the scenario where KVM was be built without
>          ^^^^^^^^^^
>
> I'm not following.  Was there supposed to be a patch attached?
>

I think Sean refers to the original implementation which was out of
the scope for the git diff so it was left out of the patch:

/*
 * Allocate a fully in-kernel IRQ chip by default, but fall back to a
 * split model (x86 only) if that fails (KVM x86 allows compiling out
 * support for KVM_CREATE_IRQCHIP).
 */
r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
        vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
else
        TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);

/*
 * Allocate a fully in-kernel IRQ chip by default, but fall back to a
 * split model (x86 only) if that fails (KVM x86 allows compiling out
 * support for KVM_CREATE_IRQCHIP).
 */
r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
else
TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);
/*
* Allocate a fully in-kernel IRQ chip by default, but fall back to a
* split model (x86 only) if that fails (KVM x86 allows compiling out
* support for KVM_CREATE_IRQCHIP).
*/
r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
else
TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);

> Ira
>
> > support for in-kernel I/O APIC (and PIC and PIT).
>
>

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-26 20:29       ` Sagi Shahar
@ 2025-08-26 20:30         ` Sagi Shahar
  2025-08-26 21:31           ` Sean Christopherson
  0 siblings, 1 reply; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 20:30 UTC (permalink / raw)
  To: Ira Weiny
  Cc: Sean Christopherson, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Chao Gao, Chenyi Qiang,
	linux-kernel, kvm

On Tue, Aug 26, 2025 at 3:29 PM Sagi Shahar <sagis@google.com> wrote:
>
> On Tue, Aug 26, 2025 at 3:14 PM Ira Weiny <ira.weiny@intel.com> wrote:
> >
> > Sean Christopherson wrote:
> > > On Wed, Aug 20, 2025, Sagi Shahar wrote:
> > > > TDX require special handling for VM and VCPU initialization for various
> > > > reasons:
> > > > - Special ioctlss for creating VM and VCPU.
> > > > - TDX registers are inaccessible to KVM.
> > > > - TDX require special boot code trampoline for loading parameters.
> > > > - TDX only supports KVM_CAP_SPLIT_IRQCHIP.
> > >
> > > Please split this up and elaborate at least a little bit on why each flow needs
> > > special handling for TDX.  Even for someone like me who is fairly familiar with
> > > TDX, there's too much "Trust me bro" and not enough explanation of why selftests
> > > really need all of these special paths for TDX.
> > >
> > > At least four patches, one for each of your bullet points.  Probably 5 or 6, as
> > > I think the CPUID handling warrants its own patch.
> > >
> > > > Hook this special handling into __vm_create() and vm_arch_vcpu_add()
> > > > using the utility functions added in previous patches.
> > > >
> > > > Signed-off-by: Sagi Shahar <sagis@google.com>
> > > > ---
> > > >  tools/testing/selftests/kvm/lib/kvm_util.c    | 24 ++++++++-
> > > >  .../testing/selftests/kvm/lib/x86/processor.c | 49 ++++++++++++++-----
> > > >  2 files changed, 61 insertions(+), 12 deletions(-)
> > > >
> > > > diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> > > > index b4c8702ba4bd..d9f0ff97770d 100644
> > > > --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> > > > +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> > > > @@ -4,6 +4,7 @@
> > > >   *
> > > >   * Copyright (C) 2018, Google LLC.
> > > >   */
> > > > +#include "tdx/tdx_util.h"
> > > >  #include "test_util.h"
> > > >  #include "kvm_util.h"
> > > >  #include "processor.h"
> > > > @@ -465,7 +466,7 @@ void kvm_set_files_rlimit(uint32_t nr_vcpus)
> > > >  static bool is_guest_memfd_required(struct vm_shape shape)
> > > >  {
> > > >  #ifdef __x86_64__
> > > > -   return shape.type == KVM_X86_SNP_VM;
> > > > +   return (shape.type == KVM_X86_SNP_VM || shape.type == KVM_X86_TDX_VM);
> > > >  #else
> > > >     return false;
> > > >  #endif
> > > > @@ -499,6 +500,12 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
> > > >     for (i = 0; i < NR_MEM_REGIONS; i++)
> > > >             vm->memslots[i] = 0;
> > > >
> > > > +   if (is_tdx_vm(vm)) {
> > > > +           /* Setup additional mem regions for TDX. */
> > > > +           vm_tdx_setup_boot_code_region(vm);
> > > > +           vm_tdx_setup_boot_parameters_region(vm, nr_runnable_vcpus);
> > > > +   }
> > > > +
> > > >     kvm_vm_elf_load(vm, program_invocation_name);
> > > >
> > > >     /*
> > > > @@ -1728,11 +1735,26 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa)
> > > >     return (void *) ((uintptr_t) region->host_alias + offset);
> > > >  }
> > > >
> > > > +static bool is_split_irqchip_required(struct kvm_vm *vm)
> > > > +{
> > > > +#ifdef __x86_64__
> > > > +   return is_tdx_vm(vm);
> > > > +#else
> > > > +   return false;
> > > > +#endif
> > > > +}
> > > > +
> > > >  /* Create an interrupt controller chip for the specified VM. */
> > > >  void vm_create_irqchip(struct kvm_vm *vm)
> > > >  {
> > > >     int r;
> > > >
> > > > +   if (is_split_irqchip_required(vm)) {
> > > > +           vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> > > > +           vm->has_irqchip = true;
> > > > +           return;
> > > > +   }
> > >
> > > Ugh.  IMO, this is a KVM bug.  Allowing KVM_CREATE_IRQCHIP for a TDX VM is simply
> > > wrong.  It _can't_ work.  Waiting until KVM_CREATE_VCPU to fail setup is terrible
> > > ABI.
> > >
> > > If we stretch the meaning of ENOTTY a bit and return that when trying to create
> > > a fully in-kernel IRQCHIP for a TDX VM, then the selftests code Just Works thanks
> > > to the code below, which handles the scenario where KVM was be built without
> >          ^^^^^^^^^^
> >
> > I'm not following.  Was there supposed to be a patch attached?
> >
>
> I think Sean refers to the original implementation which was out of
> the scope for the git diff so it was left out of the patch:
>
> /*
>  * Allocate a fully in-kernel IRQ chip by default, but fall back to a
>  * split model (x86 only) if that fails (KVM x86 allows compiling out
>  * support for KVM_CREATE_IRQCHIP).
>  */
> r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
> if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
>         vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> else
>         TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);
>
> /*
>  * Allocate a fully in-kernel IRQ chip by default, but fall back to a
>  * split model (x86 only) if that fails (KVM x86 allows compiling out
>  * support for KVM_CREATE_IRQCHIP).
>  */
> r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
> if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
> vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> else
> TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);
> /*
> * Allocate a fully in-kernel IRQ chip by default, but fall back to a
> * split model (x86 only) if that fails (KVM x86 allows compiling out
> * support for KVM_CREATE_IRQCHIP).
> */
> r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
> if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
> vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> else
> TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);
>

Sorry, I messed up the paste somehow:

/*
 * Allocate a fully in-kernel IRQ chip by default, but fall back to a
 * split model (x86 only) if that fails (KVM x86 allows compiling out
 * support for KVM_CREATE_IRQCHIP).
 */
r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
        vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
else
        TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);

> > Ira
> >
> > > support for in-kernel I/O APIC (and PIC and PIT).
> >
> >

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-26 20:30         ` Sagi Shahar
@ 2025-08-26 21:31           ` Sean Christopherson
  2025-08-26 21:38             ` Sagi Shahar
  0 siblings, 1 reply; 62+ messages in thread
From: Sean Christopherson @ 2025-08-26 21:31 UTC (permalink / raw)
  To: Sagi Shahar
  Cc: Ira Weiny, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Chao Gao, Chenyi Qiang,
	linux-kernel, kvm

On Tue, Aug 26, 2025, Sagi Shahar wrote:
> On Tue, Aug 26, 2025 at 3:29 PM Sagi Shahar <sagis@google.com> wrote:
> >
> > On Tue, Aug 26, 2025 at 3:14 PM Ira Weiny <ira.weiny@intel.com> wrote:
> > >
> > > Sean Christopherson wrote:
> > > > Ugh.  IMO, this is a KVM bug.  Allowing KVM_CREATE_IRQCHIP for a TDX VM is simply
> > > > wrong.  It _can't_ work.  Waiting until KVM_CREATE_VCPU to fail setup is terrible
> > > > ABI.
> > > >
> > > > If we stretch the meaning of ENOTTY a bit and return that when trying to create
> > > > a fully in-kernel IRQCHIP for a TDX VM, then the selftests code Just Works thanks
> > > > to the code below, which handles the scenario where KVM was be built without
> > >          ^^^^^^^^^^
> > >
> > > I'm not following.  Was there supposed to be a patch attached?
> > >
> >
> > I think Sean refers to the original implementation which was out of
> > the scope for the git diff so it was left out of the patch:

Yep, exactly.

> /*
>  * Allocate a fully in-kernel IRQ chip by default, but fall back to a
>  * split model (x86 only) if that fails (KVM x86 allows compiling out
>  * support for KVM_CREATE_IRQCHIP).
>  */
> r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
> if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
>         vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> else
>         TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
  2025-08-26 21:31           ` Sean Christopherson
@ 2025-08-26 21:38             ` Sagi Shahar
  0 siblings, 0 replies; 62+ messages in thread
From: Sagi Shahar @ 2025-08-26 21:38 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Ira Weiny, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Chao Gao, Chenyi Qiang,
	linux-kernel, kvm

On Tue, Aug 26, 2025 at 4:31 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Tue, Aug 26, 2025, Sagi Shahar wrote:
> > On Tue, Aug 26, 2025 at 3:29 PM Sagi Shahar <sagis@google.com> wrote:
> > >
> > > On Tue, Aug 26, 2025 at 3:14 PM Ira Weiny <ira.weiny@intel.com> wrote:
> > > >
> > > > Sean Christopherson wrote:
> > > > > Ugh.  IMO, this is a KVM bug.  Allowing KVM_CREATE_IRQCHIP for a TDX VM is simply
> > > > > wrong.  It _can't_ work.  Waiting until KVM_CREATE_VCPU to fail setup is terrible
> > > > > ABI.
> > > > >
> > > > > If we stretch the meaning of ENOTTY a bit and return that when trying to create
> > > > > a fully in-kernel IRQCHIP for a TDX VM, then the selftests code Just Works thanks
> > > > > to the code below, which handles the scenario where KVM was be built without
> > > >          ^^^^^^^^^^
> > > >
> > > > I'm not following.  Was there supposed to be a patch attached?
> > > >
> > >
> > > I think Sean refers to the original implementation which was out of
> > > the scope for the git diff so it was left out of the patch:
>
> Yep, exactly.
>

I took a stab at updating the KVM ABI and sent out a small patch [1]
to fail KVM_CREATE_IRQCHIP with ENOTTY and the test passes without the
special handling for SPLIT_IRQCHIP for TDX.

[1] https://lore.kernel.org/lkml/20250826213455.2338722-1-sagis@google.com/

> > /*
> >  * Allocate a fully in-kernel IRQ chip by default, but fall back to a
> >  * split model (x86 only) if that fails (KVM x86 allows compiling out
> >  * support for KVM_CREATE_IRQCHIP).
> >  */
> > r = __vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL);
> > if (r && errno == ENOTTY && kvm_has_cap(KVM_CAP_SPLIT_IRQCHIP))
> >         vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
> > else
> >         TEST_ASSERT_VM_VCPU_IOCTL(!r, KVM_CREATE_IRQCHIP, r, vm);

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region
  2025-08-26 16:38     ` Sean Christopherson
@ 2025-08-27  1:36       ` Yan Zhao
  0 siblings, 0 replies; 62+ messages in thread
From: Yan Zhao @ 2025-08-27  1:36 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Binbin Wu, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Tue, Aug 26, 2025 at 09:38:15AM -0700, Sean Christopherson wrote:
> On Mon, Aug 25, 2025, Yan Zhao wrote:
> > > +	/*
> > > +	 * Handcode "JMP rel8" at the RESET vector to jump back to the TD boot
> > > +	 * code, as there are only 16 bytes at the RESET vector before RIP will
> > > +	 * wrap back to zero.  Insert a trailing int3 so that the vCPU crashes
> > > +	 * in case the JMP somehow falls through.  Note!  The target address is
> > > +	 * relative to the end of the instruction!
> > > +	 */
> > > +	TEST_ASSERT(TD_BOOT_CODE_SIZE < 256,
> > Looks TD_BOOT_CODE_SIZE needs to be <= 126, as the jump range is limited to -128
> > to +127 for JMP rel8.
> 
> Gah, I managed to forget that relative targets obviously need to be signed values,
> and I also forgot to account for the size of the JMP in the assert.  Go me.
> 
> Maybe express this as:
> 
> 	TEST_ASSERT(TD_BOOT_CODE_SIZE + 2 < 128,
> 		    "TD boot code not addressable by 'JMP rel8'");
I like this version, which's is much clearer than asserting TD_BOOT_CODE_SIZE
alone.

nit: TD_BOOT_CODE_SIZE + 2 can be equal to 128, i.e.,

	TEST_ASSERT(TD_BOOT_CODE_SIZE + 2 <= 128,
		    "TD boot code not addressable by 'JMP rel8'");


> > > +		    "TD boot code not addressable by 'JMP rel8'");
> > > +	hva[0] = 0xeb;
> > > +	hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;
> 
> I think I lucked into getting this right though?
Yes, this one is correct :)


> > > +	hva[2] = 0xcc;
> > > +}
> > > -- 
> > > 2.51.0.rc1.193.gad69d77794-goog
> > > 
> > > 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM
  2025-08-26  1:07       ` Yan Zhao
@ 2025-08-27  2:24         ` Binbin Wu
  2025-08-27  2:44           ` Yan Zhao
  0 siblings, 1 reply; 62+ messages in thread
From: Binbin Wu @ 2025-08-27  2:24 UTC (permalink / raw)
  To: Yan Zhao, Sagi Shahar
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Sean Christopherson,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 8/26/2025 9:07 AM, Yan Zhao wrote:
> On Mon, Aug 25, 2025 at 02:02:00PM -0500, Sagi Shahar wrote:
>> On Mon, Aug 25, 2025 at 3:41 AM Yan Zhao <yan.y.zhao@intel.com> wrote:
>>> On Wed, Aug 20, 2025 at 09:29:07PM -0700, Sagi Shahar wrote:
>>>> From: Ackerley Tng <ackerleytng@google.com>
>>>>
>>>> TDX protected memory needs to be measured and encrypted before it can be
>>>> used by the guest. Traverse the VM's memory regions and initialize all
>>>> the protected ranges by calling KVM_TDX_INIT_MEM_REGION.
>>>>
>>>> Once all the memory is initialized, the VM can be finalized by calling
>>>> KVM_TDX_FINALIZE_VM.
>>>>
>>>> Signed-off-by: Ackerley Tng <ackerleytng@google.com>
>>>> Co-developed-by: Erdem Aktas <erdemaktas@google.com>
>>>> Signed-off-by: Erdem Aktas <erdemaktas@google.com>
>>>> Co-developed-by: Sagi Shahar <sagis@google.com>
>>>> Signed-off-by: Sagi Shahar <sagis@google.com>
>>>> ---
>>>>   .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
>>>>   .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 97 +++++++++++++++++++
>>>>   2 files changed, 99 insertions(+)
>>>>
>>>> diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
>>>> index a2509959c7ce..2467b6c35557 100644
>>>> --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
>>>> +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
>>>> @@ -71,4 +71,6 @@ void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
>>>>   void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
>>>>   void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
>>>>
>>>> +void vm_tdx_finalize(struct kvm_vm *vm);
>>>> +
>>>>   #endif // SELFTESTS_TDX_TDX_UTIL_H
>>>> diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
>>>> index d8eab99d9333..4024587ed3c2 100644
>>>> --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
>>>> +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
>>>> @@ -274,3 +274,100 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
>>>>
>>>>        free(init_vm);
>>>>   }
>>>> +
>>>> +static void tdx_init_mem_region(struct kvm_vm *vm, void *source_pages,
>>>> +                             uint64_t gpa, uint64_t size)
>>>> +{
>>>> +     uint32_t metadata = KVM_TDX_MEASURE_MEMORY_REGION;
>>>> +     struct kvm_tdx_init_mem_region mem_region = {
>>>> +             .source_addr = (uint64_t)source_pages,
>>>> +             .gpa = gpa,
>>>> +             .nr_pages = size / PAGE_SIZE,
>>>> +     };
>>>> +     struct kvm_vcpu *vcpu;
>>>> +
>>>> +     vcpu = list_first_entry_or_null(&vm->vcpus, struct kvm_vcpu, list);
>>>> +
>>>> +     TEST_ASSERT((mem_region.nr_pages > 0) &&
>>>> +                 ((mem_region.nr_pages * PAGE_SIZE) == size),
>>>> +                 "Cannot add partial pages to the guest memory.\n");
>>>> +     TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) == 0,
>>>> +                 "Source memory buffer is not page aligned\n");
>>>> +     vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region);
>>>> +}
>>>> +
>>>> +static void tdx_init_pages(struct kvm_vm *vm, void *hva, uint64_t gpa,
>>>> +                        uint64_t size)
>>>> +{
>>>> +     void *scratch_page = calloc(1, PAGE_SIZE);
>>>> +     uint64_t nr_pages = size / PAGE_SIZE;
>>>> +     int i;
>>>> +
>>>> +     TEST_ASSERT(scratch_page,
>>>> +                 "Could not allocate memory for loading memory region");
>>>> +
>>>> +     for (i = 0; i < nr_pages; i++) {
>>>> +             memcpy(scratch_page, hva, PAGE_SIZE);
>>>> +
>>>> +             tdx_init_mem_region(vm, scratch_page, gpa, PAGE_SIZE);
>>>> +
>>>> +             hva += PAGE_SIZE;
>>>> +             gpa += PAGE_SIZE;
>>>> +     }
>>>> +
>>>> +     free(scratch_page);
>>>> +}
>>>> +
>>>> +static void load_td_private_memory(struct kvm_vm *vm)
>>>> +{
>>>> +     struct userspace_mem_region *region;
>>>> +     int ctr;
>>>> +
>>>> +     hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
>>>> +             const struct sparsebit *protected_pages = region->protected_phy_pages;
>>>> +             const vm_paddr_t gpa_base = region->region.guest_phys_addr;
>>>> +             const uint64_t hva_base = region->region.userspace_addr;
>>>> +             const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
>>>> +
>>>> +             sparsebit_idx_t i;
>>>> +             sparsebit_idx_t j;
>>>> +
>>>> +             if (!sparsebit_any_set(protected_pages))
>>>> +                     continue;
>>>> +
>>>> +             sparsebit_for_each_set_range(protected_pages, i, j) {
>>>> +                     const uint64_t size_to_load = (j - i + 1) * vm->page_size;
>>>> +                     const uint64_t offset =
>>>> +                             (i - lowest_page_in_region) * vm->page_size;
>>>> +                     const uint64_t hva = hva_base + offset;
>>>> +                     const uint64_t gpa = gpa_base + offset;
>>>> +
>>>> +                     vm_set_memory_attributes(vm, gpa, size_to_load,
>>>> +                                              KVM_MEMORY_ATTRIBUTE_PRIVATE);
>>>> +
>>>> +                     /*
>>>> +                      * Here, memory is being loaded from hva to gpa. If the memory
>>>> +                      * mapped to hva is also used to back gpa, then a copy has to be
>>>> +                      * made just for loading, since KVM_TDX_INIT_MEM_REGION ioctl
>>>> +                      * cannot encrypt memory in place.
>>>> +                      *
>>>> +                      * To determine if memory mapped to hva is also used to back
>>>> +                      * gpa, use a heuristic:
>>>> +                      *
>>>> +                      * If this memslot has guest_memfd, then this memslot should
>>>> +                      * have memory backed from two sources: hva for shared memory
>>>> +                      * and gpa will be backed by guest_memfd.
>>>> +                      */
>>>> +                     if (region->region.guest_memfd == -1)
>>> Why to pass !guest_memfd region to tdx_init_mem_region()?
>>>
>> Not sure I understand your comment.
>  From the implementation of tdx_init_pages(), it also invokes
> tdx_init_mem_region(), which further invokes ioctl KVM_TDX_INIT_MEM_REGION.
>
> However, if the region is with guest_memfd == -1, the ioctl
> KVM_TDX_INIT_MEM_REGION should fail as kvm_gmem_populate() won't succeed.
>
> So, I'm wondering why there's a need to for the case of
> "region->region.guest_memfd == -1".
>
> Or anything I missed?
I had the same question in v8
https://lore.kernel.org/lkml/4b7e7099-79da-4178-8f16-6780d8137ae1@linux.intel.com/

I guess the code path for non-guest_memfd is due to some old versions of TDX KVM
code before upstream. Currently, KVM doesn't support private memory from
non-guest_memfd backed memory.

>
>>>> +                             tdx_init_pages(vm, (void *)hva, gpa, size_to_load);
>>>> +                     else
>>>> +                             tdx_init_mem_region(vm, (void *)hva, gpa, size_to_load);
>>>> +             }
>>>> +     }
>>>> +}
>>>> +
>>>> +void vm_tdx_finalize(struct kvm_vm *vm)
>>>> +{
>>>> +     load_td_private_memory(vm);
>>>> +     vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
>>>> +}
>>>> --
>>>> 2.51.0.rc1.193.gad69d77794-goog
>>>>
>>>>


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM
  2025-08-27  2:24         ` Binbin Wu
@ 2025-08-27  2:44           ` Yan Zhao
  2025-08-27  3:52             ` Yan Zhao
  0 siblings, 1 reply; 62+ messages in thread
From: Yan Zhao @ 2025-08-27  2:44 UTC (permalink / raw)
  To: Binbin Wu
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Sean Christopherson, Ackerley Tng, Ryan Afranji, Andrew Jones,
	Isaku Yamahata, Erdem Aktas, Rick Edgecombe, Roger Wang,
	Oliver Upton, Pratik R. Sampat, Reinette Chatre, Ira Weiny,
	Chao Gao, Chenyi Qiang, linux-kernel, kvm

On Wed, Aug 27, 2025 at 10:24:03AM +0800, Binbin Wu wrote:
> 
> 
> On 8/26/2025 9:07 AM, Yan Zhao wrote:
> > On Mon, Aug 25, 2025 at 02:02:00PM -0500, Sagi Shahar wrote:
> > > On Mon, Aug 25, 2025 at 3:41 AM Yan Zhao <yan.y.zhao@intel.com> wrote:
> > > > On Wed, Aug 20, 2025 at 09:29:07PM -0700, Sagi Shahar wrote:
> > > > > From: Ackerley Tng <ackerleytng@google.com>
> > > > > 
> > > > > TDX protected memory needs to be measured and encrypted before it can be
> > > > > used by the guest. Traverse the VM's memory regions and initialize all
> > > > > the protected ranges by calling KVM_TDX_INIT_MEM_REGION.
> > > > > 
> > > > > Once all the memory is initialized, the VM can be finalized by calling
> > > > > KVM_TDX_FINALIZE_VM.
> > > > > 
> > > > > Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> > > > > Co-developed-by: Erdem Aktas <erdemaktas@google.com>
> > > > > Signed-off-by: Erdem Aktas <erdemaktas@google.com>
> > > > > Co-developed-by: Sagi Shahar <sagis@google.com>
> > > > > Signed-off-by: Sagi Shahar <sagis@google.com>
> > > > > ---
> > > > >   .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
> > > > >   .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 97 +++++++++++++++++++
> > > > >   2 files changed, 99 insertions(+)
> > > > > 
> > > > > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > > > index a2509959c7ce..2467b6c35557 100644
> > > > > --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > > > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > > > @@ -71,4 +71,6 @@ void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
> > > > >   void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
> > > > >   void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
> > > > > 
> > > > > +void vm_tdx_finalize(struct kvm_vm *vm);
> > > > > +
> > > > >   #endif // SELFTESTS_TDX_TDX_UTIL_H
> > > > > diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > > > index d8eab99d9333..4024587ed3c2 100644
> > > > > --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > > > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > > > @@ -274,3 +274,100 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
> > > > > 
> > > > >        free(init_vm);
> > > > >   }
> > > > > +
> > > > > +static void tdx_init_mem_region(struct kvm_vm *vm, void *source_pages,
> > > > > +                             uint64_t gpa, uint64_t size)
> > > > > +{
> > > > > +     uint32_t metadata = KVM_TDX_MEASURE_MEMORY_REGION;
> > > > > +     struct kvm_tdx_init_mem_region mem_region = {
> > > > > +             .source_addr = (uint64_t)source_pages,
> > > > > +             .gpa = gpa,
> > > > > +             .nr_pages = size / PAGE_SIZE,
> > > > > +     };
> > > > > +     struct kvm_vcpu *vcpu;
> > > > > +
> > > > > +     vcpu = list_first_entry_or_null(&vm->vcpus, struct kvm_vcpu, list);
> > > > > +
> > > > > +     TEST_ASSERT((mem_region.nr_pages > 0) &&
> > > > > +                 ((mem_region.nr_pages * PAGE_SIZE) == size),
> > > > > +                 "Cannot add partial pages to the guest memory.\n");
> > > > > +     TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) == 0,
> > > > > +                 "Source memory buffer is not page aligned\n");
> > > > > +     vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region);
> > > > > +}
> > > > > +
> > > > > +static void tdx_init_pages(struct kvm_vm *vm, void *hva, uint64_t gpa,
> > > > > +                        uint64_t size)
> > > > > +{
> > > > > +     void *scratch_page = calloc(1, PAGE_SIZE);
> > > > > +     uint64_t nr_pages = size / PAGE_SIZE;
> > > > > +     int i;
> > > > > +
> > > > > +     TEST_ASSERT(scratch_page,
> > > > > +                 "Could not allocate memory for loading memory region");
> > > > > +
> > > > > +     for (i = 0; i < nr_pages; i++) {
> > > > > +             memcpy(scratch_page, hva, PAGE_SIZE);
> > > > > +
> > > > > +             tdx_init_mem_region(vm, scratch_page, gpa, PAGE_SIZE);
> > > > > +
> > > > > +             hva += PAGE_SIZE;
> > > > > +             gpa += PAGE_SIZE;
> > > > > +     }
> > > > > +
> > > > > +     free(scratch_page);
> > > > > +}
> > > > > +
> > > > > +static void load_td_private_memory(struct kvm_vm *vm)
> > > > > +{
> > > > > +     struct userspace_mem_region *region;
> > > > > +     int ctr;
> > > > > +
> > > > > +     hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
> > > > > +             const struct sparsebit *protected_pages = region->protected_phy_pages;
> > > > > +             const vm_paddr_t gpa_base = region->region.guest_phys_addr;
> > > > > +             const uint64_t hva_base = region->region.userspace_addr;
> > > > > +             const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
> > > > > +
> > > > > +             sparsebit_idx_t i;
> > > > > +             sparsebit_idx_t j;
> > > > > +
> > > > > +             if (!sparsebit_any_set(protected_pages))
> > > > > +                     continue;
> > > > > +
> > > > > +             sparsebit_for_each_set_range(protected_pages, i, j) {
> > > > > +                     const uint64_t size_to_load = (j - i + 1) * vm->page_size;
> > > > > +                     const uint64_t offset =
> > > > > +                             (i - lowest_page_in_region) * vm->page_size;
> > > > > +                     const uint64_t hva = hva_base + offset;
> > > > > +                     const uint64_t gpa = gpa_base + offset;
> > > > > +
> > > > > +                     vm_set_memory_attributes(vm, gpa, size_to_load,
> > > > > +                                              KVM_MEMORY_ATTRIBUTE_PRIVATE);
> > > > > +
> > > > > +                     /*
> > > > > +                      * Here, memory is being loaded from hva to gpa. If the memory
> > > > > +                      * mapped to hva is also used to back gpa, then a copy has to be
> > > > > +                      * made just for loading, since KVM_TDX_INIT_MEM_REGION ioctl
> > > > > +                      * cannot encrypt memory in place.
> > > > > +                      *
> > > > > +                      * To determine if memory mapped to hva is also used to back
> > > > > +                      * gpa, use a heuristic:
> > > > > +                      *
> > > > > +                      * If this memslot has guest_memfd, then this memslot should
> > > > > +                      * have memory backed from two sources: hva for shared memory
> > > > > +                      * and gpa will be backed by guest_memfd.
> > > > > +                      */
> > > > > +                     if (region->region.guest_memfd == -1)
> > > > Why to pass !guest_memfd region to tdx_init_mem_region()?
> > > > 
> > > Not sure I understand your comment.
> >  From the implementation of tdx_init_pages(), it also invokes
> > tdx_init_mem_region(), which further invokes ioctl KVM_TDX_INIT_MEM_REGION.
> > 
> > However, if the region is with guest_memfd == -1, the ioctl
> > KVM_TDX_INIT_MEM_REGION should fail as kvm_gmem_populate() won't succeed.
> > 
> > So, I'm wondering why there's a need to for the case of
> > "region->region.guest_memfd == -1".
> > 
> > Or anything I missed?
> I had the same question in v8
> https://lore.kernel.org/lkml/4b7e7099-79da-4178-8f16-6780d8137ae1@linux.intel.com/
I agree with you.
In patch "KVM: selftests: TDX: Test LOG_DIRTY_PAGES flag to a non-GUEST_MEMFD
memslot", virt_map_shared() prevents the non-guest_memfd region from being
searched by the load_td_private_memory().
Otherwise, the tdx_init_mem_region() would fail on this region.

> I guess the code path for non-guest_memfd is due to some old versions of TDX KVM
> code before upstream. Currently, KVM doesn't support private memory from
> non-guest_memfd backed memory.
I guess so. Maybe just drop this case and assert?

TEST_ASSERT(region->region.guest_memfd != -1, "TDX private memory only supports
guest_memfd backend\n");

> > 
> > > > > +                             tdx_init_pages(vm, (void *)hva, gpa, size_to_load);
> > > > > +                     else
> > > > > +                             tdx_init_mem_region(vm, (void *)hva, gpa, size_to_load);
> > > > > +             }
> > > > > +     }
> > > > > +}
> > > > > +
> > > > > +void vm_tdx_finalize(struct kvm_vm *vm)
> > > > > +{
> > > > > +     load_td_private_memory(vm);
> > > > > +     vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
> > > > > +}
> > > > > --
> > > > > 2.51.0.rc1.193.gad69d77794-goog
> > > > > 
> > > > > 
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM
  2025-08-27  2:44           ` Yan Zhao
@ 2025-08-27  3:52             ` Yan Zhao
  0 siblings, 0 replies; 62+ messages in thread
From: Yan Zhao @ 2025-08-27  3:52 UTC (permalink / raw)
  To: Binbin Wu, Sagi Shahar, linux-kselftest, Paolo Bonzini,
	Shuah Khan, Sean Christopherson, Ackerley Tng, Ryan Afranji,
	Andrew Jones, Isaku Yamahata, Erdem Aktas, Rick Edgecombe,
	Roger Wang, Oliver Upton, Pratik R. Sampat, Reinette Chatre,
	Ira Weiny, Chao Gao, Chenyi Qiang, linux-kernel, kvm

On Wed, Aug 27, 2025 at 10:44:58AM +0800, Yan Zhao wrote:
> On Wed, Aug 27, 2025 at 10:24:03AM +0800, Binbin Wu wrote:
> > 
> > 
> > On 8/26/2025 9:07 AM, Yan Zhao wrote:
> > > On Mon, Aug 25, 2025 at 02:02:00PM -0500, Sagi Shahar wrote:
> > > > On Mon, Aug 25, 2025 at 3:41 AM Yan Zhao <yan.y.zhao@intel.com> wrote:
> > > > > On Wed, Aug 20, 2025 at 09:29:07PM -0700, Sagi Shahar wrote:
> > > > > > From: Ackerley Tng <ackerleytng@google.com>
> > > > > > 
> > > > > > TDX protected memory needs to be measured and encrypted before it can be
> > > > > > used by the guest. Traverse the VM's memory regions and initialize all
> > > > > > the protected ranges by calling KVM_TDX_INIT_MEM_REGION.
> > > > > > 
> > > > > > Once all the memory is initialized, the VM can be finalized by calling
> > > > > > KVM_TDX_FINALIZE_VM.
> > > > > > 
> > > > > > Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> > > > > > Co-developed-by: Erdem Aktas <erdemaktas@google.com>
> > > > > > Signed-off-by: Erdem Aktas <erdemaktas@google.com>
> > > > > > Co-developed-by: Sagi Shahar <sagis@google.com>
> > > > > > Signed-off-by: Sagi Shahar <sagis@google.com>
> > > > > > ---
> > > > > >   .../selftests/kvm/include/x86/tdx/tdx_util.h  |  2 +
> > > > > >   .../selftests/kvm/lib/x86/tdx/tdx_util.c      | 97 +++++++++++++++++++
> > > > > >   2 files changed, 99 insertions(+)
> > > > > > 
> > > > > > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > > > > index a2509959c7ce..2467b6c35557 100644
> > > > > > --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > > > > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
> > > > > > @@ -71,4 +71,6 @@ void vm_tdx_load_common_boot_parameters(struct kvm_vm *vm);
> > > > > >   void vm_tdx_load_vcpu_boot_parameters(struct kvm_vm *vm, struct kvm_vcpu *vcpu);
> > > > > >   void vm_tdx_set_vcpu_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
> > > > > > 
> > > > > > +void vm_tdx_finalize(struct kvm_vm *vm);
> > > > > > +
> > > > > >   #endif // SELFTESTS_TDX_TDX_UTIL_H
> > > > > > diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > > > > index d8eab99d9333..4024587ed3c2 100644
> > > > > > --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > > > > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > > > > > @@ -274,3 +274,100 @@ void vm_tdx_init_vm(struct kvm_vm *vm, uint64_t attributes)
> > > > > > 
> > > > > >        free(init_vm);
> > > > > >   }
> > > > > > +
> > > > > > +static void tdx_init_mem_region(struct kvm_vm *vm, void *source_pages,
> > > > > > +                             uint64_t gpa, uint64_t size)
> > > > > > +{
> > > > > > +     uint32_t metadata = KVM_TDX_MEASURE_MEMORY_REGION;
> > > > > > +     struct kvm_tdx_init_mem_region mem_region = {
> > > > > > +             .source_addr = (uint64_t)source_pages,
> > > > > > +             .gpa = gpa,
> > > > > > +             .nr_pages = size / PAGE_SIZE,
> > > > > > +     };
> > > > > > +     struct kvm_vcpu *vcpu;
> > > > > > +
> > > > > > +     vcpu = list_first_entry_or_null(&vm->vcpus, struct kvm_vcpu, list);
> > > > > > +
> > > > > > +     TEST_ASSERT((mem_region.nr_pages > 0) &&
> > > > > > +                 ((mem_region.nr_pages * PAGE_SIZE) == size),
> > > > > > +                 "Cannot add partial pages to the guest memory.\n");
> > > > > > +     TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) == 0,
> > > > > > +                 "Source memory buffer is not page aligned\n");
> > > > > > +     vm_tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region);
> > > > > > +}
> > > > > > +
> > > > > > +static void tdx_init_pages(struct kvm_vm *vm, void *hva, uint64_t gpa,
> > > > > > +                        uint64_t size)
> > > > > > +{
> > > > > > +     void *scratch_page = calloc(1, PAGE_SIZE);
> > > > > > +     uint64_t nr_pages = size / PAGE_SIZE;
> > > > > > +     int i;
> > > > > > +
> > > > > > +     TEST_ASSERT(scratch_page,
> > > > > > +                 "Could not allocate memory for loading memory region");
> > > > > > +
> > > > > > +     for (i = 0; i < nr_pages; i++) {
> > > > > > +             memcpy(scratch_page, hva, PAGE_SIZE);
> > > > > > +
> > > > > > +             tdx_init_mem_region(vm, scratch_page, gpa, PAGE_SIZE);
> > > > > > +
> > > > > > +             hva += PAGE_SIZE;
> > > > > > +             gpa += PAGE_SIZE;
> > > > > > +     }
> > > > > > +
> > > > > > +     free(scratch_page);
> > > > > > +}
> > > > > > +
> > > > > > +static void load_td_private_memory(struct kvm_vm *vm)
> > > > > > +{
> > > > > > +     struct userspace_mem_region *region;
> > > > > > +     int ctr;
> > > > > > +
> > > > > > +     hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
> > > > > > +             const struct sparsebit *protected_pages = region->protected_phy_pages;
> > > > > > +             const vm_paddr_t gpa_base = region->region.guest_phys_addr;
> > > > > > +             const uint64_t hva_base = region->region.userspace_addr;
> > > > > > +             const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
> > > > > > +
> > > > > > +             sparsebit_idx_t i;
> > > > > > +             sparsebit_idx_t j;
> > > > > > +
> > > > > > +             if (!sparsebit_any_set(protected_pages))
> > > > > > +                     continue;
> > > > > > +
> > > > > > +             sparsebit_for_each_set_range(protected_pages, i, j) {
> > > > > > +                     const uint64_t size_to_load = (j - i + 1) * vm->page_size;
> > > > > > +                     const uint64_t offset =
> > > > > > +                             (i - lowest_page_in_region) * vm->page_size;
> > > > > > +                     const uint64_t hva = hva_base + offset;
> > > > > > +                     const uint64_t gpa = gpa_base + offset;
> > > > > > +
> > > > > > +                     vm_set_memory_attributes(vm, gpa, size_to_load,
> > > > > > +                                              KVM_MEMORY_ATTRIBUTE_PRIVATE);
> > > > > > +
> > > > > > +                     /*
> > > > > > +                      * Here, memory is being loaded from hva to gpa. If the memory
> > > > > > +                      * mapped to hva is also used to back gpa, then a copy has to be
> > > > > > +                      * made just for loading, since KVM_TDX_INIT_MEM_REGION ioctl
> > > > > > +                      * cannot encrypt memory in place.
> > > > > > +                      *
> > > > > > +                      * To determine if memory mapped to hva is also used to back
> > > > > > +                      * gpa, use a heuristic:
> > > > > > +                      *
> > > > > > +                      * If this memslot has guest_memfd, then this memslot should
> > > > > > +                      * have memory backed from two sources: hva for shared memory
> > > > > > +                      * and gpa will be backed by guest_memfd.
> > > > > > +                      */
> > > > > > +                     if (region->region.guest_memfd == -1)
> > > > > Why to pass !guest_memfd region to tdx_init_mem_region()?
> > > > > 
> > > > Not sure I understand your comment.
> > >  From the implementation of tdx_init_pages(), it also invokes
> > > tdx_init_mem_region(), which further invokes ioctl KVM_TDX_INIT_MEM_REGION.
> > > 
> > > However, if the region is with guest_memfd == -1, the ioctl
> > > KVM_TDX_INIT_MEM_REGION should fail as kvm_gmem_populate() won't succeed.
> > > 
> > > So, I'm wondering why there's a need to for the case of
> > > "region->region.guest_memfd == -1".
> > > 
> > > Or anything I missed?
> > I had the same question in v8
> > https://lore.kernel.org/lkml/4b7e7099-79da-4178-8f16-6780d8137ae1@linux.intel.com/
> I agree with you.
> In patch "KVM: selftests: TDX: Test LOG_DIRTY_PAGES flag to a non-GUEST_MEMFD
> memslot", virt_map_shared() prevents the non-guest_memfd region from being
> searched by the load_td_private_memory().
Specifically, there's no __vm_phy_pages_alloc() being invoked with protected
being true for the non-guest-memfd region in
verify_log_dirty_pages_flag_on_non_gmemfd_slot().

> Otherwise, the tdx_init_mem_region() would fail on this region.
> 
> > I guess the code path for non-guest_memfd is due to some old versions of TDX KVM
> > code before upstream. Currently, KVM doesn't support private memory from
> > non-guest_memfd backed memory.
> I guess so. Maybe just drop this case and assert?
> 
> TEST_ASSERT(region->region.guest_memfd != -1, "TDX private memory only supports
> guest_memfd backend\n");
> 
> > > 
> > > > > > +                             tdx_init_pages(vm, (void *)hva, gpa, size_to_load);
> > > > > > +                     else
> > > > > > +                             tdx_init_mem_region(vm, (void *)hva, gpa, size_to_load);
> > > > > > +             }
> > > > > > +     }
> > > > > > +}
> > > > > > +
> > > > > > +void vm_tdx_finalize(struct kvm_vm *vm)
> > > > > > +{
> > > > > > +     load_td_private_memory(vm);
> > > > > > +     vm_tdx_vm_ioctl(vm, KVM_TDX_FINALIZE_VM, 0, NULL);
> > > > > > +}
> > > > > > --
> > > > > > 2.51.0.rc1.193.gad69d77794-goog
> > > > > > 
> > > > > > 
> > 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX
  2025-08-21  4:29 ` [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX Sagi Shahar
@ 2025-08-27  7:18   ` Binbin Wu
  2025-09-02 15:45     ` Sean Christopherson
  0 siblings, 1 reply; 62+ messages in thread
From: Binbin Wu @ 2025-08-27  7:18 UTC (permalink / raw)
  To: Sagi Shahar, Sean Christopherson
  Cc: linux-kselftest, Paolo Bonzini, Shuah Khan, Ackerley Tng,
	Ryan Afranji, Andrew Jones, Isaku Yamahata, Erdem Aktas,
	Rick Edgecombe, Roger Wang, Oliver Upton, Pratik R. Sampat,
	Reinette Chatre, Ira Weiny, Chao Gao, Chenyi Qiang, linux-kernel,
	kvm



On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> From: Ackerley Tng <ackerleytng@google.com>
>
> ucalls for non-Coco VMs work by having the guest write to the rdi
> register, then perform an io instruction to exit to the host. The host
> then reads rdi using kvm_get_regs().
>
> CPU registers can't be read using kvm_get_regs() for TDX, so TDX
> guests use MMIO to pass the struct ucall's hva to the host. MMIO was
> chosen because it is one of the simplest (hence unlikely to fail)
> mechanisms that support passing 8 bytes from guest to host.
>
> Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> Co-developed-by: Sagi Shahar <sagis@google.com>
> Signed-off-by: Sagi Shahar <sagis@google.com>
> ---
>   .../testing/selftests/kvm/include/x86/ucall.h |  4 +-
>   tools/testing/selftests/kvm/lib/x86/ucall.c   | 45 ++++++++++++++++---
>   2 files changed, 41 insertions(+), 8 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/include/x86/ucall.h b/tools/testing/selftests/kvm/include/x86/ucall.h
> index d3825dcc3cd9..0494a4a21557 100644
> --- a/tools/testing/selftests/kvm/include/x86/ucall.h
> +++ b/tools/testing/selftests/kvm/include/x86/ucall.h
> @@ -6,8 +6,6 @@
>   
>   #define UCALL_EXIT_REASON       KVM_EXIT_IO
>   
> -static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa)
> -{
> -}
> +void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa);
>   
>   #endif
> diff --git a/tools/testing/selftests/kvm/lib/x86/ucall.c b/tools/testing/selftests/kvm/lib/x86/ucall.c
> index 1265cecc7dd1..0ad24baaa3c4 100644
> --- a/tools/testing/selftests/kvm/lib/x86/ucall.c
> +++ b/tools/testing/selftests/kvm/lib/x86/ucall.c
> @@ -5,11 +5,34 @@
>    * Copyright (C) 2018, Red Hat, Inc.
>    */
>   #include "kvm_util.h"
> +#include "tdx/tdx.h"
>   
>   #define UCALL_PIO_PORT ((uint16_t)0x1000)
>   
> +static uint8_t vm_type;
> +static vm_paddr_t host_ucall_mmio_gpa;
> +static vm_paddr_t ucall_mmio_gpa;
> +
> +void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa)
> +{
> +	vm_type = vm->type;
> +	sync_global_to_guest(vm, vm_type);
> +
> +	host_ucall_mmio_gpa = ucall_mmio_gpa = mmio_gpa;
> +
> +	if (vm_type == KVM_X86_TDX_VM)
> +		ucall_mmio_gpa |= vm->arch.s_bit;
> +
> +	sync_global_to_guest(vm, ucall_mmio_gpa);
> +}
> +
>   void ucall_arch_do_ucall(vm_vaddr_t uc)
>   {
> +	if (vm_type == KVM_X86_TDX_VM) {
> +		tdg_vp_vmcall_ve_request_mmio_write(ucall_mmio_gpa, 8, uc);
> +		return;
> +	}
> +
>   	/*
>   	 * FIXME: Revert this hack (the entire commit that added it) once nVMX
>   	 * preserves L2 GPRs across a nested VM-Exit.  If a ucall from L2, e.g.
> @@ -46,11 +69,23 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
>   {
>   	struct kvm_run *run = vcpu->run;
>   
> -	if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
> -		struct kvm_regs regs;
> +	switch (vm_type) {
> +	case KVM_X86_TDX_VM:
> +		if (vcpu->run->exit_reason == KVM_EXIT_MMIO &&
> +		    vcpu->run->mmio.phys_addr == host_ucall_mmio_gpa &&
> +		    vcpu->run->mmio.len == 8 && vcpu->run->mmio.is_write) {
> +			uint64_t data = *(uint64_t *)vcpu->run->mmio.data;
> +
> +			return (void *)data;
> +		}
> +		return NULL;

My first thought was how did SEV_ES or SNP work for this since they are not
able to get RDI neither.
Then I had a check in sev_smoke_test.c, both guest_sev_es_code() and
guest_snp_code() call GUEST_ASSERT(), which finally calls ucall_assert(), but
in test_sev(), the code doesn't handle ucall for SEV_ES or SNP.
Does it mean GUEST_ASSERT() is currently not working and ignored for SEV_ES
and SNP? Or did I miss anything?

> +	default:
> +		if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
> +			struct kvm_regs regs;
>   
> -		vcpu_regs_get(vcpu, &regs);
> -		return (void *)regs.rdi;
> +			vcpu_regs_get(vcpu, &regs);
> +			return (void *)regs.rdi;
> +		}
> +		return NULL;
>   	}
> -	return NULL;
>   }


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX
  2025-08-27  7:18   ` Binbin Wu
@ 2025-09-02 15:45     ` Sean Christopherson
  2025-09-03  1:07       ` Binbin Wu
  0 siblings, 1 reply; 62+ messages in thread
From: Sean Christopherson @ 2025-09-02 15:45 UTC (permalink / raw)
  To: Binbin Wu
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm

On Wed, Aug 27, 2025, Binbin Wu wrote:
> On 8/21/2025 12:29 PM, Sagi Shahar wrote:
> > @@ -46,11 +69,23 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
> >   {
> >   	struct kvm_run *run = vcpu->run;
> > -	if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
> > -		struct kvm_regs regs;
> > +	switch (vm_type) {
> > +	case KVM_X86_TDX_VM:
> > +		if (vcpu->run->exit_reason == KVM_EXIT_MMIO &&
> > +		    vcpu->run->mmio.phys_addr == host_ucall_mmio_gpa &&
> > +		    vcpu->run->mmio.len == 8 && vcpu->run->mmio.is_write) {
> > +			uint64_t data = *(uint64_t *)vcpu->run->mmio.data;
> > +
> > +			return (void *)data;
> > +		}
> > +		return NULL;
> 
> My first thought was how did SEV_ES or SNP work for this since they are not
> able to get RDI neither.
> Then I had a check in sev_smoke_test.c, both guest_sev_es_code() and
> guest_snp_code() call GUEST_ASSERT(), which finally calls ucall_assert(), but
> in test_sev(), the code doesn't handle ucall for SEV_ES or SNP.
> Does it mean GUEST_ASSERT() is currently not working and ignored for SEV_ES
> and SNP? Or did I miss anything?

GUEST_ASSERT() "works" for -ES and -SNP in the sense that it generates as test
failure due to the #VC not being handled (leads to SHUTDOWN).  But you're correct
that ucall isn't functional yet.  x86/sev_smoke_test.c fudges around lack of ucall
by using the GHCB MSR protocol to signal "done".

        /*
         * TODO: Add GHCB and ucall support for SEV-ES guests.  For now, simply
         * force "termination" to signal "done" via the GHCB MSR protocol.
         */
        wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
        vmgexit();

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX
  2025-09-02 15:45     ` Sean Christopherson
@ 2025-09-03  1:07       ` Binbin Wu
  0 siblings, 0 replies; 62+ messages in thread
From: Binbin Wu @ 2025-09-03  1:07 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Sagi Shahar, linux-kselftest, Paolo Bonzini, Shuah Khan,
	Ackerley Tng, Ryan Afranji, Andrew Jones, Isaku Yamahata,
	Erdem Aktas, Rick Edgecombe, Roger Wang, Oliver Upton,
	Pratik R. Sampat, Reinette Chatre, Ira Weiny, Chao Gao,
	Chenyi Qiang, linux-kernel, kvm



On 9/2/2025 11:45 PM, Sean Christopherson wrote:
> On Wed, Aug 27, 2025, Binbin Wu wrote:
>> On 8/21/2025 12:29 PM, Sagi Shahar wrote:
>>> @@ -46,11 +69,23 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
>>>    {
>>>    	struct kvm_run *run = vcpu->run;
>>> -	if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
>>> -		struct kvm_regs regs;
>>> +	switch (vm_type) {
>>> +	case KVM_X86_TDX_VM:
>>> +		if (vcpu->run->exit_reason == KVM_EXIT_MMIO &&
>>> +		    vcpu->run->mmio.phys_addr == host_ucall_mmio_gpa &&
>>> +		    vcpu->run->mmio.len == 8 && vcpu->run->mmio.is_write) {
>>> +			uint64_t data = *(uint64_t *)vcpu->run->mmio.data;
>>> +
>>> +			return (void *)data;
>>> +		}
>>> +		return NULL;
>> My first thought was how did SEV_ES or SNP work for this since they are not
>> able to get RDI neither.
>> Then I had a check in sev_smoke_test.c, both guest_sev_es_code() and
>> guest_snp_code() call GUEST_ASSERT(), which finally calls ucall_assert(), but
>> in test_sev(), the code doesn't handle ucall for SEV_ES or SNP.
>> Does it mean GUEST_ASSERT() is currently not working and ignored for SEV_ES
>> and SNP? Or did I miss anything?
> GUEST_ASSERT() "works" for -ES and -SNP in the sense that it generates as test
> failure due to the #VC not being handled (leads to SHUTDOWN).  But you're correct
> that ucall isn't functional yet.  x86/sev_smoke_test.c fudges around lack of ucall
> by using the GHCB MSR protocol to signal "done".
>
>          /*
>           * TODO: Add GHCB and ucall support for SEV-ES guests.  For now, simply
>           * force "termination" to signal "done" via the GHCB MSR protocol.
>           */
>          wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
>          vmgexit();
>
OK, thanks for the explanation!


^ permalink raw reply	[flat|nested] 62+ messages in thread

end of thread, other threads:[~2025-09-03  1:08 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-21  4:28 [PATCH v9 00/19] TDX KVM selftests Sagi Shahar
2025-08-21  4:28 ` [PATCH v9 01/19] KVM: selftests: Include overflow.h instead of redefining is_signed_type() Sagi Shahar
2025-08-21 14:16   ` Sean Christopherson
2025-08-21 14:37   ` Ira Weiny
2025-08-21 14:42     ` Sean Christopherson
2025-08-21  4:28 ` [PATCH v9 02/19] KVM: selftests: Allocate pgd in virt_map() as necessary Sagi Shahar
2025-08-21 14:45   ` Ira Weiny
2025-08-26  2:36   ` Binbin Wu
2025-08-21  4:28 ` [PATCH v9 03/19] KVM: selftests: Expose functions to get default sregs values Sagi Shahar
2025-08-26  2:36   ` Binbin Wu
2025-08-26 14:05     ` Sean Christopherson
2025-08-21  4:28 ` [PATCH v9 04/19] KVM: selftests: Expose function to allocate guest vCPU stack Sagi Shahar
2025-08-21 22:00   ` Ira Weiny
2025-08-21 22:24     ` Sagi Shahar
2025-08-26  5:39   ` Binbin Wu
2025-08-26 16:00     ` Sagi Shahar
2025-08-26 17:16     ` Sean Christopherson
2025-08-21  4:28 ` [PATCH v9 05/19] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Sagi Shahar
2025-08-21 22:05   ` Ira Weiny
2025-08-21 22:30     ` Sagi Shahar
2025-08-26  5:51   ` Binbin Wu
2025-08-26 16:04     ` Sagi Shahar
2025-08-21  4:28 ` [PATCH v9 06/19] KVM: selftests: Expose segment definitons to assembly files Sagi Shahar
2025-08-21 20:04   ` Ira Weiny
2025-08-21  4:29 ` [PATCH v9 07/19] KVM: selftests: Add kbuild definitons Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 08/19] KVM: selftests: Define structs to pass parameters to TDX boot code Sagi Shahar
2025-08-26  6:52   ` Binbin Wu
2025-08-26 16:10     ` Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 09/19] KVM: selftests: Add " Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 10/19] KVM: selftests: Set up TDX boot code region Sagi Shahar
2025-08-25  5:32   ` Yan Zhao
2025-08-26 16:38     ` Sean Christopherson
2025-08-27  1:36       ` Yan Zhao
2025-08-21  4:29 ` [PATCH v9 11/19] KVM: selftests: Set up TDX boot parameters region Sagi Shahar
2025-08-26  8:36   ` Binbin Wu
2025-08-26 16:17     ` Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 12/19] KVM: selftests: Add helper to initialize TDX VM Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 13/19] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration Sagi Shahar
2025-08-26  9:22   ` Binbin Wu
2025-08-21  4:29 ` [PATCH v9 14/19] KVM: selftests: Add helpers to init TDX memory and finalize VM Sagi Shahar
2025-08-25  8:40   ` Yan Zhao
2025-08-25 19:02     ` Sagi Shahar
2025-08-26  1:07       ` Yan Zhao
2025-08-27  2:24         ` Binbin Wu
2025-08-27  2:44           ` Yan Zhao
2025-08-27  3:52             ` Yan Zhao
2025-08-21  4:29 ` [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation Sagi Shahar
2025-08-26  8:28   ` Chenyi Qiang
2025-08-26 16:12     ` Sagi Shahar
2025-08-26 17:31   ` Sean Christopherson
2025-08-26 20:16     ` Ira Weiny
2025-08-26 20:29       ` Sagi Shahar
2025-08-26 20:30         ` Sagi Shahar
2025-08-26 21:31           ` Sean Christopherson
2025-08-26 21:38             ` Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 16/19] KVM: selftests: Add support for TDX TDCALL from guest Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 17/19] KVM: selftests: Add wrapper for TDX MMIO " Sagi Shahar
2025-08-21  4:29 ` [PATCH v9 18/19] KVM: selftests: Add ucall support for TDX Sagi Shahar
2025-08-27  7:18   ` Binbin Wu
2025-09-02 15:45     ` Sean Christopherson
2025-09-03  1:07       ` Binbin Wu
2025-08-21  4:29 ` [PATCH v9 19/19] KVM: selftests: Add TDX lifecycle test Sagi Shahar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).