Commit d4ba3313 authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -143,7 +143,7 @@ config LOONGARCH ...@@ -143,7 +143,7 @@ config LOONGARCH
select HAVE_LIVEPATCH select HAVE_LIVEPATCH
select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI 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_PCI
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select HAVE_PERF_REGS select HAVE_PERF_REGS
...@@ -261,6 +261,9 @@ config AS_HAS_EXPLICIT_RELOCS ...@@ -261,6 +261,9 @@ config AS_HAS_EXPLICIT_RELOCS
config AS_HAS_FCSR_CLASS config AS_HAS_FCSR_CLASS
def_bool $(as-instr,movfcsr2gr \$t0$(comma)\$fcsr0) 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 config AS_HAS_LSX_EXTENSION
def_bool $(as-instr,vld \$vr0$(comma)\$a0$(comma)0) def_bool $(as-instr,vld \$vr0$(comma)\$a0$(comma)0)
......
...@@ -28,6 +28,7 @@ config UNWINDER_PROLOGUE ...@@ -28,6 +28,7 @@ config UNWINDER_PROLOGUE
config UNWINDER_ORC config UNWINDER_ORC
bool "ORC unwinder" bool "ORC unwinder"
depends on HAVE_OBJTOOL
select OBJTOOL select OBJTOOL
help help
This option enables the ORC (Oops Rewind Capability) unwinder for This option enables the ORC (Oops Rewind Capability) unwinder for
......
...@@ -75,6 +75,8 @@ do { \ ...@@ -75,6 +75,8 @@ do { \
#define CSR_MWPC_NUM 0x3f #define CSR_MWPC_NUM 0x3f
#define CTRL_PLV_ENABLE 0x1e #define CTRL_PLV_ENABLE 0x1e
#define CTRL_PLV0_ENABLE 0x02
#define CTRL_PLV3_ENABLE 0x10
#define MWPnCFG3_LoadEn 8 #define MWPnCFG3_LoadEn 8
#define MWPnCFG3_StoreEn 9 #define MWPnCFG3_StoreEn 9
...@@ -101,7 +103,7 @@ struct perf_event; ...@@ -101,7 +103,7 @@ struct perf_event;
struct perf_event_attr; struct perf_event_attr;
extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, 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 arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
extern int hw_breakpoint_arch_parse(struct perf_event *bp, extern int hw_breakpoint_arch_parse(struct perf_event *bp,
const struct perf_event_attr *attr, const struct perf_event_attr *attr,
......
...@@ -174,11 +174,21 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk) ...@@ -174,11 +174,21 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
static int hw_breakpoint_control(struct perf_event *bp, static int hw_breakpoint_control(struct perf_event *bp,
enum hw_breakpoint_ops ops) enum hw_breakpoint_ops ops)
{ {
u32 ctrl; u32 ctrl, privilege;
int i, max_slots, enable; int i, max_slots, enable;
struct pt_regs *regs;
struct perf_event **slots; struct perf_event **slots;
struct arch_hw_breakpoint *info = counter_arch_bp(bp); 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) { if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
/* Breakpoint */ /* Breakpoint */
slots = this_cpu_ptr(bp_on_reg); slots = this_cpu_ptr(bp_on_reg);
...@@ -197,31 +207,38 @@ static int hw_breakpoint_control(struct perf_event *bp, ...@@ -197,31 +207,38 @@ static int hw_breakpoint_control(struct perf_event *bp,
switch (ops) { switch (ops) {
case HW_BREAKPOINT_INSTALL: case HW_BREAKPOINT_INSTALL:
/* Set the FWPnCFG/MWPnCFG 1~4 register. */ /* 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, 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, 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, 0, 0);
write_wb_reg(CSR_CFG_ASID, i, 1, 0); write_wb_reg(CSR_CFG_CTRL, i, 0, privilege);
if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
} else { } 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); 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); enable = csr_read64(LOONGARCH_CSR_CRMD);
csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD); csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD);
if (bp->hw.target)
regs->csr_prmd |= CSR_PRMD_PWE;
break; break;
case HW_BREAKPOINT_UNINSTALL: case HW_BREAKPOINT_UNINSTALL:
/* Reset the FWPnCFG/MWPnCFG 1~4 register. */ /* 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, 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, 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, 0, 0);
write_wb_reg(CSR_CFG_CTRL, i, 1, 0);
write_wb_reg(CSR_CFG_ASID, i, 0, 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); write_wb_reg(CSR_CFG_ASID, i, 1, 0);
}
if (bp->hw.target)
regs->csr_prmd &= ~CSR_PRMD_PWE;
break; break;
} }
...@@ -283,7 +300,7 @@ int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw) ...@@ -283,7 +300,7 @@ int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
* to generic breakpoint descriptions. * to generic breakpoint descriptions.
*/ */
int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, 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 */ /* Type */
switch (ctrl.type) { switch (ctrl.type) {
...@@ -303,11 +320,6 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, ...@@ -303,11 +320,6 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
return -EINVAL; return -EINVAL;
} }
if (!ctrl.len)
return -EINVAL;
*offset = __ffs(ctrl.len);
/* Len */ /* Len */
switch (ctrl.len) { switch (ctrl.len) {
case LOONGARCH_BREAKPOINT_LEN_1: case LOONGARCH_BREAKPOINT_LEN_1:
...@@ -386,21 +398,17 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, ...@@ -386,21 +398,17 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
struct arch_hw_breakpoint *hw) struct arch_hw_breakpoint *hw)
{ {
int ret; int ret;
u64 alignment_mask, offset; u64 alignment_mask;
/* Build the arch_hw_breakpoint. */ /* Build the arch_hw_breakpoint. */
ret = arch_build_bp_info(bp, attr, hw); ret = arch_build_bp_info(bp, attr, hw);
if (ret) if (ret)
return ret; return ret;
if (hw->ctrl.type != LOONGARCH_BREAKPOINT_EXECUTE) if (hw->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
alignment_mask = 0x7;
else
alignment_mask = 0x3; alignment_mask = 0x3;
offset = hw->address & alignment_mask;
hw->address &= ~alignment_mask; hw->address &= ~alignment_mask;
hw->ctrl.len <<= offset; }
return 0; return 0;
} }
...@@ -471,12 +479,15 @@ void breakpoint_handler(struct pt_regs *regs) ...@@ -471,12 +479,15 @@ void breakpoint_handler(struct pt_regs *regs)
slots = this_cpu_ptr(bp_on_reg); slots = this_cpu_ptr(bp_on_reg);
for (i = 0; i < boot_cpu_data.watch_ireg_count; ++i) { for (i = 0; i < boot_cpu_data.watch_ireg_count; ++i) {
if ((csr_read32(LOONGARCH_CSR_FWPS) & (0x1 << i))) {
bp = slots[i]; bp = slots[i];
if (bp == NULL) if (bp == NULL)
continue; continue;
perf_bp_event(bp, regs); perf_bp_event(bp, regs);
} csr_write32(0x1 << i, LOONGARCH_CSR_FWPS);
update_bp_registers(regs, 0, 0); update_bp_registers(regs, 0, 0);
}
}
} }
NOKPROBE_SYMBOL(breakpoint_handler); NOKPROBE_SYMBOL(breakpoint_handler);
...@@ -488,12 +499,15 @@ void watchpoint_handler(struct pt_regs *regs) ...@@ -488,12 +499,15 @@ void watchpoint_handler(struct pt_regs *regs)
slots = this_cpu_ptr(wp_on_reg); slots = this_cpu_ptr(wp_on_reg);
for (i = 0; i < boot_cpu_data.watch_dreg_count; ++i) { for (i = 0; i < boot_cpu_data.watch_dreg_count; ++i) {
if ((csr_read32(LOONGARCH_CSR_MWPS) & (0x1 << i))) {
wp = slots[i]; wp = slots[i];
if (wp == NULL) if (wp == NULL)
continue; continue;
perf_bp_event(wp, regs); perf_bp_event(wp, regs);
} csr_write32(0x1 << i, LOONGARCH_CSR_MWPS);
update_bp_registers(regs, 0, 1); update_bp_registers(regs, 0, 1);
}
}
} }
NOKPROBE_SYMBOL(watchpoint_handler); NOKPROBE_SYMBOL(watchpoint_handler);
......
...@@ -494,28 +494,14 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, ...@@ -494,28 +494,14 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
struct arch_hw_breakpoint_ctrl ctrl, struct arch_hw_breakpoint_ctrl ctrl,
struct perf_event_attr *attr) 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) if (err)
return 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_len = len;
attr->bp_type = type; attr->bp_type = type;
attr->bp_addr += offset;
return 0; return 0;
} }
...@@ -609,10 +595,27 @@ static int ptrace_hbp_set_ctrl(unsigned int note_type, ...@@ -609,10 +595,27 @@ static int ptrace_hbp_set_ctrl(unsigned int note_type,
return PTR_ERR(bp); return PTR_ERR(bp);
attr = bp->attr; 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); decode_ctrl_reg(uctrl, &ctrl);
break;
default:
return -EINVAL;
}
if (uctrl & CTRL_PLV_ENABLE) {
err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr); err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
if (err) if (err)
return err; return err;
attr.disabled = 0;
} else {
attr.disabled = 1;
}
return modify_user_hw_breakpoint(bp, &attr); return modify_user_hw_breakpoint(bp, &attr);
} }
...@@ -643,6 +646,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type, ...@@ -643,6 +646,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type,
struct perf_event *bp; struct perf_event *bp;
struct perf_event_attr attr; 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); bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
if (IS_ERR(bp)) if (IS_ERR(bp))
return PTR_ERR(bp); return PTR_ERR(bp);
......
...@@ -761,7 +761,7 @@ static void kvm_handle_service(struct kvm_vcpu *vcpu) ...@@ -761,7 +761,7 @@ static void kvm_handle_service(struct kvm_vcpu *vcpu)
default: default:
ret = KVM_HCALL_INVALID_CODE; ret = KVM_HCALL_INVALID_CODE;
break; break;
}; }
kvm_write_reg(vcpu, LOONGARCH_GPR_A0, ret); kvm_write_reg(vcpu, LOONGARCH_GPR_A0, ret);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment