Received: by 2002:a05:6a10:d5a5:0:0:0:0 with SMTP id gn37csp4635343pxb; Tue, 5 Oct 2021 07:16:44 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwfOXFUwR+mEZLJqAVUZZFN4onyQZCbSUMUMUp0aZ2IetY35Fi6bNZCvL/NuNroAJ7WNvgV X-Received: by 2002:a17:90a:1a19:: with SMTP id 25mr4149275pjk.34.1633443404716; Tue, 05 Oct 2021 07:16:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1633443404; cv=none; d=google.com; s=arc-20160816; b=jrEQLvQwpv+lYjZ/v5B2J5MY+YgSa0rggf4/RVaVKlO4R93UxUkExC6vnOzTG0nxYR W2A69ju7ZgYbvnGbuTniyBp/+cuWUCi7D4Y/QRGu6mqKHdx1Xlp8D04T9Ppn73U1j0b7 Q3L84Bl8sj67K+4l9KGcbV2TfC2eeHOJ3anSsBM8OjFU1cZq1+l2TnIMcDcCVnUNbYoa dKOAJRYzPiFspdHTx1/Y6hYzjwqLb/ERi2/1RiCl+qFT3wEcY4F7ZK5BxcC1HYz0WAf2 gyo6tqAEG2tk+B5CUe6/2kO5e/2xB/l+ojkPkpI2ECdt9LErf1BL39tYuqGTYg9V/z86 xX/Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:dkim-signature; bh=t2Nyc947fq1fyt/+C1EvB7mfKiK13Hmxu0sij0YInK8=; b=RHdF+ty7uNqWRfxVJ7n0h4bve4pvLQVq2yZMUl9eze//H0CFDAVEbnMW3H/nCFAtWT Byq8zpwVmkd2BDlKfiIsYT2WRtIlCBasl0burnaCRzYfbMs3onyzdaH3CDZdtiTg9QR6 CHM3BsMEznDjG2r4TcgQu7PSFeNh38tupp4gIKWLnBOxKIRY4c3u+VBw+OdpDIjmtI0M xl59rH6Bb8/KOdNG5GYWTXszxwXUwU+gj3xbOAWL/4ZHRxJgh2FNLaOSQU3JYVfHAeLi +mr3+ym8SIPCZEZRgtWkVZieYhlsjPh9bswuNsSw1vzywJud1a8NLszXGs5M8BmUA5OB d2fQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=OM3RhU0E; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id 21si21146959pgb.269.2021.10.05.07.16.29; Tue, 05 Oct 2021 07:16:44 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=OM3RhU0E; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236225AbhJEORC (ORCPT + 99 others); Tue, 5 Oct 2021 10:17:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40906 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235038AbhJEOQz (ORCPT ); Tue, 5 Oct 2021 10:16:55 -0400 Received: from mail-pl1-x649.google.com (mail-pl1-x649.google.com [IPv6:2607:f8b0:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0C1EC0617BF for ; Tue, 5 Oct 2021 07:14:08 -0700 (PDT) Received: by mail-pl1-x649.google.com with SMTP id o6-20020a170902bcc600b00138a9a5bc42so1859021pls.17 for ; Tue, 05 Oct 2021 07:14:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=t2Nyc947fq1fyt/+C1EvB7mfKiK13Hmxu0sij0YInK8=; b=OM3RhU0EDcnX9C8D3ifKmf3VIjb/hO19JGMU2lHvE78VXsoG7c0CYW1LqPI89hm0Lh hEtjT3XnUwBpvYdexu/WfTQjGDzDPw0mT9bPuNaEWlpWom95PVKZsYCLE0DVHT5G+Xym 5mUxnKLNOWOUtKr6ljpv8rTcRtf7FBLuOs4gqafKnPR7UAr77FYLm/pjbsFhWEqOgURM qe+RP2o9FlgU6JmfRt7W0VKoMYYEnY5qkBFyoFRyWWSF0BVmuOSZfqhxRM3yJkyQBz2F R4B9bApZD7Ot+GEe5fzRW5xG+AOgyaPEjNYncG2dBPexgdqGITH2pwwspZhqSlEyPkWr Pc1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=t2Nyc947fq1fyt/+C1EvB7mfKiK13Hmxu0sij0YInK8=; b=6GeMdiDNBUpiJZPwlR/CCaBn8fJu76L4v/O2jbF7gD1kZhVzCw/2ZcLyChNpaEH3ew 3qci0SVaUSKQDRGu1umGCeILqTSVlTj+bTJ9e8cENYBn6KnjEKDkHfqohLzM1z1trwKj eFelYcWl7+BSR++CEAv9yYN9B3Znyk0pBW6L0JBQaoZcypUl4DokjG/hv182zdXoYji9 Q+Z4yxGISDQo2xaIoZ0Q9HVotR/jflPlfPJzg1FtU5ecdJIh0oo5HDN4mE0wUao96cmi 2CgwHrcz3M1huGGrBbRWn6mSvdRuTMl01ssq7hkxb84f4pgtgZ/27h1bB1nTzuNw0o+F fZZA== X-Gm-Message-State: AOAM533i7MHCmPDBzhkYGqpsfuSH81UN37K3/w2rZuW/lxcXayJdjvCe bDxQZPiijp622Q8yB/FAiRx3LgqMxuA= X-Received: from pgonda1.kir.corp.google.com ([2620:15c:29:204:225f:7216:6111:7f1c]) (user=pgonda job=sendgmr) by 2002:a17:90b:30cb:: with SMTP id hi11mr4131742pjb.51.1633443248182; Tue, 05 Oct 2021 07:14:08 -0700 (PDT) Date: Tue, 5 Oct 2021 07:13:54 -0700 In-Reply-To: <20211005141357.2393627-1-pgonda@google.com> Message-Id: <20211005141357.2393627-2-pgonda@google.com> Mime-Version: 1.0 References: <20211005141357.2393627-1-pgonda@google.com> X-Mailer: git-send-email 2.33.0.800.g4c38ced690-goog Subject: [PATCH 1/4 V9] KVM: SEV: Add support for SEV intra host migration From: Peter Gonda To: kvm@vger.kernel.org Cc: Peter Gonda , Sean Christopherson , Marc Orr , Paolo Bonzini , David Rientjes , "Dr . David Alan Gilbert" , Brijesh Singh , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , linux-kernel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org For SEV to work with intra host migration, contents of the SEV info struct such as the ASID (used to index the encryption key in the AMD SP) and the list of memory regions need to be transferred to the target VM. This change adds a commands for a target VMM to get a source SEV VM's sev info. Signed-off-by: Peter Gonda Suggested-by: Sean Christopherson Reviewed-by: Marc Orr Cc: Marc Orr Cc: Paolo Bonzini Cc: Sean Christopherson Cc: David Rientjes Cc: Dr. David Alan Gilbert Cc: Brijesh Singh Cc: Vitaly Kuznetsov Cc: Wanpeng Li Cc: Jim Mattson Cc: Joerg Roedel Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Borislav Petkov Cc: "H. Peter Anvin" Cc: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- Documentation/virt/kvm/api.rst | 15 ++++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm/sev.c | 137 ++++++++++++++++++++++++++++++++ arch/x86/kvm/svm/svm.c | 1 + arch/x86/kvm/svm/svm.h | 2 + arch/x86/kvm/x86.c | 6 ++ include/uapi/linux/kvm.h | 1 + 7 files changed, 163 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 3b093d6dbe22..d9797c6d4b1d 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6911,6 +6911,21 @@ MAP_SHARED mmap will result in an -EINVAL return. When enabled the VMM may make use of the ``KVM_ARM_MTE_COPY_TAGS`` ioctl to perform a bulk copy of tags to/from the guest. +7.29 KVM_CAP_VM_MIGRATE_PROTECTED_VM_FROM +------------------------------------- + +Architectures: x86 SEV enabled +Type: vm +Parameters: args[0] is the fd of the source vm +Returns: 0 on success + +This capability enables userspace to migrate the encryption context from the VM +indicated by the fd to the VM this is called on. + +This is intended to support intra-host migration of VMs between userspace VMMs. +in-guest workloads scheduled by the host. This allows for upgrading the VMM +process without interrupting the guest. + 8. Other capabilities. ====================== diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 88f0326c184a..a334e6b36309 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1481,6 +1481,7 @@ struct kvm_x86_ops { 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); + int (*vm_migrate_protected_vm_from)(struct kvm *kvm, unsigned int source_fd); int (*get_msr_feature)(struct kvm_msr_entry *entry); diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 69f1155ae45f..8cf6c475f866 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1524,6 +1524,143 @@ static bool cmd_allowed_from_miror(u32 cmd_id) return false; } +static int sev_lock_for_migration(struct kvm *kvm) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + + /* + * Bail if this VM is already involved in a migration to avoid deadlock + * between two VMs trying to migrate to/from each other. + */ + if (atomic_cmpxchg_acquire(&sev->migration_in_progress, 0, 1)) + return -EBUSY; + + mutex_lock(&kvm->lock); + + return 0; +} + +static void sev_unlock_after_migration(struct kvm *kvm) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + + mutex_unlock(&kvm->lock); + atomic_set_release(&sev->migration_in_progress, 0); +} + + +static int sev_lock_vcpus_for_migration(struct kvm *kvm) +{ + struct kvm_vcpu *vcpu; + int i, j; + + kvm_for_each_vcpu(i, vcpu, kvm) { + if (mutex_lock_killable(&vcpu->mutex)) + goto out_unlock; + } + + return 0; + +out_unlock: + kvm_for_each_vcpu(j, vcpu, kvm) { + if (i == j) + break; + + mutex_unlock(&vcpu->mutex); + } + return -EINTR; +} + +static void sev_unlock_vcpus_for_migration(struct kvm *kvm) +{ + struct kvm_vcpu *vcpu; + int i; + + kvm_for_each_vcpu(i, vcpu, kvm) { + mutex_unlock(&vcpu->mutex); + } +} + +static void sev_migrate_from(struct kvm_sev_info *dst, + struct kvm_sev_info *src) +{ + dst->active = true; + dst->asid = src->asid; + dst->misc_cg = src->misc_cg; + dst->handle = src->handle; + dst->pages_locked = src->pages_locked; + + src->asid = 0; + src->active = false; + src->handle = 0; + src->pages_locked = 0; + src->misc_cg = NULL; + + INIT_LIST_HEAD(&dst->regions_list); + list_replace_init(&src->regions_list, &dst->regions_list); +} + +int svm_vm_migrate_from(struct kvm *kvm, unsigned int source_fd) +{ + struct kvm_sev_info *dst_sev = &to_kvm_svm(kvm)->sev_info; + struct file *source_kvm_file; + struct kvm *source_kvm; + struct kvm_vcpu *vcpu; + int i, ret; + + ret = sev_lock_for_migration(kvm); + if (ret) + return ret; + + if (sev_guest(kvm)) { + ret = -EINVAL; + goto out_unlock; + } + + source_kvm_file = fget(source_fd); + if (!file_is_kvm(source_kvm_file)) { + ret = -EBADF; + goto out_fput; + } + + source_kvm = source_kvm_file->private_data; + ret = sev_lock_for_migration(source_kvm); + if (ret) + goto out_fput; + + if (!sev_guest(source_kvm) || sev_es_guest(source_kvm)) { + ret = -EINVAL; + goto out_source; + } + ret = sev_lock_vcpus_for_migration(kvm); + if (ret) + goto out_dst_vcpu; + ret = sev_lock_vcpus_for_migration(source_kvm); + if (ret) + goto out_source_vcpu; + + sev_migrate_from(dst_sev, &to_kvm_svm(source_kvm)->sev_info); + kvm_for_each_vcpu(i, vcpu, source_kvm) { + kvm_vcpu_reset(vcpu, /* init_event= */ false); + } + ret = 0; + +out_source_vcpu: + sev_unlock_vcpus_for_migration(source_kvm); + +out_dst_vcpu: + sev_unlock_vcpus_for_migration(kvm); + +out_source: + sev_unlock_after_migration(source_kvm); +out_fput: + if (source_kvm_file) + fput(source_kvm_file); +out_unlock: + sev_unlock_after_migration(kvm); + return ret; +} + int svm_mem_enc_op(struct kvm *kvm, void __user *argp) { struct kvm_sev_cmd sev_cmd; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 89077160d463..1bda39844773 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4697,6 +4697,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .mem_enc_unreg_region = svm_unregister_enc_region, .vm_copy_enc_context_from = svm_vm_copy_asid_from, + .vm_migrate_protected_vm_from = svm_vm_migrate_from, .can_emulate_instruction = svm_can_emulate_instruction, diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 0d7bbe548ac3..064e7c7f2834 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -80,6 +80,7 @@ struct kvm_sev_info { u64 ap_jump_table; /* SEV-ES AP Jump Table address */ struct kvm *enc_context_owner; /* Owner of copied encryption context */ struct misc_cg *misc_cg; /* For misc cgroup accounting */ + atomic_t migration_in_progress; }; struct kvm_svm { @@ -558,6 +559,7 @@ int svm_register_enc_region(struct kvm *kvm, int svm_unregister_enc_region(struct kvm *kvm, struct kvm_enc_region *range); int svm_vm_copy_asid_from(struct kvm *kvm, unsigned int source_fd); +int svm_vm_migrate_from(struct kvm *kvm, unsigned int source_fd); void pre_sev_run(struct vcpu_svm *svm, int cpu); void __init sev_set_cpu_caps(void); void __init sev_hardware_setup(void); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 196ac33ef958..093deb784b6b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5806,6 +5806,12 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, if (kvm_x86_ops.vm_copy_enc_context_from) r = kvm_x86_ops.vm_copy_enc_context_from(kvm, cap->args[0]); return r; + case KVM_CAP_VM_MIGRATE_PROTECTED_VM_FROM: + r = -EINVAL; + if (kvm_x86_ops.vm_migrate_protected_vm_from) + r = kvm_x86_ops.vm_migrate_protected_vm_from( + kvm, cap->args[0]); + return r; case KVM_CAP_EXIT_HYPERCALL: if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) { r = -EINVAL; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 5ca5ffe16cb4..dabd143aad8f 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1120,6 +1120,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_BINARY_STATS_FD 203 #define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204 #define KVM_CAP_ARM_MTE 205 +#define KVM_CAP_VM_MIGRATE_PROTECTED_VM_FROM 206 #ifdef KVM_CAP_IRQ_ROUTING -- 2.33.0.800.g4c38ced690-goog