On 7/23/2026 7:13 AM, Lisa Wang wrote:
From: Sagi Shahar <[email protected]>
TDX VMs need to issue the KVM_TDX_INIT_VCPU ioctl for each vcpu after
vcpu creation.
Since the cpuids for TD are managed by the TDX module, read the values
Please use CPUIDs instead of cpuids.
virtualized for the TD using KVM_TDX_GET_CPUID and set them in kvm using
KVM_SET_CPUID2 so that kvm has an accurate view of the VM cpuid values.
This does two things, and KVM_SET_CPUID2 isn't a hard requirement for
KVM_TDX_INIT_VCPU. we'd better split it into two patches.
Signed-off-by: Sagi Shahar <[email protected]>
Signed-off-by: Lisa Wang <[email protected]>
---
.../selftests/kvm/include/x86/tdx/tdx_util.h | 21 ++++++++++++++
tools/testing/selftests/kvm/lib/x86/processor.c | 33 ++++++++++++++++------
2 files changed, 46 insertions(+), 8 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
index f5003cbaa106..07e7f5c90329 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -44,6 +44,27 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
} \
})
+#define __tdx_vcpu_ioctl(vcpu, cmd, _flags, arg) \
+({ \
+ union { \
+ struct kvm_tdx_cmd c; \
+ unsigned long raw; \
+ } tdx_cmd = { .c = { \
+ .id = (cmd), \
+ .flags = (u32)(_flags), \
+ .data = (u64)(arg), \
+ } }; \
+ \
+ __vcpu_ioctl(vcpu, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd.raw); \
+})
+
+#define tdx_vcpu_ioctl(vcpu, cmd, flags, arg) \
+({ \
+ int ret = __tdx_vcpu_ioctl(vcpu, cmd, flags, arg); \
+ TEST_ASSERT(!ret, "%s failed, errno: %d (%s)", \
+ #cmd, errno, strerror(errno)); \
+})
It doesn't handle the tdx_cmd.c.hw_error for vcpu ioctl, but handle it
for vm ioctl, which looks inconsistent. This at least deserves a
justification in the changelog.
void tdx_init_vm(struct kvm_vm *vm, u64 attributes);
void tdx_vm_setup_boot_code_region(struct kvm_vm *vm);
void tdx_vm_setup_boot_parameters_region(struct kvm_vm *vm, u32
nr_runnable_vcpus);
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c
b/tools/testing/selftests/kvm/lib/x86/processor.c
index 8f8bb90fec35..f6a2aa6b86a4 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -838,6 +838,17 @@ gva_t kvm_allocate_vcpu_stack(struct kvm_vm *vm)
return stack_gva;
}
+static void tdx_vcpu_init(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid2 *cpuid;
+
+ cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
+ tdx_vcpu_ioctl(vcpu, KVM_TDX_GET_CPUID, 0, cpuid);
If I remember correctly, though KVM_TDX_GET_CPUID is a vcpu ioctl, the
data returned by KVM is retrived from TDX module and TDX module only
maintains the TD scope CPUID. So the CPUID returned here is TD scope,
for per-vcpu CPUIDs, e.g., x2apicid, we need to update them accordingly.
This seems not a functional gap. I'm OK to leave it to the future, but
please leave a TODO comment for it.
+ vcpu_init_cpuid(vcpu, cpuid);
+ free(cpuid);
+ tdx_vcpu_ioctl(vcpu, KVM_TDX_INIT_VCPU, 0, NULL);
+}
+
struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, u32 vcpu_id)
{
struct kvm_mp_state mp_state;
@@ -845,15 +856,21 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, u32
vcpu_id)
struct kvm_regs regs;
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, ®s);
- regs.rflags = regs.rflags | 0x2;
- regs.rsp = kvm_allocate_vcpu_stack(vm);
- vcpu_regs_set(vcpu, ®s);
+ if (is_tdx_vm(vm)) {
+ tdx_vcpu_init(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, ®s);
+ regs.rflags = regs.rflags | 0x2;
+ regs.rsp = kvm_allocate_vcpu_stack(vm);
+ vcpu_regs_set(vcpu, ®s);
+ }
/* Setup the MP state */
mp_state.mp_state = 0;