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

Commit 20e8155e authored by Jon Medhurst's avatar Jon Medhurst Committed by Nicolas Pitre
Browse files

ARM: kprobes: Add emulation of SBFX, UBFX, BFI and BFC instructions



These bit field manipulation instructions occur several thousand
times in an ARMv7 kernel.

Signed-off-by: default avatarJon Medhurst <tixy@yxit.co.uk>
Signed-off-by: default avatarNicolas Pitre <nicolas.pitre@linaro.org>
parent c9836777
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -672,6 +672,19 @@ emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs)
	regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn);
}

static void __kprobes
emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs)
{
	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
	kprobe_opcode_t insn = p->opcode;
	int rd = (insn >> 12) & 0xf;
	int rn = insn & 0xf;
	long rdv = regs->uregs[rd];
	long rnv = regs->uregs[rn];

	regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn);
}

static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs)
{
	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
@@ -869,6 +882,20 @@ prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi)
	return INSN_GOOD;
}

static enum kprobe_insn __kprobes
prep_emulate_rd12rn0_modify(kprobe_opcode_t insn,
			    struct arch_specific_insn *asi)
{
	if (is_r15(insn, 12))
		return INSN_REJECTED;	/* Rd is PC */

	insn &= 0xffff0ff0;	/* Rd = r0 */
	insn |= 0x00000001;	/* Rn = r1 */
	asi->insn[0] = insn;
	asi->insn_handler = emulate_rd12rn0_modify;
	return INSN_GOOD;
}

static enum kprobe_insn __kprobes
prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi)
{
@@ -1396,6 +1423,21 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
	if ((insn & 0x0ff000d0) == 0x075000d0)
		return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);

	/* SBFX   : cccc 0111 101x xxxx xxxx xxxx x101 xxxx :  */
	/* UBFX   : cccc 0111 111x xxxx xxxx xxxx x101 xxxx :  */
	if ((insn & 0x0fa00070) == 0x07a00050)
		return prep_emulate_rd12rm0(insn, asi);

	/* BFI    : cccc 0111 110x xxxx xxxx xxxx x001 xxxx :  */
	/* BFC    : cccc 0111 110x xxxx xxxx xxxx x001 1111 :  */
	if ((insn & 0x0fe00070) == 0x07c00010) {

		if ((insn & 0x0000000f) == 0x0000000f)
			return prep_emulate_rd12_modify(insn, asi);
		else
			return prep_emulate_rd12rn0_modify(insn, asi);
	}

	return INSN_REJECTED;
}