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 2/13/22 2:31 AM, Marc Orr wrote:
> 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>
> 

Thank you Marc for going over the series! I'll have the v3 out soon.

Regards,
Varad




[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