riscv: implement maskisr steponly command (#681)

* riscv: implement maskisr steponly command

Change-Id: I1a3b666d466b064460c3acc307a36485ce165601
Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com>

* riscv: restore triggers and irq mask inside step function

Change-Id: I4e1b0665f4f2f75e42a6191c61634bdfa19ae2fb
Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com>

* doc: update for riscv set_maskisr command

Change-Id: Ia7d3a6df846cfc4568d79558f719e93f038aee9b
Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com>
This commit is contained in:
Erhan Kurubas 2022-03-01 19:05:54 +01:00 committed by GitHub
parent 64f3f8877e
commit 87c0cda00f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 140 additions and 32 deletions

View File

@ -10424,6 +10424,13 @@ tunneled DR scan consists of:
@end deffn
@deffn {Command} {riscv set_maskisr} [@option{off}|@option{steponly}]
Selects whether interrupts will be disabled when single stepping. The default configuration is @option{off}.
This feature is only useful on hardware that always steps into interrupts and doesn't support dcsr.stepie=0.
Keep in mind, disabling the option does not guarantee that single stepping will go into interrupt handlers.
To make that happen, dcsr.stepie would have to be written to 1 as well.
@end deffn
@deffn {Command} {riscv set_ebreakm} on|off
Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.

View File

@ -1953,26 +1953,11 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
}
}
/* Disable Interrupts before attempting to run the algorithm. */
uint64_t current_mstatus;
uint8_t mstatus_bytes[8] = { 0 };
LOG_DEBUG("Disabling Interrupts");
struct reg *reg_mstatus = register_get_by_name(target->reg_cache,
"mstatus", true);
if (!reg_mstatus) {
LOG_ERROR("Couldn't find mstatus!");
uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE;
if (riscv_interrupts_disable(target, irq_disabled_mask, &current_mstatus) != ERROR_OK)
return ERROR_FAIL;
}
reg_mstatus->type->get(reg_mstatus);
current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size);
uint64_t ie_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE;
buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus,
ie_mask, 0));
reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
/* Run algorithm */
LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
@ -2028,9 +2013,8 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
}
/* Restore Interrupts */
LOG_DEBUG("Restoring Interrupts");
buf_set_u64(mstatus_bytes, 0, info->xlen, current_mstatus);
reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK)
return ERROR_FAIL;
/* Restore registers */
uint8_t buf[8] = { 0 };
@ -2366,7 +2350,7 @@ int riscv_openocd_poll(struct target *target)
}
int riscv_openocd_step(struct target *target, int current,
target_addr_t address, int handle_breakpoints)
target_addr_t address, int handle_breakpoints)
{
LOG_DEBUG("stepping rtos hart");
@ -2377,23 +2361,48 @@ int riscv_openocd_step(struct target *target, int current,
if (disable_triggers(target, trigger_state) != ERROR_OK)
return ERROR_FAIL;
int out = riscv_step_rtos_hart(target);
if (out != ERROR_OK) {
bool success = true;
uint64_t current_mstatus;
RISCV_INFO(info);
if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) {
/* Disable Interrupts before stepping. */
uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE;
if (riscv_interrupts_disable(target, irq_disabled_mask,
&current_mstatus) != ERROR_OK) {
success = false;
LOG_ERROR("unable to disable interrupts");
goto _exit;
}
}
if (riscv_step_rtos_hart(target) != ERROR_OK) {
success = false;
LOG_ERROR("unable to step rtos hart");
return out;
}
register_cache_invalidate(target->reg_cache);
if (enable_triggers(target, trigger_state) != ERROR_OK)
return ERROR_FAIL;
if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY)
if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) {
success = false;
LOG_ERROR("unable to restore interrupts");
}
target->state = TARGET_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
target->state = TARGET_HALTED;
target->debug_reason = DBG_REASON_SINGLESTEP;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
return out;
_exit:
if (enable_triggers(target, trigger_state) != ERROR_OK) {
success = false;
LOG_ERROR("unable to enable triggers");
}
if (success) {
target->state = TARGET_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
target->state = TARGET_HALTED;
target->debug_reason = DBG_REASON_SINGLESTEP;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
return success ? ERROR_OK : ERROR_FAIL;
}
/* Command Handlers */
@ -2936,6 +2945,31 @@ COMMAND_HANDLER(riscv_use_bscan_tunnel)
return ERROR_OK;
}
COMMAND_HANDLER(riscv_set_maskisr)
{
struct target *target = get_current_target(CMD_CTX);
RISCV_INFO(info);
static const struct jim_nvp nvp_maskisr_modes[] = {
{ .name = "off", .value = RISCV_ISRMASK_OFF },
{ .name = "steponly", .value = RISCV_ISRMASK_STEPONLY },
{ .name = NULL, .value = -1 },
};
const struct jim_nvp *n;
if (CMD_ARGC > 0) {
n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
if (!n->name)
return ERROR_COMMAND_SYNTAX_ERROR;
info->isrmask_mode = n->value;
} else {
n = jim_nvp_value2name_simple(nvp_maskisr_modes, info->isrmask_mode);
command_print(CMD, "riscv interrupt mask %s", n->name);
}
return ERROR_OK;
}
COMMAND_HANDLER(riscv_set_enable_virt2phys)
{
if (CMD_ARGC != 1) {
@ -3345,6 +3379,13 @@ static const struct command_registration riscv_exec_command_handlers[] = {
"(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , "
"1: DATA_REGISTER}"
},
{
.name = "set_maskisr",
.handler = riscv_set_maskisr,
.mode = COMMAND_EXEC,
.help = "mask riscv interrupts",
.usage = "['off'|'steponly']",
},
{
.name = "set_enable_virt2phys",
.handler = riscv_set_enable_virt2phys,
@ -3489,6 +3530,8 @@ void riscv_info_init(struct target *target, riscv_info_t *r)
r->xlen = -1;
r->isrmask_mode = RISCV_ISRMASK_OFF;
r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF;
r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS;
r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT;
@ -3520,6 +3563,52 @@ static int riscv_resume_go_all_harts(struct target *target)
return ERROR_OK;
}
int riscv_interrupts_disable(struct target *target, uint64_t irq_mask, uint64_t *old_mstatus)
{
LOG_DEBUG("Disabling Interrupts");
struct reg *reg_mstatus = register_get_by_name(target->reg_cache,
"mstatus", true);
if (!reg_mstatus) {
LOG_ERROR("Couldn't find mstatus!");
return ERROR_FAIL;
}
int retval = reg_mstatus->type->get(reg_mstatus);
if (retval != ERROR_OK)
return retval;
RISCV_INFO(info);
uint8_t mstatus_bytes[8] = { 0 };
uint64_t current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size);
buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus,
irq_mask, 0));
retval = reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
if (retval != ERROR_OK)
return retval;
if (old_mstatus)
*old_mstatus = current_mstatus;
return ERROR_OK;
}
int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus)
{
LOG_DEBUG("Restore Interrupts");
struct reg *reg_mstatus = register_get_by_name(target->reg_cache,
"mstatus", true);
if (!reg_mstatus) {
LOG_ERROR("Couldn't find mstatus!");
return ERROR_FAIL;
}
RISCV_INFO(info);
uint8_t mstatus_bytes[8];
buf_set_u64(mstatus_bytes, 0, info->xlen, old_mstatus);
return reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
}
int riscv_step_rtos_hart(struct target *target)
{
RISCV_INFO(r);

View File

@ -56,6 +56,13 @@ enum riscv_halt_reason {
RISCV_HALT_ERROR
};
enum riscv_isrmasking_mode {
/* RISCV_ISRMASK_AUTO, */ /* not supported yet */
RISCV_ISRMASK_OFF,
/* RISCV_ISRMASK_ON, */ /* not supported yet */
RISCV_ISRMASK_STEPONLY,
};
typedef struct {
struct target *target;
unsigned custom_number;
@ -135,6 +142,8 @@ typedef struct {
/* This target was selected using hasel. */
bool selected;
enum riscv_isrmasking_mode isrmask_mode;
/* Helper functions that target the various RISC-V debug spec
* implementations. */
int (*get_register)(struct target *target, riscv_reg_t *value, int regid);
@ -403,4 +412,7 @@ void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *fie
int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer);
int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer);
int riscv_interrupts_disable(struct target *target, uint64_t ie_mask, uint64_t *old_mstatus);
int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus);
#endif