diff options
author | Zi Shen Lim <zlim.lnx@gmail.com> | 2014-08-27 06:15:18 +0200 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2014-09-08 15:39:19 +0200 |
commit | c0cafbae20d2878883ec3c06d6ea30ff38a6bf92 (patch) | |
tree | bb2201347c63383bae86c4935dc8db0e3809eccf /arch/arm64/kernel | |
parent | arm64: introduce aarch64_insn_gen_comp_branch_imm() (diff) | |
download | linux-c0cafbae20d2878883ec3c06d6ea30ff38a6bf92.tar.xz linux-c0cafbae20d2878883ec3c06d6ea30ff38a6bf92.zip |
arm64: introduce aarch64_insn_gen_branch_reg()
Introduce function to generate unconditional branch (register)
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>
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r-- | arch/arm64/kernel/insn.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index d9f7827c5058..67979364daf6 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -283,6 +283,9 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type, case AARCH64_INSN_REGTYPE_RT: shift = 0; break; + case AARCH64_INSN_REGTYPE_RN: + shift = 5; + break; default: pr_err("%s: unknown register type encoding %d\n", __func__, type); @@ -325,10 +328,16 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, */ offset = branch_imm_common(pc, addr, SZ_128M); - if (type == AARCH64_INSN_BRANCH_LINK) + switch (type) { + case AARCH64_INSN_BRANCH_LINK: insn = aarch64_insn_get_bl_value(); - else + break; + case AARCH64_INSN_BRANCH_NOLINK: insn = aarch64_insn_get_b_value(); + break; + default: + BUG_ON(1); + } return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn, offset >> 2); @@ -380,3 +389,25 @@ u32 __kprobes aarch64_insn_gen_nop(void) { return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP); } + +u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg, + enum aarch64_insn_branch_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_BRANCH_NOLINK: + insn = aarch64_insn_get_br_value(); + break; + case AARCH64_INSN_BRANCH_LINK: + insn = aarch64_insn_get_blr_value(); + break; + case AARCH64_INSN_BRANCH_RETURN: + insn = aarch64_insn_get_ret_value(); + break; + default: + BUG_ON(1); + } + + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, reg); +} |