Skip to content

Commit d4ba331

Browse files
committed
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
2 parents fe37fe2 + d0a1c07 commit d4ba331

File tree

6 files changed

+91
-64
lines changed

6 files changed

+91
-64
lines changed

arch/loongarch/Kconfig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ config LOONGARCH
143143
select HAVE_LIVEPATCH
144144
select HAVE_MOD_ARCH_SPECIFIC
145145
select HAVE_NMI
146-
select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS
146+
select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB && !CC_IS_CLANG
147147
select HAVE_PCI
148148
select HAVE_PERF_EVENTS
149149
select HAVE_PERF_REGS
@@ -261,6 +261,9 @@ config AS_HAS_EXPLICIT_RELOCS
261261
config AS_HAS_FCSR_CLASS
262262
def_bool $(as-instr,movfcsr2gr \$t0$(comma)\$fcsr0)
263263

264+
config AS_HAS_THIN_ADD_SUB
265+
def_bool $(cc-option,-Wa$(comma)-mthin-add-sub)
266+
264267
config AS_HAS_LSX_EXTENSION
265268
def_bool $(as-instr,vld \$vr0$(comma)\$a0$(comma)0)
266269

arch/loongarch/Kconfig.debug

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ config UNWINDER_PROLOGUE
2828

2929
config UNWINDER_ORC
3030
bool "ORC unwinder"
31+
depends on HAVE_OBJTOOL
3132
select OBJTOOL
3233
help
3334
This option enables the ORC (Oops Rewind Capability) unwinder for

arch/loongarch/include/asm/hw_breakpoint.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ do { \
7575
#define CSR_MWPC_NUM 0x3f
7676

7777
#define CTRL_PLV_ENABLE 0x1e
78+
#define CTRL_PLV0_ENABLE 0x02
79+
#define CTRL_PLV3_ENABLE 0x10
7880

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

103105
extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
104-
int *gen_len, int *gen_type, int *offset);
106+
int *gen_len, int *gen_type);
105107
extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
106108
extern int hw_breakpoint_arch_parse(struct perf_event *bp,
107109
const struct perf_event_attr *attr,

arch/loongarch/kernel/hw_breakpoint.c

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,21 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
174174
static int hw_breakpoint_control(struct perf_event *bp,
175175
enum hw_breakpoint_ops ops)
176176
{
177-
u32 ctrl;
177+
u32 ctrl, privilege;
178178
int i, max_slots, enable;
179+
struct pt_regs *regs;
179180
struct perf_event **slots;
180181
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
181182

183+
if (arch_check_bp_in_kernelspace(info))
184+
privilege = CTRL_PLV0_ENABLE;
185+
else
186+
privilege = CTRL_PLV3_ENABLE;
187+
188+
/* Whether bp belongs to a task. */
189+
if (bp->hw.target)
190+
regs = task_pt_regs(bp->hw.target);
191+
182192
if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
183193
/* Breakpoint */
184194
slots = this_cpu_ptr(bp_on_reg);
@@ -197,31 +207,38 @@ static int hw_breakpoint_control(struct perf_event *bp,
197207
switch (ops) {
198208
case HW_BREAKPOINT_INSTALL:
199209
/* Set the FWPnCFG/MWPnCFG 1~4 register. */
200-
write_wb_reg(CSR_CFG_ADDR, i, 0, info->address);
201-
write_wb_reg(CSR_CFG_ADDR, i, 1, info->address);
202-
write_wb_reg(CSR_CFG_MASK, i, 0, info->mask);
203-
write_wb_reg(CSR_CFG_MASK, i, 1, info->mask);
204-
write_wb_reg(CSR_CFG_ASID, i, 0, 0);
205-
write_wb_reg(CSR_CFG_ASID, i, 1, 0);
206210
if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
207-
write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
211+
write_wb_reg(CSR_CFG_ADDR, i, 0, info->address);
212+
write_wb_reg(CSR_CFG_MASK, i, 0, info->mask);
213+
write_wb_reg(CSR_CFG_ASID, i, 0, 0);
214+
write_wb_reg(CSR_CFG_CTRL, i, 0, privilege);
208215
} else {
216+
write_wb_reg(CSR_CFG_ADDR, i, 1, info->address);
217+
write_wb_reg(CSR_CFG_MASK, i, 1, info->mask);
218+
write_wb_reg(CSR_CFG_ASID, i, 1, 0);
209219
ctrl = encode_ctrl_reg(info->ctrl);
210-
write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl | CTRL_PLV_ENABLE);
220+
write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl | privilege);
211221
}
212222
enable = csr_read64(LOONGARCH_CSR_CRMD);
213223
csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD);
224+
if (bp->hw.target)
225+
regs->csr_prmd |= CSR_PRMD_PWE;
214226
break;
215227
case HW_BREAKPOINT_UNINSTALL:
216228
/* Reset the FWPnCFG/MWPnCFG 1~4 register. */
217-
write_wb_reg(CSR_CFG_ADDR, i, 0, 0);
218-
write_wb_reg(CSR_CFG_ADDR, i, 1, 0);
219-
write_wb_reg(CSR_CFG_MASK, i, 0, 0);
220-
write_wb_reg(CSR_CFG_MASK, i, 1, 0);
221-
write_wb_reg(CSR_CFG_CTRL, i, 0, 0);
222-
write_wb_reg(CSR_CFG_CTRL, i, 1, 0);
223-
write_wb_reg(CSR_CFG_ASID, i, 0, 0);
224-
write_wb_reg(CSR_CFG_ASID, i, 1, 0);
229+
if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
230+
write_wb_reg(CSR_CFG_ADDR, i, 0, 0);
231+
write_wb_reg(CSR_CFG_MASK, i, 0, 0);
232+
write_wb_reg(CSR_CFG_CTRL, i, 0, 0);
233+
write_wb_reg(CSR_CFG_ASID, i, 0, 0);
234+
} else {
235+
write_wb_reg(CSR_CFG_ADDR, i, 1, 0);
236+
write_wb_reg(CSR_CFG_MASK, i, 1, 0);
237+
write_wb_reg(CSR_CFG_CTRL, i, 1, 0);
238+
write_wb_reg(CSR_CFG_ASID, i, 1, 0);
239+
}
240+
if (bp->hw.target)
241+
regs->csr_prmd &= ~CSR_PRMD_PWE;
225242
break;
226243
}
227244

@@ -283,7 +300,7 @@ int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
283300
* to generic breakpoint descriptions.
284301
*/
285302
int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
286-
int *gen_len, int *gen_type, int *offset)
303+
int *gen_len, int *gen_type)
287304
{
288305
/* Type */
289306
switch (ctrl.type) {
@@ -303,11 +320,6 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
303320
return -EINVAL;
304321
}
305322

306-
if (!ctrl.len)
307-
return -EINVAL;
308-
309-
*offset = __ffs(ctrl.len);
310-
311323
/* Len */
312324
switch (ctrl.len) {
313325
case LOONGARCH_BREAKPOINT_LEN_1:
@@ -386,21 +398,17 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
386398
struct arch_hw_breakpoint *hw)
387399
{
388400
int ret;
389-
u64 alignment_mask, offset;
401+
u64 alignment_mask;
390402

391403
/* Build the arch_hw_breakpoint. */
392404
ret = arch_build_bp_info(bp, attr, hw);
393405
if (ret)
394406
return ret;
395407

396-
if (hw->ctrl.type != LOONGARCH_BREAKPOINT_EXECUTE)
397-
alignment_mask = 0x7;
398-
else
408+
if (hw->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
399409
alignment_mask = 0x3;
400-
offset = hw->address & alignment_mask;
401-
402-
hw->address &= ~alignment_mask;
403-
hw->ctrl.len <<= offset;
410+
hw->address &= ~alignment_mask;
411+
}
404412

405413
return 0;
406414
}
@@ -471,12 +479,15 @@ void breakpoint_handler(struct pt_regs *regs)
471479
slots = this_cpu_ptr(bp_on_reg);
472480

473481
for (i = 0; i < boot_cpu_data.watch_ireg_count; ++i) {
474-
bp = slots[i];
475-
if (bp == NULL)
476-
continue;
477-
perf_bp_event(bp, regs);
482+
if ((csr_read32(LOONGARCH_CSR_FWPS) & (0x1 << i))) {
483+
bp = slots[i];
484+
if (bp == NULL)
485+
continue;
486+
perf_bp_event(bp, regs);
487+
csr_write32(0x1 << i, LOONGARCH_CSR_FWPS);
488+
update_bp_registers(regs, 0, 0);
489+
}
478490
}
479-
update_bp_registers(regs, 0, 0);
480491
}
481492
NOKPROBE_SYMBOL(breakpoint_handler);
482493

@@ -488,12 +499,15 @@ void watchpoint_handler(struct pt_regs *regs)
488499
slots = this_cpu_ptr(wp_on_reg);
489500

490501
for (i = 0; i < boot_cpu_data.watch_dreg_count; ++i) {
491-
wp = slots[i];
492-
if (wp == NULL)
493-
continue;
494-
perf_bp_event(wp, regs);
502+
if ((csr_read32(LOONGARCH_CSR_MWPS) & (0x1 << i))) {
503+
wp = slots[i];
504+
if (wp == NULL)
505+
continue;
506+
perf_bp_event(wp, regs);
507+
csr_write32(0x1 << i, LOONGARCH_CSR_MWPS);
508+
update_bp_registers(regs, 0, 1);
509+
}
495510
}
496-
update_bp_registers(regs, 0, 1);
497511
}
498512
NOKPROBE_SYMBOL(watchpoint_handler);
499513

arch/loongarch/kernel/ptrace.c

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -494,28 +494,14 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
494494
struct arch_hw_breakpoint_ctrl ctrl,
495495
struct perf_event_attr *attr)
496496
{
497-
int err, len, type, offset;
497+
int err, len, type;
498498

499-
err = arch_bp_generic_fields(ctrl, &len, &type, &offset);
499+
err = arch_bp_generic_fields(ctrl, &len, &type);
500500
if (err)
501501
return err;
502502

503-
switch (note_type) {
504-
case NT_LOONGARCH_HW_BREAK:
505-
if ((type & HW_BREAKPOINT_X) != type)
506-
return -EINVAL;
507-
break;
508-
case NT_LOONGARCH_HW_WATCH:
509-
if ((type & HW_BREAKPOINT_RW) != type)
510-
return -EINVAL;
511-
break;
512-
default:
513-
return -EINVAL;
514-
}
515-
516503
attr->bp_len = len;
517504
attr->bp_type = type;
518-
attr->bp_addr += offset;
519505

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

611597
attr = bp->attr;
612-
decode_ctrl_reg(uctrl, &ctrl);
613-
err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
614-
if (err)
615-
return err;
598+
599+
switch (note_type) {
600+
case NT_LOONGARCH_HW_BREAK:
601+
ctrl.type = LOONGARCH_BREAKPOINT_EXECUTE;
602+
ctrl.len = LOONGARCH_BREAKPOINT_LEN_4;
603+
break;
604+
case NT_LOONGARCH_HW_WATCH:
605+
decode_ctrl_reg(uctrl, &ctrl);
606+
break;
607+
default:
608+
return -EINVAL;
609+
}
610+
611+
if (uctrl & CTRL_PLV_ENABLE) {
612+
err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
613+
if (err)
614+
return err;
615+
attr.disabled = 0;
616+
} else {
617+
attr.disabled = 1;
618+
}
616619

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

649+
/* Kernel-space address cannot be monitored by user-space */
650+
if ((unsigned long)addr >= XKPRANGE)
651+
return -EINVAL;
652+
646653
bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
647654
if (IS_ERR(bp))
648655
return PTR_ERR(bp);

arch/loongarch/kvm/exit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ static void kvm_handle_service(struct kvm_vcpu *vcpu)
761761
default:
762762
ret = KVM_HCALL_INVALID_CODE;
763763
break;
764-
};
764+
}
765765

766766
kvm_write_reg(vcpu, LOONGARCH_GPR_A0, ret);
767767
}

0 commit comments

Comments
 (0)