aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZi Shen Lim <zlim.lnx@gmail.com>2014-08-27 00:15:21 -0400
committerWill Deacon <will.deacon@arm.com>2014-09-08 09:39:20 -0400
commit1bba567d0f3050e33b4dd1404fdcbceaf5a73034 (patch)
treee4dae1b7bc7a07cd6f3925df5b0d8fcae5042713
parent17cac179888166a4e8e252d00ad511e999859293 (diff)
arm64: introduce aarch64_insn_gen_load_store_pair()
Introduce function to generate load/store pair 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.h16
-rw-r--r--arch/arm64/kernel/insn.c65
2 files changed, 81 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 5bc1cc391985..eef8f1ef6736 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -66,12 +66,14 @@ enum aarch64_insn_imm_type {
66 AARCH64_INSN_IMM_14, 66 AARCH64_INSN_IMM_14,
67 AARCH64_INSN_IMM_12, 67 AARCH64_INSN_IMM_12,
68 AARCH64_INSN_IMM_9, 68 AARCH64_INSN_IMM_9,
69 AARCH64_INSN_IMM_7,
69 AARCH64_INSN_IMM_MAX 70 AARCH64_INSN_IMM_MAX
70}; 71};
71 72
72enum aarch64_insn_register_type { 73enum aarch64_insn_register_type {
73 AARCH64_INSN_REGTYPE_RT, 74 AARCH64_INSN_REGTYPE_RT,
74 AARCH64_INSN_REGTYPE_RN, 75 AARCH64_INSN_REGTYPE_RN,
76 AARCH64_INSN_REGTYPE_RT2,
75 AARCH64_INSN_REGTYPE_RM, 77 AARCH64_INSN_REGTYPE_RM,
76}; 78};
77 79
@@ -154,6 +156,10 @@ enum aarch64_insn_size_type {
154enum aarch64_insn_ldst_type { 156enum aarch64_insn_ldst_type {
155 AARCH64_INSN_LDST_LOAD_REG_OFFSET, 157 AARCH64_INSN_LDST_LOAD_REG_OFFSET,
156 AARCH64_INSN_LDST_STORE_REG_OFFSET, 158 AARCH64_INSN_LDST_STORE_REG_OFFSET,
159 AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX,
160 AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX,
161 AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
162 AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX,
157}; 163};
158 164
159#define __AARCH64_INSN_FUNCS(abbr, mask, val) \ 165#define __AARCH64_INSN_FUNCS(abbr, mask, val) \
@@ -164,6 +170,10 @@ static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
164 170
165__AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800) 171__AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
166__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800) 172__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
173__AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000)
174__AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000)
175__AARCH64_INSN_FUNCS(stp_pre, 0x7FC00000, 0x29800000)
176__AARCH64_INSN_FUNCS(ldp_pre, 0x7FC00000, 0x29C00000)
167__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000) 177__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000)
168__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000) 178__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000)
169__AARCH64_INSN_FUNCS(cbz, 0xFE000000, 0x34000000) 179__AARCH64_INSN_FUNCS(cbz, 0xFE000000, 0x34000000)
@@ -204,6 +214,12 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
204 enum aarch64_insn_register offset, 214 enum aarch64_insn_register offset,
205 enum aarch64_insn_size_type size, 215 enum aarch64_insn_size_type size,
206 enum aarch64_insn_ldst_type type); 216 enum aarch64_insn_ldst_type type);
217u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
218 enum aarch64_insn_register reg2,
219 enum aarch64_insn_register base,
220 int offset,
221 enum aarch64_insn_variant variant,
222 enum aarch64_insn_ldst_type type);
207 223
208bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); 224bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
209 225
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index b882c85527dc..7880c060f684 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -255,6 +255,10 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
255 mask = BIT(9) - 1; 255 mask = BIT(9) - 1;
256 shift = 12; 256 shift = 12;
257 break; 257 break;
258 case AARCH64_INSN_IMM_7:
259 mask = BIT(7) - 1;
260 shift = 15;
261 break;
258 default: 262 default:
259 pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n", 263 pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n",
260 type); 264 type);
@@ -286,6 +290,9 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
286 case AARCH64_INSN_REGTYPE_RN: 290 case AARCH64_INSN_REGTYPE_RN:
287 shift = 5; 291 shift = 5;
288 break; 292 break;
293 case AARCH64_INSN_REGTYPE_RT2:
294 shift = 10;
295 break;
289 case AARCH64_INSN_REGTYPE_RM: 296 case AARCH64_INSN_REGTYPE_RM:
290 shift = 16; 297 shift = 16;
291 break; 298 break;
@@ -490,3 +497,61 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
490 return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, 497 return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn,
491 offset); 498 offset);
492} 499}
500
501u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
502 enum aarch64_insn_register reg2,
503 enum aarch64_insn_register base,
504 int offset,
505 enum aarch64_insn_variant variant,
506 enum aarch64_insn_ldst_type type)
507{
508 u32 insn;
509 int shift;
510
511 switch (type) {
512 case AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX:
513 insn = aarch64_insn_get_ldp_pre_value();
514 break;
515 case AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX:
516 insn = aarch64_insn_get_stp_pre_value();
517 break;
518 case AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX:
519 insn = aarch64_insn_get_ldp_post_value();
520 break;
521 case AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX:
522 insn = aarch64_insn_get_stp_post_value();
523 break;
524 default:
525 BUG_ON(1);
526 }
527
528 switch (variant) {
529 case AARCH64_INSN_VARIANT_32BIT:
530 /* offset must be multiples of 4 in the range [-256, 252] */
531 BUG_ON(offset & 0x3);
532 BUG_ON(offset < -256 || offset > 252);
533 shift = 2;
534 break;
535 case AARCH64_INSN_VARIANT_64BIT:
536 /* offset must be multiples of 8 in the range [-512, 504] */
537 BUG_ON(offset & 0x7);
538 BUG_ON(offset < -512 || offset > 504);
539 shift = 3;
540 insn |= AARCH64_INSN_SF_BIT;
541 break;
542 default:
543 BUG_ON(1);
544 }
545
546 insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn,
547 reg1);
548
549 insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT2, insn,
550 reg2);
551
552 insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
553 base);
554
555 return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_7, insn,
556 offset >> shift);
557}