LoongArch: Add prologue unwinder support
[platform/kernel/linux-starfive.git] / arch / loongarch / include / asm / inst.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4  */
5 #ifndef _ASM_INST_H
6 #define _ASM_INST_H
7
8 #include <linux/types.h>
9 #include <asm/asm.h>
10
11 #define ADDR_IMMMASK_LU52ID     0xFFF0000000000000
12 #define ADDR_IMMMASK_LU32ID     0x000FFFFF00000000
13 #define ADDR_IMMMASK_ADDU16ID   0x00000000FFFF0000
14
15 #define ADDR_IMMSHIFT_LU52ID    52
16 #define ADDR_IMMSHIFT_LU32ID    32
17 #define ADDR_IMMSHIFT_ADDU16ID  16
18
19 #define ADDR_IMM(addr, INSN)    ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
20
21 enum reg1i20_op {
22         lu12iw_op       = 0x0a,
23         lu32id_op       = 0x0b,
24 };
25
26 enum reg1i21_op {
27         beqz_op         = 0x10,
28         bnez_op         = 0x11,
29 };
30
31 enum reg2i12_op {
32         addiw_op        = 0x0a,
33         addid_op        = 0x0b,
34         lu52id_op       = 0x0c,
35         ldb_op          = 0xa0,
36         ldh_op          = 0xa1,
37         ldw_op          = 0xa2,
38         ldd_op          = 0xa3,
39         stb_op          = 0xa4,
40         sth_op          = 0xa5,
41         stw_op          = 0xa6,
42         std_op          = 0xa7,
43 };
44
45 enum reg2i16_op {
46         jirl_op         = 0x13,
47         beq_op          = 0x16,
48         bne_op          = 0x17,
49         blt_op          = 0x18,
50         bge_op          = 0x19,
51         bltu_op         = 0x1a,
52         bgeu_op         = 0x1b,
53 };
54
55 struct reg0i26_format {
56         unsigned int immediate_h : 10;
57         unsigned int immediate_l : 16;
58         unsigned int opcode : 6;
59 };
60
61 struct reg1i20_format {
62         unsigned int rd : 5;
63         unsigned int immediate : 20;
64         unsigned int opcode : 7;
65 };
66
67 struct reg1i21_format {
68         unsigned int immediate_h  : 5;
69         unsigned int rj : 5;
70         unsigned int immediate_l : 16;
71         unsigned int opcode : 6;
72 };
73
74 struct reg2i12_format {
75         unsigned int rd : 5;
76         unsigned int rj : 5;
77         unsigned int immediate : 12;
78         unsigned int opcode : 10;
79 };
80
81 struct reg2i16_format {
82         unsigned int rd : 5;
83         unsigned int rj : 5;
84         unsigned int immediate : 16;
85         unsigned int opcode : 6;
86 };
87
88 union loongarch_instruction {
89         unsigned int word;
90         struct reg0i26_format reg0i26_format;
91         struct reg1i20_format reg1i20_format;
92         struct reg1i21_format reg1i21_format;
93         struct reg2i12_format reg2i12_format;
94         struct reg2i16_format reg2i16_format;
95 };
96
97 #define LOONGARCH_INSN_SIZE     sizeof(union loongarch_instruction)
98
99 enum loongarch_gpr {
100         LOONGARCH_GPR_ZERO = 0,
101         LOONGARCH_GPR_RA = 1,
102         LOONGARCH_GPR_TP = 2,
103         LOONGARCH_GPR_SP = 3,
104         LOONGARCH_GPR_A0 = 4,   /* Reused as V0 for return value */
105         LOONGARCH_GPR_A1,       /* Reused as V1 for return value */
106         LOONGARCH_GPR_A2,
107         LOONGARCH_GPR_A3,
108         LOONGARCH_GPR_A4,
109         LOONGARCH_GPR_A5,
110         LOONGARCH_GPR_A6,
111         LOONGARCH_GPR_A7,
112         LOONGARCH_GPR_T0 = 12,
113         LOONGARCH_GPR_T1,
114         LOONGARCH_GPR_T2,
115         LOONGARCH_GPR_T3,
116         LOONGARCH_GPR_T4,
117         LOONGARCH_GPR_T5,
118         LOONGARCH_GPR_T6,
119         LOONGARCH_GPR_T7,
120         LOONGARCH_GPR_T8,
121         LOONGARCH_GPR_FP = 22,
122         LOONGARCH_GPR_S0 = 23,
123         LOONGARCH_GPR_S1,
124         LOONGARCH_GPR_S2,
125         LOONGARCH_GPR_S3,
126         LOONGARCH_GPR_S4,
127         LOONGARCH_GPR_S5,
128         LOONGARCH_GPR_S6,
129         LOONGARCH_GPR_S7,
130         LOONGARCH_GPR_S8,
131         LOONGARCH_GPR_MAX
132 };
133
134 #define is_imm12_negative(val)  is_imm_negative(val, 12)
135
136 static inline bool is_imm_negative(unsigned long val, unsigned int bit)
137 {
138         return val & (1UL << (bit - 1));
139 }
140
141 static inline bool is_branch_ins(union loongarch_instruction *ip)
142 {
143         return ip->reg1i21_format.opcode >= beqz_op &&
144                 ip->reg1i21_format.opcode <= bgeu_op;
145 }
146
147 static inline bool is_ra_save_ins(union loongarch_instruction *ip)
148 {
149         /* st.d $ra, $sp, offset */
150         return ip->reg2i12_format.opcode == std_op &&
151                 ip->reg2i12_format.rj == LOONGARCH_GPR_SP &&
152                 ip->reg2i12_format.rd == LOONGARCH_GPR_RA &&
153                 !is_imm12_negative(ip->reg2i12_format.immediate);
154 }
155
156 static inline bool is_stack_alloc_ins(union loongarch_instruction *ip)
157 {
158         /* addi.d $sp, $sp, -imm */
159         return ip->reg2i12_format.opcode == addid_op &&
160                 ip->reg2i12_format.rj == LOONGARCH_GPR_SP &&
161                 ip->reg2i12_format.rd == LOONGARCH_GPR_SP &&
162                 is_imm12_negative(ip->reg2i12_format.immediate);
163 }
164
165 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm);
166 u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
167 u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest);
168
169 #endif /* _ASM_INST_H */