Re: [PATCH v2 1/4] KVM: x86: Move FPU register accessors into fpu.h

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

 



Siddharth Chandrasekaran <sidcha@xxxxxxxxx> writes:

> Hyper-v XMM fast hypercalls use XMM registers to pass input/output
> parameters. To access these, hyperv.c can reuse some FPU register
> accessors defined in emulator.c. Move them to a common location so both
> can access them.
>
> While at it, reorder the parameters of these accessor methods to make
> them more readable.
>
> Cc: Alexander Graf <graf@xxxxxxxxxx>
> Cc: Evgeny Iakovlev <eyakovl@xxxxxxxxx>
> Signed-off-by: Siddharth Chandrasekaran <sidcha@xxxxxxxxx>
> ---
>  arch/x86/kvm/emulate.c | 138 ++++++----------------------------------
>  arch/x86/kvm/fpu.h     | 140 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 158 insertions(+), 120 deletions(-)
>  create mode 100644 arch/x86/kvm/fpu.h
>
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index f7970ba6219f..296f8f3ce988 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -22,7 +22,6 @@
>  #include "kvm_cache_regs.h"
>  #include "kvm_emulate.h"
>  #include <linux/stringify.h>
> -#include <asm/fpu/api.h>
>  #include <asm/debugreg.h>
>  #include <asm/nospec-branch.h>
>  
> @@ -30,6 +29,7 @@
>  #include "tss.h"
>  #include "mmu.h"
>  #include "pmu.h"
> +#include "fpu.h"
>  
>  /*
>   * Operand types
> @@ -1081,116 +1081,14 @@ static void fetch_register_operand(struct operand *op)
>  	}
>  }
>  
> -static void emulator_get_fpu(void)
> -{
> -	fpregs_lock();
> -
> -	fpregs_assert_state_consistent();
> -	if (test_thread_flag(TIF_NEED_FPU_LOAD))
> -		switch_fpu_return();
> -}
> -
> -static void emulator_put_fpu(void)
> -{
> -	fpregs_unlock();
> -}
> -
> -static void read_sse_reg(sse128_t *data, int reg)
> -{
> -	emulator_get_fpu();
> -	switch (reg) {
> -	case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break;
> -	case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break;
> -	case 2: asm("movdqa %%xmm2, %0" : "=m"(*data)); break;
> -	case 3: asm("movdqa %%xmm3, %0" : "=m"(*data)); break;
> -	case 4: asm("movdqa %%xmm4, %0" : "=m"(*data)); break;
> -	case 5: asm("movdqa %%xmm5, %0" : "=m"(*data)); break;
> -	case 6: asm("movdqa %%xmm6, %0" : "=m"(*data)); break;
> -	case 7: asm("movdqa %%xmm7, %0" : "=m"(*data)); break;
> -#ifdef CONFIG_X86_64
> -	case 8: asm("movdqa %%xmm8, %0" : "=m"(*data)); break;
> -	case 9: asm("movdqa %%xmm9, %0" : "=m"(*data)); break;
> -	case 10: asm("movdqa %%xmm10, %0" : "=m"(*data)); break;
> -	case 11: asm("movdqa %%xmm11, %0" : "=m"(*data)); break;
> -	case 12: asm("movdqa %%xmm12, %0" : "=m"(*data)); break;
> -	case 13: asm("movdqa %%xmm13, %0" : "=m"(*data)); break;
> -	case 14: asm("movdqa %%xmm14, %0" : "=m"(*data)); break;
> -	case 15: asm("movdqa %%xmm15, %0" : "=m"(*data)); break;
> -#endif
> -	default: BUG();
> -	}
> -	emulator_put_fpu();
> -}
> -
> -static void write_sse_reg(sse128_t *data, int reg)
> -{
> -	emulator_get_fpu();
> -	switch (reg) {
> -	case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break;
> -	case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break;
> -	case 2: asm("movdqa %0, %%xmm2" : : "m"(*data)); break;
> -	case 3: asm("movdqa %0, %%xmm3" : : "m"(*data)); break;
> -	case 4: asm("movdqa %0, %%xmm4" : : "m"(*data)); break;
> -	case 5: asm("movdqa %0, %%xmm5" : : "m"(*data)); break;
> -	case 6: asm("movdqa %0, %%xmm6" : : "m"(*data)); break;
> -	case 7: asm("movdqa %0, %%xmm7" : : "m"(*data)); break;
> -#ifdef CONFIG_X86_64
> -	case 8: asm("movdqa %0, %%xmm8" : : "m"(*data)); break;
> -	case 9: asm("movdqa %0, %%xmm9" : : "m"(*data)); break;
> -	case 10: asm("movdqa %0, %%xmm10" : : "m"(*data)); break;
> -	case 11: asm("movdqa %0, %%xmm11" : : "m"(*data)); break;
> -	case 12: asm("movdqa %0, %%xmm12" : : "m"(*data)); break;
> -	case 13: asm("movdqa %0, %%xmm13" : : "m"(*data)); break;
> -	case 14: asm("movdqa %0, %%xmm14" : : "m"(*data)); break;
> -	case 15: asm("movdqa %0, %%xmm15" : : "m"(*data)); break;
> -#endif
> -	default: BUG();
> -	}
> -	emulator_put_fpu();
> -}
> -
> -static void read_mmx_reg(u64 *data, int reg)
> -{
> -	emulator_get_fpu();
> -	switch (reg) {
> -	case 0: asm("movq %%mm0, %0" : "=m"(*data)); break;
> -	case 1: asm("movq %%mm1, %0" : "=m"(*data)); break;
> -	case 2: asm("movq %%mm2, %0" : "=m"(*data)); break;
> -	case 3: asm("movq %%mm3, %0" : "=m"(*data)); break;
> -	case 4: asm("movq %%mm4, %0" : "=m"(*data)); break;
> -	case 5: asm("movq %%mm5, %0" : "=m"(*data)); break;
> -	case 6: asm("movq %%mm6, %0" : "=m"(*data)); break;
> -	case 7: asm("movq %%mm7, %0" : "=m"(*data)); break;
> -	default: BUG();
> -	}
> -	emulator_put_fpu();
> -}
> -
> -static void write_mmx_reg(u64 *data, int reg)
> -{
> -	emulator_get_fpu();
> -	switch (reg) {
> -	case 0: asm("movq %0, %%mm0" : : "m"(*data)); break;
> -	case 1: asm("movq %0, %%mm1" : : "m"(*data)); break;
> -	case 2: asm("movq %0, %%mm2" : : "m"(*data)); break;
> -	case 3: asm("movq %0, %%mm3" : : "m"(*data)); break;
> -	case 4: asm("movq %0, %%mm4" : : "m"(*data)); break;
> -	case 5: asm("movq %0, %%mm5" : : "m"(*data)); break;
> -	case 6: asm("movq %0, %%mm6" : : "m"(*data)); break;
> -	case 7: asm("movq %0, %%mm7" : : "m"(*data)); break;
> -	default: BUG();
> -	}
> -	emulator_put_fpu();
> -}
> -
>  static int em_fninit(struct x86_emulate_ctxt *ctxt)
>  {
>  	if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
>  		return emulate_nm(ctxt);
>  
> -	emulator_get_fpu();
> +	kvm_fpu_get();
>  	asm volatile("fninit");
> -	emulator_put_fpu();
> +	kvm_fpu_put();
>  	return X86EMUL_CONTINUE;
>  }
>  
> @@ -1201,9 +1099,9 @@ static int em_fnstcw(struct x86_emulate_ctxt *ctxt)
>  	if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
>  		return emulate_nm(ctxt);
>  
> -	emulator_get_fpu();
> +	kvm_fpu_get();
>  	asm volatile("fnstcw %0": "+m"(fcw));
> -	emulator_put_fpu();
> +	kvm_fpu_put();
>  
>  	ctxt->dst.val = fcw;
>  
> @@ -1217,9 +1115,9 @@ static int em_fnstsw(struct x86_emulate_ctxt *ctxt)
>  	if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
>  		return emulate_nm(ctxt);
>  
> -	emulator_get_fpu();
> +	kvm_fpu_get();
>  	asm volatile("fnstsw %0": "+m"(fsw));
> -	emulator_put_fpu();
> +	kvm_fpu_put();
>  
>  	ctxt->dst.val = fsw;
>  
> @@ -1238,7 +1136,7 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
>  		op->type = OP_XMM;
>  		op->bytes = 16;
>  		op->addr.xmm = reg;
> -		read_sse_reg(&op->vec_val, reg);
> +		kvm_read_sse_reg(reg, &op->vec_val);
>  		return;
>  	}
>  	if (ctxt->d & Mmx) {
> @@ -1289,7 +1187,7 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
>  			op->type = OP_XMM;
>  			op->bytes = 16;
>  			op->addr.xmm = ctxt->modrm_rm;
> -			read_sse_reg(&op->vec_val, ctxt->modrm_rm);
> +			kvm_read_sse_reg(ctxt->modrm_rm, &op->vec_val);
>  			return rc;
>  		}
>  		if (ctxt->d & Mmx) {
> @@ -1866,10 +1764,10 @@ static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op)
>  				       op->bytes * op->count);
>  		break;
>  	case OP_XMM:
> -		write_sse_reg(&op->vec_val, op->addr.xmm);
> +		kvm_write_sse_reg(op->addr.xmm, &op->vec_val);
>  		break;
>  	case OP_MM:
> -		write_mmx_reg(&op->mm_val, op->addr.mm);
> +		kvm_write_mmx_reg(op->addr.mm, &op->mm_val);
>  		break;
>  	case OP_NONE:
>  		/* no writeback */
> @@ -4124,11 +4022,11 @@ static int em_fxsave(struct x86_emulate_ctxt *ctxt)
>  	if (rc != X86EMUL_CONTINUE)
>  		return rc;
>  
> -	emulator_get_fpu();
> +	kvm_fpu_get();
>  
>  	rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_state));
>  
> -	emulator_put_fpu();
> +	kvm_fpu_put();
>  
>  	if (rc != X86EMUL_CONTINUE)
>  		return rc;
> @@ -4172,7 +4070,7 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
>  	if (rc != X86EMUL_CONTINUE)
>  		return rc;
>  
> -	emulator_get_fpu();
> +	kvm_fpu_get();
>  
>  	if (size < __fxstate_size(16)) {
>  		rc = fxregs_fixup(&fx_state, size);
> @@ -4189,7 +4087,7 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
>  		rc = asm_safe("fxrstor %[fx]", : [fx] "m"(fx_state));
>  
>  out:
> -	emulator_put_fpu();
> +	kvm_fpu_put();
>  
>  	return rc;
>  }
> @@ -5510,9 +5408,9 @@ static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt)
>  {
>  	int rc;
>  
> -	emulator_get_fpu();
> +	kvm_fpu_get();
>  	rc = asm_safe("fwait");
> -	emulator_put_fpu();
> +	kvm_fpu_put();
>  
>  	if (unlikely(rc != X86EMUL_CONTINUE))
>  		return emulate_exception(ctxt, MF_VECTOR, 0, false);
> @@ -5523,7 +5421,7 @@ static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt)
>  static void fetch_possible_mmx_operand(struct operand *op)
>  {
>  	if (op->type == OP_MM)
> -		read_mmx_reg(&op->mm_val, op->addr.mm);
> +		kvm_read_mmx_reg(op->addr.mm, &op->mm_val);
>  }
>  
>  static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop)
> diff --git a/arch/x86/kvm/fpu.h b/arch/x86/kvm/fpu.h
> new file mode 100644
> index 000000000000..3ba12888bf66
> --- /dev/null
> +++ b/arch/x86/kvm/fpu.h
> @@ -0,0 +1,140 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __KVM_FPU_H_
> +#define __KVM_FPU_H_
> +
> +#include <asm/fpu/api.h>
> +
> +typedef u32		__attribute__((vector_size(16))) sse128_t;

Post-patch we seem to have two definitions of 'sse128_t':

$ git grep sse128_t
HEAD~3:arch/x86/kvm/fpu.h:typedef u32           __attribute__((vector_size(16))) sse128_t;
HEAD~3:arch/x86/kvm/fpu.h:#define __sse128_u    union { sse128_t vec; u64 as_u64[2]; u32 as_u32[4]; }
HEAD~3:arch/x86/kvm/fpu.h:static inline void _kvm_read_sse_reg(int reg, sse128_t *data)
HEAD~3:arch/x86/kvm/fpu.h:static inline void _kvm_write_sse_reg(int reg, const sse128_t *data)
HEAD~3:arch/x86/kvm/fpu.h:static inline void kvm_read_sse_reg(int reg, sse128_t *data)
HEAD~3:arch/x86/kvm/fpu.h:static inline void kvm_write_sse_reg(int reg, const sse128_t *data)
HEAD~3:arch/x86/kvm/kvm_emulate.h:typedef u32 __attribute__((vector_size(16))) sse128_t;
HEAD~3:arch/x86/kvm/kvm_emulate.h:              char valptr[sizeof(sse128_t)];
HEAD~3:arch/x86/kvm/kvm_emulate.h:              sse128_t vec_val;

Should the one from kvm_emulate.h go away?

> +#define __sse128_u	union { sse128_t vec; u64 as_u64[2]; u32 as_u32[4]; }
> +#define sse128_lo(x)	({ __sse128_u t; t.vec = x; t.as_u64[0]; })
> +#define sse128_hi(x)	({ __sse128_u t; t.vec = x; t.as_u64[1]; })
> +#define sse128_l0(x)	({ __sse128_u t; t.vec = x; t.as_u32[0]; })
> +#define sse128_l1(x)	({ __sse128_u t; t.vec = x; t.as_u32[1]; })
> +#define sse128_l2(x)	({ __sse128_u t; t.vec = x; t.as_u32[2]; })
> +#define sse128_l3(x)	({ __sse128_u t; t.vec = x; t.as_u32[3]; })
> +#define sse128(lo, hi)	({ __sse128_u t; t.as_u64[0] = lo; t.as_u64[1] = hi; t.vec; })
> +
> +static inline void _kvm_read_sse_reg(int reg, sse128_t *data)
> +{
> +	switch (reg) {
> +	case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break;
> +	case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break;
> +	case 2: asm("movdqa %%xmm2, %0" : "=m"(*data)); break;
> +	case 3: asm("movdqa %%xmm3, %0" : "=m"(*data)); break;
> +	case 4: asm("movdqa %%xmm4, %0" : "=m"(*data)); break;
> +	case 5: asm("movdqa %%xmm5, %0" : "=m"(*data)); break;
> +	case 6: asm("movdqa %%xmm6, %0" : "=m"(*data)); break;
> +	case 7: asm("movdqa %%xmm7, %0" : "=m"(*data)); break;
> +#ifdef CONFIG_X86_64
> +	case 8: asm("movdqa %%xmm8, %0" : "=m"(*data)); break;
> +	case 9: asm("movdqa %%xmm9, %0" : "=m"(*data)); break;
> +	case 10: asm("movdqa %%xmm10, %0" : "=m"(*data)); break;
> +	case 11: asm("movdqa %%xmm11, %0" : "=m"(*data)); break;
> +	case 12: asm("movdqa %%xmm12, %0" : "=m"(*data)); break;
> +	case 13: asm("movdqa %%xmm13, %0" : "=m"(*data)); break;
> +	case 14: asm("movdqa %%xmm14, %0" : "=m"(*data)); break;
> +	case 15: asm("movdqa %%xmm15, %0" : "=m"(*data)); break;
> +#endif
> +	default: BUG();
> +	}
> +}
> +
> +static inline void _kvm_write_sse_reg(int reg, const sse128_t *data)
> +{
> +	switch (reg) {
> +	case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break;
> +	case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break;
> +	case 2: asm("movdqa %0, %%xmm2" : : "m"(*data)); break;
> +	case 3: asm("movdqa %0, %%xmm3" : : "m"(*data)); break;
> +	case 4: asm("movdqa %0, %%xmm4" : : "m"(*data)); break;
> +	case 5: asm("movdqa %0, %%xmm5" : : "m"(*data)); break;
> +	case 6: asm("movdqa %0, %%xmm6" : : "m"(*data)); break;
> +	case 7: asm("movdqa %0, %%xmm7" : : "m"(*data)); break;
> +#ifdef CONFIG_X86_64
> +	case 8: asm("movdqa %0, %%xmm8" : : "m"(*data)); break;
> +	case 9: asm("movdqa %0, %%xmm9" : : "m"(*data)); break;
> +	case 10: asm("movdqa %0, %%xmm10" : : "m"(*data)); break;
> +	case 11: asm("movdqa %0, %%xmm11" : : "m"(*data)); break;
> +	case 12: asm("movdqa %0, %%xmm12" : : "m"(*data)); break;
> +	case 13: asm("movdqa %0, %%xmm13" : : "m"(*data)); break;
> +	case 14: asm("movdqa %0, %%xmm14" : : "m"(*data)); break;
> +	case 15: asm("movdqa %0, %%xmm15" : : "m"(*data)); break;
> +#endif
> +	default: BUG();
> +	}
> +}
> +
> +static inline void _kvm_read_mmx_reg(int reg, u64 *data)
> +{
> +	switch (reg) {
> +	case 0: asm("movq %%mm0, %0" : "=m"(*data)); break;
> +	case 1: asm("movq %%mm1, %0" : "=m"(*data)); break;
> +	case 2: asm("movq %%mm2, %0" : "=m"(*data)); break;
> +	case 3: asm("movq %%mm3, %0" : "=m"(*data)); break;
> +	case 4: asm("movq %%mm4, %0" : "=m"(*data)); break;
> +	case 5: asm("movq %%mm5, %0" : "=m"(*data)); break;
> +	case 6: asm("movq %%mm6, %0" : "=m"(*data)); break;
> +	case 7: asm("movq %%mm7, %0" : "=m"(*data)); break;
> +	default: BUG();
> +	}
> +}
> +
> +static inline void _kvm_write_mmx_reg(int reg, const u64 *data)
> +{
> +	switch (reg) {
> +	case 0: asm("movq %0, %%mm0" : : "m"(*data)); break;
> +	case 1: asm("movq %0, %%mm1" : : "m"(*data)); break;
> +	case 2: asm("movq %0, %%mm2" : : "m"(*data)); break;
> +	case 3: asm("movq %0, %%mm3" : : "m"(*data)); break;
> +	case 4: asm("movq %0, %%mm4" : : "m"(*data)); break;
> +	case 5: asm("movq %0, %%mm5" : : "m"(*data)); break;
> +	case 6: asm("movq %0, %%mm6" : : "m"(*data)); break;
> +	case 7: asm("movq %0, %%mm7" : : "m"(*data)); break;
> +	default: BUG();
> +	}
> +}
> +
> +static inline void kvm_fpu_get(void)
> +{
> +	fpregs_lock();
> +
> +	fpregs_assert_state_consistent();
> +	if (test_thread_flag(TIF_NEED_FPU_LOAD))
> +		switch_fpu_return();
> +}
> +
> +static inline void kvm_fpu_put(void)
> +{
> +	fpregs_unlock();
> +}
> +
> +static inline void kvm_read_sse_reg(int reg, sse128_t *data)
> +{
> +	kvm_fpu_get();
> +	_kvm_read_sse_reg(reg, data);
> +	kvm_fpu_put();
> +}
> +
> +static inline void kvm_write_sse_reg(int reg, const sse128_t *data)
> +{
> +	kvm_fpu_get();
> +	_kvm_write_sse_reg(reg, data);
> +	kvm_fpu_put();
> +}
> +
> +static inline void kvm_read_mmx_reg(int reg, u64 *data)
> +{
> +	kvm_fpu_get();
> +	_kvm_read_mmx_reg(reg, data);
> +	kvm_fpu_put();
> +}
> +
> +static inline void kvm_write_mmx_reg(int reg, const u64 *data)
> +{
> +	kvm_fpu_get();
> +	_kvm_write_mmx_reg(reg, data);
> +	kvm_fpu_put();
> +}
> +
> +#endif

-- 
Vitaly




[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