arch/xtensa/kernel/hw_breakpoint.c

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

File Facts

System
Linux kernel
Corpus path
arch/xtensa/kernel/hw_breakpoint.c
Extension
.c
Size
7099 bytes
Lines
310
Domain
Architecture Layer
Bucket
arch/xtensa
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 (!slot[i]) {
			slot[i] = bp;
			return i;
		}
	}
	return -EBUSY;
}

static void set_ibreak_regs(int reg, struct perf_event *bp)
{
	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
	unsigned long ibreakenable;

	xtensa_wsr(info->address, SREG_IBREAKA + reg);
	ibreakenable = xtensa_get_sr(SREG_IBREAKENABLE);
	xtensa_set_sr(ibreakenable | (1 << reg), SREG_IBREAKENABLE);
}

static void set_dbreak_regs(int reg, struct perf_event *bp)
{
	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
	unsigned long dbreakc = DBREAKC_MASK_MASK & -info->len;

	if (info->type & XTENSA_BREAKPOINT_LOAD)
		dbreakc |= DBREAKC_LOAD_MASK;
	if (info->type & XTENSA_BREAKPOINT_STORE)
		dbreakc |= DBREAKC_STOR_MASK;

	xtensa_wsr(info->address, SREG_DBREAKA + reg);
	xtensa_wsr(dbreakc, SREG_DBREAKC + reg);
}

int arch_install_hw_breakpoint(struct perf_event *bp)
{
	int i;

	if (counter_arch_bp(bp)->type == XTENSA_BREAKPOINT_EXECUTE) {
		/* Breakpoint */
		i = alloc_slot(this_cpu_ptr(bp_on_reg), XCHAL_NUM_IBREAK, bp);
		if (i < 0)
			return i;
		set_ibreak_regs(i, bp);

	} else {
		/* Watchpoint */
		i = alloc_slot(this_cpu_ptr(wp_on_reg), XCHAL_NUM_DBREAK, bp);
		if (i < 0)
			return i;
		set_dbreak_regs(i, bp);
	}
	return 0;
}

static int free_slot(struct perf_event **slot, size_t n,
		     struct perf_event *bp)
{
	size_t i;

	for (i = 0; i < n; ++i) {
		if (slot[i] == bp) {
			slot[i] = NULL;
			return i;
		}
	}
	return -EBUSY;
}

void arch_uninstall_hw_breakpoint(struct perf_event *bp)
{
	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
	int i;

	if (info->type == XTENSA_BREAKPOINT_EXECUTE) {
		unsigned long ibreakenable;

		/* Breakpoint */
		i = free_slot(this_cpu_ptr(bp_on_reg), XCHAL_NUM_IBREAK, bp);
		if (i >= 0) {
			ibreakenable = xtensa_get_sr(SREG_IBREAKENABLE);
			xtensa_set_sr(ibreakenable & ~(1 << i),
				      SREG_IBREAKENABLE);
		}
	} else {
		/* Watchpoint */
		i = free_slot(this_cpu_ptr(wp_on_reg), XCHAL_NUM_DBREAK, bp);
		if (i >= 0)
			xtensa_wsr(0, SREG_DBREAKC + i);
	}
}

Annotation

Implementation Notes