@@ -174,11 +174,21 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
174174static 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 */
285302int 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}
481492NOKPROBE_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}
498512NOKPROBE_SYMBOL (watchpoint_handler );
499513
0 commit comments