Re: [kvm-unit-tests PATCH v2 10/10] x86: AMD SEV-ES: Handle string IO for IOIO #VC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Feb 9, 2022 at 8:44 AM Varad Gautam <varad.gautam@xxxxxxxx> wrote:
>
> Using Linux's IOIO #VC processing logic.
>
> Signed-off-by: Varad Gautam <varad.gautam@xxxxxxxx>
> ---
>  lib/x86/amd_sev_vc.c | 108 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 106 insertions(+), 2 deletions(-)
>
> diff --git a/lib/x86/amd_sev_vc.c b/lib/x86/amd_sev_vc.c
> index 88c95e1..c79d9be 100644
> --- a/lib/x86/amd_sev_vc.c
> +++ b/lib/x86/amd_sev_vc.c
> @@ -278,10 +278,46 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
>         return ES_OK;
>  }
>
> +static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
> +                                         void *src, unsigned char *buf,
> +                                         unsigned int data_size,
> +                                         unsigned int count,
> +                                         bool backwards)
> +{
> +       int i, b = backwards ? -1 : 1;
> +
> +       for (i = 0; i < count; i++) {
> +               void *s = src + (i * data_size * b);
> +               unsigned char *d = buf + (i * data_size);
> +
> +               memcpy(d, s, data_size);
> +       }
> +
> +       return ES_OK;
> +}
> +
> +static enum es_result vc_insn_string_write(struct es_em_ctxt *ctxt,
> +                                          void *dst, unsigned char *buf,
> +                                          unsigned int data_size,
> +                                          unsigned int count,
> +                                          bool backwards)
> +{
> +       int i, s = backwards ? -1 : 1;
> +
> +       for (i = 0; i < count; i++) {
> +               void *d = dst + (i * data_size * s);
> +               unsigned char *b = buf + (i * data_size);
> +
> +               memcpy(d, b, data_size);
> +       }
> +
> +       return ES_OK;
> +}
> +
>  static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
>  {
>         struct ex_regs *regs = ctxt->regs;
> -       u64 exit_info_1;
> +       u64 exit_info_1, exit_info_2;
>         enum es_result ret;
>
>         ret = vc_ioio_exitinfo(ctxt, &exit_info_1);
> @@ -289,7 +325,75 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
>                 return ret;
>
>         if (exit_info_1 & IOIO_TYPE_STR) {
> -               ret = ES_VMM_ERROR;
> +               /* (REP) INS/OUTS */
> +
> +               bool df = ((regs->rflags & X86_EFLAGS_DF) == X86_EFLAGS_DF);
> +               unsigned int io_bytes, exit_bytes;
> +               unsigned int ghcb_count, op_count;
> +               unsigned long es_base;
> +               u64 sw_scratch;
> +
> +               /*
> +                * For the string variants with rep prefix the amount of in/out
> +                * operations per #VC exception is limited so that the kernel
> +                * has a chance to take interrupts and re-schedule while the
> +                * instruction is emulated.
> +                */
> +               io_bytes   = (exit_info_1 >> 4) & 0x7;
> +               ghcb_count = sizeof(ghcb->shared_buffer) / io_bytes;
> +
> +               op_count    = (exit_info_1 & IOIO_REP) ? regs->rcx : 1;
> +               exit_info_2 = op_count < ghcb_count ? op_count : ghcb_count;
> +               exit_bytes  = exit_info_2 * io_bytes;
> +
> +               es_base = 0;
> +
> +               /* Read bytes of OUTS into the shared buffer */
> +               if (!(exit_info_1 & IOIO_TYPE_IN)) {
> +                       ret = vc_insn_string_read(ctxt,
> +                                              (void *)(es_base + regs->rsi),
> +                                              ghcb->shared_buffer, io_bytes,
> +                                              exit_info_2, df);
> +                       if (ret)
> +                               return ret;
> +               }
> +
> +               /*
> +                * Issue an VMGEXIT to the HV to consume the bytes from the
> +                * shared buffer or to have it write them into the shared buffer
> +                * depending on the instruction: OUTS or INS.
> +                */
> +               sw_scratch = __pa(ghcb) + offsetof(struct ghcb, shared_buffer);
> +               ghcb_set_sw_scratch(ghcb, sw_scratch);
> +               ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO,
> +                                         exit_info_1, exit_info_2);
> +               if (ret != ES_OK)
> +                       return ret;
> +
> +               /* Read bytes from shared buffer into the guest's destination. */
> +               if (exit_info_1 & IOIO_TYPE_IN) {
> +                       ret = vc_insn_string_write(ctxt,
> +                                                  (void *)(es_base + regs->rdi),
> +                                                  ghcb->shared_buffer, io_bytes,
> +                                                  exit_info_2, df);
> +                       if (ret)
> +                               return ret;
> +
> +                       if (df)
> +                               regs->rdi -= exit_bytes;
> +                       else
> +                               regs->rdi += exit_bytes;
> +               } else {
> +                       if (df)
> +                               regs->rsi -= exit_bytes;
> +                       else
> +                               regs->rsi += exit_bytes;
> +               }
> +
> +               if (exit_info_1 & IOIO_REP)
> +                       regs->rcx -= exit_info_2;
> +
> +               ret = regs->rcx ? ES_RETRY : ES_OK;
>         } else {
>                 /* IN/OUT into/from rAX */
>
> --
> 2.32.0
>

I was able to run both the amd_sev and msr tests under SEV-ES using
this built-in #VC handler on my setup. Obviously, that doesn't
exercise all of this #VC handler code. But I also compared it against
what's in LInux and read through all of it as well. Great job, Varad!

Reviewed-by: Marc Orr <marcorr@xxxxxxxxxx>
Tested-by: Marc Orr <marcorr@xxxxxxxxxx>



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux