aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZi Shen Lim <zlim.lnx@gmail.com>2014-08-27 00:15:20 -0400
committerWill Deacon <will.deacon@arm.com>2014-09-08 09:39:19 -0400
commit17cac179888166a4e8e252d00ad511e999859293 (patch)
tree4522e67daecfff6e8b054de692bfa1274df1c292
parent345e0d35ecdd7aff31881462a6f7786fda3241d9 (diff)
arm64: introduce aarch64_insn_gen_load_store_reg()
Introduce function to generate load/store (register offset) instructions. Signed-off-by: Zi Shen Lim <zlim.lnx@gmail.com> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/include/asm/insn.h20
-rw-r--r--arch/arm64/kernel/insn.c62
2 files changed, 82 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 86a8a9cc9ec6..5bc1cc391985 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -72,6 +72,7 @@ enum aarch64_insn_imm_type {
72enum aarch64_insn_register_type { 72enum aarch64_insn_register_type {
73 AARCH64_INSN_REGTYPE_RT, 73 AARCH64_INSN_REGTYPE_RT,
74 AARCH64_INSN_REGTYPE_RN, 74 AARCH64_INSN_REGTYPE_RN,
75 AARCH64_INSN_REGTYPE_RM,
75}; 76};
76 77
77enum aarch64_insn_register { 78enum aarch64_insn_register {
@@ -143,12 +144,26 @@ enum aarch64_insn_branch_type {
143 AARCH64_INSN_BRANCH_COMP_NONZERO, 144 AARCH64_INSN_BRANCH_COMP_NONZERO,
144}; 145};
145 146
147enum aarch64_insn_size_type {
148 AARCH64_INSN_SIZE_8,
149 AARCH64_INSN_SIZE_16,
150 AARCH64_INSN_SIZE_32,
151 AARCH64_INSN_SIZE_64,
152};
153
154enum aarch64_insn_ldst_type {
155 AARCH64_INSN_LDST_LOAD_REG_OFFSET,
156 AARCH64_INSN_LDST_STORE_REG_OFFSET,
157};
158
146#define __AARCH64_INSN_FUNCS(abbr, mask, val) \ 159#define __AARCH64_INSN_FUNCS(abbr, mask, val) \
147static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ 160static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
148{ return (code & (mask)) == (val); } \ 161{ return (code & (mask)) == (val); } \
149static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \ 162static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
150{ return (val); } 163{ return (val); }
151 164
165__AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
166__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
152__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000) 167__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000)
153__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000) 168__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000)
154__AARCH64_INSN_FUNCS(cbz, 0xFE000000, 0x34000000) 169__AARCH64_INSN_FUNCS(cbz, 0xFE000000, 0x34000000)
@@ -184,6 +199,11 @@ u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op);
184u32 aarch64_insn_gen_nop(void); 199u32 aarch64_insn_gen_nop(void);
185u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg, 200u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
186 enum aarch64_insn_branch_type type); 201 enum aarch64_insn_branch_type type);
202u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
203 enum aarch64_insn_register base,
204 enum aarch64_insn_register offset,
205 enum aarch64_insn_size_type size,
206 enum aarch64_insn_ldst_type type);
187 207
188bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); 208bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
189 209
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index b65edc02cf81..b882c85527dc 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -286,6 +286,9 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
286 case AARCH64_INSN_REGTYPE_RN: 286 case AARCH64_INSN_REGTYPE_RN:
287 shift = 5; 287 shift = 5;
288 break; 288 break;
289 case AARCH64_INSN_REGTYPE_RM:
290 shift = 16;
291 break;
289 default: 292 default:
290 pr_err("%s: unknown register type encoding %d\n", __func__, 293 pr_err("%s: unknown register type encoding %d\n", __func__,
291 type); 294 type);
@@ -298,6 +301,35 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
298 return insn; 301 return insn;
299} 302}
300 303
304static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type,
305 u32 insn)
306{
307 u32 size;
308
309 switch (type) {
310 case AARCH64_INSN_SIZE_8:
311 size = 0;
312 break;
313 case AARCH64_INSN_SIZE_16:
314 size = 1;
315 break;
316 case AARCH64_INSN_SIZE_32:
317 size = 2;
318 break;
319 case AARCH64_INSN_SIZE_64:
320 size = 3;
321 break;
322 default:
323 pr_err("%s: unknown size encoding %d\n", __func__, type);
324 return 0;
325 }
326
327 insn &= ~GENMASK(31, 30);
328 insn |= size << 30;
329
330 return insn;
331}
332
301static inline long branch_imm_common(unsigned long pc, unsigned long addr, 333static inline long branch_imm_common(unsigned long pc, unsigned long addr,
302 long range) 334 long range)
303{ 335{
@@ -428,3 +460,33 @@ u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
428 460
429 return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, reg); 461 return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, reg);
430} 462}
463
464u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
465 enum aarch64_insn_register base,
466 enum aarch64_insn_register offset,
467 enum aarch64_insn_size_type size,
468 enum aarch64_insn_ldst_type type)
469{
470 u32 insn;
471
472 switch (type) {
473 case AARCH64_INSN_LDST_LOAD_REG_OFFSET:
474 insn = aarch64_insn_get_ldr_reg_value();
475 break;
476 case AARCH64_INSN_LDST_STORE_REG_OFFSET:
477 insn = aarch64_insn_get_str_reg_value();
478 break;
479 default:
480 BUG_ON(1);
481 }
482
483 insn = aarch64_insn_encode_ldst_size(size, insn);
484
485 insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);
486
487 insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
488 base);
489
490 return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn,
491 offset);
492}