]> git.karo-electronics.de Git - linux-beck.git/commitdiff
arm64: introduce aarch64_insn_gen_branch_reg()
authorZi Shen Lim <zlim.lnx@gmail.com>
Wed, 27 Aug 2014 04:15:18 +0000 (05:15 +0100)
committerWill Deacon <will.deacon@arm.com>
Mon, 8 Sep 2014 13:39:19 +0000 (14:39 +0100)
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>
arch/arm64/include/asm/insn.h
arch/arm64/kernel/insn.c

index a98c4954b38086ef5190cf7a68c1c475c1878f08..5080962058b0431b1e76ce8faac56ec234ea562f 100644 (file)
@@ -71,6 +71,7 @@ enum aarch64_insn_imm_type {
 
 enum aarch64_insn_register_type {
        AARCH64_INSN_REGTYPE_RT,
+       AARCH64_INSN_REGTYPE_RN,
 };
 
 enum aarch64_insn_register {
@@ -119,6 +120,7 @@ enum aarch64_insn_variant {
 enum aarch64_insn_branch_type {
        AARCH64_INSN_BRANCH_NOLINK,
        AARCH64_INSN_BRANCH_LINK,
+       AARCH64_INSN_BRANCH_RETURN,
        AARCH64_INSN_BRANCH_COMP_ZERO,
        AARCH64_INSN_BRANCH_COMP_NONZERO,
 };
@@ -138,6 +140,9 @@ __AARCH64_INSN_FUNCS(hvc,   0xFFE0001F, 0xD4000002)
 __AARCH64_INSN_FUNCS(smc,      0xFFE0001F, 0xD4000003)
 __AARCH64_INSN_FUNCS(brk,      0xFFE0001F, 0xD4200000)
 __AARCH64_INSN_FUNCS(hint,     0xFFFFF01F, 0xD503201F)
+__AARCH64_INSN_FUNCS(br,       0xFFFFFC1F, 0xD61F0000)
+__AARCH64_INSN_FUNCS(blr,      0xFFFFFC1F, 0xD63F0000)
+__AARCH64_INSN_FUNCS(ret,      0xFFFFFC1F, 0xD65F0000)
 
 #undef __AARCH64_INSN_FUNCS
 
@@ -156,6 +161,8 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
                                     enum aarch64_insn_branch_type type);
 u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op);
 u32 aarch64_insn_gen_nop(void);
+u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
+                               enum aarch64_insn_branch_type type);
 
 bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
 
index d9f7827c5058ce2b361291477af299bbebb99ebe..67979364daf64a1fbde9d9a6c2f7b321fe967b28 100644 (file)
@@ -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);
+}