Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/awk -f
0002 # SPDX-License-Identifier: GPL-2.0
0003 # gen-insn-attr-x86.awk: Instruction attribute table generator
0004 # Written by Masami Hiramatsu <mhiramat@redhat.com>
0005 #
0006 # Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
0007 
0008 # Awk implementation sanity check
0009 function check_awk_implement() {
0010   if (sprintf("%x", 0) != "0")
0011     return "Your awk has a printf-format problem."
0012   return ""
0013 }
0014 
0015 # Clear working vars
0016 function clear_vars() {
0017   delete table
0018   delete lptable2
0019   delete lptable1
0020   delete lptable3
0021   eid = -1 # escape id
0022   gid = -1 # group id
0023   aid = -1 # AVX id
0024   tname = ""
0025 }
0026 
0027 BEGIN {
0028   # Implementation error checking
0029   awkchecked = check_awk_implement()
0030   if (awkchecked != "") {
0031     print "Error: " awkchecked > "/dev/stderr"
0032     print "Please try to use gawk." > "/dev/stderr"
0033     exit 1
0034   }
0035 
0036   # Setup generating tables
0037   print "/* x86 opcode map generated from x86-opcode-map.txt */"
0038   print "/* Do not change this code. */\n"
0039   ggid = 1
0040   geid = 1
0041   gaid = 0
0042   delete etable
0043   delete gtable
0044   delete atable
0045 
0046   opnd_expr = "^[A-Za-z/]"
0047   ext_expr = "^\\("
0048   sep_expr = "^\\|$"
0049   group_expr = "^Grp[0-9A-Za-z]+"
0050 
0051   imm_expr = "^[IJAOL][a-z]"
0052   imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
0053   imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
0054   imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
0055   imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
0056   imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
0057   imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
0058   imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
0059   imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
0060   imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
0061   imm_flag["Ob"] = "INAT_MOFFSET"
0062   imm_flag["Ov"] = "INAT_MOFFSET"
0063   imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
0064 
0065   modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
0066   force64_expr = "\\([df]64\\)"
0067   rex_expr = "^REX(\\.[XRWB]+)*"
0068   fpu_expr = "^ESC" # TODO
0069 
0070   lprefix1_expr = "\\((66|!F3)\\)"
0071   lprefix2_expr = "\\(F3\\)"
0072   lprefix3_expr = "\\((F2|!F3|66&F2)\\)"
0073   lprefix_expr = "\\((66|F2|F3)\\)"
0074   max_lprefix = 4
0075 
0076   # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript
0077   # accepts VEX prefix
0078   vexok_opcode_expr = "^[vk].*"
0079   vexok_expr = "\\(v1\\)"
0080   # All opcodes with (v) superscript supports *only* VEX prefix
0081   vexonly_expr = "\\(v\\)"
0082   # All opcodes with (ev) superscript supports *only* EVEX prefix
0083   evexonly_expr = "\\(ev\\)"
0084 
0085   prefix_expr = "\\(Prefix\\)"
0086   prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
0087   prefix_num["REPNE"] = "INAT_PFX_REPNE"
0088   prefix_num["REP/REPE"] = "INAT_PFX_REPE"
0089   prefix_num["XACQUIRE"] = "INAT_PFX_REPNE"
0090   prefix_num["XRELEASE"] = "INAT_PFX_REPE"
0091   prefix_num["LOCK"] = "INAT_PFX_LOCK"
0092   prefix_num["SEG=CS"] = "INAT_PFX_CS"
0093   prefix_num["SEG=DS"] = "INAT_PFX_DS"
0094   prefix_num["SEG=ES"] = "INAT_PFX_ES"
0095   prefix_num["SEG=FS"] = "INAT_PFX_FS"
0096   prefix_num["SEG=GS"] = "INAT_PFX_GS"
0097   prefix_num["SEG=SS"] = "INAT_PFX_SS"
0098   prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
0099   prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
0100   prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
0101   prefix_num["EVEX"] = "INAT_PFX_EVEX"
0102 
0103   clear_vars()
0104 }
0105 
0106 function semantic_error(msg) {
0107   print "Semantic error at " NR ": " msg > "/dev/stderr"
0108   exit 1
0109 }
0110 
0111 function debug(msg) {
0112   print "DEBUG: " msg
0113 }
0114 
0115 function array_size(arr,   i,c) {
0116   c = 0
0117   for (i in arr)
0118     c++
0119   return c
0120 }
0121 
0122 /^Table:/ {
0123   print "/* " $0 " */"
0124   if (tname != "")
0125     semantic_error("Hit Table: before EndTable:.");
0126 }
0127 
0128 /^Referrer:/ {
0129   if (NF != 1) {
0130     # escape opcode table
0131     ref = ""
0132     for (i = 2; i <= NF; i++)
0133       ref = ref $i
0134     eid = escape[ref]
0135     tname = sprintf("inat_escape_table_%d", eid)
0136   }
0137 }
0138 
0139 /^AVXcode:/ {
0140   if (NF != 1) {
0141     # AVX/escape opcode table
0142     aid = $2
0143     if (gaid <= aid)
0144       gaid = aid + 1
0145     if (tname == "")  # AVX only opcode table
0146       tname = sprintf("inat_avx_table_%d", $2)
0147   }
0148   if (aid == -1 && eid == -1) # primary opcode table
0149     tname = "inat_primary_table"
0150 }
0151 
0152 /^GrpTable:/ {
0153   print "/* " $0 " */"
0154   if (!($2 in group))
0155     semantic_error("No group: " $2 )
0156   gid = group[$2]
0157   tname = "inat_group_table_" gid
0158 }
0159 
0160 function print_table(tbl,name,fmt,n)
0161 {
0162   print "const insn_attr_t " name " = {"
0163   for (i = 0; i < n; i++) {
0164     id = sprintf(fmt, i)
0165     if (tbl[id])
0166       print " [" id "] = " tbl[id] ","
0167   }
0168   print "};"
0169 }
0170 
0171 /^EndTable/ {
0172   if (gid != -1) {
0173     # print group tables
0174     if (array_size(table) != 0) {
0175       print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
0176             "0x%x", 8)
0177       gtable[gid,0] = tname
0178     }
0179     if (array_size(lptable1) != 0) {
0180       print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
0181             "0x%x", 8)
0182       gtable[gid,1] = tname "_1"
0183     }
0184     if (array_size(lptable2) != 0) {
0185       print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
0186             "0x%x", 8)
0187       gtable[gid,2] = tname "_2"
0188     }
0189     if (array_size(lptable3) != 0) {
0190       print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
0191             "0x%x", 8)
0192       gtable[gid,3] = tname "_3"
0193     }
0194   } else {
0195     # print primary/escaped tables
0196     if (array_size(table) != 0) {
0197       print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
0198             "0x%02x", 256)
0199       etable[eid,0] = tname
0200       if (aid >= 0)
0201         atable[aid,0] = tname
0202     }
0203     if (array_size(lptable1) != 0) {
0204       print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
0205             "0x%02x", 256)
0206       etable[eid,1] = tname "_1"
0207       if (aid >= 0)
0208         atable[aid,1] = tname "_1"
0209     }
0210     if (array_size(lptable2) != 0) {
0211       print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
0212             "0x%02x", 256)
0213       etable[eid,2] = tname "_2"
0214       if (aid >= 0)
0215         atable[aid,2] = tname "_2"
0216     }
0217     if (array_size(lptable3) != 0) {
0218       print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
0219             "0x%02x", 256)
0220       etable[eid,3] = tname "_3"
0221       if (aid >= 0)
0222         atable[aid,3] = tname "_3"
0223     }
0224   }
0225   print ""
0226   clear_vars()
0227 }
0228 
0229 function add_flags(old,new) {
0230   if (old && new)
0231     return old " | " new
0232   else if (old)
0233     return old
0234   else
0235     return new
0236 }
0237 
0238 # convert operands to flags.
0239 function convert_operands(count,opnd,       i,j,imm,mod)
0240 {
0241   imm = null
0242   mod = null
0243   for (j = 1; j <= count; j++) {
0244     i = opnd[j]
0245     if (match(i, imm_expr) == 1) {
0246       if (!imm_flag[i])
0247         semantic_error("Unknown imm opnd: " i)
0248       if (imm) {
0249         if (i != "Ib")
0250           semantic_error("Second IMM error")
0251         imm = add_flags(imm, "INAT_SCNDIMM")
0252       } else
0253         imm = imm_flag[i]
0254     } else if (match(i, modrm_expr))
0255       mod = "INAT_MODRM"
0256   }
0257   return add_flags(imm, mod)
0258 }
0259 
0260 /^[0-9a-f]+:/ {
0261   if (NR == 1)
0262     next
0263   # get index
0264   idx = "0x" substr($1, 1, index($1,":") - 1)
0265   if (idx in table)
0266     semantic_error("Redefine " idx " in " tname)
0267 
0268   # check if escaped opcode
0269   if ("escape" == $2) {
0270     if ($3 != "#")
0271       semantic_error("No escaped name")
0272     ref = ""
0273     for (i = 4; i <= NF; i++)
0274       ref = ref $i
0275     if (ref in escape)
0276       semantic_error("Redefine escape (" ref ")")
0277     escape[ref] = geid
0278     geid++
0279     table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
0280     next
0281   }
0282 
0283   variant = null
0284   # converts
0285   i = 2
0286   while (i <= NF) {
0287     opcode = $(i++)
0288     delete opnds
0289     ext = null
0290     flags = null
0291     opnd = null
0292     # parse one opcode
0293     if (match($i, opnd_expr)) {
0294       opnd = $i
0295       count = split($(i++), opnds, ",")
0296       flags = convert_operands(count, opnds)
0297     }
0298     if (match($i, ext_expr))
0299       ext = $(i++)
0300     if (match($i, sep_expr))
0301       i++
0302     else if (i < NF)
0303       semantic_error($i " is not a separator")
0304 
0305     # check if group opcode
0306     if (match(opcode, group_expr)) {
0307       if (!(opcode in group)) {
0308         group[opcode] = ggid
0309         ggid++
0310       }
0311       flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
0312     }
0313     # check force(or default) 64bit
0314     if (match(ext, force64_expr))
0315       flags = add_flags(flags, "INAT_FORCE64")
0316 
0317     # check REX prefix
0318     if (match(opcode, rex_expr))
0319       flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
0320 
0321     # check coprocessor escape : TODO
0322     if (match(opcode, fpu_expr))
0323       flags = add_flags(flags, "INAT_MODRM")
0324 
0325     # check VEX codes
0326     if (match(ext, evexonly_expr))
0327       flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
0328     else if (match(ext, vexonly_expr))
0329       flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
0330     else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
0331       flags = add_flags(flags, "INAT_VEXOK")
0332 
0333     # check prefixes
0334     if (match(ext, prefix_expr)) {
0335       if (!prefix_num[opcode])
0336         semantic_error("Unknown prefix: " opcode)
0337       flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
0338     }
0339     if (length(flags) == 0)
0340       continue
0341     # check if last prefix
0342     if (match(ext, lprefix1_expr)) {
0343       lptable1[idx] = add_flags(lptable1[idx],flags)
0344       variant = "INAT_VARIANT"
0345     }
0346     if (match(ext, lprefix2_expr)) {
0347       lptable2[idx] = add_flags(lptable2[idx],flags)
0348       variant = "INAT_VARIANT"
0349     }
0350     if (match(ext, lprefix3_expr)) {
0351       lptable3[idx] = add_flags(lptable3[idx],flags)
0352       variant = "INAT_VARIANT"
0353     }
0354     if (!match(ext, lprefix_expr)){
0355       table[idx] = add_flags(table[idx],flags)
0356     }
0357   }
0358   if (variant)
0359     table[idx] = add_flags(table[idx],variant)
0360 }
0361 
0362 END {
0363   if (awkchecked != "")
0364     exit 1
0365 
0366   print "#ifndef __BOOT_COMPRESSED\n"
0367 
0368   # print escape opcode map's array
0369   print "/* Escape opcode map array */"
0370   print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \
0371         "[INAT_LSTPFX_MAX + 1] = {"
0372   for (i = 0; i < geid; i++)
0373     for (j = 0; j < max_lprefix; j++)
0374       if (etable[i,j])
0375         print " ["i"]["j"] = "etable[i,j]","
0376   print "};\n"
0377   # print group opcode map's array
0378   print "/* Group opcode map array */"
0379   print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\
0380         "[INAT_LSTPFX_MAX + 1] = {"
0381   for (i = 0; i < ggid; i++)
0382     for (j = 0; j < max_lprefix; j++)
0383       if (gtable[i,j])
0384         print " ["i"]["j"] = "gtable[i,j]","
0385   print "};\n"
0386   # print AVX opcode map's array
0387   print "/* AVX opcode map array */"
0388   print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\
0389         "[INAT_LSTPFX_MAX + 1] = {"
0390   for (i = 0; i < gaid; i++)
0391     for (j = 0; j < max_lprefix; j++)
0392       if (atable[i,j])
0393         print " ["i"]["j"] = "atable[i,j]","
0394   print "};\n"
0395 
0396   print "#else /* !__BOOT_COMPRESSED */\n"
0397 
0398   print "/* Escape opcode map array */"
0399   print "static const insn_attr_t *inat_escape_tables[INAT_ESC_MAX + 1]" \
0400         "[INAT_LSTPFX_MAX + 1];"
0401   print ""
0402 
0403   print "/* Group opcode map array */"
0404   print "static const insn_attr_t *inat_group_tables[INAT_GRP_MAX + 1]"\
0405         "[INAT_LSTPFX_MAX + 1];"
0406   print ""
0407 
0408   print "/* AVX opcode map array */"
0409   print "static const insn_attr_t *inat_avx_tables[X86_VEX_M_MAX + 1]"\
0410         "[INAT_LSTPFX_MAX + 1];"
0411   print ""
0412 
0413   print "static void inat_init_tables(void)"
0414   print "{"
0415 
0416   # print escape opcode map's array
0417   print "\t/* Print Escape opcode map array */"
0418   for (i = 0; i < geid; i++)
0419     for (j = 0; j < max_lprefix; j++)
0420       if (etable[i,j])
0421         print "\tinat_escape_tables["i"]["j"] = "etable[i,j]";"
0422   print ""
0423 
0424   # print group opcode map's array
0425   print "\t/* Print Group opcode map array */"
0426   for (i = 0; i < ggid; i++)
0427     for (j = 0; j < max_lprefix; j++)
0428       if (gtable[i,j])
0429         print "\tinat_group_tables["i"]["j"] = "gtable[i,j]";"
0430   print ""
0431   # print AVX opcode map's array
0432   print "\t/* Print AVX opcode map array */"
0433   for (i = 0; i < gaid; i++)
0434     for (j = 0; j < max_lprefix; j++)
0435       if (atable[i,j])
0436         print "\tinat_avx_tables["i"]["j"] = "atable[i,j]";"
0437 
0438   print "}"
0439   print "#endif"
0440 }
0441