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:
parent
64f3f8877e
commit
87c0cda00f
|
@ -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.
|
||||
|
|
|
@ -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, ¤t_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,
|
||||
¤t_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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue