From 193aeedc9b66d759148d51b97610ec4558569aae Mon Sep 17 00:00:00 2001 From: Mykola Hohsadze Date: Mon, 24 Jul 2023 17:49:24 -0300 Subject: arm64/disassem.c: add extended register instruction definitions Add disassembly support for the following extended register instructions: add, adds, sub, subs, cmp, cmn. Reviewed by: mhorne MFC after: 1 week Pull Request: https://reviews.freebsd.org/D40967 (cherry picked from commit 4a07c778632bddb86a82f3e1fe144d889dae69c5) --- sys/arm64/arm64/disassem.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/sys/arm64/arm64/disassem.c b/sys/arm64/arm64/disassem.c index c1e38266a2e0..a86fef1d96a6 100644 --- a/sys/arm64/arm64/disassem.c +++ b/sys/arm64/arm64/disassem.c @@ -73,6 +73,11 @@ static const char *shift_2[] = { "lsl", "lsr", "asr", "ror" }; +static const char *extend_types[] = { + "uxtb", "uxth", "uxtw", "uxtx", + "sxtb", "sxth", "sxtw", "sxtx", +}; + /* * Structure representing single token (operand) inside instruction. * name - name of operand @@ -107,6 +112,12 @@ enum arm64_format_type { /* OP , #imm SF32/64 */ TYPE_03, + + /* + * OP , , {, { # } } + * OP , , {, { # } } + */ + TYPE_04, }; /* @@ -260,6 +271,18 @@ static struct arm64_insn arm64_i[] = { TYPE_01, OP_SHIFT_ROR }, /* eon shifted register */ { "eor", "SF(1)|1001010|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)", TYPE_01, OP_SHIFT_ROR }, /* eor shifted register */ + { "add", "SF(1)|0001011001|RM(5)|OPTION(3)|IMM(3)|RN(5)|RD(5)", + TYPE_04, OP_RD_SP }, /* add extended register */ + { "cmn", "SF(1)|0101011001|RM(5)|OPTION(3)|IMM(3)|RN(5)|11111", + TYPE_04, 0 }, /* cmn extended register */ + { "adds", "SF(1)|0101011001|RM(5)|OPTION(3)|IMM(3)|RN(5)|RD(5)", + TYPE_04, 0 }, /* adds extended register */ + { "sub", "SF(1)|1001011001|RM(5)|OPTION(3)|IMM(3)|RN(5)|RD(5)", + TYPE_04, OP_RD_SP }, /* sub extended register */ + { "cmp", "SF(1)|1101011001|RM(5)|OPTION(3)|IMM(3)|RN(5)|11111", + TYPE_04, 0 }, /* cmp extended register */ + { "subs", "SF(1)|1101011001|RM(5)|OPTION(3)|IMM(3)|RN(5)|RD(5)", + TYPE_04, 0 }, /* subs extended register */ { NULL, NULL } }; @@ -408,6 +431,27 @@ arm64_disasm_read_token_sign_ext(struct arm64_insn *insn, u_int opcode, return (EINVAL); } +static const char * +arm64_disasm_reg_extend(int sf, int option, int rd, int rn, int amount) +{ + bool is_sp, lsl_preferred_uxtw, lsl_preferred_uxtx, lsl_preferred; + + is_sp = rd == 31 || rn == 31; + lsl_preferred_uxtw = sf == 0 && option == 2; + lsl_preferred_uxtx = sf == 1 && option == 3; + lsl_preferred = is_sp && (lsl_preferred_uxtw || lsl_preferred_uxtx); + + /* + * LSL may be omitted when is 0. + * In all other cases is required. + */ + if (lsl_preferred && amount == 0) + return (NULL); + if (lsl_preferred) + return ("lsl"); + return (extend_types[option]); +} + static const char * arm64_w_reg(int num, int wsp) { @@ -432,6 +476,18 @@ arm64_reg(int b64, int num, int sp) return (arm64_w_reg(num, sp)); } +/* + * Decodes OPTION(3) to get register or + * for extended register instruction. + */ +static const char * +arm64_disasm_reg_width(int option, int reg) +{ + if (option == 3 || option == 7) + return (arm64_x_reg(reg, 0)); + return (arm64_w_reg(reg, 0)); +} + vm_offset_t disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt) { @@ -451,10 +507,13 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt) /* Indicate if shift type ror is supported */ bool has_shift_ror; + const char *extend; + /* Initialize defaults, all are 0 except SF indicating 64bit access */ shift = rd = rm = rn = imm = idx = option = amount = scale = 0; sign_ext = 0; sf = 1; + extend = NULL; matchp = 0; insn = di->di_readword(loc); @@ -669,6 +728,37 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt) di->di_printf("#%d", imm); break; + + case TYPE_04: + /* + * OP , , {, { # } } + * OP , , {, { # } } + */ + + arm64_disasm_read_token(i_ptr, insn, "RN", &rn); + arm64_disasm_read_token(i_ptr, insn, "RM", &rm); + arm64_disasm_read_token(i_ptr, insn, "OPTION", &option); + + rd_absent = arm64_disasm_read_token(i_ptr, insn, "RD", &rd); + extend = arm64_disasm_reg_extend(sf, option, rd, rn, imm); + + di->di_printf("%s\t", i_ptr->name); + + if (!rd_absent) + di->di_printf("%s, ", arm64_reg(sf, rd, rd_sp)); + + di->di_printf("%s, ", arm64_reg(sf, rn, 1)); + + if (sf != 0) + di->di_printf("%s", + arm64_disasm_reg_width(option, rm)); + else + di->di_printf("%s", arm64_w_reg(rm, 0)); + + if (extend != NULL) + di->di_printf(", %s #%d", extend, imm); + + break; default: goto undefined; } -- cgit v1.2.3