Add support to export and import VCPU for cases where the VCPU state is only accessible to the guest. Live migration of confidential computing needs help of KVM for the firmware specific calls at least for TDX. Introduce optional KVM_EXPORT_VCPU and KVM_IMPORT_VCPU. Based on earlier code by Wei Wang . Co-developed-by: Kishen Maloor Signed-off-by: Kishen Maloor Signed-off-by: Tony Lindgren --- arch/x86/include/asm/kvm-x86-ops.h | 2 ++ arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/x86.c | 40 ++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 8 ++++++ 4 files changed, 52 insertions(+) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 173d0c4f1115e..7f110f80d6f82 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -152,6 +152,8 @@ KVM_X86_OP_OPTIONAL_RET0(cap_live_migration) KVM_X86_OP_OPTIONAL(migrate_cmd) KVM_X86_OP_OPTIONAL(export_memory) KVM_X86_OP_OPTIONAL(import_memory) +KVM_X86_OP_OPTIONAL(export_vcpu) +KVM_X86_OP_OPTIONAL(import_vcpu) #endif #undef KVM_X86_OP diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 9a517bfc2f3a6..b6362408dab80 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2014,6 +2014,8 @@ struct kvm_x86_ops { int (*migrate_cmd)(struct kvm *kvm, struct kvm_migrate_cmd *cmd); int (*export_memory)(struct kvm *kvm, struct kvm_memory_transfer *mem); int (*import_memory)(struct kvm *kvm, struct kvm_memory_transfer *mem); + int (*export_vcpu)(struct kvm_vcpu *vcpu, struct kvm_vcpu_transfer *vcpu_state); + int (*import_vcpu)(struct kvm_vcpu *vcpu, struct kvm_vcpu_transfer *vcpu_state); }; struct kvm_x86_nested_ops { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8a99c665008a3..e8385326894b1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6189,6 +6189,38 @@ static int kvm_get_reg_list(struct kvm_vcpu *vcpu, return 0; } +static int kvm_vcpu_ioctl_transfer_vcpu(struct kvm_vcpu *vcpu, bool import, + void __user *argp) +{ + struct kvm_vcpu_transfer vcpu_state; + struct kvm *kvm = vcpu->kvm; + int r; + + if (!kvm_x86_call(cap_live_migration)(kvm) || + (import && !kvm_x86_ops.import_vcpu) || + (!import && !kvm_x86_ops.export_vcpu)) + return -ENOTTY; + + if (copy_from_user(&vcpu_state, argp, sizeof(vcpu_state))) + return -EFAULT; + + if (vcpu_state.reserved || vcpu_state.buf.reserved) + return -EINVAL; + + if (import) + r = kvm_x86_call(import_vcpu)(vcpu, &vcpu_state); + else + r = kvm_x86_call(export_vcpu)(vcpu, &vcpu_state); + if (r > 0) + r = -EIO; + + /* Copy back also on an error to report a partially done transfer */ + if (copy_to_user(argp, &vcpu_state, sizeof(vcpu_state))) + r = -EFAULT; + + return r; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -6659,6 +6691,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp, goto out; r = kvm_x86_ops.vcpu_mem_enc_ioctl(vcpu, argp); break; + case KVM_EXPORT_VCPU: { + r = kvm_vcpu_ioctl_transfer_vcpu(vcpu, false, argp); + break; + } + case KVM_IMPORT_VCPU: { + r = kvm_vcpu_ioctl_transfer_vcpu(vcpu, true, argp); + break; + } default: r = -EINVAL; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 666bbdf220d65..0a9aa126daadb 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1496,6 +1496,8 @@ struct kvm_enc_region { /* Available with KVM_CAP_LIVE_MIGRATION */ #define KVM_EXPORT_MEMORY _IOWR(KVMIO, 0xe5, struct kvm_memory_transfer) #define KVM_IMPORT_MEMORY _IOWR(KVMIO, 0xe6, struct kvm_memory_transfer) +#define KVM_EXPORT_VCPU _IOWR(KVMIO, 0xe7, struct kvm_vcpu_transfer) +#define KVM_IMPORT_VCPU _IOWR(KVMIO, 0xe8, struct kvm_vcpu_transfer) #define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0) #define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1) @@ -1705,4 +1707,10 @@ struct kvm_memory_transfer { struct kvm_transfer_buffer buf; }; +struct kvm_vcpu_transfer { + __u32 flags; + __u32 reserved; + struct kvm_transfer_buffer buf; +}; + #endif /* __LINUX_KVM_H */ -- 2.43.0