From 7eaf60f1b58da45087fb8e5c5808b84b3451c990 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 26 Jul 2019 11:08:35 -0700 Subject: [PATCH] Properly detect errors in SBA reads. (#392) Also don't set/clear sbreadondata when only reading one word. Change-Id: Ia81834014895f1f4b552312ad0b60b3d3967a2c7 --- src/target/riscv/riscv-013.c | 45 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6b7da475c..cb4f9fef6 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2211,11 +2211,12 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, target_addr_t end_address = address + count * size; while (next_address < end_address) { - uint32_t sbcs = set_field(0, DMI_SBCS_SBREADONADDR, 1); - sbcs |= sb_sbaccess(size); - sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1); - sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, count > 1); - if (dmi_write(target, DMI_SBCS, sbcs) != ERROR_OK) + uint32_t sbcs_write = set_field(0, DMI_SBCS_SBREADONADDR, 1); + sbcs_write |= sb_sbaccess(size); + sbcs_write = set_field(sbcs_write, DMI_SBCS_SBAUTOINCREMENT, 1); + if (count > 1) + sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, count > 1); + if (dmi_write(target, DMI_SBCS, sbcs_write) != ERROR_OK) return ERROR_FAIL; /* This address write will trigger the first read. */ @@ -2236,23 +2237,29 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; } - /* "Writes to sbcs while sbbusy is high result in undefined behavior. - * A debugger must not write to sbcs until it reads sbbusy as 0." */ - if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK) - return ERROR_FAIL; + uint32_t sbcs_read = 0; + if (count > 1) { + /* "Writes to sbcs while sbbusy is high result in undefined behavior. + * A debugger must not write to sbcs until it reads sbbusy as 0." */ + if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) + return ERROR_FAIL; - sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, 0); - if (dmi_write(target, DMI_SBCS, sbcs) != ERROR_OK) - return ERROR_FAIL; + sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, 0); + if (dmi_write(target, DMI_SBCS, sbcs_write) != ERROR_OK) + return ERROR_FAIL; + } - if (read_memory_bus_word(target, address + (count - 1) * size, size, - buffer + (count - 1) * size) != ERROR_OK) - return ERROR_FAIL; + if (!get_field(sbcs_read, DMI_SBCS_SBERROR) && + !get_field(sbcs_read, DMI_SBCS_SBBUSYERROR)) { + if (read_memory_bus_word(target, address + (count - 1) * size, size, + buffer + (count - 1) * size) != ERROR_OK) + return ERROR_FAIL; - if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK) - return ERROR_FAIL; + if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) + return ERROR_FAIL; + } - if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) { + if (get_field(sbcs_read, DMI_SBCS_SBBUSYERROR)) { /* We read while the target was busy. Slow down and try again. */ if (dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR) != ERROR_OK) return ERROR_FAIL; @@ -2261,7 +2268,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, continue; } - unsigned error = get_field(sbcs, DMI_SBCS_SBERROR); + unsigned error = get_field(sbcs_read, DMI_SBCS_SBERROR); if (error == 0) { next_address = end_address; } else {