insn.h 8.3 KB
Newer Older
1 2 3 4
/*
 * Copyright (C) 2013 Huawei Ltd.
 * Author: Jiang Liu <liuj97@gmail.com>
 *
5 6
 * Copyright (C) 2014 Zi Shen Lim <zlim.lnx@gmail.com>
 *
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef	__ASM_INSN_H
#define	__ASM_INSN_H
#include <linux/types.h>

23 24 25
/* A64 instructions are always 32 bits. */
#define	AARCH64_INSN_SIZE		4

26
#ifndef __ASSEMBLY__
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/*
 * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a
 * Section C3.1 "A64 instruction index by encoding":
 * AArch64 main encoding table
 *  Bit position
 *   28 27 26 25	Encoding Group
 *   0  0  -  -		Unallocated
 *   1  0  0  -		Data processing, immediate
 *   1  0  1  -		Branch, exception generation and system instructions
 *   -  1  -  0		Loads and stores
 *   -  1  0  1		Data processing - register
 *   0  1  1  1		Data processing - SIMD and floating point
 *   1  1  1  1		Data processing - SIMD and floating point
 * "-" means "don't care"
 */
enum aarch64_insn_encoding_class {
	AARCH64_INSN_CLS_UNKNOWN,	/* UNALLOCATED */
	AARCH64_INSN_CLS_DP_IMM,	/* Data processing - immediate */
	AARCH64_INSN_CLS_DP_REG,	/* Data processing - register */
	AARCH64_INSN_CLS_DP_FPSIMD,	/* Data processing - SIMD and FP */
	AARCH64_INSN_CLS_LDST,		/* Loads and stores */
	AARCH64_INSN_CLS_BR_SYS,	/* Branch, exception generation and
					 * system instructions */
};

enum aarch64_insn_hint_op {
	AARCH64_INSN_HINT_NOP	= 0x0 << 5,
	AARCH64_INSN_HINT_YIELD	= 0x1 << 5,
	AARCH64_INSN_HINT_WFE	= 0x2 << 5,
	AARCH64_INSN_HINT_WFI	= 0x3 << 5,
	AARCH64_INSN_HINT_SEV	= 0x4 << 5,
	AARCH64_INSN_HINT_SEVL	= 0x5 << 5,
};

61 62 63 64 65 66 67 68
enum aarch64_insn_imm_type {
	AARCH64_INSN_IMM_ADR,
	AARCH64_INSN_IMM_26,
	AARCH64_INSN_IMM_19,
	AARCH64_INSN_IMM_16,
	AARCH64_INSN_IMM_14,
	AARCH64_INSN_IMM_12,
	AARCH64_INSN_IMM_9,
69
	AARCH64_INSN_IMM_7,
70 71 72
	AARCH64_INSN_IMM_MAX
};

73 74
enum aarch64_insn_register_type {
	AARCH64_INSN_REGTYPE_RT,
75
	AARCH64_INSN_REGTYPE_RN,
76
	AARCH64_INSN_REGTYPE_RT2,
77
	AARCH64_INSN_REGTYPE_RM,
78
	AARCH64_INSN_REGTYPE_RD,
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
};

enum aarch64_insn_register {
	AARCH64_INSN_REG_0  = 0,
	AARCH64_INSN_REG_1  = 1,
	AARCH64_INSN_REG_2  = 2,
	AARCH64_INSN_REG_3  = 3,
	AARCH64_INSN_REG_4  = 4,
	AARCH64_INSN_REG_5  = 5,
	AARCH64_INSN_REG_6  = 6,
	AARCH64_INSN_REG_7  = 7,
	AARCH64_INSN_REG_8  = 8,
	AARCH64_INSN_REG_9  = 9,
	AARCH64_INSN_REG_10 = 10,
	AARCH64_INSN_REG_11 = 11,
	AARCH64_INSN_REG_12 = 12,
	AARCH64_INSN_REG_13 = 13,
	AARCH64_INSN_REG_14 = 14,
	AARCH64_INSN_REG_15 = 15,
	AARCH64_INSN_REG_16 = 16,
	AARCH64_INSN_REG_17 = 17,
	AARCH64_INSN_REG_18 = 18,
	AARCH64_INSN_REG_19 = 19,
	AARCH64_INSN_REG_20 = 20,
	AARCH64_INSN_REG_21 = 21,
	AARCH64_INSN_REG_22 = 22,
	AARCH64_INSN_REG_23 = 23,
	AARCH64_INSN_REG_24 = 24,
	AARCH64_INSN_REG_25 = 25,
	AARCH64_INSN_REG_26 = 26,
	AARCH64_INSN_REG_27 = 27,
	AARCH64_INSN_REG_28 = 28,
	AARCH64_INSN_REG_29 = 29,
	AARCH64_INSN_REG_FP = 29, /* Frame pointer */
	AARCH64_INSN_REG_30 = 30,
	AARCH64_INSN_REG_LR = 30, /* Link register */
	AARCH64_INSN_REG_ZR = 31, /* Zero: as source register */
	AARCH64_INSN_REG_SP = 31  /* Stack pointer: as load/store base reg */
};

enum aarch64_insn_variant {
	AARCH64_INSN_VARIANT_32BIT,
	AARCH64_INSN_VARIANT_64BIT
};

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
enum aarch64_insn_condition {
	AARCH64_INSN_COND_EQ = 0x0, /* == */
	AARCH64_INSN_COND_NE = 0x1, /* != */
	AARCH64_INSN_COND_CS = 0x2, /* unsigned >= */
	AARCH64_INSN_COND_CC = 0x3, /* unsigned < */
	AARCH64_INSN_COND_MI = 0x4, /* < 0 */
	AARCH64_INSN_COND_PL = 0x5, /* >= 0 */
	AARCH64_INSN_COND_VS = 0x6, /* overflow */
	AARCH64_INSN_COND_VC = 0x7, /* no overflow */
	AARCH64_INSN_COND_HI = 0x8, /* unsigned > */
	AARCH64_INSN_COND_LS = 0x9, /* unsigned <= */
	AARCH64_INSN_COND_GE = 0xa, /* signed >= */
	AARCH64_INSN_COND_LT = 0xb, /* signed < */
	AARCH64_INSN_COND_GT = 0xc, /* signed > */
	AARCH64_INSN_COND_LE = 0xd, /* signed <= */
	AARCH64_INSN_COND_AL = 0xe, /* always */
};

142 143 144
enum aarch64_insn_branch_type {
	AARCH64_INSN_BRANCH_NOLINK,
	AARCH64_INSN_BRANCH_LINK,
145
	AARCH64_INSN_BRANCH_RETURN,
146 147
	AARCH64_INSN_BRANCH_COMP_ZERO,
	AARCH64_INSN_BRANCH_COMP_NONZERO,
148 149
};

150 151 152 153 154 155 156 157 158 159
enum aarch64_insn_size_type {
	AARCH64_INSN_SIZE_8,
	AARCH64_INSN_SIZE_16,
	AARCH64_INSN_SIZE_32,
	AARCH64_INSN_SIZE_64,
};

enum aarch64_insn_ldst_type {
	AARCH64_INSN_LDST_LOAD_REG_OFFSET,
	AARCH64_INSN_LDST_STORE_REG_OFFSET,
160 161 162 163
	AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX,
	AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX,
	AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
	AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX,
164 165
};

166 167 168 169 170 171 172
enum aarch64_insn_adsb_type {
	AARCH64_INSN_ADSB_ADD,
	AARCH64_INSN_ADSB_SUB,
	AARCH64_INSN_ADSB_ADD_SETFLAGS,
	AARCH64_INSN_ADSB_SUB_SETFLAGS
};

173 174 175 176 177 178
#define	__AARCH64_INSN_FUNCS(abbr, mask, val)	\
static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
{ return (code & (mask)) == (val); } \
static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
{ return (val); }

179 180
__AARCH64_INSN_FUNCS(str_reg,	0x3FE0EC00, 0x38206800)
__AARCH64_INSN_FUNCS(ldr_reg,	0x3FE0EC00, 0x38606800)
181 182 183 184
__AARCH64_INSN_FUNCS(stp_post,	0x7FC00000, 0x28800000)
__AARCH64_INSN_FUNCS(ldp_post,	0x7FC00000, 0x28C00000)
__AARCH64_INSN_FUNCS(stp_pre,	0x7FC00000, 0x29800000)
__AARCH64_INSN_FUNCS(ldp_pre,	0x7FC00000, 0x29C00000)
185 186 187 188
__AARCH64_INSN_FUNCS(add_imm,	0x7F000000, 0x11000000)
__AARCH64_INSN_FUNCS(adds_imm,	0x7F000000, 0x31000000)
__AARCH64_INSN_FUNCS(sub_imm,	0x7F000000, 0x51000000)
__AARCH64_INSN_FUNCS(subs_imm,	0x7F000000, 0x71000000)
189 190
__AARCH64_INSN_FUNCS(b,		0xFC000000, 0x14000000)
__AARCH64_INSN_FUNCS(bl,	0xFC000000, 0x94000000)
191 192
__AARCH64_INSN_FUNCS(cbz,	0xFE000000, 0x34000000)
__AARCH64_INSN_FUNCS(cbnz,	0xFE000000, 0x35000000)
193
__AARCH64_INSN_FUNCS(bcond,	0xFF000010, 0x54000000)
194 195 196 197 198
__AARCH64_INSN_FUNCS(svc,	0xFFE0001F, 0xD4000001)
__AARCH64_INSN_FUNCS(hvc,	0xFFE0001F, 0xD4000002)
__AARCH64_INSN_FUNCS(smc,	0xFFE0001F, 0xD4000003)
__AARCH64_INSN_FUNCS(brk,	0xFFE0001F, 0xD4200000)
__AARCH64_INSN_FUNCS(hint,	0xFFFFF01F, 0xD503201F)
199 200 201
__AARCH64_INSN_FUNCS(br,	0xFFFFFC1F, 0xD61F0000)
__AARCH64_INSN_FUNCS(blr,	0xFFFFFC1F, 0xD63F0000)
__AARCH64_INSN_FUNCS(ret,	0xFFFFFC1F, 0xD65F0000)
202 203 204 205 206

#undef	__AARCH64_INSN_FUNCS

bool aarch64_insn_is_nop(u32 insn);

207 208
int aarch64_insn_read(void *addr, u32 *insnp);
int aarch64_insn_write(void *addr, u32 insn);
209
enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
210 211
u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
				  u32 insn, u64 imm);
212 213
u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
				enum aarch64_insn_branch_type type);
214 215 216 217
u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
				     enum aarch64_insn_register reg,
				     enum aarch64_insn_variant variant,
				     enum aarch64_insn_branch_type type);
218 219
u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
				     enum aarch64_insn_condition cond);
220 221
u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op);
u32 aarch64_insn_gen_nop(void);
222 223
u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
				enum aarch64_insn_branch_type type);
224 225 226 227 228
u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
				    enum aarch64_insn_register base,
				    enum aarch64_insn_register offset,
				    enum aarch64_insn_size_type size,
				    enum aarch64_insn_ldst_type type);
229 230 231 232 233 234
u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
				     enum aarch64_insn_register reg2,
				     enum aarch64_insn_register base,
				     int offset,
				     enum aarch64_insn_variant variant,
				     enum aarch64_insn_ldst_type type);
235 236 237 238
u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
				 enum aarch64_insn_register src,
				 int imm, enum aarch64_insn_variant variant,
				 enum aarch64_insn_adsb_type type);
239

240 241
bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);

242 243 244
int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
245
#endif /* __ASSEMBLY__ */
246

247
#endif	/* __ASM_INSN_H */