Commit 436d03fa authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Ingo Molnar

x86/decoder: Fix bsr/bsf/jmpe decoding with operand-size prefix

Fix the x86 instruction decoder to decode bsr/bsf/jmpe with
operand-size prefix (66h). This fixes the test case failure
reported by Linus, attached below.

bsf/bsr/jmpe have a special encoding. Opcode map in
Intel Software Developers Manual vol2 says they have
TZCNT/LZCNT variants if it has F3h prefix. However, there
is no information if it has other 66h or F2h prefixes.
Current instruction decoder supposes that those are
bad instructions, but it actually accepts at least
operand-size prefixes.

H. Peter Anvin further explains:

 " TZCNT/LZCNT are F3 + BSF/BSR exactly because the F2 and
   F3 prefixes have historically been no-ops with most instructions.
   This allows software to unconditionally use the prefixed versions
   and get TZCNT/LZCNT on the processors that have them if they don't
   care about the difference. "

This fixes errors reported by test_get_len:

  Warning: arch/x86/tools/test_get_len found difference at <em_bsf>:ffffffff81036d87
  Warning: ffffffff81036de5:	66 0f bc c2          	bsf    %dx,%ax
  Warning: objdump says 4 bytes, but insn_get_length() says 3
  Warning: arch/x86/tools/test_get_len found difference at <em_bsr>:ffffffff81036ea6
  Warning: ffffffff81036f04:	66 0f bd c2          	bsr    %dx,%ax
  Warning: objdump says 4 bytes, but insn_get_length() says 3
  Warning: decoded and checked 13298882 instructions with 2 warnings
Reported-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Reported-by: default avatarPekka Enberg <penberg@kernel.org>
Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: <yrl.pp-manager.tt@hitachi.com>
Link: http://lkml.kernel.org/r/20120604150911.22338.43296.stgit@localhost.localdomainSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 02e03040
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
# - (66): the last prefix is 0x66 # - (66): the last prefix is 0x66
# - (F3): the last prefix is 0xF3 # - (F3): the last prefix is 0xF3
# - (F2): the last prefix is 0xF2 # - (F2): the last prefix is 0xF2
# # - (!F3) : the last prefix is not 0xF3 (including non-last prefix case)
Table: one byte opcode Table: one byte opcode
Referrer: Referrer:
...@@ -515,12 +515,12 @@ b4: LFS Gv,Mp ...@@ -515,12 +515,12 @@ b4: LFS Gv,Mp
b5: LGS Gv,Mp b5: LGS Gv,Mp
b6: MOVZX Gv,Eb b6: MOVZX Gv,Eb
b7: MOVZX Gv,Ew b7: MOVZX Gv,Ew
b8: JMPE | POPCNT Gv,Ev (F3) b8: JMPE (!F3) | POPCNT Gv,Ev (F3)
b9: Grp10 (1A) b9: Grp10 (1A)
ba: Grp8 Ev,Ib (1A) ba: Grp8 Ev,Ib (1A)
bb: BTC Ev,Gv bb: BTC Ev,Gv
bc: BSF Gv,Ev | TZCNT Gv,Ev (F3) bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3)
bd: BSR Gv,Ev | LZCNT Gv,Ev (F3) bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3)
be: MOVSX Gv,Eb be: MOVSX Gv,Eb
bf: MOVSX Gv,Ew bf: MOVSX Gv,Ew
# 0x0f 0xc0-0xcf # 0x0f 0xc0-0xcf
......
...@@ -66,9 +66,10 @@ BEGIN { ...@@ -66,9 +66,10 @@ BEGIN {
rex_expr = "^REX(\\.[XRWB]+)*" rex_expr = "^REX(\\.[XRWB]+)*"
fpu_expr = "^ESC" # TODO fpu_expr = "^ESC" # TODO
lprefix1_expr = "\\(66\\)" lprefix1_expr = "\\((66|!F3)\\)"
lprefix2_expr = "\\(F3\\)" lprefix2_expr = "\\(F3\\)"
lprefix3_expr = "\\(F2\\)" lprefix3_expr = "\\((F2|!F3)\\)"
lprefix_expr = "\\((66|F2|F3)\\)"
max_lprefix = 4 max_lprefix = 4
# All opcodes starting with lower-case 'v' or with (v1) superscript # All opcodes starting with lower-case 'v' or with (v1) superscript
...@@ -333,13 +334,16 @@ function convert_operands(count,opnd, i,j,imm,mod) ...@@ -333,13 +334,16 @@ function convert_operands(count,opnd, i,j,imm,mod)
if (match(ext, lprefix1_expr)) { if (match(ext, lprefix1_expr)) {
lptable1[idx] = add_flags(lptable1[idx],flags) lptable1[idx] = add_flags(lptable1[idx],flags)
variant = "INAT_VARIANT" variant = "INAT_VARIANT"
} else if (match(ext, lprefix2_expr)) { }
if (match(ext, lprefix2_expr)) {
lptable2[idx] = add_flags(lptable2[idx],flags) lptable2[idx] = add_flags(lptable2[idx],flags)
variant = "INAT_VARIANT" variant = "INAT_VARIANT"
} else if (match(ext, lprefix3_expr)) { }
if (match(ext, lprefix3_expr)) {
lptable3[idx] = add_flags(lptable3[idx],flags) lptable3[idx] = add_flags(lptable3[idx],flags)
variant = "INAT_VARIANT" variant = "INAT_VARIANT"
} else { }
if (!match(ext, lprefix_expr)){
table[idx] = add_flags(table[idx],flags) table[idx] = add_flags(table[idx],flags)
} }
} }
......
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