From 3207841e504768447081f1aab54564cffbc4a0d4 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 6 Dec 2024 17:54:51 -0800 Subject: [PATCH] Add decode/encode support for Intel's ENQCMD extension. (#7105) Add the ENQCMD/ENQCMDS instructions. Because they are patterned identically to MOVDIR64B the changes are very straightforward. MOD_EXT entries are added because the upcoming USER_MSR extension will use the modrm.mod == 3 slots for these opcodes. --- core/ir/x86/decode_table.c | 16 ++++++- core/ir/x86/disassemble.c | 4 +- core/ir/x86/instr_create_api.h | 4 ++ core/ir/x86/opcode_api.h | 4 ++ suite/tests/api/ir_x86_2args_mm.h | 46 +++++++++++++++++++ .../test_decenc/drdecode_decenc_x86.expect | 40 ++++++++++++++++ .../test_decenc/drdecode_decenc_x86_64.expect | 40 ++++++++++++++++ .../binutils/test_decenc/test_decenc_x86.asm | 19 ++++++++ .../test_decenc/test_decenc_x86_64.asm | 26 +++++++++++ 9 files changed, 196 insertions(+), 3 deletions(-) diff --git a/core/ir/x86/decode_table.c b/core/ir/x86/decode_table.c index dc1ca5b24ca..8997e730f67 100644 --- a/core/ir/x86/decode_table.c +++ b/core/ir/x86/decode_table.c @@ -1648,6 +1648,10 @@ const instr_info_t * const op_instr[] = /* MOVDIR64B */ /* OP_movdir64b */ &prefix_extensions[192][2], + + /* ENQCMD */ + /* OP_enqcmd */ &mod_extensions[122][0], + /* OP_enqcmds */ &mod_extensions[121][0], }; @@ -5915,9 +5919,9 @@ const instr_info_t prefix_extensions[][12] = { {INVALID, 0xf201e808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA}, },{ /* prefix extension 192 */ {INVALID, 0x38f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA}, - {INVALID, 0xf338f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA}, + {MOD_EXT, 0xf338f808, catUncategorized, "(mod ext 121)", xx, xx, xx, xx, xx, no, x, 121}, {OP_movdir64b, 0x6638f808, catMove, "movdir64b", GesvS_oq, xx, Moq, xx, xx, mrm, x, END_LIST}, - {INVALID, 0xf238f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA}, + {MOD_EXT, 0xf238f808, catUncategorized, "(mod ext 122)", xx, xx, xx, xx, xx, no, x, 122}, {INVALID, 0x38f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA}, {INVALID, 0xf338f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA}, {INVALID, 0x6638f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA}, @@ -7056,6 +7060,14 @@ const instr_info_t mod_extensions[][2] = { {INVALID, 0x0f0135, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, END_LIST}, {RM_EXT, 0x0f0175, catUncategorized, "(group 7 mod + rm ext 5)", xx, xx, xx, xx, xx, mrm, x, 5}, }, + { /* mod extension 121 */ + {OP_enqcmds, 0xf338f808, catMove | catOther, "enqcmds", GesvS_oq, xx, Moq, xx, xx, mrm, fW6, END_LIST}, + {INVALID, 0xf338f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, END_LIST}, + }, + { /* mod extension 122 */ + {OP_enqcmd, 0xf238f808, catMove | catOther, "enqcmd", GesvS_oq, xx, Moq, xx, xx, mrm, fW6, END_LIST}, + {INVALID, 0xf238f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, END_LIST}, + }, }; /* Naturally all of these have modrm bytes even if they have no explicit operands */ diff --git a/core/ir/x86/disassemble.c b/core/ir/x86/disassemble.c index 58ddb818060..0ec7ca0a5e1 100644 --- a/core/ir/x86/disassemble.c +++ b/core/ir/x86/disassemble.c @@ -290,7 +290,9 @@ suppress_memory_size_annotations(instr_t *instr) * TYPE_G_ES_VAR_REG_SIZE but this is sufficient for now. */ switch (instr_get_opcode(instr)) { - case OP_movdir64b: return true; + case OP_movdir64b: + case OP_enqcmd: + case OP_enqcmds: return true; default: return false; } } diff --git a/core/ir/x86/instr_create_api.h b/core/ir/x86/instr_create_api.h index 7320eebc4c9..7cca6983275 100644 --- a/core/ir/x86/instr_create_api.h +++ b/core/ir/x86/instr_create_api.h @@ -1583,6 +1583,10 @@ /* MOVDIR64B */ #define INSTR_CREATE_movdir64b(dc, d, s) \ instr_create_1dst_1src((dc), OP_movdir64b, (d), (s)) +/* ENQCMD */ +#define INSTR_CREATE_enqcmd(dc, d, s) instr_create_1dst_1src((dc), OP_enqcmd, (d), (s)) +#define INSTR_CREATE_enqcmds(dc, d, s) instr_create_1dst_1src((dc), OP_enqcmds, (d), (s)) + /** @} */ /* end doxygen group */ /* 1 destination, 1 implicit source */ diff --git a/core/ir/x86/opcode_api.h b/core/ir/x86/opcode_api.h index 4d824aaa5de..ec2aee77f58 100644 --- a/core/ir/x86/opcode_api.h +++ b/core/ir/x86/opcode_api.h @@ -1635,6 +1635,10 @@ enum { /* MOVDIR64B */ /* 1445 */ OP_movdir64b, /**< IA-32/AMD64 movdir64b opcode. */ + /* ENQCMD */ + /* 1446 */ OP_enqcmd, /**< IA-32/AMD64 enqcmd opcode. */ + /* 1447 */ OP_enqcmds, /**< IA-32/AMD64 enqcmds opcode. */ + OP_AFTER_LAST, OP_FIRST = OP_add, /**< First real opcode. */ OP_LAST = OP_AFTER_LAST - 1, /**< Last real opcode. */ diff --git a/suite/tests/api/ir_x86_2args_mm.h b/suite/tests/api/ir_x86_2args_mm.h index 0f1412b8eac..f467ec3381b 100644 --- a/suite/tests/api/ir_x86_2args_mm.h +++ b/suite/tests/api/ir_x86_2args_mm.h @@ -353,3 +353,49 @@ OPCODE(movdir64b64, movdir64b, movdir64b, X64_ONLY, OPCODE(movdir64b64lohi, movdir64b, movdir64b, X64_ONLY, opnd_create_far_base_disp(DR_SEG_ES, DR_REG_R9, DR_REG_NULL, 0, 0, OPSZ_64), MEMARG(OPSZ_64)) + +/* ENQCMD */ +/* NB: We can never use MEMARG for the dst because we need the segment selector. */ +/* NB: Can't use MEMARG for the src because it doesn't work with addr16 prefix. */ +OPCODE(enqcmd16, enqcmd, enqcmd, X86_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_AX, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_SI, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +/* NB: Can't use MEMARG for the src because the base register needs to be the size of EAX. + */ +OPCODE(enqcmd32, enqcmd, enqcmd, 0, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_EAX, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_ECX, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +OPCODE(enqcmd32lohi, enqcmd, enqcmd, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_R8D, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_ECX, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +OPCODE(enqcmd32hilo, enqcmd, enqcmd, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_EAX, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_R9D, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +OPCODE(enqcmd64, enqcmd, enqcmd, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_RAX, DR_REG_NULL, 0, 0, OPSZ_64), + MEMARG(OPSZ_64)) +OPCODE(enqcmd64lohi, enqcmd, enqcmd, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_R9, DR_REG_NULL, 0, 0, OPSZ_64), + MEMARG(OPSZ_64)) + +/* NB: Can't use MEMARG for the src because it doesn't work with addr16 prefix. */ +OPCODE(enqcmds16, enqcmds, enqcmds, X86_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_AX, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_SI, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +/* NB: Can't use MEMARG for the src because the base register needs to be the size of EAX. + */ +OPCODE(enqcmds32, enqcmds, enqcmds, 0, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_EAX, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_ECX, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +OPCODE(enqcmds32lohi, enqcmds, enqcmds, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_R8D, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_ECX, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +OPCODE(enqcmds32hilo, enqcmds, enqcmds, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_EAX, DR_REG_NULL, 0, 0, OPSZ_64), + opnd_create_base_disp(DR_REG_R9D, DR_REG_NULL, 0, memarg_disp, OPSZ_64)) +OPCODE(enqcmds64, enqcmds, enqcmds, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_RAX, DR_REG_NULL, 0, 0, OPSZ_64), + MEMARG(OPSZ_64)) +OPCODE(enqcmds64lohi, enqcmds, enqcmds, X64_ONLY, + opnd_create_far_base_disp(DR_SEG_ES, DR_REG_R9, DR_REG_NULL, 0, 0, OPSZ_64), + MEMARG(OPSZ_64)) diff --git a/third_party/binutils/test_decenc/drdecode_decenc_x86.expect b/third_party/binutils/test_decenc/drdecode_decenc_x86.expect index f199a399912..d587700cb67 100644 --- a/third_party/binutils/test_decenc/drdecode_decenc_x86.expect +++ b/third_party/binutils/test_decenc/drdecode_decenc_x86.expect @@ -138870,6 +138870,46 @@ test_s: 90 nop 90 nop 90 nop + f2 0f 38 f8 01 enqcmd (%ecx), %eax + 67 f2 0f 38 f8 04 enqcmd (%si), %ax + f3 0f 38 f8 01 enqcmds (%ecx), %eax + 67 f3 0f 38 f8 04 enqcmds (%si), %ax + 67 f2 0f 38 f8 0e 00 enqcmd 0x00, %cx + 00 + 67 f2 0f 38 f8 0e 34 enqcmd 0x1234, %cx + 12 + 67 f3 0f 38 f8 0e 00 enqcmds 0x00, %cx + 00 + 67 f3 0f 38 f8 0e 34 enqcmds 0x1234, %cx + 12 + f2 0f 38 f8 01 enqcmd (%ecx), %eax + 67 f2 0f 38 f8 04 enqcmd (%si), %ax + f3 0f 38 f8 01 enqcmds (%ecx), %eax + 67 f3 0f 38 f8 04 enqcmds (%si), %ax + 67 f2 0f 38 f8 0e 00 enqcmd 0x00, %cx + 00 + 67 f2 0f 38 f8 0e 34 enqcmd 0x1234, %cx + 12 + 67 f3 0f 38 f8 0e 00 enqcmds 0x00, %cx + 00 + 67 f3 0f 38 f8 0e 34 enqcmds 0x1234, %cx + 12 + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop + 90 nop 90 nop 90 nop 90 nop diff --git a/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect b/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect index ecc4c96c11b..6f5060dc2f3 100644 --- a/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect +++ b/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect @@ -102877,6 +102877,46 @@ test_x86_64_s: 00 00 00 00 67 66 0f 38 f8 0c 25 movdir64b 0x12345678, %ecx 78 56 34 12 + f2 0f 38 f8 01 enqcmd (%rcx), %rax + 67 f2 0f 38 f8 01 enqcmd (%ecx), %eax + f3 0f 38 f8 01 enqcmds (%rcx), %rax + 67 f3 0f 38 f8 01 enqcmds (%ecx), %eax + f2 0f 38 f8 0d 00 00 enqcmd 0x0000000010070b49, %rcx + 00 00 + 67 f2 0f 38 f8 0d 00 enqcmd 0x0000000010070b53, %ecx + 00 00 00 + f3 0f 38 f8 0d 00 00 enqcmds 0x0000000010070b5c, %rcx + 00 00 + 67 f3 0f 38 f8 0d 00 enqcmds 0x0000000010070b66, %ecx + 00 00 00 + f2 0f 38 f8 0c 25 00 enqcmd 0x00, %rcx + 00 00 00 + 67 f2 0f 38 f8 0c 25 enqcmd 0x00, %ecx + 00 00 00 00 + f3 0f 38 f8 0c 25 00 enqcmds 0x00, %rcx + 00 00 00 + 67 f3 0f 38 f8 0c 25 enqcmds 0x00, %ecx + 00 00 00 00 + f2 0f 38 f8 01 enqcmd (%rcx), %rax + 67 f2 0f 38 f8 01 enqcmd (%ecx), %eax + f3 0f 38 f8 01 enqcmds (%rcx), %rax + 67 f3 0f 38 f8 01 enqcmds (%ecx), %eax + f2 0f 38 f8 0d 00 00 enqcmd 0x0000000010070baf, %rcx + 00 00 + 67 f2 0f 38 f8 0d 00 enqcmd 0x0000000010070bb9, %ecx + 00 00 00 + f3 0f 38 f8 0d 00 00 enqcmds 0x0000000010070bc2, %rcx + 00 00 + 67 f3 0f 38 f8 0d 00 enqcmds 0x0000000010070bcc, %ecx + 00 00 00 + f2 0f 38 f8 0c 25 00 enqcmd 0x00, %rcx + 00 00 00 + 67 f2 0f 38 f8 0c 25 enqcmd 0x00, %ecx + 00 00 00 00 + f3 0f 38 f8 0c 25 00 enqcmds 0x00, %rcx + 00 00 00 + 67 f3 0f 38 f8 0c 25 enqcmds 0x00, %ecx + 00 00 00 00 0f 01 ca clac 0f 01 cb stac 90 nop diff --git a/third_party/binutils/test_decenc/test_decenc_x86.asm b/third_party/binutils/test_decenc/test_decenc_x86.asm index 3058afd345c..836767c7928 100644 --- a/third_party/binutils/test_decenc/test_decenc_x86.asm +++ b/third_party/binutils/test_decenc/test_decenc_x86.asm @@ -139910,5 +139910,24 @@ GLOBAL_LABEL(FUNCNAME:) RAW(67) RAW(66) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(34) RAW(12) END_OF_SUBTEST_MARKER + /* enqcmd.s */ + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(04) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(04) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(00) RAW(00) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(34) RAW(12) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(00) RAW(00) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(34) RAW(12) + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(04) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(04) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(00) RAW(00) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(34) RAW(12) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(00) RAW(00) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0e) RAW(34) RAW(12) + END_OF_SUBTEST_MARKER + END_OF_FUNCTION_MARKER END_FUNC(FUNCNAME) diff --git a/third_party/binutils/test_decenc/test_decenc_x86_64.asm b/third_party/binutils/test_decenc/test_decenc_x86_64.asm index 323f4729e5c..c3c8a057e78 100644 --- a/third_party/binutils/test_decenc/test_decenc_x86_64.asm +++ b/third_party/binutils/test_decenc/test_decenc_x86_64.asm @@ -106699,6 +106699,32 @@ GLOBAL_LABEL(FUNCNAME:) RAW(67) RAW(66) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) RAW(67) RAW(66) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(78) RAW(56) RAW(34) RAW(12) + /* x86_64_enqcmd.s */ + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(01) + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0d) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f2) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + RAW(67) RAW(f3) RAW(0f) RAW(38) RAW(f8) RAW(0c) RAW(25) RAW(00) RAW(00) RAW(00) RAW(00) + /* TODO i#5505: Move the following back under * x86_64_arch_3.s in a separate PR to keep the huge * diff isolated from PR #6484.