arch/arm/probes/kprobes/actions-thumb.c

Source file repositories/reference/linux-study-clean/arch/arm/probes/kprobes/actions-thumb.c

File Facts

System
Linux kernel
Corpus path
arch/arm/probes/kprobes/actions-thumb.c
Extension
.c
Size
19454 bytes
Lines
676
Domain
Architecture Layer
Bucket
arch/arm
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!(insn & (1 << 12))) {
			/* BLX so switch to ARM mode */
			regs->ARM_cpsr &= ~PSR_T_BIT;
			pc &= ~3;
		}
	}

	regs->ARM_pc = pc + (offset * 2);
}

static void __kprobes
t32_simulate_ldr_literal(probes_opcode_t insn,
		struct arch_probes_insn *asi, struct pt_regs *regs)
{
	unsigned long addr = regs->ARM_pc & ~3;
	int rt = (insn >> 12) & 0xf;
	unsigned long rtv;

	long offset = insn & 0xfff;
	if (insn & 0x00800000)
		addr += offset;
	else
		addr -= offset;

	if (insn & 0x00400000) {
		/* LDR */
		rtv = *(unsigned long *)addr;
		if (rt == 15) {
			bx_write_pc(rtv, regs);
			return;
		}
	} else if (insn & 0x00200000) {
		/* LDRH */
		if (insn & 0x01000000)
			rtv = *(s16 *)addr;
		else
			rtv = *(u16 *)addr;
	} else {
		/* LDRB */
		if (insn & 0x01000000)
			rtv = *(s8 *)addr;
		else
			rtv = *(u8 *)addr;
	}

	regs->uregs[rt] = rtv;
}

static enum probes_insn __kprobes
t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
		const struct decode_header *d)
{
	enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);

	/* Fixup modified instruction to have halfwords in correct order...*/
	insn = __mem_to_opcode_arm(asi->insn[0]);
	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);

	return ret;
}

static void __kprobes
t32_emulate_ldrdstrd(probes_opcode_t insn,
		struct arch_probes_insn *asi, struct pt_regs *regs)
{
	unsigned long pc = regs->ARM_pc & ~3;
	int rt1 = (insn >> 12) & 0xf;
	int rt2 = (insn >> 8) & 0xf;
	int rn = (insn >> 16) & 0xf;

	register unsigned long rt1v asm("r0") = regs->uregs[rt1];
	register unsigned long rt2v asm("r1") = regs->uregs[rt2];
	register unsigned long rnv asm("r2") = (rn == 15) ? pc
							  : regs->uregs[rn];

	__asm__ __volatile__ (
		"blx    %[fn]"
		: "=r" (rt1v), "=r" (rt2v), "=r" (rnv)
		: "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn)
		: "lr", "memory", "cc"
	);

	if (rn != 15)
		regs->uregs[rn] = rnv; /* Writeback base register */
	regs->uregs[rt1] = rt1v;
	regs->uregs[rt2] = rt2v;
}

static void __kprobes

Annotation

Implementation Notes