Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2015 Cisco and/or its affiliates. |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at: |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
| 14 | */ |
| 15 | /* FIXME |
| 16 | opcode name remove to save table space; enum |
| 17 | x87 |
| 18 | 3dnow |
| 19 | cbw naming |
| 20 | */ |
| 21 | |
| 22 | #include <vppinfra/error.h> |
| 23 | #include <vppinfra/byte_order.h> |
| 24 | #include <vppinfra/asm_x86.h> |
| 25 | |
| 26 | #define foreach_x86_gp_register \ |
| 27 | _ (AX) _ (CX) _ (DX) _ (BX) \ |
| 28 | _ (SP) _ (BP) _ (SI) _ (DI) |
| 29 | |
| 30 | typedef enum { |
| 31 | #define _(r) X86_INSN_GP_REG_##r, |
| 32 | foreach_x86_gp_register |
| 33 | #undef _ |
| 34 | } x86_insn_gp_register_t; |
| 35 | |
| 36 | typedef union { |
| 37 | struct { |
| 38 | u8 rm : 3; |
| 39 | u8 reg : 3; |
| 40 | u8 mode : 2; |
| 41 | }; |
| 42 | u8 byte; |
| 43 | } x86_insn_modrm_byte_t; |
| 44 | |
| 45 | typedef union { |
| 46 | struct { |
| 47 | u8 base : 3; |
| 48 | u8 index : 3; |
| 49 | u8 log2_scale : 2; |
| 50 | }; |
| 51 | u8 byte; |
| 52 | } x86_insn_sib_byte_t; |
| 53 | |
| 54 | always_inline uword |
| 55 | x86_insn_has_modrm_byte (x86_insn_t * insn) |
| 56 | { |
| 57 | int i; |
| 58 | for (i = 0; i < ARRAY_LEN (insn->operands); i++) |
| 59 | switch (insn->operands[i].code) |
| 60 | { |
| 61 | case 'G': case 'E': case 'M': case 'R': |
| 62 | return 1; |
| 63 | } |
| 64 | return 0; |
| 65 | } |
| 66 | |
| 67 | always_inline uword |
| 68 | x86_insn_immediate_type (x86_insn_t * insn) |
| 69 | { |
| 70 | int i; |
| 71 | for (i = 0; i < ARRAY_LEN (insn->operands); i++) |
| 72 | switch (insn->operands[i].code) |
| 73 | { |
| 74 | case 'J': |
| 75 | case 'I': |
| 76 | case 'O': |
| 77 | return insn->operands[i].type; |
| 78 | } |
| 79 | return 0; |
| 80 | } |
| 81 | |
| 82 | /* Opcode extension in modrm byte reg field. */ |
| 83 | #define foreach_x86_insn_modrm_reg_group \ |
| 84 | _ (1) _ (1a) _ (2) _ (3) _ (4) _ (5) _ (6) _ (7) \ |
| 85 | _ (8) _ (9) _ (10) _ (11) _ (12) _ (13) _ (14) \ |
| 86 | _ (15) _ (16) _ (p) |
| 87 | |
| 88 | #define foreach_x86_insn_sse_group \ |
| 89 | _ (10) _ (28) _ (50) _ (58) _ (60) _ (68) _ (70) _ (78) \ |
| 90 | _ (c0) _ (d0) _ (d8) _ (e0) _ (e8) _ (f0) _ (f8) |
| 91 | |
| 92 | enum { |
| 93 | #define _(x) X86_INSN_MODRM_REG_GROUP_##x, |
| 94 | foreach_x86_insn_modrm_reg_group |
| 95 | #undef _ |
| 96 | #define _(x) X86_INSN_SSE_GROUP_##x, |
| 97 | foreach_x86_insn_sse_group |
| 98 | #undef _ |
| 99 | }; |
| 100 | |
| 101 | enum { |
| 102 | #define _(x) \ |
| 103 | X86_INSN_FLAG_MODRM_REG_GROUP_##x \ |
| 104 | = X86_INSN_FLAG_SET_MODRM_REG_GROUP (1 + X86_INSN_MODRM_REG_GROUP_##x), |
| 105 | foreach_x86_insn_modrm_reg_group |
| 106 | #undef _ |
| 107 | |
| 108 | #define _(x) \ |
| 109 | X86_INSN_FLAG_SSE_GROUP_##x \ |
| 110 | = X86_INSN_FLAG_SET_SSE_GROUP (1 + X86_INSN_SSE_GROUP_##x), |
| 111 | foreach_x86_insn_sse_group |
| 112 | #undef _ |
| 113 | }; |
| 114 | |
| 115 | #define foreach_x86_gp_reg \ |
| 116 | _ (AX) _ (CX) _ (DX) _ (BX) \ |
| 117 | _ (SP) _ (BP) _ (SI) _ (DI) |
| 118 | |
| 119 | #define foreach_x86_condition \ |
| 120 | _ (o) _ (no) _ (b) _ (nb) \ |
| 121 | _ (z) _ (nz) _ (be) _ (nbe) \ |
| 122 | _ (s) _ (ns) _ (p) _ (np) \ |
| 123 | _ (l) _ (nl) _ (le) _ (nle) |
| 124 | |
| 125 | #define _3f(x,f,o0,o1,o2) \ |
| 126 | { \ |
| 127 | .name = #x, \ |
| 128 | .flags = (f), \ |
| 129 | .operands[0] = { .data = #o0 }, \ |
| 130 | .operands[1] = { .data = #o1 }, \ |
| 131 | .operands[2] = { .data = #o2 }, \ |
| 132 | } |
| 133 | |
| 134 | #define _2f(x,f,o0,o1) _3f(x,f,o0,o1,__) |
| 135 | #define _1f(x,f,o0) _2f(x,f,o0,__) |
| 136 | #define _0f(x,f) _1f(x,f,__) |
| 137 | |
| 138 | #define _3(x,o0,o1,o2) _3f(x,0,o0,o1,o2) |
| 139 | #define _2(x,o0,o1) _2f(x,0,o0,o1) |
| 140 | #define _1(x,o0) _1f(x,0,o0) |
| 141 | #define _0(x) _0f(x,0) |
| 142 | |
| 143 | static x86_insn_t x86_insns_one_byte[256] = { |
| 144 | |
| 145 | #define _(x) \ |
| 146 | _2 (x, Eb, Gb), \ |
| 147 | _2 (x, Ev, Gv), \ |
| 148 | _2 (x, Gb, Eb), \ |
| 149 | _2 (x, Gv, Ev), \ |
| 150 | _2 (x, AL, Ib), \ |
| 151 | _2 (x, AX, Iz) |
| 152 | |
| 153 | /* 0x00 */ |
| 154 | _ (add), |
| 155 | _0 (push_es), |
| 156 | _0 (pop_es), |
| 157 | _ (or), |
| 158 | _0 (push_cs), |
| 159 | _0 (escape_two_byte), |
| 160 | |
| 161 | /* 0x10 */ |
| 162 | _ (adc), |
| 163 | _0 (push_ss), |
| 164 | _0 (pop_ss), |
| 165 | _ (sbb), |
| 166 | _0 (push_ds), |
| 167 | _0 (pop_ds), |
| 168 | |
| 169 | /* 0x20 */ |
| 170 | _ (and), |
| 171 | _0 (segment_es), |
| 172 | _0 (daa), |
| 173 | _ (sub), |
| 174 | _0 (segment_cs), |
| 175 | _0 (das), |
| 176 | |
| 177 | /* 0x30 */ |
| 178 | _ (xor), |
| 179 | _0 (segment_ss), |
| 180 | _0 (aaa), |
| 181 | _ (cmp), |
| 182 | _0 (segment_ds), |
| 183 | _0 (aas), |
| 184 | |
| 185 | #undef _ |
| 186 | |
| 187 | /* 0x40 */ |
| 188 | #define _(r) _1 (inc, r), |
| 189 | foreach_x86_gp_reg |
| 190 | #undef _ |
| 191 | #define _(r) _1 (dec, r), |
| 192 | foreach_x86_gp_reg |
| 193 | #undef _ |
| 194 | |
| 195 | /* 0x50 */ |
| 196 | #define _(r) _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, r), |
| 197 | foreach_x86_gp_reg |
| 198 | #undef _ |
| 199 | #define _(r) _1f (pop, X86_INSN_FLAG_DEFAULT_64_BIT, r), |
| 200 | foreach_x86_gp_reg |
| 201 | #undef _ |
| 202 | |
| 203 | /* 0x60 */ |
| 204 | _0 (pusha), |
| 205 | _0 (popa), |
| 206 | _2 (bound, Gv, Ma), |
| 207 | _2 (movsxd, Gv, Ed), |
| 208 | _0 (segment_fs), |
| 209 | _0 (segment_gs), |
| 210 | _0 (operand_type), |
| 211 | _0 (address_size), |
| 212 | _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, Iz), |
| 213 | _3 (imul, Gv, Ev, Iz), |
| 214 | _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, Ib), |
| 215 | _3 (imul, Gv, Ev, Ib), |
| 216 | _1 (insb, DX), |
| 217 | _1 (insw, DX), |
| 218 | _1 (outsb, DX), |
| 219 | _1 (outsw, DX), |
| 220 | |
| 221 | /* 0x70 */ |
| 222 | #define _(x) _1 (j##x, Jb), |
| 223 | foreach_x86_condition |
| 224 | #undef _ |
| 225 | |
| 226 | /* 0x80 */ |
| 227 | _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Eb, Ib), |
| 228 | _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Ev, Iz), |
| 229 | _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Eb, Ib), |
| 230 | _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Ev, Ib), |
| 231 | _2 (test, Eb, Gb), |
| 232 | _2 (test, Ev, Gv), |
| 233 | _2 (xchg, Eb, Gb), |
| 234 | _2 (xchg, Ev, Gv), |
| 235 | _2 (mov, Eb, Gb), |
| 236 | _2 (mov, Ev, Gv), |
| 237 | _2 (mov, Gb, Eb), |
| 238 | _2 (mov, Gv, Ev), |
| 239 | _2 (mov, Ev, Sw), |
| 240 | _2 (lea, Gv, Ev), |
| 241 | _2 (mov, Sw, Ew), |
| 242 | _1f (modrm_group_1a, X86_INSN_FLAG_MODRM_REG_GROUP_1a, Ev), |
| 243 | |
| 244 | /* 0x90 */ |
| 245 | _0 (nop), |
| 246 | _1 (xchg, CX), |
| 247 | _1 (xchg, DX), |
| 248 | _1 (xchg, BX), |
| 249 | _1 (xchg, SP), |
| 250 | _1 (xchg, BP), |
| 251 | _1 (xchg, SI), |
| 252 | _1 (xchg, DI), |
| 253 | _0 (cbw), |
| 254 | _0 (cwd), |
| 255 | _1 (call, Ap), |
| 256 | _0 (wait), |
| 257 | _0 (pushf), |
| 258 | _0 (popf), |
| 259 | _0 (sahf), |
| 260 | _0 (lahf), |
| 261 | |
| 262 | /* 0xa0 */ |
| 263 | _2 (mov, AL, Ob), |
| 264 | _2 (mov, AX, Ov), |
| 265 | _2 (mov, Ob, AL), |
| 266 | _2 (mov, Ov, AX), |
| 267 | _0 (movsb), |
| 268 | _0 (movsw), |
| 269 | _0 (cmpsb), |
| 270 | _0 (cmpsw), |
| 271 | _2 (test, AL, Ib), |
| 272 | _2 (test, AX, Iz), |
| 273 | _1 (stosb, AL), |
| 274 | _1 (stosw, AX), |
| 275 | _1 (lodsb, AL), |
| 276 | _1 (lodsw, AX), |
| 277 | _1 (scasb, AL), |
| 278 | _1 (scasw, AX), |
| 279 | |
| 280 | /* 0xb0 */ |
| 281 | _2 (mov, AL, Ib), |
| 282 | _2 (mov, CL, Ib), |
| 283 | _2 (mov, DL, Ib), |
| 284 | _2 (mov, BL, Ib), |
| 285 | _2 (mov, AH, Ib), |
| 286 | _2 (mov, CH, Ib), |
| 287 | _2 (mov, DH, Ib), |
| 288 | _2 (mov, BH, Ib), |
| 289 | #define _(r) _2 (mov, r, Iv), |
| 290 | foreach_x86_gp_reg |
| 291 | #undef _ |
| 292 | |
| 293 | /* 0xc0 */ |
| 294 | _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, Ib), |
| 295 | _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, Ib), |
| 296 | _1 (ret, Iw), |
| 297 | _0 (ret), |
| 298 | _2 (les, Gz, Mp), |
| 299 | _2 (lds, Gz, Mp), |
| 300 | _2f (modrm_group_11, X86_INSN_FLAG_MODRM_REG_GROUP_11, Eb, Ib), |
| 301 | _2f (modrm_group_11, X86_INSN_FLAG_MODRM_REG_GROUP_11, Ev, Iz), |
| 302 | _2 (enter, Iw, Ib), |
| 303 | _0 (leave), |
| 304 | _1 (ret, Iw), |
| 305 | _0 (ret), |
| 306 | _0 (int3), |
| 307 | _1 (int, Ib), |
| 308 | _0 (into), |
| 309 | _0 (iret), |
| 310 | |
| 311 | /* 0xd0 */ |
| 312 | _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, 1b), |
| 313 | _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, 1b), |
| 314 | _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, CL), |
| 315 | _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, CL), |
| 316 | _0 (aam), |
| 317 | _0 (aad), |
| 318 | _0 (salc), |
| 319 | _0 (xlat), |
| 320 | /* FIXME x87 */ |
| 321 | _0 (bad), |
| 322 | _0 (bad), |
| 323 | _0 (bad), |
| 324 | _0 (bad), |
| 325 | _0 (bad), |
| 326 | _0 (bad), |
| 327 | _0 (bad), |
| 328 | _0 (bad), |
| 329 | |
| 330 | /* 0xe0 */ |
| 331 | _1 (loopnz, Jb), |
| 332 | _1 (loopz, Jb), |
| 333 | _1 (loop, Jb), |
| 334 | _1 (jcxz, Jb), |
| 335 | _2 (in, AL, Ib), |
| 336 | _2 (in, AX, Ib), |
| 337 | _2 (out, Ib, AL), |
| 338 | _2 (out, Ib, AX), |
| 339 | _1f (call, X86_INSN_FLAG_DEFAULT_64_BIT, Jz), |
| 340 | _1f ( jmp, X86_INSN_FLAG_DEFAULT_64_BIT, Jz), |
| 341 | _1 (jmp, Ap), |
| 342 | _1 (jmp, Jb), |
| 343 | _2 (in, AL, DX), |
| 344 | _2 (in, AX, DX), |
| 345 | _2 (out, DX, AL), |
| 346 | _2 (out, DX, AX), |
| 347 | |
| 348 | /* 0xf0 */ |
| 349 | _0 (lock), |
| 350 | _0 (int1), |
| 351 | _0 (repne), |
| 352 | _0 (rep), |
| 353 | _0 (hlt), |
| 354 | _0 (cmc), |
| 355 | _0f (modrm_group_3, X86_INSN_FLAG_MODRM_REG_GROUP_3), |
| 356 | _0f (modrm_group_3, X86_INSN_FLAG_MODRM_REG_GROUP_3), |
| 357 | _0 (clc), |
| 358 | _0 (stc), |
| 359 | _0 (cli), |
| 360 | _0 (sti), |
| 361 | _0 (cld), |
| 362 | _0 (std), |
| 363 | _1f (modrm_group_4, X86_INSN_FLAG_MODRM_REG_GROUP_4, Eb), |
| 364 | _0f (modrm_group_5, X86_INSN_FLAG_MODRM_REG_GROUP_5), |
| 365 | }; |
| 366 | |
| 367 | static x86_insn_t x86_insns_two_byte[256] = { |
| 368 | /* 0x00 */ |
| 369 | _0f (modrm_group_6, X86_INSN_FLAG_MODRM_REG_GROUP_6), |
| 370 | _0f (modrm_group_7, X86_INSN_FLAG_MODRM_REG_GROUP_7), |
| 371 | _2 (lar, Gv, Ew), |
| 372 | _2 (lsl, Gv, Ew), |
| 373 | _0 (bad), |
| 374 | _0 (syscall), |
| 375 | _0 (clts), |
| 376 | _0 (sysret), |
| 377 | _0 (invd), |
| 378 | _0 (wbinvd), |
| 379 | _0 (bad), |
| 380 | _0 (ud2), |
| 381 | _0 (bad), |
| 382 | _0f (modrm_group_p, X86_INSN_FLAG_MODRM_REG_GROUP_p), |
| 383 | _0 (femms), |
| 384 | _0 (escape_3dnow), |
| 385 | |
| 386 | /* 0x10 */ |
| 387 | _2f (movups, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), |
| 388 | _2f (movups, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), |
| 389 | _2f (movlps, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), |
| 390 | _2f (movlps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), |
| 391 | _2f (unpcklps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), |
| 392 | _2f (unpckhps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), |
| 393 | _2f (movhps, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), |
| 394 | _2f (movhps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), |
| 395 | _0f (modrm_group_16, X86_INSN_FLAG_MODRM_REG_GROUP_16), |
| 396 | _0 (nop), |
| 397 | _0 (nop), |
| 398 | _0 (nop), |
| 399 | _0 (nop), |
| 400 | _0 (nop), |
| 401 | _0 (nop), |
| 402 | _0 (nop), |
| 403 | |
| 404 | /* 0x20 */ |
| 405 | _2 (mov, Rv, Cv), |
| 406 | _2 (mov, Rv, Dv), |
| 407 | _2 (mov, Cv, Rv), |
| 408 | _2 (mov, Dv, Rv), |
| 409 | _0 (bad), |
| 410 | _0 (bad), |
| 411 | _0 (bad), |
| 412 | _0 (bad), |
| 413 | _2f (movaps, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), |
| 414 | _2f (movaps, X86_INSN_FLAG_SSE_GROUP_28, Ex, Gx), |
| 415 | _2f (cvtpi2ps, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), |
| 416 | _2f (movntps, X86_INSN_FLAG_SSE_GROUP_28, Mx, Gx), |
| 417 | _2f (cvttps2pi, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), |
| 418 | _2f (cvtps2pi, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), |
| 419 | _2f (ucomiss, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), |
| 420 | _2f (comiss, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), |
| 421 | |
| 422 | /* 0x30 */ |
| 423 | _0 (wrmsr), |
| 424 | _0 (rdtsc), |
| 425 | _0 (rdmsr), |
| 426 | _0 (rdpmc), |
| 427 | _0 (sysenter), |
| 428 | _0 (sysexit), |
| 429 | _0 (bad), |
| 430 | _0 (bad), |
| 431 | _0 (bad), |
| 432 | _0 (bad), |
| 433 | _0 (bad), |
| 434 | _0 (bad), |
| 435 | _0 (bad), |
| 436 | _0 (bad), |
| 437 | _0 (bad), |
| 438 | _0 (bad), |
| 439 | |
| 440 | /* 0x40 */ |
| 441 | #define _(x) _2 (cmov##x, Gv, Ev), |
| 442 | foreach_x86_condition |
| 443 | #undef _ |
| 444 | |
| 445 | /* 0x50 */ |
| 446 | _2f (movmskps, X86_INSN_FLAG_SSE_GROUP_50, Gd, Rx), |
| 447 | _2f (sqrtps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), |
| 448 | _2f (rsqrtps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), |
| 449 | _2f (rcpps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), |
| 450 | _2f (andps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), |
| 451 | _2f (andnps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), |
| 452 | _2f (orps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), |
| 453 | _2f (xorps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), |
| 454 | _2f (addps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 455 | _2f (mulps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 456 | _2f (cvtps2pd, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 457 | _2f (cvtdq2ps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 458 | _2f (subps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 459 | _2f (minps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 460 | _2f (divps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 461 | _2f (maxps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), |
| 462 | |
| 463 | /* 0x60 */ |
| 464 | _2f (punpcklbw, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 465 | _2f (punpcklwd, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 466 | _2f (punpckldq, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 467 | _2f (packsswb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 468 | _2f (pcmpgtb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 469 | _2f (pcmpgtw, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 470 | _2f (pcmpgtd, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 471 | _2f (packuswb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), |
| 472 | _2f (punpckhbw, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), |
| 473 | _2f (punpckhwd, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), |
| 474 | _2f (punpckhdq, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), |
| 475 | _2f (packssdw, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), |
| 476 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_68), |
| 477 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_68), |
| 478 | _2f (movd, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), |
| 479 | _2f (movq, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), |
| 480 | |
| 481 | /* 0x70 */ |
| 482 | _3f (pshufw, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em, Ib), |
| 483 | _0f (modrm_group_12, X86_INSN_FLAG_MODRM_REG_GROUP_12), |
| 484 | _0f (modrm_group_13, X86_INSN_FLAG_MODRM_REG_GROUP_13), |
| 485 | _0f (modrm_group_14, X86_INSN_FLAG_MODRM_REG_GROUP_14), |
| 486 | _2f (pcmpeqb, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), |
| 487 | _2f (pcmpeqw, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), |
| 488 | _2f (pcmpeqd, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), |
| 489 | _0f (emms, X86_INSN_FLAG_SSE_GROUP_70), |
| 490 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), |
| 491 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), |
| 492 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), |
| 493 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), |
| 494 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), |
| 495 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), |
| 496 | _2f (movd, X86_INSN_FLAG_SSE_GROUP_78, Em, Gm), |
| 497 | _2f (movq, X86_INSN_FLAG_SSE_GROUP_78, Em, Gm), |
| 498 | |
| 499 | /* 0x80 */ |
| 500 | #define _(x) _1 (jmp##x, Jz), |
| 501 | foreach_x86_condition |
| 502 | #undef _ |
| 503 | |
| 504 | /* 0x90 */ |
| 505 | #define _(x) _1 (set##x, Eb), |
| 506 | foreach_x86_condition |
| 507 | #undef _ |
| 508 | |
| 509 | /* 0xa0 */ |
| 510 | _0 (push_fs), |
| 511 | _0 (pop_fs), |
| 512 | _0 (cpuid), |
| 513 | _2 (bt, Ev, Gv), |
| 514 | _3 (shld, Ev, Gv, Ib), |
| 515 | _3 (shld, Ev, Gv, CL), |
| 516 | _0 (bad), |
| 517 | _0 (bad), |
| 518 | _0 (push_gs), |
| 519 | _0 (pop_gs), |
| 520 | _0 (rsm), |
| 521 | _2 (bts, Ev, Gv), |
| 522 | _3 (shrd, Ev, Gv, Ib), |
| 523 | _3 (shrd, Ev, Gv, CL), |
| 524 | _0f (modrm_group_15, X86_INSN_FLAG_MODRM_REG_GROUP_15), |
| 525 | _2 (imul, Gv, Ev), |
| 526 | |
| 527 | /* 0xb0 */ |
| 528 | _2 (cmpxchg, Eb, Gb), |
| 529 | _2 (cmpxchg, Ev, Gv), |
| 530 | _2 (lss, Gz, Mp), |
| 531 | _2 (btr, Ev, Gv), |
| 532 | _2 (lfs, Gz, Mp), |
| 533 | _2 (lgs, Gz, Mp), |
| 534 | _2 (movzbl, Gv, Eb), |
| 535 | _2 (movzwl, Gv, Ew), |
| 536 | _0 (bad), |
| 537 | _0f (modrm_group_10, X86_INSN_FLAG_MODRM_REG_GROUP_10), |
| 538 | _2f (modrm_group_8, X86_INSN_FLAG_MODRM_REG_GROUP_8, Ev, Ib), |
| 539 | _2 (btc, Ev, Gv), |
| 540 | _2 (bsf, Gv, Ev), |
| 541 | _2 (bsr, Gv, Ev), |
| 542 | _2 (movsx, Gv, Eb), |
| 543 | _2 (movsx, Gv, Ew), |
| 544 | |
| 545 | /* 0xc0 */ |
| 546 | _2 (xadd, Eb, Gb), |
| 547 | _2 (xadd, Ev, Gv), |
| 548 | _3f (cmpps, X86_INSN_FLAG_SSE_GROUP_c0, Gx, Ex, Ib), |
| 549 | _2 (movnti, Mv, Gv), |
| 550 | _3f (pinsrw, X86_INSN_FLAG_SSE_GROUP_c0, Gm, Ew, Ib), |
| 551 | _3f (pextrw, X86_INSN_FLAG_SSE_GROUP_c0, Gd, Rm, Ib), |
| 552 | _3f (shufps, X86_INSN_FLAG_SSE_GROUP_c0, Gx, Ex, Ib), |
| 553 | _1f (modrm_group_9, X86_INSN_FLAG_MODRM_REG_GROUP_9, Mx), |
| 554 | #define _(r) _1 (bswap, r), |
| 555 | foreach_x86_gp_reg |
| 556 | #undef _ |
| 557 | |
| 558 | /* 0xd0 */ |
| 559 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_d0), |
| 560 | _2f (psrlw, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), |
| 561 | _2f (psrld, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), |
| 562 | _2f (psrlq, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), |
| 563 | _2f (paddq, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), |
| 564 | _2f (pmullw, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), |
| 565 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_d0), |
| 566 | _2f (pmovmskb, X86_INSN_FLAG_SSE_GROUP_d0, Gd, Rm), |
| 567 | _2f (psubusb, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 568 | _2f (psubusw, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 569 | _2f (pminub, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 570 | _2f (pand, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 571 | _2f (paddusb, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 572 | _2f (paddusw, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 573 | _2f (pmaxub, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 574 | _2f (pandn, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), |
| 575 | |
| 576 | /* 0xe0 */ |
| 577 | _2f (pavgb, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), |
| 578 | _2f (psraw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), |
| 579 | _2f (psrad, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), |
| 580 | _2f (pavgw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), |
| 581 | _2f (pmulhuw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), |
| 582 | _2f (pmulhw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), |
| 583 | _2f (bad, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), |
| 584 | _2f (movntq, X86_INSN_FLAG_SSE_GROUP_e0, Mm, Gm), |
| 585 | _2f (psubsb, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 586 | _2f (psubsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 587 | _2f (pminsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 588 | _2f (por, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 589 | _2f (paddsb, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 590 | _2f (paddsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 591 | _2f (pmaxsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 592 | _2f (pxor, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), |
| 593 | |
| 594 | /* 0xf0 */ |
| 595 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_f0), |
| 596 | _2f (psllw, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), |
| 597 | _2f (pslld, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), |
| 598 | _2f (psllq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), |
| 599 | _2f (pmuludq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), |
| 600 | _2f (pmaddwd, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), |
| 601 | _2f (psadbw, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), |
| 602 | _2f (maskmovq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), |
| 603 | _2f (psubb, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), |
| 604 | _2f (psubw, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), |
| 605 | _2f (psubd, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), |
| 606 | _2f (psubq, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), |
| 607 | _2f (paddb, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), |
| 608 | _2f (paddw, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), |
| 609 | _2f (paddd, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), |
| 610 | _0f (bad, X86_INSN_FLAG_SSE_GROUP_f8), |
| 611 | }; |
| 612 | |
| 613 | typedef struct { |
| 614 | x86_insn_t insns[8]; |
| 615 | } x86_insn_group8_t; |
| 616 | |
| 617 | /* Escape groups are indexed by modrm reg field. */ |
| 618 | static x86_insn_group8_t x86_insn_modrm_reg_groups[] = { |
| 619 | [X86_INSN_MODRM_REG_GROUP_1].insns = { |
| 620 | _0 (add), _0 ( or), _0 (adc), _0 (sbb), |
| 621 | _0 (and), _0 (sub), _0 (xor), _0 (cmp), |
| 622 | }, |
| 623 | |
| 624 | [X86_INSN_MODRM_REG_GROUP_1a].insns = { |
| 625 | _0f (pop, X86_INSN_FLAG_DEFAULT_64_BIT), |
| 626 | _0 (bad), _0 (bad), _0 (bad), |
| 627 | _0 (bad), _0 (bad), _0 (bad), _0 (bad), |
| 628 | }, |
| 629 | |
| 630 | [X86_INSN_MODRM_REG_GROUP_2].insns = { |
| 631 | _0 (rol), _0 (ror), _0 (rcl), _0 (rcr), |
| 632 | _0 (shl), _0 (shr), _0 (sal), _0 (sar), |
| 633 | }, |
| 634 | |
| 635 | [X86_INSN_MODRM_REG_GROUP_3].insns = { |
| 636 | _0 (test), _0 (test), _0 (not), _0 (neg), |
| 637 | _0 (mul), _0 (imul), _0 (div), _0 (idiv), |
| 638 | }, |
| 639 | |
| 640 | [X86_INSN_MODRM_REG_GROUP_4].insns = { |
| 641 | _0 (inc), _0 (dec), _0 (bad), _0 (bad), |
| 642 | _0 (bad), _0 (bad), _0 (bad), _0 (bad), |
| 643 | }, |
| 644 | |
| 645 | [X86_INSN_MODRM_REG_GROUP_5].insns = { |
| 646 | _1 (inc, Ev), |
| 647 | _1 (dec, Ev), |
| 648 | _1f (call, X86_INSN_FLAG_DEFAULT_64_BIT, Ev), |
| 649 | _1 (call, Mp), |
| 650 | _1f (jmp, X86_INSN_FLAG_DEFAULT_64_BIT, Ev), |
| 651 | _1 (jmp, Mp), |
| 652 | _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, Ev), |
| 653 | _0 (bad), |
| 654 | }, |
| 655 | |
| 656 | [X86_INSN_MODRM_REG_GROUP_6].insns = { |
| 657 | _1 (sldt, Ev), |
| 658 | _1 (str, Ev), |
| 659 | _1 (lldt, Ev), |
| 660 | _1 (ltr, Ev), |
| 661 | _1 (verr, Ev), |
| 662 | _1 (verw, Ev), |
| 663 | _0 (bad), |
| 664 | _0 (bad), |
| 665 | }, |
| 666 | |
| 667 | [X86_INSN_MODRM_REG_GROUP_7].insns = { |
| 668 | _1 (sgdt, Mv), |
| 669 | _1 (sidt, Mv), |
| 670 | _1 (lgdt, Mv), |
| 671 | _1 (lidt, Mv), |
| 672 | _1 (smsw, Ev), |
| 673 | _0 (bad), |
| 674 | _1 (lmsw, Ew), |
| 675 | _1 (invlpg, Mv), |
| 676 | }, |
| 677 | |
| 678 | [X86_INSN_MODRM_REG_GROUP_8].insns = { |
| 679 | _0 (bad), |
| 680 | _0 (bad), |
| 681 | _0 (bad), |
| 682 | _0 (bad), |
| 683 | _2 (bt, Ev, Ib), |
| 684 | _2 (bts, Ev, Ib), |
| 685 | _2 (btr, Ev, Ib), |
| 686 | _2 (btc, Ev, Ib), |
| 687 | }, |
| 688 | |
| 689 | [X86_INSN_MODRM_REG_GROUP_9].insns = { |
| 690 | _0 (bad), |
| 691 | _1 (cmpxchg, Mx), |
| 692 | _0 (bad), |
| 693 | _0 (bad), |
| 694 | _0 (bad), |
| 695 | _0 (bad), |
| 696 | _0 (bad), |
| 697 | _0 (bad), |
| 698 | }, |
| 699 | |
| 700 | [X86_INSN_MODRM_REG_GROUP_10].insns = { |
| 701 | _0 (bad), _0 (bad), _0 (bad), _0 (bad), |
| 702 | _0 (bad), _0 (bad), _0 (bad), _0 (bad), |
| 703 | }, |
| 704 | |
| 705 | [X86_INSN_MODRM_REG_GROUP_11].insns = { |
| 706 | _0 (mov), _0 (bad), _0 (bad), _0 (bad), |
| 707 | _0 (bad), _0 (bad), _0 (bad), _0 (bad), |
| 708 | }, |
| 709 | |
| 710 | [X86_INSN_MODRM_REG_GROUP_12].insns = { |
| 711 | _0 (bad), |
| 712 | _0 (bad), |
| 713 | _2 (psrlw, Rm, Ib), |
| 714 | _0 (bad), |
| 715 | _2 (psraw, Rm, Ib), |
| 716 | _0 (bad), |
| 717 | _2 (psllw, Rm, Ib), |
| 718 | _0 (bad), |
| 719 | }, |
| 720 | |
| 721 | [X86_INSN_MODRM_REG_GROUP_13].insns = { |
| 722 | _0 (bad), |
| 723 | _0 (bad), |
| 724 | _2 (psrld, Rm, Ib), |
| 725 | _0 (bad), |
| 726 | _2 (psrad, Rm, Ib), |
| 727 | _0 (bad), |
| 728 | _2 (pslld, Rm, Ib), |
| 729 | _0 (bad), |
| 730 | }, |
| 731 | |
| 732 | [X86_INSN_MODRM_REG_GROUP_14].insns = { |
| 733 | _0 (bad), |
| 734 | _0 (bad), |
| 735 | _2 (psrlq, Rm, Ib), |
| 736 | _0f (bad, 0), |
| 737 | _0 (bad), |
| 738 | _0 (bad), |
| 739 | _2 (psllq, Rm, Ib), |
| 740 | _0f (bad, 0), |
| 741 | }, |
| 742 | |
| 743 | [X86_INSN_MODRM_REG_GROUP_15].insns = { |
| 744 | _1 (fxsave, Mv), |
| 745 | _1 (fxrstor, Mv), |
| 746 | _1 (ldmxcsr, Mv), |
| 747 | _1 (stmxcsr, Mv), |
| 748 | _0 (bad), |
| 749 | _1 (lfence, Mv), |
| 750 | _1 (mfence, Mv), |
| 751 | _1 (sfence, Mv), |
| 752 | }, |
| 753 | |
| 754 | [X86_INSN_MODRM_REG_GROUP_16].insns = { |
| 755 | _1 (prefetch_nta, Mv), |
| 756 | _1 (prefetch_t0, Mv), |
| 757 | _1 (prefetch_t1, Mv), |
| 758 | _1 (prefetch_t2, Mv), |
| 759 | _1 (prefetch_nop, Mv), |
| 760 | _1 (prefetch_nop, Mv), |
| 761 | _1 (prefetch_nop, Mv), |
| 762 | _1 (prefetch_nop, Mv), |
| 763 | }, |
| 764 | |
| 765 | [X86_INSN_MODRM_REG_GROUP_p].insns = { |
| 766 | _1 (prefetch_exclusive, Mv), |
| 767 | _1 (prefetch_modified, Mv), |
| 768 | _1 (prefetch_nop, Mv), |
| 769 | _1 (prefetch_modified, Mv), |
| 770 | _1 (prefetch_nop, Mv), |
| 771 | _1 (prefetch_nop, Mv), |
| 772 | _1 (prefetch_nop, Mv), |
| 773 | _1 (prefetch_nop, Mv), |
| 774 | }, |
| 775 | }; |
| 776 | |
| 777 | static x86_insn_group8_t x86_insn_sse_groups_repz[] = { |
| 778 | [X86_INSN_SSE_GROUP_10].insns = { |
| 779 | _2 (movss, Gx, Ex), |
| 780 | _2 (movss, Ex, Gx), |
| 781 | _2 (movsldup, Gx, Ex), |
| 782 | _0 (bad), |
| 783 | _0 (bad), |
| 784 | _0 (bad), |
| 785 | _2 (movshdup, Gx, Ex), |
| 786 | _0 (bad), |
| 787 | }, |
| 788 | |
| 789 | [X86_INSN_SSE_GROUP_28].insns = { |
| 790 | _0 (bad), |
| 791 | _0 (bad), |
| 792 | _2 (cvtsi2ss, Gx, Ev), |
| 793 | _0 (bad), |
| 794 | _2 (cvttss2si, Gv, Ex), |
| 795 | _2 (cvtss2si, Gv, Ex), |
| 796 | _0 (bad), |
| 797 | _0 (bad), |
| 798 | }, |
| 799 | |
| 800 | [X86_INSN_SSE_GROUP_50].insns = { |
| 801 | _0 (bad), |
| 802 | _2 (sqrtss, Gx, Ex), |
| 803 | _2 (rsqrtps, Gx, Ex), |
| 804 | _2 (rcpss, Gx, Ex), |
| 805 | _0 (bad), |
| 806 | _0 (bad), |
| 807 | _0 (bad), |
| 808 | _0 (bad), |
| 809 | }, |
| 810 | |
| 811 | [X86_INSN_SSE_GROUP_58].insns = { |
| 812 | _2 (addss, Gx, Ex), |
| 813 | _2 (mulss, Gx, Ex), |
| 814 | _2 (cvtss2sd, Gx, Ex), |
| 815 | _2 (cvttps2dq, Gx, Ex), |
| 816 | _2 (subss, Gx, Ex), |
| 817 | _2 (minss, Gx, Ex), |
| 818 | _2 (divss, Gx, Ex), |
| 819 | _2 (maxss, Gx, Ex), |
| 820 | }, |
| 821 | |
| 822 | [X86_INSN_SSE_GROUP_60].insns = { |
| 823 | _0 (bad), |
| 824 | _0 (bad), |
| 825 | _0 (bad), |
| 826 | _0 (bad), |
| 827 | _0 (bad), |
| 828 | _0 (bad), |
| 829 | _0 (bad), |
| 830 | _0 (bad), |
| 831 | }, |
| 832 | |
| 833 | [X86_INSN_SSE_GROUP_68].insns = { |
| 834 | _0 (bad), |
| 835 | _0 (bad), |
| 836 | _0 (bad), |
| 837 | _0 (bad), |
| 838 | _0 (bad), |
| 839 | _0 (bad), |
| 840 | _0 (bad), |
| 841 | _2 (movdqu, Gx, Ex), |
| 842 | }, |
| 843 | |
| 844 | [X86_INSN_SSE_GROUP_70].insns = { |
| 845 | _3 (pshufhw, Gx, Ex, Ib), |
| 846 | _0 (bad), |
| 847 | _0 (bad), |
| 848 | _0 (bad), |
| 849 | _0 (bad), |
| 850 | _0 (bad), |
| 851 | _0 (bad), |
| 852 | _0 (bad), |
| 853 | }, |
| 854 | |
| 855 | [X86_INSN_SSE_GROUP_78].insns = { |
| 856 | _0 (bad), |
| 857 | _0 (bad), |
| 858 | _0 (bad), |
| 859 | _0 (bad), |
| 860 | _0 (bad), |
| 861 | _0 (bad), |
| 862 | _2 (movq, Gx, Ex), |
| 863 | _2 (movdqu, Ex, Gx), |
| 864 | }, |
| 865 | |
| 866 | [X86_INSN_SSE_GROUP_c0].insns = { |
| 867 | _0 (bad), |
| 868 | _0 (bad), |
| 869 | _3 (cmpss, Gx, Ex, Ib), |
| 870 | _0 (bad), |
| 871 | _0 (bad), |
| 872 | _0 (bad), |
| 873 | _0 (bad), |
| 874 | _0 (bad), |
| 875 | }, |
| 876 | |
| 877 | [X86_INSN_SSE_GROUP_d0].insns = { |
| 878 | _0 (bad), |
| 879 | _0 (bad), |
| 880 | _0 (bad), |
| 881 | _0 (bad), |
| 882 | _0 (bad), |
| 883 | _0 (bad), |
| 884 | _2 (movq2dq, Gx, Em), |
| 885 | _0 (bad), |
| 886 | }, |
| 887 | |
| 888 | [X86_INSN_SSE_GROUP_d8].insns = { |
| 889 | _0 (bad), |
| 890 | _0 (bad), |
| 891 | _0 (bad), |
| 892 | _0 (bad), |
| 893 | _0 (bad), |
| 894 | _0 (bad), |
| 895 | _0 (bad), |
| 896 | _0 (bad), |
| 897 | }, |
| 898 | |
| 899 | [X86_INSN_SSE_GROUP_e0].insns = { |
| 900 | _0 (bad), |
| 901 | _0 (bad), |
| 902 | _0 (bad), |
| 903 | _0 (bad), |
| 904 | _0 (bad), |
| 905 | _0 (bad), |
| 906 | _2 (cvtdq2pd, Gx, Ex), |
| 907 | _0 (bad), |
| 908 | }, |
| 909 | |
| 910 | [X86_INSN_SSE_GROUP_e8].insns = { |
| 911 | _0 (bad), |
| 912 | _0 (bad), |
| 913 | _0 (bad), |
| 914 | _0 (bad), |
| 915 | _0 (bad), |
| 916 | _0 (bad), |
| 917 | _0 (bad), |
| 918 | _0 (bad), |
| 919 | }, |
| 920 | |
| 921 | [X86_INSN_SSE_GROUP_f0].insns = { |
| 922 | _0 (bad), |
| 923 | _0 (bad), |
| 924 | _0 (bad), |
| 925 | _0 (bad), |
| 926 | _0 (bad), |
| 927 | _0 (bad), |
| 928 | _0 (bad), |
| 929 | _0 (bad), |
| 930 | }, |
| 931 | |
| 932 | [X86_INSN_SSE_GROUP_f8].insns = { |
| 933 | _0 (bad), |
| 934 | _0 (bad), |
| 935 | _0 (bad), |
| 936 | _0 (bad), |
| 937 | _0 (bad), |
| 938 | _0 (bad), |
| 939 | _0 (bad), |
| 940 | _0 (bad), |
| 941 | }, |
| 942 | }; |
| 943 | |
| 944 | static x86_insn_group8_t x86_insn_sse_groups_operand_size[] = { |
| 945 | [X86_INSN_SSE_GROUP_10].insns = { |
| 946 | _2 (movupd, Gx, Ex), |
| 947 | _2 (movupd, Ex, Gx), |
| 948 | _2 (movlpd, Gx, Ex), |
| 949 | _2 (movlpd, Ex, Gx), |
| 950 | _2 (unpcklpd, Gx, Ex), |
| 951 | _2 (unpckhpd, Gx, Ex), |
| 952 | _2 (movhpd, Gx, Mx), |
| 953 | _2 (movhpd, Mx, Gx), |
| 954 | }, |
| 955 | |
| 956 | [X86_INSN_SSE_GROUP_28].insns = { |
| 957 | _2 (movapd, Gx, Ex), |
| 958 | _2 (movapd, Ex, Gx), |
| 959 | _2 (cvtpi2pd, Gx, Ex), |
| 960 | _2 (movntpd, Mx, Gx), |
| 961 | _2 (cvttpd2pi, Gx, Mx), |
| 962 | _2 (cvtpd2pi, Gx, Mx), |
| 963 | _2 (ucomisd, Gx, Ex), |
| 964 | _2 (comisd, Gx, Ex), |
| 965 | }, |
| 966 | |
| 967 | [X86_INSN_SSE_GROUP_50].insns = { |
| 968 | _2 (movmskpd, Gd, Rx), |
| 969 | _2 (sqrtpd, Gx, Ex), |
| 970 | _0 (bad), |
| 971 | _0 (bad), |
| 972 | _2 (andpd, Gx, Ex), |
| 973 | _2 (andnpd, Gx, Ex), |
| 974 | _2 (orpd, Gx, Ex), |
| 975 | _2 (xorpd, Gx, Ex), |
| 976 | }, |
| 977 | |
| 978 | [X86_INSN_SSE_GROUP_58].insns = { |
| 979 | _2 (addpd, Gx, Ex), |
| 980 | _2 (mulpd, Gx, Ex), |
| 981 | _2 (cvtpd2ps, Gx, Ex), |
| 982 | _2 (cvtps2dq, Gx, Ex), |
| 983 | _2 (subpd, Gx, Ex), |
| 984 | _2 (minpd, Gx, Ex), |
| 985 | _2 (divpd, Gx, Ex), |
| 986 | _2 (maxpd, Gx, Ex), |
| 987 | }, |
| 988 | |
| 989 | [X86_INSN_SSE_GROUP_60].insns = { |
| 990 | _2 (punpcklbw, Gx, Ex), |
| 991 | _2 (punpcklwd, Gx, Ex), |
| 992 | _2 (punpckldq, Gx, Ex), |
| 993 | _2 (packsswb, Gx, Ex), |
| 994 | _2 (pcmpgtb, Gx, Ex), |
| 995 | _2 (pcmpgtw, Gx, Ex), |
| 996 | _2 (pcmpgtd, Gx, Ex), |
| 997 | _2 (packuswb, Gx, Ex), |
| 998 | }, |
| 999 | |
| 1000 | [X86_INSN_SSE_GROUP_68].insns = { |
| 1001 | _2 (punpckhbw, Gx, Ex), |
| 1002 | _2 (punpckhwd, Gx, Ex), |
| 1003 | _2 (punpckhdq, Gx, Ex), |
| 1004 | _2 (packssdw, Gx, Ex), |
| 1005 | _2 (punpcklqdq, Gx, Ex), |
| 1006 | _2 (punpckhqdq, Gx, Ex), |
| 1007 | _2 (movd, Gx, Ev), |
| 1008 | _2 (movdqa, Gx, Ex), |
| 1009 | }, |
| 1010 | |
| 1011 | [X86_INSN_SSE_GROUP_70].insns = { |
| 1012 | _3 (pshufd, Gx, Ex, Ib), |
| 1013 | _0f (modrm_group_12, X86_INSN_FLAG_MODRM_REG_GROUP_12), |
| 1014 | _0f (modrm_group_13, X86_INSN_FLAG_MODRM_REG_GROUP_13), |
| 1015 | _0f (modrm_group_14, X86_INSN_FLAG_MODRM_REG_GROUP_14), |
| 1016 | _2 (pcmpeqb, Gx, Ex), |
| 1017 | _2 (pcmpeqw, Gx, Ex), |
| 1018 | _2 (pcmpeqd, Gx, Ex), |
| 1019 | _0 (bad), |
| 1020 | }, |
| 1021 | |
| 1022 | [X86_INSN_SSE_GROUP_78].insns = { |
| 1023 | _0 (bad), |
| 1024 | _0 (bad), |
| 1025 | _0 (bad), |
| 1026 | _0 (bad), |
| 1027 | _2 (haddpd, Gx, Ex), |
| 1028 | _2 (hsubpd, Gx, Ex), |
| 1029 | _2 (movd, Ev, Gx), |
| 1030 | _2 (movdqa, Ex, Gx), |
| 1031 | }, |
| 1032 | |
| 1033 | [X86_INSN_SSE_GROUP_c0].insns = { |
| 1034 | _0 (bad), |
| 1035 | _0 (bad), |
| 1036 | _3 (cmppd, Gx, Ex, Ib), |
| 1037 | _0 (bad), |
| 1038 | _3 (pinsrw, Gx, Ew, Ib), |
| 1039 | _3 (pextrw, Gd, Gx, Ib), |
| 1040 | _3 (shufpd, Gx, Ex, Ib), |
| 1041 | _0 (bad), |
| 1042 | }, |
| 1043 | |
| 1044 | [X86_INSN_SSE_GROUP_d0].insns = { |
| 1045 | _2 (addsubpd, Gx, Ex), |
| 1046 | _2 (psrlw, Gx, Ex), |
| 1047 | _2 (psrld, Gx, Ex), |
| 1048 | _2 (psrlq, Gx, Ex), |
| 1049 | _2 (paddq, Gx, Ex), |
| 1050 | _2 (pmullw, Gx, Ex), |
| 1051 | _2 (movq, Ex, Gx), |
| 1052 | _2 (pmovmskb, Gd, Rx), |
| 1053 | }, |
| 1054 | |
| 1055 | [X86_INSN_SSE_GROUP_d8].insns = { |
| 1056 | _2 (psubusb, Gx, Ex), |
| 1057 | _2 (psubusw, Gx, Ex), |
| 1058 | _2 (pminub, Gx, Ex), |
| 1059 | _2 (pand, Gx, Ex), |
| 1060 | _2 (paddusb, Gx, Ex), |
| 1061 | _2 (paddusw, Gx, Ex), |
| 1062 | _2 (pmaxub, Gx, Ex), |
| 1063 | _2 (pandn, Gx, Ex), |
| 1064 | }, |
| 1065 | |
| 1066 | [X86_INSN_SSE_GROUP_e0].insns = { |
| 1067 | _2 (pavgb, Gx, Ex), |
| 1068 | _2 (psraw, Gx, Ex), |
| 1069 | _2 (psrad, Gx, Ex), |
| 1070 | _2 (pavgw, Gx, Ex), |
| 1071 | _2 (pmulhuw, Gx, Ex), |
| 1072 | _2 (pmulhw, Gx, Ex), |
| 1073 | _2 (cvttpd2dq, Gx, Ex), |
| 1074 | _2 (movntdq, Mx, Gx), |
| 1075 | }, |
| 1076 | |
| 1077 | [X86_INSN_SSE_GROUP_e8].insns = { |
| 1078 | _2 (psubsb, Gx, Ex), |
| 1079 | _2 (psubsw, Gx, Ex), |
| 1080 | _2 (pminsw, Gx, Ex), |
| 1081 | _2 (por, Gx, Ex), |
| 1082 | _2 (paddsb, Gx, Ex), |
| 1083 | _2 (paddsw, Gx, Ex), |
| 1084 | _2 (pmaxsw, Gx, Ex), |
| 1085 | _2 (pxor, Gx, Ex), |
| 1086 | }, |
| 1087 | |
| 1088 | [X86_INSN_SSE_GROUP_f0].insns = { |
| 1089 | _0 (bad), |
| 1090 | _2 (psllw, Gx, Ex), |
| 1091 | _2 (pslld, Gx, Ex), |
| 1092 | _2 (psllq, Gx, Ex), |
| 1093 | _2 (pmuludq, Gx, Ex), |
| 1094 | _2 (pmaddwd, Gx, Ex), |
| 1095 | _2 (psadbw, Gx, Ex), |
| 1096 | _2 (maskmovdqu, Gx, Ex), |
| 1097 | }, |
| 1098 | |
| 1099 | [X86_INSN_SSE_GROUP_f8].insns = { |
| 1100 | _2 (psubb, Gx, Ex), |
| 1101 | _2 (psubw, Gx, Ex), |
| 1102 | _2 (psubd, Gx, Ex), |
| 1103 | _2 (psubq, Gx, Ex), |
| 1104 | _2 (paddb, Gx, Ex), |
| 1105 | _2 (paddw, Gx, Ex), |
| 1106 | _2 (paddd, Gx, Ex), |
| 1107 | _0 (bad), |
| 1108 | }, |
| 1109 | }; |
| 1110 | |
| 1111 | static x86_insn_group8_t x86_insn_sse_groups_repnz[] = { |
| 1112 | [X86_INSN_SSE_GROUP_10].insns = { |
| 1113 | _2 (movsd, Gx, Ex), |
| 1114 | _2 (movsd, Ex, Gx), |
| 1115 | _2 (movddup, Gx, Ex), |
| 1116 | _0 (bad), |
| 1117 | _0 (bad), |
| 1118 | _0 (bad), |
| 1119 | _0 (bad), |
| 1120 | _0 (bad), |
| 1121 | }, |
| 1122 | |
| 1123 | [X86_INSN_SSE_GROUP_28].insns = { |
| 1124 | _0 (bad), |
| 1125 | _0 (bad), |
| 1126 | _2 (cvtsi2sd, Gx, Ev), |
| 1127 | _0 (bad), |
| 1128 | _2 (cvttsd2si, Gv, Ex), |
| 1129 | _2 (cvtsd2si, Gv, Ex), |
| 1130 | _0 (bad), |
| 1131 | _0 (bad), |
| 1132 | }, |
| 1133 | |
| 1134 | [X86_INSN_SSE_GROUP_50].insns = { |
| 1135 | _0 (bad), |
| 1136 | _2 (sqrtsd, Gx, Ex), |
| 1137 | _0 (bad), |
| 1138 | _0 (bad), |
| 1139 | _0 (bad), |
| 1140 | _0 (bad), |
| 1141 | _0 (bad), |
| 1142 | _0 (bad), |
| 1143 | }, |
| 1144 | |
| 1145 | [X86_INSN_SSE_GROUP_58].insns = { |
| 1146 | _2 (addsd, Gx, Ex), |
| 1147 | _2 (mulsd, Gx, Ex), |
| 1148 | _2 (cvtsd2ss, Gx, Ex), |
| 1149 | _0 (bad), |
| 1150 | _2 (subsd, Gx, Ex), |
| 1151 | _2 (minsd, Gx, Ex), |
| 1152 | _2 (divsd, Gx, Ex), |
| 1153 | _2 (maxsd, Gx, Ex), |
| 1154 | }, |
| 1155 | |
| 1156 | [X86_INSN_SSE_GROUP_60].insns = { |
| 1157 | _0 (bad), |
| 1158 | _0 (bad), |
| 1159 | _0 (bad), |
| 1160 | _0 (bad), |
| 1161 | _0 (bad), |
| 1162 | _0 (bad), |
| 1163 | _0 (bad), |
| 1164 | _0 (bad), |
| 1165 | }, |
| 1166 | |
| 1167 | [X86_INSN_SSE_GROUP_68].insns = { |
| 1168 | _0 (bad), |
| 1169 | _0 (bad), |
| 1170 | _0 (bad), |
| 1171 | _0 (bad), |
| 1172 | _0 (bad), |
| 1173 | _0 (bad), |
| 1174 | _0 (bad), |
| 1175 | _0 (bad), |
| 1176 | }, |
| 1177 | |
| 1178 | [X86_INSN_SSE_GROUP_70].insns = { |
| 1179 | _3 (pshuflw, Gx, Ex, Ib), |
| 1180 | _0 (bad), |
| 1181 | _0 (bad), |
| 1182 | _0 (bad), |
| 1183 | _0 (bad), |
| 1184 | _0 (bad), |
| 1185 | _0 (bad), |
| 1186 | _0 (bad), |
| 1187 | }, |
| 1188 | |
| 1189 | [X86_INSN_SSE_GROUP_78].insns = { |
| 1190 | _0 (bad), |
| 1191 | _0 (bad), |
| 1192 | _0 (bad), |
| 1193 | _0 (bad), |
| 1194 | _2 (haddps, Gx, Ex), |
| 1195 | _2 (hsubps, Gx, Ex), |
| 1196 | _0 (bad), |
| 1197 | _0 (bad), |
| 1198 | }, |
| 1199 | |
| 1200 | [X86_INSN_SSE_GROUP_c0].insns = { |
| 1201 | _0 (bad), |
| 1202 | _0 (bad), |
| 1203 | _3 (cmpsd, Gx, Ex, Ib), |
| 1204 | _0 (bad), |
| 1205 | _0 (bad), |
| 1206 | _0 (bad), |
| 1207 | _0 (bad), |
| 1208 | _0 (bad), |
| 1209 | }, |
| 1210 | |
| 1211 | [X86_INSN_SSE_GROUP_d0].insns = { |
| 1212 | _2 (addsubps, Gx, Ex), |
| 1213 | _0 (bad), |
| 1214 | _0 (bad), |
| 1215 | _0 (bad), |
| 1216 | _0 (bad), |
| 1217 | _0 (bad), |
| 1218 | _2 (movdq2q, Gm, Ex), |
| 1219 | _0 (bad), |
| 1220 | }, |
| 1221 | |
| 1222 | [X86_INSN_SSE_GROUP_d8].insns = { |
| 1223 | _0 (bad), |
| 1224 | _0 (bad), |
| 1225 | _0 (bad), |
| 1226 | _0 (bad), |
| 1227 | _0 (bad), |
| 1228 | _0 (bad), |
| 1229 | _0 (bad), |
| 1230 | _0 (bad), |
| 1231 | }, |
| 1232 | |
| 1233 | [X86_INSN_SSE_GROUP_e0].insns = { |
| 1234 | _0 (bad), |
| 1235 | _0 (bad), |
| 1236 | _0 (bad), |
| 1237 | _0 (bad), |
| 1238 | _0 (bad), |
| 1239 | _0 (bad), |
| 1240 | _2 (cvtpd2dq, Gx, Ex), |
| 1241 | _0 (bad), |
| 1242 | }, |
| 1243 | |
| 1244 | [X86_INSN_SSE_GROUP_e8].insns = { |
| 1245 | _0 (bad), |
| 1246 | _0 (bad), |
| 1247 | _0 (bad), |
| 1248 | _0 (bad), |
| 1249 | _0 (bad), |
| 1250 | _0 (bad), |
| 1251 | _0 (bad), |
| 1252 | _0 (bad), |
| 1253 | }, |
| 1254 | |
| 1255 | [X86_INSN_SSE_GROUP_f0].insns = { |
| 1256 | _2 (lddqu, Gx, Mx), |
| 1257 | _0 (bad), |
| 1258 | _0 (bad), |
| 1259 | _0 (bad), |
| 1260 | _0 (bad), |
| 1261 | _0 (bad), |
| 1262 | _0 (bad), |
| 1263 | _0 (bad), |
| 1264 | }, |
| 1265 | |
| 1266 | [X86_INSN_SSE_GROUP_f8].insns = { |
| 1267 | _0 (bad), |
| 1268 | _0 (bad), |
| 1269 | _0 (bad), |
| 1270 | _0 (bad), |
| 1271 | _0 (bad), |
| 1272 | _0 (bad), |
| 1273 | _0 (bad), |
| 1274 | _0 (bad), |
| 1275 | }, |
| 1276 | }; |
| 1277 | |
| 1278 | #undef _ |
| 1279 | |
| 1280 | /* Parses memory displacements and immediates. */ |
| 1281 | static u8 * x86_insn_parse_number (u32 log2_n_bytes, |
| 1282 | u8 * code, u8 * code_end, |
| 1283 | i64 * result) |
| 1284 | { |
| 1285 | i64 x = 0; |
| 1286 | |
| 1287 | if (code + (1 << log2_n_bytes) > code_end) |
| 1288 | return 0; |
| 1289 | |
| 1290 | switch (log2_n_bytes) |
| 1291 | { |
| 1292 | case 3: |
| 1293 | x = clib_little_to_host_unaligned_mem_u64 ((u64 *) code); |
| 1294 | break; |
| 1295 | |
| 1296 | case 2: |
| 1297 | x = (i32) clib_little_to_host_unaligned_mem_u32 ((u32 *) code); |
| 1298 | break; |
| 1299 | |
| 1300 | case 1: |
| 1301 | x = (i16) clib_little_to_host_unaligned_mem_u16 ((u16 *) code); |
| 1302 | break; |
| 1303 | |
| 1304 | case 0: |
| 1305 | x = (i8) code[0]; |
| 1306 | break; |
| 1307 | |
| 1308 | default: |
| 1309 | ASSERT (0); |
| 1310 | } |
| 1311 | |
| 1312 | *result = x; |
| 1313 | return code + (1 << log2_n_bytes); |
| 1314 | } |
| 1315 | |
| 1316 | static u32 |
| 1317 | x86_insn_log2_immediate_bytes (x86_insn_parse_t * p, x86_insn_t * insn) |
| 1318 | { |
| 1319 | u32 i = ~0; |
| 1320 | switch (x86_insn_immediate_type (insn)) |
| 1321 | { |
| 1322 | case 'b': i = 0; break; |
| 1323 | case 'w': i = 1; break; |
| 1324 | case 'd': i = 2; break; |
| 1325 | case 'q': i = 3; break; |
| 1326 | |
| 1327 | case 'z': |
| 1328 | i = p->log2_effective_operand_bytes; |
| 1329 | if (i > 2) i = 2; |
| 1330 | break; |
| 1331 | |
| 1332 | case 'v': |
| 1333 | i = p->log2_effective_operand_bytes; |
| 1334 | break; |
| 1335 | |
| 1336 | default: |
| 1337 | i = ~0; |
| 1338 | break; |
| 1339 | } |
| 1340 | |
| 1341 | return i; |
| 1342 | } |
| 1343 | |
| 1344 | static u8 * |
| 1345 | x86_insn_parse_modrm_byte (x86_insn_parse_t * x, |
| 1346 | x86_insn_modrm_byte_t modrm, |
| 1347 | u32 parse_flags, |
| 1348 | u8 * code, |
| 1349 | u8 * code_end) |
| 1350 | { |
| 1351 | u8 effective_address_bits; |
| 1352 | |
| 1353 | if (parse_flags & X86_INSN_PARSE_64_BIT) |
| 1354 | effective_address_bits = (x->flags & X86_INSN_ADDRESS_SIZE) ? 32 : 64; |
| 1355 | else if (parse_flags & X86_INSN_PARSE_32_BIT) |
| 1356 | effective_address_bits = (x->flags & X86_INSN_ADDRESS_SIZE) ? 16 : 32; |
| 1357 | else |
| 1358 | effective_address_bits = (x->flags & X86_INSN_ADDRESS_SIZE) ? 32 : 16; |
| 1359 | |
| 1360 | x->log2_effective_address_bytes = 1; |
| 1361 | x->log2_effective_address_bytes += effective_address_bits > 16; |
| 1362 | x->log2_effective_address_bytes += effective_address_bits > 32; |
| 1363 | |
| 1364 | x->regs[0] |= modrm.reg; |
| 1365 | if (modrm.mode == 3) |
| 1366 | x->regs[1] |= modrm.rm; |
| 1367 | else |
| 1368 | { |
| 1369 | u32 log2_disp_bytes = ~0; |
| 1370 | |
| 1371 | x->flags |= X86_INSN_IS_ADDRESS; |
| 1372 | |
| 1373 | if (effective_address_bits != 16) |
| 1374 | { |
| 1375 | u8 has_sib_byte = 0; |
| 1376 | |
| 1377 | switch (modrm.mode) |
| 1378 | { |
| 1379 | case 0: |
| 1380 | /* When base is bp displacement is present for mode 0. */ |
| 1381 | if (modrm.rm == X86_INSN_GP_REG_BP) |
| 1382 | { |
| 1383 | log2_disp_bytes = x->log2_effective_address_bytes; |
| 1384 | break; |
| 1385 | } |
| 1386 | else if (modrm.rm == X86_INSN_GP_REG_SP |
| 1387 | && effective_address_bits != 16) |
| 1388 | { |
| 1389 | has_sib_byte = 1; |
| 1390 | break; |
| 1391 | } |
| 1392 | /* fall through */ |
| 1393 | case 1: |
| 1394 | case 2: |
| 1395 | x->regs[1] |= modrm.rm; |
| 1396 | x->flags |= X86_INSN_HAS_BASE; |
| 1397 | if (modrm.mode != 0) |
| 1398 | { |
| 1399 | log2_disp_bytes = (modrm.mode == 1 |
| 1400 | ? 0 |
| 1401 | : x->log2_effective_address_bytes); |
| 1402 | if (log2_disp_bytes > 2) |
| 1403 | log2_disp_bytes = 2; |
| 1404 | } |
| 1405 | break; |
| 1406 | } |
| 1407 | |
| 1408 | if (has_sib_byte) |
| 1409 | { |
| 1410 | x86_insn_sib_byte_t sib; |
| 1411 | |
| 1412 | if (code >= code_end) |
| 1413 | return 0; |
| 1414 | sib.byte = *code++; |
| 1415 | |
| 1416 | x->log2_index_scale = 1 << sib.log2_scale; |
| 1417 | x->regs[1] |= sib.base; |
| 1418 | x->flags |= X86_INSN_HAS_BASE; |
| 1419 | |
| 1420 | if (sib.index != X86_INSN_GP_REG_SP) |
| 1421 | { |
| 1422 | x->regs[2] |= sib.index; |
| 1423 | x->flags |= X86_INSN_HAS_INDEX; |
| 1424 | } |
| 1425 | } |
| 1426 | } |
| 1427 | else |
| 1428 | { |
| 1429 | /* effective_address_bits == 16 */ |
| 1430 | switch (modrm.mode) |
| 1431 | { |
| 1432 | case 0: |
| 1433 | if (modrm.rm == 6) |
| 1434 | { |
| 1435 | /* [disp16] */ |
| 1436 | log2_disp_bytes = 1; |
| 1437 | break; |
| 1438 | } |
| 1439 | /* fall through */ |
| 1440 | case 1: |
| 1441 | case 2: |
| 1442 | switch (modrm.rm) |
| 1443 | { |
| 1444 | case 0: /* [bx + si/di] */ |
| 1445 | case 1: |
| 1446 | x->regs[1] = X86_INSN_GP_REG_BX; |
| 1447 | x->regs[2] = X86_INSN_GP_REG_SI + (modrm.rm & 1); |
| 1448 | x->flags |= X86_INSN_HAS_BASE | X86_INSN_HAS_INDEX; |
| 1449 | break; |
| 1450 | |
| 1451 | case 2: /* [bp + si/di] */ |
| 1452 | case 3: |
| 1453 | x->regs[1] = X86_INSN_GP_REG_BP; |
| 1454 | x->regs[2] = X86_INSN_GP_REG_SI + (modrm.rm & 1); |
| 1455 | x->flags |= X86_INSN_HAS_BASE | X86_INSN_HAS_INDEX; |
| 1456 | break; |
| 1457 | |
| 1458 | case 4: /* [si/di] */ |
| 1459 | case 5: |
| 1460 | x->regs[1] = X86_INSN_GP_REG_SI + (modrm.rm & 1); |
| 1461 | x->flags |= X86_INSN_HAS_BASE; |
| 1462 | break; |
| 1463 | |
| 1464 | case 6: /* [bp + disp] */ |
| 1465 | x->regs[1] = X86_INSN_GP_REG_BP; |
| 1466 | x->flags |= X86_INSN_HAS_BASE; |
| 1467 | break; |
| 1468 | |
| 1469 | case 7: /* [bx + disp] */ |
| 1470 | x->regs[1] = X86_INSN_GP_REG_BX; |
| 1471 | x->flags |= X86_INSN_HAS_BASE; |
| 1472 | break; |
| 1473 | } |
| 1474 | |
| 1475 | if (modrm.mode != 0) |
| 1476 | log2_disp_bytes = modrm.mode == 1 ? 0 : 1; |
| 1477 | break; |
| 1478 | } |
| 1479 | } |
| 1480 | |
| 1481 | if (log2_disp_bytes != ~0) |
| 1482 | { |
| 1483 | i64 disp; |
| 1484 | code = x86_insn_parse_number (log2_disp_bytes, code, code_end, |
| 1485 | &disp); |
| 1486 | if (code) |
| 1487 | x->displacement = disp; |
| 1488 | } |
| 1489 | } |
| 1490 | |
| 1491 | return code; |
| 1492 | } |
| 1493 | |
| 1494 | u8 * x86_insn_parse (x86_insn_parse_t * p, u8 * code_start) |
| 1495 | { |
| 1496 | u8 i, * code, * code_end; |
| 1497 | x86_insn_t * insn, * group_insn; |
| 1498 | u8 default_operand_bits, effective_operand_bits; |
| 1499 | u32 opcode, parse_flags; |
| 1500 | |
| 1501 | /* Preserve global parse flags. */ |
| 1502 | parse_flags = p->flags & (X86_INSN_PARSE_32_BIT | X86_INSN_PARSE_64_BIT); |
| 1503 | memset (p, 0, sizeof (p[0])); |
| 1504 | p->flags = parse_flags; |
| 1505 | |
| 1506 | /* 64 implies 32 bit parsing. */ |
| 1507 | if (parse_flags & X86_INSN_PARSE_64_BIT) |
| 1508 | parse_flags |= X86_INSN_PARSE_32_BIT; |
| 1509 | |
| 1510 | /* Instruction must be <= 15 bytes. */ |
| 1511 | code = code_start; |
| 1512 | code_end = code + 15; |
| 1513 | |
| 1514 | /* Parse legacy prefixes. */ |
| 1515 | while (1) |
| 1516 | { |
| 1517 | if (code >= code_end) |
| 1518 | goto insn_too_long; |
| 1519 | i = code[0]; |
| 1520 | code++; |
| 1521 | switch (i) |
| 1522 | { |
| 1523 | default: goto prefix_done; |
| 1524 | |
| 1525 | /* Set flags based on prefix. */ |
| 1526 | #define _(x,o) case o: p->flags |= X86_INSN_##x; break; |
| 1527 | foreach_x86_legacy_prefix; |
| 1528 | #undef _ |
| 1529 | } |
| 1530 | } |
| 1531 | prefix_done: |
| 1532 | |
| 1533 | /* REX prefix. */ |
| 1534 | if ((parse_flags & X86_INSN_PARSE_64_BIT) && i >= 0x40 && i <= 0x4f) |
| 1535 | { |
| 1536 | p->regs[0] |= ((i & (1 << 2)) != 0) << 3; /* r bit */ |
| 1537 | p->regs[1] |= ((i & (1 << 0)) != 0) << 3; /* b bit */ |
| 1538 | p->regs[2] |= ((i & (1 << 1)) != 0) << 3; /* x bit */ |
| 1539 | p->flags |= ((i & (1 << 3)) /* w bit */ |
| 1540 | ? X86_INSN_OPERAND_SIZE_64 : 0); |
| 1541 | if (code >= code_end) |
| 1542 | goto insn_too_long; |
| 1543 | i = *code++; |
| 1544 | } |
| 1545 | |
| 1546 | opcode = i; |
| 1547 | if (opcode == 0x0f) |
| 1548 | { |
| 1549 | /* two byte opcode. */; |
| 1550 | if (code >= code_end) |
| 1551 | goto insn_too_long; |
| 1552 | i = *code++; |
| 1553 | opcode = (opcode << 8) | i; |
| 1554 | insn = x86_insns_two_byte + i; |
| 1555 | } |
| 1556 | else |
| 1557 | { |
| 1558 | static x86_insn_t arpl = { |
| 1559 | .name = "arpl", |
| 1560 | .operands[0].data = "Ew", |
| 1561 | .operands[1].data = "Gw", |
| 1562 | }; |
| 1563 | |
| 1564 | if (PREDICT_FALSE (i == 0x63 |
| 1565 | && ! (parse_flags & X86_INSN_PARSE_64_BIT))) |
| 1566 | insn = &arpl; |
| 1567 | else |
| 1568 | insn = x86_insns_one_byte + i; |
| 1569 | } |
| 1570 | |
| 1571 | if ((i = X86_INSN_FLAG_GET_SSE_GROUP (insn->flags)) != 0) |
| 1572 | { |
| 1573 | x86_insn_group8_t * g8; |
| 1574 | |
| 1575 | if (p->flags & X86_INSN_OPERAND_SIZE) |
| 1576 | g8 = x86_insn_sse_groups_operand_size; |
| 1577 | else if (p->flags & X86_INSN_REPZ) |
| 1578 | g8 = x86_insn_sse_groups_repz; |
| 1579 | else if (p->flags & X86_INSN_REPNZ) |
| 1580 | g8 = x86_insn_sse_groups_repnz; |
| 1581 | else |
| 1582 | g8 = 0; |
| 1583 | |
| 1584 | /* insn flags have 1 + group so != 0 test above can work. */ |
| 1585 | ASSERT ((i - 1) < ARRAY_LEN (x86_insn_sse_groups_operand_size)); |
| 1586 | if (g8) |
| 1587 | insn = g8[i - 1].insns + (opcode & 7); |
| 1588 | } |
| 1589 | |
| 1590 | /* Parse modrm and displacement if present. */ |
| 1591 | if (x86_insn_has_modrm_byte (insn)) |
| 1592 | { |
| 1593 | x86_insn_modrm_byte_t modrm; |
| 1594 | |
| 1595 | if (code >= code_end) |
| 1596 | goto insn_too_long; |
| 1597 | modrm.byte = *code++; |
| 1598 | |
| 1599 | /* Handle special 0x0f01 and 0x0fae encodings. */ |
| 1600 | if (PREDICT_FALSE (modrm.mode == 3 |
| 1601 | && (opcode == 0x0f01 |
| 1602 | || opcode == 0x0fae))) |
| 1603 | { |
| 1604 | static x86_insn_t x86_insns_0f01_special[] = { |
| 1605 | _0 (swapgs), _0 (rdtscp), _0 (bad), _0 (bad), |
| 1606 | _0 (bad), _0 (bad), _0 (bad), _0 (bad), |
| 1607 | }; |
| 1608 | static x86_insn_t x86_insns_0fae_special[] = { |
| 1609 | _0 (vmrun), _0 (vmmcall), _0 (vmload), _0 (vmsave), |
| 1610 | _0 (stgi), _0 (clgi), _0 (skinit), _0 (invlpga), |
| 1611 | }; |
| 1612 | |
| 1613 | if (opcode == 0x0f01) |
| 1614 | insn = x86_insns_0f01_special; |
| 1615 | else |
| 1616 | insn = x86_insns_0fae_special; |
| 1617 | insn += modrm.rm; |
| 1618 | opcode = (opcode << 8) | modrm.byte; |
| 1619 | } |
| 1620 | else |
| 1621 | { |
| 1622 | code = x86_insn_parse_modrm_byte (p, modrm, parse_flags, |
| 1623 | code, code_end); |
| 1624 | if (! code) |
| 1625 | goto insn_too_long; |
| 1626 | } |
| 1627 | } |
| 1628 | |
| 1629 | group_insn = 0; |
| 1630 | if ((i = X86_INSN_FLAG_GET_MODRM_REG_GROUP (insn->flags)) != 0) |
| 1631 | { |
| 1632 | u32 g = i - 1; |
| 1633 | ASSERT (g < ARRAY_LEN (x86_insn_modrm_reg_groups)); |
| 1634 | group_insn = x86_insn_modrm_reg_groups[g].insns + (p->regs[0] & 7); |
| 1635 | } |
| 1636 | |
| 1637 | p->insn = insn[0]; |
| 1638 | if (group_insn) |
| 1639 | { |
| 1640 | u32 k; |
| 1641 | p->insn.name = group_insn->name; |
| 1642 | p->insn.flags |= group_insn->flags; |
| 1643 | for (k = 0; k < ARRAY_LEN (group_insn->operands); k++) |
| 1644 | if (x86_insn_operand_is_valid (group_insn, k)) |
| 1645 | p->insn.operands[k] = group_insn->operands[k]; |
| 1646 | } |
| 1647 | |
| 1648 | default_operand_bits |
| 1649 | = ((((parse_flags & X86_INSN_PARSE_32_BIT) != 0) |
| 1650 | ^ ((p->flags & X86_INSN_OPERAND_SIZE) != 0)) |
| 1651 | ? BITS (u32) : BITS (u16)); |
| 1652 | |
| 1653 | if ((parse_flags & X86_INSN_PARSE_64_BIT) |
| 1654 | && (p->insn.flags & X86_INSN_FLAG_DEFAULT_64_BIT)) |
| 1655 | default_operand_bits = BITS (u64); |
| 1656 | |
| 1657 | effective_operand_bits = default_operand_bits; |
| 1658 | if (p->flags & X86_INSN_OPERAND_SIZE_64) |
| 1659 | effective_operand_bits = BITS (u64); |
| 1660 | |
| 1661 | p->log2_effective_operand_bytes = 1; |
| 1662 | p->log2_effective_operand_bytes += effective_operand_bits > 16; |
| 1663 | p->log2_effective_operand_bytes += effective_operand_bits > 32; |
| 1664 | |
| 1665 | /* Parse immediate if present. */ |
| 1666 | { |
| 1667 | u32 l = x86_insn_log2_immediate_bytes (p, insn); |
| 1668 | if (l <= 3) |
| 1669 | { |
| 1670 | code = x86_insn_parse_number (l, code, code_end, &p->immediate); |
| 1671 | if (! code) |
| 1672 | goto insn_too_long; |
| 1673 | } |
| 1674 | } |
| 1675 | |
| 1676 | return code; |
| 1677 | |
| 1678 | insn_too_long: |
| 1679 | return 0; |
| 1680 | } |
| 1681 | |
| 1682 | static u8 * format_x86_gp_reg_operand (u8 * s, va_list * va) |
| 1683 | { |
| 1684 | u32 r = va_arg (*va, u32); |
| 1685 | u32 log2_n_bytes = va_arg (*va, u32); |
| 1686 | |
| 1687 | const char names8[8] = "acdbsbsd"; |
| 1688 | const char names16[8] = "xxxxppii"; |
| 1689 | |
| 1690 | ASSERT (r < 16); |
| 1691 | |
| 1692 | /* Add % register prefix. */ |
| 1693 | vec_add1 (s, '%'); |
| 1694 | |
| 1695 | switch (log2_n_bytes) |
| 1696 | { |
| 1697 | case 0: |
| 1698 | { |
| 1699 | |
| 1700 | if (r < 8) |
| 1701 | s = format (s, "%c%c", names8[r & 3], (r >> 2) ? 'l' : 'h'); |
| 1702 | else |
| 1703 | s = format (s, "r%db", r); |
| 1704 | } |
| 1705 | break; |
| 1706 | |
| 1707 | case 2: |
| 1708 | case 3: |
| 1709 | s = format (s, "%c", log2_n_bytes == 2 ? 'e' : 'r'); |
| 1710 | /* fall through */ |
| 1711 | case 1: |
| 1712 | if (r < 8) |
| 1713 | s = format (s, "%c%c", names8[r], names16[r]); |
| 1714 | else |
| 1715 | { |
| 1716 | s = format (s, "%d", r); |
| 1717 | if (log2_n_bytes != 3) |
| 1718 | s = format (s, "%c", log2_n_bytes == 1 ? 'w' : 'd'); |
| 1719 | } |
| 1720 | break; |
| 1721 | |
| 1722 | default: |
| 1723 | ASSERT (0); |
| 1724 | } |
| 1725 | |
| 1726 | return s; |
| 1727 | } |
| 1728 | |
| 1729 | static u8 * format_x86_reg_operand (u8 * s, va_list * va) |
| 1730 | { |
| 1731 | u32 reg = va_arg (*va, u32); |
| 1732 | u32 log2_n_bytes = va_arg (*va, u32); |
| 1733 | u32 type = va_arg (*va, u32); |
| 1734 | |
| 1735 | switch (type) |
| 1736 | { |
| 1737 | default: |
| 1738 | ASSERT (0); |
Dave Barach | f9c231e | 2016-08-05 10:10:18 -0400 | [diff] [blame] | 1739 | break; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1740 | |
| 1741 | case 'x': |
| 1742 | ASSERT (reg < 16); |
| 1743 | return format (s, "%%xmm%d", reg); |
| 1744 | |
| 1745 | case 'm': |
| 1746 | ASSERT (reg < 8); |
| 1747 | return format (s, "%%mm%d", reg); |
| 1748 | |
| 1749 | /* Explicit byte/word/double-word/quad-word */ |
| 1750 | case 'b': log2_n_bytes = 0; break; |
| 1751 | case 'w': log2_n_bytes = 1; break; |
| 1752 | case 'd': log2_n_bytes = 2; break; |
| 1753 | case 'q': log2_n_bytes = 3; break; |
| 1754 | |
| 1755 | /* Use effective operand size. */ |
| 1756 | case 'v': break; |
| 1757 | |
| 1758 | /* word or double-word depending on effective operand size. */ |
| 1759 | case 'z': |
| 1760 | log2_n_bytes = clib_min (log2_n_bytes, 2); |
| 1761 | break; |
| 1762 | } |
| 1763 | |
| 1764 | s = format (s, "%U", format_x86_gp_reg_operand, reg, log2_n_bytes); |
| 1765 | return s; |
| 1766 | } |
| 1767 | |
| 1768 | static u8 * format_x86_mem_operand (u8 * s, va_list * va) |
| 1769 | { |
| 1770 | x86_insn_parse_t * p = va_arg (*va, x86_insn_parse_t *); |
| 1771 | |
| 1772 | if (p->displacement != 0) |
| 1773 | s = format (s, "0x%x", p->displacement); |
| 1774 | |
| 1775 | if (p->flags & X86_INSN_HAS_BASE) |
| 1776 | { |
| 1777 | s = format (s, "(%U", |
| 1778 | format_x86_gp_reg_operand, p->regs[1], |
| 1779 | p->log2_effective_address_bytes); |
| 1780 | if (p->flags & X86_INSN_HAS_INDEX) |
| 1781 | { |
| 1782 | s = format (s, ",%U", |
| 1783 | format_x86_gp_reg_operand, p->regs[2], |
| 1784 | p->log2_effective_address_bytes); |
| 1785 | if (p->log2_index_scale != 0) |
| 1786 | s = format (s, ",%d", 1 << p->log2_index_scale); |
| 1787 | } |
| 1788 | s = format (s, ")"); |
| 1789 | } |
| 1790 | |
| 1791 | /* [RIP+disp] PC relative addressing in 64 bit mode. */ |
| 1792 | else if (p->flags & X86_INSN_PARSE_64_BIT) |
| 1793 | s = format (s, "(%%rip)"); |
| 1794 | |
| 1795 | return s; |
| 1796 | } |
| 1797 | |
| 1798 | static u8 * format_x86_insn_operand (u8 * s, va_list * va) |
| 1799 | { |
| 1800 | x86_insn_parse_t * p = va_arg (*va, x86_insn_parse_t *); |
| 1801 | x86_insn_t * insn = &p->insn; |
| 1802 | u32 o = va_arg (*va, u32); |
| 1803 | u8 c, t; |
| 1804 | |
| 1805 | ASSERT (o < ARRAY_LEN (insn->operands)); |
| 1806 | c = insn->operands[o].code; |
| 1807 | t = insn->operands[o].type; |
| 1808 | |
| 1809 | /* Register encoded in instruction. */ |
| 1810 | if (c < 8) |
| 1811 | return format (s, "%U", |
| 1812 | format_x86_gp_reg_operand, c, |
| 1813 | p->log2_effective_operand_bytes); |
| 1814 | |
| 1815 | switch (c) |
| 1816 | { |
| 1817 | /* Memory or reg field from modrm byte. */ |
| 1818 | case 'M': |
| 1819 | ASSERT (p->flags & X86_INSN_IS_ADDRESS); |
Dave Barach | f9c231e | 2016-08-05 10:10:18 -0400 | [diff] [blame] | 1820 | /* FALLTHROUGH */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1821 | case 'E': |
| 1822 | if (p->flags & X86_INSN_IS_ADDRESS) |
| 1823 | s = format (s, "%U", format_x86_mem_operand, p); |
| 1824 | else |
| 1825 | s = format (s, "%U", |
| 1826 | format_x86_reg_operand, p->regs[1], |
| 1827 | p->log2_effective_operand_bytes, t); |
| 1828 | break; |
| 1829 | |
| 1830 | /* reg field from modrm byte. */ |
| 1831 | case 'R': |
| 1832 | case 'G': |
| 1833 | s = format (s, "%U", |
| 1834 | format_x86_reg_operand, p->regs[0], |
| 1835 | p->log2_effective_operand_bytes, t); |
| 1836 | break; |
| 1837 | |
| 1838 | case 'I': |
| 1839 | { |
| 1840 | u32 l = x86_insn_log2_immediate_bytes (p, insn); |
Dave Barach | f9c231e | 2016-08-05 10:10:18 -0400 | [diff] [blame] | 1841 | i64 mask = pow2_mask (8ULL << l); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1842 | s = format (s, "$0x%Lx", p->immediate & mask); |
| 1843 | } |
| 1844 | break; |
| 1845 | |
| 1846 | case 'J': |
| 1847 | if (p->immediate < 0) |
| 1848 | s = format (s, "- 0x%Lx", -p->immediate); |
| 1849 | else |
| 1850 | s = format (s, "+ 0x%Lx", p->immediate); |
| 1851 | break; |
| 1852 | |
| 1853 | case 'O': |
| 1854 | s = format (s, "0x%Lx", p->immediate); |
| 1855 | break; |
| 1856 | |
| 1857 | case 'A': |
| 1858 | /* AX/AL */ |
| 1859 | s = format (s, "%U", |
| 1860 | format_x86_gp_reg_operand, X86_INSN_GP_REG_AX, |
| 1861 | t == 'L' ? 0 : p->log2_effective_operand_bytes); |
| 1862 | break; |
| 1863 | |
| 1864 | case 'B': |
| 1865 | /* BX/BL/BP */ |
| 1866 | s = format (s, "%U", |
| 1867 | format_x86_gp_reg_operand, |
| 1868 | t == 'P' ? X86_INSN_GP_REG_BP : X86_INSN_GP_REG_BX, |
| 1869 | t == 'L' ? 0 : p->log2_effective_operand_bytes); |
| 1870 | break; |
| 1871 | |
| 1872 | case 'C': |
| 1873 | /* CX/CL */ |
| 1874 | s = format (s, "%U", |
| 1875 | format_x86_gp_reg_operand, X86_INSN_GP_REG_CX, |
| 1876 | t == 'L' ? 0 : p->log2_effective_operand_bytes); |
| 1877 | break; |
| 1878 | |
| 1879 | case 'D': |
| 1880 | /* DX/DL/DI */ |
| 1881 | s = format (s, "%U", |
| 1882 | format_x86_gp_reg_operand, |
| 1883 | t == 'I' ? X86_INSN_GP_REG_DI : X86_INSN_GP_REG_DX, |
| 1884 | t == 'L' ? 0 : p->log2_effective_operand_bytes); |
| 1885 | break; |
| 1886 | |
| 1887 | case 'S': |
| 1888 | /* SI/SP */ |
| 1889 | s = format (s, "%U", |
| 1890 | format_x86_gp_reg_operand, |
| 1891 | t == 'I' ? X86_INSN_GP_REG_SI : X86_INSN_GP_REG_SP, |
| 1892 | p->log2_effective_operand_bytes); |
| 1893 | break; |
| 1894 | |
| 1895 | case '1': |
| 1896 | s = format (s, "1"); |
| 1897 | break; |
| 1898 | |
| 1899 | default: |
| 1900 | ASSERT (0); |
| 1901 | } |
| 1902 | |
| 1903 | return s; |
| 1904 | } |
| 1905 | |
| 1906 | u8 * format_x86_insn_parse (u8 * s, va_list * va) |
| 1907 | { |
| 1908 | x86_insn_parse_t * p = va_arg (*va, x86_insn_parse_t *); |
| 1909 | x86_insn_t * insn = &p->insn; |
| 1910 | u32 o, i, is_src_dst; |
| 1911 | |
| 1912 | s = format (s, "%s", insn->name); |
| 1913 | |
| 1914 | if (! x86_insn_operand_is_valid (insn, 0)) |
| 1915 | goto done; |
| 1916 | |
| 1917 | is_src_dst = x86_insn_operand_is_valid (insn, 1); |
| 1918 | |
| 1919 | /* If instruction has immediate add suffix to opcode to |
| 1920 | indicate operand size. */ |
| 1921 | if (is_src_dst) |
| 1922 | { |
| 1923 | u32 b; |
| 1924 | |
| 1925 | b = x86_insn_log2_immediate_bytes (p, insn); |
| 1926 | if (b < p->log2_effective_operand_bytes |
| 1927 | && (p->flags & X86_INSN_IS_ADDRESS)) |
| 1928 | s = format (s, "%c", "bwlq"[b]); |
| 1929 | } |
| 1930 | |
| 1931 | for (i = 0; i < ARRAY_LEN (insn->operands); i++) |
| 1932 | { |
| 1933 | o = is_src_dst + i; |
| 1934 | if (! x86_insn_operand_is_valid (insn, o)) |
| 1935 | break; |
| 1936 | s = format (s, "%s%U", |
| 1937 | i == 0 ? " " : ", ", |
| 1938 | format_x86_insn_operand, p, o); |
| 1939 | } |
| 1940 | |
| 1941 | if (is_src_dst) |
| 1942 | s = format (s, ", %U", |
| 1943 | format_x86_insn_operand, p, 0); |
| 1944 | |
| 1945 | done: |
| 1946 | return s; |
| 1947 | } |