Commit c0cafbae authored by Zi Shen Lim's avatar Zi Shen Lim Committed by Will Deacon

arm64: introduce aarch64_insn_gen_branch_reg()

Introduce function to generate unconditional branch (register)
instructions.
Signed-off-by: default avatarZi Shen Lim <zlim.lnx@gmail.com>
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 617d2fbc
...@@ -71,6 +71,7 @@ enum aarch64_insn_imm_type { ...@@ -71,6 +71,7 @@ enum aarch64_insn_imm_type {
enum aarch64_insn_register_type { enum aarch64_insn_register_type {
AARCH64_INSN_REGTYPE_RT, AARCH64_INSN_REGTYPE_RT,
AARCH64_INSN_REGTYPE_RN,
}; };
enum aarch64_insn_register { enum aarch64_insn_register {
...@@ -119,6 +120,7 @@ enum aarch64_insn_variant { ...@@ -119,6 +120,7 @@ enum aarch64_insn_variant {
enum aarch64_insn_branch_type { enum aarch64_insn_branch_type {
AARCH64_INSN_BRANCH_NOLINK, AARCH64_INSN_BRANCH_NOLINK,
AARCH64_INSN_BRANCH_LINK, AARCH64_INSN_BRANCH_LINK,
AARCH64_INSN_BRANCH_RETURN,
AARCH64_INSN_BRANCH_COMP_ZERO, AARCH64_INSN_BRANCH_COMP_ZERO,
AARCH64_INSN_BRANCH_COMP_NONZERO, AARCH64_INSN_BRANCH_COMP_NONZERO,
}; };
...@@ -138,6 +140,9 @@ __AARCH64_INSN_FUNCS(hvc, 0xFFE0001F, 0xD4000002) ...@@ -138,6 +140,9 @@ __AARCH64_INSN_FUNCS(hvc, 0xFFE0001F, 0xD4000002)
__AARCH64_INSN_FUNCS(smc, 0xFFE0001F, 0xD4000003) __AARCH64_INSN_FUNCS(smc, 0xFFE0001F, 0xD4000003)
__AARCH64_INSN_FUNCS(brk, 0xFFE0001F, 0xD4200000) __AARCH64_INSN_FUNCS(brk, 0xFFE0001F, 0xD4200000)
__AARCH64_INSN_FUNCS(hint, 0xFFFFF01F, 0xD503201F) __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 #undef __AARCH64_INSN_FUNCS
...@@ -156,6 +161,8 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr, ...@@ -156,6 +161,8 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
enum aarch64_insn_branch_type type); enum aarch64_insn_branch_type type);
u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op); u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op);
u32 aarch64_insn_gen_nop(void); 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); bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
......
...@@ -283,6 +283,9 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type, ...@@ -283,6 +283,9 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
case AARCH64_INSN_REGTYPE_RT: case AARCH64_INSN_REGTYPE_RT:
shift = 0; shift = 0;
break; break;
case AARCH64_INSN_REGTYPE_RN:
shift = 5;
break;
default: default:
pr_err("%s: unknown register type encoding %d\n", __func__, pr_err("%s: unknown register type encoding %d\n", __func__,
type); type);
...@@ -325,10 +328,16 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, ...@@ -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); 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(); insn = aarch64_insn_get_bl_value();
else break;
case AARCH64_INSN_BRANCH_NOLINK:
insn = aarch64_insn_get_b_value(); insn = aarch64_insn_get_b_value();
break;
default:
BUG_ON(1);
}
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn, return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn,
offset >> 2); offset >> 2);
...@@ -380,3 +389,25 @@ u32 __kprobes aarch64_insn_gen_nop(void) ...@@ -380,3 +389,25 @@ u32 __kprobes aarch64_insn_gen_nop(void)
{ {
return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP); 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment