arch/arm64/kernel/hw_breakpoint.c

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

File Facts

System
Linux kernel
Corpus path
arch/arm64/kernel/hw_breakpoint.c
Extension
.c
Size
25674 bytes
Lines
1013
Domain
Architecture Layer
Bucket
arch/arm64
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;
		case HW_BREAKPOINT_RESTORE:
			if (*slot == bp)
				return i;
			break;
		default:
			pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
			return -EINVAL;
		}
	}
	return -ENOSPC;
}

static int hw_breakpoint_control(struct perf_event *bp,
				 enum hw_breakpoint_ops ops)
{
	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
	struct perf_event **slots;
	struct debug_info *debug_info = &current->thread.debug;
	int i, max_slots, ctrl_reg, val_reg, reg_enable;
	enum dbg_active_el dbg_el = debug_exception_level(info->ctrl.privilege);
	u32 ctrl;

	if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
		/* Breakpoint */
		ctrl_reg = AARCH64_DBG_REG_BCR;
		val_reg = AARCH64_DBG_REG_BVR;
		slots = this_cpu_ptr(bp_on_reg);
		max_slots = core_num_brps;
		reg_enable = !debug_info->bps_disabled;
	} else {
		/* Watchpoint */
		ctrl_reg = AARCH64_DBG_REG_WCR;
		val_reg = AARCH64_DBG_REG_WVR;
		slots = this_cpu_ptr(wp_on_reg);
		max_slots = core_num_wrps;
		reg_enable = !debug_info->wps_disabled;
	}

	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:
		/*
		 * Ensure debug monitors are enabled at the correct exception
		 * level.
		 */
		enable_debug_monitors(dbg_el);
		fallthrough;
	case HW_BREAKPOINT_RESTORE:
		/* Setup the address register. */
		write_wb_reg(val_reg, i, info->address);

		/* Setup the control register. */
		ctrl = encode_ctrl_reg(info->ctrl);
		write_wb_reg(ctrl_reg, i,
			     reg_enable ? ctrl | 0x1 : ctrl & ~0x1);
		break;
	case HW_BREAKPOINT_UNINSTALL:
		/* Reset the control register. */
		write_wb_reg(ctrl_reg, i, 0);

		/*
		 * Release the debug monitors for the correct exception
		 * level.
		 */
		disable_debug_monitors(dbg_el);
		break;
	}

	return 0;
}

/*
 * Install a perf counter breakpoint.

Annotation

Implementation Notes