Skip to content

Commit 98afd4d

Browse files
committed
Merge tag 'x86_misc_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 instruction decoder update from Borislav Petkov: - Add instruction decoding support for the XOP-prefixed instruction set present on the AMD Bulldozer uarch [ These instructions don't normally happen, but a X86_NATIVE_CPU build on a bulldozer host can make the compiler then use these unusual instruction encodings ] * tag 'x86_misc_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/insn: Add XOP prefix instructions decoder support
2 parents 03f76dd + 26178b7 commit 98afd4d

13 files changed

Lines changed: 513 additions & 27 deletions

File tree

arch/x86/include/asm/inat.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#define INAT_PFX_EVEX 15 /* EVEX prefix */
3838
/* x86-64 REX2 prefix */
3939
#define INAT_PFX_REX2 16 /* 0xD5 */
40+
/* AMD XOP prefix */
41+
#define INAT_PFX_XOP 17 /* 0x8F */
4042

4143
#define INAT_LSTPFX_MAX 3
4244
#define INAT_LGCPFX_MAX 11
@@ -77,6 +79,7 @@
7779
#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3))
7880
#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4))
7981
#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5))
82+
#define INAT_XOPOK INAT_VEXOK
8083
#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6))
8184
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
8285
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
@@ -111,6 +114,8 @@ extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
111114
extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode,
112115
insn_byte_t vex_m,
113116
insn_byte_t vex_pp);
117+
extern insn_attr_t inat_get_xop_attribute(insn_byte_t opcode,
118+
insn_byte_t map_select);
114119

115120
/* Attribute checking functions */
116121
static inline int inat_is_legacy_prefix(insn_attr_t attr)
@@ -164,6 +169,11 @@ static inline int inat_is_vex3_prefix(insn_attr_t attr)
164169
return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3;
165170
}
166171

172+
static inline int inat_is_xop_prefix(insn_attr_t attr)
173+
{
174+
return (attr & INAT_PFX_MASK) == INAT_PFX_XOP;
175+
}
176+
167177
static inline int inat_is_escape(insn_attr_t attr)
168178
{
169179
return attr & INAT_ESC_MASK;
@@ -229,6 +239,11 @@ static inline int inat_accept_vex(insn_attr_t attr)
229239
return attr & INAT_VEXOK;
230240
}
231241

242+
static inline int inat_accept_xop(insn_attr_t attr)
243+
{
244+
return attr & INAT_XOPOK;
245+
}
246+
232247
static inline int inat_must_vex(insn_attr_t attr)
233248
{
234249
return attr & (INAT_VEXONLY | INAT_EVEXONLY);

arch/x86/include/asm/insn.h

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ struct insn {
7171
* prefixes.bytes[3]: last prefix
7272
*/
7373
struct insn_field rex_prefix; /* REX prefix */
74-
struct insn_field vex_prefix; /* VEX prefix */
74+
union {
75+
struct insn_field vex_prefix; /* VEX prefix */
76+
struct insn_field xop_prefix; /* XOP prefix */
77+
};
7578
struct insn_field opcode; /*
7679
* opcode.bytes[0]: opcode1
7780
* opcode.bytes[1]: opcode2
@@ -135,6 +138,17 @@ struct insn {
135138
#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */
136139
#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */
137140
#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */
141+
/* XOP bit fields */
142+
#define X86_XOP_R(xop) ((xop) & 0x80) /* XOP Byte2 */
143+
#define X86_XOP_X(xop) ((xop) & 0x40) /* XOP Byte2 */
144+
#define X86_XOP_B(xop) ((xop) & 0x20) /* XOP Byte2 */
145+
#define X86_XOP_M(xop) ((xop) & 0x1f) /* XOP Byte2 */
146+
#define X86_XOP_W(xop) ((xop) & 0x80) /* XOP Byte3 */
147+
#define X86_XOP_V(xop) ((xop) & 0x78) /* XOP Byte3 */
148+
#define X86_XOP_L(xop) ((xop) & 0x04) /* XOP Byte3 */
149+
#define X86_XOP_P(xop) ((xop) & 0x03) /* XOP Byte3 */
150+
#define X86_XOP_M_MIN 0x08 /* Min of XOP.M */
151+
#define X86_XOP_M_MAX 0x1f /* Max of XOP.M */
138152

139153
extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64);
140154
extern int insn_get_prefixes(struct insn *insn);
@@ -178,7 +192,7 @@ static inline insn_byte_t insn_rex2_m_bit(struct insn *insn)
178192
return X86_REX2_M(insn->rex_prefix.bytes[1]);
179193
}
180194

181-
static inline int insn_is_avx(struct insn *insn)
195+
static inline int insn_is_avx_or_xop(struct insn *insn)
182196
{
183197
if (!insn->prefixes.got)
184198
insn_get_prefixes(insn);
@@ -192,6 +206,22 @@ static inline int insn_is_evex(struct insn *insn)
192206
return (insn->vex_prefix.nbytes == 4);
193207
}
194208

209+
/* If we already know this is AVX/XOP encoded */
210+
static inline int avx_insn_is_xop(struct insn *insn)
211+
{
212+
insn_attr_t attr = inat_get_opcode_attribute(insn->vex_prefix.bytes[0]);
213+
214+
return inat_is_xop_prefix(attr);
215+
}
216+
217+
static inline int insn_is_xop(struct insn *insn)
218+
{
219+
if (!insn_is_avx_or_xop(insn))
220+
return 0;
221+
222+
return avx_insn_is_xop(insn);
223+
}
224+
195225
static inline int insn_has_emulate_prefix(struct insn *insn)
196226
{
197227
return !!insn->emulate_prefix_size;
@@ -222,11 +252,26 @@ static inline insn_byte_t insn_vex_w_bit(struct insn *insn)
222252
return X86_VEX_W(insn->vex_prefix.bytes[2]);
223253
}
224254

255+
static inline insn_byte_t insn_xop_map_bits(struct insn *insn)
256+
{
257+
if (insn->xop_prefix.nbytes < 3) /* XOP is 3 bytes */
258+
return 0;
259+
return X86_XOP_M(insn->xop_prefix.bytes[1]);
260+
}
261+
262+
static inline insn_byte_t insn_xop_p_bits(struct insn *insn)
263+
{
264+
return X86_XOP_P(insn->vex_prefix.bytes[2]);
265+
}
266+
225267
/* Get the last prefix id from last prefix or VEX prefix */
226268
static inline int insn_last_prefix_id(struct insn *insn)
227269
{
228-
if (insn_is_avx(insn))
270+
if (insn_is_avx_or_xop(insn)) {
271+
if (avx_insn_is_xop(insn))
272+
return insn_xop_p_bits(insn);
229273
return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */
274+
}
230275

231276
if (insn->prefixes.bytes[3])
232277
return inat_get_last_prefix_id(insn->prefixes.bytes[3]);

arch/x86/lib/inat.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,16 @@ insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m,
8181
return table[opcode];
8282
}
8383

84+
insn_attr_t inat_get_xop_attribute(insn_byte_t opcode, insn_byte_t map_select)
85+
{
86+
const insn_attr_t *table;
87+
88+
if (map_select < X86_XOP_M_MIN || map_select > X86_XOP_M_MAX)
89+
return 0;
90+
map_select -= X86_XOP_M_MIN;
91+
/* At first, this checks the master table */
92+
table = inat_xop_tables[map_select];
93+
if (!table)
94+
return 0;
95+
return table[opcode];
96+
}

arch/x86/lib/insn.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,15 @@ int insn_get_prefixes(struct insn *insn)
200200
}
201201
insn->rex_prefix.got = 1;
202202

203-
/* Decode VEX prefix */
203+
/* Decode VEX/XOP prefix */
204204
b = peek_next(insn_byte_t, insn);
205-
attr = inat_get_opcode_attribute(b);
206-
if (inat_is_vex_prefix(attr)) {
205+
if (inat_is_vex_prefix(attr) || inat_is_xop_prefix(attr)) {
207206
insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1);
208-
if (!insn->x86_64) {
207+
208+
if (inat_is_xop_prefix(attr) && X86_MODRM_REG(b2) == 0) {
209+
/* Grp1A.0 is always POP Ev */
210+
goto vex_end;
211+
} else if (!insn->x86_64) {
209212
/*
210213
* In 32-bits mode, if the [7:6] bits (mod bits of
211214
* ModRM) on the second byte are not 11b, it is
@@ -226,13 +229,13 @@ int insn_get_prefixes(struct insn *insn)
226229
if (insn->x86_64 && X86_VEX_W(b2))
227230
/* VEX.W overrides opnd_size */
228231
insn->opnd_bytes = 8;
229-
} else if (inat_is_vex3_prefix(attr)) {
232+
} else if (inat_is_vex3_prefix(attr) || inat_is_xop_prefix(attr)) {
230233
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
231234
insn_set_byte(&insn->vex_prefix, 2, b2);
232235
insn->vex_prefix.nbytes = 3;
233236
insn->next_byte += 3;
234237
if (insn->x86_64 && X86_VEX_W(b2))
235-
/* VEX.W overrides opnd_size */
238+
/* VEX.W/XOP.W overrides opnd_size */
236239
insn->opnd_bytes = 8;
237240
} else {
238241
/*
@@ -288,9 +291,22 @@ int insn_get_opcode(struct insn *insn)
288291
insn_set_byte(opcode, 0, op);
289292
opcode->nbytes = 1;
290293

291-
/* Check if there is VEX prefix or not */
292-
if (insn_is_avx(insn)) {
294+
/* Check if there is VEX/XOP prefix or not */
295+
if (insn_is_avx_or_xop(insn)) {
293296
insn_byte_t m, p;
297+
298+
/* XOP prefix has different encoding */
299+
if (unlikely(avx_insn_is_xop(insn))) {
300+
m = insn_xop_map_bits(insn);
301+
insn->attr = inat_get_xop_attribute(op, m);
302+
if (!inat_accept_xop(insn->attr)) {
303+
insn->attr = 0;
304+
return -EINVAL;
305+
}
306+
/* XOP has only 1 byte for opcode */
307+
goto end;
308+
}
309+
294310
m = insn_vex_m_bits(insn);
295311
p = insn_vex_p_bits(insn);
296312
insn->attr = inat_get_avx_attribute(op, m, p);
@@ -383,7 +399,8 @@ int insn_get_modrm(struct insn *insn)
383399
pfx_id = insn_last_prefix_id(insn);
384400
insn->attr = inat_get_group_attribute(mod, pfx_id,
385401
insn->attr);
386-
if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) {
402+
if (insn_is_avx_or_xop(insn) && !inat_accept_vex(insn->attr) &&
403+
!inat_accept_xop(insn->attr)) {
387404
/* Bad insn */
388405
insn->attr = 0;
389406
return -EINVAL;

arch/x86/lib/x86-opcode-map.txt

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
# (evo): this opcode is changed by EVEX prefix (EVEX opcode)
2828
# (v): this opcode requires VEX prefix.
2929
# (v1): this opcode only supports 128bit VEX.
30+
# (xop): this opcode accepts XOP prefix.
31+
#
32+
# XOP Superscripts
33+
# (W=0): this opcode requires XOP.W == 0
34+
# (W=1): this opcode requires XOP.W == 1
3035
#
3136
# Last Prefix Superscripts
3237
# - (66): the last prefix is 0x66
@@ -194,7 +199,7 @@ AVXcode:
194199
8c: MOV Ev,Sw
195200
8d: LEA Gv,M
196201
8e: MOV Sw,Ew
197-
8f: Grp1A (1A) | POP Ev (d64)
202+
8f: Grp1A (1A) | POP Ev (d64) | XOP (Prefix)
198203
# 0x90 - 0x9f
199204
90: NOP | PAUSE (F3) | XCHG r8,rAX
200205
91: XCHG rCX/r9,rAX
@@ -1106,6 +1111,84 @@ AVXcode: 7
11061111
f8: URDMSR Rq,Id (F2),(v1),(11B) | UWRMSR Id,Rq (F3),(v1),(11B)
11071112
EndTable
11081113

1114+
# From AMD64 Architecture Programmer's Manual Vol3, Appendix A.1.5
1115+
Table: XOP map 8h
1116+
Referrer:
1117+
XOPcode: 0
1118+
85: VPMACSSWW Vo,Ho,Wo,Lo
1119+
86: VPMACSSWD Vo,Ho,Wo,Lo
1120+
87: VPMACSSDQL Vo,Ho,Wo,Lo
1121+
8e: VPMACSSDD Vo,Ho,Wo,Lo
1122+
8f: VPMACSSDQH Vo,Ho,Wo,Lo
1123+
95: VPMACSWW Vo,Ho,Wo,Lo
1124+
96: VPMACSWD Vo,Ho,Wo,Lo
1125+
97: VPMACSDQL Vo,Ho,Wo,Lo
1126+
9e: VPMACSDD Vo,Ho,Wo,Lo
1127+
9f: VPMACSDQH Vo,Ho,Wo,Lo
1128+
a2: VPCMOV Vx,Hx,Wx,Lx (W=0) | VPCMOV Vx,Hx,Lx,Wx (W=1)
1129+
a3: VPPERM Vo,Ho,Wo,Lo (W=0) | VPPERM Vo,Ho,Lo,Wo (W=1)
1130+
a6: VPMADCSSWD Vo,Ho,Wo,Lo
1131+
b6: VPMADCSWD Vo,Ho,Wo,Lo
1132+
c0: VPROTB Vo,Wo,Ib
1133+
c1: VPROTW Vo,Wo,Ib
1134+
c2: VPROTD Vo,Wo,Ib
1135+
c3: VPROTQ Vo,Wo,Ib
1136+
cc: VPCOMccB Vo,Ho,Wo,Ib
1137+
cd: VPCOMccW Vo,Ho,Wo,Ib
1138+
ce: VPCOMccD Vo,Ho,Wo,Ib
1139+
cf: VPCOMccQ Vo,Ho,Wo,Ib
1140+
ec: VPCOMccUB Vo,Ho,Wo,Ib
1141+
ed: VPCOMccUW Vo,Ho,Wo,Ib
1142+
ee: VPCOMccUD Vo,Ho,Wo,Ib
1143+
ef: VPCOMccUQ Vo,Ho,Wo,Ib
1144+
EndTable
1145+
1146+
Table: XOP map 9h
1147+
Referrer:
1148+
XOPcode: 1
1149+
01: GrpXOP1
1150+
02: GrpXOP2
1151+
12: GrpXOP3
1152+
80: VFRCZPS Vx,Wx
1153+
81: VFRCZPD Vx,Wx
1154+
82: VFRCZSS Vq,Wss
1155+
83: VFRCZSD Vq,Wsd
1156+
90: VPROTB Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1)
1157+
91: VPROTW Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1)
1158+
92: VPROTD Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1)
1159+
93: VPROTQ Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1)
1160+
94: VPSHLB Vo,Wo,Ho (W=0) | VPSHLB Vo,Ho,Wo (W=1)
1161+
95: VPSHLW Vo,Wo,Ho (W=0) | VPSHLW Vo,Ho,Wo (W=1)
1162+
96: VPSHLD Vo,Wo,Ho (W=0) | VPSHLD Vo,Ho,Wo (W=1)
1163+
97: VPSHLQ Vo,Wo,Ho (W=0) | VPSHLQ Vo,Ho,Wo (W=1)
1164+
98: VPSHAB Vo,Wo,Ho (W=0) | VPSHAB Vo,Ho,Wo (W=1)
1165+
99: VPSHAW Vo,Wo,Ho (W=0) | VPSHAW Vo,Ho,Wo (W=1)
1166+
9a: VPSHAD Vo,Wo,Ho (W=0) | VPSHAD Vo,Ho,Wo (W=1)
1167+
9b: VPSHAQ Vo,Wo,Ho (W=0) | VPSHAQ Vo,Ho,Wo (W=1)
1168+
c1: VPHADDBW Vo,Wo
1169+
c2: VPHADDBD Vo,Wo
1170+
c3: VPHADDBQ Vo,Wo
1171+
c6: VPHADDWD Vo,Wo
1172+
c7: VPHADDWQ Vo,Wo
1173+
cb: VPHADDDQ Vo,Wo
1174+
d1: VPHADDUBWD Vo,Wo
1175+
d2: VPHADDUBD Vo,Wo
1176+
d3: VPHADDUBQ Vo,Wo
1177+
d6: VPHADDUWD Vo,Wo
1178+
d7: VPHADDUWQ Vo,Wo
1179+
db: VPHADDUDQ Vo,Wo
1180+
e1: VPHSUBBW Vo,Wo
1181+
e2: VPHSUBWD Vo,Wo
1182+
e3: VPHSUBDQ Vo,Wo
1183+
EndTable
1184+
1185+
Table: XOP map Ah
1186+
Referrer:
1187+
XOPcode: 2
1188+
10: BEXTR Gy,Ey,Id
1189+
12: GrpXOP4
1190+
EndTable
1191+
11091192
GrpTable: Grp1
11101193
0: ADD
11111194
1: OR
@@ -1320,3 +1403,29 @@ GrpTable: GrpRNG
13201403
4: xcrypt-cfb
13211404
5: xcrypt-ofb
13221405
EndTable
1406+
1407+
# GrpXOP1-4 is shown in AMD APM Vol.3 Appendix A as XOP group #1-4
1408+
GrpTable: GrpXOP1
1409+
1: BLCFILL By,Ey (xop)
1410+
2: BLSFILL By,Ey (xop)
1411+
3: BLCS By,Ey (xop)
1412+
4: TZMSK By,Ey (xop)
1413+
5: BLCIC By,Ey (xop)
1414+
6: BLSIC By,Ey (xop)
1415+
7: T1MSKC By,Ey (xop)
1416+
EndTable
1417+
1418+
GrpTable: GrpXOP2
1419+
1: BLCMSK By,Ey (xop)
1420+
6: BLCI By,Ey (xop)
1421+
EndTable
1422+
1423+
GrpTable: GrpXOP3
1424+
0: LLWPCB Ry (xop)
1425+
1: SLWPCB Ry (xop)
1426+
EndTable
1427+
1428+
GrpTable: GrpXOP4
1429+
0: LWPINS By,Ed,Id (xop)
1430+
1: LWPVAL By,Ed,Id (xop)
1431+
EndTable

0 commit comments

Comments
 (0)