According to both Volume 2 of Intel 64 and IA-32 Architectures Software Developer's Manual and Volume 4 of AMD64 Architecture Programmer's Manual, VEX.L is a "don't care" bit for `VROUNDSS`, `VROUNDSD`, `VMOVSS`, `VMOVSD`.
Currently, QEMU handles VEX.L with these instructions differently: - In the VMOVSS and VMOVSD case, VEX.L allows to select the register size (XMM or YMM), leading to differences between QEMU and the real hardware. - In `gen_VROUNDSS()` and `gen_VROUNDSD()`, there is an assert which checks that `s->vex_l` is not set. When either instruction is encountered with VEX.L bit set, the QEMU process crashes with an assertion failure. These behaviors deviate from real hardware, and in VROUNDSS/VROUNDSD case, it also allows unprivileged guest userspace to crash the QEMU process itself. Instead, always handle the instructions as if VEX.L=0. Reported-by: Andrey Polivoda <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/decode-new.h | 6 ++++++ target/i386/tcg/decode-new.c.inc | 17 +++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/target/i386/tcg/decode-new.h b/target/i386/tcg/decode-new.h index 92822969003..25f7d2215ee 100644 --- a/target/i386/tcg/decode-new.h +++ b/target/i386/tcg/decode-new.h @@ -263,6 +263,12 @@ typedef enum X86VEXSpecial { * operands, and thus handled by decode_op_size. */ X86_VEX_AVX2_256, + + /* + * Instructions that do not care about VEX.L; used for scalar operands, because + * they *should* be used only with VEX.L=0 but may accept VEX.L=1 on some machines. + */ + X86_VEX_LIG, } X86VEXSpecial; diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index 459452b04e3..8d1e581cfde 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -260,6 +260,7 @@ #define svm(a) .intercept = SVM_EXIT_##a, .has_intercept = true, #define avx2_256 .vex_special = X86_VEX_AVX2_256, +#define vex_lig .vex_special = X86_VEX_LIG, #define P_00 1 #define P_66 (1 << PREFIX_DATA) @@ -996,8 +997,8 @@ static const X86OpEntry opcodes_0F3A[256] = { * For other unary operations such as VSQRTSx this is hidden by the "REPScalar" * value of vex_special, because the table lists the operand types of VSQRTPx. */ - [0x0a] = X86_OP_ENTRY4(VROUNDSS, V,x, H,x, W,ss, vex3 cpuid(SSE41) p_66), - [0x0b] = X86_OP_ENTRY4(VROUNDSD, V,x, H,x, W,sd, vex3 cpuid(SSE41) p_66), + [0x0a] = X86_OP_ENTRY4(VROUNDSS, V,x, H,x, W,ss, vex3 vex_lig cpuid(SSE41) p_66), + [0x0b] = X86_OP_ENTRY4(VROUNDSD, V,x, H,x, W,sd, vex3 vex_lig cpuid(SSE41) p_66), [0x0c] = X86_OP_ENTRY4(VBLENDPS, V,x, H,x, W,x, vex4 cpuid(SSE41) p_66), [0x0d] = X86_OP_ENTRY4(VBLENDPD, V,x, H,x, W,x, vex4 cpuid(SSE41) p_66), [0x0e] = X86_OP_ENTRY4(VPBLENDW, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), @@ -1053,8 +1054,8 @@ static void decode_0F10(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui static const X86OpEntry opcodes_0F10_mem[4] = { X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex4_unal), /* MOVUPS */ X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex4_unal), /* MOVUPD */ - X86_OP_ENTRY3(VMOVSS_ld, V,x, H,x, M,ss, vex5), - X86_OP_ENTRY3(VMOVSD_ld, V,x, H,x, M,sd, vex5), + X86_OP_ENTRY3(VMOVSS_ld, V,x, H,x, M,ss, vex5 vex_lig), + X86_OP_ENTRY3(VMOVSD_ld, V,x, H,x, M,sd, vex5 vex_lig), }; if ((get_modrm(s, env) >> 6) == 3) { @@ -1076,8 +1077,8 @@ static void decode_0F11(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui static const X86OpEntry opcodes_0F11_mem[4] = { X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex4_unal), /* MOVUPS */ X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex4_unal), /* MOVUPD */ - X86_OP_ENTRY3(VMOVSS_st, M,ss, None,None, V,x, vex5), - X86_OP_ENTRY3(VMOVLPx_st, M,sd, None,None, V,x, vex5), /* MOVSD */ + X86_OP_ENTRY3(VMOVSS_st, M,ss, None,None, V,x, vex5 vex_lig), + X86_OP_ENTRY3(VMOVLPx_st, M,sd, None,None, V,x, vex5 vex_lig), /* MOVSD */ }; if ((get_modrm(s, env) >> 6) == 3) { @@ -2653,6 +2654,10 @@ static bool validate_vex(DisasContext *s, X86DecodedInsn *decode) case X86_VEX_None: break; + case X86_VEX_LIG: + s->vex_l = 0; + break; + case X86_VEX_REPScalar: /* * Instructions which differ between 00/66 and F2/F3 in the -- 2.55.0
