diff options
author | Jiang Liu <liuj97@gmail.com> | 2014-01-07 09:17:11 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2014-01-08 10:21:29 -0500 |
commit | 5c5bf25d4f7a950382f94fc120a5818197b48fe9 (patch) | |
tree | c5b7ade94cccaec0e8ab746a704f534b5748f4f6 /arch/arm64 | |
parent | c84fced8d990dd86c523233d38b4685a52a4fc3f (diff) |
arm64: introduce aarch64_insn_gen_{nop|branch_imm}() helper functions
Introduce aarch64_insn_gen_{nop|branch_imm}() helper functions, which
will be used to implement jump label on ARM64.
Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Jiang Liu <liuj97@gmail.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64')
-rw-r--r-- | arch/arm64/include/asm/insn.h | 10 | ||||
-rw-r--r-- | arch/arm64/kernel/insn.c | 40 |
2 files changed, 50 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index fb4466022bd0..c44ad39ed310 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h | |||
@@ -66,6 +66,11 @@ enum aarch64_insn_imm_type { | |||
66 | AARCH64_INSN_IMM_MAX | 66 | AARCH64_INSN_IMM_MAX |
67 | }; | 67 | }; |
68 | 68 | ||
69 | enum aarch64_insn_branch_type { | ||
70 | AARCH64_INSN_BRANCH_NOLINK, | ||
71 | AARCH64_INSN_BRANCH_LINK, | ||
72 | }; | ||
73 | |||
69 | #define __AARCH64_INSN_FUNCS(abbr, mask, val) \ | 74 | #define __AARCH64_INSN_FUNCS(abbr, mask, val) \ |
70 | static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ | 75 | static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ |
71 | { return (code & (mask)) == (val); } \ | 76 | { return (code & (mask)) == (val); } \ |
@@ -89,6 +94,11 @@ int aarch64_insn_write(void *addr, u32 insn); | |||
89 | enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn); | 94 | enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn); |
90 | u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, | 95 | u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, |
91 | u32 insn, u64 imm); | 96 | u32 insn, u64 imm); |
97 | u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, | ||
98 | enum aarch64_insn_branch_type type); | ||
99 | u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op); | ||
100 | u32 aarch64_insn_gen_nop(void); | ||
101 | |||
92 | bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); | 102 | bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); |
93 | 103 | ||
94 | int aarch64_insn_patch_text_nosync(void *addr, u32 insn); | 104 | int aarch64_insn_patch_text_nosync(void *addr, u32 insn); |
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 7df08075fc7a..92f36835486b 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | #include <linux/bitops.h> | ||
17 | #include <linux/compiler.h> | 18 | #include <linux/compiler.h> |
18 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
19 | #include <linux/smp.h> | 20 | #include <linux/smp.h> |
@@ -262,3 +263,42 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, | |||
262 | 263 | ||
263 | return insn; | 264 | return insn; |
264 | } | 265 | } |
266 | |||
267 | u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, | ||
268 | enum aarch64_insn_branch_type type) | ||
269 | { | ||
270 | u32 insn; | ||
271 | long offset; | ||
272 | |||
273 | /* | ||
274 | * PC: A 64-bit Program Counter holding the address of the current | ||
275 | * instruction. A64 instructions must be word-aligned. | ||
276 | */ | ||
277 | BUG_ON((pc & 0x3) || (addr & 0x3)); | ||
278 | |||
279 | /* | ||
280 | * B/BL support [-128M, 128M) offset | ||
281 | * ARM64 virtual address arrangement guarantees all kernel and module | ||
282 | * texts are within +/-128M. | ||
283 | */ | ||
284 | offset = ((long)addr - (long)pc); | ||
285 | BUG_ON(offset < -SZ_128M || offset >= SZ_128M); | ||
286 | |||
287 | if (type == AARCH64_INSN_BRANCH_LINK) | ||
288 | insn = aarch64_insn_get_bl_value(); | ||
289 | else | ||
290 | insn = aarch64_insn_get_b_value(); | ||
291 | |||
292 | return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn, | ||
293 | offset >> 2); | ||
294 | } | ||
295 | |||
296 | u32 __kprobes aarch64_insn_gen_hint(enum aarch64_insn_hint_op op) | ||
297 | { | ||
298 | return aarch64_insn_get_hint_value() | op; | ||
299 | } | ||
300 | |||
301 | u32 __kprobes aarch64_insn_gen_nop(void) | ||
302 | { | ||
303 | return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP); | ||
304 | } | ||