Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -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 {
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)
__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,
				     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);


+33 −2
Original line number Original line Diff line number Diff line
@@ -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,
	 */
	 */
	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)
{
{
	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);
}