diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index db6b7790d0c25..f0cb1328698f6 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1483,6 +1483,7 @@ struct kvm_x86_ops { int (*mem_enc_op_dev)(void __user *argp); int (*mem_enc_op)(struct kvm *kvm, void __user *argp); + int (*mem_enc_op_vcpu)(struct kvm_vcpu *vcpu, void __user *argp); int (*mem_enc_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp); int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp); int (*vm_copy_enc_context_from)(struct kvm *kvm, unsigned int source_fd); diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index ddf5e3dc093f6..e36a851388570 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -515,6 +515,7 @@ struct kvm_pmu_event_filter { enum kvm_tdx_cmd_id { KVM_TDX_CAPABILITIES = 0, KVM_TDX_INIT_VM, + KVM_TDX_INIT_VCPU, KVM_TDX_CMD_NR_MAX, }; diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index ee9f286f147fc..76053f2538c89 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -117,6 +117,14 @@ static int vt_mem_enc_op(struct kvm *kvm, void __user *argp) return tdx_vm_ioctl(kvm, argp); } +static int vt_mem_enc_op_vcpu(struct kvm_vcpu *vcpu, void __user *argp) +{ + if (!is_td_vcpu(vcpu)) + return -EINVAL; + + return tdx_vcpu_ioctl(vcpu, argp); +} + struct kvm_x86_ops vt_x86_ops __initdata = { .name = "kvm_intel", @@ -259,6 +267,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .mem_enc_op_dev = vt_mem_enc_op_dev, .mem_enc_op = vt_mem_enc_op, + .mem_enc_op_vcpu = vt_mem_enc_op_vcpu, }; static struct kvm_x86_init_ops vt_init_ops __initdata = { diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 033e38b590f01..7e96c37dc7fa8 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -106,6 +106,11 @@ static inline bool is_hkid_assigned(struct kvm_tdx *kvm_tdx) return kvm_tdx->hkid >= 0; } +static inline bool is_td_finalized(struct kvm_tdx *kvm_tdx) +{ + return kvm_tdx->finalized; +} + void tdx_hardware_enable(void) { } @@ -794,6 +799,45 @@ int tdx_vm_ioctl(struct kvm *kvm, void __user *argp) return r; } +int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp) +{ + struct kvm_tdx *kvm_tdx = to_kvm_tdx(vcpu->kvm); + struct vcpu_tdx *tdx = to_tdx(vcpu); + struct kvm_tdx_cmd cmd; + u64 err; + + if (tdx->initialized) + return -EINVAL; + + if (!is_td_initialized(vcpu->kvm) || is_td_finalized(kvm_tdx)) + return -EINVAL; + + if (copy_from_user(&cmd, argp, sizeof(cmd))) + return -EFAULT; + + if (cmd.metadata || cmd.id != KVM_TDX_INIT_VCPU) + return -EINVAL; + + err = tdh_vp_init(tdx->tdvpr.pa, cmd.data); + if (WARN_ON_ONCE(err)) { + pr_tdx_error(TDH_VP_INIT, err, NULL); + return -EIO; + } + + tdx->initialized = true; + + td_vmcs_write16(tdx, POSTED_INTR_NV, POSTED_INTR_VECTOR); + td_vmcs_write64(tdx, POSTED_INTR_DESC_ADDR, __pa(&tdx->pi_desc)); + td_vmcs_setbit32(tdx, PIN_BASED_VM_EXEC_CONTROL, PIN_BASED_POSTED_INTR); + + if (vcpu->kvm->arch.bus_lock_detection_enabled) + td_vmcs_setbit32(tdx, + SECONDARY_VM_EXEC_CONTROL, + SECONDARY_EXEC_BUS_LOCK_DETECTION); + + return 0; +} + int __init tdx_hardware_setup(struct kvm_x86_ops *x86_ops) { int i, max_pkgs; diff --git a/arch/x86/kvm/vmx/tdx.h b/arch/x86/kvm/vmx/tdx.h index 605cbce0e7e04..ccc53e42a3946 100644 --- a/arch/x86/kvm/vmx/tdx.h +++ b/arch/x86/kvm/vmx/tdx.h @@ -31,6 +31,8 @@ struct kvm_tdx { int cpuid_nent; struct kvm_cpuid_entry2 cpuid_entries[KVM_MAX_CPUID_ENTRIES]; + bool finalized; + u64 tsc_offset; }; @@ -42,6 +44,8 @@ struct vcpu_tdx { /* Posted interrupt descriptor */ struct pi_desc pi_desc; + + bool initialized; }; #define TDX_MAX_NR_CPUID_CONFIGS \ diff --git a/arch/x86/kvm/vmx/tdx_stubs.c b/arch/x86/kvm/vmx/tdx_stubs.c index 97a9cfd88f9ab..6bbd63d1ef375 100644 --- a/arch/x86/kvm/vmx/tdx_stubs.c +++ b/arch/x86/kvm/vmx/tdx_stubs.c @@ -13,3 +13,4 @@ void tdx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) {} int tdx_dev_ioctl(void __user *argp) { return -EOPNOTSUPP; } int tdx_vm_ioctl(struct kvm *kvm, void __user *argp) { return -EOPNOTSUPP; } +int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp) { return -ENOPNOTSUPP; } diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index fcc0fdd56ffe8..ecad3d248c045 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -138,5 +138,6 @@ void tdx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event); int tdx_dev_ioctl(void __user *argp); int tdx_vm_ioctl(struct kvm *kvm, void __user *argp); +int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp); #endif /* __KVM_X86_VMX_X86_OPS_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fb39785a48022..b35e31f9fd0a7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5524,6 +5524,12 @@ long kvm_arch_vcpu_ioctl(struct file *filp, case KVM_SET_DEVICE_ATTR: r = kvm_vcpu_ioctl_device_attr(vcpu, ioctl, argp); break; + case KVM_MEMORY_ENCRYPT_OP: + r = -EINVAL; + if (!kvm_x86_ops.mem_enc_op_vcpu) + goto out; + r = kvm_x86_ops.mem_enc_op_vcpu(vcpu, argp); + break; default: r = -EINVAL; } diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index ddf5e3dc093f6..e36a851388570 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -515,6 +515,7 @@ struct kvm_pmu_event_filter { enum kvm_tdx_cmd_id { KVM_TDX_CAPABILITIES = 0, KVM_TDX_INIT_VM, + KVM_TDX_INIT_VCPU, KVM_TDX_CMD_NR_MAX, };