@@ -1,5 +1,7 @@
-*- text -*-
+* Add support for the x86 Intel MSR_IMM instructions.
+
* Add support for Intel AVX10.2 instructions.
* Add support for the x86 Zhaoxin GMI instructions.
@@ -1221,6 +1221,7 @@ static const arch_entry cpu_arch[] =
SUBARCH (apx_f, APX_F, APX_F, false),
VECARCH (avx10.2, AVX10_2, ANY_AVX10_2, set),
SUBARCH (gmi, GMI, GMI, false),
+ SUBARCH (msr_imm, MSR_IMM, MSR_IMM, false),
};
#undef SUBARCH
@@ -2233,7 +2234,8 @@ cpu_flags_match (const insn_template *t)
&& (any.bitfield.cpubmi || any.bitfield.cpubmi2
|| any.bitfield.cpuavx512f || any.bitfield.cpuavx512bw
|| any.bitfield.cpuavx512dq || any.bitfield.cpuamx_tile
- || any.bitfield.cpucmpccxadd || any.bitfield.cpuuser_msr))
+ || any.bitfield.cpucmpccxadd || any.bitfield.cpuuser_msr
+ || any.bitfield.cpumsr_imm))
{
/* These checks (verifying that APX_F() was properly used in the
opcode table entry) make sure there's no need for an "else" to
@@ -4037,7 +4039,8 @@ install_template (const insn_template *t)
if ((maybe_cpu (t, CpuCMPCCXADD) || maybe_cpu (t, CpuAMX_TILE)
|| maybe_cpu (t, CpuAVX512F) || maybe_cpu (t, CpuAVX512DQ)
|| maybe_cpu (t, CpuAVX512BW) || maybe_cpu (t, CpuBMI)
- || maybe_cpu (t, CpuBMI2) || maybe_cpu (t, CpuUSER_MSR))
+ || maybe_cpu (t, CpuBMI2) || maybe_cpu (t, CpuUSER_MSR)
+ || maybe_cpu (t, CpuMSR_IMM))
&& maybe_cpu (t, CpuAPX_F))
{
if (need_evex_encoding (t))
@@ -6990,18 +6993,20 @@ i386_assemble (char *line)
because of the swapping above) in the incoming set of operands. */
if ((i.imm_operands == 2
&& (t->mnem_off == MN_extrq || t->mnem_off == MN_insertq))
- || (t->mnem_off == MN_uwrmsr && i.imm_operands
- && i.operands > i.imm_operands))
+ || ((t->mnem_off == MN_uwrmsr || t->mnem_off == MN_wrmsrns)
+ && i.imm_operands && i.operands > i.imm_operands))
swap_2_operands (0, 1);
if (i.imm_operands)
{
- /* For USER_MSR instructions, imm32 stands for the name of an model specific
- register (MSR). That's an unsigned quantity, whereas all other insns with
- 32-bit immediate and 64-bit operand size use sign-extended
- immediates (imm32s). Therefore these insns are special-cased, bypassing
- the normal handling of immediates here. */
- if (is_cpu(current_templates.start, CpuUSER_MSR))
+ /* For USER_MSR and MSR_IMM instructions, imm32 stands for the name of a
+ model specific register (MSR). That's an unsigned quantity, whereas all
+ other insns with 32-bit immediate and 64-bit operand size use
+ sign-extended immediates (imm32s). Therefore these insns are
+ special-cased, bypassing the normal handling of immediates here. */
+ if (is_cpu(current_templates.start, CpuUSER_MSR)
+ || t->mnem_off == MN_rdmsr
+ || t->mnem_off == MN_wrmsrns)
{
for (j = 0; j < i.operands; j++)
{
@@ -218,6 +218,7 @@ accept various extension mnemonics. For example,
@code{avx10.1/256},
@code{avx10.1/128},
@code{user_msr},
+@code{msr_imm},
@code{apx_f},
@code{avx10.2},
@code{avx10.2/512},
@@ -1694,7 +1695,7 @@ supported on the CPU specified. The choices for @var{cpu_type} are:
@item @samp{.cmpccxadd} @tab @samp{.wrmsrns} @tab @samp{.msrlist}
@item @samp{.avx_ne_convert} @tab @samp{.rao_int} @tab @samp{.fred} @tab @samp{.lkgs}
@item @samp{.avx_vnni_int16} @tab @samp{.sha512} @tab @samp{.sm3} @tab @samp{.sm4}
-@item @samp{.pbndkb} @tab @samp{.user_msr} @tab @samp{.avx10.2}
+@item @samp{.pbndkb} @tab @samp{.user_msr} @tab @samp{.msr_imm} @tab @samp{.avx10.2}
@item @samp{.wbnoinvd} @tab @samp{.pconfig} @tab @samp{.waitpkg} @tab @samp{.cldemote}
@item @samp{.shstk} @tab @samp{.gfni} @tab @samp{.vaes} @tab @samp{.vpclmulqdq}
@item @samp{.movdiri} @tab @samp{.movdir64b} @tab @samp{.enqcmd} @tab @samp{.tsxldtrk}
@@ -519,6 +519,7 @@ if [gas_32_check] then {
run_dump_test "sm4-intel"
run_list_test "pbndkb-inval"
run_list_test "user_msr-inval"
+ run_list_test "msr_imm-inval"
run_list_test "apx-push2pop2-inval"
run_dump_test "avx10_2-rounding"
run_dump_test "avx10_2-rounding-intel"
new file mode 100644
@@ -0,0 +1,3 @@
+.* Assembler messages:
+.*:5: Error: unsupported instruction `rdmsr'
+.*:6: Error: unsupported instruction `wrmsrns'
new file mode 100644
@@ -0,0 +1,6 @@
+# Check Illegal 32bit MSR_IMM instructions
+
+ .text
+_start:
+ rdmsr $51515151, %eax
+ wrmsrns %eax, $51515151
new file mode 100644
@@ -0,0 +1,35 @@
+#as:
+#objdump: -dw -Mintel
+#name: x86_64 MSR_IMM insns (Intel disassembly)
+#source: x86-64-msr_imm.s
+
+.*: +file format .*
+
+Disassembly of section \.text:
+
+0+ <_start>:
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 0f 0f 12 03\s+rdmsr r12,0x3120f0f
+\s*[a-f0-9]+:\s*c4 e7 7b f6 c0 0f 0f 12 03\s+rdmsr rax,0x3120f0f
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 7f 00 00 00\s+rdmsr r12,0x7f
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 ff 7f 00 00\s+rdmsr r12,0x7fff
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 00 00 00 80\s+rdmsr r12,0x80000000
+\s*[a-f0-9]+:\s*62 df 7f 08 f6 c0 0f 0f 12 03\s+rdmsr r24,0x3120f0f
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 0f 0f 12 03\s+wrmsrns 0x3120f0f,r12
+\s*[a-f0-9]+:\s*c4 e7 7a f6 c0 0f 0f 12 03\s+wrmsrns 0x3120f0f,rax
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 7f 00 00 00\s+wrmsrns 0x7f,r12
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 ff 7f 00 00\s+wrmsrns 0x7fff,r12
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 00 00 00 80\s+wrmsrns 0x80000000,r12
+\s*[a-f0-9]+:\s*62 df 7e 08 f6 c0 0f 0f 12 03\s+wrmsrns 0x3120f0f,r24
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 0f 0f 12 03\s+rdmsr r12,0x3120f0f
+\s*[a-f0-9]+:\s*c4 e7 7b f6 c0 0f 0f 12 03\s+rdmsr rax,0x3120f0f
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 7f 00 00 00\s+rdmsr r12,0x7f
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 ff 7f 00 00\s+rdmsr r12,0x7fff
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 00 00 00 80\s+rdmsr r12,0x80000000
+\s*[a-f0-9]+:\s*62 df 7f 08 f6 c0 0f 0f 12 03\s+rdmsr r24,0x3120f0f
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 0f 0f 12 03\s+wrmsrns 0x3120f0f,r12
+\s*[a-f0-9]+:\s*c4 e7 7a f6 c0 0f 0f 12 03\s+wrmsrns 0x3120f0f,rax
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 7f 00 00 00\s+wrmsrns 0x7f,r12
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 ff 7f 00 00\s+wrmsrns 0x7fff,r12
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 00 00 00 80\s+wrmsrns 0x80000000,r12
+\s*[a-f0-9]+:\s*62 df 7e 08 f6 c0 0f 0f 12 03\s+wrmsrns 0x3120f0f,r24
+#pass
new file mode 100644
@@ -0,0 +1,5 @@
+.* Assembler messages:
+.*:5: Error: operand type mismatch for `rdmsr'
+.*:6: Error: operand type mismatch for `rdmsr'
+.*:7: Error: operand type mismatch for `wrmsrns'
+.*:8: Error: operand type mismatch for `wrmsrns'
new file mode 100644
@@ -0,0 +1,8 @@
+# Check Illegal 64bit MSR_IMM instructions
+
+ .text
+_start:
+ rdmsr $5151515151515151, %r12
+ rdmsr $-515151, %r12
+ wrmsrns %r12, $5151515151515151
+ wrmsrns %r12, $-515151
new file mode 100644
@@ -0,0 +1,35 @@
+#as:
+#objdump: -dw
+#name: x86_64 MSR_IMM insns
+#source: x86-64-msr_imm.s
+
+.*: +file format .*
+
+Disassembly of section \.text:
+
+0+ <_start>:
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 0f 0f 12 03\s+rdmsr\s+\$0x3120f0f,%r12
+\s*[a-f0-9]+:\s*c4 e7 7b f6 c0 0f 0f 12 03\s+rdmsr\s+\$0x3120f0f,%rax
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 7f 00 00 00\s+rdmsr\s+\$0x7f,%r12
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 ff 7f 00 00\s+rdmsr\s+\$0x7fff,%r12
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 00 00 00 80\s+rdmsr\s+\$0x80000000,%r12
+\s*[a-f0-9]+:\s*62 df 7f 08 f6 c0 0f 0f 12 03\s+rdmsr\s+\$0x3120f0f,%r24
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 0f 0f 12 03\s+wrmsrns\s+%r12,\$0x3120f0f
+\s*[a-f0-9]+:\s*c4 e7 7a f6 c0 0f 0f 12 03\s+wrmsrns\s+%rax,\$0x3120f0f
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 7f 00 00 00\s+wrmsrns\s+%r12,\$0x7f
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 ff 7f 00 00\s+wrmsrns\s+%r12,\$0x7fff
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 00 00 00 80\s+wrmsrns\s+%r12,\$0x80000000
+\s*[a-f0-9]+:\s*62 df 7e 08 f6 c0 0f 0f 12 03\s+wrmsrns\s+%r24,\$0x3120f0f
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 0f 0f 12 03\s+rdmsr\s+\$0x3120f0f,%r12
+\s*[a-f0-9]+:\s*c4 e7 7b f6 c0 0f 0f 12 03\s+rdmsr\s+\$0x3120f0f,%rax
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 7f 00 00 00\s+rdmsr\s+\$0x7f,%r12
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 ff 7f 00 00\s+rdmsr\s+\$0x7fff,%r12
+\s*[a-f0-9]+:\s*c4 c7 7b f6 c4 00 00 00 80\s+rdmsr\s+\$0x80000000,%r12
+\s*[a-f0-9]+:\s*62 df 7f 08 f6 c0 0f 0f 12 03\s+rdmsr\s+\$0x3120f0f,%r24
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 0f 0f 12 03\s+wrmsrns\s+%r12,\$0x3120f0f
+\s*[a-f0-9]+:\s*c4 e7 7a f6 c0 0f 0f 12 03\s+wrmsrns\s+%rax,\$0x3120f0f
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 7f 00 00 00\s+wrmsrns\s+%r12,\$0x7f
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 ff 7f 00 00\s+wrmsrns\s+%r12,\$0x7fff
+\s*[a-f0-9]+:\s*c4 c7 7a f6 c4 00 00 00 80\s+wrmsrns\s+%r12,\$0x80000000
+\s*[a-f0-9]+:\s*62 df 7e 08 f6 c0 0f 0f 12 03\s+wrmsrns\s+%r24,\$0x3120f0f
+#pass
new file mode 100644
@@ -0,0 +1,30 @@
+# Check 64bit MSR_IMM instructions
+
+ .text
+_start:
+ rdmsr $51515151, %r12
+ rdmsr $51515151, %rax
+ rdmsr $0x7f, %r12
+ rdmsr $0x7fff, %r12
+ rdmsr $0x80000000, %r12
+ rdmsr $51515151, %r24
+ wrmsrns %r12, $51515151
+ wrmsrns %rax, $51515151
+ wrmsrns %r12, $0x7f
+ wrmsrns %r12, $0x7fff
+ wrmsrns %r12, $0x80000000
+ wrmsrns %r24, $51515151
+
+ .intel_syntax noprefix
+ rdmsr r12, 51515151
+ rdmsr rax, 51515151
+ rdmsr r12, 0x7f
+ rdmsr r12, 0x7fff
+ rdmsr r12, 0x80000000
+ rdmsr r24, 51515151
+ wrmsrns 51515151, r12
+ wrmsrns 51515151, rax
+ wrmsrns 0x7f, r12
+ wrmsrns 0x7fff, r12
+ wrmsrns 0x80000000, r12
+ wrmsrns 51515151, r24
@@ -498,6 +498,9 @@ run_dump_test "x86-64-pbndkb-intel"
run_dump_test "x86-64-user_msr"
run_dump_test "x86-64-user_msr-intel"
run_list_test "x86-64-user_msr-inval"
+run_dump_test "x86-64-msr_imm"
+run_dump_test "x86-64-msr_imm-intel"
+run_list_test "x86-64-msr_imm-inval"
run_dump_test "x86-64-avx10_2-rounding"
run_dump_test "x86-64-avx10_2-rounding-intel"
run_dump_test "x86-64-avx10_2-evex-promote"
@@ -902,6 +902,7 @@ enum
REG_VEX_0FAE,
REG_VEX_0F3849_X86_64_L_0_W_0_M_1_P_0,
REG_VEX_0F38F3_L_0_P_0,
+ REG_VEX_MAP7_F6_L_0_W_0,
REG_VEX_MAP7_F8_L_0_W_0,
REG_XOP_09_01_L_0,
@@ -1151,6 +1152,7 @@ enum
PREFIX_VEX_0F38F6_L_0,
PREFIX_VEX_0F38F7_L_0,
PREFIX_VEX_0F3AF0_L_0,
+ PREFIX_VEX_MAP7_F6_L_0_W_0_R_0_X86_64,
PREFIX_VEX_MAP7_F8_L_0_W_0_R_0_X86_64,
PREFIX_EVEX_0F2E,
@@ -1348,6 +1350,7 @@ enum
X86_64_VEX_0F386C,
X86_64_VEX_0F38Ex,
+ X86_64_VEX_MAP7_F6_L_0_W_0_R_0,
X86_64_VEX_MAP7_F8_L_0_W_0_R_0,
X86_64_EVEX_MAP5_6C_W_1_P_1,
@@ -1467,6 +1470,7 @@ enum
VEX_LEN_0F3ADE_W_0,
VEX_LEN_0F3ADF,
VEX_LEN_0F3AF0,
+ VEX_LEN_MAP7_F6,
VEX_LEN_MAP7_F8,
VEX_LEN_XOP_08_85,
VEX_LEN_XOP_08_86,
@@ -1633,6 +1637,7 @@ enum
VEX_W_0F3ACE,
VEX_W_0F3ACF,
VEX_W_0F3ADE,
+ VEX_W_MAP7_F6_L_0,
VEX_W_MAP7_F8_L_0,
VEX_W_XOP_08_85_L_0,
@@ -3004,6 +3009,10 @@ static const struct dis386 reg_table[][8] = {
{ "%NFblsmskS", { VexGdq, Edq }, 0 },
{ "%NFblsiS", { VexGdq, Edq }, 0 },
},
+ /* REG_VEX_MAP7_F6_L_0_W_0 */
+ {
+ { X86_64_TABLE (X86_64_VEX_MAP7_F6_L_0_W_0_R_0) },
+ },
/* REG_VEX_MAP7_F8_L_0_W_0 */
{
{ X86_64_TABLE (X86_64_VEX_MAP7_F8_L_0_W_0_R_0) },
@@ -4212,12 +4221,20 @@ static const struct dis386 prefix_table[][4] = {
{ "%XErorxS", { Gdq, Edq, Ib }, 0 },
},
+ /* PREFIX_VEX_MAP7_F6_L_0_W_0_R_0_X86_64 */
+ {
+ { Bad_Opcode },
+ { "wrmsrns", { Skip_MODRM, Id, Rq }, 0 },
+ { Bad_Opcode },
+ { "rdmsr", { Rq, Id }, 0 },
+ },
+
/* PREFIX_VEX_MAP7_F8_L_0_W_0_R_0_X86_64 */
{
{ Bad_Opcode },
- { "uwrmsr", { Skip_MODRM, Id, Rq }, 0 },
+ { "uwrmsr", { Skip_MODRM, Id, Rq }, 0 },
{ Bad_Opcode },
- { "urdmsr", { Rq, Id }, 0 },
+ { "urdmsr", { Rq, Id }, 0 },
},
#include "i386-dis-evex-prefix.h"
@@ -4576,6 +4593,12 @@ static const struct dis386 x86_64_table[][2] = {
{ "%XEcmp%CCxadd", { Mdq, Gdq, VexGdq }, PREFIX_DATA },
},
+ /* X86_64_VEX_MAP7_F6_L_0_W_0_R_0 */
+ {
+ { Bad_Opcode },
+ { PREFIX_TABLE (PREFIX_VEX_MAP7_F6_L_0_W_0_R_0_X86_64) },
+ },
+
/* X86_64_VEX_MAP7_F8_L_0_W_0_R_0 */
{
{ Bad_Opcode },
@@ -7335,6 +7358,11 @@ static const struct dis386 vex_len_table[][2] = {
{ PREFIX_TABLE (PREFIX_VEX_0F3AF0_L_0) },
},
+ /* VEX_LEN_MAP7_F6 */
+ {
+ { VEX_W_TABLE (VEX_W_MAP7_F6_L_0) },
+ },
+
/* VEX_LEN_MAP7_F8 */
{
{ VEX_W_TABLE (VEX_W_MAP7_F8_L_0) },
@@ -7946,6 +7974,10 @@ static const struct dis386 vex_w_table[][2] = {
/* VEX_W_0F3ADE */
{ VEX_LEN_TABLE (VEX_LEN_0F3ADE_W_0) },
},
+ {
+ /* VEX_W_MAP7_F6_L_0 */
+ { REG_TABLE (REG_VEX_MAP7_F6_L_0_W_0) },
+ },
{
/* VEX_W_MAP7_F8_L_0 */
{ REG_TABLE (REG_VEX_MAP7_F8_L_0_W_0) },
@@ -8691,6 +8723,7 @@ static const struct dis386 bad_opcode = { "(bad)", { XX }, 0 };
/* Fetch error indicator. */
static const struct dis386 err_opcode = { NULL, { XX }, 0 };
+static const struct dis386 map7_f6_opcode = { VEX_LEN_TABLE (VEX_LEN_MAP7_F6) };
static const struct dis386 map7_f8_opcode = { VEX_LEN_TABLE (VEX_LEN_MAP7_F8) };
/* Get a pointer to struct dis386 with a valid name. */
@@ -9004,6 +9037,8 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins)
ins->condition_code = vindex & 0xf;
if (vex_table_index != VEX_MAP7)
dp = &vex_table[vex_table_index][vindex];
+ else if (vindex == 0xf6)
+ dp = &map7_f6_opcode;
else if (vindex == 0xf8)
dp = &map7_f8_opcode;
else
@@ -9165,6 +9200,8 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins)
dp = &evex_table[vex_table_index][vindex];
else if (vindex == 0xf8)
dp = &map7_f8_opcode;
+ else if (vindex == 0xf6)
+ dp = &map7_f6_opcode;
else
dp = &bad_opcode;
ins->end_codep = ins->codep;
@@ -279,6 +279,8 @@ static const dependency isa_dependencies[] =
"64" },
{ "USER_MSR",
"64" },
+ { "MSR_IMM",
+ "64" },
{ "APX_F",
"XSAVE|64" },
};
@@ -404,6 +406,7 @@ static bitfield cpu_flags[] =
BITFIELD (FRED),
BITFIELD (LKGS),
BITFIELD (USER_MSR),
+ BITFIELD (MSR_IMM),
BITFIELD (APX_F),
BITFIELD (AVX10_2),
BITFIELD (MWAITX),
@@ -227,6 +227,8 @@ enum i386_cpu
CpuLKGS,
/* Intel USER_MSR Instruction support required. */
CpuUSER_MSR,
+ /* Intel MSR_IMM Instructions support required. */
+ CpuMSR_IMM,
/* Intel AVX10.2 Instructions support required. */
CpuAVX10_2,
/* mwaitx instruction required */
@@ -482,6 +484,7 @@ typedef union i386_cpu_flags
unsigned int cpufred:1;
unsigned int cpulkgs:1;
unsigned int cpuuser_msr:1;
+ unsigned int cpumsr_imm:1;
unsigned int cpuavx10_2:1;
unsigned int cpumwaitx:1;
unsigned int cpuclzero:1;
@@ -3420,6 +3420,14 @@ uwrmsr, 0xf3f8/0, APX_F(USER_MSR), Modrm|Vex128|xVexMap7|EVex128|VexW0|NoSuf, {
// USER_MSR instructions end.
+// MSR_IMM instructions.
+
+rdmsr, 0xf2f6/0, APX_F(MSR_IMM), Modrm|Vex128|xVexMap7|EVex128|VexW0|NoSuf, { Imm32, Reg64 }
+// See uwrmsr for the unusual Imm32.
+wrmsrns, 0xf3f6/0, APX_F(MSR_IMM), Modrm|Vex128|xVexMap7|EVex128|VexW0|NoSuf, { Imm32, Reg64 }
+
+// MSR_IMM instructions end.
+
// APX Push2/Pop2 instructions.
//PUSH2/POP2 pushes/pops 2 GPRs at a time to/from the stack. So 2 GPRs are both
//Dst/Src, here the V register is used to encode the Operand 1 (Intel format).