* [PATCH v14 01/22] KVM: selftests: Add macros to simplify creating VM shapes for non-default types
2026-07-22 23:13 [PATCH v14 00/22] TDX KVM selftests Lisa Wang
@ 2026-07-22 23:13 ` Lisa Wang
2026-08-19 7:44 ` Peter Fang
2026-09-08 16:58 ` Ackerley Tng
2026-07-22 23:13 ` [PATCH v14 02/22] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Lisa Wang
` (21 subsequent siblings)
22 siblings, 2 replies; 98+ messages in thread
From: Lisa Wang @ 2026-07-22 23:13 UTC (permalink / raw)
To: Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Ira Weiny, Isaku Yamahata,
Kiryl Shutsemau, linux-kselftest, Paolo Bonzini, Pratik R. Sampat,
Reinette Chatre, Rick Edgecombe, Roger Wang, Ryan Afranji,
Sagi Shahar, Sean Christopherson, Shuah Khan, Xiaoyao Li,
Oliver Upton
Cc: Jeremiah McReynolds, kvm, linux-coco, linux-kernel, x86,
Lisa Wang
From: Sean Christopherson <seanjc@google.com>
Add VM_TYPE() and __VM_SHAPE() macros to create a vm_shape structure given
a type (and mode), and use the macros to define VM_SHAPE_{SEV,SEV_ES,SNP}
shapes for x86's SEV family of VM shapes. Providing common infrastructure
will avoid having to copy+paste vm_sev_create_with_one_vcpu() for TDX.
Use the new SEV+ shapes and drop vm_sev_create_with_one_vcpu().
Opportunistically move the existing VM_SHAPE() (now __VM_SHAPE()) macro
below the definitions of VM_MODE_DEFAULT so that all of the SHAPE/TYPE
macros are bundled together.
No functional change intended.
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/include/kvm_util.h | 27 ++++++++-------
.../testing/selftests/kvm/include/x86/processor.h | 4 +++
tools/testing/selftests/kvm/include/x86/sev.h | 2 --
tools/testing/selftests/kvm/lib/x86/sev.c | 16 ---------
tools/testing/selftests/kvm/x86/sev_smoke_test.c | 40 +++++++++++-----------
5 files changed, 39 insertions(+), 50 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index dc70c6da63fa..2a3923dad570 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -221,18 +221,6 @@ struct vm_shape {
kvm_static_assert(sizeof(struct vm_shape) == sizeof(u64));
-#define VM_TYPE_DEFAULT 0
-
-#define VM_SHAPE(__mode) \
-({ \
- struct vm_shape shape = { \
- .mode = (__mode), \
- .type = VM_TYPE_DEFAULT \
- }; \
- \
- shape; \
-})
-
extern enum vm_guest_mode vm_mode_default;
#if defined(__aarch64__)
@@ -270,8 +258,23 @@ extern enum vm_guest_mode vm_mode_default;
#endif
+#define VM_TYPE_DEFAULT 0
+
+#define __VM_SHAPE(__mode, __type) \
+({ \
+ struct vm_shape shape = { \
+ .mode = (__mode), \
+ .type = (__type), \
+ }; \
+ \
+ shape; \
+})
+
+#define VM_SHAPE(__mode) __VM_SHAPE(__mode, VM_TYPE_DEFAULT)
#define VM_SHAPE_DEFAULT VM_SHAPE(VM_MODE_DEFAULT)
+#define VM_TYPE(__type) __VM_SHAPE(VM_MODE_DEFAULT, __type)
+
#define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT)
#define PTES_PER_MIN_PAGE ptes_per_page(MIN_PAGE_SIZE)
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 77f576ee7789..0aa6eecfcbde 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -365,6 +365,10 @@ static inline unsigned int x86_model(unsigned int eax)
return ((eax >> 12) & 0xf0) | ((eax >> 4) & 0x0f);
}
+#define VM_SHAPE_SEV VM_TYPE(KVM_X86_SEV_VM)
+#define VM_SHAPE_SEV_ES VM_TYPE(KVM_X86_SEV_ES_VM)
+#define VM_SHAPE_SNP VM_TYPE(KVM_X86_SNP_VM)
+
#define PHYSICAL_PAGE_MASK GENMASK_ULL(51, 12)
#define PAGE_SHIFT 12
diff --git a/tools/testing/selftests/kvm/include/x86/sev.h b/tools/testing/selftests/kvm/include/x86/sev.h
index 1af44c151d60..944c59dbe510 100644
--- a/tools/testing/selftests/kvm/include/x86/sev.h
+++ b/tools/testing/selftests/kvm/include/x86/sev.h
@@ -53,8 +53,6 @@ void snp_vm_launch_start(struct kvm_vm *vm, u64 policy);
void snp_vm_launch_update(struct kvm_vm *vm);
void snp_vm_launch_finish(struct kvm_vm *vm);
-struct kvm_vm *vm_sev_create_with_one_vcpu(u32 type, void *guest_code,
- struct kvm_vcpu **cpu);
void vm_sev_launch(struct kvm_vm *vm, u64 policy, u8 *measurement);
kvm_static_assert(SEV_RET_SUCCESS == 0);
diff --git a/tools/testing/selftests/kvm/lib/x86/sev.c b/tools/testing/selftests/kvm/lib/x86/sev.c
index 93f916903461..95d8520eea34 100644
--- a/tools/testing/selftests/kvm/lib/x86/sev.c
+++ b/tools/testing/selftests/kvm/lib/x86/sev.c
@@ -158,22 +158,6 @@ void snp_vm_launch_finish(struct kvm_vm *vm)
vm_sev_ioctl(vm, KVM_SEV_SNP_LAUNCH_FINISH, &launch_finish);
}
-struct kvm_vm *vm_sev_create_with_one_vcpu(u32 type, void *guest_code,
- struct kvm_vcpu **cpu)
-{
- struct vm_shape shape = {
- .mode = VM_MODE_DEFAULT,
- .type = type,
- };
- struct kvm_vm *vm;
- struct kvm_vcpu *cpus[1];
-
- vm = __vm_create_with_vcpus(shape, 1, 0, guest_code, cpus);
- *cpu = cpus[0];
-
- return vm;
-}
-
void vm_sev_launch(struct kvm_vm *vm, u64 policy, u8 *measurement)
{
if (is_sev_snp_vm(vm)) {
diff --git a/tools/testing/selftests/kvm/x86/sev_smoke_test.c b/tools/testing/selftests/kvm/x86/sev_smoke_test.c
index 1a49ee391586..fe2c438882ae 100644
--- a/tools/testing/selftests/kvm/x86/sev_smoke_test.c
+++ b/tools/testing/selftests/kvm/x86/sev_smoke_test.c
@@ -104,7 +104,7 @@ static void compare_xsave(u8 *from_host, u8 *from_guest)
abort();
}
-static void test_sync_vmsa(u32 type, u64 policy)
+static void test_sync_vmsa(struct vm_shape shape, u64 policy)
{
struct kvm_vcpu *vcpu;
struct kvm_vm *vm;
@@ -114,7 +114,7 @@ static void test_sync_vmsa(u32 type, u64 policy)
double x87val = M_PI;
struct kvm_xsave __attribute__((aligned(64))) xsave = { 0 };
- vm = vm_sev_create_with_one_vcpu(type, guest_code_xsave, &vcpu);
+ vm = vm_create_shape_with_one_vcpu(shape, &vcpu, guest_code_xsave);
gva = vm_alloc_shared(vm, PAGE_SIZE, KVM_UTIL_MIN_VADDR,
MEM_REGION_TEST_DATA);
hva = addr_gva2hva(vm, gva);
@@ -150,13 +150,13 @@ static void test_sync_vmsa(u32 type, u64 policy)
kvm_vm_free(vm);
}
-static void test_sev(void *guest_code, u32 type, u64 policy)
+static void test_sev(void *guest_code, struct vm_shape shape, u64 policy)
{
struct kvm_vcpu *vcpu;
struct kvm_vm *vm;
struct ucall uc;
- vm = vm_sev_create_with_one_vcpu(type, guest_code, &vcpu);
+ vm = vm_create_shape_with_one_vcpu(shape, &vcpu, guest_code);
/* TODO: Validate the measurement is as expected. */
vm_sev_launch(vm, policy, NULL);
@@ -201,12 +201,12 @@ static void guest_shutdown_code(void)
__asm__ __volatile__("ud2");
}
-static void test_sev_shutdown(u32 type, u64 policy)
+static void test_sev_shutdown(struct vm_shape shape, u64 policy)
{
struct kvm_vcpu *vcpu;
struct kvm_vm *vm;
- vm = vm_sev_create_with_one_vcpu(type, guest_shutdown_code, &vcpu);
+ vm = vm_create_shape_with_one_vcpu(shape, &vcpu, guest_shutdown_code);
vm_sev_launch(vm, policy, NULL);
@@ -218,28 +218,28 @@ static void test_sev_shutdown(u32 type, u64 policy)
kvm_vm_free(vm);
}
-static void test_sev_smoke(void *guest, u32 type, u64 policy)
+static void test_sev_smoke(void *guest, struct vm_shape shape, u64 policy)
{
const u64 xf_mask = XFEATURE_MASK_X87_AVX;
- if (type == KVM_X86_SNP_VM)
- test_sev(guest, type, policy | SNP_POLICY_DBG);
+ if (shape.type == KVM_X86_SNP_VM)
+ test_sev(guest, shape, policy | SNP_POLICY_DBG);
else
- test_sev(guest, type, policy | SEV_POLICY_NO_DBG);
- test_sev(guest, type, policy);
+ test_sev(guest, shape, policy | SEV_POLICY_NO_DBG);
+ test_sev(guest, shape, policy);
- if (type == KVM_X86_SEV_VM)
+ if (shape.type == KVM_X86_SEV_VM)
return;
- test_sev_shutdown(type, policy);
+ test_sev_shutdown(shape, policy);
if (kvm_has_cap(KVM_CAP_XCRS) &&
(xgetbv(0) & kvm_cpu_supported_xcr0() & xf_mask) == xf_mask) {
- test_sync_vmsa(type, policy);
- if (type == KVM_X86_SNP_VM)
- test_sync_vmsa(type, policy | SNP_POLICY_DBG);
+ test_sync_vmsa(shape, policy);
+ if (shape.type == KVM_X86_SNP_VM)
+ test_sync_vmsa(shape, policy | SNP_POLICY_DBG);
else
- test_sync_vmsa(type, policy | SEV_POLICY_NO_DBG);
+ test_sync_vmsa(shape, policy | SEV_POLICY_NO_DBG);
}
}
@@ -247,13 +247,13 @@ int main(int argc, char *argv[])
{
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));
- test_sev_smoke(guest_sev_code, KVM_X86_SEV_VM, 0);
+ test_sev_smoke(guest_sev_code, VM_SHAPE_SEV, 0);
if (kvm_cpu_has(X86_FEATURE_SEV_ES))
- test_sev_smoke(guest_sev_es_code, KVM_X86_SEV_ES_VM, SEV_POLICY_ES);
+ test_sev_smoke(guest_sev_es_code, VM_SHAPE_SEV_ES, SEV_POLICY_ES);
if (kvm_cpu_has(X86_FEATURE_SEV_SNP))
- test_sev_smoke(guest_snp_code, KVM_X86_SNP_VM, snp_default_policy());
+ test_sev_smoke(guest_snp_code, VM_SHAPE_SNP, snp_default_policy());
return 0;
}
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 98+ messages in thread* Re: [PATCH v14 01/22] KVM: selftests: Add macros to simplify creating VM shapes for non-default types
2026-07-22 23:13 ` [PATCH v14 01/22] KVM: selftests: Add macros to simplify creating VM shapes for non-default types Lisa Wang
@ 2026-08-19 7:44 ` Peter Fang
2026-09-08 16:58 ` Ackerley Tng
1 sibling, 0 replies; 98+ messages in thread
From: Peter Fang @ 2026-08-19 7:44 UTC (permalink / raw)
To: Lisa Wang
Cc: Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Ira Weiny, Isaku Yamahata,
Kiryl Shutsemau, linux-kselftest, Paolo Bonzini, Pratik R. Sampat,
Reinette Chatre, Rick Edgecombe, Roger Wang, Ryan Afranji,
Sagi Shahar, Sean Christopherson, Shuah Khan, Xiaoyao Li,
Oliver Upton, Jeremiah McReynolds, kvm, linux-coco, linux-kernel,
x86
On Wed, Jul 22, 2026 at 11:13:06PM +0000, Lisa Wang wrote:
> From: Sean Christopherson <seanjc@google.com>
>
> Add VM_TYPE() and __VM_SHAPE() macros to create a vm_shape structure given
> a type (and mode), and use the macros to define VM_SHAPE_{SEV,SEV_ES,SNP}
> shapes for x86's SEV family of VM shapes. Providing common infrastructure
> will avoid having to copy+paste vm_sev_create_with_one_vcpu() for TDX.
>
> Use the new SEV+ shapes and drop vm_sev_create_with_one_vcpu().
>
> Opportunistically move the existing VM_SHAPE() (now __VM_SHAPE()) macro
> below the definitions of VM_MODE_DEFAULT so that all of the SHAPE/TYPE
> macros are bundled together.
>
> No functional change intended.
>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
Missing the submitter's SOB?
> ---
> tools/testing/selftests/kvm/include/kvm_util.h | 27 ++++++++-------
> .../testing/selftests/kvm/include/x86/processor.h | 4 +++
> tools/testing/selftests/kvm/include/x86/sev.h | 2 --
> tools/testing/selftests/kvm/lib/x86/sev.c | 16 ---------
> tools/testing/selftests/kvm/x86/sev_smoke_test.c | 40 +++++++++++-----------
> 5 files changed, 39 insertions(+), 50 deletions(-)
>
^ permalink raw reply [flat|nested] 98+ messages in thread* Re: [PATCH v14 01/22] KVM: selftests: Add macros to simplify creating VM shapes for non-default types
2026-07-22 23:13 ` [PATCH v14 01/22] KVM: selftests: Add macros to simplify creating VM shapes for non-default types Lisa Wang
2026-08-19 7:44 ` Peter Fang
@ 2026-09-08 16:58 ` Ackerley Tng
1 sibling, 0 replies; 98+ messages in thread
From: Ackerley Tng @ 2026-09-08 16:58 UTC (permalink / raw)
To: Lisa Wang, Andrew Jones, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Ira Weiny, Isaku Yamahata,
Kiryl Shutsemau, linux-kselftest, Paolo Bonzini, Pratik R. Sampat,
Reinette Chatre, Rick Edgecombe, Roger Wang, Ryan Afranji,
Sagi Shahar, Sean Christopherson, Shuah Khan, Xiaoyao Li,
Oliver Upton
Cc: Jeremiah McReynolds, kvm, linux-coco, linux-kernel, x86
Lisa Wang <wyihan@google.com> writes:
> From: Sean Christopherson <seanjc@google.com>
>
> Add VM_TYPE() and __VM_SHAPE() macros to create a vm_shape structure given
> a type (and mode), and use the macros to define VM_SHAPE_{SEV,SEV_ES,SNP}
> shapes for x86's SEV family of VM shapes. Providing common infrastructure
> will avoid having to copy+paste vm_sev_create_with_one_vcpu() for TDX.
>
> Use the new SEV+ shapes and drop vm_sev_create_with_one_vcpu().
>
> Opportunistically move the existing VM_SHAPE() (now __VM_SHAPE()) macro
> below the definitions of VM_MODE_DEFAULT so that all of the SHAPE/TYPE
> macros are bundled together.
>
> No functional change intended.
>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
>
> [...snip...]
>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
^ permalink raw reply [flat|nested] 98+ messages in thread
* [PATCH v14 02/22] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
2026-07-22 23:13 [PATCH v14 00/22] TDX KVM selftests Lisa Wang
2026-07-22 23:13 ` [PATCH v14 01/22] KVM: selftests: Add macros to simplify creating VM shapes for non-default types Lisa Wang
@ 2026-07-22 23:13 ` Lisa Wang
2026-08-13 23:17 ` Edgecombe, Rick P
2026-07-22 23:13 ` [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM Lisa Wang
` (20 subsequent siblings)
22 siblings, 1 reply; 98+ messages in thread
From: Lisa Wang @ 2026-07-22 23:13 UTC (permalink / raw)
To: Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Ira Weiny, Isaku Yamahata,
Kiryl Shutsemau, linux-kselftest, Paolo Bonzini, Pratik R. Sampat,
Reinette Chatre, Rick Edgecombe, Roger Wang, Ryan Afranji,
Sagi Shahar, Sean Christopherson, Shuah Khan, Xiaoyao Li,
Oliver Upton
Cc: Jeremiah McReynolds, kvm, linux-coco, linux-kernel, x86,
Lisa Wang, Adrian Hunter
From: Isaku Yamahata <isaku.yamahata@intel.com>
Initialize the TDX S-bit and the GPA tag mask in
kvm_init_vm_address_properties() for TDX VMs, similar to how the C-bit
is initialized for SEV VMs.
The TDX S-bit is used to distinguish between shared and private guest
physical addresses. Its position is determined by the guest physical
address width, which is either 48 or 52 bits for current TDX
implementations.
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
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>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Lisa Wang <wyihan@google.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
tools/testing/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(-)
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..f647e6ca6b34
--- /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 b51467d70f6e..b68ad1dc7e02 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -11,6 +11,7 @@
#include "smm.h"
#include "svm_util.h"
#include "sev.h"
+#include "tdx/tdx_util.h"
#include "vmx.h"
#ifndef NUM_INTERRUPTS
@@ -1311,12 +1312,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)
{
+ u32 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 = BIT_ULL(gpa_bits - 1);
+ vm->gpa_tag_mask = vm->arch.s_bit;
}
}
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 98+ messages in thread* Re: [PATCH v14 02/22] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
2026-07-22 23:13 ` [PATCH v14 02/22] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Lisa Wang
@ 2026-08-13 23:17 ` Edgecombe, Rick P
2026-09-08 17:42 ` Ackerley Tng
0 siblings, 1 reply; 98+ messages in thread
From: Edgecombe, Rick P @ 2026-08-13 23:17 UTC (permalink / raw)
To: Aktas, Erdem, Li, Xiaoyao, shuah@kernel.org,
dave.hansen@linux.intel.com, afranji@google.com, kas@kernel.org,
binbin.wu@linux.intel.com, ira.weiny@intel.com,
pbonzini@redhat.com, Chatre, Reinette, isaku.yamahata@intel.com,
ackerleytng@google.com, seanjc@google.com,
pratikrajesh.sampat@amd.com, oupton@kernel.org, wyihan@google.com,
sagis@google.com, Gao, Chao, Wang, Roger,
linux-kselftest@vger.kernel.org, ajones@ventanamicro.com,
Qiang, Chenyi
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
jmcrey@google.com, linux-kernel@vger.kernel.org, Hunter, Adrian,
x86@kernel.org
On Wed, 2026-07-22 at 23:13 +0000, Lisa Wang wrote:
> From: Isaku Yamahata <isaku.yamahata@intel.com>
>
> Initialize the TDX S-bit and the GPA tag mask in
> kvm_init_vm_address_properties() for TDX VMs, similar to how the C-bit
> is initialized for SEV VMs.
>
> The TDX S-bit is used to distinguish between shared and private guest
> physical addresses. Its position is determined by the guest physical
> address width, which is either 48 or 52 bits for current TDX
> implementations.
Since S-bit=1 means shared and C-bit=1 means private, we can't have a single
bit. I'd justify why a second field is needed. For "untagging" GPAs we could
have a single field, but there are other usages?
>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> 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>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> Signed-off-by: Lisa Wang <wyihan@google.com>
> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> ---
Nit: these are not ordered correctly. I think KVM prefers the order in:
Documentation/process/maintainer-tip.rst
But I think at least the RBs can be grouped together. Also... can't really point
fingers here, but that is a fair amount of of patch history.
^ permalink raw reply [flat|nested] 98+ messages in thread
* Re: [PATCH v14 02/22] KVM: selftests: Update kvm_init_vm_address_properties() for TDX
2026-08-13 23:17 ` Edgecombe, Rick P
@ 2026-09-08 17:42 ` Ackerley Tng
0 siblings, 0 replies; 98+ messages in thread
From: Ackerley Tng @ 2026-09-08 17:42 UTC (permalink / raw)
To: Edgecombe, Rick P, Aktas, Erdem, Li, Xiaoyao, shuah@kernel.org,
dave.hansen@linux.intel.com, afranji@google.com, kas@kernel.org,
binbin.wu@linux.intel.com, ira.weiny@intel.com,
pbonzini@redhat.com, Chatre, Reinette, isaku.yamahata@intel.com,
seanjc@google.com, pratikrajesh.sampat@amd.com, oupton@kernel.org,
wyihan@google.com, sagis@google.com, Gao, Chao, Wang, Roger,
linux-kselftest@vger.kernel.org, ajones@ventanamicro.com,
Qiang, Chenyi
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
jmcrey@google.com, linux-kernel@vger.kernel.org, Hunter, Adrian,
x86@kernel.org
"Edgecombe, Rick P" <rick.p.edgecombe@intel.com> writes:
> On Wed, 2026-07-22 at 23:13 +0000, Lisa Wang wrote:
>> From: Isaku Yamahata <isaku.yamahata@intel.com>
>>
>> Initialize the TDX S-bit and the GPA tag mask in
>> kvm_init_vm_address_properties() for TDX VMs, similar to how the C-bit
>> is initialized for SEV VMs.
>>
>> The TDX S-bit is used to distinguish between shared and private guest
>> physical addresses. Its position is determined by the guest physical
>> address width, which is either 48 or 52 bits for current TDX
>> implementations.
>
> Since S-bit=1 means shared and C-bit=1 means private, we can't have a single
> bit. I'd justify why a second field is needed.
The s_bit field was introduced prior to this patch series, so I think
the patch introducing the s_bit field should have justified the addition
of this second field.
Did you mean that we should add something related to "Since S-bit=1
means shared and C-bit=1 means private, we can't have a single bit." in
the commit message to reiterate/as a refresher?
> For "untagging" GPAs we could
> have a single field, but there are other usages?
>
I think this part in __virt_pg_map() requires separate fields, are you
requesting to only retain one of the c_bit/s_bit vs gpa_tag_mask?
if (vm_is_gpa_protected(vm, gpa))
*pte |= PTE_C_BIT_MASK(mmu);
else
*pte |= PTE_S_BIT_MASK(mmu);
I think if there's any unification/simplification required among these
fields, perhaps that can be left to another series.
>>
>> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
>> 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>
>> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
>> Signed-off-by: Lisa Wang <wyihan@google.com>
>> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
>> ---
> Nit: these are not ordered correctly. I think KVM prefers the order in:
> Documentation/process/maintainer-tip.rst
>
> But I think at least the RBs can be grouped together. Also... can't really point
> fingers here, but that is a fair amount of of patch history.
I was also involved in some earlier revision of this series, tracing
this history is not trivial...
For this series, given the long history and many handoffs, shall we help
Lisa out by explicitly requesting to be credited on specific patches?
Emailing either Lisa/Ackerley privately or on-list is fine :)
^ permalink raw reply [flat|nested] 98+ messages in thread
* [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-07-22 23:13 [PATCH v14 00/22] TDX KVM selftests Lisa Wang
2026-07-22 23:13 ` [PATCH v14 01/22] KVM: selftests: Add macros to simplify creating VM shapes for non-default types Lisa Wang
2026-07-22 23:13 ` [PATCH v14 02/22] KVM: selftests: Update kvm_init_vm_address_properties() for TDX Lisa Wang
@ 2026-07-22 23:13 ` Lisa Wang
2026-07-23 8:44 ` Xiaoyao Li
` (2 more replies)
2026-07-22 23:13 ` [PATCH v14 04/22] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration Lisa Wang
` (19 subsequent siblings)
22 siblings, 3 replies; 98+ messages in thread
From: Lisa Wang @ 2026-07-22 23:13 UTC (permalink / raw)
To: Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Ira Weiny, Isaku Yamahata,
Kiryl Shutsemau, linux-kselftest, Paolo Bonzini, Pratik R. Sampat,
Reinette Chatre, Rick Edgecombe, Roger Wang, Ryan Afranji,
Sagi Shahar, Sean Christopherson, Shuah Khan, Xiaoyao Li,
Oliver Upton
Cc: Jeremiah McReynolds, kvm, linux-coco, linux-kernel, x86,
Lisa Wang
From: Sagi Shahar <sagis@google.com>
Add tdx_init_vm() to handle the mandatory VM-level initialization
sequence required for Intel TDX.
For TDX, the guest's CPUID configuration must be "sealed" during
KVM_TDX_INIT_VM before any vCPUs are created. This is necessary because
the TDX hardware directly virtualizes CPUID and includes the
configuration in the guest's initial security measurement.
The helper calculates the required CPUID values by filtering the host-
supported bits (kvm_get_supported_cpuid) against the "directly
configurable" bits reported by KVM_TDX_CAPABILITIES, ensuring
compliance with the strict requirements of the TDH.MNG.INIT SEAMCALL.
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>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Lisa Wang <wyihan@google.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../testing/selftests/kvm/include/x86/processor.h | 2 +
.../selftests/kvm/include/x86/tdx/tdx_util.h | 35 ++++++
tools/testing/selftests/kvm/lib/x86/processor.c | 21 +++-
tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c | 120 +++++++++++++++++++++
5 files changed, 175 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index e5769268936a..3f98d1c6488c 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -27,6 +27,7 @@ LIBKVM_x86 += lib/x86/pmu.c
LIBKVM_x86 += lib/x86/processor.c
LIBKVM_x86 += lib/x86/sev.c
LIBKVM_x86 += lib/x86/svm.c
+LIBKVM_x86 += lib/x86/tdx/tdx_util.c
LIBKVM_x86 += lib/x86/ucall.c
LIBKVM_x86 += lib/x86/vmx.c
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 0aa6eecfcbde..76180dfaffea 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -956,6 +956,8 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs)
vcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs);
}
+const struct kvm_cpuid_entry2 *__get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
+ u32 function, u32 index);
const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
u32 function, u32 index);
const struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
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 f647e6ca6b34..eb8602dce0bc 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,39 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
return vm->type == KVM_X86_TDX_VM;
}
+/*
+ * TDX ioctls
+ * Use underscores to avoid collisions with struct member names.
+ */
+#define __tdx_vm_ioctl(vm, cmd, _flags, arg) \
+({ \
+ u64 r; \
+ \
+ union { \
+ struct kvm_tdx_cmd c; \
+ unsigned long raw; \
+ } tdx_cmd = { .c = { \
+ .id = (cmd), \
+ .flags = (u32)(_flags), \
+ .data = (u64)(arg), \
+ } }; \
+ \
+ r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw); \
+ r ?: tdx_cmd.c.hw_error; \
+})
+
+#define tdx_vm_ioctl(vm, cmd, flags, arg) \
+({ \
+ u64 ret = __tdx_vm_ioctl(vm, cmd, flags, arg); \
+ \
+ if (ret) { \
+ TEST_ASSERT(!ret, \
+ "%s failed, rc: 0x%llx errno: %i (%s)", \
+ #cmd, (unsigned long long)ret, \
+ errno, strerror(errno)); \
+ } \
+})
+
+void tdx_init_vm(struct kvm_vm *vm, u64 attributes);
+
#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 b68ad1dc7e02..7d23344854cc 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -802,6 +802,9 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus)
vm_sev_ioctl(vm, KVM_SEV_INIT2, &init);
}
+ if (is_tdx_vm(vm))
+ tdx_init_vm(vm, 0);
+
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;
@@ -1328,8 +1331,8 @@ void kvm_init_vm_address_properties(struct kvm_vm *vm)
}
}
-const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
- u32 function, u32 index)
+const struct kvm_cpuid_entry2 *__get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
+ u32 function, u32 index)
{
int i;
@@ -1339,11 +1342,21 @@ const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
return &cpuid->entries[i];
}
- TEST_FAIL("CPUID function 0x%x index 0x%x not found ", function, index);
-
return NULL;
}
+const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
+ u32 function, u32 index)
+{
+ const struct kvm_cpuid_entry2 *entry;
+
+ entry = __get_cpuid_entry(cpuid, function, index);
+ if (!entry)
+ TEST_FAIL("CPUID function 0x%x index 0x%x not found ", function, index);
+
+ return entry;
+}
+
#define X86_HYPERCALL(inputs...) \
({ \
u64 r; \
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..e1ffb67a106c
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "processor.h"
+#include "tdx/tdx_util.h"
+
+static struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm *vm)
+{
+ static struct kvm_tdx_capabilities *tdx_cap;
+ int nr_cpuid_configs = 4;
+ int rc = -1;
+ int i;
+
+ if (tdx_cap)
+ return tdx_cap;
+
+ do {
+ nr_cpuid_configs *= 2;
+
+ tdx_cap = realloc(tdx_cap, sizeof(*tdx_cap) +
+ (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 = __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;
+}
+
+/*
+ * Filter CPUID based on TDX supported capabilities
+ *
+ * Input Args:
+ * vm - Virtual Machine
+ * cpuid_data - CPUID fields to filter
+ *
+ * Output Args: None
+ *
+ * Return: None
+ *
+ * For each CPUID leaf, filter out unsupported bits based on the capabilities
+ * reported by the TDX module
+ */
+static void tdx_filter_cpuid(struct kvm_vm *vm,
+ struct kvm_cpuid2 *cpuid_data)
+{
+ struct kvm_tdx_capabilities *tdx_cap;
+ const 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 = __get_cpuid_entry(&tdx_cap->cpuid, 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++;
+ }
+}
+
+void tdx_init_vm(struct kvm_vm *vm, u64 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(tmp->nent);
+ memcpy(cpuid, tmp, kvm_cpuid2_size(tmp->nent));
+ 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;
+
+ tdx_vm_ioctl(vm, KVM_TDX_INIT_VM, 0, init_vm);
+
+ free(init_vm);
+}
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 98+ messages in thread* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-07-22 23:13 ` [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM Lisa Wang
@ 2026-07-23 8:44 ` Xiaoyao Li
2026-08-13 23:41 ` Edgecombe, Rick P
2026-09-08 8:04 ` Lisa Wang
2026-08-13 23:41 ` Edgecombe, Rick P
2026-08-20 8:46 ` Peter Fang
2 siblings, 2 replies; 98+ messages in thread
From: Xiaoyao Li @ 2026-07-23 8:44 UTC (permalink / raw)
To: Lisa Wang, Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao,
Chenyi Qiang, Dave Hansen, Erdem Aktas, Kiryl Shutsemau,
linux-kselftest, Paolo Bonzini, Pratik R. Sampat, Reinette Chatre,
Rick Edgecombe, Roger Wang, Ryan Afranji, Sagi Shahar,
Sean Christopherson, Shuah Khan, Oliver Upton
Cc: Jeremiah McReynolds, kvm, linux-coco, linux-kernel, x86
On 7/23/2026 7:13 AM, Lisa Wang wrote:
> From: Sagi Shahar <sagis@google.com>
>
> Add tdx_init_vm() to handle the mandatory VM-level initialization
> sequence required for Intel TDX.
>
> For TDX, the guest's CPUID configuration must be "sealed" during
> KVM_TDX_INIT_VM before any vCPUs are created. This is necessary because
> the TDX hardware directly virtualizes CPUID and includes the
> configuration in the guest's initial security measurement.
>
> The helper calculates the required CPUID values by filtering the host-
> supported bits (kvm_get_supported_cpuid) against the "directly
> configurable" bits reported by KVM_TDX_CAPABILITIES, ensuring
> compliance with the strict requirements of the TDH.MNG.INIT SEAMCALL.
<snip>
> +/*
> + * TDX ioctls
> + * Use underscores to avoid collisions with struct member names.
> + */
> +#define __tdx_vm_ioctl(vm, cmd, _flags, arg) \
sev uses the name __vm_sev_ioctl, I think we need to keep them consistent.
> +({ \
> + u64 r; \
> + \
> + union { \
> + struct kvm_tdx_cmd c; \
> + unsigned long raw; \
> + } tdx_cmd = { .c = { \
> + .id = (cmd), \
> + .flags = (u32)(_flags), \
> + .data = (u64)(arg), \
> + } }; \
> + \
> + r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw); \
> + r ?: tdx_cmd.c.hw_error; \
I know it takes the same handling from __vm_sev_ioctl(). But I think the
handling for hw_error is not correct, at least for TDX (I didn't check
for SEV).
the hw_error is the additional info, to tell the SEAMCALL return code,
when the IOCTL fails. KVM requires hw_error to be in the input, and KVM
puts the SEAMCALL return code into hw_error when the IOCTL fails due to
SEAMCALL failure. That means, when r == 0, the hw_error is always 0.
I think we need to provide hw_error along with r to the caller so that
caller can print them together.
> +})
> +
> +#define tdx_vm_ioctl(vm, cmd, flags, arg) \
> +({ \
> + u64 ret = __tdx_vm_ioctl(vm, cmd, flags, arg); \
> + \
> + if (ret) { \
> + TEST_ASSERT(!ret, \
> + "%s failed, rc: 0x%llx errno: %i (%s)", \
> + #cmd, (unsigned long long)ret, \
> + errno, strerror(errno)); \
The if() looks silly. Why add it? And why change it from
__TEST_ASSERT_VM_VCPU_IOCTL() in the v13?
Considering the suggestion of hw_error above, I think we need to
introduce the TEST_ASSERT_TDX_VM_VCPU_IOCTL() which accepts additional
hw_error?
<snip>
> 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..e1ffb67a106c
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> @@ -0,0 +1,120 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include "processor.h"
> +#include "tdx/tdx_util.h"
> +
> +static struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm *vm)
make it const, is better.
<snip>
> +
> +void tdx_init_vm(struct kvm_vm *vm, u64 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(tmp->nent);
> + memcpy(cpuid, tmp, kvm_cpuid2_size(tmp->nent));
> + 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;
Besides CPUID, it only allows attributes to be configure but leave XFAM
as 0. I think the changelog needs to explain why we need to configure
attributes.
The rest of the patch looks good to me.
> +
> + tdx_vm_ioctl(vm, KVM_TDX_INIT_VM, 0, init_vm);
> +
> + free(init_vm);
> +}
>
^ permalink raw reply [flat|nested] 98+ messages in thread* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-07-23 8:44 ` Xiaoyao Li
@ 2026-08-13 23:41 ` Edgecombe, Rick P
2026-08-15 9:17 ` Xiaoyao Li
2026-09-08 8:04 ` Lisa Wang
1 sibling, 1 reply; 98+ messages in thread
From: Edgecombe, Rick P @ 2026-08-13 23:41 UTC (permalink / raw)
To: Aktas, Erdem, Li, Xiaoyao, shuah@kernel.org,
dave.hansen@linux.intel.com, afranji@google.com, kas@kernel.org,
Chatre, Reinette, binbin.wu@linux.intel.com, pbonzini@redhat.com,
seanjc@google.com, ackerleytng@google.com,
pratikrajesh.sampat@amd.com, oupton@kernel.org, wyihan@google.com,
sagis@google.com, Wang, Roger, Gao, Chao,
linux-kselftest@vger.kernel.org, ajones@ventanamicro.com,
Qiang, Chenyi
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
jmcrey@google.com, linux-kernel@vger.kernel.org, x86@kernel.org
On Thu, 2026-07-23 at 16:44 +0800, Xiaoyao Li wrote:
> > + init_vm->attributes = attributes;
>
> Besides CPUID, it only allows attributes to be configure but leave XFAM
> as 0. I think the changelog needs to explain why we need to configure
> attributes.
>
> The rest of the patch looks good to me.
How about directly setting xfam to zero for clarity?
^ permalink raw reply [flat|nested] 98+ messages in thread
* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-08-13 23:41 ` Edgecombe, Rick P
@ 2026-08-15 9:17 ` Xiaoyao Li
0 siblings, 0 replies; 98+ messages in thread
From: Xiaoyao Li @ 2026-08-15 9:17 UTC (permalink / raw)
To: Edgecombe, Rick P, Aktas, Erdem, shuah@kernel.org,
dave.hansen@linux.intel.com, afranji@google.com, kas@kernel.org,
Chatre, Reinette, binbin.wu@linux.intel.com, pbonzini@redhat.com,
seanjc@google.com, ackerleytng@google.com,
pratikrajesh.sampat@amd.com, oupton@kernel.org, wyihan@google.com,
sagis@google.com, Wang, Roger, Gao, Chao,
linux-kselftest@vger.kernel.org, ajones@ventanamicro.com,
Qiang, Chenyi
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
jmcrey@google.com, linux-kernel@vger.kernel.org, x86@kernel.org
On 8/14/2026 7:41 AM, Edgecombe, Rick P wrote:
> On Thu, 2026-07-23 at 16:44 +0800, Xiaoyao Li wrote:
>>> + init_vm->attributes = attributes;
>>
>> Besides CPUID, it only allows attributes to be configure but leave XFAM
>> as 0. I think the changelog needs to explain why we need to configure
>> attributes.
>>
>> The rest of the patch looks good to me.
>
> How about directly setting xfam to zero for clarity?
Agreed. It's simple.
^ permalink raw reply [flat|nested] 98+ messages in thread
* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-07-23 8:44 ` Xiaoyao Li
2026-08-13 23:41 ` Edgecombe, Rick P
@ 2026-09-08 8:04 ` Lisa Wang
2026-09-08 18:08 ` Ackerley Tng
1 sibling, 1 reply; 98+ messages in thread
From: Lisa Wang @ 2026-09-08 8:04 UTC (permalink / raw)
To: Xiaoyao Li
Cc: Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Kiryl Shutsemau, linux-kselftest,
Paolo Bonzini, Pratik R. Sampat, Reinette Chatre, Rick Edgecombe,
Roger Wang, Ryan Afranji, Sagi Shahar, Sean Christopherson,
Shuah Khan, Oliver Upton, Jeremiah McReynolds, kvm, linux-coco,
linux-kernel, x86
On Thu, Jul 23, 2026 at 04:44:08PM +0800, Xiaoyao Li wrote:
> > + */
> > +#define __tdx_vm_ioctl(vm, cmd, _flags, arg) \
>
> sev uses the name __vm_sev_ioctl, I think we need to keep them consistent.
While __vm_tdx_ioctl matches SEV, the TDX selftest follows a tdx_<scope>_*
naming convention (1. TDX prefix, 2. Scope: VM or vCPU). I named it
__tdx_vm_ioctl to keep the TDX codebase internally consistent.[1]
Do you think we should align with SEV's naming convention instead of
sticking with the internal TDX pattern?
[1]: https://lore.kernel.org/kvm/489f3c7b-db03-43dc-bb64-910a0fcba31e@intel.com/
> > +({ \
> > + u64 r; \
> > + \
> > + union { \
> > + struct kvm_tdx_cmd c; \
> > + unsigned long raw; \
> > + } tdx_cmd = { .c = { \
> > + .id = (cmd), \
> > + .flags = (u32)(_flags), \
> > + .data = (u64)(arg), \
> > + } }; \
> > + \
> > + r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw); \
> > + r ?: tdx_cmd.c.hw_error; \
>
> I know it takes the same handling from __vm_sev_ioctl(). But I think the
> handling for hw_error is not correct, at least for TDX (I didn't check for
> SEV).
>
> the hw_error is the additional info, to tell the SEAMCALL return code, when
> the IOCTL fails. KVM requires hw_error to be in the input, and KVM puts the
> SEAMCALL return code into hw_error when the IOCTL fails due to SEAMCALL
> failure. That means, when r == 0, the hw_error is always 0.
>
> I think we need to provide hw_error along with r to the caller so that
> caller can print them together.
I think the value of r is not important, because the ioctl failure
is already captured in errno.
We only need to fix the return values for SEV and TDX and have
TEST_ASSERT_* print formatted error logs with errno and hw_error.
- r ?: {tdx, sev}_cmd.c.hw_error;
+ r ? {tdx, sev}_cmd.c.hw_error : 0;
> > +})
> > +
> > +#define tdx_vm_ioctl(vm, cmd, flags, arg) \
> > +({ \
> > + u64 ret = __tdx_vm_ioctl(vm, cmd, flags, arg); \
> > + \
> > + if (ret) { \
> > + TEST_ASSERT(!ret, \
> > + "%s failed, rc: 0x%llx errno: %i (%s)", \
> > + #cmd, (unsigned long long)ret, \
> > + errno, strerror(errno)); \
>
> The if() looks silly. Why add it? And why change it from
> __TEST_ASSERT_VM_VCPU_IOCTL() in the v13?
>
> Considering the suggestion of hw_error above, I think we need to introduce
> the TEST_ASSERT_TDX_VM_VCPU_IOCTL() which accepts additional hw_error?
The reason we could not use __TEST_ASSERT_VM_VCPU_IOCTL() directly[2] is
because it formats ther return value as %i (32-bit), whereas
__tdx_vm_ioctl might return a u64 hardware error code.
I agree with your suggestion to introduce a new
TEST_ASSERT_TDX_VM_VCPU_IOCTL() macro to print out u64 hardware error
code properly.
[2]: https://lore.kernel.org/all/a58e2941-77f9-43cf-a54d-023506dd7eb0@linux.intel.com/
> <snip>
> > 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..e1ffb67a106c
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> > @@ -0,0 +1,120 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +#include "processor.h"
> > +#include "tdx/tdx_util.h"
> > +
> > +static struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm *vm)
>
> make it const, is better.
Thanks, noted.
> > + init_vm->attributes = attributes;
>
> Besides CPUID, it only allows attributes to be configure but leave XFAM as
> 0. I think the changelog needs to explain why we need to configure
> attributes.
Thanks, noted.
> The rest of the patch looks good to me.
^ permalink raw reply [flat|nested] 98+ messages in thread* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-09-08 8:04 ` Lisa Wang
@ 2026-09-08 18:08 ` Ackerley Tng
2026-09-09 10:00 ` Xiaoyao Li
0 siblings, 1 reply; 98+ messages in thread
From: Ackerley Tng @ 2026-09-08 18:08 UTC (permalink / raw)
To: Lisa Wang, Xiaoyao Li
Cc: Andrew Jones, Binbin Wu, Chao Gao, Chenyi Qiang, Dave Hansen,
Erdem Aktas, Kiryl Shutsemau, linux-kselftest, Paolo Bonzini,
Pratik R. Sampat, Reinette Chatre, Rick Edgecombe, Roger Wang,
Ryan Afranji, Sagi Shahar, Sean Christopherson, Shuah Khan,
Oliver Upton, Jeremiah McReynolds, kvm, linux-coco, linux-kernel,
x86
Lisa Wang <wyihan@google.com> writes:
> On Thu, Jul 23, 2026 at 04:44:08PM +0800, Xiaoyao Li wrote:
>> > + */
>> > +#define __tdx_vm_ioctl(vm, cmd, _flags, arg) \
>>
>> sev uses the name __vm_sev_ioctl, I think we need to keep them consistent.
>
> While __vm_tdx_ioctl matches SEV, the TDX selftest follows a tdx_<scope>_*
> naming convention (1. TDX prefix, 2. Scope: VM or vCPU). I named it
> __tdx_vm_ioctl to keep the TDX codebase internally consistent.[1]
>
> Do you think we should align with SEV's naming convention instead of
> sticking with the internal TDX pattern?
>
> [1]: https://lore.kernel.org/kvm/489f3c7b-db03-43dc-bb64-910a0fcba31e@intel.com/
>
Given that __vm_sev_ioctl and __tdx_vm_ioctl aren't likely to appear
next to each other, I think it's better to have the tdx prefix earlier
to keep the TDX code consistent. To move things along, I think we could
continue as-is and not swap to align with sev.
(The sev functions actually look kind of inconsistent in sev.h, but
that's a discussion for another series.)
>> > +({ \
>> > + u64 r; \
>> > + \
>> > + union { \
>> > + struct kvm_tdx_cmd c; \
>> > + unsigned long raw; \
>> > + } tdx_cmd = { .c = { \
>> > + .id = (cmd), \
>> > + .flags = (u32)(_flags), \
>> > + .data = (u64)(arg), \
>> > + } }; \
>> > + \
>> > + r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw); \
>> > + r ?: tdx_cmd.c.hw_error; \
>>
>> I know it takes the same handling from __vm_sev_ioctl(). But I think the
>> handling for hw_error is not correct, at least for TDX (I didn't check for
>> SEV).
>>
>> the hw_error is the additional info, to tell the SEAMCALL return code, when
>> the IOCTL fails. KVM requires hw_error to be in the input, and KVM puts the
>> SEAMCALL return code into hw_error when the IOCTL fails due to SEAMCALL
>> failure. That means, when r == 0, the hw_error is always 0.
>>
>> I think we need to provide hw_error along with r to the caller so that
>> caller can print them together.
>
> I think the value of r is not important, because the ioctl failure
> is already captured in errno.
>
> We only need to fix the return values for SEV and TDX and have
> TEST_ASSERT_* print formatted error logs with errno and hw_error.
>
> - r ?: {tdx, sev}_cmd.c.hw_error;
> + r ? {tdx, sev}_cmd.c.hw_error : 0;
>
I didn't look in detail, perhaps Lisa could look into these:
+ What are the possible values of r? Is it always going to be 1 on
error?
+ Is r always positive or negative?
+ Is tdx_cmd.c.hw_error always positive or negative? It's probably not
one of the standard Linux errors, right?
Perhaps squashing hw_error together with a retval conflates the two.
In the lower-level __tdx_vm_ioctl() we could pass a hw_error and have
the macro set hw_error? That will allow the caller to print both.
>> > +})
>> > +
>> > +#define tdx_vm_ioctl(vm, cmd, flags, arg) \
>> > +({ \
>> > + u64 ret = __tdx_vm_ioctl(vm, cmd, flags, arg); \
>> > + \
>> > + if (ret) { \
>> > + TEST_ASSERT(!ret, \
>> > + "%s failed, rc: 0x%llx errno: %i (%s)", \
>> > + #cmd, (unsigned long long)ret, \
>> > + errno, strerror(errno)); \
>>
>> The if() looks silly. Why add it? And why change it from
>> __TEST_ASSERT_VM_VCPU_IOCTL() in the v13?
>>
>> Considering the suggestion of hw_error above, I think we need to introduce
>> the TEST_ASSERT_TDX_VM_VCPU_IOCTL() which accepts additional hw_error?
>
> The reason we could not use __TEST_ASSERT_VM_VCPU_IOCTL() directly[2] is
> because it formats ther return value as %i (32-bit), whereas
> __tdx_vm_ioctl might return a u64 hardware error code.
>
> I agree with your suggestion to introduce a new
> TEST_ASSERT_TDX_VM_VCPU_IOCTL() macro to print out u64 hardware error
> code properly.
>
> [2]: https://lore.kernel.org/all/a58e2941-77f9-43cf-a54d-023506dd7eb0@linux.intel.com/
>
Is tdx_vm_ioctl() the only place where TEST_ASSERT_TDX_VM_VCPU_IOCTL()
is going to be used though? If so, maybe we should defer introducing
TEST_ASSERT_TDX_VM_VCPU_IOCTL() till later.
I think the issue with if (ret) is just that TEST_ASSERT(!ret) already
does that same check, and so we can drop the if (ret) part.
>> <snip>
>> > 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..e1ffb67a106c
>> > --- /dev/null
>> > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
>> > @@ -0,0 +1,120 @@
>> > +// SPDX-License-Identifier: GPL-2.0-only
>> > +
>> > +#include "processor.h"
>> > +#include "tdx/tdx_util.h"
>> > +
>> > +static struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm *vm)
>>
>> make it const, is better.
>
> Thanks, noted.
>
>> > + init_vm->attributes = attributes;
>>
>> Besides CPUID, it only allows attributes to be configure but leave XFAM as
>> 0. I think the changelog needs to explain why we need to configure
>> attributes.
>
> Thanks, noted.
>
>> The rest of the patch looks good to me.
>
^ permalink raw reply [flat|nested] 98+ messages in thread* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-09-08 18:08 ` Ackerley Tng
@ 2026-09-09 10:00 ` Xiaoyao Li
2026-09-18 1:40 ` Lisa Wang
0 siblings, 1 reply; 98+ messages in thread
From: Xiaoyao Li @ 2026-09-09 10:00 UTC (permalink / raw)
To: Ackerley Tng, Lisa Wang
Cc: Andrew Jones, Binbin Wu, Chao Gao, Chenyi Qiang, Dave Hansen,
Erdem Aktas, Kiryl Shutsemau, linux-kselftest, Paolo Bonzini,
Pratik R. Sampat, Reinette Chatre, Rick Edgecombe, Roger Wang,
Ryan Afranji, Sagi Shahar, Sean Christopherson, Shuah Khan,
Oliver Upton, Jeremiah McReynolds, kvm, linux-coco, linux-kernel,
x86
On 9/9/2026 2:08 AM, Ackerley Tng wrote:
> Lisa Wang <wyihan@google.com> writes:
>
>> On Thu, Jul 23, 2026 at 04:44:08PM +0800, Xiaoyao Li wrote:
>>>> + */
>>>> +#define __tdx_vm_ioctl(vm, cmd, _flags, arg) \
>>>
>>> sev uses the name __vm_sev_ioctl, I think we need to keep them consistent.
>>
>> While __vm_tdx_ioctl matches SEV, the TDX selftest follows a tdx_<scope>_*
>> naming convention (1. TDX prefix, 2. Scope: VM or vCPU). I named it
>> __tdx_vm_ioctl to keep the TDX codebase internally consistent.[1]
>>
>> Do you think we should align with SEV's naming convention instead of
>> sticking with the internal TDX pattern?
>>
>> [1]: https://lore.kernel.org/kvm/489f3c7b-db03-43dc-bb64-910a0fcba31e@intel.com/
>>
>
> Given that __vm_sev_ioctl and __tdx_vm_ioctl aren't likely to appear
> next to each other, I think it's better to have the tdx prefix earlier
> to keep the TDX code consistent. To move things along, I think we could
> continue as-is and not swap to align with sev.
>
> (The sev functions actually look kind of inconsistent in sev.h, but
> that's a discussion for another series.)
Yeah, either adjusting this patch to follow SEV or renaming existing SEV
MACROs is OK.
Keep the patch as-is and leave the SEV work to future are OK.
>>>> +({ \
>>>> + u64 r; \
>>>> + \
>>>> + union { \
>>>> + struct kvm_tdx_cmd c; \
>>>> + unsigned long raw; \
>>>> + } tdx_cmd = { .c = { \
>>>> + .id = (cmd), \
>>>> + .flags = (u32)(_flags), \
>>>> + .data = (u64)(arg), \
>>>> + } }; \
>>>> + \
>>>> + r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw); \
>>>> + r ?: tdx_cmd.c.hw_error; \
>>>
>>> I know it takes the same handling from __vm_sev_ioctl(). But I think the
>>> handling for hw_error is not correct, at least for TDX (I didn't check for
>>> SEV).
>>>
>>> the hw_error is the additional info, to tell the SEAMCALL return code, when
>>> the IOCTL fails. KVM requires hw_error to be in the input, and KVM puts the
>>> SEAMCALL return code into hw_error when the IOCTL fails due to SEAMCALL
>>> failure. That means, when r == 0, the hw_error is always 0.
>>>
>>> I think we need to provide hw_error along with r to the caller so that
>>> caller can print them together.
>>
>> I think the value of r is not important, because the ioctl failure
>> is already captured in errno.
>>
>> We only need to fix the return values for SEV and TDX and have
>> TEST_ASSERT_* print formatted error logs with errno and hw_error.
>>
>> - r ?: {tdx, sev}_cmd.c.hw_error;
>> + r ? {tdx, sev}_cmd.c.hw_error : 0;
>>
No. It is not correct because hw_error can be 0 when r != 0.
> I didn't look in detail, perhaps Lisa could look into these:
>
> + What are the possible values of r? Is it always going to be 1 on
> error?
> + Is r always positive or negative?
> + Is tdx_cmd.c.hw_error always positive or negative? It's probably not
> one of the standard Linux errors, right?
>
> Perhaps squashing hw_error together with a retval conflates the two.
>
> In the lower-level __tdx_vm_ioctl() we could pass a hw_error and have
> the macro set hw_error? That will allow the caller to print both.
yeah. This idea can work.
>>>> +})
>>>> +
>>>> +#define tdx_vm_ioctl(vm, cmd, flags, arg) \
>>>> +({ \
>>>> + u64 ret = __tdx_vm_ioctl(vm, cmd, flags, arg); \
>>>> + \
>>>> + if (ret) { \
>>>> + TEST_ASSERT(!ret, \
>>>> + "%s failed, rc: 0x%llx errno: %i (%s)", \
>>>> + #cmd, (unsigned long long)ret, \
>>>> + errno, strerror(errno)); \
>>>
>>> The if() looks silly. Why add it? And why change it from
>>> __TEST_ASSERT_VM_VCPU_IOCTL() in the v13?
>>>
>>> Considering the suggestion of hw_error above, I think we need to introduce
>>> the TEST_ASSERT_TDX_VM_VCPU_IOCTL() which accepts additional hw_error?
>>
>> The reason we could not use __TEST_ASSERT_VM_VCPU_IOCTL() directly[2] is
>> because it formats ther return value as %i (32-bit), whereas
>> __tdx_vm_ioctl might return a u64 hardware error code.
>>
Since we cannot simply use hw_error to replace ret, there will be not 32bit
vs 64bit issue. But ...
>> I agree with your suggestion to introduce a new
>> TEST_ASSERT_TDX_VM_VCPU_IOCTL() macro to print out u64 hardware error
>> code properly.
... if we want to print hw_error as well, we still need a new macro.
>> [2]: https://lore.kernel.org/all/a58e2941-77f9-43cf-a54d-023506dd7eb0@linux.intel.com/
>>
>
> Is tdx_vm_ioctl() the only place where TEST_ASSERT_TDX_VM_VCPU_IOCTL()
> is going to be used though? If so, maybe we should defer introducing
> TEST_ASSERT_TDX_VM_VCPU_IOCTL() till later.
I think tdx_vcpu_ioctl() will use it as well?
> I think the issue with if (ret) is just that TEST_ASSERT(!ret) already
> does that same check, and so we can drop the if (ret) part.
>
^ permalink raw reply [flat|nested] 98+ messages in thread* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-09-09 10:00 ` Xiaoyao Li
@ 2026-09-18 1:40 ` Lisa Wang
0 siblings, 0 replies; 98+ messages in thread
From: Lisa Wang @ 2026-09-18 1:40 UTC (permalink / raw)
To: Xiaoyao Li
Cc: Ackerley Tng, Andrew Jones, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Kiryl Shutsemau, linux-kselftest,
Paolo Bonzini, Pratik R. Sampat, Reinette Chatre, Rick Edgecombe,
Roger Wang, Ryan Afranji, Sagi Shahar, Sean Christopherson,
Shuah Khan, Oliver Upton, Jeremiah McReynolds, kvm, linux-coco,
linux-kernel, x86
On Wed, Sep 09, 2026 at 06:00:53PM +0800, Xiaoyao Li wrote:
> >> The reason we could not use __TEST_ASSERT_VM_VCPU_IOCTL() directly[2] is
> >> because it formats ther return value as %i (32-bit), whereas
> >> __tdx_vm_ioctl might return a u64 hardware error code.
> >>
>
> Since we cannot simply use hw_error to replace ret, there will be not 32bit
> vs 64bit issue. But ...
>
> >> I agree with your suggestion to introduce a new
> >> TEST_ASSERT_TDX_VM_VCPU_IOCTL() macro to print out u64 hardware error
> >> code properly.
>
> ... if we want to print hw_error as well, we still need a new macro.
>
> >> [2]: https://lore.kernel.org/all/a58e2941-77f9-43cf-a54d-023506dd7eb0@linux.intel.com/
> >>
> >
> > Is tdx_vm_ioctl() the only place where TEST_ASSERT_TDX_VM_VCPU_IOCTL()
> > is going to be used though? If so, maybe we should defer introducing
> > TEST_ASSERT_TDX_VM_VCPU_IOCTL() till later.
>
> I think tdx_vcpu_ioctl() will use it as well?
Thanks for replying.
I agree all of the other parts of your comments.
Just wanted to point out one detail: tdx_vm_ioctl() is the only place
that actually needs to evaluate hw_error right now. Unlike the VM-scoped
ioctls in the x86 kernel code, the functions dispatched via
tdx_vcpu_unlocked_ioctl() (such as tdx_vcpu_init or
tdx_vcpu_init_mem_region) do not currently return the TDX SEAMCALL error
codes into the hw_error field.
Thus, I would prefer to inline TEST_ASSERT directly inside tdx_vm_ioctl()
instead of introducing a new TEST_ASSERT_TDX_VM_VCPU_IOCTL() right now.
Lisa
> > I think the issue with if (ret) is just that TEST_ASSERT(!ret) already
> > does that same check, and so we can drop the if (ret) part.
> >
^ permalink raw reply [flat|nested] 98+ messages in thread
* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-07-22 23:13 ` [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM Lisa Wang
2026-07-23 8:44 ` Xiaoyao Li
@ 2026-08-13 23:41 ` Edgecombe, Rick P
2026-08-14 21:18 ` Peter Fang
2026-08-20 8:46 ` Peter Fang
2 siblings, 1 reply; 98+ messages in thread
From: Edgecombe, Rick P @ 2026-08-13 23:41 UTC (permalink / raw)
To: Aktas, Erdem, Li, Xiaoyao, shuah@kernel.org,
dave.hansen@linux.intel.com, afranji@google.com, kas@kernel.org,
binbin.wu@linux.intel.com, ira.weiny@intel.com,
pbonzini@redhat.com, Chatre, Reinette, isaku.yamahata@intel.com,
ackerleytng@google.com, seanjc@google.com,
pratikrajesh.sampat@amd.com, oupton@kernel.org, wyihan@google.com,
sagis@google.com, Gao, Chao, Wang, Roger,
linux-kselftest@vger.kernel.org, ajones@ventanamicro.com,
Qiang, Chenyi
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
jmcrey@google.com, linux-kernel@vger.kernel.org, Fang, Peter,
x86@kernel.org
On Wed, 2026-07-22 at 23:13 +0000, Lisa Wang wrote:
> From: Sagi Shahar <sagis@google.com>
>
> Add tdx_init_vm() to handle the mandatory VM-level initialization
> sequence required for Intel TDX.
>
> For TDX, the guest's CPUID configuration must be "sealed" during
> KVM_TDX_INIT_VM before any vCPUs are created. This is necessary because
> the TDX hardware directly virtualizes CPUID and includes the
> configuration in the guest's initial security measurement.
"TDX hardware" should be TDX module. But I'm not sure what it is trying to say
about directly virtualizes.
Also, it is not accurate to say that the CPUID configuration is included in the
measurement? Is that right Peter? It's not in the report, but is it in the
measurement?
Or maybe it doesn't really need to be in the log anyway.
>
> The helper calculates the required CPUID values by filtering the host-
> supported bits (kvm_get_supported_cpuid) against the "directly
> configurable" bits reported by KVM_TDX_CAPABILITIES, ensuring
> compliance with the strict requirements of the TDH.MNG.INIT SEAMCALL.
>
> 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>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> Signed-off-by: Lisa Wang <wyihan@google.com>
> ---
> tools/testing/selftests/kvm/Makefile.kvm | 1 +
> .../testing/selftests/kvm/include/x86/processor.h | 2 +
> .../selftests/kvm/include/x86/tdx/tdx_util.h | 35 ++++++
> tools/testing/selftests/kvm/lib/x86/processor.c | 21 +++-
> tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c | 120 +++++++++++++++++++++
> 5 files changed, 175 insertions(+), 4 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> index e5769268936a..3f98d1c6488c 100644
> --- a/tools/testing/selftests/kvm/Makefile.kvm
> +++ b/tools/testing/selftests/kvm/Makefile.kvm
> @@ -27,6 +27,7 @@ LIBKVM_x86 += lib/x86/pmu.c
> LIBKVM_x86 += lib/x86/processor.c
> LIBKVM_x86 += lib/x86/sev.c
> LIBKVM_x86 += lib/x86/svm.c
> +LIBKVM_x86 += lib/x86/tdx/tdx_util.c
> LIBKVM_x86 += lib/x86/ucall.c
> LIBKVM_x86 += lib/x86/vmx.c
>
> diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
> index 0aa6eecfcbde..76180dfaffea 100644
> --- a/tools/testing/selftests/kvm/include/x86/processor.h
> +++ b/tools/testing/selftests/kvm/include/x86/processor.h
> @@ -956,6 +956,8 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs)
> vcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs);
> }
>
> +const struct kvm_cpuid_entry2 *__get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
> + u32 function, u32 index);
> const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
> u32 function, u32 index);
> const struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
> 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 f647e6ca6b34..eb8602dce0bc 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,39 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
> return vm->type == KVM_X86_TDX_VM;
> }
>
> +/*
> + * TDX ioctls
> + * Use underscores to avoid collisions with struct member names.
> + */
> +#define __tdx_vm_ioctl(vm, cmd, _flags, arg) \
> +({ \
> + u64 r; \
> + \
> + union { \
> + struct kvm_tdx_cmd c; \
> + unsigned long raw; \
> + } tdx_cmd = { .c = { \
> + .id = (cmd), \
> + .flags = (u32)(_flags), \
> + .data = (u64)(arg), \
> + } }; \
> + \
> + r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw); \
> + r ?: tdx_cmd.c.hw_error; \
> +})
> +
> +#define tdx_vm_ioctl(vm, cmd, flags, arg) \
> +({ \
> + u64 ret = __tdx_vm_ioctl(vm, cmd, flags, arg); \
> + \
> + if (ret) { \
> + TEST_ASSERT(!ret, \
> + "%s failed, rc: 0x%llx errno: %i (%s)", \
> + #cmd, (unsigned long long)ret, \
> + errno, strerror(errno)); \
> + } \
> +})
> +
> +void tdx_init_vm(struct kvm_vm *vm, u64 attributes);
> +
> #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 b68ad1dc7e02..7d23344854cc 100644
> --- a/tools/testing/selftests/kvm/lib/x86/processor.c
> +++ b/tools/testing/selftests/kvm/lib/x86/processor.c
> @@ -802,6 +802,9 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus)
> vm_sev_ioctl(vm, KVM_SEV_INIT2, &init);
> }
>
> + if (is_tdx_vm(vm))
> + tdx_init_vm(vm, 0);
In this series tdx_init_vm() is only called with 0 for attributes. Do we need
the arg or could we just set it to 0 internally like xfam?
> +
> 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;
> @@ -1328,8 +1331,8 @@ void kvm_init_vm_address_properties(struct kvm_vm *vm)
> }
> }
>
> -const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
> - u32 function, u32 index)
> +const struct kvm_cpuid_entry2 *__get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
> + u32 function, u32 index)
> {
> int i;
>
> @@ -1339,11 +1342,21 @@ const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
> return &cpuid->entries[i];
> }
>
> - TEST_FAIL("CPUID function 0x%x index 0x%x not found ", function, index);
> -
> return NULL;
> }
>
> +const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
> + u32 function, u32 index)
> +{
> + const struct kvm_cpuid_entry2 *entry;
> +
> + entry = __get_cpuid_entry(cpuid, function, index);
> + if (!entry)
> + TEST_FAIL("CPUID function 0x%x index 0x%x not found ", function, index);
> +
> + return entry;
> +}
> +
> #define X86_HYPERCALL(inputs...) \
> ({ \
> u64 r; \
> 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..e1ffb67a106c
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
> @@ -0,0 +1,120 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include "processor.h"
> +#include "tdx/tdx_util.h"
> +
> +static struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm *vm)
> +{
> + static struct kvm_tdx_capabilities *tdx_cap;
> + int nr_cpuid_configs = 4;
> + int rc = -1;
> + int i;
> +
> + if (tdx_cap)
> + return tdx_cap;
> +
> + do {
> + nr_cpuid_configs *= 2;
> +
> + tdx_cap = realloc(tdx_cap, sizeof(*tdx_cap) +
> + (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 = __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;
> +}
> +
> +/*
> + * Filter CPUID based on TDX supported capabilities
> + *
> + * Input Args:
> + * vm - Virtual Machine
> + * cpuid_data - CPUID fields to filter
> + *
> + * Output Args: None
> + *
> + * Return: None
> + *
> + * For each CPUID leaf, filter out unsupported bits based on the capabilities
> + * reported by the TDX module
> + */
> +static void tdx_filter_cpuid(struct kvm_vm *vm,
> + struct kvm_cpuid2 *cpuid_data)
> +{
> + struct kvm_tdx_capabilities *tdx_cap;
> + const 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 = __get_cpuid_entry(&tdx_cap->cpuid, 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++;
> + }
> +}
> +
> +void tdx_init_vm(struct kvm_vm *vm, u64 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(tmp->nent);
> + memcpy(cpuid, tmp, kvm_cpuid2_size(tmp->nent));
> + 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;
> +
> + tdx_vm_ioctl(vm, KVM_TDX_INIT_VM, 0, init_vm);
> +
> + free(init_vm);
> +}
>
^ permalink raw reply [flat|nested] 98+ messages in thread* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-08-13 23:41 ` Edgecombe, Rick P
@ 2026-08-14 21:18 ` Peter Fang
0 siblings, 0 replies; 98+ messages in thread
From: Peter Fang @ 2026-08-14 21:18 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: Aktas, Erdem, Li, Xiaoyao, shuah@kernel.org,
dave.hansen@linux.intel.com, afranji@google.com, kas@kernel.org,
binbin.wu@linux.intel.com, ira.weiny@intel.com,
pbonzini@redhat.com, Chatre, Reinette, isaku.yamahata@intel.com,
ackerleytng@google.com, seanjc@google.com,
pratikrajesh.sampat@amd.com, oupton@kernel.org, wyihan@google.com,
sagis@google.com, Gao, Chao, Wang, Roger,
linux-kselftest@vger.kernel.org, ajones@ventanamicro.com,
Qiang, Chenyi, kvm@vger.kernel.org, linux-coco@lists.linux.dev,
jmcrey@google.com, linux-kernel@vger.kernel.org, x86@kernel.org
On Thu, Aug 13, 2026 at 04:41:07PM -0700, Edgecombe, Rick P wrote:
> On Wed, 2026-07-22 at 23:13 +0000, Lisa Wang wrote:
> > From: Sagi Shahar <sagis@google.com>
> >
> > Add tdx_init_vm() to handle the mandatory VM-level initialization
> > sequence required for Intel TDX.
> >
> > For TDX, the guest's CPUID configuration must be "sealed" during
> > KVM_TDX_INIT_VM before any vCPUs are created. This is necessary because
> > the TDX hardware directly virtualizes CPUID and includes the
> > configuration in the guest's initial security measurement.
>
> "TDX hardware" should be TDX module. But I'm not sure what it is trying to say
> about directly virtualizes.
>
> Also, it is not accurate to say that the CPUID configuration is included in the
> measurement? Is that right Peter? It's not in the report, but is it in the
> measurement?
CPUID is not in the report or the TDX module's measurement. TD
attributes and XFAM are in both the report and initial measurement, and
some of the bits in there are related to CPUID (e.g. ATTRIBUTES.PKS or
XFAM.MAXPA_VIRT). Probably better to make a distinction between these
things.
>
> Or maybe it doesn't really need to be in the log anyway.
>
> >
^ permalink raw reply [flat|nested] 98+ messages in thread
* Re: [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM
2026-07-22 23:13 ` [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM Lisa Wang
2026-07-23 8:44 ` Xiaoyao Li
2026-08-13 23:41 ` Edgecombe, Rick P
@ 2026-08-20 8:46 ` Peter Fang
2 siblings, 0 replies; 98+ messages in thread
From: Peter Fang @ 2026-08-20 8:46 UTC (permalink / raw)
To: Lisa Wang
Cc: Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Ira Weiny, Isaku Yamahata,
Kiryl Shutsemau, linux-kselftest, Paolo Bonzini, Pratik R. Sampat,
Reinette Chatre, Rick Edgecombe, Roger Wang, Ryan Afranji,
Sagi Shahar, Sean Christopherson, Shuah Khan, Xiaoyao Li,
Oliver Upton, Jeremiah McReynolds, kvm, linux-coco, linux-kernel,
x86
On Wed, Jul 22, 2026 at 11:13:08PM +0000, Lisa Wang wrote:
> From: Sagi Shahar <sagis@google.com>
>
> Add tdx_init_vm() to handle the mandatory VM-level initialization
> sequence required for Intel TDX.
>
> For TDX, the guest's CPUID configuration must be "sealed" during
> KVM_TDX_INIT_VM before any vCPUs are created. This is necessary because
> the TDX hardware directly virtualizes CPUID and includes the
> configuration in the guest's initial security measurement.
>
> The helper calculates the required CPUID values by filtering the host-
> supported bits (kvm_get_supported_cpuid) against the "directly
> configurable" bits reported by KVM_TDX_CAPABILITIES, ensuring
> compliance with the strict requirements of the TDH.MNG.INIT SEAMCALL.
>
[ ... ]
> +
> +/*
> + * Filter CPUID based on TDX supported capabilities
> + *
> + * Input Args:
> + * vm - Virtual Machine
> + * cpuid_data - CPUID fields to filter
> + *
> + * Output Args: None
> + *
> + * Return: None
> + *
> + * For each CPUID leaf, filter out unsupported bits based on the capabilities
> + * reported by the TDX module
> + */
> +static void tdx_filter_cpuid(struct kvm_vm *vm,
> + struct kvm_cpuid2 *cpuid_data)
> +{
> + struct kvm_tdx_capabilities *tdx_cap;
> + const struct kvm_cpuid_entry2 *config;
Nit: reverse fir tree order i.e. declaring "config" first?
> + struct kvm_cpuid_entry2 *e;
> + int i;
> +
^ permalink raw reply [flat|nested] 98+ messages in thread
* [PATCH v14 04/22] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration
2026-07-22 23:13 [PATCH v14 00/22] TDX KVM selftests Lisa Wang
` (2 preceding siblings ...)
2026-07-22 23:13 ` [PATCH v14 03/22] KVM: selftests: Initialize the TDX VM Lisa Wang
@ 2026-07-22 23:13 ` Lisa Wang
2026-08-13 23:45 ` Edgecombe, Rick P
2026-07-22 23:13 ` [PATCH v14 05/22] KVM: selftests: Expose segment definitions to assembly files Lisa Wang
` (18 subsequent siblings)
22 siblings, 1 reply; 98+ messages in thread
From: Lisa Wang @ 2026-07-22 23:13 UTC (permalink / raw)
To: Andrew Jones, Ackerley Tng, Binbin Wu, Chao Gao, Chenyi Qiang,
Dave Hansen, Erdem Aktas, Ira Weiny, Isaku Yamahata,
Kiryl Shutsemau, linux-kselftest, Paolo Bonzini, Pratik R. Sampat,
Reinette Chatre, Rick Edgecombe, Roger Wang, Ryan Afranji,
Sagi Shahar, Sean Christopherson, Shuah Khan, Xiaoyao Li,
Oliver Upton
Cc: Jeremiah McReynolds, kvm, linux-coco, linux-kernel, x86,
Lisa Wang
From: Isaku Yamahata <isaku.yamahata@intel.com>
Make sure that all the attributes enabled by the test are reported as
supported by both the TDX module and KVM. KVM filters out the attributes
not supported by itself.
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>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Lisa Wang <wyihan@google.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c | 12 ++++++++++++
1 file changed, 12 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 e1ffb67a106c..c01a26567b73 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -93,6 +93,16 @@ static void tdx_filter_cpuid(struct kvm_vm *vm,
}
}
+static void tdx_check_attributes(struct kvm_vm *vm, u64 attributes)
+{
+ struct kvm_tdx_capabilities *tdx_cap;
+
+ tdx_cap = tdx_read_capabilities(vm);
+
+ /* Make sure all the attributes are reported as supported */
+ TEST_ASSERT_EQ(attributes & tdx_cap->supported_attrs, attributes);
+}
+
void tdx_init_vm(struct kvm_vm *vm, u64 attributes)
{
struct kvm_tdx_init_vm *init_vm;
@@ -112,6 +122,8 @@ void tdx_init_vm(struct kvm_vm *vm, u64 attributes)
memcpy(&init_vm->cpuid, cpuid, kvm_cpuid2_size(cpuid->nent));
free(cpuid);
+ tdx_check_attributes(vm, attributes);
+
init_vm->attributes = attributes;
tdx_vm_ioctl(vm, KVM_TDX_INIT_VM, 0, init_vm);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 98+ messages in thread* Re: [PATCH v14 04/22] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration
2026-07-22 23:13 ` [PATCH v14 04/22] KVM: selftests: TDX: Use KVM_TDX_CAPABILITIES to validate TDs' attribute configuration Lisa Wang
@ 2026-08-13 23:45 ` Edgecombe, Rick P
2026-09-08 19:06 ` Ackerley Tng
0 siblings, 1 reply; 98+ messages in thread
From: Edgecombe, Rick P @ 2026-08-13 23:45 UTC (permalink / raw)
To: Aktas, Erdem, Li, Xiaoyao, shuah@kernel.org,
dave.hansen@linux.intel.com, afranji@google.com, kas@kernel.org,
binbin.wu@linux.intel.com, ira.weiny@intel.com,
pbonzini@redhat.com, Chatre, Reinette, isaku.yamahata@intel.com,
ackerleytng@google.com, seanjc@google.com,
pratikrajesh.sampat@amd.com, oupton@kernel.org, wyihan@google.com,
sagis@google.com, Gao, Chao, Wang, Roger,