Skip to content

Commit 6587668

Browse files
authored
Merge pull request #1162 from aap-sc/aap-sc/csr_as_hex
target/riscv: allow hexadecimal values to expose_csr-like commands
2 parents 1bf7efb + ba8c1ee commit 6587668

File tree

1 file changed

+81
-50
lines changed

1 file changed

+81
-50
lines changed

src/target/riscv/riscv.c

Lines changed: 81 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4086,74 +4086,96 @@ COMMAND_HANDLER(riscv_set_mem_access)
40864086
return ERROR_OK;
40874087
}
40884088

4089-
static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val)
4090-
{
4091-
char *args = strdup(tcl_arg);
4092-
if (!args)
4093-
return ERROR_FAIL;
40944089

4095-
/* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */
4096-
char *arg = strtok(args, ",");
4097-
while (arg) {
4090+
static bool parse_csr_address(const char *reg_address_str, unsigned int *reg_addr)
4091+
{
4092+
*reg_addr = -1;
4093+
/* skip initial spaces */
4094+
while (isspace(reg_address_str[0]))
4095+
++reg_address_str;
4096+
/* try to detect if string starts with 0x or 0X */
4097+
bool is_hex_address = strncmp(reg_address_str, "0x", 2) == 0 ||
4098+
strncmp(reg_address_str, "0X", 2) == 0;
4099+
4100+
unsigned int scanned_chars;
4101+
if (is_hex_address) {
4102+
reg_address_str += 2;
4103+
if (sscanf(reg_address_str, "%x%n", reg_addr, &scanned_chars) != 1)
4104+
return false;
4105+
} else {
4106+
/* If we are here and register address string starts with zero, this is
4107+
* an indication that most likely user has an incorrect input because:
4108+
* - decimal numbers typically do not start with "0"
4109+
* - octals are not supported by our interface
4110+
* - hexadecimal numbers should have "0x" prefix
4111+
* Thus such input is rejected. */
4112+
if (reg_address_str[0] == '0' && strlen(reg_address_str) > 1)
4113+
return false;
4114+
if (sscanf(reg_address_str, "%u%n", reg_addr, &scanned_chars) != 1)
4115+
return false;
4116+
}
4117+
return scanned_chars == strlen(reg_address_str);
4118+
}
4119+
4120+
static int parse_reg_ranges_impl(struct list_head *ranges, char *args,
4121+
const char *reg_type, unsigned int max_val, char ** const name_buffer)
4122+
{
4123+
/* For backward compatibility, allow multiple parameters within one TCL
4124+
* argument, separated by ',' */
4125+
for (char *arg = strtok(args, ","); arg; arg = strtok(NULL, ",")) {
40984126
unsigned int low = 0;
40994127
unsigned int high = 0;
41004128
char *name = NULL;
41014129

41024130
char *dash = strchr(arg, '-');
41034131
char *equals = strchr(arg, '=');
4104-
unsigned int pos;
41054132

41064133
if (!dash && !equals) {
41074134
/* Expecting single register number. */
4108-
if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) {
4135+
if (!parse_csr_address(arg, &low)) {
41094136
LOG_ERROR("Failed to parse single register number from '%s'.", arg);
4110-
free(args);
41114137
return ERROR_COMMAND_SYNTAX_ERROR;
41124138
}
41134139
} else if (dash && !equals) {
41144140
/* Expecting register range - two numbers separated by a dash: ##-## */
4115-
*dash = 0;
4116-
dash++;
4117-
if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) {
4118-
LOG_ERROR("Failed to parse single register number from '%s'.", arg);
4119-
free(args);
4141+
*dash = '\0';
4142+
if (!parse_csr_address(arg, &low)) {
4143+
LOG_ERROR("Failed to parse '%s' - not a valid decimal or hexadecimal number.",
4144+
arg);
41204145
return ERROR_COMMAND_SYNTAX_ERROR;
41214146
}
4122-
if (sscanf(dash, "%u%n", &high, &pos) != 1 || pos != strlen(dash)) {
4123-
LOG_ERROR("Failed to parse single register number from '%s'.", dash);
4124-
free(args);
4147+
const char *high_num_in = dash + 1;
4148+
if (!parse_csr_address(high_num_in, &high)) {
4149+
LOG_ERROR("Failed to parse '%s' - not a valid decimal or hexadecimal number.",
4150+
high_num_in);
41254151
return ERROR_COMMAND_SYNTAX_ERROR;
41264152
}
41274153
if (high < low) {
41284154
LOG_ERROR("Incorrect range encountered [%u, %u].", low, high);
4129-
free(args);
41304155
return ERROR_FAIL;
41314156
}
41324157
} else if (!dash && equals) {
41334158
/* Expecting single register number with textual name specified: ##=name */
4134-
*equals = 0;
4135-
equals++;
4136-
if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) {
4137-
LOG_ERROR("Failed to parse single register number from '%s'.", arg);
4138-
free(args);
4159+
*equals = '\0';
4160+
if (!parse_csr_address(arg, &low)) {
4161+
LOG_ERROR("Failed to parse '%s' - not a valid decimal or hexadecimal number.",
4162+
arg);
41394163
return ERROR_COMMAND_SYNTAX_ERROR;
41404164
}
41414165

4142-
name = calloc(1, strlen(equals) + strlen(reg_type) + 2);
4166+
const char * const reg_name_in = equals + 1;
4167+
*name_buffer = calloc(1, strlen(reg_name_in) + strlen(reg_type) + 2);
4168+
name = *name_buffer;
41434169
if (!name) {
4144-
LOG_ERROR("Failed to allocate register name.");
4145-
free(args);
4170+
LOG_ERROR("Out of memory");
41464171
return ERROR_FAIL;
41474172
}
41484173

4149-
/* Register prefix: "csr_" or "custom_" */
4150-
strcpy(name, reg_type);
4151-
name[strlen(reg_type)] = '_';
4152-
4153-
if (sscanf(equals, "%[_a-zA-Z0-9]%n", name + strlen(reg_type) + 1, &pos) != 1 || pos != strlen(equals)) {
4154-
LOG_ERROR("Failed to parse register name from '%s'.", equals);
4155-
free(args);
4156-
free(name);
4174+
unsigned int scanned_chars;
4175+
char *scan_dst = name + strlen(reg_type) + 1;
4176+
if (sscanf(reg_name_in, "%[_a-zA-Z0-9]%n", scan_dst, &scanned_chars) != 1 ||
4177+
scanned_chars != strlen(reg_name_in)) {
4178+
LOG_ERROR("Invalid characters in register name '%s'.", reg_name_in);
41574179
return ERROR_COMMAND_SYNTAX_ERROR;
41584180
}
41594181
} else {
@@ -4165,9 +4187,8 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha
41654187
high = MAX(high, low);
41664188

41674189
if (high > max_val) {
4168-
LOG_ERROR("Cannot expose %s register number %u, maximum allowed value is %u.", reg_type, high, max_val);
4169-
free(name);
4170-
free(args);
4190+
LOG_ERROR("Cannot expose %s register number 0x%x, maximum allowed value is 0x%x.",
4191+
reg_type, high, max_val);
41714192
return ERROR_FAIL;
41724193
}
41734194

@@ -4185,32 +4206,42 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha
41854206

41864207
if (entry->name && name && (strcasecmp(entry->name, name) == 0)) {
41874208
LOG_ERROR("Duplicate register name \"%s\" found.", name);
4188-
free(name);
4189-
free(args);
41904209
return ERROR_FAIL;
41914210
}
41924211
}
41934212

41944213
range_list_t *range = calloc(1, sizeof(range_list_t));
41954214
if (!range) {
4196-
LOG_ERROR("Failed to allocate range list.");
4197-
free(name);
4198-
free(args);
4215+
LOG_ERROR("Out of memory");
41994216
return ERROR_FAIL;
42004217
}
42014218

42024219
range->low = low;
42034220
range->high = high;
42044221
range->name = name;
4222+
/* ownership over name_buffer contents is transferred to list item here */
4223+
*name_buffer = NULL;
42054224
list_add(&range->list, ranges);
4206-
4207-
arg = strtok(NULL, ",");
42084225
}
42094226

4210-
free(args);
42114227
return ERROR_OK;
42124228
}
42134229

4230+
static int parse_reg_ranges(struct list_head *ranges, const char *tcl_arg,
4231+
const char *reg_type, unsigned int max_val)
4232+
{
4233+
char *args = strdup(tcl_arg);
4234+
if (!args) {
4235+
LOG_ERROR("Out of memory");
4236+
return ERROR_FAIL;
4237+
}
4238+
char *name_buffer = NULL;
4239+
int result = parse_reg_ranges_impl(ranges, args, reg_type, max_val, &name_buffer);
4240+
free(name_buffer);
4241+
free(args);
4242+
return result;
4243+
}
4244+
42144245
COMMAND_HANDLER(riscv_set_expose_csrs)
42154246
{
42164247
if (CMD_ARGC == 0)
@@ -4221,7 +4252,7 @@ COMMAND_HANDLER(riscv_set_expose_csrs)
42214252
int ret = ERROR_OK;
42224253

42234254
for (unsigned int i = 0; i < CMD_ARGC; i++) {
4224-
ret = parse_ranges(&info->expose_csr, CMD_ARGV[i], "csr", 0xfff);
4255+
ret = parse_reg_ranges(&info->expose_csr, CMD_ARGV[i], "csr", 0xfff);
42254256
if (ret != ERROR_OK)
42264257
break;
42274258
}
@@ -4239,7 +4270,7 @@ COMMAND_HANDLER(riscv_set_expose_custom)
42394270
int ret = ERROR_OK;
42404271

42414272
for (unsigned int i = 0; i < CMD_ARGC; i++) {
4242-
ret = parse_ranges(&info->expose_custom, CMD_ARGV[i], "custom", 0x3fff);
4273+
ret = parse_reg_ranges(&info->expose_custom, CMD_ARGV[i], "custom", 0x3fff);
42434274
if (ret != ERROR_OK)
42444275
break;
42454276
}
@@ -4257,7 +4288,7 @@ COMMAND_HANDLER(riscv_hide_csrs)
42574288
int ret = ERROR_OK;
42584289

42594290
for (unsigned int i = 0; i < CMD_ARGC; i++) {
4260-
ret = parse_ranges(&info->hide_csr, CMD_ARGV[i], "csr", 0xfff);
4291+
ret = parse_reg_ranges(&info->hide_csr, CMD_ARGV[i], "csr", 0xfff);
42614292
if (ret != ERROR_OK)
42624293
break;
42634294
}

0 commit comments

Comments
 (0)