aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/insn.h
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2009-08-13 16:34:13 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-08-26 18:35:56 -0400
commiteb13296cfaf6c699566473669a96a38a90562384 (patch)
tree466c44bf0a747effaf85ec13dbf75ae857449bfd /arch/x86/include/asm/insn.h
parent35dce1a99d010f3d738af4ce1b9b77302fdfe69c (diff)
x86: Instruction decoder API
Add x86 instruction decoder to arch-specific libraries. This decoder can decode x86 instructions used in kernel into prefix, opcode, modrm, sib, displacement and immediates. This can also show the length of instructions. This version introduces instruction attributes for decoding instructions. The instruction attribute tables are generated from the opcode map file (x86-opcode-map.txt) by the generator script(gen-insn-attr-x86.awk). Currently, the opcode maps are based on opcode maps in Intel(R) 64 and IA-32 Architectures Software Developers Manual Vol.2: Appendix.A, and consist of below two types of opcode tables. 1-byte/2-bytes/3-bytes opcodes, which has 256 elements, are written as below; Table: table-name Referrer: escaped-name opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] (or) opcode: escape # escaped-name EndTable Group opcodes, which has 8 elements, are written as below; GrpTable: GrpXXX reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] EndTable These opcode maps include a few SSE and FP opcodes (for setup), because those opcodes are used in the kernel. Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Signed-off-by: Jim Keniston <jkenisto@us.ibm.com> Acked-by: H. Peter Anvin <hpa@zytor.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Avi Kivity <avi@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Frank Ch. Eigler <fche@redhat.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Jason Baron <jbaron@redhat.com> Cc: K.Prasad <prasad@linux.vnet.ibm.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Przemysław Pawełczyk <przemyslaw@pawelczyk.it> Cc: Roland McGrath <roland@redhat.com> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Vegard Nossum <vegard.nossum@gmail.com> LKML-Reference: <20090813203413.31965.49709.stgit@localhost.localdomain> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Diffstat (limited to 'arch/x86/include/asm/insn.h')
-rw-r--r--arch/x86/include/asm/insn.h143
1 files changed, 143 insertions, 0 deletions
diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
new file mode 100644
index 000000000000..12b4e3751d3f
--- /dev/null
+++ b/arch/x86/include/asm/insn.h
@@ -0,0 +1,143 @@
1#ifndef _ASM_X86_INSN_H
2#define _ASM_X86_INSN_H
3/*
4 * x86 instruction analysis
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Copyright (C) IBM Corporation, 2009
21 */
22
23/* insn_attr_t is defined in inat.h */
24#include <asm/inat.h>
25
26struct insn_field {
27 union {
28 insn_value_t value;
29 insn_byte_t bytes[4];
30 };
31 /* !0 if we've run insn_get_xxx() for this field */
32 unsigned char got;
33 unsigned char nbytes;
34};
35
36struct insn {
37 struct insn_field prefixes; /*
38 * Prefixes
39 * prefixes.bytes[3]: last prefix
40 */
41 struct insn_field rex_prefix; /* REX prefix */
42 struct insn_field opcode; /*
43 * opcode.bytes[0]: opcode1
44 * opcode.bytes[1]: opcode2
45 * opcode.bytes[2]: opcode3
46 */
47 struct insn_field modrm;
48 struct insn_field sib;
49 struct insn_field displacement;
50 union {
51 struct insn_field immediate;
52 struct insn_field moffset1; /* for 64bit MOV */
53 struct insn_field immediate1; /* for 64bit imm or off16/32 */
54 };
55 union {
56 struct insn_field moffset2; /* for 64bit MOV */
57 struct insn_field immediate2; /* for 64bit imm or seg16 */
58 };
59
60 insn_attr_t attr;
61 unsigned char opnd_bytes;
62 unsigned char addr_bytes;
63 unsigned char length;
64 unsigned char x86_64;
65
66 const insn_byte_t *kaddr; /* kernel address of insn to analyze */
67 const insn_byte_t *next_byte;
68};
69
70#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6)
71#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3)
72#define X86_MODRM_RM(modrm) ((modrm) & 0x07)
73
74#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6)
75#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
76#define X86_SIB_BASE(sib) ((sib) & 0x07)
77
78#define X86_REX_W(rex) ((rex) & 8)
79#define X86_REX_R(rex) ((rex) & 4)
80#define X86_REX_X(rex) ((rex) & 2)
81#define X86_REX_B(rex) ((rex) & 1)
82
83/* The last prefix is needed for two-byte and three-byte opcodes */
84static inline insn_byte_t insn_last_prefix(struct insn *insn)
85{
86 return insn->prefixes.bytes[3];
87}
88
89extern void insn_init(struct insn *insn, const void *kaddr, int x86_64);
90extern void insn_get_prefixes(struct insn *insn);
91extern void insn_get_opcode(struct insn *insn);
92extern void insn_get_modrm(struct insn *insn);
93extern void insn_get_sib(struct insn *insn);
94extern void insn_get_displacement(struct insn *insn);
95extern void insn_get_immediate(struct insn *insn);
96extern void insn_get_length(struct insn *insn);
97
98/* Attribute will be determined after getting ModRM (for opcode groups) */
99static inline void insn_get_attribute(struct insn *insn)
100{
101 insn_get_modrm(insn);
102}
103
104/* Instruction uses RIP-relative addressing */
105extern int insn_rip_relative(struct insn *insn);
106
107/* Init insn for kernel text */
108static inline void kernel_insn_init(struct insn *insn, const void *kaddr)
109{
110#ifdef CONFIG_X86_64
111 insn_init(insn, kaddr, 1);
112#else /* CONFIG_X86_32 */
113 insn_init(insn, kaddr, 0);
114#endif
115}
116
117/* Offset of each field from kaddr */
118static inline int insn_offset_rex_prefix(struct insn *insn)
119{
120 return insn->prefixes.nbytes;
121}
122static inline int insn_offset_opcode(struct insn *insn)
123{
124 return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
125}
126static inline int insn_offset_modrm(struct insn *insn)
127{
128 return insn_offset_opcode(insn) + insn->opcode.nbytes;
129}
130static inline int insn_offset_sib(struct insn *insn)
131{
132 return insn_offset_modrm(insn) + insn->modrm.nbytes;
133}
134static inline int insn_offset_displacement(struct insn *insn)
135{
136 return insn_offset_sib(insn) + insn->sib.nbytes;
137}
138static inline int insn_offset_immediate(struct insn *insn)
139{
140 return insn_offset_displacement(insn) + insn->displacement.nbytes;
141}
142
143#endif /* _ASM_X86_INSN_H */