Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20120210053340.30429.73410.stgit@localhost.localdomain
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Masami Hiramatsu and committed by
Ingo Molnar
f8d98f10 86f5e6a7

+40 -32
+3 -2
arch/x86/include/asm/inat.h
··· 97 97 98 98 /* Attribute search APIs */ 99 99 extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); 100 + extern int inat_get_last_prefix_id(insn_byte_t last_pfx); 100 101 extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, 101 - insn_byte_t last_pfx, 102 + int lpfx_id, 102 103 insn_attr_t esc_attr); 103 104 extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, 104 - insn_byte_t last_pfx, 105 + int lpfx_id, 105 106 insn_attr_t esc_attr); 106 107 extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, 107 108 insn_byte_t vex_m,
+12 -6
arch/x86/include/asm/insn.h
··· 96 96 #define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ 97 97 #define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ 98 98 99 - /* The last prefix is needed for two-byte and three-byte opcodes */ 100 - static inline insn_byte_t insn_last_prefix(struct insn *insn) 101 - { 102 - return insn->prefixes.bytes[3]; 103 - } 104 - 105 99 extern void insn_init(struct insn *insn, const void *kaddr, int x86_64); 106 100 extern void insn_get_prefixes(struct insn *insn); 107 101 extern void insn_get_opcode(struct insn *insn); ··· 152 158 return X86_VEX_P(insn->vex_prefix.bytes[1]); 153 159 else 154 160 return X86_VEX_P(insn->vex_prefix.bytes[2]); 161 + } 162 + 163 + /* Get the last prefix id from last prefix or VEX prefix */ 164 + static inline int insn_last_prefix_id(struct insn *insn) 165 + { 166 + if (insn_is_avx(insn)) 167 + return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ 168 + 169 + if (insn->prefixes.bytes[3]) 170 + return inat_get_last_prefix_id(insn->prefixes.bytes[3]); 171 + 172 + return 0; 155 173 } 156 174 157 175 /* Offset of each field from kaddr */
+18 -18
arch/x86/lib/inat.c
··· 29 29 return inat_primary_table[opcode]; 30 30 } 31 31 32 - insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, insn_byte_t last_pfx, 32 + int inat_get_last_prefix_id(insn_byte_t last_pfx) 33 + { 34 + insn_attr_t lpfx_attr; 35 + 36 + lpfx_attr = inat_get_opcode_attribute(last_pfx); 37 + return inat_last_prefix_id(lpfx_attr); 38 + } 39 + 40 + insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, 33 41 insn_attr_t esc_attr) 34 42 { 35 43 const insn_attr_t *table; 36 - insn_attr_t lpfx_attr; 37 - int n, m = 0; 44 + int n; 38 45 39 46 n = inat_escape_id(esc_attr); 40 - if (last_pfx) { 41 - lpfx_attr = inat_get_opcode_attribute(last_pfx); 42 - m = inat_last_prefix_id(lpfx_attr); 43 - } 47 + 44 48 table = inat_escape_tables[n][0]; 45 49 if (!table) 46 50 return 0; 47 - if (inat_has_variant(table[opcode]) && m) { 48 - table = inat_escape_tables[n][m]; 51 + if (inat_has_variant(table[opcode]) && lpfx_id) { 52 + table = inat_escape_tables[n][lpfx_id]; 49 53 if (!table) 50 54 return 0; 51 55 } 52 56 return table[opcode]; 53 57 } 54 58 55 - insn_attr_t inat_get_group_attribute(insn_byte_t modrm, insn_byte_t last_pfx, 59 + insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, 56 60 insn_attr_t grp_attr) 57 61 { 58 62 const insn_attr_t *table; 59 - insn_attr_t lpfx_attr; 60 - int n, m = 0; 63 + int n; 61 64 62 65 n = inat_group_id(grp_attr); 63 - if (last_pfx) { 64 - lpfx_attr = inat_get_opcode_attribute(last_pfx); 65 - m = inat_last_prefix_id(lpfx_attr); 66 - } 66 + 67 67 table = inat_group_tables[n][0]; 68 68 if (!table) 69 69 return inat_group_common_attribute(grp_attr); 70 - if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && m) { 71 - table = inat_group_tables[n][m]; 70 + if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { 71 + table = inat_group_tables[n][lpfx_id]; 72 72 if (!table) 73 73 return inat_group_common_attribute(grp_attr); 74 74 }
+7 -6
arch/x86/lib/insn.c
··· 185 185 void insn_get_opcode(struct insn *insn) 186 186 { 187 187 struct insn_field *opcode = &insn->opcode; 188 - insn_byte_t op, pfx; 188 + insn_byte_t op; 189 + int pfx_id; 189 190 if (opcode->got) 190 191 return; 191 192 if (!insn->prefixes.got) ··· 213 212 /* Get escaped opcode */ 214 213 op = get_next(insn_byte_t, insn); 215 214 opcode->bytes[opcode->nbytes++] = op; 216 - pfx = insn_last_prefix(insn); 217 - insn->attr = inat_get_escape_attribute(op, pfx, insn->attr); 215 + pfx_id = insn_last_prefix_id(insn); 216 + insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); 218 217 } 219 218 if (inat_must_vex(insn->attr)) 220 219 insn->attr = 0; /* This instruction is bad */ ··· 236 235 void insn_get_modrm(struct insn *insn) 237 236 { 238 237 struct insn_field *modrm = &insn->modrm; 239 - insn_byte_t pfx, mod; 238 + insn_byte_t pfx_id, mod; 240 239 if (modrm->got) 241 240 return; 242 241 if (!insn->opcode.got) ··· 247 246 modrm->value = mod; 248 247 modrm->nbytes = 1; 249 248 if (inat_is_group(insn->attr)) { 250 - pfx = insn_last_prefix(insn); 251 - insn->attr = inat_get_group_attribute(mod, pfx, 249 + pfx_id = insn_last_prefix_id(insn); 250 + insn->attr = inat_get_group_attribute(mod, pfx_id, 252 251 insn->attr); 253 252 if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) 254 253 insn->attr = 0; /* This is bad */