Commit 5ed934e5 authored by Vasily Gorbik's avatar Vasily Gorbik Committed by Josh Poimboeuf

x86/insn: Fix vector instruction decoding on big endian cross-compiles

Running instruction decoder posttest on an s390 host with an x86 target
with allyesconfig shows errors. Instructions used in a couple of kernel
objects could not be correctly decoded on big endian system.

  insn_decoder_test: warning: objdump says 6 bytes, but insn_get_length() says 5
  insn_decoder_test: warning: Found an x86 instruction decoder bug, please report this.
  insn_decoder_test: warning: ffffffff831eb4e1:    62 d1 fd 48 7f 04 24    vmovdqa64 %zmm0,(%r12)
  insn_decoder_test: warning: objdump says 7 bytes, but insn_get_length() says 6
  insn_decoder_test: warning: Found an x86 instruction decoder bug, please report this.
  insn_decoder_test: warning: ffffffff831eb4e8:    62 51 fd 48 7f 44 24 01         vmovdqa64 %zmm8,0x40(%r12)
  insn_decoder_test: warning: objdump says 8 bytes, but insn_get_length() says 6

This is because in a few places instruction field bytes are set directly
with further usage of "value". To address that introduce and use a
insn_set_byte() helper, which correctly updates "value" on big endian
systems.
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
Acked-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
parent 7786032e
...@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v, ...@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
p->nbytes = n; p->nbytes = n;
} }
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
insn_byte_t v)
{
p->bytes[n] = v;
}
#else #else
struct insn_field { struct insn_field {
...@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v, ...@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
p->nbytes = n; p->nbytes = n;
} }
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
insn_byte_t v)
{
p->bytes[n] = v;
p->value = __le32_to_cpu(p->little);
}
#endif #endif
struct insn { struct insn {
......
...@@ -161,9 +161,9 @@ void insn_get_prefixes(struct insn *insn) ...@@ -161,9 +161,9 @@ void insn_get_prefixes(struct insn *insn)
b = insn->prefixes.bytes[3]; b = insn->prefixes.bytes[3];
for (i = 0; i < nb; i++) for (i = 0; i < nb; i++)
if (prefixes->bytes[i] == lb) if (prefixes->bytes[i] == lb)
prefixes->bytes[i] = b; insn_set_byte(prefixes, i, b);
} }
insn->prefixes.bytes[3] = lb; insn_set_byte(&insn->prefixes, 3, lb);
} }
/* Decode REX prefix */ /* Decode REX prefix */
...@@ -194,13 +194,13 @@ void insn_get_prefixes(struct insn *insn) ...@@ -194,13 +194,13 @@ void insn_get_prefixes(struct insn *insn)
if (X86_MODRM_MOD(b2) != 3) if (X86_MODRM_MOD(b2) != 3)
goto vex_end; goto vex_end;
} }
insn->vex_prefix.bytes[0] = b; insn_set_byte(&insn->vex_prefix, 0, b);
insn->vex_prefix.bytes[1] = b2; insn_set_byte(&insn->vex_prefix, 1, b2);
if (inat_is_evex_prefix(attr)) { if (inat_is_evex_prefix(attr)) {
b2 = peek_nbyte_next(insn_byte_t, insn, 2); b2 = peek_nbyte_next(insn_byte_t, insn, 2);
insn->vex_prefix.bytes[2] = b2; insn_set_byte(&insn->vex_prefix, 2, b2);
b2 = peek_nbyte_next(insn_byte_t, insn, 3); b2 = peek_nbyte_next(insn_byte_t, insn, 3);
insn->vex_prefix.bytes[3] = b2; insn_set_byte(&insn->vex_prefix, 3, b2);
insn->vex_prefix.nbytes = 4; insn->vex_prefix.nbytes = 4;
insn->next_byte += 4; insn->next_byte += 4;
if (insn->x86_64 && X86_VEX_W(b2)) if (insn->x86_64 && X86_VEX_W(b2))
...@@ -208,7 +208,7 @@ void insn_get_prefixes(struct insn *insn) ...@@ -208,7 +208,7 @@ void insn_get_prefixes(struct insn *insn)
insn->opnd_bytes = 8; insn->opnd_bytes = 8;
} else if (inat_is_vex3_prefix(attr)) { } else if (inat_is_vex3_prefix(attr)) {
b2 = peek_nbyte_next(insn_byte_t, insn, 2); b2 = peek_nbyte_next(insn_byte_t, insn, 2);
insn->vex_prefix.bytes[2] = b2; insn_set_byte(&insn->vex_prefix, 2, b2);
insn->vex_prefix.nbytes = 3; insn->vex_prefix.nbytes = 3;
insn->next_byte += 3; insn->next_byte += 3;
if (insn->x86_64 && X86_VEX_W(b2)) if (insn->x86_64 && X86_VEX_W(b2))
...@@ -220,7 +220,7 @@ void insn_get_prefixes(struct insn *insn) ...@@ -220,7 +220,7 @@ void insn_get_prefixes(struct insn *insn)
* Makes it easier to decode vex.W, vex.vvvv, * Makes it easier to decode vex.W, vex.vvvv,
* vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
*/ */
insn->vex_prefix.bytes[2] = b2 & 0x7f; insn_set_byte(&insn->vex_prefix, 2, b2 & 0x7f);
insn->vex_prefix.nbytes = 2; insn->vex_prefix.nbytes = 2;
insn->next_byte += 2; insn->next_byte += 2;
} }
...@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn) ...@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn)
/* Get first opcode */ /* Get first opcode */
op = get_next(insn_byte_t, insn); op = get_next(insn_byte_t, insn);
opcode->bytes[0] = op; insn_set_byte(opcode, 0, op);
opcode->nbytes = 1; opcode->nbytes = 1;
/* Check if there is VEX prefix or not */ /* Check if there is VEX prefix or not */
......
...@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v, ...@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
p->nbytes = n; p->nbytes = n;
} }
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
insn_byte_t v)
{
p->bytes[n] = v;
}
#else #else
struct insn_field { struct insn_field {
...@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v, ...@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
p->nbytes = n; p->nbytes = n;
} }
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
insn_byte_t v)
{
p->bytes[n] = v;
p->value = __le32_to_cpu(p->little);
}
#endif #endif
struct insn { struct insn {
......
...@@ -161,9 +161,9 @@ void insn_get_prefixes(struct insn *insn) ...@@ -161,9 +161,9 @@ void insn_get_prefixes(struct insn *insn)
b = insn->prefixes.bytes[3]; b = insn->prefixes.bytes[3];
for (i = 0; i < nb; i++) for (i = 0; i < nb; i++)
if (prefixes->bytes[i] == lb) if (prefixes->bytes[i] == lb)
prefixes->bytes[i] = b; insn_set_byte(prefixes, i, b);
} }
insn->prefixes.bytes[3] = lb; insn_set_byte(&insn->prefixes, 3, lb);
} }
/* Decode REX prefix */ /* Decode REX prefix */
...@@ -194,13 +194,13 @@ void insn_get_prefixes(struct insn *insn) ...@@ -194,13 +194,13 @@ void insn_get_prefixes(struct insn *insn)
if (X86_MODRM_MOD(b2) != 3) if (X86_MODRM_MOD(b2) != 3)
goto vex_end; goto vex_end;
} }
insn->vex_prefix.bytes[0] = b; insn_set_byte(&insn->vex_prefix, 0, b);
insn->vex_prefix.bytes[1] = b2; insn_set_byte(&insn->vex_prefix, 1, b2);
if (inat_is_evex_prefix(attr)) { if (inat_is_evex_prefix(attr)) {
b2 = peek_nbyte_next(insn_byte_t, insn, 2); b2 = peek_nbyte_next(insn_byte_t, insn, 2);
insn->vex_prefix.bytes[2] = b2; insn_set_byte(&insn->vex_prefix, 2, b2);
b2 = peek_nbyte_next(insn_byte_t, insn, 3); b2 = peek_nbyte_next(insn_byte_t, insn, 3);
insn->vex_prefix.bytes[3] = b2; insn_set_byte(&insn->vex_prefix, 3, b2);
insn->vex_prefix.nbytes = 4; insn->vex_prefix.nbytes = 4;
insn->next_byte += 4; insn->next_byte += 4;
if (insn->x86_64 && X86_VEX_W(b2)) if (insn->x86_64 && X86_VEX_W(b2))
...@@ -208,7 +208,7 @@ void insn_get_prefixes(struct insn *insn) ...@@ -208,7 +208,7 @@ void insn_get_prefixes(struct insn *insn)
insn->opnd_bytes = 8; insn->opnd_bytes = 8;
} else if (inat_is_vex3_prefix(attr)) { } else if (inat_is_vex3_prefix(attr)) {
b2 = peek_nbyte_next(insn_byte_t, insn, 2); b2 = peek_nbyte_next(insn_byte_t, insn, 2);
insn->vex_prefix.bytes[2] = b2; insn_set_byte(&insn->vex_prefix, 2, b2);
insn->vex_prefix.nbytes = 3; insn->vex_prefix.nbytes = 3;
insn->next_byte += 3; insn->next_byte += 3;
if (insn->x86_64 && X86_VEX_W(b2)) if (insn->x86_64 && X86_VEX_W(b2))
...@@ -220,7 +220,7 @@ void insn_get_prefixes(struct insn *insn) ...@@ -220,7 +220,7 @@ void insn_get_prefixes(struct insn *insn)
* Makes it easier to decode vex.W, vex.vvvv, * Makes it easier to decode vex.W, vex.vvvv,
* vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
*/ */
insn->vex_prefix.bytes[2] = b2 & 0x7f; insn_set_byte(&insn->vex_prefix, 2, b2 & 0x7f);
insn->vex_prefix.nbytes = 2; insn->vex_prefix.nbytes = 2;
insn->next_byte += 2; insn->next_byte += 2;
} }
...@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn) ...@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn)
/* Get first opcode */ /* Get first opcode */
op = get_next(insn_byte_t, insn); op = get_next(insn_byte_t, insn);
opcode->bytes[0] = op; insn_set_byte(opcode, 0, op);
opcode->nbytes = 1; opcode->nbytes = 1;
/* Check if there is VEX prefix or not */ /* Check if there is VEX prefix or not */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment