aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/tools
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/tools
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/tools')
-rw-r--r--arch/x86/tools/gen-insn-attr-x86.awk314
1 files changed, 314 insertions, 0 deletions
diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk
new file mode 100644
index 000000000000..93b62c92d044
--- /dev/null
+++ b/arch/x86/tools/gen-insn-attr-x86.awk
@@ -0,0 +1,314 @@
1#!/bin/awk -f
2# gen-insn-attr-x86.awk: Instruction attribute table generator
3# Written by Masami Hiramatsu <mhiramat@redhat.com>
4#
5# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
6
7BEGIN {
8 print "/* x86 opcode map generated from x86-opcode-map.txt */"
9 print "/* Do not change this code. */"
10 ggid = 1
11 geid = 1
12
13 opnd_expr = "^[[:alpha:]]"
14 ext_expr = "^\\("
15 sep_expr = "^\\|$"
16 group_expr = "^Grp[[:alnum:]]+"
17
18 imm_expr = "^[IJAO][[:lower:]]"
19 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
20 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
21 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
22 imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
23 imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
24 imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
25 imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
26 imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
27 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
28 imm_flag["Ob"] = "INAT_MOFFSET"
29 imm_flag["Ov"] = "INAT_MOFFSET"
30
31 modrm_expr = "^([CDEGMNPQRSUVW][[:lower:]]+|NTA|T[012])"
32 force64_expr = "\\([df]64\\)"
33 rex_expr = "^REX(\\.[XRWB]+)*"
34 fpu_expr = "^ESC" # TODO
35
36 lprefix1_expr = "\\(66\\)"
37 delete lptable1
38 lprefix2_expr = "\\(F2\\)"
39 delete lptable2
40 lprefix3_expr = "\\(F3\\)"
41 delete lptable3
42 max_lprefix = 4
43
44 prefix_expr = "\\(Prefix\\)"
45 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
46 prefix_num["REPNE"] = "INAT_PFX_REPNE"
47 prefix_num["REP/REPE"] = "INAT_PFX_REPE"
48 prefix_num["LOCK"] = "INAT_PFX_LOCK"
49 prefix_num["SEG=CS"] = "INAT_PFX_CS"
50 prefix_num["SEG=DS"] = "INAT_PFX_DS"
51 prefix_num["SEG=ES"] = "INAT_PFX_ES"
52 prefix_num["SEG=FS"] = "INAT_PFX_FS"
53 prefix_num["SEG=GS"] = "INAT_PFX_GS"
54 prefix_num["SEG=SS"] = "INAT_PFX_SS"
55 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
56
57 delete table
58 delete etable
59 delete gtable
60 eid = -1
61 gid = -1
62}
63
64function semantic_error(msg) {
65 print "Semantic error at " NR ": " msg > "/dev/stderr"
66 exit 1
67}
68
69function debug(msg) {
70 print "DEBUG: " msg
71}
72
73function array_size(arr, i,c) {
74 c = 0
75 for (i in arr)
76 c++
77 return c
78}
79
80/^Table:/ {
81 print "/* " $0 " */"
82}
83
84/^Referrer:/ {
85 if (NF == 1) {
86 # primary opcode table
87 tname = "inat_primary_table"
88 eid = -1
89 } else {
90 # escape opcode table
91 ref = ""
92 for (i = 2; i <= NF; i++)
93 ref = ref $i
94 eid = escape[ref]
95 tname = sprintf("inat_escape_table_%d", eid)
96 }
97}
98
99/^GrpTable:/ {
100 print "/* " $0 " */"
101 if (!($2 in group))
102 semantic_error("No group: " $2 )
103 gid = group[$2]
104 tname = "inat_group_table_" gid
105}
106
107function print_table(tbl,name,fmt,n)
108{
109 print "const insn_attr_t " name " = {"
110 for (i = 0; i < n; i++) {
111 id = sprintf(fmt, i)
112 if (tbl[id])
113 print " [" id "] = " tbl[id] ","
114 }
115 print "};"
116}
117
118/^EndTable/ {
119 if (gid != -1) {
120 # print group tables
121 if (array_size(table) != 0) {
122 print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
123 "0x%x", 8)
124 gtable[gid,0] = tname
125 }
126 if (array_size(lptable1) != 0) {
127 print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
128 "0x%x", 8)
129 gtable[gid,1] = tname "_1"
130 }
131 if (array_size(lptable2) != 0) {
132 print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
133 "0x%x", 8)
134 gtable[gid,2] = tname "_2"
135 }
136 if (array_size(lptable3) != 0) {
137 print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
138 "0x%x", 8)
139 gtable[gid,3] = tname "_3"
140 }
141 } else {
142 # print primary/escaped tables
143 if (array_size(table) != 0) {
144 print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
145 "0x%02x", 256)
146 etable[eid,0] = tname
147 }
148 if (array_size(lptable1) != 0) {
149 print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
150 "0x%02x", 256)
151 etable[eid,1] = tname "_1"
152 }
153 if (array_size(lptable2) != 0) {
154 print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
155 "0x%02x", 256)
156 etable[eid,2] = tname "_2"
157 }
158 if (array_size(lptable3) != 0) {
159 print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
160 "0x%02x", 256)
161 etable[eid,3] = tname "_3"
162 }
163 }
164 print ""
165 delete table
166 delete lptable1
167 delete lptable2
168 delete lptable3
169 gid = -1
170 eid = -1
171}
172
173function add_flags(old,new) {
174 if (old && new)
175 return old " | " new
176 else if (old)
177 return old
178 else
179 return new
180}
181
182# convert operands to flags.
183function convert_operands(opnd, i,imm,mod)
184{
185 imm = null
186 mod = null
187 for (i in opnd) {
188 i = opnd[i]
189 if (match(i, imm_expr) == 1) {
190 if (!imm_flag[i])
191 semantic_error("Unknown imm opnd: " i)
192 if (imm) {
193 if (i != "Ib")
194 semantic_error("Second IMM error")
195 imm = add_flags(imm, "INAT_SCNDIMM")
196 } else
197 imm = imm_flag[i]
198 } else if (match(i, modrm_expr))
199 mod = "INAT_MODRM"
200 }
201 return add_flags(imm, mod)
202}
203
204/^[0-9a-f]+\:/ {
205 if (NR == 1)
206 next
207 # get index
208 idx = "0x" substr($1, 1, index($1,":") - 1)
209 if (idx in table)
210 semantic_error("Redefine " idx " in " tname)
211
212 # check if escaped opcode
213 if ("escape" == $2) {
214 if ($3 != "#")
215 semantic_error("No escaped name")
216 ref = ""
217 for (i = 4; i <= NF; i++)
218 ref = ref $i
219 if (ref in escape)
220 semantic_error("Redefine escape (" ref ")")
221 escape[ref] = geid
222 geid++
223 table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
224 next
225 }
226
227 variant = null
228 # converts
229 i = 2
230 while (i <= NF) {
231 opcode = $(i++)
232 delete opnds
233 ext = null
234 flags = null
235 opnd = null
236 # parse one opcode
237 if (match($i, opnd_expr)) {
238 opnd = $i
239 split($(i++), opnds, ",")
240 flags = convert_operands(opnds)
241 }
242 if (match($i, ext_expr))
243 ext = $(i++)
244 if (match($i, sep_expr))
245 i++
246 else if (i < NF)
247 semantic_error($i " is not a separator")
248
249 # check if group opcode
250 if (match(opcode, group_expr)) {
251 if (!(opcode in group)) {
252 group[opcode] = ggid
253 ggid++
254 }
255 flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
256 }
257 # check force(or default) 64bit
258 if (match(ext, force64_expr))
259 flags = add_flags(flags, "INAT_FORCE64")
260
261 # check REX prefix
262 if (match(opcode, rex_expr))
263 flags = add_flags(flags, "INAT_REXPFX")
264
265 # check coprocessor escape : TODO
266 if (match(opcode, fpu_expr))
267 flags = add_flags(flags, "INAT_MODRM")
268
269 # check prefixes
270 if (match(ext, prefix_expr)) {
271 if (!prefix_num[opcode])
272 semantic_error("Unknown prefix: " opcode)
273 flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
274 }
275 if (length(flags) == 0)
276 continue
277 # check if last prefix
278 if (match(ext, lprefix1_expr)) {
279 lptable1[idx] = add_flags(lptable1[idx],flags)
280 variant = "INAT_VARIANT"
281 } else if (match(ext, lprefix2_expr)) {
282 lptable2[idx] = add_flags(lptable2[idx],flags)
283 variant = "INAT_VARIANT"
284 } else if (match(ext, lprefix3_expr)) {
285 lptable3[idx] = add_flags(lptable3[idx],flags)
286 variant = "INAT_VARIANT"
287 } else {
288 table[idx] = add_flags(table[idx],flags)
289 }
290 }
291 if (variant)
292 table[idx] = add_flags(table[idx],variant)
293}
294
295END {
296 # print escape opcode map's array
297 print "/* Escape opcode map array */"
298 print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
299 "[INAT_LPREFIX_MAX + 1] = {"
300 for (i = 0; i < geid; i++)
301 for (j = 0; j < max_lprefix; j++)
302 if (etable[i,j])
303 print " ["i"]["j"] = "etable[i,j]","
304 print "};\n"
305 # print group opcode map's array
306 print "/* Group opcode map array */"
307 print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
308 "[INAT_LPREFIX_MAX + 1] = {"
309 for (i = 0; i < ggid; i++)
310 for (j = 0; j < max_lprefix; j++)
311 if (gtable[i,j])
312 print " ["i"]["j"] = "gtable[i,j]","
313 print "};"
314}