arch/csky/kernel/probes/kprobes.c

Source file repositories/reference/linux-study-clean/arch/csky/kernel/probes/kprobes.c

File Facts

System
Linux kernel
Corpus path
arch/csky/kernel/probes/kprobes.c
Extension
.c
Size
9910 bytes
Lines
413
Domain
Architecture Layer
Bucket
arch/csky
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

struct csky_insn_patch {
	kprobe_opcode_t	*addr;
	u32		opcode;
	atomic_t	cpu_count;
};

static int __kprobes patch_text_cb(void *priv)
{
	struct csky_insn_patch *param = priv;
	unsigned int addr = (unsigned int)param->addr;

	if (atomic_inc_return(&param->cpu_count) == num_online_cpus()) {
		*(u16 *) addr = cpu_to_le16(param->opcode);
		dcache_wb_range(addr, addr + 2);
		atomic_inc(&param->cpu_count);
	} else {
		while (atomic_read(&param->cpu_count) <= num_online_cpus())
			cpu_relax();
	}

	icache_inv_range(addr, addr + 2);

	return 0;
}

static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
{
	struct csky_insn_patch param = { addr, opcode, ATOMIC_INIT(0) };

	return stop_machine_cpuslocked(patch_text_cb, &param, cpu_online_mask);
}

static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
{
	unsigned long offset = is_insn32(p->opcode) ? 4 : 2;

	p->ainsn.api.restore = (unsigned long)p->addr + offset;

	patch_text(p->ainsn.api.insn, p->opcode);
}

static void __kprobes arch_prepare_simulate(struct kprobe *p)
{
	p->ainsn.api.restore = 0;
}

static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
{
	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();

	if (p->ainsn.api.handler)
		p->ainsn.api.handler((u32)p->opcode, (long)p->addr, regs);

	post_kprobe_handler(kcb, regs);
}

int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
	unsigned long probe_addr = (unsigned long)p->addr;

	if (probe_addr & 0x1)
		return -EILSEQ;

	/* copy instruction */
	p->opcode = le32_to_cpu(*p->addr);

	/* decode instruction */
	switch (csky_probe_decode_insn(p->addr, &p->ainsn.api)) {
	case INSN_REJECTED:	/* insn not supported */
		return -EINVAL;

	case INSN_GOOD_NO_SLOT:	/* insn need simulation */
		p->ainsn.api.insn = NULL;
		break;

	case INSN_GOOD:	/* instruction uses slot */
		p->ainsn.api.insn = get_insn_slot();
		if (!p->ainsn.api.insn)
			return -ENOMEM;
		break;
	}

	/* prepare the instruction */
	if (p->ainsn.api.insn)
		arch_prepare_ss_slot(p);
	else
		arch_prepare_simulate(p);

	return 0;
}

Annotation

Implementation Notes