@@ -529,6 +529,8 @@ static void riscv_deinit_target(struct target *target)
529529 if (!info )
530530 return ;
531531
532+ free (info -> reserved_triggers );
533+
532534 range_list_t * entry , * tmp ;
533535 list_for_each_entry_safe (entry , tmp , & info -> hide_csr , list ) {
534536 free (entry -> name );
@@ -622,6 +624,15 @@ static int find_first_trigger_by_id(struct target *target, int unique_id)
622624static int set_trigger (struct target * target , unsigned int idx , riscv_reg_t tdata1 , riscv_reg_t tdata2 ,
623625 riscv_reg_t tdata1_ignore_mask )
624626{
627+ RISCV_INFO (r );
628+ assert (r -> reserved_triggers );
629+ assert (idx < r -> trigger_count );
630+ if (r -> reserved_triggers [idx ]) {
631+ LOG_TARGET_DEBUG (target ,
632+ "Trigger %u is reserved by 'reserve_trigger' command." , idx );
633+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE ;
634+ }
635+
625636 riscv_reg_t tdata1_rb , tdata2_rb ;
626637 // Select which trigger to use
627638 if (riscv_reg_set (target , GDB_REGNO_TSELECT , idx ) != ERROR_OK )
@@ -2455,87 +2466,48 @@ static int riscv_deassert_reset(struct target *target)
24552466 return tt -> deassert_reset (target );
24562467}
24572468
2458- /* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */
2459- static int disable_triggers (struct target * target , riscv_reg_t * state )
2469+ /* "wp_is_set" array must have at least "r->trigger_count" items. */
2470+ static int disable_watchpoints (struct target * target , bool * wp_is_set )
24602471{
24612472 RISCV_INFO (r );
2462-
24632473 LOG_TARGET_DEBUG (target , "Disabling triggers." );
24642474
2465- if ( riscv_enumerate_triggers ( target ) != ERROR_OK )
2466- return ERROR_FAIL ;
2467-
2468- if ( r -> manual_hwbp_set ) {
2469- /* Look at every trigger that may have been set. */
2470- riscv_reg_t tselect ;
2471- if ( riscv_reg_get ( target , & tselect , GDB_REGNO_TSELECT ) != ERROR_OK )
2472- return ERROR_FAIL ;
2473- for ( unsigned int t = 0 ; t < r -> trigger_count ; t ++ ) {
2474- if ( riscv_reg_set ( target , GDB_REGNO_TSELECT , t ) != ERROR_OK )
2475- return ERROR_FAIL ;
2476- riscv_reg_t tdata1 ;
2477- if (riscv_reg_get (target , & tdata1 , GDB_REGNO_TDATA1 ) != ERROR_OK )
2475+ /* TODO: The algorithm is flawed and may result in a situation described in
2476+ * https://github.com/riscv-collab/riscv-openocd/issues/1108
2477+ */
2478+ memset ( wp_is_set , false, r -> trigger_count );
2479+ struct watchpoint * watchpoint = target -> watchpoints ;
2480+ int i = 0 ;
2481+ while ( watchpoint ) {
2482+ LOG_TARGET_DEBUG ( target , "Watchpoint %" PRIu32 ": set=%s" ,
2483+ watchpoint -> unique_id ,
2484+ wp_is_set [ i ] ? "true" : "false" );
2485+ wp_is_set [ i ] = watchpoint -> is_set ;
2486+ if ( watchpoint -> is_set ) {
2487+ if (riscv_remove_watchpoint (target , watchpoint ) != ERROR_OK )
24782488 return ERROR_FAIL ;
2479- if (tdata1 & CSR_TDATA1_DMODE (riscv_xlen (target ))) {
2480- state [t ] = tdata1 ;
2481- if (riscv_reg_set (target , GDB_REGNO_TDATA1 , 0 ) != ERROR_OK )
2482- return ERROR_FAIL ;
2483- }
2484- }
2485- if (riscv_reg_set (target , GDB_REGNO_TSELECT , tselect ) != ERROR_OK )
2486- return ERROR_FAIL ;
2487-
2488- } else {
2489- /* Just go through the triggers we manage. */
2490- struct watchpoint * watchpoint = target -> watchpoints ;
2491- int i = 0 ;
2492- while (watchpoint ) {
2493- LOG_TARGET_DEBUG (target , "Watchpoint %d: set=%d" , i , watchpoint -> is_set );
2494- state [i ] = watchpoint -> is_set ;
2495- if (watchpoint -> is_set ) {
2496- if (riscv_remove_watchpoint (target , watchpoint ) != ERROR_OK )
2497- return ERROR_FAIL ;
2498- }
2499- watchpoint = watchpoint -> next ;
2500- i ++ ;
25012489 }
2490+ watchpoint = watchpoint -> next ;
2491+ i ++ ;
25022492 }
25032493
25042494 return ERROR_OK ;
25052495}
25062496
2507- static int enable_triggers (struct target * target , riscv_reg_t * state )
2497+ static int enable_watchpoints (struct target * target , bool * wp_is_set )
25082498{
2509- RISCV_INFO (r );
2510-
2511- if (r -> manual_hwbp_set ) {
2512- /* Look at every trigger that may have been set. */
2513- riscv_reg_t tselect ;
2514- if (riscv_reg_get (target , & tselect , GDB_REGNO_TSELECT ) != ERROR_OK )
2515- return ERROR_FAIL ;
2516- for (unsigned int t = 0 ; t < r -> trigger_count ; t ++ ) {
2517- if (state [t ] != 0 ) {
2518- if (riscv_reg_set (target , GDB_REGNO_TSELECT , t ) != ERROR_OK )
2519- return ERROR_FAIL ;
2520- if (riscv_reg_set (target , GDB_REGNO_TDATA1 , state [t ]) != ERROR_OK )
2521- return ERROR_FAIL ;
2522- }
2523- }
2524- if (riscv_reg_set (target , GDB_REGNO_TSELECT , tselect ) != ERROR_OK )
2525- return ERROR_FAIL ;
2526-
2527- } else {
2528- struct watchpoint * watchpoint = target -> watchpoints ;
2529- int i = 0 ;
2530- while (watchpoint ) {
2531- LOG_TARGET_DEBUG (target , "Watchpoint %d: cleared=%" PRId64 , i , state [i ]);
2532- if (state [i ]) {
2533- if (riscv_add_watchpoint (target , watchpoint ) != ERROR_OK )
2534- return ERROR_FAIL ;
2535- }
2536- watchpoint = watchpoint -> next ;
2537- i ++ ;
2499+ struct watchpoint * watchpoint = target -> watchpoints ;
2500+ int i = 0 ;
2501+ while (watchpoint ) {
2502+ LOG_TARGET_DEBUG (target , "Watchpoint %" PRIu32
2503+ ": %s to be re-enabled." , watchpoint -> unique_id ,
2504+ wp_is_set [i ] ? "needs " : "does not need" );
2505+ if (wp_is_set [i ]) {
2506+ if (riscv_add_watchpoint (target , watchpoint ) != ERROR_OK )
2507+ return ERROR_FAIL ;
25382508 }
2509+ watchpoint = watchpoint -> next ;
2510+ i ++ ;
25392511 }
25402512
25412513 return ERROR_OK ;
@@ -3783,10 +3755,17 @@ static int riscv_openocd_step_impl(struct target *target, int current,
37833755 return ERROR_FAIL ;
37843756 }
37853757
3786- riscv_reg_t trigger_state [RISCV_MAX_HWBPS ] = {0 };
3787- if (disable_triggers (target , trigger_state ) != ERROR_OK )
3758+ if (riscv_enumerate_triggers (target ) != ERROR_OK )
37883759 return ERROR_FAIL ;
37893760
3761+ RISCV_INFO (r );
3762+ bool * wps_to_enable = calloc (sizeof (* wps_to_enable ), r -> trigger_count );
3763+ if (disable_watchpoints (target , wps_to_enable ) != ERROR_OK ) {
3764+ LOG_TARGET_ERROR (target , "Failed to temporarily disable "
3765+ "watchpoints before single-step." );
3766+ return ERROR_FAIL ;
3767+ }
3768+
37903769 bool success = true;
37913770 uint64_t current_mstatus ;
37923771 RISCV_INFO (info );
@@ -3816,9 +3795,10 @@ static int riscv_openocd_step_impl(struct target *target, int current,
38163795 }
38173796
38183797_exit :
3819- if (enable_triggers (target , trigger_state ) != ERROR_OK ) {
3798+ if (enable_watchpoints (target , wps_to_enable ) != ERROR_OK ) {
38203799 success = false;
3821- LOG_TARGET_ERROR (target , "Unable to enable triggers." );
3800+ LOG_TARGET_ERROR (target , "Failed to re-enable watchpoints "
3801+ "after single-step." );
38223802 }
38233803
38243804 if (breakpoint && (riscv_add_breakpoint (target , breakpoint ) != ERROR_OK )) {
@@ -5038,6 +5018,57 @@ COMMAND_HANDLER(riscv_set_enable_trigger_feature)
50385018 return ERROR_OK ;
50395019}
50405020
5021+ static COMMAND_HELPER (report_reserved_triggers , struct target * target )
5022+ {
5023+ RISCV_INFO (r );
5024+ if (riscv_enumerate_triggers (target ) != ERROR_OK )
5025+ return ERROR_FAIL ;
5026+ const char * separator = "" ;
5027+ for (riscv_reg_t t = 0 ; t < r -> trigger_count ; ++ t ) {
5028+ if (r -> reserved_triggers [t ]) {
5029+ command_print_sameline (CMD , "%s%" PRIu64 , separator , t );
5030+ separator = " " ;
5031+ }
5032+ }
5033+ command_print_sameline (CMD , "\n" );
5034+ return ERROR_OK ;
5035+ }
5036+
5037+ COMMAND_HANDLER (handle_reserve_trigger )
5038+ {
5039+ struct target * target = get_current_target (CMD_CTX );
5040+ if (CMD_ARGC == 0 )
5041+ return CALL_COMMAND_HANDLER (report_reserved_triggers , target );
5042+
5043+ if (CMD_ARGC != 2 )
5044+ return ERROR_COMMAND_SYNTAX_ERROR ;
5045+
5046+ riscv_reg_t t ;
5047+ COMMAND_PARSE_NUMBER (u64 , CMD_ARGV [0 ], t );
5048+
5049+ if (riscv_enumerate_triggers (target ) != ERROR_OK )
5050+ return ERROR_FAIL ;
5051+ RISCV_INFO (r );
5052+ if (r -> trigger_count == 0 ) {
5053+ command_print (CMD , "Error: There are no triggers on the target." );
5054+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE ;
5055+ }
5056+ if (t >= r -> trigger_count ) {
5057+ command_print (CMD , "Error: trigger with index %" PRIu64
5058+ " does not exist. There are only %u triggers"
5059+ " on the target (with indexes 0 .. %u)." ,
5060+ t , r -> trigger_count , r -> trigger_count - 1 );
5061+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE ;
5062+ }
5063+ if (r -> trigger_unique_id [t ] != -1 ) {
5064+ command_print (CMD , "Error: trigger with index %" PRIu64
5065+ " is already in use and can not be reserved." , t );
5066+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE ;
5067+ }
5068+ COMMAND_PARSE_ON_OFF (CMD_ARGV [1 ], r -> reserved_triggers [t ]);
5069+ return ERROR_OK ;
5070+ }
5071+
50415072static const struct command_registration riscv_exec_command_handlers [] = {
50425073 {
50435074 .name = "dump_sample_buf" ,
@@ -5290,6 +5321,14 @@ static const struct command_registration riscv_exec_command_handlers[] = {
52905321 .usage = "[('eq'|'napot'|'ge_lt'|'all') ('wp'|'none')]" ,
52915322 .help = "Control whether OpenOCD is allowed to use certain RISC-V trigger features for watchpoints."
52925323 },
5324+ {
5325+ .name = "reserve_trigger" ,
5326+ .handler = handle_reserve_trigger ,
5327+ /* TODO: Move this to COMMAND_ANY */
5328+ .mode = COMMAND_EXEC ,
5329+ .usage = "[index ('on'|'off')]" ,
5330+ .help = "Controls which RISC-V triggers shall not be touched by OpenOCD." ,
5331+ },
52935332 COMMAND_REGISTRATION_DONE
52945333};
52955334
@@ -5714,6 +5753,8 @@ int riscv_enumerate_triggers(struct target *target)
57145753 "Assuming that triggers are not implemented." );
57155754 r -> triggers_enumerated = true;
57165755 r -> trigger_count = 0 ;
5756+ free (r -> reserved_triggers );
5757+ r -> reserved_triggers = NULL ;
57175758 return ERROR_OK ;
57185759 }
57195760
@@ -5748,6 +5789,8 @@ int riscv_enumerate_triggers(struct target *target)
57485789 r -> triggers_enumerated = true;
57495790 r -> trigger_count = t ;
57505791 LOG_TARGET_INFO (target , "Found %d triggers" , r -> trigger_count );
5792+ free (r -> reserved_triggers );
5793+ r -> reserved_triggers = calloc (sizeof (* r -> reserved_triggers ), t );
57515794 create_wp_trigger_cache (target );
57525795 return ERROR_OK ;
57535796}
0 commit comments