lkml.org 
[lkml]   [2022]   [Jun]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH Part2 v6 34/49] KVM: SVM: Do not use long-lived GHCB map while setting scratch area
    Date
    From: Brijesh Singh <brijesh.singh@amd.com>

    The setup_vmgexit_scratch() function may rely on a long-lived GHCB
    mapping if the GHCB shared buffer area was used for the scratch area.
    In preparation for eliminating the long-lived GHCB mapping, always
    allocate a buffer for the scratch area so it can be accessed without
    the GHCB mapping.

    Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
    ---
    arch/x86/kvm/svm/sev.c | 74 +++++++++++++++++++-----------------------
    arch/x86/kvm/svm/svm.h | 3 +-
    2 files changed, 36 insertions(+), 41 deletions(-)

    diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
    index 91d3d24e60d2..01ea257e17d6 100644
    --- a/arch/x86/kvm/svm/sev.c
    +++ b/arch/x86/kvm/svm/sev.c
    @@ -2820,8 +2820,7 @@ void sev_free_vcpu(struct kvm_vcpu *vcpu)
    __free_page(virt_to_page(svm->sev_es.vmsa));

    skip_vmsa_free:
    - if (svm->sev_es.ghcb_sa_free)
    - kvfree(svm->sev_es.ghcb_sa);
    + kvfree(svm->sev_es.ghcb_sa);
    }

    static void dump_ghcb(struct vcpu_svm *svm)
    @@ -2909,6 +2908,9 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
    control->exit_info_1 = ghcb_get_sw_exit_info_1(ghcb);
    control->exit_info_2 = ghcb_get_sw_exit_info_2(ghcb);

    + /* Copy the GHCB scratch area GPA */
    + svm->sev_es.ghcb_sa_gpa = ghcb_get_sw_scratch(ghcb);
    +
    /* Clear the valid entries fields */
    memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
    }
    @@ -3054,23 +3056,12 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm)
    if (!svm->sev_es.ghcb)
    return;

    - if (svm->sev_es.ghcb_sa_free) {
    - /*
    - * The scratch area lives outside the GHCB, so there is a
    - * buffer that, depending on the operation performed, may
    - * need to be synced, then freed.
    - */
    - if (svm->sev_es.ghcb_sa_sync) {
    - kvm_write_guest(svm->vcpu.kvm,
    - ghcb_get_sw_scratch(svm->sev_es.ghcb),
    - svm->sev_es.ghcb_sa,
    - svm->sev_es.ghcb_sa_len);
    - svm->sev_es.ghcb_sa_sync = false;
    - }
    -
    - kvfree(svm->sev_es.ghcb_sa);
    - svm->sev_es.ghcb_sa = NULL;
    - svm->sev_es.ghcb_sa_free = false;
    + /* Sync the scratch buffer area. */
    + if (svm->sev_es.ghcb_sa_sync) {
    + kvm_write_guest(svm->vcpu.kvm,
    + ghcb_get_sw_scratch(svm->sev_es.ghcb),
    + svm->sev_es.ghcb_sa, svm->sev_es.ghcb_sa_len);
    + svm->sev_es.ghcb_sa_sync = false;
    }

    trace_kvm_vmgexit_exit(svm->vcpu.vcpu_id, svm->sev_es.ghcb);
    @@ -3111,9 +3102,8 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
    struct ghcb *ghcb = svm->sev_es.ghcb;
    u64 ghcb_scratch_beg, ghcb_scratch_end;
    u64 scratch_gpa_beg, scratch_gpa_end;
    - void *scratch_va;

    - scratch_gpa_beg = ghcb_get_sw_scratch(ghcb);
    + scratch_gpa_beg = svm->sev_es.ghcb_sa_gpa;
    if (!scratch_gpa_beg) {
    pr_err("vmgexit: scratch gpa not provided\n");
    goto e_scratch;
    @@ -3143,9 +3133,6 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
    scratch_gpa_beg, scratch_gpa_end);
    goto e_scratch;
    }
    -
    - scratch_va = (void *)svm->sev_es.ghcb;
    - scratch_va += (scratch_gpa_beg - control->ghcb_gpa);
    } else {
    /*
    * The guest memory must be read into a kernel buffer, so
    @@ -3156,29 +3143,36 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
    len, GHCB_SCRATCH_AREA_LIMIT);
    goto e_scratch;
    }
    - scratch_va = kvzalloc(len, GFP_KERNEL_ACCOUNT);
    - if (!scratch_va)
    - return -ENOMEM;
    + }

    - if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) {
    - /* Unable to copy scratch area from guest */
    - pr_err("vmgexit: kvm_read_guest for scratch area failed\n");
    + if (svm->sev_es.ghcb_sa_alloc_len < len) {
    + void *scratch_va = kvzalloc(len, GFP_KERNEL_ACCOUNT);

    - kvfree(scratch_va);
    - return -EFAULT;
    - }
    + if (!scratch_va)
    + return -ENOMEM;

    /*
    - * The scratch area is outside the GHCB. The operation will
    - * dictate whether the buffer needs to be synced before running
    - * the vCPU next time (i.e. a read was requested so the data
    - * must be written back to the guest memory).
    + * Free the old scratch area and switch to using newly
    + * allocated.
    */
    - svm->sev_es.ghcb_sa_sync = sync;
    - svm->sev_es.ghcb_sa_free = true;
    + kvfree(svm->sev_es.ghcb_sa);
    +
    + svm->sev_es.ghcb_sa_alloc_len = len;
    + svm->sev_es.ghcb_sa = scratch_va;
    }

    - svm->sev_es.ghcb_sa = scratch_va;
    + if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, svm->sev_es.ghcb_sa, len)) {
    + /* Unable to copy scratch area from guest */
    + pr_err("vmgexit: kvm_read_guest for scratch area failed\n");
    + return -EFAULT;
    + }
    +
    + /*
    + * The operation will dictate whether the buffer needs to be synced
    + * before running the vCPU next time (i.e. a read was requested so
    + * the data must be written back to the guest memory).
    + */
    + svm->sev_es.ghcb_sa_sync = sync;
    svm->sev_es.ghcb_sa_len = len;

    return 0;
    diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
    index 7782312a1cda..bd0db4d4a61e 100644
    --- a/arch/x86/kvm/svm/svm.h
    +++ b/arch/x86/kvm/svm/svm.h
    @@ -197,8 +197,9 @@ struct vcpu_sev_es_state {
    /* SEV-ES scratch area support */
    void *ghcb_sa;
    u32 ghcb_sa_len;
    + u64 ghcb_sa_gpa;
    + u32 ghcb_sa_alloc_len;
    bool ghcb_sa_sync;
    - bool ghcb_sa_free;
    };

    struct vcpu_svm {
    --
    2.25.1
    \
     
     \ /
      Last update: 2022-06-21 01:15    [W:4.261 / U:0.620 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site