riscv: make local symbols static
[fw/openocd] / src / target / riscv / riscv-011.c
index bd3f159fbeebd213683cb8eefc68867f8f695579..79d952694a14dfe751ef78612571d023334bfa61 100644 (file)
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
 /*
  * Support for RISC-V, debug version 0.11. This was never an officially adopted
  * spec, but SiFive made some silicon that uses it.
@@ -14,7 +16,7 @@
 #include "target/target.h"
 #include "target/algorithm.h"
 #include "target/target_type.h"
-#include "log.h"
+#include <helper/log.h>
 #include "jtag/jtag.h"
 #include "target/register.h"
 #include "target/breakpoints.h"
@@ -68,8 +70,6 @@
 #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
 #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
 
-#define DIM(x)         (sizeof(x)/sizeof(*x))
-
 /* Constants for legacy SiFive hardware breakpoints. */
 #define CSR_BPCONTROL_X                        (1<<0)
 #define CSR_BPCONTROL_W                        (1<<1)
@@ -152,6 +152,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
@@ -204,7 +207,6 @@ typedef struct {
         * before the interrupt is cleared. */
        unsigned int interrupt_high_delay;
 
-       bool need_strict_step;
        bool never_halted;
 } riscv011_info_t;
 
@@ -217,8 +219,7 @@ typedef struct {
 
 static int poll_target(struct target *target, bool announce);
 static int riscv011_poll(struct target *target);
-static int get_register(struct target *target, riscv_reg_t *value, int hartid,
-               int regid);
+static int get_register(struct target *target, riscv_reg_t *value, int regid);
 
 /*** Utility functions. ***/
 
@@ -226,8 +227,10 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
 
 static riscv011_info_t *get_info(const struct target *target)
 {
-       riscv_info_t *info = (riscv_info_t *) target->arch_info;
-       return (riscv011_info_t *) info->version_specific;
+       struct riscv_info *info = target->arch_info;
+       assert(info);
+       assert(info->version_specific);
+       return info->version_specific;
 }
 
 static unsigned int slot_offset(const struct target *target, slot_t slot)
@@ -280,7 +283,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
 {
        struct scan_field field;
        uint8_t in_value[4];
-       uint8_t out_value[4];
+       uint8_t out_value[4] = { 0 };
 
        buf_set_u32(out_value, 0, 32, out);
 
@@ -358,6 +361,15 @@ static void add_dbus_scan(const struct target *target, struct scan_field *field,
                uint16_t address, uint64_t data)
 {
        riscv011_info_t *info = get_info(target);
+       RISCV_INFO(r);
+
+       if (r->reset_delays_wait >= 0) {
+               r->reset_delays_wait--;
+               if (r->reset_delays_wait < 0) {
+                       info->dbus_busy_delay = 0;
+                       info->interrupt_high_delay = 0;
+               }
+       }
 
        field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE;
        field->in_value = in_value;
@@ -413,7 +425,7 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in,
 {
        riscv011_info_t *info = get_info(target);
        uint8_t in[8] = {0};
-       uint8_t out[8];
+       uint8_t out[8] = {0};
        struct scan_field field = {
                .num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE,
                .out_value = out,
@@ -510,6 +522,8 @@ typedef struct {
 static scans_t *scans_new(struct target *target, unsigned int scan_count)
 {
        scans_t *scans = malloc(sizeof(scans_t));
+       if (!scans)
+               goto error0;
        scans->scan_count = scan_count;
        /* This code also gets called before xlen is detected. */
        if (riscv_xlen(target))
@@ -518,10 +532,25 @@ static scans_t *scans_new(struct target *target, unsigned int scan_count)
                scans->scan_size = 2 + 128 / 8;
        scans->next_scan = 0;
        scans->in = calloc(scans->scan_size, scans->scan_count);
+       if (!scans->in)
+               goto error1;
        scans->out = calloc(scans->scan_size, scans->scan_count);
+       if (!scans->out)
+               goto error2;
        scans->field = calloc(scans->scan_count, sizeof(struct scan_field));
+       if (!scans->field)
+               goto error3;
        scans->target = target;
        return scans;
+
+error3:
+       free(scans->out);
+error2:
+       free(scans->in);
+error1:
+       free(scans);
+error0:
+       return NULL;
 }
 
 static scans_t *scans_delete(scans_t *scans)
@@ -835,6 +864,8 @@ static int cache_write(struct target *target, unsigned int address, bool run)
        LOG_DEBUG("enter");
        riscv011_info_t *info = get_info(target);
        scans_t *scans = scans_new(target, info->dramsize + 2);
+       if (!scans)
+               return ERROR_FAIL;
 
        unsigned int last = info->dramsize;
        for (unsigned int i = 0; i < info->dramsize; i++) {
@@ -1003,7 +1034,7 @@ static int wait_for_state(struct target *target, enum target_state state)
        }
 }
 
-static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
+static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr)
 {
        riscv011_info_t *info = get_info(target);
        cache_set32(target, 0, csrr(S0, csr));
@@ -1025,7 +1056,7 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
        return ERROR_OK;
 }
 
-static int write_csr(struct target *target, uint32_t csr, uint64_t value)
+static int write_remote_csr(struct target *target, uint32_t csr, uint64_t value)
 {
        LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value);
        cache_set_load(target, 0, S0, SLOT0);
@@ -1053,7 +1084,7 @@ static int maybe_read_tselect(struct target *target)
        riscv011_info_t *info = get_info(target);
 
        if (info->tselect_dirty) {
-               int result = read_csr(target, &info->tselect, CSR_TSELECT);
+               int result = read_remote_csr(target, &info->tselect, CSR_TSELECT);
                if (result != ERROR_OK)
                        return result;
                info->tselect_dirty = false;
@@ -1067,7 +1098,7 @@ static int maybe_write_tselect(struct target *target)
        riscv011_info_t *info = get_info(target);
 
        if (!info->tselect_dirty) {
-               int result = write_csr(target, CSR_TSELECT, info->tselect);
+               int result = write_remote_csr(target, CSR_TSELECT, info->tselect);
                if (result != ERROR_OK)
                        return result;
                info->tselect_dirty = true;
@@ -1106,7 +1137,10 @@ static int execute_resume(struct target *target, bool step)
                }
        }
 
-       info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU;
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
        info->dcsr &= ~DCSR_HALT;
 
        if (step)
@@ -1200,7 +1234,7 @@ static int update_mstatus_actual(struct target *target)
        /* Force reading the register. In that process mstatus_actual will be
         * updated. */
        riscv_reg_t mstatus;
-       return get_register(target, &mstatus, 0, GDB_REGNO_MSTATUS);
+       return get_register(target, &mstatus, GDB_REGNO_MSTATUS);
 }
 
 /*** OpenOCD target functions. ***/
@@ -1246,7 +1280,7 @@ static int register_write(struct target *target, unsigned int number,
 
        if (number == S0) {
                cache_set_load(target, 0, S0, SLOT0);
-               cache_set32(target, 1, csrw(S0, CSR_DSCRATCH));
+               cache_set32(target, 1, csrw(S0, CSR_DSCRATCH0));
                cache_set_jump(target, 2);
        } else if (number == S1) {
                cache_set_load(target, 0, S0, SLOT0);
@@ -1304,10 +1338,8 @@ static int register_write(struct target *target, unsigned int number,
        return ERROR_OK;
 }
 
-static int get_register(struct target *target, riscv_reg_t *value, int hartid,
-               int regid)
+static int get_register(struct target *target, riscv_reg_t *value, int regid)
 {
-       assert(hartid == 0);
        riscv011_info_t *info = get_info(target);
 
        maybe_write_tselect(target);
@@ -1350,10 +1382,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
        return ERROR_OK;
 }
 
-static int set_register(struct target *target, int hartid, int regid,
-               uint64_t value)
+static int set_register(struct target *target, int regid, uint64_t value)
 {
-       assert(hartid == 0);
        return register_write(target, regid, value);
 }
 
@@ -1375,45 +1405,21 @@ static int halt(struct target *target)
        return ERROR_OK;
 }
 
-static int init_target(struct command_context *cmd_ctx,
-               struct target *target)
-{
-       LOG_DEBUG("init");
-       riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
-       generic_info->get_register = get_register;
-       generic_info->set_register = set_register;
-
-       generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
-       if (!generic_info->version_specific)
-               return ERROR_FAIL;
-
-       /* Assume 32-bit until we discover the real value in examine(). */
-       generic_info->xlen[0] = 32;
-       riscv_init_registers(target);
-
-       return ERROR_OK;
-}
-
 static void deinit_target(struct target *target)
 {
        LOG_DEBUG("riscv_deinit_target()");
-       riscv_info_t *info = (riscv_info_t *) target->arch_info;
+       struct riscv_info *info = target->arch_info;
+       if (!info)
+               return;
+
        free(info->version_specific);
        info->version_specific = NULL;
 }
 
 static int strict_step(struct target *target, bool announce)
 {
-       riscv011_info_t *info = get_info(target);
-
        LOG_DEBUG("enter");
 
-       struct breakpoint *breakpoint = target->breakpoints;
-       while (breakpoint) {
-               riscv_remove_breakpoint(target, breakpoint);
-               breakpoint = breakpoint->next;
-       }
-
        struct watchpoint *watchpoint = target->watchpoints;
        while (watchpoint) {
                riscv_remove_watchpoint(target, watchpoint);
@@ -1424,28 +1430,18 @@ static int strict_step(struct target *target, bool announce)
        if (result != ERROR_OK)
                return result;
 
-       breakpoint = target->breakpoints;
-       while (breakpoint) {
-               riscv_add_breakpoint(target, breakpoint);
-               breakpoint = breakpoint->next;
-       }
-
        watchpoint = target->watchpoints;
        while (watchpoint) {
                riscv_add_watchpoint(target, watchpoint);
                watchpoint = watchpoint->next;
        }
 
-       info->need_strict_step = false;
-
        return ERROR_OK;
 }
 
 static int step(struct target *target, int current, target_addr_t address,
                int handle_breakpoints)
 {
-       riscv011_info_t *info = get_info(target);
-
        jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
 
        if (!current) {
@@ -1458,12 +1454,12 @@ static int step(struct target *target, int current, target_addr_t address,
                        return result;
        }
 
-       if (info->need_strict_step || handle_breakpoints) {
+       if (handle_breakpoints) {
                int result = strict_step(target, true);
                if (result != ERROR_OK)
                        return result;
        } else {
-               return resume(target, 0, true);
+               return full_step(target, false);
        }
 
        return ERROR_OK;
@@ -1489,7 +1485,6 @@ static int examine(struct target *target)
        }
 
        RISCV_INFO(r);
-       r->hart_count = 1;
 
        riscv011_info_t *info = get_info(target);
        info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS);
@@ -1531,7 +1526,7 @@ static int examine(struct target *target)
        }
 
        /* Pretend this is a 32-bit system until we have found out the true value. */
-       r->xlen[0] = 32;
+       r->xlen = 32;
 
        /* Figure out XLEN, and test writing all of Debug RAM while we're at it. */
        cache_set32(target, 0, xori(S1, ZERO, -1));
@@ -1557,13 +1552,13 @@ static int examine(struct target *target)
 
        uint32_t word0 = cache_get32(target, 0);
        uint32_t word1 = cache_get32(target, 1);
-       riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
+       struct riscv_info *generic_info = riscv_info(target);
        if (word0 == 1 && word1 == 0) {
-               generic_info->xlen[0] = 32;
+               generic_info->xlen = 32;
        } else if (word0 == 0xffffffff && word1 == 3) {
-               generic_info->xlen[0] = 64;
+               generic_info->xlen = 64;
        } else if (word0 == 0xffffffff && word1 == 0xffffffff) {
-               generic_info->xlen[0] = 128;
+               generic_info->xlen = 128;
        } else {
                uint32_t exception = cache_get32(target, info->dramsize-1);
                LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x",
@@ -1573,11 +1568,11 @@ static int examine(struct target *target)
        }
        LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
 
-       if (read_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) {
+       if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) {
                const unsigned old_csr_misa = 0xf10;
                LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
                                old_csr_misa);
-               if (read_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) {
+               if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) {
                        /* Maybe this is an old core that still has $misa at the old
                         * address. */
                        LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
@@ -1599,7 +1594,7 @@ static int examine(struct target *target)
        for (size_t i = 0; i < 32; ++i)
                reg_cache_set(target, i, -1);
        LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
-                       riscv_xlen(target), r->misa[0]);
+                       riscv_xlen(target), r->misa);
 
        return ERROR_OK;
 }
@@ -1609,6 +1604,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
        riscv011_info_t *info = get_info(target);
 
        scans_t *scans = scans_new(target, 256);
+       if (!scans)
+               return RE_FAIL;
 
        /* Read all GPRs as fast as we can, because gdb is going to ask for them
         * anyway. Reading them one at a time is much slower. */
@@ -1637,8 +1634,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
        scans_add_read(scans, SLOT0, false);
 
        /* Read S0 from dscratch */
-       unsigned int csr[] = {CSR_DSCRATCH, CSR_DPC, CSR_DCSR};
-       for (unsigned int i = 0; i < DIM(csr); i++) {
+       unsigned int csr[] = {CSR_DSCRATCH0, CSR_DPC, CSR_DCSR};
+       for (unsigned int i = 0; i < ARRAY_SIZE(csr); i++) {
                scans_add_write32(scans, 0, csrr(S0, csr[i]), true);
                scans_add_read(scans, SLOT0, false);
        }
@@ -1676,7 +1673,7 @@ static riscv_error_t handle_halt_routine(struct target *target)
                                break;
                        default:
                                LOG_ERROR("Got invalid bus access status: %d", status);
-                               return ERROR_FAIL;
+                               goto error;
                }
                if (data & DMCONTROL_INTERRUPT) {
                        interrupt_set++;
@@ -1850,10 +1847,7 @@ static int handle_halt(struct target *target, bool announce)
                        target->debug_reason = DBG_REASON_BREAKPOINT;
                        break;
                case DCSR_CAUSE_HWBP:
-                       target->debug_reason = DBG_REASON_WPTANDBKPT;
-                       /* If we halted because of a data trigger, gdb doesn't know to do
-                        * the disable-breakpoints-step-enable-breakpoints dance. */
-                       info->need_strict_step = true;
+                       target->debug_reason = DBG_REASON_WATCHPOINT;
                        break;
                case DCSR_CAUSE_DEBUGINT:
                        target->debug_reason = DBG_REASON_DBGRQ;
@@ -1938,26 +1932,10 @@ static int riscv011_poll(struct target *target)
 static int riscv011_resume(struct target *target, int current,
                target_addr_t address, int handle_breakpoints, int debug_execution)
 {
-       riscv011_info_t *info = get_info(target);
-
+       RISCV_INFO(r);
        jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
 
-       if (!current) {
-               if (riscv_xlen(target) > 32) {
-                       LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
-                                       riscv_xlen(target));
-               }
-               int result = register_write(target, GDB_REGNO_PC, address);
-               if (result != ERROR_OK)
-                       return result;
-       }
-
-       if (info->need_strict_step || handle_breakpoints) {
-               int result = strict_step(target, false);
-               if (result != ERROR_OK)
-                       return result;
-       }
-
+       r->prepped = false;
        return resume(target, debug_execution, false);
 }
 
@@ -1976,8 +1954,11 @@ static int assert_reset(struct target *target)
 
        /* Not sure what we should do when there are multiple cores.
         * Here just reset the single hart we're talking to. */
-       info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS |
-               DCSR_EBREAKU | DCSR_HALT;
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
+       info->dcsr |= DCSR_HALT;
        if (target->reset_halt)
                info->dcsr |= DCSR_NDRESET;
        else
@@ -2004,8 +1985,13 @@ static int deassert_reset(struct target *target)
 }
 
 static int read_memory(struct target *target, target_addr_t address,
-               uint32_t size, uint32_t count, uint8_t *buffer)
+               uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
 {
+       if (increment != size) {
+               LOG_ERROR("read_memory with custom increment not implemented");
+               return ERROR_NOT_IMPLEMENTED;
+       }
+
        jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
 
        cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
@@ -2032,6 +2018,8 @@ static int read_memory(struct target *target, target_addr_t address,
        riscv011_info_t *info = get_info(target);
        const unsigned max_batch_size = 256;
        scans_t *scans = scans_new(target, max_batch_size);
+       if (!scans)
+               return ERROR_FAIL;
 
        uint32_t result_value = 0x777;
        uint32_t i = 0;
@@ -2188,6 +2176,8 @@ static int write_memory(struct target *target, target_addr_t address,
 
        const unsigned max_batch_size = 256;
        scans_t *scans = scans_new(target, max_batch_size);
+       if (!scans)
+               return ERROR_FAIL;
 
        uint32_t result_value = 0x777;
        uint32_t i = 0;
@@ -2307,6 +2297,100 @@ static int arch_state(struct target *target)
        return ERROR_OK;
 }
 
+static COMMAND_HELPER(riscv011_print_info, struct target *target)
+{
+       /* Abstract description. */
+       riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running8", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running16", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running16", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running32", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running32", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running64", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running64", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running128", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running128", 0);
+
+       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 int 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 int 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)
+{
+       LOG_DEBUG("init");
+       RISCV_INFO(generic_info);
+       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)
+               return ERROR_FAIL;
+
+       /* Assume 32-bit until we discover the real value in examine(). */
+       generic_info->xlen = 32;
+       riscv_init_registers(target);
+
+       return ERROR_OK;
+}
+
 struct target_type riscv011_target = {
        .name = "riscv",
 
@@ -2324,7 +2408,6 @@ struct target_type riscv011_target = {
        .assert_reset = assert_reset,
        .deassert_reset = deassert_reset,
 
-       .read_memory = read_memory,
        .write_memory = write_memory,
 
        .arch_state = arch_state,