arch/s390/kernel/kprobes.c

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

File Facts

System
Linux kernel
Corpus path
arch/s390/kernel/kprobes.c
Extension
.c
Size
13098 bytes
Lines
504
Domain
Architecture Layer
Bucket
arch/s390
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 swap_insn_args {
	struct kprobe *p;
	unsigned int arm_kprobe : 1;
};

static int swap_instruction(void *data)
{
	struct swap_insn_args *args = data;
	struct kprobe *p = args->p;
	u16 opc;

	opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode;
	s390_kernel_write(p->addr, &opc, sizeof(opc));
	return 0;
}
NOKPROBE_SYMBOL(swap_instruction);

void arch_arm_kprobe(struct kprobe *p)
{
	struct swap_insn_args args = {.p = p, .arm_kprobe = 1};

	if (cpu_has_seq_insn()) {
		swap_instruction(&args);
		text_poke_sync();
	} else {
		stop_machine_cpuslocked(swap_instruction, &args, NULL);
	}
}
NOKPROBE_SYMBOL(arch_arm_kprobe);

void arch_disarm_kprobe(struct kprobe *p)
{
	struct swap_insn_args args = {.p = p, .arm_kprobe = 0};

	if (cpu_has_seq_insn()) {
		swap_instruction(&args);
		text_poke_sync();
	} else {
		stop_machine_cpuslocked(swap_instruction, &args, NULL);
	}
}
NOKPROBE_SYMBOL(arch_disarm_kprobe);

void arch_remove_kprobe(struct kprobe *p)
{
	if (!p->ainsn.insn)
		return;
	free_insn_slot(p->ainsn.insn, 0);
	p->ainsn.insn = NULL;
}
NOKPROBE_SYMBOL(arch_remove_kprobe);

static void enable_singlestep(struct kprobe_ctlblk *kcb,
			      struct pt_regs *regs,
			      unsigned long ip)
{
	union {
		struct ctlreg regs[3];
		struct {
			struct ctlreg control;
			struct ctlreg start;
			struct ctlreg end;
		};
	} per_kprobe;

	/* Set up the PER control registers %cr9-%cr11 */
	per_kprobe.control.val = PER_EVENT_IFETCH;
	per_kprobe.start.val = ip;
	per_kprobe.end.val = ip;

	/* Save control regs and psw mask */
	__local_ctl_store(9, 11, kcb->kprobe_saved_ctl);
	kcb->kprobe_saved_imask = regs->psw.mask &
		(PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);

	/* Set PER control regs, turns on single step for the given address */
	__local_ctl_load(9, 11, per_kprobe.regs);
	regs->psw.mask |= PSW_MASK_PER;
	regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
	regs->psw.addr = ip;
}
NOKPROBE_SYMBOL(enable_singlestep);

static void disable_singlestep(struct kprobe_ctlblk *kcb,
			       struct pt_regs *regs,
			       unsigned long ip)
{
	/* Restore control regs and psw mask, set new psw address */
	__local_ctl_load(9, 11, kcb->kprobe_saved_ctl);
	regs->psw.mask &= ~PSW_MASK_PER;

Annotation

Implementation Notes