From: Simon Scherer <[email protected]> The decoding of the extrq instruction with an immediate operand (EXTRQ_i) is incorrect. Per the AMD manual the instruction encoding looks as follows:
EXTRQ xmm1, imm8, imm8 66 0F 78 /0 ib ib The /0 indicates that the "Reg" field of the ModR/M byte must be equal to 0 and the XMM register operand is specified by the "R/M" field. However, qemu incorrectly uses the "Reg" field to extract the register operand. This patch instead extracts the XMM register operand from the "R/M" field. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3611 Signed-off-by: Simon Scherer <[email protected]> Reviewed-by: Richard Henderson <[email protected]> Link: https://lore.kernel.org/r/[email protected] [Check for the reg field to be 0. Make decoding of REPZ+66 consistent between 0F 78 and 0F 79. - Paolo] Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/decode-new.c.inc | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index ac181308ca4..ac5964b95de 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -603,23 +603,33 @@ static void decode_0F77(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui static void decode_0F78(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) { - static const X86OpEntry opcodes_0F78[4] = { - {}, - X86_OP_ENTRY3(EXTRQ_i, V,x, None,None, I,w, cpuid(SSE4A)), /* AMD extension */ - {}, - X86_OP_ENTRY3(INSERTQ_i, V,x, U,x, I,w, cpuid(SSE4A)), /* AMD extension */ - }; - *entry = *decode_by_prefix(s, opcodes_0F78); + static const X86OpEntry opcodes_0F78_f2 = + X86_OP_ENTRY3(INSERTQ_i, V,x, U,x, I,w, cpuid(SSE4A)); /* AMD extension */ + static const X86OpEntry opcodes_0F78_66 = + X86_OP_ENTRY3(EXTRQ_i, U,x, None,None, I,w, cpuid(SSE4A)); /* AMD extension */ + + entry->gen = NULL; + if (s->prefix & PREFIX_REPNZ) { + *entry = opcodes_0F78_f2; + } else if (s->prefix & PREFIX_REPZ) { + /* undefined */ + } else if (s->prefix & PREFIX_DATA) { + int op = (get_modrm(s, env) >> 3) & 7; + if (op == 0) { + *entry = opcodes_0F78_66; + } + } } static void decode_0F79(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) { + entry->gen = NULL; if (s->prefix & PREFIX_REPNZ) { entry->gen = gen_INSERTQ_r; /* AMD extension */ + } else if (s->prefix & PREFIX_REPZ) { + /* undefined */ } else if (s->prefix & PREFIX_DATA) { entry->gen = gen_EXTRQ_r; /* AMD extension */ - } else { - entry->gen = NULL; }; } -- 2.55.0
