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

Re: [Xen-devel] [PATCH v5 3/4] VMX: use proper instruction mnemonics if assembler supports them



On 26/08/2013 16:31, Jan Beulich wrote:
> With the hex byte emission we were taking away a good part of
> flexibility from the compiler, as for simplicity reasons these were
> built using fixed operands. All half way modern build environments
> would allow using the mnemonics (but we can't disable the hex variants
> yet, since the binutils around at the time gcc 4.1 got released didn't
> support these yet).
>
> I didn't convert __vmread() yet because that would, just like for
> __vmread_safe(), imply converting to a macro so that the output operand
> can be the caller supplied variable rather than an intermediate one. As
> that would require touching all invocation points of __vmread() (of
> which there are quite a few), I'd first like to be certain the approach
> is acceptable; the main question being whether the now conditional code
> might be considered to cause future maintenance issues, and the second
> being that of parameter/argument ordering (here I made __vmread_safe()
> match __vmwrite(), but one could also take the position that read and
> write should use the inverse order of one another, in line with the
> actual instruction operands).
>
> Additionally I was quite puzzled to find that all the asm()-s involved
> here have memory clobbers - what are they needed for? Or can they be
> dropped at least in some cases?
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

Reviewed-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

> ---
> v5: drop "q" operand qualifiers from __invept() and __invvpid() inline
>     assembly (pointed out as questionable by Andrew Cooper), changing
>     the types of their "type" parameters to "unsigned long" (which is
>     by itself a fix to the original code)
>
> --- a/Config.mk
> +++ b/Config.mk
> @@ -4,6 +4,12 @@ ifeq ($(filter /%,$(XEN_ROOT)),)
>  $(error XEN_ROOT must be absolute)
>  endif
>  
> +# Convenient variables
> +comma   := ,
> +squote  := '
> +empty   :=
> +space   := $(empty) $(empty)
> +
>  # fallback for older make
>  realpath = $(wildcard $(foreach file,$(1),$(shell cd -P $(dir $(file)) && 
> echo "$$PWD/$(notdir $(file))")))
>  
> @@ -128,6 +134,21 @@ endef
>  check-$(gcc) = $(call cc-ver-check,CC,0x040100,"Xen requires at least 
> gcc-4.1")
>  $(eval $(check-y))
>  
> +# as-insn: Check whether assembler supports an instruction.
> +# Usage: cflags-y += $(call as-insn "insn",option-yes,option-no)
> +as-insn = $(if $(shell echo 'void _(void) { asm volatile ( $(2) ); }' \
> +                       | $(1) -c -x c -o /dev/null - 2>&1),$(4),$(3))
> +
> +# as-insn-check: Add an option to compilation flags, but only if insn is
> +#                supported by assembler.
> +# Usage: $(call as-insn-check CFLAGS,CC,"nop",-DHAVE_GAS_NOP)
> +as-insn-check = $(eval $(call as-insn-check-closure,$(1),$(2),$(3),$(4)))
> +define as-insn-check-closure
> +    ifeq ($$(call as-insn,$$($(2)),$(3),y,n),y)
> +        $(1) += $(4)
> +    endif
> +endef
> +
>  define buildmakevars2shellvars
>      export PREFIX="$(PREFIX)";                                            \
>      export XEN_SCRIPT_DIR="$(XEN_SCRIPT_DIR)";                            \
> --- a/xen/arch/x86/Rules.mk
> +++ b/xen/arch/x86/Rules.mk
> @@ -28,6 +28,8 @@ CFLAGS += -msoft-float
>  
>  $(call cc-options-add,CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS))
>  $(call cc-option-add,CFLAGS,CC,-Wnested-externs)
> +$(call as-insn-check,CFLAGS,CC,"vmcall",-DHAVE_GAS_VMX)
> +$(call as-insn-check,CFLAGS,CC,"invept (%rax)$$(comma)%rax",-DHAVE_GAS_EPT)
>  
>  ifeq ($(supervisor_mode_kernel),y)
>  CFLAGS += -DCONFIG_X86_SUPERVISOR_MODE_KERNEL=1
> --- a/xen/arch/x86/hvm/vmx/vmcs.c
> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
> @@ -1292,12 +1292,11 @@ void vmx_do_resume(struct vcpu *v)
>      reset_stack_and_jump(vmx_asm_do_vmentry);
>  }
>  
> -static unsigned long vmr(unsigned long field)
> +static inline unsigned long vmr(unsigned long field)
>  {
> -    int rc;
>      unsigned long val;
> -    val = __vmread_safe(field, &rc);
> -    return rc ? 0 : val;
> +
> +    return __vmread_safe(field, &val) ? val : 0;
>  }
>  
>  static void vmx_dump_sel(char *name, uint32_t selector)
> --- a/xen/arch/x86/hvm/vmx/vvmx.c
> +++ b/xen/arch/x86/hvm/vmx/vvmx.c
> @@ -951,13 +951,11 @@ fallback:
>          vvmcs_to_shadow(vvmcs, field[i]);
>  }
>  
> -static void shadow_to_vvmcs(void *vvmcs, unsigned int field)
> +static inline void shadow_to_vvmcs(void *vvmcs, unsigned int field)
>  {
> -    u64 value;
> -    int rc;
> +    unsigned long value;
>  
> -    value = __vmread_safe(field, &rc);
> -    if ( !rc )
> +    if ( __vmread_safe(field, &value) )
>          __set_vvmcs(vvmcs, field, value);
>  }
>  
> --- a/xen/include/asm-x86/hvm/vmx/vmx.h
> +++ b/xen/include/asm-x86/hvm/vmx/vmx.h
> @@ -282,27 +282,43 @@ extern uint8_t posted_intr_vector;
>  
>  static inline void __vmptrld(u64 addr)
>  {
> -    asm volatile ( VMPTRLD_OPCODE
> -                   MODRM_EAX_06
> +    asm volatile (
> +#ifdef HAVE_GAS_VMX
> +                   "vmptrld %0\n"
> +#else
> +                   VMPTRLD_OPCODE MODRM_EAX_06
> +#endif
>                     /* CF==1 or ZF==1 --> crash (ud2) */
>                     UNLIKELY_START(be, vmptrld)
>                     "\tud2\n"
>                     UNLIKELY_END_SECTION
>                     :
> +#ifdef HAVE_GAS_VMX
> +                   : "m" (addr)
> +#else
>                     : "a" (&addr)
> +#endif
>                     : "memory");
>  }
>  
>  static inline void __vmpclear(u64 addr)
>  {
> -    asm volatile ( VMCLEAR_OPCODE
> -                   MODRM_EAX_06
> +    asm volatile (
> +#ifdef HAVE_GAS_VMX
> +                   "vmclear %0\n"
> +#else
> +                   VMCLEAR_OPCODE MODRM_EAX_06
> +#endif
>                     /* CF==1 or ZF==1 --> crash (ud2) */
>                     UNLIKELY_START(be, vmclear)
>                     "\tud2\n"
>                     UNLIKELY_END_SECTION
>                     :
> +#ifdef HAVE_GAS_VMX
> +                   : "m" (addr)
> +#else
>                     : "a" (&addr)
> +#endif
>                     : "memory");
>  }
>  
> @@ -325,33 +341,50 @@ static inline unsigned long __vmread(uns
>  
>  static inline void __vmwrite(unsigned long field, unsigned long value)
>  {
> -    asm volatile ( VMWRITE_OPCODE
> -                   MODRM_EAX_ECX
> +    asm volatile (
> +#ifdef HAVE_GAS_VMX
> +                   "vmwrite %1, %0\n"
> +#else
> +                   VMWRITE_OPCODE MODRM_EAX_ECX
> +#endif
>                     /* CF==1 or ZF==1 --> crash (ud2) */
>                     UNLIKELY_START(be, vmwrite)
>                     "\tud2\n"
>                     UNLIKELY_END_SECTION
>                     : 
> +#ifdef HAVE_GAS_VMX
> +                   : "r" (field) , "rm" (value)
> +#else
>                     : "a" (field) , "c" (value)
> +#endif
>                     : "memory");
>  }
>  
> -static inline unsigned long __vmread_safe(unsigned long field, int *error)
> +static inline bool_t __vmread_safe(unsigned long field, unsigned long *value)
>  {
> -    unsigned long ecx;
> +    bool_t okay;
>  
> -    asm volatile ( VMREAD_OPCODE
> -                   MODRM_EAX_ECX
> -                   /* CF==1 or ZF==1 --> rc = -1 */
> -                   "setna %b0 ; neg %0"
> -                   : "=q" (*error), "=c" (ecx)
> -                   : "0" (0), "a" (field)
> +    asm volatile (
> +#ifdef HAVE_GAS_VMX
> +                   "vmread %2, %1\n\t"
> +#else
> +                   VMREAD_OPCODE MODRM_EAX_ECX
> +#endif
> +                   /* CF==1 or ZF==1 --> rc = 0 */
> +                   "setnbe %0"
> +#ifdef HAVE_GAS_VMX
> +                   : "=qm" (okay), "=rm" (*value)
> +                   : "r" (field)
> +#else
> +                   : "=qm" (okay), "=c" (*value)
> +                   : "a" (field)
> +#endif
>                     : "memory");
>  
> -    return ecx;
> +    return okay;
>  }
>  
> -static inline void __invept(int type, u64 eptp, u64 gpa)
> +static inline void __invept(unsigned long type, u64 eptp, u64 gpa)
>  {
>      struct {
>          u64 eptp, gpa;
> @@ -365,18 +398,26 @@ static inline void __invept(int type, u6
>           !cpu_has_vmx_ept_invept_single_context )
>          type = INVEPT_ALL_CONTEXT;
>  
> -    asm volatile ( INVEPT_OPCODE
> -                   MODRM_EAX_08
> +    asm volatile (
> +#ifdef HAVE_GAS_EPT
> +                   "invept %0, %1\n"
> +#else
> +                   INVEPT_OPCODE MODRM_EAX_08
> +#endif
>                     /* CF==1 or ZF==1 --> crash (ud2) */
>                     UNLIKELY_START(be, invept)
>                     "\tud2\n"
>                     UNLIKELY_END_SECTION
>                     :
> +#ifdef HAVE_GAS_EPT
> +                   : "m" (operand), "r" (type)
> +#else
>                     : "a" (&operand), "c" (type)
> +#endif
>                     : "memory" );
>  }
>  
> -static inline void __invvpid(int type, u16 vpid, u64 gva)
> +static inline void __invvpid(unsigned long type, u16 vpid, u64 gva)
>  {
>      struct {
>          u64 vpid:16;
> @@ -385,7 +426,12 @@ static inline void __invvpid(int type, u
>      } __attribute__ ((packed)) operand = {vpid, 0, gva};
>  
>      /* Fix up #UD exceptions which occur when TLBs are flushed before VMXON. 
> */
> -    asm volatile ( "1: " INVVPID_OPCODE MODRM_EAX_08
> +    asm volatile ( "1: "
> +#ifdef HAVE_GAS_EPT
> +                   "invvpid %0, %1\n"
> +#else
> +                   INVVPID_OPCODE MODRM_EAX_08
> +#endif
>                     /* CF==1 or ZF==1 --> crash (ud2) */
>                     UNLIKELY_START(be, invvpid)
>                     "\tud2\n"
> @@ -393,7 +439,11 @@ static inline void __invvpid(int type, u
>                     "2:"
>                     _ASM_EXTABLE(1b, 2b)
>                     :
> +#ifdef HAVE_GAS_EPT
> +                   : "m" (operand), "r" (type)
> +#else
>                     : "a" (&operand), "c" (type)
> +#endif
>                     : "memory" );
>  }
>  
>
>


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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