Commit f8d98f10 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Ingo Molnar

x86: Fix to decode grouped AVX with VEX pp bits

Fix to decode grouped AVX with VEX pp bits which should be
handled as same as last-prefixes. This fixes below warnings
in posttest with CONFIG_CRYPTO_SHA1_SSSE3=y.

 Warning: arch/x86/tools/test_get_len found difference at <sha1_transform_avx>:ffffffff810d5fc0
 Warning: ffffffff810d6069:	c5 f9 73 de 04       	vpsrldq $0x4,%xmm6,%xmm0
 Warning: objdump says 5 bytes, but insn_get_length() says 4
 ...

With this change, test_get_len can decode it correctly.

 $ arch/x86/tools/test_get_len -v -y
 ffffffff810d6069:       c5 f9 73 de 04          vpsrldq $0x4,%xmm6,%xmm0
 Succeed: decoded and checked 1 instructions
Reported-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20120210053340.30429.73410.stgit@localhost.localdomainSigned-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 86f5e6a7
...@@ -97,11 +97,12 @@ ...@@ -97,11 +97,12 @@
/* Attribute search APIs */ /* Attribute search APIs */
extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
extern int inat_get_last_prefix_id(insn_byte_t last_pfx);
extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode,
insn_byte_t last_pfx, int lpfx_id,
insn_attr_t esc_attr); insn_attr_t esc_attr);
extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
insn_byte_t last_pfx, int lpfx_id,
insn_attr_t esc_attr); insn_attr_t esc_attr);
extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode,
insn_byte_t vex_m, insn_byte_t vex_m,
......
...@@ -96,12 +96,6 @@ struct insn { ...@@ -96,12 +96,6 @@ struct insn {
#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ #define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */
#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ #define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */
/* The last prefix is needed for two-byte and three-byte opcodes */
static inline insn_byte_t insn_last_prefix(struct insn *insn)
{
return insn->prefixes.bytes[3];
}
extern void insn_init(struct insn *insn, const void *kaddr, int x86_64); extern void insn_init(struct insn *insn, const void *kaddr, int x86_64);
extern void insn_get_prefixes(struct insn *insn); extern void insn_get_prefixes(struct insn *insn);
extern void insn_get_opcode(struct insn *insn); extern void insn_get_opcode(struct insn *insn);
...@@ -160,6 +154,18 @@ static inline insn_byte_t insn_vex_p_bits(struct insn *insn) ...@@ -160,6 +154,18 @@ static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
return X86_VEX_P(insn->vex_prefix.bytes[2]); return X86_VEX_P(insn->vex_prefix.bytes[2]);
} }
/* Get the last prefix id from last prefix or VEX prefix */
static inline int insn_last_prefix_id(struct insn *insn)
{
if (insn_is_avx(insn))
return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */
if (insn->prefixes.bytes[3])
return inat_get_last_prefix_id(insn->prefixes.bytes[3]);
return 0;
}
/* Offset of each field from kaddr */ /* Offset of each field from kaddr */
static inline int insn_offset_rex_prefix(struct insn *insn) static inline int insn_offset_rex_prefix(struct insn *insn)
{ {
......
...@@ -29,46 +29,46 @@ insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) ...@@ -29,46 +29,46 @@ insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode)
return inat_primary_table[opcode]; return inat_primary_table[opcode];
} }
insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, insn_byte_t last_pfx, int inat_get_last_prefix_id(insn_byte_t last_pfx)
{
insn_attr_t lpfx_attr;
lpfx_attr = inat_get_opcode_attribute(last_pfx);
return inat_last_prefix_id(lpfx_attr);
}
insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id,
insn_attr_t esc_attr) insn_attr_t esc_attr)
{ {
const insn_attr_t *table; const insn_attr_t *table;
insn_attr_t lpfx_attr; int n;
int n, m = 0;
n = inat_escape_id(esc_attr); n = inat_escape_id(esc_attr);
if (last_pfx) {
lpfx_attr = inat_get_opcode_attribute(last_pfx);
m = inat_last_prefix_id(lpfx_attr);
}
table = inat_escape_tables[n][0]; table = inat_escape_tables[n][0];
if (!table) if (!table)
return 0; return 0;
if (inat_has_variant(table[opcode]) && m) { if (inat_has_variant(table[opcode]) && lpfx_id) {
table = inat_escape_tables[n][m]; table = inat_escape_tables[n][lpfx_id];
if (!table) if (!table)
return 0; return 0;
} }
return table[opcode]; return table[opcode];
} }
insn_attr_t inat_get_group_attribute(insn_byte_t modrm, insn_byte_t last_pfx, insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id,
insn_attr_t grp_attr) insn_attr_t grp_attr)
{ {
const insn_attr_t *table; const insn_attr_t *table;
insn_attr_t lpfx_attr; int n;
int n, m = 0;
n = inat_group_id(grp_attr); n = inat_group_id(grp_attr);
if (last_pfx) {
lpfx_attr = inat_get_opcode_attribute(last_pfx);
m = inat_last_prefix_id(lpfx_attr);
}
table = inat_group_tables[n][0]; table = inat_group_tables[n][0];
if (!table) if (!table)
return inat_group_common_attribute(grp_attr); return inat_group_common_attribute(grp_attr);
if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && m) { if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) {
table = inat_group_tables[n][m]; table = inat_group_tables[n][lpfx_id];
if (!table) if (!table)
return inat_group_common_attribute(grp_attr); return inat_group_common_attribute(grp_attr);
} }
......
...@@ -185,7 +185,8 @@ void insn_get_prefixes(struct insn *insn) ...@@ -185,7 +185,8 @@ void insn_get_prefixes(struct insn *insn)
void insn_get_opcode(struct insn *insn) void insn_get_opcode(struct insn *insn)
{ {
struct insn_field *opcode = &insn->opcode; struct insn_field *opcode = &insn->opcode;
insn_byte_t op, pfx; insn_byte_t op;
int pfx_id;
if (opcode->got) if (opcode->got)
return; return;
if (!insn->prefixes.got) if (!insn->prefixes.got)
...@@ -212,8 +213,8 @@ void insn_get_opcode(struct insn *insn) ...@@ -212,8 +213,8 @@ void insn_get_opcode(struct insn *insn)
/* Get escaped opcode */ /* Get escaped opcode */
op = get_next(insn_byte_t, insn); op = get_next(insn_byte_t, insn);
opcode->bytes[opcode->nbytes++] = op; opcode->bytes[opcode->nbytes++] = op;
pfx = insn_last_prefix(insn); pfx_id = insn_last_prefix_id(insn);
insn->attr = inat_get_escape_attribute(op, pfx, insn->attr); insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr);
} }
if (inat_must_vex(insn->attr)) if (inat_must_vex(insn->attr))
insn->attr = 0; /* This instruction is bad */ insn->attr = 0; /* This instruction is bad */
...@@ -235,7 +236,7 @@ void insn_get_opcode(struct insn *insn) ...@@ -235,7 +236,7 @@ void insn_get_opcode(struct insn *insn)
void insn_get_modrm(struct insn *insn) void insn_get_modrm(struct insn *insn)
{ {
struct insn_field *modrm = &insn->modrm; struct insn_field *modrm = &insn->modrm;
insn_byte_t pfx, mod; insn_byte_t pfx_id, mod;
if (modrm->got) if (modrm->got)
return; return;
if (!insn->opcode.got) if (!insn->opcode.got)
...@@ -246,8 +247,8 @@ void insn_get_modrm(struct insn *insn) ...@@ -246,8 +247,8 @@ void insn_get_modrm(struct insn *insn)
modrm->value = mod; modrm->value = mod;
modrm->nbytes = 1; modrm->nbytes = 1;
if (inat_is_group(insn->attr)) { if (inat_is_group(insn->attr)) {
pfx = insn_last_prefix(insn); pfx_id = insn_last_prefix_id(insn);
insn->attr = inat_get_group_attribute(mod, pfx, insn->attr = inat_get_group_attribute(mod, pfx_id,
insn->attr); insn->attr);
if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) if (insn_is_avx(insn) && !inat_accept_vex(insn->attr))
insn->attr = 0; /* This is bad */ insn->attr = 0; /* This is bad */
......
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