target/riscv: restrict BSCAN-related commands to before-`init`

Logically, BSCAN tunneling is used to establish a connection, therefore
it should be set up before the communication starts (i.e. before
`init`).

Moreover, current implementation does not support changing
`bscan_tunnel_ir_width` after `init`. This is evident by RISC-V handler
of the `init` itself.
Link: 9a23c9e679/src/target/riscv/riscv.c (L467-L481)

Change-Id: I817c6a996f7f7171b2286e181daf1092bd358f69
Signed-off-by: Evgeniy Naydanov <evgeniy.naydanov@syntacore.com>
This commit is contained in:
Evgeniy Naydanov 2024-08-12 21:20:41 +03:00
parent 9a23c9e679
commit 342f294031
3 changed files with 36 additions and 32 deletions

View File

@ -11354,10 +11354,15 @@ Display/set the current core displayed in GDB. This is needed only if
@code{riscv smp} was used. @code{riscv smp} was used.
@end deffn @end deffn
@deffn {Command} {riscv use_bscan_tunnel} value @deffn {Command} {riscv use_bscan_tunnel} width [type]
Enable or disable use of a BSCAN tunnel to reach the Debug Module. Supply the Enable or disable use of a BSCAN tunnel to reach the Debug Module. Supply the
width of the DM transport TAP's instruction register to enable. Supply a @var{width} of the DM transport TAP's instruction register to enable. The
value of 0 to disable. @var{width} should fit into 7 bits. Supply a value of 0 to disable.
Pass a second argument (optional) to indicate Bscan Tunnel Type:
@enumerate
@item 0:(default) NESTED_TAP
@item 1: DATA_REGISTER
@end enumerate
This BSCAN tunnel interface is specific to SiFive IP. Anybody may implement This BSCAN tunnel interface is specific to SiFive IP. Anybody may implement
it, but currently there is no good documentation on it. In a nutshell, this it, but currently there is no good documentation on it. In a nutshell, this

View File

@ -54,7 +54,8 @@ struct scan_field select_idcode = {
}; };
static bscan_tunnel_type_t bscan_tunnel_type; static bscan_tunnel_type_t bscan_tunnel_type;
int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ #define BSCAN_TUNNEL_IR_WIDTH_NBITS 7
uint8_t bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */
static int bscan_tunnel_ir_id; /* IR ID of the JTAG TAP to access the tunnel. Valid when not 0 */ static int bscan_tunnel_ir_id; /* IR ID of the JTAG TAP to access the tunnel. Valid when not 0 */
static const uint8_t bscan_zero[4] = {0}; static const uint8_t bscan_zero[4] = {0};
@ -67,7 +68,6 @@ static struct scan_field select_user4 = {
}; };
static uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */
static struct scan_field _bscan_tunnel_data_register_select_dmi[] = { static struct scan_field _bscan_tunnel_data_register_select_dmi[] = {
{ {
.num_bits = 3, .num_bits = 3,
@ -80,8 +80,8 @@ static struct scan_field _bscan_tunnel_data_register_select_dmi[] = {
.in_value = NULL, .in_value = NULL,
}, },
{ {
.num_bits = 7, .num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS,
.out_value = bscan_tunneled_ir_width, .out_value = &bscan_tunnel_ir_width,
.in_value = NULL, .in_value = NULL,
}, },
{ {
@ -98,8 +98,8 @@ static struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = {
.in_value = NULL, .in_value = NULL,
}, },
{ {
.num_bits = 7, .num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS,
.out_value = bscan_tunneled_ir_width, .out_value = &bscan_tunnel_ir_width,
.in_value = NULL, .in_value = NULL,
}, },
{ {
@ -300,7 +300,6 @@ void select_dmi_via_bscan(struct target *target)
int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr) int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr)
{ {
/* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */ /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */
uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width};
uint8_t tunneled_dr_width[4] = {32}; uint8_t tunneled_dr_width[4] = {32};
uint8_t out_value[5] = {0}; uint8_t out_value[5] = {0};
uint8_t in_value[5] = {0}; uint8_t in_value[5] = {0};
@ -316,8 +315,8 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_
tunneled_ir[1].num_bits = bscan_tunnel_ir_width; tunneled_ir[1].num_bits = bscan_tunnel_ir_width;
tunneled_ir[1].out_value = ir_dtmcontrol; tunneled_ir[1].out_value = ir_dtmcontrol;
tunneled_ir[1].in_value = NULL; tunneled_ir[1].in_value = NULL;
tunneled_ir[2].num_bits = 7; tunneled_ir[2].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS;
tunneled_ir[2].out_value = tunneled_ir_width; tunneled_ir[2].out_value = &bscan_tunnel_ir_width;
tunneled_ir[2].in_value = NULL; tunneled_ir[2].in_value = NULL;
tunneled_ir[3].num_bits = 1; tunneled_ir[3].num_bits = 1;
tunneled_ir[3].out_value = bscan_zero; tunneled_ir[3].out_value = bscan_zero;
@ -329,7 +328,7 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_
tunneled_dr[1].num_bits = 32 + 1; tunneled_dr[1].num_bits = 32 + 1;
tunneled_dr[1].out_value = out_value; tunneled_dr[1].out_value = out_value;
tunneled_dr[1].in_value = in_value; tunneled_dr[1].in_value = in_value;
tunneled_dr[2].num_bits = 7; tunneled_dr[2].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS;
tunneled_dr[2].out_value = tunneled_dr_width; tunneled_dr[2].out_value = tunneled_dr_width;
tunneled_dr[2].in_value = NULL; tunneled_dr[2].in_value = NULL;
tunneled_dr[3].num_bits = 1; tunneled_dr[3].num_bits = 1;
@ -343,8 +342,8 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_
tunneled_ir[2].num_bits = bscan_tunnel_ir_width; tunneled_ir[2].num_bits = bscan_tunnel_ir_width;
tunneled_ir[2].out_value = ir_dtmcontrol; tunneled_ir[2].out_value = ir_dtmcontrol;
tunneled_ir[1].in_value = NULL; tunneled_ir[1].in_value = NULL;
tunneled_ir[1].num_bits = 7; tunneled_ir[1].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS;
tunneled_ir[1].out_value = tunneled_ir_width; tunneled_ir[1].out_value = &bscan_tunnel_ir_width;
tunneled_ir[2].in_value = NULL; tunneled_ir[2].in_value = NULL;
tunneled_ir[0].num_bits = 1; tunneled_ir[0].num_bits = 1;
tunneled_ir[0].out_value = bscan_zero; tunneled_ir[0].out_value = bscan_zero;
@ -473,7 +472,6 @@ static int riscv_init_target(struct command_context *cmd_ctx,
} }
h_u32_to_le(ir_user4, ir_user4_raw); h_u32_to_le(ir_user4, ir_user4_raw);
select_user4.num_bits = target->tap->ir_length; select_user4.num_bits = target->tap->ir_length;
bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width;
if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width; bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width;
else /* BSCAN_TUNNEL_NESTED_TAP */ else /* BSCAN_TUNNEL_NESTED_TAP */
@ -4382,18 +4380,23 @@ COMMAND_HANDLER(riscv_resume_order)
COMMAND_HANDLER(riscv_use_bscan_tunnel) COMMAND_HANDLER(riscv_use_bscan_tunnel)
{ {
int irwidth = 0; uint8_t irwidth = 0;
int tunnel_type = BSCAN_TUNNEL_NESTED_TAP; int tunnel_type = BSCAN_TUNNEL_NESTED_TAP;
if (CMD_ARGC > 2) { if (CMD_ARGC < 1 || CMD_ARGC > 2)
LOG_ERROR("Command takes at most two arguments");
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
} else if (CMD_ARGC == 1) {
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); if (CMD_ARGC >= 1) {
} else if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], irwidth);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); assert(BSCAN_TUNNEL_IR_WIDTH_NBITS < 8);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type); if (irwidth >= (uint8_t)1 << BSCAN_TUNNEL_IR_WIDTH_NBITS) {
command_print(CMD, "'value' does not fit into %d bits.",
BSCAN_TUNNEL_IR_WIDTH_NBITS);
return ERROR_COMMAND_ARGUMENT_OVERFLOW;
}
} }
if (CMD_ARGC == 2)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type);
if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP) if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP)
LOG_INFO("Nested Tap based Bscan Tunnel Selected"); LOG_INFO("Nested Tap based Bscan Tunnel Selected");
else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
@ -5195,18 +5198,14 @@ static const struct command_registration riscv_exec_command_handlers[] = {
{ {
.name = "use_bscan_tunnel", .name = "use_bscan_tunnel",
.handler = riscv_use_bscan_tunnel, .handler = riscv_use_bscan_tunnel,
.mode = COMMAND_ANY, .mode = COMMAND_CONFIG,
.usage = "value [type]", .usage = "value [type]",
.help = "Enable or disable use of a BSCAN tunnel to reach DM. Supply " .help = "Enable or disable use of a BSCAN tunnel to reach DM."
"the width of the DM transport TAP's instruction register to "
"enable. Supply a value of 0 to disable. Pass A second argument "
"(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , "
"1: DATA_REGISTER}"
}, },
{ {
.name = "set_bscan_tunnel_ir", .name = "set_bscan_tunnel_ir",
.handler = riscv_set_bscan_tunnel_ir, .handler = riscv_set_bscan_tunnel_ir,
.mode = COMMAND_ANY, .mode = COMMAND_CONFIG,
.usage = "value", .usage = "value",
.help = "Specify the JTAG TAP IR used to access the bscan tunnel. " .help = "Specify the JTAG TAP IR used to access the bscan tunnel. "
"By default it is 0x23 << (ir_length - 6), which map some " "By default it is 0x23 << (ir_length - 6), which map some "

View File

@ -365,7 +365,7 @@ extern struct scan_field select_idcode;
extern struct scan_field *bscan_tunneled_select_dmi; extern struct scan_field *bscan_tunneled_select_dmi;
extern uint32_t bscan_tunneled_select_dmi_num_fields; extern uint32_t bscan_tunneled_select_dmi_num_fields;
typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t; typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t;
extern int bscan_tunnel_ir_width; extern uint8_t bscan_tunnel_ir_width;
int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr); int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr);
void select_dmi_via_bscan(struct target *target); void select_dmi_via_bscan(struct target *target);