On 4/2/2025 7:41 PM, Daniel P. Berrangé wrote:
On Tue, Apr 01, 2025 at 09:01:18AM -0400, Xiaoyao Li wrote:
Invoke KVM_TDX_INIT_VM in kvm_arch_pre_create_vcpu() that
KVM_TDX_INIT_VM configures global TD configurations, e.g. the canonical
CPUID config, and must be executed prior to creating vCPUs.
Use kvm_x86_arch_cpuid() to setup the CPUID settings for TDX VM.
Note, this doesn't address the fact that QEMU may change the CPUID
configuration when creating vCPUs, i.e. punts on refactoring QEMU to
provide a stable CPUID config prior to kvm_arch_init().
Signed-off-by: Xiaoyao Li <xiaoyao...@intel.com>
Acked-by: Gerd Hoffmann <kra...@redhat.com>
Acked-by: Markus Armbruster <arm...@redhat.com>
---
Changes in v8:
- Drop the code that initializes cpu->kvm_state before
kvm_arch_pre_create_vcpu() because it's not needed anymore.
Changes in v7:
- Add comments to explain why KVM_TDX_INIT_VM should retry on -EAGAIN;
- Add retry limit of 10000 times for -EAGAIN on KVM_TDX_INIT_VM;
Changes in v6:
- setup xfam explicitly to fit with new uapi;
- use tdx_caps->cpuid to filter the input of cpuids because now KVM only
allows the leafs that reported via KVM_TDX_GET_CAPABILITIES;
Changes in v4:
- mark init_vm with g_autofree() and use QEMU_LOCK_GUARD() to eliminate
the goto labels; (Daniel)
Changes in v3:
- Pass @errp in tdx_pre_create_vcpu() and pass error info to it. (Daniel)
---
target/i386/kvm/kvm.c | 16 +++---
target/i386/kvm/kvm_i386.h | 5 ++
target/i386/kvm/meson.build | 2 +-
target/i386/kvm/tdx-stub.c | 10 ++++
target/i386/kvm/tdx.c | 105 ++++++++++++++++++++++++++++++++++++
target/i386/kvm/tdx.h | 6 +++
6 files changed, 137 insertions(+), 7 deletions(-)
create mode 100644 target/i386/kvm/tdx-stub.c
diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c
index 16f67e18ae78..0afaf739c09f 100644
--- a/target/i386/kvm/tdx.c
+++ b/target/i386/kvm/tdx.c
+int tdx_pre_create_vcpu(CPUState *cpu, Error **errp)
+{
+ X86CPU *x86cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86cpu->env;
+ g_autofree struct kvm_tdx_init_vm *init_vm = NULL;
+ Error *local_err = NULL;
+ int retry = 10000;
+ int r = 0;
+
+ QEMU_LOCK_GUARD(&tdx_guest->lock);
+ if (tdx_guest->initialized) {
+ return r;
+ }
+
+ init_vm = g_malloc0(sizeof(struct kvm_tdx_init_vm) +
+ sizeof(struct kvm_cpuid_entry2) *
KVM_MAX_CPUID_ENTRIES);
+
+ r = setup_td_xfam(x86cpu, errp);
+ if (r) {
+ return r;
+ }
+
+ init_vm->cpuid.nent = kvm_x86_build_cpuid(env, init_vm->cpuid.entries, 0);
+ tdx_filter_cpuid(&init_vm->cpuid);
+
+ init_vm->attributes = tdx_guest->attributes;
+ init_vm->xfam = tdx_guest->xfam;
+
+ /*
+ * KVM_TDX_INIT_VM gets -EAGAIN when KVM side SEAMCALL(TDH_MNG_CREATE)
+ * gets TDX_RND_NO_ENTROPY due to Random number generation (e.g., RDRAND or
+ * RDSEED) is busy.
+ *
+ * Retry for the case.
+ */
+ do {
+ error_free(local_err);
+ local_err = NULL;
+ r = tdx_vm_ioctl(KVM_TDX_INIT_VM, 0, init_vm, &local_err);
+ } while (r == -EAGAIN && --retry);
+
+ if (r < 0) {
+ if (!retry) {
+ error_report("Hardware RNG (Random Number Generator) is busy "
+ "occupied by someone (via RDRAND/RDSEED) maliciously,
"
+ "which leads to KVM_TDX_INIT_VM keeping failure "
+ "due to lack of entropy.");
This needs to be
error_append_hint(local_err, ....);
so that this message gets associated with the error object that
is propagated, and the top level will print it all at once.
Good suggestion! Will change to it in the next version.
+ }
+ error_propagate(errp, local_err);
+ return r;
+ }
+
+ tdx_guest->initialized = true;
+
+ return 0;
+}
With regards,
Daniel