Commit d4ba3313 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'loongarch-fixes-6.10-2' of...

Merge tag 'loongarch-fixes-6.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson

Pull LoongArch fixes from Huacai Chen:
 "Some hw breakpoint fixes, an objtool build warnging fix, and a trivial
  cleanup"

* tag 'loongarch-fixes-6.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
  LoongArch: KVM: Remove an unneeded semicolon
  LoongArch: Fix multiple hardware watchpoint issues
  LoongArch: Trigger user-space watchpoints correctly
  LoongArch: Fix watchpoint setting error
  LoongArch: Only allow OBJTOOL & ORC unwinder if toolchain supports -mthin-add-sub
parents fe37fe2a d0a1c077
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ config LOONGARCH
	select HAVE_LIVEPATCH
	select HAVE_MOD_ARCH_SPECIFIC
	select HAVE_NMI
	select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS
	select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB && !CC_IS_CLANG
	select HAVE_PCI
	select HAVE_PERF_EVENTS
	select HAVE_PERF_REGS
@@ -261,6 +261,9 @@ config AS_HAS_EXPLICIT_RELOCS
config AS_HAS_FCSR_CLASS
	def_bool $(as-instr,movfcsr2gr \$t0$(comma)\$fcsr0)

config AS_HAS_THIN_ADD_SUB
	def_bool $(cc-option,-Wa$(comma)-mthin-add-sub)

config AS_HAS_LSX_EXTENSION
	def_bool $(as-instr,vld \$vr0$(comma)\$a0$(comma)0)

+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ config UNWINDER_PROLOGUE

config UNWINDER_ORC
	bool "ORC unwinder"
	depends on HAVE_OBJTOOL
	select OBJTOOL
	help
	  This option enables the ORC (Oops Rewind Capability) unwinder for
+3 −1
Original line number Diff line number Diff line
@@ -75,6 +75,8 @@ do { \
#define CSR_MWPC_NUM		0x3f

#define CTRL_PLV_ENABLE		0x1e
#define CTRL_PLV0_ENABLE	0x02
#define CTRL_PLV3_ENABLE	0x10

#define MWPnCFG3_LoadEn		8
#define MWPnCFG3_StoreEn	9
@@ -101,7 +103,7 @@ struct perf_event;
struct perf_event_attr;

extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
				  int *gen_len, int *gen_type, int *offset);
				  int *gen_len, int *gen_type);
extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
extern int hw_breakpoint_arch_parse(struct perf_event *bp,
				    const struct perf_event_attr *attr,
+55 −41
Original line number Diff line number Diff line
@@ -174,11 +174,21 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
static int hw_breakpoint_control(struct perf_event *bp,
				 enum hw_breakpoint_ops ops)
{
	u32 ctrl;
	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);
@@ -197,31 +207,38 @@ static int hw_breakpoint_control(struct perf_event *bp,
	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_ADDR, i, 1, info->address);
			write_wb_reg(CSR_CFG_MASK, i, 0, info->mask);
		write_wb_reg(CSR_CFG_MASK, i, 1, info->mask);
			write_wb_reg(CSR_CFG_ASID, i, 0, 0);
		write_wb_reg(CSR_CFG_ASID, i, 1, 0);
		if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
			write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
			write_wb_reg(CSR_CFG_CTRL, i, 0, privilege);
		} else {
			write_wb_reg(CSR_CFG_ADDR, i, 1, info->address);
			write_wb_reg(CSR_CFG_MASK, i, 1, info->mask);
			write_wb_reg(CSR_CFG_ASID, i, 1, 0);
			ctrl = encode_ctrl_reg(info->ctrl);
			write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl | CTRL_PLV_ENABLE);
			write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl | privilege);
		}
		enable = csr_read64(LOONGARCH_CSR_CRMD);
		csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD);
		if (bp->hw.target)
			regs->csr_prmd |= CSR_PRMD_PWE;
		break;
	case HW_BREAKPOINT_UNINSTALL:
		/* Reset the FWPnCFG/MWPnCFG 1~4 register. */
		if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
			write_wb_reg(CSR_CFG_ADDR, i, 0, 0);
		write_wb_reg(CSR_CFG_ADDR, i, 1, 0);
			write_wb_reg(CSR_CFG_MASK, i, 0, 0);
		write_wb_reg(CSR_CFG_MASK, i, 1, 0);
			write_wb_reg(CSR_CFG_CTRL, i, 0, 0);
		write_wb_reg(CSR_CFG_CTRL, i, 1, 0);
			write_wb_reg(CSR_CFG_ASID, i, 0, 0);
		} else {
			write_wb_reg(CSR_CFG_ADDR, i, 1, 0);
			write_wb_reg(CSR_CFG_MASK, i, 1, 0);
			write_wb_reg(CSR_CFG_CTRL, i, 1, 0);
			write_wb_reg(CSR_CFG_ASID, i, 1, 0);
		}
		if (bp->hw.target)
			regs->csr_prmd &= ~CSR_PRMD_PWE;
		break;
	}

@@ -283,7 +300,7 @@ int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
 * to generic breakpoint descriptions.
 */
int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
			   int *gen_len, int *gen_type, int *offset)
			   int *gen_len, int *gen_type)
{
	/* Type */
	switch (ctrl.type) {
@@ -303,11 +320,6 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
		return -EINVAL;
	}

	if (!ctrl.len)
		return -EINVAL;

	*offset = __ffs(ctrl.len);

	/* Len */
	switch (ctrl.len) {
	case LOONGARCH_BREAKPOINT_LEN_1:
@@ -386,21 +398,17 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
			     struct arch_hw_breakpoint *hw)
{
	int ret;
	u64 alignment_mask, offset;
	u64 alignment_mask;

	/* Build the arch_hw_breakpoint. */
	ret = arch_build_bp_info(bp, attr, hw);
	if (ret)
		return ret;

	if (hw->ctrl.type != LOONGARCH_BREAKPOINT_EXECUTE)
		alignment_mask = 0x7;
	else
	if (hw->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
		alignment_mask = 0x3;
	offset = hw->address & alignment_mask;

		hw->address &= ~alignment_mask;
	hw->ctrl.len <<= offset;
	}

	return 0;
}
@@ -471,13 +479,16 @@ void breakpoint_handler(struct pt_regs *regs)
	slots = this_cpu_ptr(bp_on_reg);

	for (i = 0; i < boot_cpu_data.watch_ireg_count; ++i) {
		if ((csr_read32(LOONGARCH_CSR_FWPS) & (0x1 << i))) {
			bp = slots[i];
			if (bp == NULL)
				continue;
			perf_bp_event(bp, regs);
	}
			csr_write32(0x1 << i, LOONGARCH_CSR_FWPS);
			update_bp_registers(regs, 0, 0);
		}
	}
}
NOKPROBE_SYMBOL(breakpoint_handler);

void watchpoint_handler(struct pt_regs *regs)
@@ -488,13 +499,16 @@ void watchpoint_handler(struct pt_regs *regs)
	slots = this_cpu_ptr(wp_on_reg);

	for (i = 0; i < boot_cpu_data.watch_dreg_count; ++i) {
		if ((csr_read32(LOONGARCH_CSR_MWPS) & (0x1 << i))) {
			wp = slots[i];
			if (wp == NULL)
				continue;
			perf_bp_event(wp, regs);
	}
			csr_write32(0x1 << i, LOONGARCH_CSR_MWPS);
			update_bp_registers(regs, 0, 1);
		}
	}
}
NOKPROBE_SYMBOL(watchpoint_handler);

static int __init arch_hw_breakpoint_init(void)
+27 −20
Original line number Diff line number Diff line
@@ -494,28 +494,14 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
				     struct arch_hw_breakpoint_ctrl ctrl,
				     struct perf_event_attr *attr)
{
	int err, len, type, offset;
	int err, len, type;

	err = arch_bp_generic_fields(ctrl, &len, &type, &offset);
	err = arch_bp_generic_fields(ctrl, &len, &type);
	if (err)
		return err;

	switch (note_type) {
	case NT_LOONGARCH_HW_BREAK:
		if ((type & HW_BREAKPOINT_X) != type)
			return -EINVAL;
		break;
	case NT_LOONGARCH_HW_WATCH:
		if ((type & HW_BREAKPOINT_RW) != type)
			return -EINVAL;
		break;
	default:
		return -EINVAL;
	}

	attr->bp_len	= len;
	attr->bp_type	= type;
	attr->bp_addr	+= offset;

	return 0;
}
@@ -609,10 +595,27 @@ static int ptrace_hbp_set_ctrl(unsigned int note_type,
		return PTR_ERR(bp);

	attr = bp->attr;

	switch (note_type) {
	case NT_LOONGARCH_HW_BREAK:
		ctrl.type = LOONGARCH_BREAKPOINT_EXECUTE;
		ctrl.len = LOONGARCH_BREAKPOINT_LEN_4;
		break;
	case NT_LOONGARCH_HW_WATCH:
		decode_ctrl_reg(uctrl, &ctrl);
		break;
	default:
		return -EINVAL;
	}

	if (uctrl & CTRL_PLV_ENABLE) {
		err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
		if (err)
			return err;
		attr.disabled = 0;
	} else {
		attr.disabled = 1;
	}

	return modify_user_hw_breakpoint(bp, &attr);
}
@@ -643,6 +646,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type,
	struct perf_event *bp;
	struct perf_event_attr attr;

	/* Kernel-space address cannot be monitored by user-space */
	if ((unsigned long)addr >= XKPRANGE)
		return -EINVAL;

	bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
	if (IS_ERR(bp))
		return PTR_ERR(bp);
Loading