mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-16 18:26:42 +00:00
x86/insn: Add support for APX EVEX to the instruction decoder logic
Intel Advanced Performance Extensions (APX) extends the EVEX prefix to support: - extended general purpose registers (EGPRs) i.e. r16 to r31 - Push-Pop Acceleration (PPX) hints - new data destination (NDD) register - suppress status flags writes (NF) of common instructions - new instructions Refer to the Intel Advanced Performance Extensions (Intel APX) Architecture Specification for details. The extended EVEX prefix does not need amended instruction decoder logic, except in one area. Some instructions are defined as SCALABLE which means the EVEX.W bit and EVEX.pp bits are used to determine operand size. Specifically, if an instruction is SCALABLE and EVEX.W is zero, then EVEX.pp value 0 (representing no prefix NP) means default operand size, whereas EVEX.pp value 1 (representing 66 prefix) means operand size override i.e. 16 bits Add an attribute (INAT_EVEX_SCALABLE) to identify such instructions, and amend the logic appropriately. Amend the awk script that generates the attribute tables from the opcode map, to recognise "(es)" as attribute INAT_EVEX_SCALABLE. 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-8-adrian.hunter@intel.com
This commit is contained in:
parent
159039af8c
commit
87bbaf1a4b
@ -81,6 +81,7 @@
|
||||
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
|
||||
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
|
||||
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
|
||||
#define INAT_EVEX_SCALABLE (1 << (INAT_FLAG_OFFS + 10))
|
||||
/* Attribute making macros for attribute tables */
|
||||
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
|
||||
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
|
||||
@ -236,4 +237,9 @@ static inline int inat_must_evex(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_EVEXONLY;
|
||||
}
|
||||
|
||||
static inline int inat_evex_scalable(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_EVEX_SCALABLE;
|
||||
}
|
||||
#endif
|
||||
|
@ -215,6 +215,13 @@ static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
|
||||
return X86_VEX_P(insn->vex_prefix.bytes[2]);
|
||||
}
|
||||
|
||||
static inline insn_byte_t insn_vex_w_bit(struct insn *insn)
|
||||
{
|
||||
if (insn->vex_prefix.nbytes < 3)
|
||||
return 0;
|
||||
return X86_VEX_W(insn->vex_prefix.bytes[2]);
|
||||
}
|
||||
|
||||
/* Get the last prefix id from last prefix or VEX prefix */
|
||||
static inline int insn_last_prefix_id(struct insn *insn)
|
||||
{
|
||||
|
@ -294,6 +294,10 @@ int insn_get_opcode(struct insn *insn)
|
||||
m = insn_vex_m_bits(insn);
|
||||
p = insn_vex_p_bits(insn);
|
||||
insn->attr = inat_get_avx_attribute(op, m, p);
|
||||
/* SCALABLE EVEX uses p bits to encode operand size */
|
||||
if (inat_evex_scalable(insn->attr) && !insn_vex_w_bit(insn) &&
|
||||
p == INAT_PFX_OPNDSZ)
|
||||
insn->opnd_bytes = 2;
|
||||
if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
|
||||
(!inat_accept_vex(insn->attr) &&
|
||||
!inat_is_group(insn->attr))) {
|
||||
|
@ -83,6 +83,8 @@ BEGIN {
|
||||
vexonly_expr = "\\(v\\)"
|
||||
# All opcodes with (ev) superscript supports *only* EVEX prefix
|
||||
evexonly_expr = "\\(ev\\)"
|
||||
# (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size
|
||||
evex_scalable_expr = "\\(es\\)"
|
||||
|
||||
prefix_expr = "\\(Prefix\\)"
|
||||
prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
|
||||
@ -332,6 +334,8 @@ function convert_operands(count,opnd, i,j,imm,mod)
|
||||
# check VEX codes
|
||||
if (match(ext, evexonly_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
|
||||
else if (match(ext, evex_scalable_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY | INAT_EVEX_SCALABLE")
|
||||
else if (match(ext, vexonly_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
|
||||
else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
|
||||
|
@ -81,6 +81,7 @@
|
||||
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
|
||||
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
|
||||
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
|
||||
#define INAT_EVEX_SCALABLE (1 << (INAT_FLAG_OFFS + 10))
|
||||
/* Attribute making macros for attribute tables */
|
||||
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
|
||||
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
|
||||
@ -236,4 +237,9 @@ static inline int inat_must_evex(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_EVEXONLY;
|
||||
}
|
||||
|
||||
static inline int inat_evex_scalable(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_EVEX_SCALABLE;
|
||||
}
|
||||
#endif
|
||||
|
@ -215,6 +215,13 @@ static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
|
||||
return X86_VEX_P(insn->vex_prefix.bytes[2]);
|
||||
}
|
||||
|
||||
static inline insn_byte_t insn_vex_w_bit(struct insn *insn)
|
||||
{
|
||||
if (insn->vex_prefix.nbytes < 3)
|
||||
return 0;
|
||||
return X86_VEX_W(insn->vex_prefix.bytes[2]);
|
||||
}
|
||||
|
||||
/* Get the last prefix id from last prefix or VEX prefix */
|
||||
static inline int insn_last_prefix_id(struct insn *insn)
|
||||
{
|
||||
|
@ -294,6 +294,10 @@ int insn_get_opcode(struct insn *insn)
|
||||
m = insn_vex_m_bits(insn);
|
||||
p = insn_vex_p_bits(insn);
|
||||
insn->attr = inat_get_avx_attribute(op, m, p);
|
||||
/* SCALABLE EVEX uses p bits to encode operand size */
|
||||
if (inat_evex_scalable(insn->attr) && !insn_vex_w_bit(insn) &&
|
||||
p == INAT_PFX_OPNDSZ)
|
||||
insn->opnd_bytes = 2;
|
||||
if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
|
||||
(!inat_accept_vex(insn->attr) &&
|
||||
!inat_is_group(insn->attr))) {
|
||||
|
@ -83,6 +83,8 @@ BEGIN {
|
||||
vexonly_expr = "\\(v\\)"
|
||||
# All opcodes with (ev) superscript supports *only* EVEX prefix
|
||||
evexonly_expr = "\\(ev\\)"
|
||||
# (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size
|
||||
evex_scalable_expr = "\\(es\\)"
|
||||
|
||||
prefix_expr = "\\(Prefix\\)"
|
||||
prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
|
||||
@ -332,6 +334,8 @@ function convert_operands(count,opnd, i,j,imm,mod)
|
||||
# check VEX codes
|
||||
if (match(ext, evexonly_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
|
||||
else if (match(ext, evex_scalable_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY | INAT_EVEX_SCALABLE")
|
||||
else if (match(ext, vexonly_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
|
||||
else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
|
||||
|
Loading…
x
Reference in New Issue
Block a user