[RFC v5 42/57] objtool: arm64: Decode SVE instructions

From: Julien Thierry
Date: Thu Jan 09 2020 - 11:08:31 EST


Decode instructions from the SVE architecture extension.

These instructions do not modify the stack or frame pointer. Simply
acknowledge the corresponding opcodes are valid.

Suggested-by: Raphael Gault <raphael.gault@xxxxxxx>
Signed-off-by: Julien Thierry <jthierry@xxxxxxxxxx>
---
tools/objtool/arch/arm64/decode.c | 109 ++++++++++++++++++
.../objtool/arch/arm64/include/insn_decode.h | 4 +
2 files changed, 113 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index d35c2b58d309..5a5f82b5cb81 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -126,6 +126,7 @@ static int is_arm64(struct elf *elf)
static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
[INSN_RESERVED] = arm_decode_unknown,
[INSN_UNKNOWN] = arm_decode_unknown,
+ [INSN_SVE_ENC] = arm_decode_sve_encoding,
[INSN_UNALLOC] = arm_decode_unknown,
[INSN_LD_ST_4] = arm_decode_ld_st,
[INSN_DP_REG_5] = arm_decode_dp_reg,
@@ -2755,3 +2756,111 @@ int arm_decode_dp_simd(u32 instr, enum insn_type *type,
*type = INSN_OTHER;
return 0;
}
+
+static struct aarch64_insn_decoder sve_enc_decoder[] = {
+ {
+ .mask = 0b1111010000111000,
+ .value = 0b0000010000011000,
+ },
+ {
+ .mask = 0b1111110000111000,
+ .value = 0b0001110000000000,
+ },
+ {
+ .mask = 0b1111010000110000,
+ .value = 0b0011010000010000,
+ },
+ {
+ .mask = 0b1111011100111000,
+ .value = 0b0011010100101000,
+ },
+ {
+ .mask = 0b1111011000110000,
+ .value = 0b0011011000100000,
+ },
+ {
+ .mask = 0b1111010000100000,
+ .value = 0b0100000000100000,
+ },
+ {
+ .mask = 0b1111000000000000,
+ .value = 0b0101000000000000,
+ },
+ {
+ .mask = 0b1111011111111000,
+ .value = 0b0110000000101000,
+ },
+ {
+ .mask = 0b1111011111110000,
+ .value = 0b0110000000110000,
+ },
+ {
+ .mask = 0b1111011111100000,
+ .value = 0b0110000001100000,
+ },
+ {
+ .mask = 0b1111011110100000,
+ .value = 0b0110000010100000,
+ },
+ {
+ .mask = 0b1111011100100000,
+ .value = 0b0110000100100000,
+ },
+ {
+ .mask = 0b1111011000100000,
+ .value = 0b0110001000100000,
+ },
+ {
+ .mask = 0b1111010000110110,
+ .value = 0b0110010000000010,
+ },
+ {
+ .mask = 0b1111010000111111,
+ .value = 0b0110010000001001,
+ },
+ {
+ .mask = 0b1111010000111100,
+ .value = 0b0110010000001100,
+ },
+ {
+ .mask = 0b1111010000110000,
+ .value = 0b0110010000010000,
+ },
+ {
+ .mask = 0b1111010000100000,
+ .value = 0b0110010000100000,
+ },
+ {
+ .mask = 0b1111011100111100,
+ .value = 0b0111000100001000,
+ },
+};
+
+int arm_decode_sve_encoding(u32 instr, enum insn_type *type,
+ unsigned long *immediate,
+ struct list_head *ops_list)
+{
+ int i = 0;
+ unsigned char op0 = 0, op1 = 0, op2 = 0, op3 = 0;
+ u32 decode_field = 0;
+
+ op0 = (instr >> 29) & ONES(3);
+ op1 = (instr >> 23) & ONES(2);
+ op2 = (instr >> 17) & ONES(5);
+ op3 = (instr >> 10) & ONES(6);
+
+ decode_field = (op0 << 2) | op1;
+ decode_field = (decode_field << 5) | op2;
+ decode_field = (decode_field << 6) | op3;
+
+ for (i = 0; i < ARRAY_SIZE(sve_enc_decoder); i++) {
+ if ((decode_field & sve_enc_decoder[i].mask) ==
+ sve_enc_decoder[i].value)
+ return arm_decode_unknown(instr, type, immediate,
+ ops_list);
+ }
+
+ *type = INSN_OTHER;
+
+ return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 2bff4d7da007..89cff8791c0b 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -7,6 +7,7 @@

#define INSN_RESERVED 0b0000
#define INSN_UNKNOWN 0b0001
+#define INSN_SVE_ENC 0b0010
#define INSN_UNALLOC 0b0011
#define INSN_DP_IMM 0b1001 //0x100x
#define INSN_SYS_BRANCH 0b1011 //0x101x
@@ -41,6 +42,9 @@ struct aarch64_insn_decoder {
};

/* arm64 instruction classes */
+int arm_decode_sve_encoding(u32 instr, enum insn_type *type,
+ unsigned long *immediate,
+ struct list_head *ops_list);
int arm_decode_dp_imm(u32 instr, enum insn_type *type,
unsigned long *immediate, struct list_head *ops_list);
int arm_decode_dp_reg(u32 instr, enum insn_type *type,
--
2.21.0