Skip to content

Commit

Permalink
Add decode/encode support for Intel's ENQCMD extension. (#7105)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
khuey authored Dec 7, 2024
1 parent b0237d2 commit 3207841
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 3 deletions.
16 changes: 14 additions & 2 deletions core/ir/x86/decode_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -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],
};


Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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 */
Expand Down
4 changes: 3 additions & 1 deletion core/ir/x86/disassemble.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
4 changes: 4 additions & 0 deletions core/ir/x86/instr_create_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
4 changes: 4 additions & 0 deletions core/ir/x86/opcode_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
46 changes: 46 additions & 0 deletions suite/tests/api/ir_x86_2args_mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
40 changes: 40 additions & 0 deletions third_party/binutils/test_decenc/drdecode_decenc_x86.expect
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 40 additions & 0 deletions third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect
Original file line number Diff line number Diff line change
Expand Up @@ -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 <rel> 0x0000000010070b49, %rcx
00 00
67 f2 0f 38 f8 0d 00 enqcmd <rel> 0x0000000010070b53, %ecx
00 00 00
f3 0f 38 f8 0d 00 00 enqcmds <rel> 0x0000000010070b5c, %rcx
00 00
67 f3 0f 38 f8 0d 00 enqcmds <rel> 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 <rel> 0x0000000010070baf, %rcx
00 00
67 f2 0f 38 f8 0d 00 enqcmd <rel> 0x0000000010070bb9, %ecx
00 00 00
f3 0f 38 f8 0d 00 00 enqcmds <rel> 0x0000000010070bc2, %rcx
00 00
67 f3 0f 38 f8 0d 00 enqcmds <rel> 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
Expand Down
19 changes: 19 additions & 0 deletions third_party/binutils/test_decenc/test_decenc_x86.asm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
26 changes: 26 additions & 0 deletions third_party/binutils/test_decenc/test_decenc_x86_64.asm
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 3207841

Please sign in to comment.