arch/loongarch/kernel/hw_breakpoint.c

Source file repositories/reference/linux-study-clean/arch/loongarch/kernel/hw_breakpoint.c

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kernel/hw_breakpoint.c
Extension
.c
Size
14442 bytes
Lines
576
Domain
Architecture Layer
Bucket
arch/loongarch
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

switch (ops) {
		case HW_BREAKPOINT_INSTALL:
			if (!*slot) {
				*slot = bp;
				return i;
			}
			break;
		case HW_BREAKPOINT_UNINSTALL:
			if (*slot == bp) {
				*slot = NULL;
				return i;
			}
			break;
		default:
			pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
			return -EINVAL;
		}
	}

	return -ENOSPC;
}

void ptrace_hw_copy_thread(struct task_struct *tsk)
{
	memset(tsk->thread.hbp_break, 0, sizeof(tsk->thread.hbp_break));
	memset(tsk->thread.hbp_watch, 0, sizeof(tsk->thread.hbp_watch));
}

/*
 * Unregister breakpoints from this task and reset the pointers in the thread_struct.
 */
void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
{
	int i;
	struct thread_struct *t = &tsk->thread;

	for (i = 0; i < LOONGARCH_MAX_BRP; i++) {
		if (t->hbp_break[i]) {
			unregister_hw_breakpoint(t->hbp_break[i]);
			t->hbp_break[i] = NULL;
		}
	}

	for (i = 0; i < LOONGARCH_MAX_WRP; i++) {
		if (t->hbp_watch[i]) {
			unregister_hw_breakpoint(t->hbp_watch[i]);
			t->hbp_watch[i] = NULL;
		}
	}
}

static int hw_breakpoint_control(struct perf_event *bp,
				 enum hw_breakpoint_ops ops)
{
	u32 ctrl, privilege;
	int i, max_slots, enable;
	struct pt_regs *regs;
	struct perf_event **slots;
	struct arch_hw_breakpoint *info = counter_arch_bp(bp);

	if (arch_check_bp_in_kernelspace(info))
		privilege = CTRL_PLV0_ENABLE;
	else
		privilege = CTRL_PLV3_ENABLE;

	/*  Whether bp belongs to a task. */
	if (bp->hw.target)
		regs = task_pt_regs(bp->hw.target);

	if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
		/* Breakpoint */
		slots = this_cpu_ptr(bp_on_reg);
		max_slots = boot_cpu_data.watch_ireg_count;
	} else {
		/* Watchpoint */
		slots = this_cpu_ptr(wp_on_reg);
		max_slots = boot_cpu_data.watch_dreg_count;
	}

	i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops);

	if (WARN_ONCE(i < 0, "Can't find any breakpoint slot"))
		return i;

	switch (ops) {
	case HW_BREAKPOINT_INSTALL:
		/* Set the FWPnCFG/MWPnCFG 1~4 register. */
		if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
			write_wb_reg(CSR_CFG_ADDR, i, 0, info->address);
			write_wb_reg(CSR_CFG_MASK, i, 0, info->mask);

Annotation

Implementation Notes