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

Re: [Xen-devel] [PATCH 03/11] x86: Initialise debug registers correctly



On Mon, Jun 04, 2018 at 02:59:07PM +0100, Andrew Cooper wrote:
> In particular, initialising %dr6 with the value 0 is buggy, because on
> hardware supporting Transnational Memory, it will cause the sticky RTM bit to
> be asserted, even though a debug event from a transaction hasn't actually been
> observed.
> 
> Introduce X86_DR7_DEFAULT to match the existing X86_DR6_DEFAULT, and use
> correct defaults when resetting the debug registers in cpu_init().
> 
> For vcpus, %dr6/7 have never been initialised.  In practice, this means that
> toolstack get/set operations see zeros until the vcpu has first touched its
> debug registers (at which point hardware fixes up the reserved bits), and the
> RTM corner case will persist beyond that point.
> 
> Introduce initialise_registers() to set register defaults (including eflags
> while we are fixing this) and call it early in vcpu_initialise().  Make a
> similar adjustment in hvm_vcpu_reset_state().
> 
> Finally, adjust the vcpu state initialising logic in libxc.  All 3 sites zero
> memory before choosing the nonzero defaults, which propagates the RTM corner
> case.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

LGTM:

Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>

Just a couple of questions below.

> ---
> CC: Jan Beulich <JBeulich@xxxxxxxx>
> CC: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx>
> CC: Wei Liu <wei.liu2@xxxxxxxxxx>
> CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
> ---
>  tools/libxc/xc_dom_x86.c       | 12 ++++++++++++
>  xen/arch/x86/cpu/common.c      | 12 ++++++++----
>  xen/arch/x86/domain.c          | 10 ++++++++++
>  xen/arch/x86/hvm/hvm.c         |  6 +++++-
>  xen/include/asm-x86/debugreg.h |  2 ++
>  5 files changed, 37 insertions(+), 5 deletions(-)
> 
> diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c
> index e33a288..3ab918c 100644
> --- a/tools/libxc/xc_dom_x86.c
> +++ b/tools/libxc/xc_dom_x86.c
> @@ -53,6 +53,9 @@
>  #define X86_CR0_PE 0x01
>  #define X86_CR0_ET 0x10
>  
> +#define X86_DR6_DEFAULT 0xffff0ff0u
> +#define X86_DR7_DEFAULT 0x00000400u
> +
>  #define SPECIALPAGE_PAGING   0
>  #define SPECIALPAGE_ACCESS   1
>  #define SPECIALPAGE_SHARING  2
> @@ -860,6 +863,9 @@ static int vcpu_x86_32(struct xc_dom_image *dom)
>          dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86;
>      ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */
>  
> +    ctxt->debugreg[6] = X86_DR6_DEFAULT;
> +    ctxt->debugreg[7] = X86_DR7_DEFAULT;
> +
>      ctxt->flags = VGCF_in_kernel_X86_32 | VGCF_online_X86_32;
>      if ( dom->parms.pae == XEN_PAE_EXTCR3 ||
>           dom->parms.pae == XEN_PAE_BIMODAL )
> @@ -907,6 +913,9 @@ static int vcpu_x86_64(struct xc_dom_image *dom)
>          dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86;
>      ctxt->user_regs.rflags = 1 << 9; /* Interrupt Enable */
>  
> +    ctxt->debugreg[6] = X86_DR6_DEFAULT;
> +    ctxt->debugreg[7] = X86_DR7_DEFAULT;
> +
>      ctxt->flags = VGCF_in_kernel_X86_64 | VGCF_online_X86_64;
>      cr3_pfn = xc_dom_p2m(dom, dom->pgtables_seg.pfn);
>      ctxt->ctrlreg[3] = xen_pfn_to_cr3_x86_64(cr3_pfn);
> @@ -1011,6 +1020,9 @@ static int vcpu_hvm(struct xc_dom_image *dom)
>      /* Set the IP. */
>      bsp_ctx.cpu.rip = dom->parms.phys_entry;
>  
> +    bsp_ctx.cpu.dr6 = X86_DR6_DEFAULT;
> +    bsp_ctx.cpu.dr7 = X86_DR7_DEFAULT;
> +
>      if ( dom->start_info_seg.pfn )
>          bsp_ctx.cpu.rbx = dom->start_info_seg.pfn << PAGE_SHIFT;
>  
> diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
> index 528aff1..0872466 100644
> --- a/xen/arch/x86/cpu/common.c
> +++ b/xen/arch/x86/cpu/common.c
> @@ -3,6 +3,7 @@
>  #include <xen/delay.h>
>  #include <xen/smp.h>
>  #include <asm/current.h>
> +#include <asm/debugreg.h>
>  #include <asm/processor.h>
>  #include <asm/xstate.h>
>  #include <asm/msr.h>
> @@ -823,10 +824,13 @@ void cpu_init(void)
>       /* Ensure FPU gets initialised for each domain. */
>       stts();
>  
> -     /* Clear all 6 debug registers: */
> -#define CD(register) asm volatile ( "mov %0,%%db" #register : : "r"(0UL) );
> -     CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
> -#undef CD
> +     /* Reset debug registers: */
> +     write_debugreg(0, 0);
> +     write_debugreg(1, 0);
> +     write_debugreg(2, 0);
> +     write_debugreg(3, 0);
> +     write_debugreg(6, X86_DR6_DEFAULT);
> +     write_debugreg(7, X86_DR7_DEFAULT);

AFAICT you are writing the default init values, which should be there
already. So this is just a safebelt in case the CPU is initialized
with some bogus DR values?

>  }
>  
>  void cpu_uninit(unsigned int cpu)
> diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
> index 0ca820a..7ae9789 100644
> --- a/xen/arch/x86/domain.c
> +++ b/xen/arch/x86/domain.c
> @@ -322,6 +322,14 @@ void free_vcpu_struct(struct vcpu *v)
>      free_xenheap_page(v);
>  }
>  
> +static void initialise_registers(struct vcpu *v)
> +{
> +    v->arch.user_regs.eflags = X86_EFLAGS_MBS;
> +
> +    v->arch.debugreg[6] = X86_DR6_DEFAULT;
> +    v->arch.debugreg[7] = X86_DR7_DEFAULT;
> +}
> +
>  int vcpu_initialise(struct vcpu *v)
>  {
>      struct domain *d = v->domain;
> @@ -341,6 +349,8 @@ int vcpu_initialise(struct vcpu *v)
>              return rc;
>  
>          vmce_init_vcpu(v);
> +
> +        initialise_registers(v);
>      }
>      else if ( (rc = xstate_alloc_save_area(v)) != 0 )
>          return rc;
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index c23983c..10415e6 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -40,6 +40,7 @@
>  #include <asm/shadow.h>
>  #include <asm/hap.h>
>  #include <asm/current.h>
> +#include <asm/debugreg.h>
>  #include <asm/e820.h>
>  #include <asm/io.h>
>  #include <asm/regs.h>
> @@ -3907,7 +3908,10 @@ void hvm_vcpu_reset_state(struct vcpu *v, uint16_t cs, 
> uint16_t ip)
>      v->arch.user_regs.rflags = X86_EFLAGS_MBS;
>      v->arch.user_regs.rdx = 0x00000f00;
>      v->arch.user_regs.rip = ip;
> -    memset(&v->arch.debugreg, 0, sizeof(v->arch.debugreg));
> +
> +    memset(&v->arch.debugreg, 0, sizeof(v->arch.debugreg) - 16);

For clarity I would use offsetof here, or rather just zero the whole
thing. This is not a hot path, so I would prefer to avoid the
optimization.

Roger.

_______________________________________________
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®.