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


Reply via email to