18a1867f4SWojciech Macek /*- 28a1867f4SWojciech Macek * Copyright (c) 2016 Cavium 38a1867f4SWojciech Macek * All rights reserved. 48a1867f4SWojciech Macek * 58a1867f4SWojciech Macek * This software was developed by Semihalf. 68a1867f4SWojciech Macek * 78a1867f4SWojciech Macek * Redistribution and use in source and binary forms, with or without 88a1867f4SWojciech Macek * modification, are permitted provided that the following conditions 98a1867f4SWojciech Macek * are met: 108a1867f4SWojciech Macek * 1. Redistributions of source code must retain the above copyright 118a1867f4SWojciech Macek * notice, this list of conditions and the following disclaimer. 128a1867f4SWojciech Macek * 2. Redistributions in binary form must reproduce the above copyright 138a1867f4SWojciech Macek * notice, this list of conditions and the following disclaimer in the 148a1867f4SWojciech Macek * documentation and/or other materials provided with the distribution. 158a1867f4SWojciech Macek * 168a1867f4SWojciech Macek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 178a1867f4SWojciech Macek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188a1867f4SWojciech Macek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198a1867f4SWojciech Macek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 208a1867f4SWojciech Macek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 218a1867f4SWojciech Macek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228a1867f4SWojciech Macek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 238a1867f4SWojciech Macek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 248a1867f4SWojciech Macek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258a1867f4SWojciech Macek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268a1867f4SWojciech Macek * SUCH DAMAGE. 278a1867f4SWojciech Macek */ 288a1867f4SWojciech Macek 298a1867f4SWojciech Macek #include <sys/cdefs.h> 308a1867f4SWojciech Macek __FBSDID("$FreeBSD$"); 318a1867f4SWojciech Macek #include <sys/param.h> 328a1867f4SWojciech Macek 338a1867f4SWojciech Macek #include <sys/systm.h> 348a1867f4SWojciech Macek #include <machine/disassem.h> 358a1867f4SWojciech Macek #include <machine/armreg.h> 368a1867f4SWojciech Macek #include <ddb/ddb.h> 378a1867f4SWojciech Macek 388a1867f4SWojciech Macek #define ARM64_MAX_TOKEN_LEN 8 398a1867f4SWojciech Macek #define ARM64_MAX_TOKEN_CNT 10 408a1867f4SWojciech Macek 41c7fc655fSWojciech Macek #define ARM_INSN_SIZE_OFFSET 30 42c7fc655fSWojciech Macek #define ARM_INSN_SIZE_MASK 0x3 43c7fc655fSWojciech Macek 44c7fc655fSWojciech Macek /* Special options for instruction printing */ 45c7fc655fSWojciech Macek #define OP_SIGN_EXT (1UL << 0) /* Sign-extend immediate value */ 46c7fc655fSWojciech Macek #define OP_LITERAL (1UL << 1) /* Use literal (memory offset) */ 47c7fc655fSWojciech Macek #define OP_MULT_4 (1UL << 2) /* Multiply immediate by 4 */ 48c7fc655fSWojciech Macek #define OP_SF32 (1UL << 3) /* Force 32-bit access */ 49c7fc655fSWojciech Macek #define OP_SF_INV (1UL << 6) /* SF is inverted (1 means 32 bit access) */ 50c7fc655fSWojciech Macek 518a1867f4SWojciech Macek static const char *w_reg[] = { 528a1867f4SWojciech Macek "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", 538a1867f4SWojciech Macek "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", 548a1867f4SWojciech Macek "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", 558a1867f4SWojciech Macek "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wSP", 568a1867f4SWojciech Macek }; 578a1867f4SWojciech Macek 588a1867f4SWojciech Macek static const char *x_reg[] = { 598a1867f4SWojciech Macek "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 608a1867f4SWojciech Macek "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 618a1867f4SWojciech Macek "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 628a1867f4SWojciech Macek "x24", "x25", "x26", "x27", "x28", "x29", "LR", "SP", 638a1867f4SWojciech Macek }; 648a1867f4SWojciech Macek 658a1867f4SWojciech Macek static const char *shift_2[] = { 668a1867f4SWojciech Macek "LSL", "LSR", "ASR", "RSV" 678a1867f4SWojciech Macek }; 688a1867f4SWojciech Macek 698a1867f4SWojciech Macek /* 708a1867f4SWojciech Macek * Structure representing single token (operand) inside instruction. 718a1867f4SWojciech Macek * name - name of operand 728a1867f4SWojciech Macek * pos - position within the instruction (in bits) 738a1867f4SWojciech Macek * len - operand length (in bits) 748a1867f4SWojciech Macek */ 758a1867f4SWojciech Macek struct arm64_insn_token { 768a1867f4SWojciech Macek char name[ARM64_MAX_TOKEN_LEN]; 778a1867f4SWojciech Macek int pos; 788a1867f4SWojciech Macek int len; 798a1867f4SWojciech Macek }; 808a1867f4SWojciech Macek 818a1867f4SWojciech Macek /* 828a1867f4SWojciech Macek * Define generic types for instruction printing. 838a1867f4SWojciech Macek */ 848a1867f4SWojciech Macek enum arm64_format_type { 858a1867f4SWojciech Macek TYPE_01, /* OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #<imm>} SF32/64 868a1867f4SWojciech Macek OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64 */ 87c7fc655fSWojciech Macek TYPE_02, /* OP <RT>, [<RN>, #<imm>]{!}] SF32/64 88c7fc655fSWojciech Macek OP <RT>, [<RN>], #<imm>{!} SF32/64 89c7fc655fSWojciech Macek OP <RT>, <RN>, <RM> {, EXTEND AMOUNT } */ 90c7fc655fSWojciech Macek TYPE_03, /* OP <RT>, #imm SF32/64 */ 918a1867f4SWojciech Macek }; 928a1867f4SWojciech Macek 938a1867f4SWojciech Macek /* 948a1867f4SWojciech Macek * Structure representing single parsed instruction format. 958a1867f4SWojciech Macek * name - opcode name 968a1867f4SWojciech Macek * format - opcode format in a human-readable way 978a1867f4SWojciech Macek * type - syntax type for printing 988a1867f4SWojciech Macek * special_ops - special options passed to a printer (if any) 998a1867f4SWojciech Macek * mask - bitmask for instruction matching 1008a1867f4SWojciech Macek * pattern - pattern to look for 1018a1867f4SWojciech Macek * tokens - array of tokens (operands) inside instruction 1028a1867f4SWojciech Macek */ 1038a1867f4SWojciech Macek struct arm64_insn { 1048a1867f4SWojciech Macek char* name; 1058a1867f4SWojciech Macek char* format; 1068a1867f4SWojciech Macek enum arm64_format_type type; 1078a1867f4SWojciech Macek uint64_t special_ops; 1088a1867f4SWojciech Macek uint32_t mask; 1098a1867f4SWojciech Macek uint32_t pattern; 1108a1867f4SWojciech Macek struct arm64_insn_token tokens[ARM64_MAX_TOKEN_CNT]; 1118a1867f4SWojciech Macek }; 1128a1867f4SWojciech Macek 1138a1867f4SWojciech Macek /* 1148a1867f4SWojciech Macek * Specify instruction opcode format in a human-readable way. Use notation 1158a1867f4SWojciech Macek * obtained from ARM Architecture Reference Manual for ARMv8-A. 1168a1867f4SWojciech Macek * 1178a1867f4SWojciech Macek * Format string description: 1188a1867f4SWojciech Macek * Each group must be separated by "|". Group made of 0/1 is used to 1198a1867f4SWojciech Macek * generate mask and pattern for instruction matching. Groups containing 1208a1867f4SWojciech Macek * an operand token (in format NAME(length_bits)) are used to retrieve any 1218a1867f4SWojciech Macek * operand data from the instruction. Names here must be meaningful 1228a1867f4SWojciech Macek * and match the one described in the Manual. 1238a1867f4SWojciech Macek * 1248a1867f4SWojciech Macek * Token description: 1258a1867f4SWojciech Macek * SF - "0" represents 32-bit access, "1" represents 64-bit access 1268a1867f4SWojciech Macek * SHIFT - type of shift (instruction dependent) 1278a1867f4SWojciech Macek * IMM - immediate value 1288a1867f4SWojciech Macek * Rx - register number 129c7fc655fSWojciech Macek * OPTION - command specific options 130c7fc655fSWojciech Macek * SCALE - scaling of immediate value 1318a1867f4SWojciech Macek */ 1328a1867f4SWojciech Macek static struct arm64_insn arm64_i[] = { 133c7fc655fSWojciech Macek { "add", "SF(1)|0001011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)", 134c7fc655fSWojciech Macek TYPE_01, 0 }, 135c7fc655fSWojciech Macek { "mov", "SF(1)|001000100000000000000|RN(5)|RD(5)", 136c7fc655fSWojciech Macek TYPE_01, 0 }, 137c7fc655fSWojciech Macek { "add", "SF(1)|0010001|SHIFT(2)|IMM(12)|RN(5)|RD(5)", 138c7fc655fSWojciech Macek TYPE_01, 0 }, 139c7fc655fSWojciech Macek { "ldr", "1|SF(1)|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", 140c7fc655fSWojciech Macek TYPE_02, OP_SIGN_EXT }, /* ldr immediate post/pre index */ 141c7fc655fSWojciech Macek { "ldr", "1|SF(1)|11100101|IMM(12)|RN(5)|RT(5)", 142c7fc655fSWojciech Macek TYPE_02, 0 }, /* ldr immediate unsigned */ 143c7fc655fSWojciech Macek { "ldr", "1|SF(1)|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 144c7fc655fSWojciech Macek TYPE_02, 0 }, /* ldr register */ 145c7fc655fSWojciech Macek { "ldr", "0|SF(1)|011000|IMM(19)|RT(5)", 146c7fc655fSWojciech Macek TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */ 147c7fc655fSWojciech Macek { "ldrb", "00|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", 148c7fc655fSWojciech Macek TYPE_02, OP_SIGN_EXT | OP_SF32 }, /* ldrb immediate post/pre index */ 149c7fc655fSWojciech Macek { "ldrb", "00|11100101|IMM(12)|RN(5)|RT(5)", 150c7fc655fSWojciech Macek TYPE_02, OP_SF32 }, /* ldrb immediate unsigned */ 151c7fc655fSWojciech Macek { "ldrb", "00|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 152c7fc655fSWojciech Macek TYPE_02, OP_SF32 }, /* ldrb register */ 153c7fc655fSWojciech Macek { "ldrh", "01|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", TYPE_02, 154c7fc655fSWojciech Macek OP_SIGN_EXT | OP_SF32 }, /* ldrh immediate post/pre index */ 155c7fc655fSWojciech Macek { "ldrh", "01|11100101|IMM(12)|RN(5)|RT(5)", 156c7fc655fSWojciech Macek TYPE_02, OP_SF32 }, /* ldrh immediate unsigned */ 157c7fc655fSWojciech Macek { "ldrh", "01|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 158c7fc655fSWojciech Macek TYPE_02, OP_SF32 }, /* ldrh register */ 159c7fc655fSWojciech Macek { "ldrsb", "001110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)", 160c7fc655fSWojciech Macek TYPE_02, OP_SIGN_EXT | OP_SF_INV }, /* ldrsb immediate post/pre index */ 161c7fc655fSWojciech Macek { "ldrsb", "001110011|SF(1)|IMM(12)|RN(5)|RT(5)",\ 162c7fc655fSWojciech Macek TYPE_02, OP_SF_INV}, /* ldrsb immediate unsigned */ 163c7fc655fSWojciech Macek { "ldrsb", "001110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 164c7fc655fSWojciech Macek TYPE_02, OP_SF_INV }, /* ldrsb register */ 165c7fc655fSWojciech Macek { "ldrsh", "011110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)", 166c7fc655fSWojciech Macek TYPE_02, OP_SIGN_EXT | OP_SF_INV }, /* ldrsh immediate post/pre index */ 167c7fc655fSWojciech Macek { "ldrsh", "011110011|SF(1)|IMM(12)|RN(5)|RT(5)", 168c7fc655fSWojciech Macek TYPE_02, OP_SF_INV}, /* ldrsh immediate unsigned */ 169c7fc655fSWojciech Macek { "ldrsh", "011110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 170c7fc655fSWojciech Macek TYPE_02, OP_SF_INV }, /* ldrsh register */ 171c7fc655fSWojciech Macek { "ldrsw", "10111000100|IMM(9)|OPTION(2)|RN(5)|RT(5)", 172c7fc655fSWojciech Macek TYPE_02, OP_SIGN_EXT }, /* ldrsw immediate post/pre index */ 173c7fc655fSWojciech Macek { "ldrsw", "1011100110|IMM(12)|RN(5)|RT(5)", 174c7fc655fSWojciech Macek TYPE_02, 0 }, /* ldrsw immediate unsigned */ 175c7fc655fSWojciech Macek { "ldrsw", "10111000101|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 176c7fc655fSWojciech Macek TYPE_02, 0 }, /* ldrsw register */ 177c7fc655fSWojciech Macek { "ldrsw", "10011000|IMM(19)|RT(5)", 178c7fc655fSWojciech Macek TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */ 1798a1867f4SWojciech Macek { NULL, NULL } 1808a1867f4SWojciech Macek }; 1818a1867f4SWojciech Macek 1828a1867f4SWojciech Macek static void 1838a1867f4SWojciech Macek arm64_disasm_generate_masks(struct arm64_insn *tab) 1848a1867f4SWojciech Macek { 1858a1867f4SWojciech Macek uint32_t mask, val; 1868a1867f4SWojciech Macek int a, i; 1878a1867f4SWojciech Macek int len, ret; 1888a1867f4SWojciech Macek int token = 0; 1898a1867f4SWojciech Macek char *format; 1908a1867f4SWojciech Macek int error; 1918a1867f4SWojciech Macek 1928a1867f4SWojciech Macek while (tab->name != NULL) { 1938a1867f4SWojciech Macek mask = 0; 1948a1867f4SWojciech Macek val = 0; 1958a1867f4SWojciech Macek format = tab->format; 1968a1867f4SWojciech Macek token = 0; 1978a1867f4SWojciech Macek error = 0; 1988a1867f4SWojciech Macek 1998a1867f4SWojciech Macek /* 2008a1867f4SWojciech Macek * For each entry analyze format strings from the 2018a1867f4SWojciech Macek * left (i.e. from the MSB). 2028a1867f4SWojciech Macek */ 2038a1867f4SWojciech Macek a = (INSN_SIZE * NBBY) - 1; 2048a1867f4SWojciech Macek while (*format != '\0' && (a >= 0)) { 2058a1867f4SWojciech Macek switch(*format) { 2068a1867f4SWojciech Macek case '0': 2078a1867f4SWojciech Macek /* Bit is 0, add to mask and pattern */ 2088a1867f4SWojciech Macek mask |= (1 << a); 2098a1867f4SWojciech Macek a--; 2108a1867f4SWojciech Macek format++; 2118a1867f4SWojciech Macek break; 2128a1867f4SWojciech Macek case '1': 2138a1867f4SWojciech Macek /* Bit is 1, add to mask and pattern */ 2148a1867f4SWojciech Macek mask |= (1 << a); 2158a1867f4SWojciech Macek val |= (1 << a); 2168a1867f4SWojciech Macek a--; 2178a1867f4SWojciech Macek format++; 2188a1867f4SWojciech Macek break; 2198a1867f4SWojciech Macek case '|': 2208a1867f4SWojciech Macek /* skip */ 2218a1867f4SWojciech Macek format++; 2228a1867f4SWojciech Macek break; 2238a1867f4SWojciech Macek default: 2248a1867f4SWojciech Macek /* Token found, copy the name */ 2258a1867f4SWojciech Macek memset(tab->tokens[token].name, 0, 2268a1867f4SWojciech Macek sizeof(tab->tokens[token].name)); 2278a1867f4SWojciech Macek i = 0; 2288a1867f4SWojciech Macek while (*format != '(') { 2298a1867f4SWojciech Macek tab->tokens[token].name[i] = *format; 2308a1867f4SWojciech Macek i++; 2318a1867f4SWojciech Macek format++; 2328a1867f4SWojciech Macek if (i >= ARM64_MAX_TOKEN_LEN) { 2338a1867f4SWojciech Macek printf("ERROR: token too long in op %s\n", 2348a1867f4SWojciech Macek tab->name); 2358a1867f4SWojciech Macek error = 1; 2368a1867f4SWojciech Macek break; 2378a1867f4SWojciech Macek } 2388a1867f4SWojciech Macek } 2398a1867f4SWojciech Macek if (error != 0) 2408a1867f4SWojciech Macek break; 2418a1867f4SWojciech Macek 2428a1867f4SWojciech Macek /* Read the length value */ 2438a1867f4SWojciech Macek ret = sscanf(format, "(%d)", &len); 2448a1867f4SWojciech Macek if (ret == 1) { 2458a1867f4SWojciech Macek if (token >= ARM64_MAX_TOKEN_CNT) { 2468a1867f4SWojciech Macek printf("ERROR: to many tokens in op %s\n", 2478a1867f4SWojciech Macek tab->name); 2488a1867f4SWojciech Macek error = 1; 2498a1867f4SWojciech Macek break; 2508a1867f4SWojciech Macek } 2518a1867f4SWojciech Macek 2528a1867f4SWojciech Macek a -= len; 2538a1867f4SWojciech Macek tab->tokens[token].pos = a + 1; 2548a1867f4SWojciech Macek tab->tokens[token].len = len; 2558a1867f4SWojciech Macek token++; 2568a1867f4SWojciech Macek } 2578a1867f4SWojciech Macek 2588a1867f4SWojciech Macek /* Skip to the end of the token */ 2598a1867f4SWojciech Macek while (*format != 0 && *format != '|') 2608a1867f4SWojciech Macek format++; 2618a1867f4SWojciech Macek } 2628a1867f4SWojciech Macek } 2638a1867f4SWojciech Macek 2648a1867f4SWojciech Macek /* Write mask and pattern to the instruction array */ 2658a1867f4SWojciech Macek tab->mask = mask; 2668a1867f4SWojciech Macek tab->pattern = val; 2678a1867f4SWojciech Macek 2688a1867f4SWojciech Macek /* 2698a1867f4SWojciech Macek * If we got here, format string must be parsed and "a" 2708a1867f4SWojciech Macek * should point to -1. If it's not, wrong number of bits 2718a1867f4SWojciech Macek * in format string. Mark this as invalid and prevent 2728a1867f4SWojciech Macek * from being matched. 2738a1867f4SWojciech Macek */ 2748a1867f4SWojciech Macek if (*format != 0 || (a != -1) || (error != 0)) { 2758a1867f4SWojciech Macek tab->mask = 0; 2768a1867f4SWojciech Macek tab->pattern = 0xffffffff; 2778a1867f4SWojciech Macek printf("ERROR: skipping instruction op %s\n", 2788a1867f4SWojciech Macek tab->name); 2798a1867f4SWojciech Macek } 2808a1867f4SWojciech Macek 2818a1867f4SWojciech Macek tab++; 2828a1867f4SWojciech Macek } 2838a1867f4SWojciech Macek } 2848a1867f4SWojciech Macek 2858a1867f4SWojciech Macek static int 2868a1867f4SWojciech Macek arm64_disasm_read_token(struct arm64_insn *insn, u_int opcode, 2878a1867f4SWojciech Macek const char *token, int *val) 2888a1867f4SWojciech Macek { 2898a1867f4SWojciech Macek int i; 2908a1867f4SWojciech Macek 2918a1867f4SWojciech Macek for (i = 0; i < ARM64_MAX_TOKEN_CNT; i++) { 2928a1867f4SWojciech Macek if (strcmp(insn->tokens[i].name, token) == 0) { 2938a1867f4SWojciech Macek *val = (opcode >> insn->tokens[i].pos & 2948a1867f4SWojciech Macek ((1 << insn->tokens[i].len) - 1)); 2958a1867f4SWojciech Macek return (0); 2968a1867f4SWojciech Macek } 2978a1867f4SWojciech Macek } 2988a1867f4SWojciech Macek 2998a1867f4SWojciech Macek return (EINVAL); 3008a1867f4SWojciech Macek } 3018a1867f4SWojciech Macek 302c7fc655fSWojciech Macek static int 303c7fc655fSWojciech Macek arm64_disasm_read_token_sign_ext(struct arm64_insn *insn, u_int opcode, 304c7fc655fSWojciech Macek const char *token, int *val) 305c7fc655fSWojciech Macek { 306c7fc655fSWojciech Macek int i; 307c7fc655fSWojciech Macek int msk; 308c7fc655fSWojciech Macek 309c7fc655fSWojciech Macek for (i = 0; i < ARM64_MAX_TOKEN_CNT; i++) { 310c7fc655fSWojciech Macek if (strcmp(insn->tokens[i].name, token) == 0) { 311c7fc655fSWojciech Macek msk = (1 << insn->tokens[i].len) - 1; 312c7fc655fSWojciech Macek *val = ((opcode >> insn->tokens[i].pos) & msk); 313c7fc655fSWojciech Macek 314c7fc655fSWojciech Macek /* If last bit is 1, sign-extend the value */ 315c7fc655fSWojciech Macek if (*val & (1 << (insn->tokens[i].len - 1))) 316c7fc655fSWojciech Macek *val |= ~msk; 317c7fc655fSWojciech Macek 318c7fc655fSWojciech Macek return (0); 319c7fc655fSWojciech Macek } 320c7fc655fSWojciech Macek } 321c7fc655fSWojciech Macek 322c7fc655fSWojciech Macek return (EINVAL); 323c7fc655fSWojciech Macek } 324c7fc655fSWojciech Macek 3258a1867f4SWojciech Macek static const char * 3268a1867f4SWojciech Macek arm64_reg(int b64, int num) 3278a1867f4SWojciech Macek { 3288a1867f4SWojciech Macek 3298a1867f4SWojciech Macek if (b64 != 0) 3308a1867f4SWojciech Macek return (x_reg[num]); 3318a1867f4SWojciech Macek 3328a1867f4SWojciech Macek return (w_reg[num]); 3338a1867f4SWojciech Macek } 3348a1867f4SWojciech Macek 3358a1867f4SWojciech Macek vm_offset_t 3368a1867f4SWojciech Macek disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt) 3378a1867f4SWojciech Macek { 3388a1867f4SWojciech Macek struct arm64_insn *i_ptr = arm64_i; 3398a1867f4SWojciech Macek uint32_t insn; 3408a1867f4SWojciech Macek int matchp; 3418a1867f4SWojciech Macek int ret; 342c7fc655fSWojciech Macek int shift, rm, rt, rd, rn, imm, sf, idx, option, scale, amount; 343c7fc655fSWojciech Macek int sign_ext; 3448a1867f4SWojciech Macek int rm_absent; 345c7fc655fSWojciech Macek /* Indicate if immediate should be outside or inside brackets */ 346c7fc655fSWojciech Macek int inside; 347c7fc655fSWojciech Macek /* Print exclamation mark if pre-incremented */ 348c7fc655fSWojciech Macek int pre; 3498a1867f4SWojciech Macek 3508a1867f4SWojciech Macek /* Initialize defaults, all are 0 except SF indicating 64bit access */ 351c7fc655fSWojciech Macek shift = rd = rm = rn = imm = idx = option = amount = scale = 0; 352c7fc655fSWojciech Macek sign_ext = 0; 3538a1867f4SWojciech Macek sf = 1; 3548a1867f4SWojciech Macek 3558a1867f4SWojciech Macek matchp = 0; 3568a1867f4SWojciech Macek insn = di->di_readword(loc); 3578a1867f4SWojciech Macek while (i_ptr->name) { 3588a1867f4SWojciech Macek /* If mask is 0 then the parser was not initialized yet */ 3598a1867f4SWojciech Macek if ((i_ptr->mask != 0) && 3608a1867f4SWojciech Macek ((insn & i_ptr->mask) == i_ptr->pattern)) { 3618a1867f4SWojciech Macek matchp = 1; 3628a1867f4SWojciech Macek break; 3638a1867f4SWojciech Macek } 3648a1867f4SWojciech Macek i_ptr++; 3658a1867f4SWojciech Macek } 3668a1867f4SWojciech Macek if (matchp == 0) 3678a1867f4SWojciech Macek goto undefined; 3688a1867f4SWojciech Macek 369c7fc655fSWojciech Macek /* Global options */ 370c7fc655fSWojciech Macek if (i_ptr->special_ops & OP_SF32) 371c7fc655fSWojciech Macek sf = 0; 372c7fc655fSWojciech Macek 373c7fc655fSWojciech Macek /* Global optional tokens */ 374c7fc655fSWojciech Macek arm64_disasm_read_token(i_ptr, insn, "SF", &sf); 375c7fc655fSWojciech Macek if (i_ptr->special_ops & OP_SF_INV) 376c7fc655fSWojciech Macek sf = 1 - sf; 377c7fc655fSWojciech Macek if (arm64_disasm_read_token(i_ptr, insn, "SIGN", &sign_ext) == 0) 378c7fc655fSWojciech Macek sign_ext = 1 - sign_ext; 379c7fc655fSWojciech Macek if (i_ptr->special_ops & OP_SIGN_EXT) 380c7fc655fSWojciech Macek sign_ext = 1; 381c7fc655fSWojciech Macek if (sign_ext != 0) 382c7fc655fSWojciech Macek arm64_disasm_read_token_sign_ext(i_ptr, insn, "IMM", &imm); 383c7fc655fSWojciech Macek else 384c7fc655fSWojciech Macek arm64_disasm_read_token(i_ptr, insn, "IMM", &imm); 385c7fc655fSWojciech Macek if (i_ptr->special_ops & OP_MULT_4) 386c7fc655fSWojciech Macek imm <<= 2; 387c7fc655fSWojciech Macek 388c7fc655fSWojciech Macek /* Print opcode by type */ 3898a1867f4SWojciech Macek switch (i_ptr->type) { 3908a1867f4SWojciech Macek case TYPE_01: 3918a1867f4SWojciech Macek /* OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #<imm>} SF32/64 3928a1867f4SWojciech Macek OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64 */ 3938a1867f4SWojciech Macek 3948a1867f4SWojciech Macek /* Mandatory tokens */ 395c7fc655fSWojciech Macek ret = arm64_disasm_read_token(i_ptr, insn, "RD", &rd); 3968a1867f4SWojciech Macek ret |= arm64_disasm_read_token(i_ptr, insn, "RN", &rn); 3978a1867f4SWojciech Macek if (ret != 0) { 3988a1867f4SWojciech Macek printf("ERROR: Missing mandatory token for op %s type %d\n", 3998a1867f4SWojciech Macek i_ptr->name, i_ptr->type); 4008a1867f4SWojciech Macek goto undefined; 4018a1867f4SWojciech Macek } 4028a1867f4SWojciech Macek 4038a1867f4SWojciech Macek /* Optional tokens */ 4048a1867f4SWojciech Macek arm64_disasm_read_token(i_ptr, insn, "SHIFT", &shift); 4058a1867f4SWojciech Macek rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm); 4068a1867f4SWojciech Macek 4078a1867f4SWojciech Macek di->di_printf("%s\t%s, %s", i_ptr->name, arm64_reg(sf, rd), 4088a1867f4SWojciech Macek arm64_reg(sf, rn)); 4098a1867f4SWojciech Macek 4108a1867f4SWojciech Macek /* If RM is present use it, otherwise use immediate notation */ 4118a1867f4SWojciech Macek if (rm_absent == 0) { 4128a1867f4SWojciech Macek di->di_printf(", %s", arm64_reg(sf, rm)); 4138a1867f4SWojciech Macek if (imm != 0) 4148a1867f4SWojciech Macek di->di_printf(", %s #%d", shift_2[shift], imm); 4158a1867f4SWojciech Macek } else { 4168a1867f4SWojciech Macek if (imm != 0 || shift != 0) 4178a1867f4SWojciech Macek di->di_printf(", #0x%x", imm); 4188a1867f4SWojciech Macek if (shift != 0) 4198a1867f4SWojciech Macek di->di_printf(" LSL #12"); 4208a1867f4SWojciech Macek } 4218a1867f4SWojciech Macek break; 422c7fc655fSWojciech Macek case TYPE_02: 423c7fc655fSWojciech Macek /* OP <RT>, [<RN>, #<imm>]{!}] SF32/64 424c7fc655fSWojciech Macek OP <RT>, [<RN>], #<imm>{!} SF32/64 425c7fc655fSWojciech Macek OP <RT>, <RN>, <RM> {, EXTEND AMOUNT } */ 426c7fc655fSWojciech Macek 427c7fc655fSWojciech Macek /* Mandatory tokens */ 428c7fc655fSWojciech Macek ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt); 429c7fc655fSWojciech Macek ret |= arm64_disasm_read_token(i_ptr, insn, "RN", &rn); 430c7fc655fSWojciech Macek if (ret != 0) { 431c7fc655fSWojciech Macek printf("ERROR: Missing mandatory token for op %s type %d\n", 432c7fc655fSWojciech Macek i_ptr->name, i_ptr->type); 433c7fc655fSWojciech Macek goto undefined; 434c7fc655fSWojciech Macek } 435c7fc655fSWojciech Macek 436c7fc655fSWojciech Macek /* Optional tokens */ 437c7fc655fSWojciech Macek arm64_disasm_read_token(i_ptr, insn, "OPTION", &option); 438c7fc655fSWojciech Macek arm64_disasm_read_token(i_ptr, insn, "SCALE", &scale); 439c7fc655fSWojciech Macek rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm); 440c7fc655fSWojciech Macek 441c7fc655fSWojciech Macek if (rm_absent) { 442c7fc655fSWojciech Macek /* 443c7fc655fSWojciech Macek * In unsigned operation, shift immediate value 444c7fc655fSWojciech Macek * and reset options to default. 445c7fc655fSWojciech Macek */ 446c7fc655fSWojciech Macek if (sign_ext == 0) { 447c7fc655fSWojciech Macek imm = imm << ((insn >> ARM_INSN_SIZE_OFFSET) & 448c7fc655fSWojciech Macek ARM_INSN_SIZE_MASK); 449c7fc655fSWojciech Macek option = 0; 450c7fc655fSWojciech Macek } 451c7fc655fSWojciech Macek switch (option) { 452c7fc655fSWojciech Macek case 0x0: 453c7fc655fSWojciech Macek pre = 0; 454c7fc655fSWojciech Macek inside = 1; 455c7fc655fSWojciech Macek break; 456c7fc655fSWojciech Macek case 0x1: 457c7fc655fSWojciech Macek pre = 0; 458c7fc655fSWojciech Macek inside = 0; 459c7fc655fSWojciech Macek break; 460c7fc655fSWojciech Macek case 0x2: 461c7fc655fSWojciech Macek default: 462c7fc655fSWojciech Macek pre = 1; 463c7fc655fSWojciech Macek inside = 1; 464c7fc655fSWojciech Macek break; 465c7fc655fSWojciech Macek } 466c7fc655fSWojciech Macek 467c7fc655fSWojciech Macek di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt)); 468c7fc655fSWojciech Macek if (inside != 0) { 469c7fc655fSWojciech Macek di->di_printf("[%s", arm64_reg(1, rn)); 470c7fc655fSWojciech Macek if (imm != 0) 471c7fc655fSWojciech Macek di->di_printf(", #%d", imm); 472c7fc655fSWojciech Macek di->di_printf("]"); 473c7fc655fSWojciech Macek } else { 474c7fc655fSWojciech Macek di->di_printf("[%s]", arm64_reg(1, rn)); 475c7fc655fSWojciech Macek if (imm != 0) 476c7fc655fSWojciech Macek di->di_printf(", #%d", imm); 477c7fc655fSWojciech Macek } 478c7fc655fSWojciech Macek if (pre != 0) 479c7fc655fSWojciech Macek di->di_printf("!"); 480c7fc655fSWojciech Macek } else { 481c7fc655fSWojciech Macek /* Last bit of option field determines 32/64 bit offset */ 482c7fc655fSWojciech Macek di->di_printf("%s\t%s, [%s, %s", i_ptr->name, 483c7fc655fSWojciech Macek arm64_reg(sf, rt), arm64_reg(1, rn), 484c7fc655fSWojciech Macek arm64_reg(option & 1, rm)); 485c7fc655fSWojciech Macek 486c7fc655fSWojciech Macek /* Calculate amount, it's op(31:30) */ 487c7fc655fSWojciech Macek amount = (insn >> ARM_INSN_SIZE_OFFSET) & 488c7fc655fSWojciech Macek ARM_INSN_SIZE_MASK; 489c7fc655fSWojciech Macek 490c7fc655fSWojciech Macek switch (option) { 491c7fc655fSWojciech Macek case 0x2: 492c7fc655fSWojciech Macek di->di_printf(", uxtw #%d", amount); 493c7fc655fSWojciech Macek break; 494c7fc655fSWojciech Macek case 0x3: 495c7fc655fSWojciech Macek if (scale != 0) 496c7fc655fSWojciech Macek di->di_printf(", lsl #%d", amount); 497c7fc655fSWojciech Macek break; 498c7fc655fSWojciech Macek case 0x6: 499c7fc655fSWojciech Macek di->di_printf(", sxtw #%d", amount); 500c7fc655fSWojciech Macek break; 501c7fc655fSWojciech Macek case 0x7: 502c7fc655fSWojciech Macek di->di_printf(", sxts #%d", amount); 503c7fc655fSWojciech Macek break; 504c7fc655fSWojciech Macek default: 505c7fc655fSWojciech Macek di->di_printf(", RSVD"); 506c7fc655fSWojciech Macek break; 507c7fc655fSWojciech Macek } 508c7fc655fSWojciech Macek di->di_printf("]"); 509c7fc655fSWojciech Macek } 510c7fc655fSWojciech Macek 511c7fc655fSWojciech Macek break; 512c7fc655fSWojciech Macek 513c7fc655fSWojciech Macek case TYPE_03: 514c7fc655fSWojciech Macek /* OP <RT>, #imm SF32/64 */ 515c7fc655fSWojciech Macek 516c7fc655fSWojciech Macek /* Mandatory tokens */ 517c7fc655fSWojciech Macek ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt); 518c7fc655fSWojciech Macek if (ret != 0) { 519c7fc655fSWojciech Macek printf("ERROR: Missing mandatory token for op %s type %d\n", 520c7fc655fSWojciech Macek i_ptr->name, i_ptr->type); 521c7fc655fSWojciech Macek goto undefined; 522c7fc655fSWojciech Macek } 523c7fc655fSWojciech Macek 524c7fc655fSWojciech Macek di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt)); 525c7fc655fSWojciech Macek if (i_ptr->special_ops & OP_LITERAL) 526c7fc655fSWojciech Macek di->di_printf("0x%lx", loc + imm); 527c7fc655fSWojciech Macek else 528c7fc655fSWojciech Macek di->di_printf("#%d", imm); 529c7fc655fSWojciech Macek 530c7fc655fSWojciech Macek break; 5318a1867f4SWojciech Macek default: 5328a1867f4SWojciech Macek goto undefined; 5338a1867f4SWojciech Macek } 5348a1867f4SWojciech Macek 5358a1867f4SWojciech Macek di->di_printf("\n"); 5368a1867f4SWojciech Macek return(loc + INSN_SIZE); 5378a1867f4SWojciech Macek 5388a1867f4SWojciech Macek undefined: 5398a1867f4SWojciech Macek di->di_printf("undefined\t%08x\n", insn); 5408a1867f4SWojciech Macek return(loc + INSN_SIZE); 5418a1867f4SWojciech Macek } 5428a1867f4SWojciech Macek 5438a1867f4SWojciech Macek /* Parse format strings at the very beginning */ 5448a1867f4SWojciech Macek SYSINIT(arm64_disasm_generate_masks, SI_SUB_DDB_SERVICES, 5458a1867f4SWojciech Macek SI_ORDER_FIRST, arm64_disasm_generate_masks, arm64_i); 546