@@ -174,11 +174,21 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
174
174
static int hw_breakpoint_control (struct perf_event * bp ,
175
175
enum hw_breakpoint_ops ops )
176
176
{
177
- u32 ctrl ;
177
+ u32 ctrl , privilege ;
178
178
int i , max_slots , enable ;
179
+ struct pt_regs * regs ;
179
180
struct perf_event * * slots ;
180
181
struct arch_hw_breakpoint * info = counter_arch_bp (bp );
181
182
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
+
182
192
if (info -> ctrl .type == LOONGARCH_BREAKPOINT_EXECUTE ) {
183
193
/* Breakpoint */
184
194
slots = this_cpu_ptr (bp_on_reg );
@@ -197,31 +207,38 @@ static int hw_breakpoint_control(struct perf_event *bp,
197
207
switch (ops ) {
198
208
case HW_BREAKPOINT_INSTALL :
199
209
/* 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 );
206
210
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 );
208
215
} 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 );
209
219
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 );
211
221
}
212
222
enable = csr_read64 (LOONGARCH_CSR_CRMD );
213
223
csr_write64 (CSR_CRMD_WE | enable , LOONGARCH_CSR_CRMD );
224
+ if (bp -> hw .target )
225
+ regs -> csr_prmd |= CSR_PRMD_PWE ;
214
226
break ;
215
227
case HW_BREAKPOINT_UNINSTALL :
216
228
/* 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 ;
225
242
break ;
226
243
}
227
244
@@ -283,7 +300,7 @@ int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
283
300
* to generic breakpoint descriptions.
284
301
*/
285
302
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 )
287
304
{
288
305
/* Type */
289
306
switch (ctrl .type ) {
@@ -303,11 +320,6 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
303
320
return - EINVAL ;
304
321
}
305
322
306
- if (!ctrl .len )
307
- return - EINVAL ;
308
-
309
- * offset = __ffs (ctrl .len );
310
-
311
323
/* Len */
312
324
switch (ctrl .len ) {
313
325
case LOONGARCH_BREAKPOINT_LEN_1 :
@@ -386,21 +398,17 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
386
398
struct arch_hw_breakpoint * hw )
387
399
{
388
400
int ret ;
389
- u64 alignment_mask , offset ;
401
+ u64 alignment_mask ;
390
402
391
403
/* Build the arch_hw_breakpoint. */
392
404
ret = arch_build_bp_info (bp , attr , hw );
393
405
if (ret )
394
406
return ret ;
395
407
396
- if (hw -> ctrl .type != LOONGARCH_BREAKPOINT_EXECUTE )
397
- alignment_mask = 0x7 ;
398
- else
408
+ if (hw -> ctrl .type == LOONGARCH_BREAKPOINT_EXECUTE ) {
399
409
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
+ }
404
412
405
413
return 0 ;
406
414
}
@@ -471,12 +479,15 @@ void breakpoint_handler(struct pt_regs *regs)
471
479
slots = this_cpu_ptr (bp_on_reg );
472
480
473
481
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
+ }
478
490
}
479
- update_bp_registers (regs , 0 , 0 );
480
491
}
481
492
NOKPROBE_SYMBOL (breakpoint_handler );
482
493
@@ -488,12 +499,15 @@ void watchpoint_handler(struct pt_regs *regs)
488
499
slots = this_cpu_ptr (wp_on_reg );
489
500
490
501
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
+ }
495
510
}
496
- update_bp_registers (regs , 0 , 1 );
497
511
}
498
512
NOKPROBE_SYMBOL (watchpoint_handler );
499
513
0 commit comments