1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2696e2457SJiri Olsa #include <linux/compiler.h>
3696e2457SJiri Olsa
powerpc__associate_instruction_ops(struct arch * arch,const char * name)4dbdebdc5SRavi Bangoria static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name)
5dbdebdc5SRavi Bangoria {
6dbdebdc5SRavi Bangoria int i;
7dbdebdc5SRavi Bangoria struct ins_ops *ops;
8dbdebdc5SRavi Bangoria
9dbdebdc5SRavi Bangoria /*
10dbdebdc5SRavi Bangoria * - Interested only if instruction starts with 'b'.
11dbdebdc5SRavi Bangoria * - Few start with 'b', but aren't branch instructions.
12dbdebdc5SRavi Bangoria */
13dbdebdc5SRavi Bangoria if (name[0] != 'b' ||
14dbdebdc5SRavi Bangoria !strncmp(name, "bcd", 3) ||
15dbdebdc5SRavi Bangoria !strncmp(name, "brinc", 5) ||
16dbdebdc5SRavi Bangoria !strncmp(name, "bper", 4))
17dbdebdc5SRavi Bangoria return NULL;
18dbdebdc5SRavi Bangoria
19dbdebdc5SRavi Bangoria ops = &jump_ops;
20dbdebdc5SRavi Bangoria
21dbdebdc5SRavi Bangoria i = strlen(name) - 1;
22dbdebdc5SRavi Bangoria if (i < 0)
23dbdebdc5SRavi Bangoria return NULL;
24dbdebdc5SRavi Bangoria
25dbdebdc5SRavi Bangoria /* ignore optional hints at the end of the instructions */
26dbdebdc5SRavi Bangoria if (name[i] == '+' || name[i] == '-')
27dbdebdc5SRavi Bangoria i--;
28dbdebdc5SRavi Bangoria
29dbdebdc5SRavi Bangoria if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) {
30dbdebdc5SRavi Bangoria /*
31dbdebdc5SRavi Bangoria * if the instruction ends up with 'l' or 'la', then
32dbdebdc5SRavi Bangoria * those are considered 'calls' since they update LR.
33dbdebdc5SRavi Bangoria * ... except for 'bnl' which is branch if not less than
34dbdebdc5SRavi Bangoria * and the absolute form of the same.
35dbdebdc5SRavi Bangoria */
36dbdebdc5SRavi Bangoria if (strcmp(name, "bnl") && strcmp(name, "bnl+") &&
37dbdebdc5SRavi Bangoria strcmp(name, "bnl-") && strcmp(name, "bnla") &&
38dbdebdc5SRavi Bangoria strcmp(name, "bnla+") && strcmp(name, "bnla-"))
39dbdebdc5SRavi Bangoria ops = &call_ops;
40dbdebdc5SRavi Bangoria }
41dbdebdc5SRavi Bangoria if (name[i] == 'r' && name[i-1] == 'l')
42dbdebdc5SRavi Bangoria /*
43dbdebdc5SRavi Bangoria * instructions ending with 'lr' are considered to be
44dbdebdc5SRavi Bangoria * return instructions
45dbdebdc5SRavi Bangoria */
46dbdebdc5SRavi Bangoria ops = &ret_ops;
47dbdebdc5SRavi Bangoria
48dbdebdc5SRavi Bangoria arch__associate_ins_ops(arch, name, ops);
49dbdebdc5SRavi Bangoria return ops;
50dbdebdc5SRavi Bangoria }
51dbdebdc5SRavi Bangoria
521acdad68SAthira Rajeev #define PPC_OP(op) (((op) >> 26) & 0x3F)
53ace7d681SAthira Rajeev #define PPC_21_30(R) (((R) >> 1) & 0x3ff)
54cd0b6f67SAthira Rajeev #define PPC_22_30(R) (((R) >> 1) & 0x1ff)
55ace7d681SAthira Rajeev
56ace7d681SAthira Rajeev struct insn_offset {
57ace7d681SAthira Rajeev const char *name;
58ace7d681SAthira Rajeev int value;
59ace7d681SAthira Rajeev };
60ace7d681SAthira Rajeev
61ace7d681SAthira Rajeev /*
62ace7d681SAthira Rajeev * There are memory instructions with opcode 31 which are
63ace7d681SAthira Rajeev * of X Form, Example:
64ace7d681SAthira Rajeev * ldx RT,RA,RB
65ace7d681SAthira Rajeev * ______________________________________
66ace7d681SAthira Rajeev * | 31 | RT | RA | RB | 21 |/|
67ace7d681SAthira Rajeev * --------------------------------------
68ace7d681SAthira Rajeev * 0 6 11 16 21 30 31
69ace7d681SAthira Rajeev *
70ace7d681SAthira Rajeev * But all instructions with opcode 31 are not memory.
71ace7d681SAthira Rajeev * Example: add RT,RA,RB
72ace7d681SAthira Rajeev *
73ace7d681SAthira Rajeev * Use bits 21 to 30 to check memory insns with 31 as opcode.
74ace7d681SAthira Rajeev * In ins_array below, for ldx instruction:
75ace7d681SAthira Rajeev * name => OP_31_XOP_LDX
76ace7d681SAthira Rajeev * value => 21
77ace7d681SAthira Rajeev */
78ace7d681SAthira Rajeev
79ace7d681SAthira Rajeev static struct insn_offset ins_array[] = {
80ace7d681SAthira Rajeev { .name = "OP_31_XOP_LXSIWZX", .value = 12, },
81ace7d681SAthira Rajeev { .name = "OP_31_XOP_LWARX", .value = 20, },
82ace7d681SAthira Rajeev { .name = "OP_31_XOP_LDX", .value = 21, },
83ace7d681SAthira Rajeev { .name = "OP_31_XOP_LWZX", .value = 23, },
84ace7d681SAthira Rajeev { .name = "OP_31_XOP_LDUX", .value = 53, },
85ace7d681SAthira Rajeev { .name = "OP_31_XOP_LWZUX", .value = 55, },
86ace7d681SAthira Rajeev { .name = "OP_31_XOP_LXSIWAX", .value = 76, },
87ace7d681SAthira Rajeev { .name = "OP_31_XOP_LDARX", .value = 84, },
88ace7d681SAthira Rajeev { .name = "OP_31_XOP_LBZX", .value = 87, },
89ace7d681SAthira Rajeev { .name = "OP_31_XOP_LVX", .value = 103, },
90ace7d681SAthira Rajeev { .name = "OP_31_XOP_LBZUX", .value = 119, },
91ace7d681SAthira Rajeev { .name = "OP_31_XOP_STXSIWX", .value = 140, },
92ace7d681SAthira Rajeev { .name = "OP_31_XOP_STDX", .value = 149, },
93ace7d681SAthira Rajeev { .name = "OP_31_XOP_STWX", .value = 151, },
94ace7d681SAthira Rajeev { .name = "OP_31_XOP_STDUX", .value = 181, },
95ace7d681SAthira Rajeev { .name = "OP_31_XOP_STWUX", .value = 183, },
96ace7d681SAthira Rajeev { .name = "OP_31_XOP_STBX", .value = 215, },
97ace7d681SAthira Rajeev { .name = "OP_31_XOP_STVX", .value = 231, },
98ace7d681SAthira Rajeev { .name = "OP_31_XOP_STBUX", .value = 247, },
99ace7d681SAthira Rajeev { .name = "OP_31_XOP_LHZX", .value = 279, },
100ace7d681SAthira Rajeev { .name = "OP_31_XOP_LHZUX", .value = 311, },
101ace7d681SAthira Rajeev { .name = "OP_31_XOP_LXVDSX", .value = 332, },
102ace7d681SAthira Rajeev { .name = "OP_31_XOP_LWAX", .value = 341, },
103ace7d681SAthira Rajeev { .name = "OP_31_XOP_LHAX", .value = 343, },
104ace7d681SAthira Rajeev { .name = "OP_31_XOP_LWAUX", .value = 373, },
105ace7d681SAthira Rajeev { .name = "OP_31_XOP_LHAUX", .value = 375, },
106ace7d681SAthira Rajeev { .name = "OP_31_XOP_STHX", .value = 407, },
107ace7d681SAthira Rajeev { .name = "OP_31_XOP_STHUX", .value = 439, },
108ace7d681SAthira Rajeev { .name = "OP_31_XOP_LXSSPX", .value = 524, },
109ace7d681SAthira Rajeev { .name = "OP_31_XOP_LDBRX", .value = 532, },
110ace7d681SAthira Rajeev { .name = "OP_31_XOP_LSWX", .value = 533, },
111ace7d681SAthira Rajeev { .name = "OP_31_XOP_LWBRX", .value = 534, },
112ace7d681SAthira Rajeev { .name = "OP_31_XOP_LFSUX", .value = 567, },
113ace7d681SAthira Rajeev { .name = "OP_31_XOP_LXSDX", .value = 588, },
114ace7d681SAthira Rajeev { .name = "OP_31_XOP_LSWI", .value = 597, },
115ace7d681SAthira Rajeev { .name = "OP_31_XOP_LFDX", .value = 599, },
116ace7d681SAthira Rajeev { .name = "OP_31_XOP_LFDUX", .value = 631, },
117ace7d681SAthira Rajeev { .name = "OP_31_XOP_STXSSPX", .value = 652, },
118ace7d681SAthira Rajeev { .name = "OP_31_XOP_STDBRX", .value = 660, },
119ace7d681SAthira Rajeev { .name = "OP_31_XOP_STXWX", .value = 661, },
120ace7d681SAthira Rajeev { .name = "OP_31_XOP_STWBRX", .value = 662, },
121ace7d681SAthira Rajeev { .name = "OP_31_XOP_STFSX", .value = 663, },
122ace7d681SAthira Rajeev { .name = "OP_31_XOP_STFSUX", .value = 695, },
123ace7d681SAthira Rajeev { .name = "OP_31_XOP_STXSDX", .value = 716, },
124ace7d681SAthira Rajeev { .name = "OP_31_XOP_STSWI", .value = 725, },
125ace7d681SAthira Rajeev { .name = "OP_31_XOP_STFDX", .value = 727, },
126ace7d681SAthira Rajeev { .name = "OP_31_XOP_STFDUX", .value = 759, },
127ace7d681SAthira Rajeev { .name = "OP_31_XOP_LXVW4X", .value = 780, },
128ace7d681SAthira Rajeev { .name = "OP_31_XOP_LHBRX", .value = 790, },
129ace7d681SAthira Rajeev { .name = "OP_31_XOP_LXVD2X", .value = 844, },
130ace7d681SAthira Rajeev { .name = "OP_31_XOP_LFIWAX", .value = 855, },
131ace7d681SAthira Rajeev { .name = "OP_31_XOP_LFIWZX", .value = 887, },
132ace7d681SAthira Rajeev { .name = "OP_31_XOP_STXVW4X", .value = 908, },
133ace7d681SAthira Rajeev { .name = "OP_31_XOP_STHBRX", .value = 918, },
134ace7d681SAthira Rajeev { .name = "OP_31_XOP_STXVD2X", .value = 972, },
135ace7d681SAthira Rajeev { .name = "OP_31_XOP_STFIWX", .value = 983, },
136ace7d681SAthira Rajeev };
137ace7d681SAthira Rajeev
138cd0b6f67SAthira Rajeev /*
139cd0b6f67SAthira Rajeev * Arithmetic instructions which are having opcode as 31.
140cd0b6f67SAthira Rajeev * These instructions are tracked to save the register state
141cd0b6f67SAthira Rajeev * changes. Example:
142cd0b6f67SAthira Rajeev *
143cd0b6f67SAthira Rajeev * lwz r10,264(r3)
144cd0b6f67SAthira Rajeev * add r31, r3, r3
145cd0b6f67SAthira Rajeev * lwz r9, 0(r31)
146cd0b6f67SAthira Rajeev *
147cd0b6f67SAthira Rajeev * Here instruction tracking needs to identify the "add"
148cd0b6f67SAthira Rajeev * instruction and save data type of r3 to r31. If a sample
149cd0b6f67SAthira Rajeev * is hit at next "lwz r9, 0(r31)", by this instruction tracking,
150cd0b6f67SAthira Rajeev * data type of r31 can be resolved.
151cd0b6f67SAthira Rajeev */
152cd0b6f67SAthira Rajeev static struct insn_offset arithmetic_ins_op_31[] = {
153cd0b6f67SAthira Rajeev { .name = "SUB_CARRY_XO_FORM", .value = 8, },
154cd0b6f67SAthira Rajeev { .name = "MUL_HDW_XO_FORM1", .value = 9, },
155cd0b6f67SAthira Rajeev { .name = "ADD_CARRY_XO_FORM", .value = 10, },
156cd0b6f67SAthira Rajeev { .name = "MUL_HW_XO_FORM1", .value = 11, },
157cd0b6f67SAthira Rajeev { .name = "SUB_XO_FORM", .value = 40, },
158cd0b6f67SAthira Rajeev { .name = "MUL_HDW_XO_FORM", .value = 73, },
159cd0b6f67SAthira Rajeev { .name = "MUL_HW_XO_FORM", .value = 75, },
160cd0b6f67SAthira Rajeev { .name = "SUB_EXT_XO_FORM", .value = 136, },
161cd0b6f67SAthira Rajeev { .name = "ADD_EXT_XO_FORM", .value = 138, },
162cd0b6f67SAthira Rajeev { .name = "SUB_ZERO_EXT_XO_FORM", .value = 200, },
163cd0b6f67SAthira Rajeev { .name = "ADD_ZERO_EXT_XO_FORM", .value = 202, },
164cd0b6f67SAthira Rajeev { .name = "SUB_EXT_XO_FORM2", .value = 232, },
165cd0b6f67SAthira Rajeev { .name = "MUL_DW_XO_FORM", .value = 233, },
166cd0b6f67SAthira Rajeev { .name = "ADD_EXT_XO_FORM2", .value = 234, },
167cd0b6f67SAthira Rajeev { .name = "MUL_W_XO_FORM", .value = 235, },
168cd0b6f67SAthira Rajeev { .name = "ADD_XO_FORM", .value = 266, },
169cd0b6f67SAthira Rajeev { .name = "DIV_DW_XO_FORM1", .value = 457, },
170cd0b6f67SAthira Rajeev { .name = "DIV_W_XO_FORM1", .value = 459, },
171cd0b6f67SAthira Rajeev { .name = "DIV_DW_XO_FORM", .value = 489, },
172cd0b6f67SAthira Rajeev { .name = "DIV_W_XO_FORM", .value = 491, },
173cd0b6f67SAthira Rajeev };
174cd0b6f67SAthira Rajeev
175539bfea3SAthira Rajeev static struct insn_offset arithmetic_two_ops[] = {
176539bfea3SAthira Rajeev { .name = "mulli", .value = 7, },
177539bfea3SAthira Rajeev { .name = "subfic", .value = 8, },
178539bfea3SAthira Rajeev { .name = "addic", .value = 12, },
179539bfea3SAthira Rajeev { .name = "addic.", .value = 13, },
180539bfea3SAthira Rajeev { .name = "addi", .value = 14, },
181539bfea3SAthira Rajeev { .name = "addis", .value = 15, },
182539bfea3SAthira Rajeev };
183cd0b6f67SAthira Rajeev
cmp_offset(const void * a,const void * b)184ace7d681SAthira Rajeev static int cmp_offset(const void *a, const void *b)
185ace7d681SAthira Rajeev {
186ace7d681SAthira Rajeev const struct insn_offset *val1 = a;
187ace7d681SAthira Rajeev const struct insn_offset *val2 = b;
188ace7d681SAthira Rajeev
189ace7d681SAthira Rajeev return (val1->value - val2->value);
190ace7d681SAthira Rajeev }
1911acdad68SAthira Rajeev
check_ppc_insn(struct disasm_line * dl)192*2c9db747SAthira Rajeev static struct ins_ops *check_ppc_insn(struct disasm_line *dl)
1931acdad68SAthira Rajeev {
194*2c9db747SAthira Rajeev int raw_insn = dl->raw.raw_insn;
1951acdad68SAthira Rajeev int opcode = PPC_OP(raw_insn);
196ace7d681SAthira Rajeev int mem_insn_31 = PPC_21_30(raw_insn);
197ace7d681SAthira Rajeev struct insn_offset *ret;
198ace7d681SAthira Rajeev struct insn_offset mem_insns_31_opcode = {
199ace7d681SAthira Rajeev "OP_31_INSN",
200ace7d681SAthira Rajeev mem_insn_31
201ace7d681SAthira Rajeev };
202*2c9db747SAthira Rajeev char name_insn[32];
2031acdad68SAthira Rajeev
2041acdad68SAthira Rajeev /*
2051acdad68SAthira Rajeev * Instructions with opcode 32 to 63 are memory
2061acdad68SAthira Rajeev * instructions in powerpc
2071acdad68SAthira Rajeev */
208ace7d681SAthira Rajeev if ((opcode & 0x20)) {
209*2c9db747SAthira Rajeev /*
210*2c9db747SAthira Rajeev * Set name in case of raw instruction to
211*2c9db747SAthira Rajeev * opcode to be used in insn-stat
212*2c9db747SAthira Rajeev */
213*2c9db747SAthira Rajeev if (!strlen(dl->ins.name)) {
214*2c9db747SAthira Rajeev sprintf(name_insn, "%d", opcode);
215*2c9db747SAthira Rajeev dl->ins.name = strdup(name_insn);
216*2c9db747SAthira Rajeev }
2171acdad68SAthira Rajeev return &load_store_ops;
218ace7d681SAthira Rajeev } else if (opcode == 31) {
219ace7d681SAthira Rajeev /* Check for memory instructions with opcode 31 */
220ace7d681SAthira Rajeev ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset);
221*2c9db747SAthira Rajeev if (ret) {
222*2c9db747SAthira Rajeev if (!strlen(dl->ins.name))
223*2c9db747SAthira Rajeev dl->ins.name = strdup(ret->name);
224ace7d681SAthira Rajeev return &load_store_ops;
225*2c9db747SAthira Rajeev } else {
226cd0b6f67SAthira Rajeev mem_insns_31_opcode.value = PPC_22_30(raw_insn);
227cd0b6f67SAthira Rajeev ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31),
228cd0b6f67SAthira Rajeev sizeof(arithmetic_ins_op_31[0]), cmp_offset);
229cd0b6f67SAthira Rajeev if (ret != NULL)
230cd0b6f67SAthira Rajeev return &arithmetic_ops;
231cd0b6f67SAthira Rajeev /* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */
232cd0b6f67SAthira Rajeev if (PPC_21_30(raw_insn) == 444)
233cd0b6f67SAthira Rajeev return &arithmetic_ops;
234cd0b6f67SAthira Rajeev }
235539bfea3SAthira Rajeev } else {
236539bfea3SAthira Rajeev mem_insns_31_opcode.value = opcode;
237539bfea3SAthira Rajeev ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops),
238539bfea3SAthira Rajeev sizeof(arithmetic_two_ops[0]), cmp_offset);
239539bfea3SAthira Rajeev if (ret != NULL)
240539bfea3SAthira Rajeev return &arithmetic_ops;
241ace7d681SAthira Rajeev }
2421acdad68SAthira Rajeev
2431acdad68SAthira Rajeev return NULL;
2441acdad68SAthira Rajeev }
2451acdad68SAthira Rajeev
24688444952SAthira Rajeev /*
24788444952SAthira Rajeev * Instruction tracking function to track register state moves.
24888444952SAthira Rajeev * Example sequence:
24988444952SAthira Rajeev * ld r10,264(r3)
25088444952SAthira Rajeev * mr r31,r3
25188444952SAthira Rajeev * <<after some sequence>
25288444952SAthira Rajeev * ld r9,312(r31)
25388444952SAthira Rajeev *
25488444952SAthira Rajeev * Previous instruction sequence shows that register state of r3
25588444952SAthira Rajeev * is moved to r31. update_insn_state_powerpc tracks these state
25688444952SAthira Rajeev * changes
25788444952SAthira Rajeev */
25888444952SAthira Rajeev #ifdef HAVE_DWARF_SUPPORT
update_insn_state_powerpc(struct type_state * state,struct data_loc_info * dloc,Dwarf_Die * cu_die __maybe_unused,struct disasm_line * dl)25988444952SAthira Rajeev static void update_insn_state_powerpc(struct type_state *state,
26088444952SAthira Rajeev struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused,
26188444952SAthira Rajeev struct disasm_line *dl)
26288444952SAthira Rajeev {
26388444952SAthira Rajeev struct annotated_insn_loc loc;
26488444952SAthira Rajeev struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE];
26588444952SAthira Rajeev struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET];
26688444952SAthira Rajeev struct type_state_reg *tsr;
26788444952SAthira Rajeev u32 insn_offset = dl->al.offset;
26888444952SAthira Rajeev
26988444952SAthira Rajeev if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)
27088444952SAthira Rajeev return;
27188444952SAthira Rajeev
27288444952SAthira Rajeev /*
27388444952SAthira Rajeev * Value 444 for bits 21:30 is for "mr"
27488444952SAthira Rajeev * instruction. "mr" is extended OR. So set the
27588444952SAthira Rajeev * source and destination reg correctly
27688444952SAthira Rajeev */
27788444952SAthira Rajeev if (PPC_21_30(dl->raw.raw_insn) == 444) {
27888444952SAthira Rajeev int src_reg = src->reg1;
27988444952SAthira Rajeev
28088444952SAthira Rajeev src->reg1 = dst->reg1;
28188444952SAthira Rajeev dst->reg1 = src_reg;
28288444952SAthira Rajeev }
28388444952SAthira Rajeev
28488444952SAthira Rajeev if (!has_reg_type(state, dst->reg1))
28588444952SAthira Rajeev return;
28688444952SAthira Rajeev
28788444952SAthira Rajeev tsr = &state->regs[dst->reg1];
28888444952SAthira Rajeev
28988444952SAthira Rajeev if (!has_reg_type(state, src->reg1) ||
29088444952SAthira Rajeev !state->regs[src->reg1].ok) {
29188444952SAthira Rajeev tsr->ok = false;
29288444952SAthira Rajeev return;
29388444952SAthira Rajeev }
29488444952SAthira Rajeev
29588444952SAthira Rajeev tsr->type = state->regs[src->reg1].type;
29688444952SAthira Rajeev tsr->kind = state->regs[src->reg1].kind;
29788444952SAthira Rajeev tsr->ok = true;
29888444952SAthira Rajeev
29988444952SAthira Rajeev pr_debug_dtp("mov [%x] reg%d -> reg%d",
30088444952SAthira Rajeev insn_offset, src->reg1, dst->reg1);
30188444952SAthira Rajeev pr_debug_type_name(&tsr->type, tsr->kind);
30288444952SAthira Rajeev }
30388444952SAthira Rajeev #endif /* HAVE_DWARF_SUPPORT */
30488444952SAthira Rajeev
powerpc__annotate_init(struct arch * arch,char * cpuid __maybe_unused)305696e2457SJiri Olsa static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
306dbdebdc5SRavi Bangoria {
307dbdebdc5SRavi Bangoria if (!arch->initialized) {
308dbdebdc5SRavi Bangoria arch->initialized = true;
309dbdebdc5SRavi Bangoria arch->associate_instruction_ops = powerpc__associate_instruction_ops;
310dbdebdc5SRavi Bangoria arch->objdump.comment_char = '#';
31106dd4c5aSAthira Rajeev annotate_opts.show_asm_raw = true;
312dbdebdc5SRavi Bangoria }
313dbdebdc5SRavi Bangoria
314dbdebdc5SRavi Bangoria return 0;
315dbdebdc5SRavi Bangoria }
316