Skip to content

Commit eada38d

Browse files
ahunter6Ingo Molnar
authored andcommitted
x86/insn: Add support for REX2 prefix to the instruction decoder logic
Intel Advanced Performance Extensions (APX) uses a new 2-byte prefix named REX2 to select extended general purpose registers (EGPRs) i.e. r16 to r31. The REX2 prefix is effectively an extended version of the REX prefix. REX2 and EVEX are also used with PUSH/POP instructions to provide a Push-Pop Acceleration (PPX) hint. With PPX hints, a CPU will attempt to fast-forward register data between matching PUSH and POP instructions. REX2 is valid only with opcodes in maps 0 and 1. Similar extension for other maps is provided by the EVEX prefix, covered in a separate patch. Some opcodes in maps 0 and 1 are reserved under REX2. One of these is used for a new 64-bit absolute direct jump instruction JMPABS. Refer to the Intel Advanced Performance Extensions (Intel APX) Architecture Specification for details. Define a code value for the REX2 prefix (INAT_PFX_REX2), and add attribute flags for opcodes reserved under REX2 (INAT_NO_REX2) and to identify opcodes (only JMPABS) that require a mandatory REX2 prefix (INAT_REX2_VARIANT). Amend logic to read the REX2 prefix and get the opcode attribute for the map number (0 or 1) encoded in the REX2 prefix. Amend the awk script that generates the attribute tables from the opcode map, to recognise "REX2" as attribute INAT_PFX_REX2, and "(!REX2)" as attribute INAT_NO_REX2, and "(REX2)" as attribute INAT_REX2_VARIANT. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://lore.kernel.org/r/20240502105853.5338-6-adrian.hunter@intel.com
1 parent 9dd3612 commit eada38d

File tree

8 files changed

+132
-12
lines changed

8 files changed

+132
-12
lines changed

arch/x86/include/asm/inat.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */
3636
#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */
3737
#define INAT_PFX_EVEX 15 /* EVEX prefix */
38+
/* x86-64 REX2 prefix */
39+
#define INAT_PFX_REX2 16 /* 0xD5 */
3840

3941
#define INAT_LSTPFX_MAX 3
4042
#define INAT_LGCPFX_MAX 11
@@ -50,7 +52,7 @@
5052

5153
/* Legacy prefix */
5254
#define INAT_PFX_OFFS 0
53-
#define INAT_PFX_BITS 4
55+
#define INAT_PFX_BITS 5
5456
#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1)
5557
#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS)
5658
/* Escape opcodes */
@@ -77,6 +79,8 @@
7779
#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5))
7880
#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6))
7981
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
82+
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
83+
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
8084
/* Attribute making macros for attribute tables */
8185
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
8286
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
@@ -128,6 +132,11 @@ static inline int inat_is_rex_prefix(insn_attr_t attr)
128132
return (attr & INAT_PFX_MASK) == INAT_PFX_REX;
129133
}
130134

135+
static inline int inat_is_rex2_prefix(insn_attr_t attr)
136+
{
137+
return (attr & INAT_PFX_MASK) == INAT_PFX_REX2;
138+
}
139+
131140
static inline int inat_last_prefix_id(insn_attr_t attr)
132141
{
133142
if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX)

arch/x86/include/asm/insn.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,15 @@ struct insn {
112112
#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
113113
#define X86_SIB_BASE(sib) ((sib) & 0x07)
114114

115-
#define X86_REX_W(rex) ((rex) & 8)
116-
#define X86_REX_R(rex) ((rex) & 4)
117-
#define X86_REX_X(rex) ((rex) & 2)
118-
#define X86_REX_B(rex) ((rex) & 1)
115+
#define X86_REX2_M(rex) ((rex) & 0x80) /* REX2 M0 */
116+
#define X86_REX2_R(rex) ((rex) & 0x40) /* REX2 R4 */
117+
#define X86_REX2_X(rex) ((rex) & 0x20) /* REX2 X4 */
118+
#define X86_REX2_B(rex) ((rex) & 0x10) /* REX2 B4 */
119+
120+
#define X86_REX_W(rex) ((rex) & 8) /* REX or REX2 W */
121+
#define X86_REX_R(rex) ((rex) & 4) /* REX or REX2 R3 */
122+
#define X86_REX_X(rex) ((rex) & 2) /* REX or REX2 X3 */
123+
#define X86_REX_B(rex) ((rex) & 1) /* REX or REX2 B3 */
119124

120125
/* VEX bit flags */
121126
#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */
@@ -161,6 +166,18 @@ static inline void insn_get_attribute(struct insn *insn)
161166
/* Instruction uses RIP-relative addressing */
162167
extern int insn_rip_relative(struct insn *insn);
163168

169+
static inline int insn_is_rex2(struct insn *insn)
170+
{
171+
if (!insn->prefixes.got)
172+
insn_get_prefixes(insn);
173+
return insn->rex_prefix.nbytes == 2;
174+
}
175+
176+
static inline insn_byte_t insn_rex2_m_bit(struct insn *insn)
177+
{
178+
return X86_REX2_M(insn->rex_prefix.bytes[1]);
179+
}
180+
164181
static inline int insn_is_avx(struct insn *insn)
165182
{
166183
if (!insn->prefixes.got)

arch/x86/lib/insn.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,17 @@ int insn_get_prefixes(struct insn *insn)
185185
if (X86_REX_W(b))
186186
/* REX.W overrides opnd_size */
187187
insn->opnd_bytes = 8;
188+
} else if (inat_is_rex2_prefix(attr)) {
189+
insn_set_byte(&insn->rex_prefix, 0, b);
190+
b = peek_nbyte_next(insn_byte_t, insn, 1);
191+
insn_set_byte(&insn->rex_prefix, 1, b);
192+
insn->rex_prefix.nbytes = 2;
193+
insn->next_byte += 2;
194+
if (X86_REX_W(b))
195+
/* REX.W overrides opnd_size */
196+
insn->opnd_bytes = 8;
197+
insn->rex_prefix.got = 1;
198+
goto vex_end;
188199
}
189200
}
190201
insn->rex_prefix.got = 1;
@@ -294,6 +305,20 @@ int insn_get_opcode(struct insn *insn)
294305
goto end;
295306
}
296307

308+
/* Check if there is REX2 prefix or not */
309+
if (insn_is_rex2(insn)) {
310+
if (insn_rex2_m_bit(insn)) {
311+
/* map 1 is escape 0x0f */
312+
insn_attr_t esc_attr = inat_get_opcode_attribute(0x0f);
313+
314+
pfx_id = insn_last_prefix_id(insn);
315+
insn->attr = inat_get_escape_attribute(op, pfx_id, esc_attr);
316+
} else {
317+
insn->attr = inat_get_opcode_attribute(op);
318+
}
319+
goto end;
320+
}
321+
297322
insn->attr = inat_get_opcode_attribute(op);
298323
while (inat_is_escape(insn->attr)) {
299324
/* Get escaped opcode */

arch/x86/tools/gen-insn-attr-x86.awk

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ BEGIN {
6464

6565
modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
6666
force64_expr = "\\([df]64\\)"
67-
rex_expr = "^REX(\\.[XRWB]+)*"
67+
rex_expr = "^((REX(\\.[XRWB]+)+)|(REX$))"
68+
rex2_expr = "\\(REX2\\)"
69+
no_rex2_expr = "\\(!REX2\\)"
6870
fpu_expr = "^ESC" # TODO
6971

7072
lprefix1_expr = "\\((66|!F3)\\)"
@@ -99,6 +101,7 @@ BEGIN {
99101
prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
100102
prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
101103
prefix_num["EVEX"] = "INAT_PFX_EVEX"
104+
prefix_num["REX2"] = "INAT_PFX_REX2"
102105

103106
clear_vars()
104107
}
@@ -314,6 +317,10 @@ function convert_operands(count,opnd, i,j,imm,mod)
314317
if (match(ext, force64_expr))
315318
flags = add_flags(flags, "INAT_FORCE64")
316319

320+
# check REX2 not allowed
321+
if (match(ext, no_rex2_expr))
322+
flags = add_flags(flags, "INAT_NO_REX2")
323+
317324
# check REX prefix
318325
if (match(opcode, rex_expr))
319326
flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
@@ -351,6 +358,8 @@ function convert_operands(count,opnd, i,j,imm,mod)
351358
lptable3[idx] = add_flags(lptable3[idx],flags)
352359
variant = "INAT_VARIANT"
353360
}
361+
if (match(ext, rex2_expr))
362+
table[idx] = add_flags(table[idx], "INAT_REX2_VARIANT")
354363
if (!match(ext, lprefix_expr)){
355364
table[idx] = add_flags(table[idx],flags)
356365
}

tools/arch/x86/include/asm/inat.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */
3636
#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */
3737
#define INAT_PFX_EVEX 15 /* EVEX prefix */
38+
/* x86-64 REX2 prefix */
39+
#define INAT_PFX_REX2 16 /* 0xD5 */
3840

3941
#define INAT_LSTPFX_MAX 3
4042
#define INAT_LGCPFX_MAX 11
@@ -50,7 +52,7 @@
5052

5153
/* Legacy prefix */
5254
#define INAT_PFX_OFFS 0
53-
#define INAT_PFX_BITS 4
55+
#define INAT_PFX_BITS 5
5456
#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1)
5557
#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS)
5658
/* Escape opcodes */
@@ -77,6 +79,8 @@
7779
#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5))
7880
#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6))
7981
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
82+
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
83+
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
8084
/* Attribute making macros for attribute tables */
8185
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
8286
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
@@ -128,6 +132,11 @@ static inline int inat_is_rex_prefix(insn_attr_t attr)
128132
return (attr & INAT_PFX_MASK) == INAT_PFX_REX;
129133
}
130134

135+
static inline int inat_is_rex2_prefix(insn_attr_t attr)
136+
{
137+
return (attr & INAT_PFX_MASK) == INAT_PFX_REX2;
138+
}
139+
131140
static inline int inat_last_prefix_id(insn_attr_t attr)
132141
{
133142
if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX)

tools/arch/x86/include/asm/insn.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,15 @@ struct insn {
112112
#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
113113
#define X86_SIB_BASE(sib) ((sib) & 0x07)
114114

115-
#define X86_REX_W(rex) ((rex) & 8)
116-
#define X86_REX_R(rex) ((rex) & 4)
117-
#define X86_REX_X(rex) ((rex) & 2)
118-
#define X86_REX_B(rex) ((rex) & 1)
115+
#define X86_REX2_M(rex) ((rex) & 0x80) /* REX2 M0 */
116+
#define X86_REX2_R(rex) ((rex) & 0x40) /* REX2 R4 */
117+
#define X86_REX2_X(rex) ((rex) & 0x20) /* REX2 X4 */
118+
#define X86_REX2_B(rex) ((rex) & 0x10) /* REX2 B4 */
119+
120+
#define X86_REX_W(rex) ((rex) & 8) /* REX or REX2 W */
121+
#define X86_REX_R(rex) ((rex) & 4) /* REX or REX2 R3 */
122+
#define X86_REX_X(rex) ((rex) & 2) /* REX or REX2 X3 */
123+
#define X86_REX_B(rex) ((rex) & 1) /* REX or REX2 B3 */
119124

120125
/* VEX bit flags */
121126
#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */
@@ -161,6 +166,18 @@ static inline void insn_get_attribute(struct insn *insn)
161166
/* Instruction uses RIP-relative addressing */
162167
extern int insn_rip_relative(struct insn *insn);
163168

169+
static inline int insn_is_rex2(struct insn *insn)
170+
{
171+
if (!insn->prefixes.got)
172+
insn_get_prefixes(insn);
173+
return insn->rex_prefix.nbytes == 2;
174+
}
175+
176+
static inline insn_byte_t insn_rex2_m_bit(struct insn *insn)
177+
{
178+
return X86_REX2_M(insn->rex_prefix.bytes[1]);
179+
}
180+
164181
static inline int insn_is_avx(struct insn *insn)
165182
{
166183
if (!insn->prefixes.got)

tools/arch/x86/lib/insn.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,17 @@ int insn_get_prefixes(struct insn *insn)
185185
if (X86_REX_W(b))
186186
/* REX.W overrides opnd_size */
187187
insn->opnd_bytes = 8;
188+
} else if (inat_is_rex2_prefix(attr)) {
189+
insn_set_byte(&insn->rex_prefix, 0, b);
190+
b = peek_nbyte_next(insn_byte_t, insn, 1);
191+
insn_set_byte(&insn->rex_prefix, 1, b);
192+
insn->rex_prefix.nbytes = 2;
193+
insn->next_byte += 2;
194+
if (X86_REX_W(b))
195+
/* REX.W overrides opnd_size */
196+
insn->opnd_bytes = 8;
197+
insn->rex_prefix.got = 1;
198+
goto vex_end;
188199
}
189200
}
190201
insn->rex_prefix.got = 1;
@@ -294,6 +305,20 @@ int insn_get_opcode(struct insn *insn)
294305
goto end;
295306
}
296307

308+
/* Check if there is REX2 prefix or not */
309+
if (insn_is_rex2(insn)) {
310+
if (insn_rex2_m_bit(insn)) {
311+
/* map 1 is escape 0x0f */
312+
insn_attr_t esc_attr = inat_get_opcode_attribute(0x0f);
313+
314+
pfx_id = insn_last_prefix_id(insn);
315+
insn->attr = inat_get_escape_attribute(op, pfx_id, esc_attr);
316+
} else {
317+
insn->attr = inat_get_opcode_attribute(op);
318+
}
319+
goto end;
320+
}
321+
297322
insn->attr = inat_get_opcode_attribute(op);
298323
while (inat_is_escape(insn->attr)) {
299324
/* Get escaped opcode */

tools/arch/x86/tools/gen-insn-attr-x86.awk

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ BEGIN {
6464

6565
modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
6666
force64_expr = "\\([df]64\\)"
67-
rex_expr = "^REX(\\.[XRWB]+)*"
67+
rex_expr = "^((REX(\\.[XRWB]+)+)|(REX$))"
68+
rex2_expr = "\\(REX2\\)"
69+
no_rex2_expr = "\\(!REX2\\)"
6870
fpu_expr = "^ESC" # TODO
6971

7072
lprefix1_expr = "\\((66|!F3)\\)"
@@ -99,6 +101,7 @@ BEGIN {
99101
prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
100102
prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
101103
prefix_num["EVEX"] = "INAT_PFX_EVEX"
104+
prefix_num["REX2"] = "INAT_PFX_REX2"
102105

103106
clear_vars()
104107
}
@@ -314,6 +317,10 @@ function convert_operands(count,opnd, i,j,imm,mod)
314317
if (match(ext, force64_expr))
315318
flags = add_flags(flags, "INAT_FORCE64")
316319

320+
# check REX2 not allowed
321+
if (match(ext, no_rex2_expr))
322+
flags = add_flags(flags, "INAT_NO_REX2")
323+
317324
# check REX prefix
318325
if (match(opcode, rex_expr))
319326
flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
@@ -351,6 +358,8 @@ function convert_operands(count,opnd, i,j,imm,mod)
351358
lptable3[idx] = add_flags(lptable3[idx],flags)
352359
variant = "INAT_VARIANT"
353360
}
361+
if (match(ext, rex2_expr))
362+
table[idx] = add_flags(table[idx], "INAT_REX2_VARIANT")
354363
if (!match(ext, lprefix_expr)){
355364
table[idx] = add_flags(table[idx],flags)
356365
}

0 commit comments

Comments
 (0)