lkml.org 
[lkml]   [2021]   [Feb]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v10 02/16] KVM: SVM: Add KVM_SEND_UPDATE_DATA command
    Date
    From: Brijesh Singh <brijesh.singh@amd.com>

    The command is used for encrypting the guest memory region using the encryption
    context created with KVM_SEV_SEND_START.

    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: "H. Peter Anvin" <hpa@zytor.com>
    Cc: Paolo Bonzini <pbonzini@redhat.com>
    Cc: "Radim Krčmář" <rkrcmar@redhat.com>
    Cc: Joerg Roedel <joro@8bytes.org>
    Cc: Borislav Petkov <bp@suse.de>
    Cc: Tom Lendacky <thomas.lendacky@amd.com>
    Cc: x86@kernel.org
    Cc: kvm@vger.kernel.org
    Cc: linux-kernel@vger.kernel.org
    Reviewed-by : Steve Rutherford <srutherford@google.com>
    Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
    Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
    ---
    .../virt/kvm/amd-memory-encryption.rst | 24 ++++
    arch/x86/kvm/svm/sev.c | 122 ++++++++++++++++++
    include/uapi/linux/kvm.h | 9 ++
    3 files changed, 155 insertions(+)

    diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
    index 9f9896b72d36..8bed1d801558 100644
    --- a/Documentation/virt/kvm/amd-memory-encryption.rst
    +++ b/Documentation/virt/kvm/amd-memory-encryption.rst
    @@ -290,6 +290,30 @@ Returns: 0 on success, -negative on error
    __u32 session_len;
    };

    +11. KVM_SEV_SEND_UPDATE_DATA
    +----------------------------
    +
    +The KVM_SEV_SEND_UPDATE_DATA command can be used by the hypervisor to encrypt the
    +outgoing guest memory region with the encryption context creating using
    +KVM_SEV_SEND_START.
    +
    +Parameters (in): struct kvm_sev_send_update_data
    +
    +Returns: 0 on success, -negative on error
    +
    +::
    +
    + struct kvm_sev_launch_send_update_data {
    + __u64 hdr_uaddr; /* userspace address containing the packet header */
    + __u32 hdr_len;
    +
    + __u64 guest_uaddr; /* the source memory region to be encrypted */
    + __u32 guest_len;
    +
    + __u64 trans_uaddr; /* the destition memory region */
    + __u32 trans_len;
    + };
    +
    References
    ==========

    diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
    index 3026c7fd2ffc..98e46ae1cba3 100644
    --- a/arch/x86/kvm/svm/sev.c
    +++ b/arch/x86/kvm/svm/sev.c
    @@ -33,6 +33,7 @@ static DECLARE_RWSEM(sev_deactivate_lock);
    static DEFINE_MUTEX(sev_bitmap_lock);
    unsigned int max_sev_asid;
    static unsigned int min_sev_asid;
    +static unsigned long sev_me_mask;
    static unsigned long *sev_asid_bitmap;
    static unsigned long *sev_reclaim_asid_bitmap;

    @@ -1161,6 +1162,123 @@ static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
    return ret;
    }

    +/* Userspace wants to query either header or trans length. */
    +static int
    +__sev_send_update_data_query_lengths(struct kvm *kvm, struct kvm_sev_cmd *argp,
    + struct kvm_sev_send_update_data *params)
    +{
    + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
    + struct sev_data_send_update_data *data;
    + int ret;
    +
    + data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
    + if (!data)
    + return -ENOMEM;
    +
    + data->handle = sev->handle;
    + ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, data, &argp->error);
    +
    + params->hdr_len = data->hdr_len;
    + params->trans_len = data->trans_len;
    +
    + if (copy_to_user((void __user *)(uintptr_t)argp->data, params,
    + sizeof(struct kvm_sev_send_update_data)))
    + ret = -EFAULT;
    +
    + kfree(data);
    + return ret;
    +}
    +
    +static int sev_send_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
    +{
    + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
    + struct sev_data_send_update_data *data;
    + struct kvm_sev_send_update_data params;
    + void *hdr, *trans_data;
    + struct page **guest_page;
    + unsigned long n;
    + int ret, offset;
    +
    + if (!sev_guest(kvm))
    + return -ENOTTY;
    +
    + if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
    + sizeof(struct kvm_sev_send_update_data)))
    + return -EFAULT;
    +
    + /* userspace wants to query either header or trans length */
    + if (!params.trans_len || !params.hdr_len)
    + return __sev_send_update_data_query_lengths(kvm, argp, &params);
    +
    + if (!params.trans_uaddr || !params.guest_uaddr ||
    + !params.guest_len || !params.hdr_uaddr)
    + return -EINVAL;
    +
    + /* Check if we are crossing the page boundary */
    + offset = params.guest_uaddr & (PAGE_SIZE - 1);
    + if ((params.guest_len + offset > PAGE_SIZE))
    + return -EINVAL;
    +
    + /* Pin guest memory */
    + guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
    + PAGE_SIZE, &n, 0);
    + if (!guest_page)
    + return -EFAULT;
    +
    + /* allocate memory for header and transport buffer */
    + ret = -ENOMEM;
    + hdr = kmalloc(params.hdr_len, GFP_KERNEL_ACCOUNT);
    + if (!hdr)
    + goto e_unpin;
    +
    + trans_data = kmalloc(params.trans_len, GFP_KERNEL_ACCOUNT);
    + if (!trans_data)
    + goto e_free_hdr;
    +
    + data = kzalloc(sizeof(*data), GFP_KERNEL);
    + if (!data)
    + goto e_free_trans_data;
    +
    + data->hdr_address = __psp_pa(hdr);
    + data->hdr_len = params.hdr_len;
    + data->trans_address = __psp_pa(trans_data);
    + data->trans_len = params.trans_len;
    +
    + /* The SEND_UPDATE_DATA command requires C-bit to be always set. */
    + data->guest_address = (page_to_pfn(guest_page[0]) << PAGE_SHIFT) +
    + offset;
    + data->guest_address |= sev_me_mask;
    + data->guest_len = params.guest_len;
    + data->handle = sev->handle;
    +
    + ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, data, &argp->error);
    +
    + if (ret)
    + goto e_free;
    +
    + /* copy transport buffer to user space */
    + if (copy_to_user((void __user *)(uintptr_t)params.trans_uaddr,
    + trans_data, params.trans_len)) {
    + ret = -EFAULT;
    + goto e_free;
    + }
    +
    + /* Copy packet header to userspace. */
    + ret = copy_to_user((void __user *)(uintptr_t)params.hdr_uaddr, hdr,
    + params.hdr_len);
    +
    +e_free:
    + kfree(data);
    +e_free_trans_data:
    + kfree(trans_data);
    +e_free_hdr:
    + kfree(hdr);
    +e_unpin:
    + sev_unpin_memory(kvm, guest_page, n);
    +
    + return ret;
    +}
    +
    int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
    {
    struct kvm_sev_cmd sev_cmd;
    @@ -1214,6 +1332,9 @@ int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
    case KVM_SEV_SEND_START:
    r = sev_send_start(kvm, &sev_cmd);
    break;
    + case KVM_SEV_SEND_UPDATE_DATA:
    + r = sev_send_update_data(kvm, &sev_cmd);
    + break;
    default:
    r = -EINVAL;
    goto out;
    @@ -1392,6 +1513,7 @@ void __init sev_hardware_setup(void)

    /* Minimum ASID value that should be used for SEV guest */
    min_sev_asid = edx;
    + sev_me_mask = 1UL << (ebx & 0x3f);

    /* Initialize SEV ASID bitmaps */
    sev_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
    diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
    index 8f538fd873f6..0ff7bed508fc 100644
    --- a/include/uapi/linux/kvm.h
    +++ b/include/uapi/linux/kvm.h
    @@ -1657,6 +1657,15 @@ struct kvm_sev_send_start {
    __u32 session_len;
    };

    +struct kvm_sev_send_update_data {
    + __u64 hdr_uaddr;
    + __u32 hdr_len;
    + __u64 guest_uaddr;
    + __u32 guest_len;
    + __u64 trans_uaddr;
    + __u32 trans_len;
    +};
    +
    #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
    #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
    #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2)
    --
    2.17.1
    \
     
     \ /
      Last update: 2021-02-04 01:39    [W:4.447 / U:0.112 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site