mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 16:37:50 +00:00
LoongArch fixes for v6.10-rc5
-----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEzOlt8mkP+tbeiYy5AoYrw/LiJnoFAmZ1T2UWHGNoZW5odWFj YWlAa2VybmVsLm9yZwAKCRAChivD8uImeq0bD/wOpM8X6Pu6d5XI97aUwZ50EJ3u VIaG2YztLmSvFBi2WnFhAka0GXJn0KqoX06is0RemF7e1Ve8xKmRqY0KnytODcTn 162gH7Bk2MP8X6fxTy5gLRP3c7BQ7zXpiCXcHFI/zvqEIGe0CKEDzXT3K3FtlHV+ qqGry5VmqS8cjhby/00hTkUMkfkRaC/GLjccLgSUIFyi8k42Bh+RwqCJJEK0CHP/ 38sBNuj1hHQW61nWEWzE9cUxeeCIPtIBlOijxKQXRTqw1+uyb1IlC+qhsbptoe/r pWiop2w/DprZ+HBoxe0lPJQgbHxVTOLCQQDwU0N9A8YnSg3nY8jjAbTb8CyWZI6G YCuPZD92pgteYpVPLe1DLjlGrB8a7mQUyjDY875Vicyu7IoDQc8YLrZRpltWLZyY +ooj4c/N7u2LKVBroU3TQFgoqw2ZaRhkc6J9BF2yXXwCm085OlKSQZqrvXZTXNgg G0N2PTRLBGyXmpAvu0HdbPwuzEP0gED/h8dWUHiKXwbHn0KO5FG7503Kh+mk0+Rd +agwW0mY2fSp+m/GgUfDMZ6bM5lVvU9GBoa+ed7pnMIUF0yEmS7Jqo+TP/e6Xa0f s+kLDSiQMRpQ7AK40DskK8inojo8zTh2DlLZx96wM4CTWgdYSxCDy0M80NfAggho PHkfo83IfPcAu5lUrg== =4Phm -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
d4ba3313e8
6 changed files with 91 additions and 64 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
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_ADDR, i, 0, info->address);
|
||||
write_wb_reg(CSR_CFG_MASK, i, 0, info->mask);
|
||||
write_wb_reg(CSR_CFG_ASID, i, 0, 0);
|
||||
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. */
|
||||
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);
|
||||
write_wb_reg(CSR_CFG_ASID, i, 1, 0);
|
||||
if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
|
||||
write_wb_reg(CSR_CFG_ADDR, i, 0, 0);
|
||||
write_wb_reg(CSR_CFG_MASK, i, 0, 0);
|
||||
write_wb_reg(CSR_CFG_CTRL, 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);
|
||||
}
|
||||
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;
|
||||
hw->address &= ~alignment_mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -471,12 +479,15 @@ 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) {
|
||||
bp = slots[i];
|
||||
if (bp == NULL)
|
||||
continue;
|
||||
perf_bp_event(bp, regs);
|
||||
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);
|
||||
}
|
||||
}
|
||||
update_bp_registers(regs, 0, 0);
|
||||
}
|
||||
NOKPROBE_SYMBOL(breakpoint_handler);
|
||||
|
||||
|
@ -488,12 +499,15 @@ 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) {
|
||||
wp = slots[i];
|
||||
if (wp == NULL)
|
||||
continue;
|
||||
perf_bp_event(wp, regs);
|
||||
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);
|
||||
}
|
||||
}
|
||||
update_bp_registers(regs, 0, 1);
|
||||
}
|
||||
NOKPROBE_SYMBOL(watchpoint_handler);
|
||||
|
||||
|
|
|
@ -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;
|
||||
decode_ctrl_reg(uctrl, &ctrl);
|
||||
err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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);
|
||||
|
|
|
@ -761,7 +761,7 @@ static void kvm_handle_service(struct kvm_vcpu *vcpu)
|
|||
default:
|
||||
ret = KVM_HCALL_INVALID_CODE;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
kvm_write_reg(vcpu, LOONGARCH_GPR_A0, ret);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue