diff options
author | Zi Shen Lim <zlim.lnx@gmail.com> | 2014-08-27 00:15:21 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2014-09-08 09:39:20 -0400 |
commit | 1bba567d0f3050e33b4dd1404fdcbceaf5a73034 (patch) | |
tree | e4dae1b7bc7a07cd6f3925df5b0d8fcae5042713 | |
parent | 17cac179888166a4e8e252d00ad511e999859293 (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.h | 16 | ||||
-rw-r--r-- | arch/arm64/kernel/insn.c | 65 |
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 | ||
72 | enum aarch64_insn_register_type { | 73 | enum 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 { | |||
154 | enum aarch64_insn_ldst_type { | 156 | enum 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); |
217 | u32 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 | ||
208 | bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); | 224 | bool 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 | |||
501 | u32 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 | } | ||