From a83ac8102208fe43029e31a20ea00eb5f242f5e3 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 28 Jan 2021 09:56:51 -0800 Subject: [PATCH] Add authdata_read/authdata_write support to 0.11. (#575) AFAIK there is no hardware that implements this, but it should be a close-to-done starting point in case it is ever required. Change-Id: I49e3082e8629b1d70b12e8a847c2848e75b04508 Signed-off-by: Tim Newsome --- doc/openocd.texi | 10 +++--- src/target/riscv/riscv-011.c | 65 ++++++++++++++++++++++++++++++++++++ src/target/riscv/riscv-013.c | 21 ++++++++++-- src/target/riscv/riscv.c | 40 ++++++++++++++-------- src/target/riscv/riscv.h | 4 +-- 5 files changed, 118 insertions(+), 22 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index b7512feb5..53fe9bfa9 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10129,12 +10129,14 @@ set challenge [riscv authdata_read] riscv authdata_write [expr $challenge + 1] @end example -@deffn Command {riscv authdata_read} -Return the 32-bit value read from authdata. +@deffn Command {riscv authdata_read} [index=0] +Return the 32-bit value read from authdata or authdata0 (index=0), or +authdata1 (index=1). @end deffn -@deffn Command {riscv authdata_write} value -Write the 32-bit value to authdata. +@deffn Command {riscv authdata_write} [index=0] value +Write the 32-bit value to authdata or authdata0 (index=0), or authdata1 +(index=1). @end deffn @subsection RISC-V DMI Commands diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 78cd55fae..d1774d701 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -154,6 +154,9 @@ typedef enum slot { #define DMINFO_AUTHTYPE (3<<2) #define DMINFO_VERSION 3 +#define DMAUTHDATA0 0x12 +#define DMAUTHDATA1 0x13 + /*** Info about the core being debugged. ***/ #define DBUS_ADDRESS_UNKNOWN 0xffff @@ -2293,6 +2296,65 @@ static int arch_state(struct target *target) return ERROR_OK; } +COMMAND_HELPER(riscv011_print_info, struct target *target) +{ + uint32_t dminfo = dbus_read(target, DMINFO); + riscv_print_info_line(CMD, "dm", "authenticated", get_field(dminfo, DMINFO_AUTHENTICATED)); + + return 0; +} + +static int wait_for_authbusy(struct target *target) +{ + time_t start = time(NULL); + while (1) { + uint32_t dminfo = dbus_read(target, DMINFO); + if (!get_field(dminfo, DMINFO_AUTHBUSY)) + break; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + dminfo); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int riscv011_authdata_read(struct target *target, uint32_t *value, unsigned index) +{ + if (index > 1) { + LOG_ERROR("Spec 0.11 only has a two authdata registers."); + return ERROR_FAIL; + } + + if (wait_for_authbusy(target) != ERROR_OK) + return ERROR_FAIL; + + uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0; + *value = dbus_read(target, authdata_address); + + return ERROR_OK; +} + +static int riscv011_authdata_write(struct target *target, uint32_t value, unsigned index) +{ + if (index > 1) { + LOG_ERROR("Spec 0.11 only has a two authdata registers."); + return ERROR_FAIL; + } + + if (wait_for_authbusy(target) != ERROR_OK) + return ERROR_FAIL; + + uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0; + dbus_write(target, authdata_address, value); + + return ERROR_OK; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -2301,6 +2363,9 @@ static int init_target(struct command_context *cmd_ctx, generic_info->get_register = get_register; generic_info->set_register = set_register; generic_info->read_memory = read_memory; + generic_info->authdata_read = &riscv011_authdata_read; + generic_info->authdata_write = &riscv011_authdata_write; + generic_info->print_info = &riscv011_print_info; generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); if (!generic_info->version_specific) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index b5ede3402..ad0423c1c 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1500,7 +1500,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return result; } -int wait_for_authbusy(struct target *target, uint32_t *dmstatus) +static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) { time_t start = time(NULL); while (1) { @@ -1784,16 +1784,26 @@ static int examine(struct target *target) return ERROR_OK; } -int riscv013_authdata_read(struct target *target, uint32_t *value) +static int riscv013_authdata_read(struct target *target, uint32_t *value, unsigned index) { + if (index > 0) { + LOG_ERROR("Spec 0.13 only has a single authdata register."); + return ERROR_FAIL; + } + if (wait_for_authbusy(target, NULL) != ERROR_OK) return ERROR_FAIL; return dmi_read(target, value, DM_AUTHDATA); } -int riscv013_authdata_write(struct target *target, uint32_t value) +static int riscv013_authdata_write(struct target *target, uint32_t value, unsigned index) { + if (index > 0) { + LOG_ERROR("Spec 0.13 only has a single authdata register."); + return ERROR_FAIL; + } + uint32_t before, after; if (wait_for_authbusy(target, &before) != ERROR_OK) return ERROR_FAIL; @@ -1867,6 +1877,7 @@ static unsigned riscv013_data_bits(struct target *target) COMMAND_HELPER(riscv013_print_info, struct target *target) { RISCV013_INFO(info); + riscv_print_info_line(CMD, "dm", "abits", info->abits); riscv_print_info_line(CMD, "dm", "progbufsize", info->progbufsize); riscv_print_info_line(CMD, "dm", "sbversion", get_field(info->sbcs, DM_SBCS_SBVERSION)); @@ -1877,6 +1888,10 @@ COMMAND_HELPER(riscv013_print_info, struct target *target) riscv_print_info_line(CMD, "dm", "sbaccess16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); riscv_print_info_line(CMD, "dm", "sbaccess8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, false) == ERROR_OK) + riscv_print_info_line(CMD, "dm", "authenticated", get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)); + return 0; } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index fb198cbd0..c9a426728 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2552,8 +2552,13 @@ COMMAND_HANDLER(riscv_set_expose_custom) COMMAND_HANDLER(riscv_authdata_read) { - if (CMD_ARGC != 0) { - LOG_ERROR("Command takes no parameters"); + unsigned index = 0; + if (CMD_ARGC == 0) { + /* nop */ + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); + } else { + LOG_ERROR("Command takes at most one parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -2571,7 +2576,7 @@ COMMAND_HANDLER(riscv_authdata_read) if (r->authdata_read) { uint32_t value; - if (r->authdata_read(target, &value) != ERROR_OK) + if (r->authdata_read(target, &value, index) != ERROR_OK) return ERROR_FAIL; command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; @@ -2583,19 +2588,26 @@ COMMAND_HANDLER(riscv_authdata_read) COMMAND_HANDLER(riscv_authdata_write) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 argument"); + uint32_t value; + unsigned index = 0; + + if (CMD_ARGC == 0) { + /* nop */ + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); + } else if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + } else { + LOG_ERROR("Command takes at most 2 arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); - if (r->authdata_write) { - return r->authdata_write(target, value); + return r->authdata_write(target, value, index); } else { LOG_ERROR("authdata_write is not implemented for this target."); return ERROR_FAIL; @@ -3103,16 +3115,18 @@ static const struct command_registration riscv_exec_command_handlers[] = { { .name = "authdata_read", .handler = riscv_authdata_read, - .usage = "", + .usage = "[index]", .mode = COMMAND_ANY, - .help = "Return the 32-bit value read from authdata." + .help = "Return the 32-bit value read from authdata or authdata0 " + "(index=0), or authdata1 (index=1)." }, { .name = "authdata_write", .handler = riscv_authdata_write, .mode = COMMAND_ANY, - .usage = "value", - .help = "Write the 32-bit value to authdata." + .usage = "[index] value", + .help = "Write the 32-bit value to authdata or authdata0 (index=0), " + "or authdata1 (index=1)." }, { .name = "dmi_read", diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 094851b7d..5e057e712 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -171,8 +171,8 @@ typedef struct { void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); void (*fill_dmi_nop_u64)(struct target *target, char *buf); - int (*authdata_read)(struct target *target, uint32_t *value); - int (*authdata_write)(struct target *target, uint32_t value); + int (*authdata_read)(struct target *target, uint32_t *value, unsigned index); + int (*authdata_write)(struct target *target, uint32_t value, unsigned index); int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); int (*dmi_write)(struct target *target, uint32_t address, uint32_t value);