From c6cf38d55d61c0534814369a2cf8a3b30cf7261c Mon Sep 17 00:00:00 2001 From: mean Date: Thu, 8 Feb 2024 08:09:30 +0100 Subject: [PATCH 1/4] riscv: add flashstub framework and helper functions --- src/target/flashstub/riscv32_flashstub.h | 10 +++ src/target/riscv32.c | 89 ++++++++++++++++++++++++ src/target/riscv_debug.h | 11 +++ 3 files changed, 110 insertions(+) create mode 100644 src/target/flashstub/riscv32_flashstub.h diff --git a/src/target/flashstub/riscv32_flashstub.h b/src/target/flashstub/riscv32_flashstub.h new file mode 100644 index 00000000000..0e79eb8afac --- /dev/null +++ b/src/target/flashstub/riscv32_flashstub.h @@ -0,0 +1,10 @@ +#pragma once + +/* + * exit stub, 0 means OK, else error code + */ +static inline void __attribute__((always_inline)) riscv_stub_exit(const int code) +{ + __asm__("li a0, %0 \n" + "ebreak" ::"i"(code)); +} diff --git a/src/target/riscv32.c b/src/target/riscv32.c index c15ce02cded..c9996da28b9 100644 --- a/src/target/riscv32.c +++ b/src/target/riscv32.c @@ -670,3 +670,92 @@ static int riscv32_breakwatch_clear(target_s *const target, breakwatch_s *const const uint32_t address = 0; return riscv_config_trigger(hart, breakwatch->reserved[0], RISCV_TRIGGER_MODE_UNUSED, &config, &address) ? 0 : -1; } + +#define RISCV_REG_A0 10 +#define RISCV_REG_A1 11 +#define RISCV_REG_A2 12 +#define RISCV_REG_A3 13 +#define RISCV_REG_PC 32 +#define RISCV_REG_SP 2 + +/* + Small helper function to translate target to hart and simplify parameters + We assume it is 32 bits +*/ +static bool riscv32_target_csr_write(target_s *target, const uint16_t reg, uint32_t val) +{ + riscv_hart_s *const hart = riscv_hart_struct(target); + return riscv_csr_write(hart, reg, &val); +} + +/* + Small helper function to translate target to hart and simplify parameters + We assume it is 32 bits +*/ +static bool riscv32_target_csr_read(target_s *target, const uint16_t reg, uint32_t *val) +{ + riscv_hart_s *const hart = riscv_hart_struct(target); + return riscv_csr_read(hart, reg, val); +} + +/* + Execute code on the target with the signature void function(a,b,c,d) + - codexec is the address the code to tun is located at + - param1/2/3/4 will end up as the 4 parameters of the stub function + + The flashstub must not use the stack at all. + It returns true on success, false on error + There is a built-in timeout of 10 seconds +*/ +bool riscv32_run_stub(target_s *t, uint32_t codeexec, uint32_t param1, uint32_t param2, uint32_t param3, + uint32_t param4) +{ + bool ret = false; + uint32_t pc, mie, zero = 0; + // save PC & MIE + t->reg_read(t, RISCV_REG_PC, &pc, 4); + riscv32_target_csr_read(t, RV_CSR_MIE, &mie); + riscv32_target_csr_write(t, RV_CSR_MIE, zero); // disable interrupt + t->reg_write(t, RISCV_REG_A0, ¶m1, 4); + t->reg_write(t, RISCV_REG_A1, ¶m2, 4); + t->reg_write(t, RISCV_REG_A2, ¶m3, 4); + t->reg_write(t, RISCV_REG_A3, ¶m4, 4); + t->reg_write(t, RISCV_REG_PC, &codeexec, 4); + + target_halt_reason_e reason = TARGET_HALT_RUNNING; + t->halt_resume(t, false); // go! + platform_timeout_s timeout; + platform_timeout_set(&timeout, 10000); + while (reason == TARGET_HALT_RUNNING) + { + if (platform_timeout_is_expired(&timeout)) + { + goto the_end; + } + reason = t->halt_poll(t, NULL); + } + + if (reason == TARGET_HALT_ERROR) + { + goto the_end; + } + + if (reason != TARGET_HALT_REQUEST) + { + goto the_end; + } + ret = true; +the_end: + t->halt_request(t); + if (ret) + { + uint32_t a0; + t->reg_read(t, RISCV_REG_A0, &a0, 4); + ret = (a0 == 0); + } + // restore PC & MIE + riscv32_target_csr_write(t, RV_CSR_MIE, mie); // put back MIE + t->reg_write(t, RISCV_REG_PC, &pc, 4); + return ret; +} +//---- diff --git a/src/target/riscv_debug.h b/src/target/riscv_debug.h index bdbc4f89150..ec9b6d69fd9 100644 --- a/src/target/riscv_debug.h +++ b/src/target/riscv_debug.h @@ -241,4 +241,15 @@ uint32_t riscv32_pack_data(const void *src, uint8_t access_width); void riscv32_mem_read(target_s *target, void *dest, target_addr_t src, size_t len); void riscv32_mem_write(target_s *target, target_addr_t dest, const void *src, size_t len); +/* + Execute code on the target with the signature void stub_function(a,b,c,d) + - codexec is the address the code to run is located at + - param1/2/3/4 will end up as the 4 parameters of the stub function + + The flashstub must not use the stack at all. + The flashstub must return 0 on success, not 0 on error + There is a built-in timeout of 10 seconds +*/ +bool riscv32_run_stub(target_s *target, uint32_t loadaddr, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3); + #endif /*TARGET_RISCV_DEBUG_H*/ From 022a6384ea17de30d207c4a8bac9cff97d0ed630 Mon Sep 17 00:00:00 2001 From: mean Date: Sun, 18 Feb 2024 16:48:39 +0100 Subject: [PATCH 2/4] fixup : take comments into account --- src/target/flashstub/riscv32_flashstub.h | 26 +++++- src/target/riscv32.c | 114 ++++++++++------------- src/target/riscv_debug.h | 8 ++ 3 files changed, 84 insertions(+), 64 deletions(-) diff --git a/src/target/flashstub/riscv32_flashstub.h b/src/target/flashstub/riscv32_flashstub.h index 0e79eb8afac..36a1d0b9539 100644 --- a/src/target/flashstub/riscv32_flashstub.h +++ b/src/target/flashstub/riscv32_flashstub.h @@ -1,4 +1,26 @@ -#pragma once +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2015 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TARGET_RISCV_FLASHSTUB_STUB_H +#define TARGET_RISCV_FLASHSTUB_STUB_H + /* * exit stub, 0 means OK, else error code @@ -8,3 +30,5 @@ static inline void __attribute__((always_inline)) riscv_stub_exit(const int code __asm__("li a0, %0 \n" "ebreak" ::"i"(code)); } + +#endif diff --git a/src/target/riscv32.c b/src/target/riscv32.c index c9996da28b9..0d7536c3c3d 100644 --- a/src/target/riscv32.c +++ b/src/target/riscv32.c @@ -30,7 +30,6 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "general.h" #include "target.h" #include "target_internal.h" @@ -671,31 +670,24 @@ static int riscv32_breakwatch_clear(target_s *const target, breakwatch_s *const return riscv_config_trigger(hart, breakwatch->reserved[0], RISCV_TRIGGER_MODE_UNUSED, &config, &address) ? 0 : -1; } -#define RISCV_REG_A0 10 -#define RISCV_REG_A1 11 -#define RISCV_REG_A2 12 -#define RISCV_REG_A3 13 -#define RISCV_REG_PC 32 -#define RISCV_REG_SP 2 - /* Small helper function to translate target to hart and simplify parameters We assume it is 32 bits */ -static bool riscv32_target_csr_write(target_s *target, const uint16_t reg, uint32_t val) +static inline bool riscv32_target_csr_write(target_s *target, const uint16_t reg, uint32_t val) { - riscv_hart_s *const hart = riscv_hart_struct(target); - return riscv_csr_write(hart, reg, &val); + riscv_hart_s *const hart = riscv_hart_struct(target); + return riscv_csr_write(hart, reg, &val); } /* Small helper function to translate target to hart and simplify parameters We assume it is 32 bits */ -static bool riscv32_target_csr_read(target_s *target, const uint16_t reg, uint32_t *val) +static inline bool riscv32_target_csr_read(target_s *target, const uint16_t reg, uint32_t *val) { - riscv_hart_s *const hart = riscv_hart_struct(target); - return riscv_csr_read(hart, reg, val); + riscv_hart_s *const hart = riscv_hart_struct(target); + return riscv_csr_read(hart, reg, val); } /* @@ -707,55 +699,51 @@ static bool riscv32_target_csr_read(target_s *target, const uint16_t reg, uint32 It returns true on success, false on error There is a built-in timeout of 10 seconds */ -bool riscv32_run_stub(target_s *t, uint32_t codeexec, uint32_t param1, uint32_t param2, uint32_t param3, - uint32_t param4) +bool riscv32_run_stub( + target_s *target, uint32_t loadaddr, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4) { - bool ret = false; - uint32_t pc, mie, zero = 0; - // save PC & MIE - t->reg_read(t, RISCV_REG_PC, &pc, 4); - riscv32_target_csr_read(t, RV_CSR_MIE, &mie); - riscv32_target_csr_write(t, RV_CSR_MIE, zero); // disable interrupt - t->reg_write(t, RISCV_REG_A0, ¶m1, 4); - t->reg_write(t, RISCV_REG_A1, ¶m2, 4); - t->reg_write(t, RISCV_REG_A2, ¶m3, 4); - t->reg_write(t, RISCV_REG_A3, ¶m4, 4); - t->reg_write(t, RISCV_REG_PC, &codeexec, 4); - - target_halt_reason_e reason = TARGET_HALT_RUNNING; - t->halt_resume(t, false); // go! - platform_timeout_s timeout; - platform_timeout_set(&timeout, 10000); - while (reason == TARGET_HALT_RUNNING) - { - if (platform_timeout_is_expired(&timeout)) - { - goto the_end; - } - reason = t->halt_poll(t, NULL); - } - - if (reason == TARGET_HALT_ERROR) - { - goto the_end; - } - - if (reason != TARGET_HALT_REQUEST) - { - goto the_end; - } - ret = true; + bool ret = false; + uint32_t pc = 0; + uint32_t mie = 0; + uint32_t zero = 0; + // save PC & MIE + target->reg_read(target, RISCV_REG_PC, &pc, 4); + riscv32_target_csr_read(target, RV_CSR_MIE, &mie); + riscv32_target_csr_write(target, RV_CSR_MIE, zero); // disable interrupt + target->reg_write(target, RISCV_REG_A0, ¶m1, 4); + target->reg_write(target, RISCV_REG_A1, ¶m2, 4); + target->reg_write(target, RISCV_REG_A2, ¶m3, 4); + target->reg_write(target, RISCV_REG_A3, ¶m4, 4); + target->reg_write(target, RISCV_REG_PC, &loadaddr, 4); + + target_halt_reason_e reason = TARGET_HALT_RUNNING; + target->halt_resume(target, false); // go! + platform_timeout_s timeout; + platform_timeout_set(&timeout, 10000); + while (reason == TARGET_HALT_RUNNING) { + if (platform_timeout_is_expired(&timeout)) { + goto the_end; + } + reason = target->halt_poll(target, NULL); + } + + if (reason == TARGET_HALT_ERROR) { + goto the_end; + } + + if (reason != TARGET_HALT_REQUEST) { + goto the_end; + } + ret = true; the_end: - t->halt_request(t); - if (ret) - { - uint32_t a0; - t->reg_read(t, RISCV_REG_A0, &a0, 4); - ret = (a0 == 0); - } - // restore PC & MIE - riscv32_target_csr_write(t, RV_CSR_MIE, mie); // put back MIE - t->reg_write(t, RISCV_REG_PC, &pc, 4); - return ret; + target->halt_request(target); + if (ret) { + uint32_t a0; + target->reg_read(target, RISCV_REG_A0, &a0, 4); + ret = (a0 == 0); + } + // restore PC & MIE + riscv32_target_csr_write(target, RV_CSR_MIE, mie); // put back MIE + target->reg_write(target, RISCV_REG_PC, &pc, 4); + return ret; } -//---- diff --git a/src/target/riscv_debug.h b/src/target/riscv_debug.h index ec9b6d69fd9..b7de0d3344d 100644 --- a/src/target/riscv_debug.h +++ b/src/target/riscv_debug.h @@ -221,6 +221,14 @@ typedef struct riscv_hart { #define RV_FPU_GDB_OFFSET 33 #define RV_FPU_GDB_CSR_OFFSET 66 +// General purpose registers +#define RISCV_REG_A0 10 +#define RISCV_REG_A1 11 +#define RISCV_REG_A2 12 +#define RISCV_REG_A3 13 +#define RISCV_REG_PC 32 +#define RISCV_REG_SP 2 + void riscv_jtag_dtm_handler(uint8_t dev_index); void riscv_dmi_init(riscv_dmi_s *dmi); riscv_hart_s *riscv_hart_struct(target_s *target); From f0d6406fd97e73b62f4a33c17bce251ffced08b1 Mon Sep 17 00:00:00 2001 From: mean Date: Sun, 18 Feb 2024 16:53:36 +0100 Subject: [PATCH 3/4] fixup : fix comment style --- src/target/riscv32.c | 28 ++++++++++++++-------------- src/target/riscv_debug.h | 16 ++++++++-------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/target/riscv32.c b/src/target/riscv32.c index 0d7536c3c3d..edf34a2bd90 100644 --- a/src/target/riscv32.c +++ b/src/target/riscv32.c @@ -671,9 +671,9 @@ static int riscv32_breakwatch_clear(target_s *const target, breakwatch_s *const } /* - Small helper function to translate target to hart and simplify parameters - We assume it is 32 bits -*/ + * Small helper function to translate target to hart and simplify parameters + * We assume it is 32 bits + */ static inline bool riscv32_target_csr_write(target_s *target, const uint16_t reg, uint32_t val) { riscv_hart_s *const hart = riscv_hart_struct(target); @@ -681,9 +681,9 @@ static inline bool riscv32_target_csr_write(target_s *target, const uint16_t reg } /* - Small helper function to translate target to hart and simplify parameters - We assume it is 32 bits -*/ + * Small helper function to translate target to hart and simplify parameters + * We assume it is 32 bits + */ static inline bool riscv32_target_csr_read(target_s *target, const uint16_t reg, uint32_t *val) { riscv_hart_s *const hart = riscv_hart_struct(target); @@ -691,14 +691,14 @@ static inline bool riscv32_target_csr_read(target_s *target, const uint16_t reg, } /* - Execute code on the target with the signature void function(a,b,c,d) - - codexec is the address the code to tun is located at - - param1/2/3/4 will end up as the 4 parameters of the stub function - - The flashstub must not use the stack at all. - It returns true on success, false on error - There is a built-in timeout of 10 seconds -*/ + * Execute code on the target with the signature void function(a,b,c,d) + * - codexec is the address the code to tun is located at + * - param1/2/3/4 will end up as the 4 parameters of the stub function + * + * The flashstub must not use the stack at all. + * It returns true on success, false on error + * There is a built-in timeout of 10 seconds + */ bool riscv32_run_stub( target_s *target, uint32_t loadaddr, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4) { diff --git a/src/target/riscv_debug.h b/src/target/riscv_debug.h index b7de0d3344d..e235bead50c 100644 --- a/src/target/riscv_debug.h +++ b/src/target/riscv_debug.h @@ -250,14 +250,14 @@ void riscv32_mem_read(target_s *target, void *dest, target_addr_t src, size_t le void riscv32_mem_write(target_s *target, target_addr_t dest, const void *src, size_t len); /* - Execute code on the target with the signature void stub_function(a,b,c,d) - - codexec is the address the code to run is located at - - param1/2/3/4 will end up as the 4 parameters of the stub function - - The flashstub must not use the stack at all. - The flashstub must return 0 on success, not 0 on error - There is a built-in timeout of 10 seconds -*/ + * Execute code on the target with the signature void stub_function(a,b,c,d) + * - codexec is the address the code to run is located at + * - param1/2/3/4 will end up as the 4 parameters of the stub function + * + * The flashstub must not use the stack at all. + * The flashstub must return 0 on success, not 0 on error + * There is a built-in timeout of 10 seconds + */ bool riscv32_run_stub(target_s *target, uint32_t loadaddr, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3); #endif /*TARGET_RISCV_DEBUG_H*/ From 15b9a29a28b1f2b47aea961c3011e8b258703946 Mon Sep 17 00:00:00 2001 From: mean Date: Sun, 18 Feb 2024 17:25:17 +0100 Subject: [PATCH 4/4] fixup: simplify error logic --- src/target/riscv32.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/target/riscv32.c b/src/target/riscv32.c index edf34a2bd90..2b1119769ce 100644 --- a/src/target/riscv32.c +++ b/src/target/riscv32.c @@ -716,26 +716,25 @@ bool riscv32_run_stub( target->reg_write(target, RISCV_REG_A3, ¶m4, 4); target->reg_write(target, RISCV_REG_PC, &loadaddr, 4); - target_halt_reason_e reason = TARGET_HALT_RUNNING; target->halt_resume(target, false); // go! platform_timeout_s timeout; platform_timeout_set(&timeout, 10000); + target_halt_reason_e reason = TARGET_HALT_RUNNING; while (reason == TARGET_HALT_RUNNING) { if (platform_timeout_is_expired(&timeout)) { - goto the_end; + reason = TARGET_HALT_ERROR; + break; } reason = target->halt_poll(target, NULL); } - - if (reason == TARGET_HALT_ERROR) { - goto the_end; - } - - if (reason != TARGET_HALT_REQUEST) { - goto the_end; + switch (reason) { + case TARGET_HALT_REQUEST: + ret = true; + break; + case TARGET_HALT_ERROR: // room left here for more detailed handling + default: + break; } - ret = true; -the_end: target->halt_request(target); if (ret) { uint32_t a0;