[PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation

Sagi Shahar posted 19 patches 1 month, 1 week ago
There is a newer version of this series
[PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Sagi Shahar 1 month, 1 week ago
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
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Sean Christopherson 1 month, 1 week ago
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).
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Ira Weiny 1 month, 1 week ago
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).
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Sagi Shahar 1 month, 1 week ago
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).
>
>
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Sagi Shahar 1 month, 1 week ago
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).
> >
> >
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Sean Christopherson 1 month, 1 week ago
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);
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Sagi Shahar 1 month, 1 week ago
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);
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Chenyi Qiang 1 month, 1 week ago

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(-)
>
Re: [PATCH v9 15/19] KVM: selftests: Hook TDX support to vm and vcpu creation
Posted by Sagi Shahar 1 month, 1 week ago
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(-)
> >
>