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

Re: [Xen-devel] [PATCH] x86/svm: Fix handling of EFLAGS.RF on task switch



> From: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> Sent: Wednesday, December 4, 2019 6:31 AM
> 
> VT-x updates RF before vmexit, so eflags written into the outgoing TSS
> happens
> to be correct.  SVM does not update RF before vmexit, and instead provides
> it
> via a bit in exitinfo2.
> 
> In practice, needing RF set in the outgoing state occurs when a task gate is
> used to handle faults.
> 
> Extend hvm_task_switch() with an extra_eflags parameter which gets fed
> into
> the outgoing TSS, and fill it in suitably from the SVM vmexit information.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> ---
> CC: Jan Beulich <JBeulich@xxxxxxxx>
> CC: Wei Liu <wl@xxxxxxx>
> CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
> CC: Jun Nakajima <jun.nakajima@xxxxxxxxx>
> CC: Kevin Tian <kevin.tian@xxxxxxxxx>
> CC: Juergen Gross <jgross@xxxxxxxx>
> 
> Kevin: There is no help in the SDM about this.  RF is not mentioned in the
> list of state either modified or unmodified by hardware on a task switch
> vmexit.  This conclusion has been drawn from looking at the actual VMExit
> state given an XTF test poking every corner of TASK_SWITCH VMExits.

Here is what I observed in latest SDM (Oct. 2019):

27.3.3 Saving RIP, RSP, RFLAGS, and SSP
...
With the exception of the resume flag (RF; bit 16), the contents 
of the RFLAGS register is saved into the RFLAGS field. RFLAGS.RF 
is saved as follows:
...
- If the VM exit is caused by a task switch (including one caused 
by a task gate in the IDT), the value saved is that which would 
have been saved in the RFLAGS image in the old task-state 
segment (TSS) had the task switch completed normally without 
exception.
...

Based on that, fox vmx part:

Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>

> 
> Juergen: I know its getting stupidly late in the day, but this, like the
> previous fixes, want backporting.  OTOH, the likelihood of not fixing it
> causing harm to VMs is minimal, unlike the earlier task switch fixes.
> ---
>  xen/arch/x86/hvm/hvm.c        | 4 ++--
>  xen/arch/x86/hvm/svm/svm.c    | 3 ++-
>  xen/arch/x86/hvm/vmx/vmx.c    | 3 ++-
>  xen/include/asm-x86/hvm/hvm.h | 2 +-
>  4 files changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index 7f556171bd..47573f71b8 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -2913,7 +2913,7 @@ void hvm_prepare_vm86_tss(struct vcpu *v,
> uint32_t base, uint32_t limit)
> 
>  void hvm_task_switch(
>      uint16_t tss_sel, enum hvm_task_switch_reason taskswitch_reason,
> -    int32_t errcode, unsigned int insn_len)
> +    int32_t errcode, unsigned int insn_len, unsigned int extra_eflags)
>  {
>      struct vcpu *v = current;
>      struct cpu_user_regs *regs = guest_cpu_user_regs();
> @@ -2988,7 +2988,7 @@ void hvm_task_switch(
>          eflags &= ~X86_EFLAGS_NT;
> 
>      tss.eip    = regs->eip + insn_len;
> -    tss.eflags = eflags;
> +    tss.eflags = eflags | extra_eflags;
>      tss.eax    = regs->eax;
>      tss.ecx    = regs->ecx;
>      tss.edx    = regs->edx;
> diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
> index 0fb1908c18..6ae43999ff 100644
> --- a/xen/arch/x86/hvm/svm/svm.c
> +++ b/xen/arch/x86/hvm/svm/svm.c
> @@ -2812,7 +2812,8 @@ void svm_vmexit_handler(struct cpu_user_regs
> *regs)
>          if ( (vmcb->exitinfo2 >> 44) & 1 )
>              errcode = (uint32_t)vmcb->exitinfo2;
> 
> -        hvm_task_switch(vmcb->exitinfo1, reason, errcode, insn_len);
> +        hvm_task_switch(vmcb->exitinfo1, reason, errcode, insn_len,
> +                        (vmcb->exitinfo2 & (1ul << 48)) ? X86_EFLAGS_RF : 0);
>          break;
>      }
> 
> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
> index 7450cbe40d..bafc3b30c5 100644
> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -3963,7 +3963,8 @@ void vmx_vmexit_handler(struct cpu_user_regs
> *regs)
>          else
>               ecode = -1;
> 
> -        hvm_task_switch(exit_qualification, reasons[source], ecode, 
> inst_len);
> +        hvm_task_switch(exit_qualification, reasons[source], ecode, inst_len,
> +                        0 /* EFLAGS.RF already updated. */);
>          break;
>      }
>      case EXIT_REASON_CPUID:
> diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-
> x86/hvm/hvm.h
> index 17fb7efa6e..1d7b66f927 100644
> --- a/xen/include/asm-x86/hvm/hvm.h
> +++ b/xen/include/asm-x86/hvm/hvm.h
> @@ -296,7 +296,7 @@ void hvm_set_rdtsc_exiting(struct domain *d, bool_t
> enable);
>  enum hvm_task_switch_reason { TSW_jmp, TSW_iret, TSW_call_or_int };
>  void hvm_task_switch(
>      uint16_t tss_sel, enum hvm_task_switch_reason taskswitch_reason,
> -    int32_t errcode, unsigned int insn_len);
> +    int32_t errcode, unsigned int insn_len, unsigned int extra_eflags);
> 
>  enum hvm_access_type {
>      hvm_access_insn_fetch,
> --
> 2.11.0

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.