From 59bc761d56f9ce9a76c917e267a2c37f1a680611 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sat, 21 Jan 2023 20:10:21 +0100 Subject: [PATCH 01/50] rtos: add custom stack read function This is optional field for the targets which has to implement their custom stack read function. Signed-off-by: Erhan Kurubas Change-Id: Icbc9ed66a052fc2cc0ef67e3ec4d85ab0c2c1b94 Reviewed-on: https://review.openocd.org/c/openocd/+/7442 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/rtos.c | 5 ++++- src/rtos/rtos.h | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 2e76b501ae..dfa158d016 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -632,7 +632,10 @@ int rtos_generic_stack_read(struct target *target, if (stacking->stack_growth_direction == 1) address -= stacking->stack_registers_size; - retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data); + if (stacking->read_stack) + retval = stacking->read_stack(target, address, stacking, stack_data); + else + retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data); if (retval != ERROR_OK) { free(stack_data); LOG_ERROR("Error reading stack frame from thread"); diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index ace57514af..9128c163c7 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -102,6 +102,13 @@ struct rtos_register_stacking { const struct rtos_register_stacking *stacking, target_addr_t stack_ptr); const struct stack_register_offset *register_offsets; + /* Optional field for targets which may have to implement their own stack read function. + * Because stack format can be weird or stack data needed to be edited before passing to the gdb. + */ + int (*read_stack)(struct target *target, + int64_t stack_ptr, + const struct rtos_register_stacking *stacking, + uint8_t *stack_data); }; #define GDB_THREAD_PACKET_NOT_CONSUMED (-40) From cf50bcb841238726697dc1250d6b6cb49fc6d19d Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sat, 21 Jan 2023 20:23:07 +0100 Subject: [PATCH 02/50] rtos/nuttx: add stacking info for Espressif Xtensa chips ESP32, ESP32-S2 and ESP32-S3 stack register offsets added Signed-off-by: Erhan Kurubas Change-Id: Ic6215c1d0152853fd08f82cbd3c138c7d62dbc46 Reviewed-on: https://review.openocd.org/c/openocd/+/7443 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/rtos_nuttx_stackings.c | 358 ++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) diff --git a/src/rtos/rtos_nuttx_stackings.c b/src/rtos/rtos_nuttx_stackings.c index b59b1356b9..b70cccb33a 100644 --- a/src/rtos/rtos_nuttx_stackings.c +++ b/src/rtos/rtos_nuttx_stackings.c @@ -108,3 +108,361 @@ const struct rtos_register_stacking nuttx_riscv_stacking = { .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = nuttx_stack_offsets_riscv, }; + +static int nuttx_esp_xtensa_stack_read(struct target *target, + int64_t stack_ptr, const struct rtos_register_stacking *stacking, + uint8_t *stack_data) +{ + int retval = target_read_buffer(target, stack_ptr, stacking->stack_registers_size, stack_data); + if (retval != ERROR_OK) + return retval; + + stack_data[4] &= ~0x10; /* Clear exception bit in PS */ + + return ERROR_OK; +} + +static const struct stack_register_offset nuttx_stack_offsets_esp32[] = { + { 0, 0x00, 32 }, /* PC */ + { 1, 0x08, 32 }, /* A0 */ + { 2, 0x0c, 32 }, /* A1 */ + { 3, 0x10, 32 }, /* A2 */ + { 4, 0x14, 32 }, /* A3 */ + { 5, 0x18, 32 }, /* A4 */ + { 6, 0x1c, 32 }, /* A5 */ + { 7, 0x20, 32 }, /* A6 */ + { 8, 0x24, 32 }, /* A7 */ + { 9, 0x28, 32 }, /* A8 */ + { 10, 0x2c, 32 }, /* A9 */ + { 11, 0x30, 32 }, /* A10 */ + { 12, 0x34, 32 }, /* A11 */ + { 13, 0x38, 32 }, /* A12 */ + { 14, 0x3c, 32 }, /* A13 */ + { 15, 0x40, 32 }, /* A14 */ + { 16, 0x44, 32 }, /* A15 */ + /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ + { 17, -1, 32 }, /* A16 */ + { 18, -1, 32 }, /* A17 */ + { 19, -1, 32 }, /* A18 */ + { 20, -1, 32 }, /* A19 */ + { 21, -1, 32 }, /* A20 */ + { 22, -1, 32 }, /* A21 */ + { 23, -1, 32 }, /* A22 */ + { 24, -1, 32 }, /* A23 */ + { 25, -1, 32 }, /* A24 */ + { 26, -1, 32 }, /* A25 */ + { 27, -1, 32 }, /* A26 */ + { 28, -1, 32 }, /* A27 */ + { 29, -1, 32 }, /* A28 */ + { 30, -1, 32 }, /* A29 */ + { 31, -1, 32 }, /* A30 */ + { 32, -1, 32 }, /* A31 */ + { 33, -1, 32 }, /* A32 */ + { 34, -1, 32 }, /* A33 */ + { 35, -1, 32 }, /* A34 */ + { 36, -1, 32 }, /* A35 */ + { 37, -1, 32 }, /* A36 */ + { 38, -1, 32 }, /* A37 */ + { 39, -1, 32 }, /* A38 */ + { 40, -1, 32 }, /* A39 */ + { 41, -1, 32 }, /* A40 */ + { 42, -1, 32 }, /* A41 */ + { 43, -1, 32 }, /* A42 */ + { 44, -1, 32 }, /* A43 */ + { 45, -1, 32 }, /* A44 */ + { 46, -1, 32 }, /* A45 */ + { 47, -1, 32 }, /* A46 */ + { 48, -1, 32 }, /* A47 */ + { 49, -1, 32 }, /* A48 */ + { 50, -1, 32 }, /* A49 */ + { 51, -1, 32 }, /* A50 */ + { 52, -1, 32 }, /* A51 */ + { 53, -1, 32 }, /* A52 */ + { 54, -1, 32 }, /* A53 */ + { 55, -1, 32 }, /* A54 */ + { 56, -1, 32 }, /* A55 */ + { 57, -1, 32 }, /* A56 */ + { 58, -1, 32 }, /* A57 */ + { 59, -1, 32 }, /* A58 */ + { 60, -1, 32 }, /* A59 */ + { 61, -1, 32 }, /* A60 */ + { 62, -1, 32 }, /* A61 */ + { 63, -1, 32 }, /* A62 */ + { 64, -1, 32 }, /* A63 */ + { 65, 0x58, 32 }, /* lbeg */ + { 66, 0x5c, 32 }, /* lend */ + { 67, 0x60, 32 }, /* lcount */ + { 68, 0x48, 32 }, /* SAR */ + { 69, -1, 32 }, /* windowbase */ + { 70, -1, 32 }, /* windowstart */ + { 71, -1, 32 }, /* configid0 */ + { 72, -1, 32 }, /* configid1 */ + { 73, 0x04, 32 }, /* PS */ + { 74, -1, 32 }, /* threadptr */ + { 75, -1, 32 }, /* br */ + { 76, 0x54, 32 }, /* scompare1 */ + { 77, -1, 32 }, /* acclo */ + { 78, -1, 32 }, /* acchi */ + { 79, -1, 32 }, /* m0 */ + { 80, -1, 32 }, /* m1 */ + { 81, -1, 32 }, /* m2 */ + { 82, -1, 32 }, /* m3 */ + { 83, -1, 32 }, /* expstate */ + { 84, -1, 32 }, /* f64r_lo */ + { 85, -1, 32 }, /* f64r_hi */ + { 86, -1, 32 }, /* f64s */ + { 87, -1, 32 }, /* f0 */ + { 88, -1, 32 }, /* f1 */ + { 89, -1, 32 }, /* f2 */ + { 90, -1, 32 }, /* f3 */ + { 91, -1, 32 }, /* f4 */ + { 92, -1, 32 }, /* f5 */ + { 93, -1, 32 }, /* f6 */ + { 94, -1, 32 }, /* f7 */ + { 95, -1, 32 }, /* f8 */ + { 96, -1, 32 }, /* f9 */ + { 97, -1, 32 }, /* f10 */ + { 98, -1, 32 }, /* f11 */ + { 99, -1, 32 }, /* f12 */ + { 100, -1, 32 }, /* f13 */ + { 101, -1, 32 }, /* f14 */ + { 102, -1, 32 }, /* f15 */ + { 103, -1, 32 }, /* fcr */ + { 104, -1, 32 }, /* fsr */ +}; + +const struct rtos_register_stacking nuttx_esp32_stacking = { + .stack_registers_size = 26 * 4, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32), + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = nuttx_stack_offsets_esp32, + .read_stack = nuttx_esp_xtensa_stack_read, +}; + +static const struct stack_register_offset nuttx_stack_offsets_esp32s2[] = { + { 0, 0x00, 32 }, /* PC */ + { 1, 0x08, 32 }, /* A0 */ + { 2, 0x0c, 32 }, /* A1 */ + { 3, 0x10, 32 }, /* A2 */ + { 4, 0x14, 32 }, /* A3 */ + { 5, 0x18, 32 }, /* A4 */ + { 6, 0x1c, 32 }, /* A5 */ + { 7, 0x20, 32 }, /* A6 */ + { 8, 0x24, 32 }, /* A7 */ + { 9, 0x28, 32 }, /* A8 */ + { 10, 0x2c, 32 }, /* A9 */ + { 11, 0x30, 32 }, /* A10 */ + { 12, 0x34, 32 }, /* A11 */ + { 13, 0x38, 32 }, /* A12 */ + { 14, 0x3c, 32 }, /* A13 */ + { 15, 0x40, 32 }, /* A14 */ + { 16, 0x44, 32 }, /* A15 */ + /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ + { 17, -1, 32 }, /* A16 */ + { 18, -1, 32 }, /* A17 */ + { 19, -1, 32 }, /* A18 */ + { 20, -1, 32 }, /* A19 */ + { 21, -1, 32 }, /* A20 */ + { 22, -1, 32 }, /* A21 */ + { 23, -1, 32 }, /* A22 */ + { 24, -1, 32 }, /* A23 */ + { 25, -1, 32 }, /* A24 */ + { 26, -1, 32 }, /* A25 */ + { 27, -1, 32 }, /* A26 */ + { 28, -1, 32 }, /* A27 */ + { 29, -1, 32 }, /* A28 */ + { 30, -1, 32 }, /* A29 */ + { 31, -1, 32 }, /* A30 */ + { 32, -1, 32 }, /* A31 */ + { 33, -1, 32 }, /* A32 */ + { 34, -1, 32 }, /* A33 */ + { 35, -1, 32 }, /* A34 */ + { 36, -1, 32 }, /* A35 */ + { 37, -1, 32 }, /* A36 */ + { 38, -1, 32 }, /* A37 */ + { 39, -1, 32 }, /* A38 */ + { 40, -1, 32 }, /* A39 */ + { 41, -1, 32 }, /* A40 */ + { 42, -1, 32 }, /* A41 */ + { 43, -1, 32 }, /* A42 */ + { 44, -1, 32 }, /* A43 */ + { 45, -1, 32 }, /* A44 */ + { 46, -1, 32 }, /* A45 */ + { 47, -1, 32 }, /* A46 */ + { 48, -1, 32 }, /* A47 */ + { 49, -1, 32 }, /* A48 */ + { 50, -1, 32 }, /* A49 */ + { 51, -1, 32 }, /* A50 */ + { 52, -1, 32 }, /* A51 */ + { 53, -1, 32 }, /* A52 */ + { 54, -1, 32 }, /* A53 */ + { 55, -1, 32 }, /* A54 */ + { 56, -1, 32 }, /* A55 */ + { 57, -1, 32 }, /* A56 */ + { 58, -1, 32 }, /* A57 */ + { 59, -1, 32 }, /* A58 */ + { 60, -1, 32 }, /* A59 */ + { 61, -1, 32 }, /* A60 */ + { 62, -1, 32 }, /* A61 */ + { 63, -1, 32 }, /* A62 */ + { 64, -1, 32 }, /* A63 */ + { 65, 0x48, 32 }, /* SAR */ + { 66, -1, 32 }, /* windowbase */ + { 67, -1, 32 }, /* windowstart */ + { 68, -1, 32 }, /* configid0 */ + { 69, -1, 32 }, /* configid1 */ + { 70, 0x04, 32 }, /* PS */ + { 71, -1, 32 }, /* threadptr */ + { 72, -1, 32 }, /* gpio_out */ +}; + +const struct rtos_register_stacking nuttx_esp32s2_stacking = { + .stack_registers_size = 25 * 4, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s2), + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = nuttx_stack_offsets_esp32s2, + .read_stack = nuttx_esp_xtensa_stack_read, +}; + +static const struct stack_register_offset nuttx_stack_offsets_esp32s3[] = { + { 0, 0x00, 32 }, /* PC */ + { 1, 0x08, 32 }, /* A0 */ + { 2, 0x0c, 32 }, /* A1 */ + { 3, 0x10, 32 }, /* A2 */ + { 4, 0x14, 32 }, /* A3 */ + { 5, 0x18, 32 }, /* A4 */ + { 6, 0x1c, 32 }, /* A5 */ + { 7, 0x20, 32 }, /* A6 */ + { 8, 0x24, 32 }, /* A7 */ + { 9, 0x28, 32 }, /* A8 */ + { 10, 0x2c, 32 }, /* A9 */ + { 11, 0x30, 32 }, /* A10 */ + { 12, 0x34, 32 }, /* A11 */ + { 13, 0x38, 32 }, /* A12 */ + { 14, 0x3c, 32 }, /* A13 */ + { 15, 0x40, 32 }, /* A14 */ + { 16, 0x44, 32 }, /* A15 */ + /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ + { 17, -1, 32 }, /* A16 */ + { 18, -1, 32 }, /* A17 */ + { 19, -1, 32 }, /* A18 */ + { 20, -1, 32 }, /* A19 */ + { 21, -1, 32 }, /* A20 */ + { 22, -1, 32 }, /* A21 */ + { 23, -1, 32 }, /* A22 */ + { 24, -1, 32 }, /* A23 */ + { 25, -1, 32 }, /* A24 */ + { 26, -1, 32 }, /* A25 */ + { 27, -1, 32 }, /* A26 */ + { 28, -1, 32 }, /* A27 */ + { 29, -1, 32 }, /* A28 */ + { 30, -1, 32 }, /* A29 */ + { 31, -1, 32 }, /* A30 */ + { 32, -1, 32 }, /* A31 */ + { 33, -1, 32 }, /* A32 */ + { 34, -1, 32 }, /* A33 */ + { 35, -1, 32 }, /* A34 */ + { 36, -1, 32 }, /* A35 */ + { 37, -1, 32 }, /* A36 */ + { 38, -1, 32 }, /* A37 */ + { 39, -1, 32 }, /* A38 */ + { 40, -1, 32 }, /* A39 */ + { 41, -1, 32 }, /* A40 */ + { 42, -1, 32 }, /* A41 */ + { 43, -1, 32 }, /* A42 */ + { 44, -1, 32 }, /* A43 */ + { 45, -1, 32 }, /* A44 */ + { 46, -1, 32 }, /* A45 */ + { 47, -1, 32 }, /* A46 */ + { 48, -1, 32 }, /* A47 */ + { 49, -1, 32 }, /* A48 */ + { 50, -1, 32 }, /* A49 */ + { 51, -1, 32 }, /* A50 */ + { 52, -1, 32 }, /* A51 */ + { 53, -1, 32 }, /* A52 */ + { 54, -1, 32 }, /* A53 */ + { 55, -1, 32 }, /* A54 */ + { 56, -1, 32 }, /* A55 */ + { 57, -1, 32 }, /* A56 */ + { 58, -1, 32 }, /* A57 */ + { 59, -1, 32 }, /* A58 */ + { 60, -1, 32 }, /* A59 */ + { 61, -1, 32 }, /* A60 */ + { 62, -1, 32 }, /* A61 */ + { 63, -1, 32 }, /* A62 */ + { 64, -1, 32 }, /* A63 */ + { 65, 0x58, 32 }, /* lbeg */ + { 66, 0x5c, 32 }, /* lend */ + { 67, 0x60, 32 }, /* lcount */ + { 68, 0x48, 32 }, /* SAR */ + { 69, -1, 32 }, /* windowbase */ + { 70, -1, 32 }, /* windowstart */ + { 71, -1, 32 }, /* configid0 */ + { 72, -1, 32 }, /* configid1 */ + { 73, 0x04, 32 }, /* PS */ + { 74, -1, 32 }, /* threadptr */ + { 75, -1, 32 }, /* br */ + { 76, 0x54, 32 }, /* scompare1 */ + { 77, -1, 32 }, /* acclo */ + { 78, -1, 32 }, /* acchi */ + { 79, -1, 32 }, /* m0 */ + { 80, -1, 32 }, /* m1 */ + { 81, -1, 32 }, /* m2 */ + { 82, -1, 32 }, /* m3 */ + { 83, -1, 32 }, /* gpio_out */ + { 84, -1, 32 }, /* f0 */ + { 85, -1, 32 }, /* f1 */ + { 86, -1, 32 }, /* f2 */ + { 87, -1, 32 }, /* f3 */ + { 88, -1, 32 }, /* f4 */ + { 89, -1, 32 }, /* f5 */ + { 90, -1, 32 }, /* f6 */ + { 91, -1, 32 }, /* f7 */ + { 92, -1, 32 }, /* f8 */ + { 93, -1, 32 }, /* f9 */ + { 94, -1, 32 }, /* f10 */ + { 95, -1, 32 }, /* f11 */ + { 96, -1, 32 }, /* f12 */ + { 97, -1, 32 }, /* f13 */ + { 98, -1, 32 }, /* f14 */ + { 99, -1, 32 }, /* f15 */ + { 100, -1, 32 }, /* fcr */ + { 101, -1, 32 }, /* fsr */ + { 102, -1, 32 }, /* accx_0 */ + { 103, -1, 32 }, /* accx_1 */ + { 104, -1, 32 }, /* qacc_h_0 */ + { 105, -1, 32 }, /* qacc_h_1 */ + { 106, -1, 32 }, /* qacc_h_2 */ + { 107, -1, 32 }, /* qacc_h_3 */ + { 108, -1, 32 }, /* qacc_h_4 */ + { 109, -1, 32 }, /* qacc_l_0 */ + { 110, -1, 32 }, /* qacc_l_1 */ + { 111, -1, 32 }, /* qacc_l_2 */ + { 112, -1, 32 }, /* qacc_l_3 */ + { 113, -1, 32 }, /* qacc_l_4 */ + { 114, -1, 32 }, /* sar_byte */ + { 115, -1, 32 }, /* fft_bit_width */ + { 116, -1, 32 }, /* ua_state_0 */ + { 117, -1, 32 }, /* ua_state_1 */ + { 118, -1, 32 }, /* ua_state_2 */ + { 119, -1, 32 }, /* ua_state_3 */ + { 120, -1, 128 }, /* q0 */ + { 121, -1, 128 }, /* q1 */ + { 122, -1, 128 }, /* q2 */ + { 123, -1, 128 }, /* q3 */ + { 124, -1, 128 }, /* q4 */ + { 125, -1, 128 }, /* q5 */ + { 126, -1, 128 }, /* q6 */ + { 127, -1, 128 }, /* q7 */ +}; + +const struct rtos_register_stacking nuttx_esp32s3_stacking = { + .stack_registers_size = 26 * 4, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s3), + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = nuttx_stack_offsets_esp32s3, + .read_stack = nuttx_esp_xtensa_stack_read, +}; From 43c8aa28cb1570c11e1099c43e685af228190679 Mon Sep 17 00:00:00 2001 From: Andreas Fritiofson Date: Fri, 15 Apr 2016 12:38:43 +0200 Subject: [PATCH 03/50] rtos: Support rt-kernel Works for the proprietary rt-kernel from rt-labs. See: https://rt-labs.com/product/rt-kernel/ Change-Id: Id2c2e292c15fb17eab25e3d07db05014daa2a2b0 Signed-off-by: Andreas Fritiofson Reviewed-on: https://review.openocd.org/c/openocd/+/6668 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 5 +- src/rtos/Makefile.am | 1 + src/rtos/rtkernel.c | 384 +++++++++++++++++++++++++++++++++++++++++++ src/rtos/rtos.c | 2 + 4 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 src/rtos/rtkernel.c diff --git a/doc/openocd.texi b/doc/openocd.texi index b9ad3ff77d..6c853f2ce4 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5000,7 +5000,7 @@ The value should normally correspond to a static mapping for the @var{rtos_type} can be one of @option{auto}, @option{none}, @option{eCos}, @option{ThreadX}, @option{FreeRTOS}, @option{linux}, @option{ChibiOS}, @option{embKernel}, @option{mqx}, @option{uCOS-III}, @option{nuttx}, -@option{RIOT}, @option{Zephyr} +@option{RIOT}, @option{Zephyr}, @option{rtkernel} @xref{gdbrtossupport,,RTOS Support}. @item @code{-defer-examine} -- skip target examination at initial JTAG chain @@ -11867,6 +11867,7 @@ Currently supported rtos's include: @item @option{RIOT} @item @option{hwthread} (This is not an actual RTOS. @xref{usingopenocdsmpwithgdb,,Using OpenOCD SMP with GDB}.) @item @option{Zephyr} +@item @option{rtkernel} @end itemize At any time, it's possible to drop the selected RTOS using: @@ -11908,6 +11909,8 @@ _tcb_name_offset. @end raggedright @item Zephyr symbols _kernel, _kernel_openocd_offsets, _kernel_openocd_size_t_size +@item rtkernel symbols +Multiple struct offsets. @end table For most RTOS supported the above symbols will be exported by default. However for diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index fc3ab8b421..b0f7daf5f4 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -21,6 +21,7 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/mqx.c \ %D%/uCOS-III.c \ %D%/nuttx.c \ + %D%/rtkernel.c \ %D%/hwthread.c \ %D%/zephyr.c \ %D%/riot.c \ diff --git a/src/rtos/rtkernel.c b/src/rtos/rtkernel.c new file mode 100644 index 0000000000..ba1de25172 --- /dev/null +++ b/src/rtos/rtkernel.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2016-2023 by Andreas Fritiofson * + * andreas.fritiofson@gmail.com * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "target/target.h" +#include "target/target_type.h" +#include "rtos.h" +#include "helper/log.h" +#include "helper/types.h" +#include "rtos_standard_stackings.h" +#include "target/armv7m.h" +#include "target/cortex_m.h" + +#define ST_DEAD BIT(0) /* Task is waiting to be deleted */ +#define ST_WAIT BIT(1) /* Task is blocked: */ +#define ST_SEM BIT(2) /* on semaphore */ +#define ST_MTX BIT(3) /* on mutex */ +#define ST_SIG BIT(4) /* on signal */ +#define ST_DLY BIT(5) /* on timer */ +#define ST_FLAG BIT(6) /* on flag */ +#define ST_FLAG_ALL BIT(7) /* on flag and flag mode is "ALL" */ +#define ST_MBOX BIT(8) /* on mailbox */ +#define ST_STP BIT(9) /* self stopped */ +#define ST_SUSPEND BIT(10) /* Task is suspended */ +#define ST_TT BIT(11) /* Time triggered task */ +#define ST_TT_YIELD BIT(12) /* Time triggered task that yields */ +#define ST_CREATE BIT(13) /* Task was created by task_create() */ + +struct rtkernel_params { + const char *target_name; + const struct rtos_register_stacking *stacking_info_cm3; + const struct rtos_register_stacking *stacking_info_cm4f; + const struct rtos_register_stacking *stacking_info_cm4f_fpu; +}; + +static const struct rtkernel_params rtkernel_params_list[] = { + { + "cortex_m", /* target_name */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + &rtos_standard_cortex_m4f_stacking, + &rtos_standard_cortex_m4f_fpu_stacking, + }, + { + "hla_target", /* target_name */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + &rtos_standard_cortex_m4f_stacking, + &rtos_standard_cortex_m4f_fpu_stacking, + }, +}; + +enum rtkernel_symbol_values { + sym_os_state = 0, + sym___off_os_state2chain = 1, + sym___off_os_state2current = 2, + sym___off_task2chain = 3, + sym___off_task2magic = 4, + sym___off_task2stack = 5, + sym___off_task2state = 6, + sym___off_task2name = 7, + sym___val_task_magic = 8, +}; + +struct symbols { + const char *name; + bool optional; +}; + +static const struct symbols rtkernel_symbol_list[] = { + { "os_state", false }, + { "__off_os_state2chain", false }, + { "__off_os_state2current", false }, + { "__off_task2chain", false }, + { "__off_task2magic", false }, + { "__off_task2stack", false }, + { "__off_task2state", false }, + { "__off_task2name", false }, + { "__val_task_magic", false }, + { NULL, false } +}; + +static void *realloc_preserve(void *ptr, size_t old_size, size_t new_size) +{ + void *new_ptr = malloc(new_size); + + if (new_ptr) { + memcpy(new_ptr, ptr, MIN(old_size, new_size)); + free(ptr); + } + + return new_ptr; +} + +static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task) +{ + int retval; + int new_thread_count = rtos->thread_count + 1; + struct thread_detail *new_thread_details = realloc_preserve(rtos->thread_details, + rtos->thread_count * sizeof(struct thread_detail), + new_thread_count * sizeof(struct thread_detail)); + if (!new_thread_details) { + LOG_ERROR("Error growing memory to %d threads", new_thread_count); + return ERROR_FAIL; + } + rtos->thread_details = new_thread_details; + struct thread_detail *thread = &new_thread_details[rtos->thread_count]; + + *thread = (struct thread_detail){ .threadid = task, .exists = true }; + + /* Read the task name */ + uint32_t name; + retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2name].address, &name); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read task name pointer from target"); + return retval; + } + uint8_t tmp_str[33]; + retval = target_read_buffer(rtos->target, name, sizeof(tmp_str) - 1, tmp_str); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading task name from target"); + return retval; + } + tmp_str[sizeof(tmp_str) - 1] = '\0'; + LOG_DEBUG("task name at 0x%" PRIx32 ", value \"%s\"", name, tmp_str); + + if (tmp_str[0] != '\0') + thread->thread_name_str = strdup((char *)tmp_str); + else + thread->thread_name_str = strdup("No Name"); + + /* Read the task state */ + uint16_t state; + retval = target_read_u16(rtos->target, task + rtos->symbols[sym___off_task2state].address, &state); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read task state from target"); + return retval; + } + + LOG_DEBUG("task state 0x%" PRIx16, state); + + char state_str[64] = ""; + if (state & ST_TT) + strcat(state_str, "TT|"); + if (task == current_task) { + strcat(state_str, "RUN"); + } else { + if (state & (ST_TT | ST_TT_YIELD)) + strcat(state_str, "YIELD"); + else if (state & ST_DEAD) + strcat(state_str, "DEAD"); + else if (state & ST_WAIT) + strcat(state_str, "WAIT"); + else if (state & ST_SUSPEND) + strcat(state_str, "SUSP"); + else + strcat(state_str, "READY"); + } + if (state & ST_SEM) + strcat(state_str, "|SEM"); + if (state & ST_MTX) + strcat(state_str, "|MTX"); + if (state & ST_SIG) + strcat(state_str, "|SIG"); + if (state & ST_DLY) + strcat(state_str, "|DLY"); + if ((state & ST_FLAG) || (state & ST_FLAG_ALL)) + strcat(state_str, "|FLAG"); + if (state & ST_FLAG_ALL) + strcat(state_str, "_ALL"); + if (state & ST_MBOX) + strcat(state_str, "|MBOX"); + if (state & ST_STP) + strcat(state_str, "|STP"); + + thread->extra_info_str = strdup(state_str); + + rtos->thread_count = new_thread_count; + if (task == current_task) + rtos->current_thread = task; + return ERROR_OK; +} + +static int rtkernel_verify_task(struct rtos *rtos, uint32_t task) +{ + int retval; + uint32_t magic; + retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2magic].address, &magic); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read task magic from target"); + return retval; + } + if (magic != rtos->symbols[sym___val_task_magic].address) { + LOG_ERROR("Invalid task found (magic=0x%" PRIx32 ")", magic); + return ERROR_FAIL; + } + return retval; +} + +static int rtkernel_update_threads(struct rtos *rtos) +{ + /* wipe out previous thread details if any */ + /* do this first because rtos layer does not check our retval */ + rtos_free_threadlist(rtos); + rtos->current_thread = 0; + + if (!rtos->symbols) { + LOG_ERROR("No symbols for rt-kernel"); + return -3; + } + + /* read the current task */ + uint32_t current_task; + int retval = target_read_u32(rtos->target, + rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2current].address, + ¤t_task); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading current task"); + return retval; + } + LOG_DEBUG("current task is 0x%" PRIx32, current_task); + + retval = rtkernel_verify_task(rtos, current_task); + if (retval != ERROR_OK) { + LOG_ERROR("Current task is invalid"); + return retval; + } + + /* loop through kernel task list */ + uint32_t chain = rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2chain].address; + LOG_DEBUG("chain start at 0x%" PRIx32, chain); + + uint32_t next = chain; + for (;;) { + retval = target_read_u32(rtos->target, next, &next); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read rt-kernel data structure from target"); + return retval; + } + LOG_DEBUG("next entry at 0x%" PRIx32, next); + if (next == chain) { + LOG_DEBUG("end of chain detected"); + break; + } + uint32_t task = next - rtos->symbols[sym___off_task2chain].address; + LOG_DEBUG("found task at 0x%" PRIx32, task); + + retval = rtkernel_verify_task(rtos, task); + if (retval != ERROR_OK) { + LOG_ERROR("Invalid task found"); + return retval; + } + + retval = rtkernel_add_task(rtos, task, current_task); + if (retval != ERROR_OK) { + LOG_ERROR("Could not add task to rtos system"); + return retval; + } + } + return ERROR_OK; +} + +static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) +{ + uint32_t stack_ptr = 0; + + if (!rtos) + return -1; + + if (thread_id == 0) + return -2; + + if (!rtos->rtos_specific_params) + return -1; + + const struct rtkernel_params *param = rtos->rtos_specific_params; + + /* Read the stack pointer */ + int retval = target_read_u32(rtos->target, thread_id + rtos->symbols[sym___off_task2stack].address, &stack_ptr); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading stack pointer from rtkernel thread"); + return retval; + } + LOG_DEBUG("stack pointer at 0x%" PRIx64 ", value 0x%" PRIx32, + thread_id + rtos->symbols[sym___off_task2stack].address, + stack_ptr); + + /* Adjust stack pointer to ignore non-standard BASEPRI register stacking */ + stack_ptr += 4; + + /* Check for armv7m with *enabled* FPU, i.e. a Cortex M4F */ + bool cm4_fpu_enabled = false; + struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); + if (is_armv7m(armv7m_target)) { + if (armv7m_target->fp_feature != FP_NONE) { + /* Found ARM v7m target which includes a FPU */ + uint32_t cpacr; + + retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read CPACR register to check FPU state"); + return -1; + } + + /* Check if CP10 and CP11 are set to full access. */ + if (cpacr & 0x00F00000) { + /* Found target with enabled FPU */ + cm4_fpu_enabled = true; + } + } + } + + if (!cm4_fpu_enabled) { + LOG_DEBUG("cm3 stacking"); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs); + } + + /* Read the LR to decide between stacking with or without FPU */ + uint32_t lr_svc; + retval = target_read_u32(rtos->target, stack_ptr + 0x20, &lr_svc); + if (retval != ERROR_OK) { + LOG_OUTPUT("Error reading stack frame from rtkernel thread\r\n"); + return retval; + } + + if ((lr_svc & 0x10) == 0) { + LOG_DEBUG("cm4f_fpu stacking"); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs); + } + + LOG_DEBUG("cm4f stacking"); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs); +} + +static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) +{ + *symbol_list = calloc(ARRAY_SIZE(rtkernel_symbol_list), sizeof(struct symbol_table_elem)); + if (!*symbol_list) + return ERROR_FAIL; + + for (size_t i = 0; i < ARRAY_SIZE(rtkernel_symbol_list); i++) { + (*symbol_list)[i].symbol_name = rtkernel_symbol_list[i].name; + (*symbol_list)[i].optional = rtkernel_symbol_list[i].optional; + } + + return ERROR_OK; +} + +static bool rtkernel_detect_rtos(struct target *target) +{ + return (target->rtos->symbols) && + (target->rtos->symbols[sym___off_os_state2chain].address != 0); +} + +static int rtkernel_create(struct target *target) +{ + for (size_t i = 0; i < ARRAY_SIZE(rtkernel_params_list); i++) { + if (strcmp(rtkernel_params_list[i].target_name, target->type->name) == 0) { + target->rtos->rtos_specific_params = (void *)&rtkernel_params_list[i]; + return 0; + } + } + + LOG_ERROR("Could not find target in rt-kernel compatibility list"); + return -1; +} + +const struct rtos_type rtkernel_rtos = { + .name = "rtkernel", + + .detect_rtos = rtkernel_detect_rtos, + .create = rtkernel_create, + .update_threads = rtkernel_update_threads, + .get_thread_reg_list = rtkernel_get_thread_reg_list, + .get_symbol_list_to_lookup = rtkernel_get_symbol_list_to_lookup, +}; diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index dfa158d016..bcd556a7bf 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -29,6 +29,7 @@ extern struct rtos_type nuttx_rtos; extern struct rtos_type hwthread_rtos; extern struct rtos_type riot_rtos; extern struct rtos_type zephyr_rtos; +extern struct rtos_type rtkernel_rtos; static struct rtos_type *rtos_types[] = { &threadx_rtos, @@ -43,6 +44,7 @@ static struct rtos_type *rtos_types[] = { &nuttx_rtos, &riot_rtos, &zephyr_rtos, + &rtkernel_rtos, /* keep this as last, as it always matches with rtos auto */ &hwthread_rtos, NULL From d032e7ec8c2978feda5df2ca7c4ddbcaec2fcbf5 Mon Sep 17 00:00:00 2001 From: Andreas Fritiofson Date: Mon, 8 Nov 2021 19:35:27 +0100 Subject: [PATCH 04/50] rtos: Fix constness of struct rtos_type Change-Id: Iaa89f2ff4036c23f944ffb4f37fe0c7afaf5069b Signed-off-by: Andreas Fritiofson Reviewed-on: https://review.openocd.org/c/openocd/+/6680 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/FreeRTOS.c | 2 +- src/rtos/chibios.c | 2 +- src/rtos/embKernel.c | 2 +- src/rtos/mqx.c | 2 +- src/rtos/nuttx.c | 2 +- src/rtos/rtos.c | 38 +++++++++++++++++++------------------- src/rtos/zephyr.c | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index 945c4b875c..070275f2c5 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -80,7 +80,7 @@ static int freertos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); -struct rtos_type freertos_rtos = { +const struct rtos_type freertos_rtos = { .name = "FreeRTOS", .detect_rtos = freertos_detect_rtos, diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c index 8319cc883c..68fe8a14c9 100644 --- a/src/rtos/chibios.c +++ b/src/rtos/chibios.c @@ -97,7 +97,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); -struct rtos_type chibios_rtos = { +const struct rtos_type chibios_rtos = { .name = "chibios", .detect_rtos = chibios_detect_rtos, diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index c1b5723fce..a03b039e0c 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -27,7 +27,7 @@ static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); -struct rtos_type embkernel_rtos = { +const struct rtos_type embkernel_rtos = { .name = "embKernel", .detect_rtos = embkernel_detect_rtos, .create = embkernel_create, diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index 8d483ed3bf..d9b694282a 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -498,7 +498,7 @@ static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[] return ERROR_OK; } -struct rtos_type mqx_rtos = { +const struct rtos_type mqx_rtos = { .name = "mqx", .detect_rtos = mqx_detect_rtos, .create = mqx_create, diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 993ff84bde..78271181e2 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -324,7 +324,7 @@ static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list return 0; } -struct rtos_type nuttx_rtos = { +const struct rtos_type nuttx_rtos = { .name = "nuttx", .detect_rtos = nuttx_detect_rtos, .create = nuttx_create, diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index bcd556a7bf..f1e8956a38 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -16,22 +16,22 @@ #include "server/gdb_server.h" /* RTOSs */ -extern struct rtos_type freertos_rtos; -extern struct rtos_type threadx_rtos; -extern struct rtos_type ecos_rtos; -extern struct rtos_type linux_rtos; -extern struct rtos_type chibios_rtos; -extern struct rtos_type chromium_ec_rtos; -extern struct rtos_type embkernel_rtos; -extern struct rtos_type mqx_rtos; -extern struct rtos_type ucos_iii_rtos; -extern struct rtos_type nuttx_rtos; -extern struct rtos_type hwthread_rtos; -extern struct rtos_type riot_rtos; -extern struct rtos_type zephyr_rtos; -extern struct rtos_type rtkernel_rtos; - -static struct rtos_type *rtos_types[] = { +extern const struct rtos_type freertos_rtos; +extern const struct rtos_type threadx_rtos; +extern const struct rtos_type ecos_rtos; +extern const struct rtos_type linux_rtos; +extern const struct rtos_type chibios_rtos; +extern const struct rtos_type chromium_ec_rtos; +extern const struct rtos_type embkernel_rtos; +extern const struct rtos_type mqx_rtos; +extern const struct rtos_type ucos_iii_rtos; +extern const struct rtos_type nuttx_rtos; +extern const struct rtos_type hwthread_rtos; +extern const struct rtos_type riot_rtos; +extern const struct rtos_type zephyr_rtos; +extern const struct rtos_type rtkernel_rtos; + +static const struct rtos_type *rtos_types[] = { &threadx_rtos, &freertos_rtos, &ecos_rtos, @@ -70,7 +70,7 @@ static int rtos_target_for_threadid(struct connection *connection, int64_t threa return ERROR_OK; } -static int os_alloc(struct target *target, struct rtos_type *ostype) +static int os_alloc(struct target *target, const struct rtos_type *ostype) { struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); @@ -100,7 +100,7 @@ static void os_free(struct target *target) target->rtos = NULL; } -static int os_alloc_create(struct target *target, struct rtos_type *ostype) +static int os_alloc_create(struct target *target, const struct rtos_type *ostype) { int ret = os_alloc(target, ostype); @@ -683,7 +683,7 @@ int rtos_generic_stack_read(struct target *target, static int rtos_try_next(struct target *target) { struct rtos *os = target->rtos; - struct rtos_type **type = rtos_types; + const struct rtos_type **type = rtos_types; if (!os) return 0; diff --git a/src/rtos/zephyr.c b/src/rtos/zephyr.c index b00b4b3418..934a8dd1cc 100644 --- a/src/rtos/zephyr.c +++ b/src/rtos/zephyr.c @@ -785,7 +785,7 @@ static int zephyr_get_symbol_list_to_lookup(struct symbol_table_elem **symbol_li return ERROR_OK; } -struct rtos_type zephyr_rtos = { +const struct rtos_type zephyr_rtos = { .name = "Zephyr", .detect_rtos = zephyr_detect_rtos, From 20285b91008106c9fa966cea3269c6f6a81e539a Mon Sep 17 00:00:00 2001 From: N S Date: Fri, 23 Dec 2022 16:59:18 -0800 Subject: [PATCH 05/50] jtag/drivers/openjtag: fix annoying num_cycles > 16 warning The OpenJTAG driver logs "num_cycles > 16 on run test" warning whenever the JTAG_RUNTEST operation cycle count is larger than 16. Instead of logging the warning and only running the first 16 TCLK cycles, remove the warning and queue up multiple operations of up to 16 cycles each. Signed-off-by: N S Change-Id: Id405fa802ff1cf3db7a21e76bd6df0c2d3a0fe61 Reviewed-on: https://review.openocd.org/c/openocd/+/7420 Tested-by: jenkins Reviewed-by: Jonathan McDowell Reviewed-by: Antonio Borneo --- src/jtag/drivers/openjtag.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 6be9507183..12ea463302 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -742,16 +742,18 @@ static void openjtag_execute_runtest(struct jtag_command *cmd) tap_set_state(TAP_IDLE); } - if (cmd->cmd.runtest->num_cycles > 16) - LOG_WARNING("num_cycles > 16 on run test"); - if (openjtag_variant != OPENJTAG_VARIANT_CY7C65215 || cmd->cmd.runtest->num_cycles) { uint8_t command; - command = 7; - command |= ((cmd->cmd.runtest->num_cycles - 1) & 0x0F) << 4; + int cycles = cmd->cmd.runtest->num_cycles; - openjtag_add_byte(command); + do { + command = 7; + command |= (((cycles > 16 ? 16 : cycles) - 1) & 0x0F) << 4; + + openjtag_add_byte(command); + cycles -= 16; + } while (cycles > 0); } tap_set_end_state(end_state); From 148bc7e2151740527b4ca67d0a7c7c9f01725981 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 14 Oct 2022 09:19:29 +0200 Subject: [PATCH 06/50] jtag/drivers/bitbang: avoid mostly harmless glitch on SWDIO bitbang_swd_exchange(rnw=true,...) calls bitbang_interface->swd_write() with swdio clamped to 0. bitbang_swd_write_reg() reads 1 turnaround bit, 3 ack bits and 1 turnaround by one call to bitbang_swd_exchange() and then switches SWDIO to output. AFAIK all bitbang interfaces switch SWDIO GPIO direction immediately in bitbang_interface->swdio_drive(). The GPIO now drives SWDIO line to the value stored in the output register which is always zero from previous bitbang_swd_exchange(rnw=true,...). In case the following data bit (bit 0) is 1 we can observe a glitch on SWDIO: _____ out 1 ____ HiZ/pull-up ----\ / \ / \______ out 0 ______/ swdio_drive(true) swd_write(0,1) The glitch fortunately takes place far enough from SWCLK rising edge where SWDIO is sampled by the target, so I believe it is harmless except some corner cases where the reflected wave is delayed on long line. Anyway keeping electrical signals glitch free is a good practice. To keep performance penalty minimal, pre-write the first data bit to SWDIO GPIO output buffer while clocking the turnaround bit. Following swdio_drive(true) outputs the pre-written value and the same value is rewritten by the next swd_write() instead of glitching SWDIO. Change-Id: I72ea9c0b2fae57e8ff5aa616859182c67abc924f Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7260 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/bitbang.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index 2ab0a2a76c..665dbf329e 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -525,7 +525,19 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay bitbang_swd_exchange(false, &cmd, 0, 8); bitbang_interface->swdio_drive(false); - bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 1); + bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3); + + /* Avoid a glitch on SWDIO when changing the direction to output. + * To keep performance penalty minimal, pre-write the first data + * bit to SWDIO GPIO output buffer while clocking the turnaround bit. + * Following swdio_drive(true) outputs the pre-written value + * and the same value is rewritten by the next swd_write() + * instead of glitching SWDIO + * HiZ/pull-up --------------> 0 -------------> 1 + * swdio_drive(true) swd_write(0,1) + * in case of data bit 0 = 1 + */ + bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 1); bitbang_interface->swdio_drive(true); bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1); From b4dd8dbc37daf073bf6481fdc7f0f9d7f2e96809 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 13 Oct 2022 16:46:31 +0200 Subject: [PATCH 07/50] jtag/drivers/bcm2835gpio: use rounding in delay math After setting adapter speed to some values, the driver shows the real speed little bit higher. Although it does not impose a problem from technical point of view because the difference is smaller than usual speed error, it looks at least strange to the user. The documentation reads that real frequency should be same or lower than requested. Use proper rounding in speed -> delay and delay -> speed conversions. Change-Id: I1831112cc58681875548d2aeb688391fb79fa37f Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7261 Tested-by: jenkins Reviewed-by: Jonathan Bell Reviewed-by: Antonio Borneo --- src/jtag/drivers/bcm2835gpio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 5aa1a99e49..320baba092 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -264,7 +264,8 @@ static int bcm2835gpio_khz(int khz, int *jtag_speed) LOG_DEBUG("BCM2835 GPIO: RCLK not supported"); return ERROR_FAIL; } - *jtag_speed = speed_coeff/khz - speed_offset; + *jtag_speed = DIV_ROUND_UP(speed_coeff, khz) - speed_offset; + LOG_DEBUG("jtag_delay %d", *jtag_speed); if (*jtag_speed < 0) *jtag_speed = 0; return ERROR_OK; @@ -272,7 +273,9 @@ static int bcm2835gpio_khz(int khz, int *jtag_speed) static int bcm2835gpio_speed_div(int speed, int *khz) { - *khz = speed_coeff/(speed + speed_offset); + int divisor = speed + speed_offset; + /* divide with roundig to the closest */ + *khz = (speed_coeff + divisor / 2) / divisor; return ERROR_OK; } From 2dde7e914b429ffa5bc56faa20fb474ca451412e Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 13 Oct 2022 22:33:12 +0200 Subject: [PATCH 08/50] jtag/drivers/bcm2835gpio: refactor delays to inline function No functional change, the delay is unchanged. Change-Id: I5b5e837d741ac01fc573657357c5fe61ad901319 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7262 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/bcm2835gpio.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 320baba092..635d9a5ffc 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -66,6 +66,12 @@ static inline void bcm2835_gpio_synchronize(void) __sync_synchronize(); } +static inline void bcm2835_delay(void) +{ + for (unsigned int i = 0; i < jtag_delay; i++) + asm volatile (""); +} + static bool is_gpio_config_valid(enum adapter_gpio_config_index idx) { /* Only chip 0 is supported, accept unset value (-1) too */ @@ -178,8 +184,7 @@ static int bcm2835gpio_write(int tck, int tms, int tdi) GPIO_CLR = clear; bcm2835_gpio_synchronize(); - for (unsigned int i = 0; i < jtag_delay; i++) - asm volatile (""); + bcm2835_delay(); return ERROR_OK; } @@ -199,8 +204,7 @@ static int bcm2835gpio_swd_write_fast(int swclk, int swdio) GPIO_CLR = clear; bcm2835_gpio_synchronize(); - for (unsigned int i = 0; i < jtag_delay; i++) - asm volatile (""); + bcm2835_delay(); return ERROR_OK; } @@ -211,8 +215,7 @@ static int bcm2835gpio_swd_write_generic(int swclk, int swdio) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio); set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */ - for (unsigned int i = 0; i < jtag_delay; ++i) - asm volatile (""); + bcm2835_delay(); return ERROR_OK; } From bec6c0eb094fb7ca1752688118f41193dc83e026 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 14 Oct 2022 11:16:58 +0200 Subject: [PATCH 09/50] tcl/interface: universal config for all Raspberry Pi models Speed calibration coeffs are computed from cpufreq/scaling_max_freq and from the device-tree compatibility information. Raspberry Pi linux offers /dev/gpiomem for non-root access to the GPIO registers since ~2016. Do not configure 'bcm2835gpio peripheral_base' as it is necessary only if /dev/mem is used - it requires running OpenOCD as root - it's a security risk so it should be avoided. The configuration of the GPIO connector (40-pin header) is factored out and ready to use in interface configuration for other driver (e.g. linux gpiod). Mark raspberrypi2-native.cfg as deprecated and redirect it to raspberrypi-native.cfg Change-Id: Icce856fb660b45374e94174da279feb51f529908 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7264 Tested-by: jenkins Reviewed-by: Jonathan Bell Reviewed-by: Antonio Borneo --- tcl/interface/raspberrypi-gpio-connector.cfg | 42 +++++++++ tcl/interface/raspberrypi-native.cfg | 91 +++++++++++++------- tcl/interface/raspberrypi2-native.cfg | 44 +--------- 3 files changed, 104 insertions(+), 73 deletions(-) create mode 100644 tcl/interface/raspberrypi-gpio-connector.cfg diff --git a/tcl/interface/raspberrypi-gpio-connector.cfg b/tcl/interface/raspberrypi-gpio-connector.cfg new file mode 100644 index 0000000000..eff73fc927 --- /dev/null +++ b/tcl/interface/raspberrypi-gpio-connector.cfg @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Config for Raspberry Pi GPIO header +# +# This is best used with a fast enough buffer but also +# is suitable for direct connection if the target voltage +# matches RPi's 3.3V and the cable is short enough. +# +# Do not forget the GND connection, e.g. pin 20 of the GPIO header. +# + +# GPIO 25 (pin 22) previously used for TMS/SWDIO is pulled-down by default. +# The JTAG/SWD specification requires pull-up at the target board +# for either signal. Connecting the signal pulled-up on the target +# to the pull-down on the adapter is not a good idea. +# GPIO 8 is pulled-up by default. +echo "Warn : TMS/SWDIO moved to GPIO 8 (pin 24). Check the wiring please!" + +# Each of the JTAG lines need a gpio number set: tck tms tdi tdo +# Header pin numbers: 23 24 19 21 +adapter gpio tck -chip 0 11 +adapter gpio tms -chip 0 8 +adapter gpio tdi -chip 0 10 +adapter gpio tdo -chip 0 9 + +# Each of the SWD lines need a gpio number set: swclk swdio +# Header pin numbers: 23 24 +adapter gpio swclk -chip 0 11 +adapter gpio swdio -chip 0 8 + +# If you define trst or srst, use appropriate reset_config +# Header pin numbers: TRST - 26, SRST - 18 + +# adapter gpio trst -chip 0 7 +# reset_config trst_only + +# adapter gpio srst -chip 0 24 +# reset_config srst_only srst_push_pull + +# or if you have both connected, +# reset_config trst_and_srst srst_push_pull diff --git a/tcl/interface/raspberrypi-native.cfg b/tcl/interface/raspberrypi-native.cfg index 02a3563500..95426c2263 100644 --- a/tcl/interface/raspberrypi-native.cfg +++ b/tcl/interface/raspberrypi-native.cfg @@ -1,44 +1,71 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# -# Config for using Raspberry Pi's expansion header -# -# This is best used with a fast enough buffer but also -# is suitable for direct connection if the target voltage -# matches RPi's 3.3V and the cable is short enough. -# -# Do not forget the GND connection, pin 6 of the expansion header. -# +# Config for Raspberry Pi used as a bitbang adapter. +# https://www.raspberrypi.com/documentation/computers/raspberry-pi.html + +# Supports all models with 40-pin or 26-pin GPIO connector up to Raspberry Pi 4 B +# also supports Raspberry Pi Zero, Zero W and Zero 2 W. + +# Adapter speed calibration is computed from cpufreq/scaling_max_freq. +# Adjusts automatically if CPU is overclocked. adapter driver bcm2835gpio -bcm2835gpio peripheral_base 0x20000000 +proc read_file { name } { + if {[catch {open $name r} fd]} { + return "" + } + set result [read $fd] + close $fd + return $result +} -# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET -# These depend on system clock, calibrated for stock 700MHz -# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET -bcm2835gpio speed_coeffs 113714 28 +proc measure_clock {} { + set result [exec vcgencmd measure_clock arm] + set clock_hz [lindex [split $result "="] 1] + expr { $clock_hz / 1000 } +} + +proc get_max_cpu_clock { default } { + set clock [read_file /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq] + if { $clock > 100000 } { + return $clock + } -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -adapter gpio tck -chip 0 11 -adapter gpio tms -chip 0 25 -adapter gpio tdi -chip 0 10 -adapter gpio tdo -chip 0 9 + # cpufreq not available. As the last resort try Broadcom's proprietary utility + if {![catch measure_clock clock] && $clock > 100000} { + return $clock + } -# Each of the SWD lines need a gpio number set: swclk swdio -# Header pin numbers: 23 22 -adapter gpio swclk -chip 0 11 -adapter gpio swdio -chip 0 25 + echo "WARNING: Host CPU clock unknown." + echo "WARNING: Using the highest possible value $default kHz as a safe default." + echo "WARNING: Expect JTAG/SWD clock significantly slower than requested." -# If you define trst or srst, use appropriate reset_config -# Header pin numbers: TRST - 26, SRST - 18 + return $default +} -# adapter gpio trst -chip 0 7 -# reset_config trst_only +set compat [read_file /proc/device-tree/compatible] +set clocks_per_timing_loop 4 -# adapter gpio srst -chip 0 24 -# reset_config srst_only srst_push_pull +if {[string match *bcm2711* $compat]} { + set speed_offset 52 +} elseif {[string match *bcm2837* $compat] || [string match *bcm2710* $compat]} { + set speed_offset 34 +} elseif {[string match *bcm2836* $compat] || [string match *bcm2709* $compat]} { + set speed_offset 36 +} elseif {[string match *bcm2835* $compat] || [string match *bcm2708* $compat]} { + set clocks_per_timing_loop 6 + set speed_offset 32 +} else { + set speed_offset 32 + echo "WARNING: Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested." +} + +set clock [get_max_cpu_clock 2000000] +set speed_coeff [expr { $clock / $clocks_per_timing_loop }] + +# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET +# The coefficients depend on system clock and CPU frequency scaling. +bcm2835gpio speed_coeffs $speed_coeff $speed_offset -# or if you have both connected, -# reset_config trst_and_srst srst_push_pull +source raspberrypi-gpio-connector.cfg diff --git a/tcl/interface/raspberrypi2-native.cfg b/tcl/interface/raspberrypi2-native.cfg index d5edded0f9..fe9186f239 100644 --- a/tcl/interface/raspberrypi2-native.cfg +++ b/tcl/interface/raspberrypi2-native.cfg @@ -1,44 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# -# Config for using Raspberry Pi's expansion header -# -# This is best used with a fast enough buffer but also -# is suitable for direct connection if the target voltage -# matches RPi's 3.3V and the cable is short enough. -# -# Do not forget the GND connection, pin 6 of the expansion header. -# +echo "WARNING: interface/raspberrypi2-native.cfg is deprecated." +echo "WARNING: Please use interface/raspberrypi-native.cfg for all Raspberry Pi models." -adapter driver bcm2835gpio - -bcm2835gpio peripheral_base 0x3F000000 - -# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET -# These depend on system clock, calibrated for scaling_max_freq 900MHz -# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET -bcm2835gpio speed_coeffs 225000 36 - -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -adapter gpio tck -chip 0 11 -adapter gpio tms -chip 0 25 -adapter gpio tdi -chip 0 10 -adapter gpio tdo -chip 0 9 - -# Each of the SWD lines need a gpio number set: swclk swdio -# Header pin numbers: 23 22 -adapter gpio swclk -chip 0 11 -adapter gpio swdio -chip 0 25 - -# If you define trst or srst, use appropriate reset_config -# Header pin numbers: TRST - 26, SRST - 18 - -# adapter gpio trst -chip 0 7 -# reset_config trst_only - -# adapter gpio srst -chip 0 24 -# reset_config srst_only srst_push_pull - -# or if you have both connected, -# reset_config trst_and_srst srst_push_pull +source [find interface/raspberrypi-native.cfg] From 227577ba7616ca129790090e1101b503f7b9cdb7 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sat, 21 Jan 2023 12:46:33 +0100 Subject: [PATCH 10/50] rtos: remove config.h includes from stackings headers And add its own header to the rtos_xxx_stackings.c Signed-off-by: Erhan Kurubas Change-Id: I084130fde7ee8645129a7cf60bb7bf59448e2f39 Reviewed-on: https://review.openocd.org/c/openocd/+/7441 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/rtos_chibios_stackings.c | 1 + src/rtos/rtos_chibios_stackings.h | 4 ---- src/rtos/rtos_ecos_stackings.c | 3 ++- src/rtos/rtos_ecos_stackings.h | 4 ---- src/rtos/rtos_embkernel_stackings.c | 1 + src/rtos/rtos_embkernel_stackings.h | 4 ---- src/rtos/rtos_mqx_stackings.c | 2 +- src/rtos/rtos_mqx_stackings.h | 4 ---- src/rtos/rtos_riot_stackings.c | 1 + src/rtos/rtos_riot_stackings.h | 5 ----- src/rtos/rtos_standard_stackings.c | 1 + src/rtos/rtos_standard_stackings.h | 4 ---- src/rtos/rtos_ucos_iii_stackings.c | 10 +++++----- src/rtos/rtos_ucos_iii_stackings.h | 6 +----- 14 files changed, 13 insertions(+), 37 deletions(-) diff --git a/src/rtos/rtos_chibios_stackings.c b/src/rtos/rtos_chibios_stackings.c index e2fe0a27f0..c0816ac3cf 100644 --- a/src/rtos/rtos_chibios_stackings.c +++ b/src/rtos/rtos_chibios_stackings.c @@ -14,6 +14,7 @@ #include "rtos.h" #include "target/armv7m.h" +#include "rtos_chibios_stackings.h" static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, -1, 32 }, /* r0 */ diff --git a/src/rtos/rtos_chibios_stackings.h b/src/rtos/rtos_chibios_stackings.h index 23ad44ae3b..e909451e25 100644 --- a/src/rtos/rtos_chibios_stackings.h +++ b/src/rtos/rtos_chibios_stackings.h @@ -8,10 +8,6 @@ #ifndef OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H #define OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking; diff --git a/src/rtos/rtos_ecos_stackings.c b/src/rtos/rtos_ecos_stackings.c index 86e1765078..cae271270a 100644 --- a/src/rtos/rtos_ecos_stackings.c +++ b/src/rtos/rtos_ecos_stackings.c @@ -5,8 +5,9 @@ #endif #include "rtos.h" -#include "rtos_standard_stackings.h" #include "target/armv7m.h" +#include "rtos_standard_stackings.h" +#include "rtos_ecos_stackings.h" /* For Cortex-M eCos applications the actual thread context register layout can * be different between active threads of an application depending on whether diff --git a/src/rtos/rtos_ecos_stackings.h b/src/rtos/rtos_ecos_stackings.h index 0375e2d1c5..a6bcf1acbb 100644 --- a/src/rtos/rtos_ecos_stackings.h +++ b/src/rtos/rtos_ecos_stackings.h @@ -3,10 +3,6 @@ #ifndef OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H #define OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking; diff --git a/src/rtos/rtos_embkernel_stackings.c b/src/rtos/rtos_embkernel_stackings.c index 809b622e06..b98628a136 100644 --- a/src/rtos/rtos_embkernel_stackings.c +++ b/src/rtos/rtos_embkernel_stackings.c @@ -12,6 +12,7 @@ #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" +#include "rtos_embkernel_stackings.h" static const struct stack_register_offset rtos_embkernel_cortex_m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ diff --git a/src/rtos/rtos_embkernel_stackings.h b/src/rtos/rtos_embkernel_stackings.h index 972bce66d9..87bd0e73b8 100644 --- a/src/rtos/rtos_embkernel_stackings.h +++ b/src/rtos/rtos_embkernel_stackings.h @@ -8,10 +8,6 @@ #ifndef OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H #define OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking; diff --git a/src/rtos/rtos_mqx_stackings.c b/src/rtos/rtos_mqx_stackings.c index 8c8fd2053a..5ab743bf30 100644 --- a/src/rtos/rtos_mqx_stackings.c +++ b/src/rtos/rtos_mqx_stackings.c @@ -11,7 +11,7 @@ #include "rtos.h" #include "target/armv7m.h" - +#include "rtos_mqx_stackings.h" /* * standard exception stack diff --git a/src/rtos/rtos_mqx_stackings.h b/src/rtos/rtos_mqx_stackings.h index f86c05a40d..faa741de60 100644 --- a/src/rtos/rtos_mqx_stackings.h +++ b/src/rtos/rtos_mqx_stackings.h @@ -8,10 +8,6 @@ #ifndef OPENOCD_RTOS_RTOS_MQX_STACKINGS_H #define OPENOCD_RTOS_RTOS_MQX_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking; diff --git a/src/rtos/rtos_riot_stackings.c b/src/rtos/rtos_riot_stackings.c index e717e8cfec..e467621684 100644 --- a/src/rtos/rtos_riot_stackings.c +++ b/src/rtos/rtos_riot_stackings.c @@ -12,6 +12,7 @@ #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" +#include "rtos_riot_stackings.h" /* This works for the M0 and M34 stackings as xPSR is in a fixed * location diff --git a/src/rtos/rtos_riot_stackings.h b/src/rtos/rtos_riot_stackings.h index 3b6c5f41c0..ebd5337568 100644 --- a/src/rtos/rtos_riot_stackings.h +++ b/src/rtos/rtos_riot_stackings.h @@ -8,14 +8,9 @@ #ifndef OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H #define OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_riot_cortex_m0_stacking; extern const struct rtos_register_stacking rtos_riot_cortex_m34_stacking; #endif /* OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H */ - diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index f83f0a1fbf..5478080cf7 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -11,6 +11,7 @@ #include "rtos.h" #include "target/armv7m.h" +#include "rtos_standard_stackings.h" static const struct stack_register_offset rtos_standard_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ diff --git a/src/rtos/rtos_standard_stackings.h b/src/rtos/rtos_standard_stackings.h index 2477fffd1e..99fbe07e48 100644 --- a/src/rtos/rtos_standard_stackings.h +++ b/src/rtos/rtos_standard_stackings.h @@ -8,10 +8,6 @@ #ifndef OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H #define OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_standard_cortex_m3_stacking; diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c index 9ba5288bf1..f1e248231e 100644 --- a/src/rtos/rtos_ucos_iii_stackings.c +++ b/src/rtos/rtos_ucos_iii_stackings.c @@ -9,11 +9,11 @@ #include "config.h" #endif -#include -#include -#include -#include -#include +#include "rtos.h" +#include "target/armv7m.h" +#include "target/esirisc.h" +#include "rtos_standard_stackings.h" +#include "rtos_ucos_iii_stackings.h" static const struct stack_register_offset rtos_ucos_iii_cortex_m_stack_offsets[] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ diff --git a/src/rtos/rtos_ucos_iii_stackings.h b/src/rtos/rtos_ucos_iii_stackings.h index 831c68e1c9..dfe60b27b4 100644 --- a/src/rtos/rtos_ucos_iii_stackings.h +++ b/src/rtos/rtos_ucos_iii_stackings.h @@ -8,11 +8,7 @@ #ifndef OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H #define OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include +#include "rtos.h" extern const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking; extern const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking; From 4423e05d9df8803e2311e70d5a2ffc55a92e5676 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 28 Nov 2022 10:54:48 +0100 Subject: [PATCH 11/50] jtag/drivers/jlink: allow SWD multidrop SW-DPv2 and SWJ-DPv2 devices do not reply to DP_TARGETSEL write cmd. Ignore the received ACK after TARGETSEL write. While on it, use swd_ack_to_error_code() for unified error code translation of the received ACK value for all other commands. Signed-off-by: Tomas Vanek Change-Id: If978c88c8496e31581175385e59c32faebfd20aa Reviewed-on: https://review.openocd.org/c/openocd/+/7383 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: zapb --- src/jtag/drivers/jlink.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 0a96ac255d..243d1a46b2 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -1976,6 +1976,8 @@ struct pending_scan_result { void *buffer; /** Offset in the destination buffer */ unsigned buffer_offset; + /** SWD command */ + uint8_t swd_cmd; }; #define MAX_PENDING_SCAN_RESULTS 256 @@ -2179,12 +2181,13 @@ static int jlink_swd_run_queue(void) } for (i = 0; i < pending_scan_results_length; i++) { + /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ + bool check_ack = swd_cmd_returns_ack(pending_scan_results_buffer[i].swd_cmd); int ack = buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3); - - if (ack != SWD_ACK_OK) { + if (check_ack && ack != SWD_ACK_OK) { LOG_DEBUG("SWD ack not OK: %d %s", ack, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); - queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; + queued_retval = swd_ack_to_error_code(ack); goto skip; } else if (pending_scan_results_buffer[i].length) { uint32_t data = buf_get_u32(tdo_buffer, 3 + pending_scan_results_buffer[i].first, 32); @@ -2221,6 +2224,7 @@ static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3 if (queued_retval != ERROR_OK) return; + pending_scan_results_buffer[pending_scan_results_length].swd_cmd = cmd; cmd |= SWD_CMD_START | SWD_CMD_PARK; jlink_queue_data_out(&cmd, 8); From 0b6f53e94cd81ee9c85ddc122004fa403b9cc454 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 2 Oct 2022 14:46:11 +0200 Subject: [PATCH 12/50] tcl/target: add rescue mode to RP2040 config Integrate a rescue mode inspired by [1]. The current OpenOCD must be restarted before normal work with the RP2040 because the rescue debug port must not be activated (or the target is reset every 'dap init'). To continue without restarting OpenOCD we would need to switch off the configured rescue dap. Change-Id: Ia05b960f06747063550c166e461939d92e232830 Link: [1] https://github.com/raspberrypi/openocd/blob/rp2040/tcl/target/rp2040-rescue.cfg Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7327 Reviewed-by: Jonathan Bell Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/target/rp2040.cfg | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tcl/target/rp2040.cfg b/tcl/target/rp2040.cfg index 0593e03bad..de76b4e29c 100644 --- a/tcl/target/rp2040.cfg +++ b/tcl/target/rp2040.cfg @@ -26,6 +26,13 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x01002927 } +# Set to '1' to start rescue mode +if { [info exists RESCUE] } { + set _RESCUE $RESCUE +} else { + set _RESCUE 0 +} + # Set to '0' or '1' for single core configuration, 'SMP' for -rtos hwthread # handling of both cores, anything else for isolated debugging of both cores if { [info exists USE_CORE] } { @@ -37,6 +44,29 @@ set _BOTH_CORES [expr { $_USE_CORE != 0 && $_USE_CORE != 1 }] swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +# The rescue debug port uses the DP CTRL/STAT bit DBGPWRUPREQ to reset the +# PSM (power on state machine) of the RP2040 with a flag set in the +# VREG_AND_POR_CHIP_RESET register. Once the reset is released +# (by clearing the DBGPWRUPREQ flag), the bootrom will run, see this flag, +# and halt. Allowing the user to load some fresh code, rather than loading +# the potentially broken code stored in flash +if { $_RESCUE } { + dap create $_CHIPNAME.rescue_dap -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0xf -ignore-syspwrupack + init + + # Clear DBGPWRUPREQ + $_CHIPNAME.rescue_dap dpreg 0x4 0x00000000 + + # Verifying CTRL/STAT is 0 + set _CTRLSTAT [$_CHIPNAME.rescue_dap dpreg 0x4] + if {[expr {$_CTRLSTAT & 0xf0000000}]} { + echo "Rescue failed, DP CTRL/STAT readback $_CTRLSTAT" + } else { + echo "Now restart OpenOCD without RESCUE flag and load code to RP2040" + } + shutdown +} + # core 0 if { $_USE_CORE != 1 } { dap create $_CHIPNAME.dap0 -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0 From 9d97cace0e95437137e3c57e40347dfcce39ebc9 Mon Sep 17 00:00:00 2001 From: Daniel Serpell Date: Tue, 24 Jan 2023 23:54:43 -0300 Subject: [PATCH 13/50] flash/nor/spi: Add some zbit flash chips. I have a RP2020 board from aliexpress that uses the ZB25VQ32 flash, this allows openocd to correctly identify it with the full flash size. I also added other models, the datasheets can be found at: Link: https://datasheet.lcsc.com/lcsc/2203210916_Zbit-Semi-ZB25VQ16ASIG_C2982491.pdf Link: https://datasheet.lcsc.com/lcsc/2003141132_Zbit-Semi-ZB25VQ32BSIG_C495744.pdf Link: https://datasheet.lcsc.com/lcsc/2003141132_Zbit-Semi-ZB25VQ64ASIG_C495745.pdf Link: https://datasheet.lcsc.com/lcsc/2006151421_Zbit-Semi-ZB25VQ128ASIG_C609616.pdf As noted by Andreas Bolsch, the devices supporting QSPI have different ID in QPI mode than SPI, so two entries are needed in the table for each one. Use 0x0B as qread command, as this does not need the dummy M7-0 parameters. Signed-off-by: Daniel Serpell Change-Id: Id99187b1963b02ac1a786b66bb352f5f48ed0ac2 Reviewed-on: https://review.openocd.org/c/openocd/+/7445 Reviewed-by: Andreas Bolsch Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/flash/nor/spi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 373a9a1441..9a606d5459 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -112,6 +112,13 @@ const struct flash_device flash_devices[] = { FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000), FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000), + FLASH_ID("zbit zb25vq16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015605e, 0x100, 0x10000, 0x200000), + FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016405e, 0x100, 0x10000, 0x400000), + FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016605e, 0x100, 0x10000, 0x400000), /* QPI mode */ + FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017405e, 0x100, 0x10000, 0x800000), + FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017605e, 0x100, 0x10000, 0x800000), /* QPI mode */ + FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018405e, 0x100, 0x10000, 0x1000000), + FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018605e, 0x100, 0x10000, 0x1000000), /* QPI mode */ FLASH_ID("issi is25lq040b", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x0013409d, 0x100, 0x1000, 0x80000), FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000), FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000), From 700cdbfac41014d9f3a9c12cbb13f01e59fb53d8 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 13:27:10 +0100 Subject: [PATCH 14/50] target: arc: rewrite command 'arc jtag get-aux-reg' as COMMAND_HANDLER This also fixes an incorrect return ERROR_OK from a jim command. Change-Id: I3c51355e7e05965327ce819a3114e370f2de5249 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7407 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 7a8004678e..56eb0ec2d2 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -318,39 +318,28 @@ static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *ar return ERROR_OK; } -static int jim_arc_get_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_get_aux_reg) { - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 1) { - Jim_SetResultFormatted(goi.interp, - "usage: %s ", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); struct arc_common *arc = target_to_arc(target); assert(arc); + uint32_t value; CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, regnum, &value)); - Jim_SetResultInt(interp, value); + + command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } @@ -445,7 +434,7 @@ static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *a static const struct command_registration arc_jtag_command_group[] = { { .name = "get-aux-reg", - .jim_handler = jim_arc_get_aux_reg, + .handler = arc_handle_get_aux_reg, .mode = COMMAND_EXEC, .help = "Get AUX register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " From 551d85b123b38d34e15b4e978250ebdfe7b952f7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 13:32:56 +0100 Subject: [PATCH 15/50] target: arc: rewrite command 'arc jtag set-aux-reg' as COMMAND_HANDLER This also fixes an incorrect return ERROR_OK from a jim command. Change-Id: Iab9bc7c25181341a632f608a8ef2d8b0bea72520 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7408 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 56eb0ec2d2..a6eb14f037 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -278,37 +278,24 @@ static struct jim_nvp nvp_add_reg_type_struct_opts[] = { { .name = NULL, .value = -1 } }; -static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_set_aux_reg) { + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 2) { - Jim_SetResultFormatted(goi.interp, - "usage: %s ", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); - - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); /* Register value */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value)); + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct arc_common *arc = target_to_arc(target); assert(arc); @@ -444,7 +431,7 @@ static const struct command_registration arc_jtag_command_group[] = { }, { .name = "set-aux-reg", - .jim_handler = jim_arc_set_aux_reg, + .handler = arc_handle_set_aux_reg, .mode = COMMAND_EXEC, .help = "Set AUX register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " From 16af56f6001782752d23567ca78823e2db9c5828 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 13:38:58 +0100 Subject: [PATCH 16/50] target: arc: rewrite command 'arc jtag get-core-reg' as COMMAND_HANDLER This also fixes an incorrect return ERROR_OK from a jim command. Change-Id: I1f9cf5d1dfa38b8a06042b5f54209e6ee2fc4e0e Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7409 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index a6eb14f037..cede9487b5 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -331,45 +331,34 @@ COMMAND_HANDLER(arc_handle_get_aux_reg) return ERROR_OK; } -static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_get_core_reg) { - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 1) { - Jim_SetResultFormatted(goi.interp, - "usage: %s ", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { - Jim_SetResultFormatted(goi.interp, "Core register number %i " + command_print(CMD, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); - return JIM_ERR; + return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_common *arc = target_to_arc(target); assert(arc); /* Read value */ + uint32_t value; CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, regnum, &value)); - Jim_SetResultInt(interp, value); + + command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } @@ -441,7 +430,7 @@ static const struct command_registration arc_jtag_command_group[] = { }, { .name = "get-core-reg", - .jim_handler = jim_arc_get_core_reg, + .handler = arc_handle_get_core_reg, .mode = COMMAND_EXEC, .help = "Get/Set core register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " From f0cb5b027238f6beb0bee80a9d385716923ae6eb Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 13:44:00 +0100 Subject: [PATCH 17/50] target: arc: rewrite command 'arc jtag set-core-reg' as COMMAND_HANDLER This also fixes an incorrect return ERROR_OK from a jim command. Change-Id: I72a522645f62b99b313573c8bad6d4f674c5ae53 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7410 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index cede9487b5..34ddc69031 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -363,41 +363,29 @@ COMMAND_HANDLER(arc_handle_get_core_reg) return ERROR_OK; } -static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_set_core_reg) { - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 2) { - Jim_SetResultFormatted(goi.interp, - "usage: %s ", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { - Jim_SetResultFormatted(goi.interp, "Core register number %i " + command_print(CMD, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); - return JIM_ERR; + return ERROR_COMMAND_ARGUMENT_INVALID; } /* Register value */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value)); + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct arc_common *arc = target_to_arc(target); assert(arc); @@ -440,7 +428,7 @@ static const struct command_registration arc_jtag_command_group[] = { }, { .name = "set-core-reg", - .jim_handler = jim_arc_set_core_reg, + .handler = arc_handle_set_core_reg, .mode = COMMAND_EXEC, .help = "Get/Set core register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " From 996d6f383dfcffbc4550daedb622d3d006e8cd37 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 17:03:03 +0100 Subject: [PATCH 18/50] target: arc: rewrite command 'arc get-reg-field' as COMMAND_HANDLER This also fixes several incorrect return ERROR_xxx from a jim command. Change-Id: I34fe3552d3dc344eac67bf504c5d5709b707fdfd Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7411 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 51 ++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 34ddc69031..264adc0b5c 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -796,59 +796,40 @@ COMMAND_HANDLER(arc_set_reg_exists) /* arc reg-field ($reg_name) ($reg_field) * Reads struct type register field */ -static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_get_reg_field) { - struct jim_getopt_info goi; - const char *reg_name, *field_name; - uint32_t value; - int retval; - - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - LOG_DEBUG("Reading register field"); - if (goi.argc != 2) { - if (!goi.argc) - Jim_WrongNumArgs(interp, goi.argc, goi.argv, " "); - else if (goi.argc == 1) - Jim_WrongNumArgs(interp, goi.argc, goi.argv, ""); - else - Jim_WrongNumArgs(interp, goi.argc, goi.argv, " "); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } - - JIM_CHECK_RETVAL(jim_getopt_string(&goi, ®_name, NULL)); - JIM_CHECK_RETVAL(jim_getopt_string(&goi, &field_name, NULL)); - assert(reg_name); - assert(field_name); - struct command_context * const ctx = current_command_context(interp); - assert(ctx); - struct target * const target = get_current_target(ctx); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } - retval = arc_reg_get_field(target, reg_name, field_name, &value); + const char *reg_name = CMD_ARGV[0]; + const char *field_name = CMD_ARGV[1]; + uint32_t value; + int retval = arc_reg_get_field(target, reg_name, field_name, &value); switch (retval) { case ERROR_OK: break; case ERROR_ARC_REGISTER_NOT_FOUND: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Register `%s' has not been found.", reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_REGISTER_IS_NOT_STRUCT: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Register `%s' must have 'struct' type.", reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Field `%s' has not been found in register `%s'.", field_name, reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_FIELD_IS_NOT_BITFIELD: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Field `%s' is not a 'bitfield' field in a structure.", field_name); return ERROR_COMMAND_ARGUMENT_INVALID; @@ -857,9 +838,9 @@ static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const * return retval; } - Jim_SetResultInt(interp, value); + command_print(CMD, "0x%" PRIx32, value); - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(arc_l1_cache_disable_auto_cmd) @@ -1002,7 +983,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "get-reg-field", - .jim_handler = jim_arc_get_reg_field, + .handler = arc_handle_get_reg_field, .mode = COMMAND_ANY, .usage = " ", .help = "Returns value of field in a register with 'struct' type.", From da76ba610b8e6b05de3a837926d06f8e7d964b97 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 17:14:15 +0100 Subject: [PATCH 19/50] target: arc: rewrite command 'arc num-actionpoints' as COMMAND_HANDLER Also drop arc_cmd_jim_get_uint32() that is now unused. Change-Id: Ic26c3f008376db3f01215bf736fca736dd1c1a4f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7412 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 264adc0b5c..e7c54446e2 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -22,14 +22,6 @@ * ------------------------------------------------------------------------- */ -static int arc_cmd_jim_get_uint32(struct jim_getopt_info *goi, uint32_t *value) -{ - jim_wide value_wide; - JIM_CHECK_RETVAL(jim_getopt_wide(goi, &value_wide)); - *value = (uint32_t)value_wide; - return JIM_OK; -} - enum add_reg_types { CFG_ADD_REG_TYPE_FLAG, CFG_ADD_REG_TYPE_STRUCT, @@ -863,27 +855,17 @@ COMMAND_HANDLER(arc_l2_cache_disable_auto_cmd) &arc->has_l2cache, "target has l2 cache enabled"); } -static int jim_handle_actionpoints_num(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_actionpoints_num) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - LOG_DEBUG("-"); - if (goi.argc >= 2) { - Jim_WrongNumArgs(interp, goi.argc, goi.argv, "[]"); - return JIM_ERR; - } - - struct command_context *context = current_command_context(interp); - assert(context); - - struct target *target = get_current_target(context); + if (CMD_ARGC >= 2) + return ERROR_COMMAND_SYNTAX_ERROR; + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } struct arc_common *arc = target_to_arc(target); @@ -892,19 +874,19 @@ static int jim_handle_actionpoints_num(Jim_Interp *interp, int argc, * "actionpoint reset, initiated by arc_set_actionpoints_num. */ uint32_t ap_num = arc->actionpoints_num; - if (goi.argc == 1) { - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &ap_num)); + if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ap_num); int e = arc_set_actionpoints_num(target, ap_num); if (e != ERROR_OK) { - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Failed to set number of actionpoints"); - return JIM_ERR; + return e; } } - Jim_SetResultInt(interp, ap_num); + command_print(CMD, "%" PRIu32, ap_num); - return JIM_OK; + return ERROR_OK; } /* ----- Exported target commands ------------------------------------------ */ @@ -1004,7 +986,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "num-actionpoints", - .jim_handler = jim_handle_actionpoints_num, + .handler = arc_handle_actionpoints_num, .mode = COMMAND_ANY, .usage = "[]", .help = "Prints or sets amount of actionpoints in the processor.", From 18bafdce615132311fd34f2e1bdf57c193d14097 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 17:20:06 +0100 Subject: [PATCH 20/50] target: arc: fix error handling in command 'arc set-reg-exists' The command is specified through COMMAND_HANDLER. It should not return JIM_OK / JIM_ERR. Change-Id: I56666414d49b0298ecc23ec7ef30c77e1e27afa8 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7413 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index e7c54446e2..fb1817de6e 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -763,7 +763,7 @@ COMMAND_HANDLER(arc_set_reg_exists) struct target * const target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "Unable to get current target."); - return JIM_ERR; + return ERROR_FAIL; } if (!CMD_ARGC) { @@ -783,7 +783,7 @@ COMMAND_HANDLER(arc_set_reg_exists) r->exist = true; } - return JIM_OK; + return ERROR_OK; } /* arc reg-field ($reg_name) ($reg_field) From ea6a99208e1bc41a878234f7220501e26ec4a7f1 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 26 Dec 2022 21:59:56 +0100 Subject: [PATCH 21/50] helper: nvp: add openocd nvp files Long ago jim_nvp was part of jimtcl. When jimtcl dropped it, OpenOCD kept copy of it in its code base. Current code of jim_nvp is still related with jimtcl data types and functions. With the target of better isolating OpenOCD code from jimtcl, create a new file nvp.c that re-proposes only the core of the old jim_nvp, dropping any link with jimtcl and removing the string 'jim' either from the filename and from the code. Keep the same license from the old code, as the new files are clearly derived from it. Change-Id: I273448cf1f1484b10f6b6113ed7bb0fcf946482b Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7423 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/helper/Makefile.am | 4 ++- src/helper/nvp.c | 67 +++++++++++++++++++++++++++++++++++++ src/helper/nvp.h | 75 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/helper/nvp.c create mode 100644 src/helper/nvp.h diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index c4c60d96b4..e9c05cfc5d 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -16,6 +16,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/util.c \ %D%/jep106.c \ %D%/jim-nvp.c \ + %D%/nvp.c \ %D%/align.h \ %D%/binarybuffer.h \ %D%/bits.h \ @@ -32,7 +33,8 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/system.h \ %D%/jep106.h \ %D%/jep106.inc \ - %D%/jim-nvp.h + %D%/jim-nvp.h \ + %D%/nvp.h STARTUP_TCL_SRCS += %D%/startup.tcl EXTRA_DIST += \ diff --git a/src/helper/nvp.c b/src/helper/nvp.c new file mode 100644 index 0000000000..7a8abc2e23 --- /dev/null +++ b/src/helper/nvp.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-2-Clause-Views + +/* + * Copyright 2005 Salvatore Sanfilippo + * Copyright 2005 Clemens Hintze + * Copyright 2005 patthoyts - Pat Thoyts + * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com + * Copyright 2008 Andrew Lunn + * Copyright 2008 Duane Ellis + * Copyright 2008 Uwe Klein + * Copyright 2008 Steve Bennett + * Copyright 2009 Nico Coesel + * Copyright 2009 Zachary T Welch zw@superlucidity.net + * Copyright 2009 David Brownell + * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. + * + * This file is extracted from jim_nvp.c, originally part of jim TCL code. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include + +const struct nvp *nvp_name2value(const struct nvp *p, const char *name) +{ + while (p->name) { + if (strcmp(name, p->name) == 0) + break; + p++; + } + return p; +} + +const struct nvp *nvp_value2name(const struct nvp *p, int value) +{ + while (p->name) { + if (value == p->value) + break; + p++; + } + return p; +} + +void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp, + const char *param_name, const char *param_value) +{ + if (param_name) + command_print_sameline(cmd, "%s: Unknown: %s, try one of: ", param_name, param_value); + else + command_print_sameline(cmd, "Unknown param: %s, try one of: ", param_value); + + while (nvp->name) { + if ((nvp + 1)->name) + command_print_sameline(cmd, "%s, ", nvp->name); + else + command_print(cmd, "or %s", nvp->name); + + nvp++; + } + + /* We assume nvp to be not empty and loop has been taken; no need to add a '\n' */ +} diff --git a/src/helper/nvp.h b/src/helper/nvp.h new file mode 100644 index 0000000000..125164e4ed --- /dev/null +++ b/src/helper/nvp.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Views */ + +/* + * Copyright 2005 Salvatore Sanfilippo + * Copyright 2005 Clemens Hintze + * Copyright 2005 patthoyts - Pat Thoyts + * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com + * Copyright 2008 Andrew Lunn + * Copyright 2008 Duane Ellis + * Copyright 2008 Uwe Klein + * Copyright 2008 Steve Bennett + * Copyright 2009 Nico Coesel + * Copyright 2009 Zachary T Welch zw@superlucidity.net + * Copyright 2009 David Brownell + * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. + * + * This file is extracted from jim_nvp.h, originally part of jim TCL code. + */ + +#ifndef OPENOCD_HELPER_NVP_H +#define OPENOCD_HELPER_NVP_H + +/** Name Value Pairs, aka: NVP + * - Given a string - return the associated int. + * - Given a number - return the associated string. + * . + * + * Very useful when the number is not a simple index into an array of + * known string, or there may be multiple strings (aliases) that mean then same + * thing. + * + * An NVP Table is terminated with ".name = NULL". + * + * During the 'name2value' operation, if no matching string is found + * the pointer to the terminal element (with p->name == NULL) is returned. + * + * Example: + * \code + * const struct nvp yn[] = { + * { "yes", 1 }, + * { "no" , 0 }, + * { "yep", 1 }, + * { "nope", 0 }, + * { NULL, -1 }, + * }; + * + * struct nvp *result; + * result = nvp_name2value(yn, "yes"); + * returns &yn[0]; + * result = nvp_name2value(yn, "no"); + * returns &yn[1]; + * result = jim_nvp_name2value(yn, "Blah"); + * returns &yn[4]; + * \endcode + * + * During the number2name operation, the first matching value is returned. + */ + +struct nvp { + const char *name; + int value; +}; + +struct command_invocation; + +/* Name Value Pairs Operations */ +const struct nvp *nvp_name2value(const struct nvp *nvp_table, const char *name) + __attribute__((returns_nonnull, nonnull(1))); +const struct nvp *nvp_value2name(const struct nvp *nvp_table, int v) + __attribute__((returns_nonnull, nonnull(1))); + +void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp, + const char *param_name, const char *param_value); + +#endif /* OPENOCD_HELPER_NVP_H */ From 92ef27494c510a2df7cbbee8b19d5c0d4d943d40 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 27 Dec 2022 00:28:16 +0100 Subject: [PATCH 22/50] target: arc: rewrite command 'arc add-reg-type-flags' as COMMAND_HANDLER Use a COMMAND_HELPER() to avoid memory leaks when the helper COMMAND_PARSE_NUMBER() returns due to an error. While there: - fix potential SIGSEGV due to dereference 'type' before checking it's not NULL; - fix an incorrect NUL byte termination while copying to type->data_type.id and to bitfields[cur_field].name; - fix some coding style error. Change-Id: Ide4cbc829871a6a523026ccc0d3100dadc2afd06 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7424 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 197 +++++++++++++++++++++---------------------- 1 file changed, 94 insertions(+), 103 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index fb1817de6e..32c62d0cae 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -13,6 +13,7 @@ #endif #include "arc.h" +#include /* -------------------------------------------------------------------------- * @@ -32,7 +33,7 @@ enum add_reg_type_flags { CFG_ADD_REG_TYPE_FLAGS_FLAG, }; -static struct jim_nvp nvp_add_reg_type_flags_opts[] = { +static const struct nvp nvp_add_reg_type_flags_opts[] = { { .name = "-name", .value = CFG_ADD_REG_TYPE_FLAGS_NAME }, { .name = "-flag", .value = CFG_ADD_REG_TYPE_FLAGS_FLAG }, { .name = NULL, .value = -1 } @@ -114,53 +115,113 @@ static int jim_arc_read_reg_type_field(struct jim_getopt_info *goi, const char * return e; } -static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +static COMMAND_HELPER(arc_handle_add_reg_type_flags_ops, struct arc_reg_data_type *type) { - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); + struct reg_data_type_flags_field *fields = type->reg_type_flags_field; + struct arc_reg_bitfield *bitfields = type->bitfields; + struct reg_data_type_flags *flags = &type->data_type_flags; + unsigned int cur_field = 0; - LOG_DEBUG("-"); + while (CMD_ARGC) { + const struct nvp *n = nvp_name2value(nvp_add_reg_type_flags_opts, CMD_ARGV[0]); + CMD_ARGC--; + CMD_ARGV++; + switch (n->value) { + case CFG_ADD_REG_TYPE_FLAGS_NAME: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; - struct command_context *ctx; - struct target *target; + const char *name = CMD_ARGV[0]; + CMD_ARGC--; + CMD_ARGV++; - ctx = current_command_context(interp); - assert(ctx); - target = get_current_target(ctx); - if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + if (strlen(name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + strcpy((void *)type->data_type.id, name); + break; + + case CFG_ADD_REG_TYPE_FLAGS_FLAG: + if (CMD_ARGC < 2) + return ERROR_COMMAND_ARGUMENT_INVALID; + + uint32_t val; + const char *field_name = CMD_ARGV[0]; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], val); + CMD_ARGC -= 2; + CMD_ARGV += 2; + bitfields[cur_field].bitfield.start = val; + bitfields[cur_field].bitfield.end = val; + + if (strlen(field_name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type field_name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + fields[cur_field].name = bitfields[cur_field].name; + strcpy(bitfields[cur_field].name, field_name); + + fields[cur_field].bitfield = &bitfields[cur_field].bitfield; + if (cur_field > 0) + fields[cur_field - 1].next = &fields[cur_field]; + else + flags->fields = fields; + + cur_field += 1; + break; + + default: + nvp_unknown_command_print(CMD, nvp_add_reg_type_flags_opts, NULL, CMD_ARGV[-1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } } - int e = JIM_OK; + if (!type->data_type.id) { + command_print(CMD, "-name is a required option"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - /* Check if the amount of arguments is not zero */ - if (goi.argc <= 0) { - Jim_SetResultFormatted(goi.interp, "The command has no arguments"); - return JIM_ERR; + return ERROR_OK; +} + +COMMAND_HANDLER(arc_handle_add_reg_type_flags) +{ + int retval; + + LOG_DEBUG("-"); + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "No current target"); + return ERROR_FAIL; } + /* Check if the amount of arguments is not zero */ + if (CMD_ARGC == 0) + return ERROR_COMMAND_SYNTAX_ERROR; + /* Estimate number of registers as (argc - 2)/3 as each -flag option has 2 * arguments while -name is required. */ - unsigned int fields_sz = (goi.argc - 2) / 3; - unsigned int cur_field = 0; + unsigned int fields_sz = (CMD_ARGC - 2) / 3; /* The maximum amount of bitfields is 32 */ if (fields_sz > 32) { - Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32"); - return JIM_ERR; + command_print(CMD, "The amount of bitfields exceed 32"); + return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_reg_data_type *type = calloc(1, sizeof(*type)); - struct reg_data_type_flags *flags = &type->data_type_flags; struct reg_data_type_flags_field *fields = calloc(fields_sz, sizeof(*fields)); - type->reg_type_flags_field = fields; struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); - if (!(type && fields && bitfields)) { - Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); + if (!type || !fields || !bitfields) { + LOG_ERROR("Out of memory"); + retval = ERROR_FAIL; goto fail; } + struct reg_data_type_flags *flags = &type->data_type_flags; + type->reg_type_flags_field = fields; /* Initialize type */ type->bitfields = bitfields; @@ -170,92 +231,22 @@ static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc, type->data_type.reg_type_flags = flags; flags->size = 4; /* For now ARC has only 32-bit registers */ - while (goi.argc > 0 && e == JIM_OK) { - struct jim_nvp *n; - e = jim_getopt_nvp(&goi, nvp_add_reg_type_flags_opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_add_reg_type_flags_opts, 0); - continue; - } - - switch (n->value) { - case CFG_ADD_REG_TYPE_FLAGS_NAME: - { - const char *name = NULL; - int name_len = 0; - - e = jim_arc_read_reg_name_field(&goi, &name, &name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read reg name."); - goto fail; - } - - if (name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type name is too big."); - goto fail; - } - - strncpy((void *)type->data_type.id, name, name_len); - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name."); - goto fail; - } - - break; - } - - case CFG_ADD_REG_TYPE_FLAGS_FLAG: - { - const char *field_name = NULL; - int field_name_len = 0; - - e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields, - cur_field, CFG_ADD_REG_TYPE_FLAG); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_flag field."); - goto fail; - } - - if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big."); - goto fail; - } - - fields[cur_field].name = bitfields[cur_field].name; - strncpy(bitfields[cur_field].name, field_name, field_name_len); - if (!fields[cur_field].name) { - Jim_SetResultFormatted(goi.interp, "Unable to setup field name. "); - goto fail; - } - - fields[cur_field].bitfield = &(bitfields[cur_field].bitfield); - if (cur_field > 0) - fields[cur_field - 1].next = &(fields[cur_field]); - else - flags->fields = fields; - - cur_field += 1; - break; - } - } - } - - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "-name is a required option"); + retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_type_flags_ops, type); + if (retval != ERROR_OK) goto fail; - } arc_reg_data_type_add(target, type); LOG_DEBUG("added flags type {name=%s}", type->data_type.id); - return JIM_OK; + return ERROR_OK; + fail: free(type); free(fields); free(bitfields); - return JIM_ERR; + return retval; } /* Add struct register data type */ @@ -924,7 +915,7 @@ static const struct command_registration arc_cache_group_handlers[] = { static const struct command_registration arc_core_command_handlers[] = { { .name = "add-reg-type-flags", - .jim_handler = jim_arc_add_reg_type_flags, + .handler = arc_handle_add_reg_type_flags, .mode = COMMAND_CONFIG, .usage = "-name -flag " "[-flag ]...", From 85f3b10a6914fd44c8f32d345654bed371d0667d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 27 Dec 2022 00:56:55 +0100 Subject: [PATCH 23/50] target: arc: rewrite command 'arc add-reg-type-struct' as COMMAND_HANDLER Use a COMMAND_HELPER() to avoid memory leaks when the helper COMMAND_PARSE_NUMBER() returns due to an error. While there: - fix potential SIGSEGV due to dereference 'type' before checking it's not NULL; - fix an incorrect NUL byte termination while copying to type->data_type.id and to bitfields[cur_field].name; - fix some coding style error; - remove the now unused function jim_arc_read_reg_type_field(). Change-Id: I7158fd93b5d4742f11654b8ae4a7abd409ad06e2 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7425 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc_cmd.c | 252 +++++++++++++++++-------------------------- 1 file changed, 101 insertions(+), 151 deletions(-) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 32c62d0cae..3b0bf76f80 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -70,51 +70,6 @@ static int jim_arc_read_reg_name_field(struct jim_getopt_info *goi, return e; } -/* Helper function to read bitfields/flags of register type. */ -static int jim_arc_read_reg_type_field(struct jim_getopt_info *goi, const char **field_name, int *field_name_len, - struct arc_reg_bitfield *bitfields, int cur_field, int type) -{ - jim_wide start_pos, end_pos; - - int e = JIM_OK; - if ((type == CFG_ADD_REG_TYPE_STRUCT && goi->argc < 3) || - (type == CFG_ADD_REG_TYPE_FLAG && goi->argc < 2)) { - Jim_SetResultFormatted(goi->interp, "Not enough arguments after -flag/-bitfield"); - return JIM_ERR; - } - - e = jim_getopt_string(goi, field_name, field_name_len); - if (e != JIM_OK) - return e; - - /* read start position of bitfield/flag */ - e = jim_getopt_wide(goi, &start_pos); - if (e != JIM_OK) - return e; - - end_pos = start_pos; - - /* Check if any arguments remain, - * set bitfields[cur_field].end if flag is multibit */ - if (goi->argc > 0) - /* Check current argv[0], if it is equal to "-flag", - * than bitfields[cur_field].end remains start */ - if ((strcmp(Jim_String(goi->argv[0]), "-flag") && type == CFG_ADD_REG_TYPE_FLAG) - || (type == CFG_ADD_REG_TYPE_STRUCT)) { - e = jim_getopt_wide(goi, &end_pos); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi->interp, "Error reading end position"); - return e; - } - } - - bitfields[cur_field].bitfield.start = start_pos; - bitfields[cur_field].bitfield.end = end_pos; - if ((end_pos != start_pos) || (type == CFG_ADD_REG_TYPE_STRUCT)) - bitfields[cur_field].bitfield.type = REG_TYPE_INT; - return e; -} - static COMMAND_HELPER(arc_handle_add_reg_type_flags_ops, struct arc_reg_data_type *type) { struct reg_data_type_flags_field *fields = type->reg_type_flags_field; @@ -255,7 +210,7 @@ enum add_reg_type_struct { CFG_ADD_REG_TYPE_STRUCT_BITFIELD, }; -static struct jim_nvp nvp_add_reg_type_struct_opts[] = { +static const struct nvp nvp_add_reg_type_struct_opts[] = { { .name = "-name", .value = CFG_ADD_REG_TYPE_STRUCT_NAME }, { .name = "-bitfield", .value = CFG_ADD_REG_TYPE_STRUCT_BITFIELD }, { .name = NULL, .value = -1 } @@ -424,53 +379,117 @@ static const struct command_registration arc_jtag_command_group[] = { /* This function supports only bitfields. */ -static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +static COMMAND_HELPER(arc_handle_add_reg_type_struct_opts, struct arc_reg_data_type *type) { - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); + struct reg_data_type_struct_field *fields = type->reg_type_struct_field; + struct arc_reg_bitfield *bitfields = type->bitfields; + struct reg_data_type_struct *struct_type = &type->data_type_struct; + unsigned int cur_field = 0; - LOG_DEBUG("-"); + while (CMD_ARGC) { + const struct nvp *n = nvp_name2value(nvp_add_reg_type_struct_opts, CMD_ARGV[0]); + CMD_ARGC--; + CMD_ARGV++; + switch (n->value) { + case CFG_ADD_REG_TYPE_STRUCT_NAME: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; - struct command_context *ctx; - struct target *target; + const char *name = CMD_ARGV[0]; + CMD_ARGC--; + CMD_ARGV++; - ctx = current_command_context(interp); - assert(ctx); - target = get_current_target(ctx); - if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + if (strlen(name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + strcpy((void *)type->data_type.id, name); + break; + + case CFG_ADD_REG_TYPE_STRUCT_BITFIELD: + if (CMD_ARGC < 3) + return ERROR_COMMAND_ARGUMENT_INVALID; + + uint32_t start_pos, end_pos; + const char *field_name = CMD_ARGV[0]; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], start_pos); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], end_pos); + CMD_ARGC -= 3; + CMD_ARGV += 3; + bitfields[cur_field].bitfield.start = start_pos; + bitfields[cur_field].bitfield.end = end_pos; + bitfields[cur_field].bitfield.type = REG_TYPE_INT; + + if (strlen(field_name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type field_name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + fields[cur_field].name = bitfields[cur_field].name; + strcpy(bitfields[cur_field].name, field_name); + + fields[cur_field].bitfield = &bitfields[cur_field].bitfield; + fields[cur_field].use_bitfields = true; + if (cur_field > 0) + fields[cur_field - 1].next = &fields[cur_field]; + else + struct_type->fields = fields; + + cur_field += 1; + + break; + + default: + nvp_unknown_command_print(CMD, nvp_add_reg_type_struct_opts, NULL, CMD_ARGV[-1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } } - int e = JIM_OK; + if (!type->data_type.id) { + command_print(CMD, "-name is a required option"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - /* Check if the amount of arguments is not zero */ - if (goi.argc <= 0) { - Jim_SetResultFormatted(goi.interp, "The command has no arguments"); - return JIM_ERR; + return ERROR_OK; +} + +COMMAND_HANDLER(arc_handle_add_reg_type_struct) +{ + int retval; + + LOG_DEBUG("-"); + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "No current target"); + return ERROR_FAIL; } + /* Check if the amount of arguments is not zero */ + if (CMD_ARGC == 0) + return ERROR_COMMAND_SYNTAX_ERROR; + /* Estimate number of registers as (argc - 2)/4 as each -bitfield option has 3 * arguments while -name is required. */ - unsigned int fields_sz = (goi.argc - 2) / 4; - unsigned int cur_field = 0; + unsigned int fields_sz = (CMD_ARGC - 2) / 4; /* The maximum amount of bitfields is 32 */ if (fields_sz > 32) { - Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32"); - return JIM_ERR; + command_print(CMD, "The amount of bitfields exceed 32"); + return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_reg_data_type *type = calloc(1, sizeof(*type)); - struct reg_data_type_struct *struct_type = &type->data_type_struct; struct reg_data_type_struct_field *fields = calloc(fields_sz, sizeof(*fields)); - type->reg_type_struct_field = fields; struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); - if (!(type && fields && bitfields)) { - Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); + if (!type || !fields || !bitfields) { + LOG_ERROR("Out of memory"); + retval = ERROR_FAIL; goto fail; } + struct reg_data_type_struct *struct_type = &type->data_type_struct; + type->reg_type_struct_field = fields; /* Initialize type */ type->data_type.id = type->data_type_id; @@ -480,91 +499,22 @@ static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc, type->data_type.reg_type_struct = struct_type; struct_type->size = 4; /* For now ARC has only 32-bit registers */ - while (goi.argc > 0 && e == JIM_OK) { - struct jim_nvp *n; - e = jim_getopt_nvp(&goi, nvp_add_reg_type_struct_opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_add_reg_type_struct_opts, 0); - continue; - } - - switch (n->value) { - case CFG_ADD_REG_TYPE_STRUCT_NAME: - { - const char *name = NULL; - int name_len = 0; - - e = jim_arc_read_reg_name_field(&goi, &name, &name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read reg name."); - goto fail; - } - - if (name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type name is too big."); - goto fail; - } - - strncpy((void *)type->data_type.id, name, name_len); - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name."); - goto fail; - } - - break; - } - case CFG_ADD_REG_TYPE_STRUCT_BITFIELD: - { - const char *field_name = NULL; - int field_name_len = 0; - e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields, - cur_field, CFG_ADD_REG_TYPE_STRUCT); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_struct field."); - goto fail; - } - - if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big."); - goto fail; - } - - fields[cur_field].name = bitfields[cur_field].name; - strncpy(bitfields[cur_field].name, field_name, field_name_len); - if (!fields[cur_field].name) { - Jim_SetResultFormatted(goi.interp, "Unable to setup field name. "); - goto fail; - } - - fields[cur_field].bitfield = &(bitfields[cur_field].bitfield); - fields[cur_field].use_bitfields = true; - if (cur_field > 0) - fields[cur_field - 1].next = &(fields[cur_field]); - else - struct_type->fields = fields; - - cur_field += 1; - - break; - } - } - } - - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "-name is a required option"); + retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_type_struct_opts, type); + if (retval != ERROR_OK) goto fail; - } arc_reg_data_type_add(target, type); + LOG_DEBUG("added struct type {name=%s}", type->data_type.id); - return JIM_OK; + + return ERROR_OK; fail: - free(type); - free(fields); - free(bitfields); + free(type); + free(fields); + free(bitfields); - return JIM_ERR; + return retval; } /* Add register */ @@ -925,7 +875,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "add-reg-type-struct", - .jim_handler = jim_arc_add_reg_type_struct, + .handler = arc_handle_add_reg_type_struct, .mode = COMMAND_CONFIG, .usage = "-name -bitfield " "[-bitfield ]...", From 4a79372b6e6e511c9b7ad5cc97b85338ffb860e3 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 27 Dec 2022 02:38:25 +0100 Subject: [PATCH 24/50] target: arc: rewrite command 'arc add-reg' as COMMAND_HANDLER While there, fix some coding style error and remove the now unused function jim_arc_read_reg_name_field() and the macro JIM_CHECK_RETVAL(). Change-Id: I140b4b929978b2936f2310e0b7d1735ba726c517 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7426 Tested-by: jenkins Reviewed-by: Evgeniy Didin --- src/target/arc.h | 10 -- src/target/arc_cmd.c | 229 ++++++++++++++++++------------------------- 2 files changed, 96 insertions(+), 143 deletions(-) diff --git a/src/target/arc.h b/src/target/arc.h index bb70a598e1..a351802ac6 100644 --- a/src/target/arc.h +++ b/src/target/arc.h @@ -253,16 +253,6 @@ struct arc_common { } \ } while (0) -#define JIM_CHECK_RETVAL(action) \ - do { \ - int __retval = (action); \ - if (__retval != JIM_OK) { \ - LOG_DEBUG("error while calling \"%s\"", \ - # action); \ - return __retval; \ - } \ - } while (0) - static inline struct arc_common *target_to_arc(struct target *target) { return target->arch_info; diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 3b0bf76f80..e7760b0378 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -55,21 +55,6 @@ static const char *validate_register(const struct arc_reg_desc * const reg, bool return NULL; } -/* Helper function to read the name of register type or register from - * configure files */ -static int jim_arc_read_reg_name_field(struct jim_getopt_info *goi, - const char **name, int *name_len) -{ - int e = JIM_OK; - - if (!goi->argc) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-name ..."); - return JIM_ERR; - } - e = jim_getopt_string(goi, name, name_len); - return e; -} - static COMMAND_HELPER(arc_handle_add_reg_type_flags_ops, struct arc_reg_data_type *type) { struct reg_data_type_flags_field *fields = type->reg_type_flags_field; @@ -528,7 +513,7 @@ enum opts_add_reg { CFG_ADD_REG_GENERAL, }; -static struct jim_nvp opts_nvp_add_reg[] = { +static const struct nvp opts_nvp_add_reg[] = { { .name = "-name", .value = CFG_ADD_REG_NAME }, { .name = "-num", .value = CFG_ADD_REG_ARCH_NUM }, { .name = "-core", .value = CFG_ADD_REG_IS_CORE }, @@ -546,155 +531,133 @@ void free_reg_desc(struct arc_reg_desc *r) free(r); } -static int jim_arc_add_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +static COMMAND_HELPER(arc_handle_add_reg_do, struct arc_reg_desc *reg) { - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - struct arc_reg_desc *reg = calloc(1, sizeof(*reg)); - if (!reg) { - Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); - return JIM_ERR; - } - /* There is no architecture number that we could treat as invalid, so * separate variable required to ensure that arch num has been set. */ bool arch_num_set = false; const char *type_name = "int"; /* Default type */ - int type_name_len = strlen(type_name); - int e = ERROR_OK; /* At least we need to specify 4 parameters: name, number and gdb_feature, * which means there should be 6 arguments. Also there can be additional parameters * "-type ", "-g" and "-core" or "-bcr" which makes maximum 10 parameters. */ - if (goi.argc < 6 || goi.argc > 10) { - free_reg_desc(reg); - Jim_SetResultFormatted(goi.interp, - "Should be at least 6 arguments and not greater than 10: " - " -name -num -feature " - " [-type ] [-core|-bcr] [-g]."); - return JIM_ERR; - } + if (CMD_ARGC < 6 || CMD_ARGC > 10) + return ERROR_COMMAND_SYNTAX_ERROR; /* Parse options. */ - while (goi.argc > 0) { - struct jim_nvp *n; - e = jim_getopt_nvp(&goi, opts_nvp_add_reg, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, opts_nvp_add_reg, 0); - free_reg_desc(reg); - return e; - } - + while (CMD_ARGC) { + const struct nvp *n = nvp_name2value(opts_nvp_add_reg, CMD_ARGV[0]); + CMD_ARGC--; + CMD_ARGV++; switch (n->value) { - case CFG_ADD_REG_NAME: - { - const char *reg_name = NULL; - int reg_name_len = 0; - - e = jim_arc_read_reg_name_field(&goi, ®_name, ®_name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read register name."); - free_reg_desc(reg); - return e; - } - - reg->name = strndup(reg_name, reg_name_len); - break; - } - case CFG_ADD_REG_IS_CORE: - reg->is_core = true; - break; - case CFG_ADD_REG_IS_BCR: - reg->is_bcr = true; - break; - case CFG_ADD_REG_ARCH_NUM: - { - jim_wide archnum; - - if (!goi.argc) { - free_reg_desc(reg); - Jim_WrongNumArgs(interp, goi.argc, goi.argv, "-num ..."); - return JIM_ERR; - } - - e = jim_getopt_wide(&goi, &archnum); - if (e != JIM_OK) { - free_reg_desc(reg); - return e; - } - - reg->arch_num = archnum; - arch_num_set = true; - break; + case CFG_ADD_REG_NAME: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg->name = strdup(CMD_ARGV[0]); + if (!reg->name) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - case CFG_ADD_REG_GDB_FEATURE: - { - const char *feature = NULL; - int feature_len = 0; - - e = jim_arc_read_reg_name_field(&goi, &feature, &feature_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read gdb_feature."); - free_reg_desc(reg); - return e; - } - - reg->gdb_xml_feature = strndup(feature, feature_len); - break; + + CMD_ARGC--; + CMD_ARGV++; + break; + + case CFG_ADD_REG_IS_CORE: + reg->is_core = true; + break; + + case CFG_ADD_REG_IS_BCR: + reg->is_bcr = true; + break; + + case CFG_ADD_REG_ARCH_NUM: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg->arch_num); + CMD_ARGC--; + CMD_ARGV++; + + arch_num_set = true; + break; + + case CFG_ADD_REG_GDB_FEATURE: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg->gdb_xml_feature = strdup(CMD_ARGV[0]); + if (!reg->gdb_xml_feature) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - case CFG_ADD_REG_TYPE: - e = jim_arc_read_reg_name_field(&goi, &type_name, &type_name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read register type."); - free_reg_desc(reg); - return e; - } - - break; - case CFG_ADD_REG_GENERAL: - reg->is_general = true; - break; - default: - LOG_DEBUG("Error: Unknown parameter"); - free_reg_desc(reg); - return JIM_ERR; + + CMD_ARGC--; + CMD_ARGV++; + break; + + case CFG_ADD_REG_TYPE: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + type_name = CMD_ARGV[0]; + CMD_ARGC--; + CMD_ARGV++; + break; + + case CFG_ADD_REG_GENERAL: + reg->is_general = true; + break; + + default: + nvp_unknown_command_print(CMD, opts_nvp_add_reg, NULL, CMD_ARGV[-1]); + return ERROR_COMMAND_ARGUMENT_INVALID; } } /* Check that required fields are set */ const char * const errmsg = validate_register(reg, arch_num_set); if (errmsg) { - Jim_SetResultFormatted(goi.interp, errmsg); - free_reg_desc(reg); - return JIM_ERR; + command_print(CMD, "%s", errmsg); + return ERROR_COMMAND_ARGUMENT_INVALID; } /* Add new register */ - struct command_context *ctx; - struct target *target; - - ctx = current_command_context(interp); - assert(ctx); - target = get_current_target(ctx); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - free_reg_desc(reg); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } reg->target = target; - e = arc_reg_add(target, reg, type_name, type_name_len); - if (e == ERROR_ARC_REGTYPE_NOT_FOUND) { - Jim_SetResultFormatted(goi.interp, + int retval = arc_reg_add(target, reg, type_name, strlen(type_name)); + if (retval == ERROR_ARC_REGTYPE_NOT_FOUND) { + command_print(CMD, "Cannot find type `%s' for register `%s'.", type_name, reg->name); + return retval; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(arc_handle_add_reg) +{ + struct arc_reg_desc *reg = calloc(1, sizeof(*reg)); + if (!reg) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + int retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_do, reg); + if (retval != ERROR_OK) { free_reg_desc(reg); - return JIM_ERR; + return retval; } - return e; + return ERROR_OK; } /* arc set-reg-exists ($reg_name)+ @@ -887,7 +850,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "add-reg", - .jim_handler = jim_arc_add_reg, + .handler = arc_handle_add_reg, .mode = COMMAND_CONFIG, .usage = "-name -num -feature [-gdbnum ] " "[-core|-bcr] [-type ] [-g]", From b6021e856a9259aac5dcba45bb3a5d8ae307886b Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 30 Jan 2023 16:38:45 +0100 Subject: [PATCH 25/50] flash/nor/stm32l4x: Add revision 'Z' for STM32L552/562 devices Change-Id: Icc6058ef1f43e969a2a9baadfaf382ac820a7b76 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/7468 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/stm32l4x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index c67dbf75dc..02e737b87c 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -318,7 +318,7 @@ static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = { }; static const struct stm32l4_rev stm32l55_l56xx_revs[] = { - { 0x1000, "A" }, { 0x2000, "B" }, + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; static const struct stm32l4_rev stm32g49_g4axx_revs[] = { From 1998b1e5a89e57b2d1109bc36d6af916106103ff Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 2 Feb 2023 14:25:27 +0100 Subject: [PATCH 26/50] README: Remove statement about libjaylink Git submodule Change-Id: I552c08979849c66d7f8f559ccfd49d27f8b68bb8 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/7470 Tested-by: jenkins Reviewed-by: Antonio Borneo --- README | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README b/README index 2f71cfc6a3..7d3f10def0 100644 --- a/README +++ b/README @@ -240,8 +240,7 @@ Optional CMSIS-DAP adapter driver needs HIDAPI library. Optional linuxgpiod adapter driver needs libgpiod library. -Optional JLink adapter driver needs libjaylink; build from git can -retrieve libjaylink as git submodule. +Optional J-Link adapter driver needs libjaylink library. Optional ARM disassembly needs capstone library. From 85ae73de03ebcc723842b7978a6c94b73166f027 Mon Sep 17 00:00:00 2001 From: Andreas Bolsch Date: Wed, 9 Mar 2022 17:22:50 +0100 Subject: [PATCH 27/50] new SPI memory devices, continuation code for manufacturer id A bunch of new SPI flash (Adesto, Cypress, XTX Tech, mainly octal) IDs and SPI FRAM (Infineon) IDs added. Backward compatible change of ID interpretation: The previously unused 4th byte now acts as continuation code (0x7F) count for manufacturer id, cf. JEDEC JEP106BC. Currently this affects only some recent octal flash and FRAM devices, which are only supported by stmqspi and cmspi flash drivers. Change-Id: Ibdcac81a84c636dc68439add4461b959df429bca Signed-off-by: Andreas Bolsch Reviewed-on: https://review.openocd.org/c/openocd/+/6929 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/spi.c | 73 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 9a606d5459..b83df96775 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -23,7 +23,9 @@ * from device datasheets and Linux SPI flash drivers. */ const struct flash_device flash_devices[] = { /* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id, - * pagesize, sectorsize, size_in_bytes */ + * pagesize, sectorsize, size_in_bytes + * note: device id is usually 3 bytes long, however the unused highest byte counts + * continuation codes for manufacturer id as per JEP106xx */ FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), FLASH_ID("st m25p10", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), FLASH_ID("st m25p20", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), @@ -51,12 +53,28 @@ const struct flash_device flash_devices[] = { FLASH_ID("cyp s25fl064l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00176001, 0x100, 0x10000, 0x800000), FLASH_ID("cyp s25fl128l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00186001, 0x100, 0x10000, 0x1000000), FLASH_ID("cyp s25fl256l", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000), + FLASH_ID("cyp s28hl256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195a34, 0x100, 0x40000, 0x2000000), /* page! */ + FLASH_ID("cyp s28hs256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195b34, 0x100, 0x40000, 0x2000000), /* page! */ + FLASH_ID("cyp s28hl512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5a34, 0x100, 0x40000, 0x4000000), /* page! */ + FLASH_ID("cyp s28hs512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5b34, 0x100, 0x40000, 0x4000000), /* page! */ + FLASH_ID("cyp s28hl01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5a34, 0x100, 0x40000, 0x8000000), /* page! */ + FLASH_ID("cyp s28hs01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5b34, 0x100, 0x40000, 0x8000000), /* page! */ FLASH_ID("atmel 25f512", 0x03, 0x00, 0x02, 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), FLASH_ID("atmel 25f1024", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), FLASH_ID("atmel 25f2048", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), FLASH_ID("atmel 25f4096", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), FLASH_ID("atmel 25fs040", 0x03, 0x00, 0x02, 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), + FLASH_ID("adesto 25sf041b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001841f, 0x100, 0x10000, 0x80000), FLASH_ID("adesto 25df081a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001451f, 0x100, 0x10000, 0x100000), + FLASH_ID("adesto 25sf081b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001851f, 0x100, 0x10000, 0x100000), + FLASH_ID("adesto 25sf161b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001861f, 0x100, 0x10000, 0x200000), + FLASH_ID("adesto 25df321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001471f, 0x100, 0x10000, 0x400000), + FLASH_ID("adesto 25sf321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001871f, 0x100, 0x10000, 0x400000), + FLASH_ID("adesto 25xf641b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001881f, 0x100, 0x10000, 0x800000), /* sf/qf */ + FLASH_ID("adesto 25xf128a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001891f, 0x100, 0x10000, 0x1000000), /* sf/qf */ + FLASH_ID("adesto xp032", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0700a743, 0x100, 0x10000, 0x400000), /* 4-byte */ + FLASH_ID("adesto xp064b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0001a81f, 0x100, 0x10000, 0x800000), /* 4-byte */ + FLASH_ID("adesto xp128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0000a91f, 0x100, 0x10000, 0x1000000), /* 4-byte */ FLASH_ID("mac 25l512", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), FLASH_ID("mac 25l1005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), FLASH_ID("mac 25l2005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), @@ -78,6 +96,9 @@ const struct flash_device flash_devices[] = { FLASH_ID("mac 25r3235f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001628c2, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25r6435f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001728c2, 0x100, 0x10000, 0x800000), FLASH_ID("mac 25u1635e", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x003525c2, 0x100, 0x1000, 0x100000), + FLASH_ID("mac 66l1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b20c2, 0x100, 0x10000, 0x8000000), + FLASH_ID("mac 66um1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b80c2, 0x100, 0x10000, 0x8000000), + FLASH_ID("mac 66lm1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b85c2, 0x100, 0x10000, 0x8000000), FLASH_ID("micron n25q032", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0016ba20, 0x100, 0x10000, 0x400000), FLASH_ID("micron n25q064", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), FLASH_ID("micron n25q128", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), @@ -102,6 +123,10 @@ const struct flash_device flash_devices[] = { FLASH_ID("win w25q256fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001940ef, 0x100, 0x10000, 0x2000000), FLASH_ID("win w25q256fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001960ef, 0x100, 0x10000, 0x2000000), /* QPI mode */ FLASH_ID("win w25q256jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001970ef, 0x100, 0x10000, 0x2000000), + FLASH_ID("win w25q512jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x002040ef, 0x100, 0x10000, 0x4000000), + FLASH_ID("win w25q01jv", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002140ef, 0x100, 0x10000, 0x8000000), + FLASH_ID("win w25q01jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002170ef, 0x100, 0x10000, 0x8000000), + FLASH_ID("win w25q02jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002270ef, 0x100, 0x10000, 0x10000000), FLASH_ID("gd gd25q512", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001040c8, 0x100, 0x1000, 0x10000), FLASH_ID("gd gd25q10", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001140c8, 0x100, 0x1000, 0x20000), FLASH_ID("gd gd25q20", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001240c8, 0x100, 0x1000, 0x40000), @@ -109,9 +134,10 @@ const struct flash_device flash_devices[] = { FLASH_ID("gd gd25q16c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), FLASH_ID("gd gd25q32c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), FLASH_ID("gd gd25q64c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001740c8, 0x100, 0x10000, 0x800000), - FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), + FLASH_ID("gd gd25q128c", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000), FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000), + FLASH_ID("gd gd25lx256e", 0x13, 0x0c, 0x12, 0xdc, 0xc7, 0x001968c8, 0x100, 0x10000, 0x2000000), FLASH_ID("zbit zb25vq16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015605e, 0x100, 0x10000, 0x200000), FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016405e, 0x100, 0x10000, 0x400000), FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016605e, 0x100, 0x10000, 0x400000), /* QPI mode */ @@ -128,6 +154,18 @@ const struct flash_device flash_devices[] = { FLASH_ID("issi is25wp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000), FLASH_ID("issi is25lp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a609d, 0x100, 0x10000, 0x4000000), FLASH_ID("issi is25wp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a709d, 0x100, 0x10000, 0x4000000), + FLASH_ID("xtx xt25f02e", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0012400b, 0x100, 0x10000, 0x40000), + FLASH_ID("xtx xt25f04d", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0013400b, 0x100, 0x10000, 0x80000), + FLASH_ID("xtx xt25f08b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0014400b, 0x100, 0x10000, 0x100000), + FLASH_ID("xtx xt25f16b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015400b, 0x100, 0x10000, 0x200000), + FLASH_ID("xtx xt25f32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016400b, 0x100, 0x10000, 0x200000), + FLASH_ID("xtx xt25f64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017400b, 0x100, 0x10000, 0x400000), + FLASH_ID("xtx xt25f128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018400b, 0x100, 0x10000, 0x800000), + FLASH_ID("xtx xt25q08d", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0014600b, 0x100, 0x10000, 0x100000), + FLASH_ID("xtx xt25q16b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0015600b, 0x100, 0x10000, 0x200000), + FLASH_ID("xtx xt25q32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016600b, 0x100, 0x10000, 0x400000), /* exists ? */ + FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000), + FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000), /* FRAM, no erase commands, no write page or sectors */ FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800), @@ -138,13 +176,30 @@ const struct flash_device flash_devices[] = { FRAM_ID("fu mb85rs512t", 0x03, 0, 0x02, 0x00032604, 0x10000), FRAM_ID("fu mb85rs1mt", 0x03, 0, 0x02, 0x00032704, 0x20000), FRAM_ID("fu mb85rs2mta", 0x03, 0, 0x02, 0x00034804, 0x40000), - FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x000821c2, 0x4000), - FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x000022c2, 0x8000), - FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x000822c2, 0x8000), - FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x000023c2, 0x10000), - FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x000024c2, 0x20000), - FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x000825c2, 0x40000), - FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x004026c2, 0x80000), + FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x060821c2, 0x4000), + FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x060022c2, 0x8000), + FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x060822c2, 0x8000), + FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x060023c2, 0x10000), + FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x060024c2, 0x20000), + FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x060825c2, 0x40000), + FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x064026c2, 0x80000), + FRAM_ID("cyp cy15b102qn", 0x03, 0, 0x02, 0x06002ac2, 0x40000), + FRAM_ID("cyp cy15v102qn", 0x03, 0, 0x02, 0x06042ac2, 0x40000), + FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06012dc2, 0x80000), + FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06a12dc2, 0x80000), + FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06052dc2, 0x80000), + FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06a52dc2, 0x80000), + FRAM_ID("cyp cy15b104qn", 0x03, 0, 0x02, 0x06402cc2, 0x80000), + FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06012fc2, 0x100000), + FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06a12fc2, 0x100000), + FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06052fc2, 0x100000), + FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06a52fc2, 0x100000), + FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06012ec2, 0x100000), + FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06032ec2, 0x100000), + FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06a12ec2, 0x100000), + FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06052ec2, 0x100000), + FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06072ec2, 0x100000), + FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06a52ec2, 0x100000), FLASH_ID(NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0) }; From 79caea8745284ac1d2e8931335b58c679cd11882 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Thu, 22 Dec 2022 22:28:21 +0100 Subject: [PATCH 28/50] flash/nor/spi: add 25pe{10/20/40/80/16} Change-Id: Ic5660bff83b8636ef397482a3313971ecdff72c0 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7416 Tested-by: jenkins Reviewed-by: Andreas Bolsch Reviewed-by: Antonio Borneo --- src/flash/nor/spi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index b83df96775..3bcaa9f613 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -26,6 +26,11 @@ const struct flash_device flash_devices[] = { * pagesize, sectorsize, size_in_bytes * note: device id is usually 3 bytes long, however the unused highest byte counts * continuation codes for manufacturer id as per JEP106xx */ + FLASH_ID("st m25pe10", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00118020, 0x100, 0x10000, 0x20000), + FLASH_ID("st m25pe20", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00128020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m25pe40", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00138020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m25pe80", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00148020, 0x100, 0x10000, 0x100000), + FLASH_ID("st m25pe16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00158020, 0x100, 0x10000, 0x200000), FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), FLASH_ID("st m25p10", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), FLASH_ID("st m25p20", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), From c99c043f3f6e79e391debee29371360b0965b2d6 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 19 Dec 2022 19:41:46 +0100 Subject: [PATCH 29/50] helper: command: drop last LF ('\n') from sequence of command_print() The OpenOCD commands produce their TCL text result through the pair command_print() and command_print_sameline(). The latter is used to concatenate output in a single line. At the end of a sequence of command_print(), the last LF is taken as part of the command result, while it is not always needed, and it is even annoying when the output of two commands needs to be concatenate in a single line. Using command_print_sameline() in place of the last call to command_print() would solve the problem but it's quite expensive in term of coding to fix all the existing commands. Drop the last LF, if present. Commands that would specifically need a LF as last char, can add an extra LF at the end of the output. Document this behavior in command.h. Change-Id: I6757c20fbfce923dd393083146e8d5a1f3b790b4 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7471 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/helper/command.c | 12 ++++++++++-- src/helper/command.h | 11 +++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/helper/command.c b/src/helper/command.c index ca66cf7dd1..12434ec90e 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -543,8 +543,16 @@ static int run_command(struct command_context *context, if (retval != ERROR_OK) LOG_DEBUG("Command '%s' failed with error code %d", words[0], retval); - /* Use the command output as the Tcl result */ - Jim_SetResult(context->interp, cmd.output); + /* + * Use the command output as the Tcl result. + * Drop last '\n' to allow command output concatenation + * while keep using command_print() everywhere. + */ + const char *output_txt = Jim_String(cmd.output); + int len = strlen(output_txt); + if (len && output_txt[len - 1] == '\n') + --len; + Jim_SetResultString(context->interp, output_txt, len); } Jim_DecrRefCount(context->interp, cmd.output); diff --git a/src/helper/command.h b/src/helper/command.h index 478e5c8ada..42cb9cb7d8 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -370,10 +370,21 @@ struct command_context *copy_command_context(struct command_context *cmd_ctx); */ void command_done(struct command_context *context); +/* + * command_print() and command_print_sameline() are used to produce the TCL + * output of OpenOCD commands. command_print() automatically adds a '\n' at + * the end or the format string. Use command_print_sameline() to avoid the + * trailing '\n', e.g. to concatenate the command output in the same line. + * The very last '\n' of the command is stripped away (see run_command()). + * For commands that strictly require a '\n' as last output character, add + * it explicitly with either an empty command_print() or with a '\n' in the + * last command_print() and add a comment to document it. + */ void command_print(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); void command_print_sameline(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); + int command_run_line(struct command_context *context, char *line); int command_run_linef(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); From 0a20e78b759efa86a676b4a9fed4027fdd84e90c Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 17 Feb 2023 18:26:05 -0800 Subject: [PATCH 30/50] jtag/drivers/cmsis_dap: run queue on reaching transaction limit We currently fail the transfer when issuing more than 255 transactions at once, e.g. > read_memory 0x10000000 32 256 CMSIS-DAP transfer count mismatch: expected 257, got 1 This is because the protocol only supports 255 transactions per packet (65535 for block transactions), and as a result we truncate the transaction count when assembling the packet. Fix it by running the queue when we hit the limit. Change-Id: Ia9e01e3af5ad035f2cf2a32292c9d66e57eafae9 Signed-off-by: Peter Collingbourne Fixes: 40bac8e8c4e5 ("jtag/drivers/cmsis_dap: improve USB packets filling") Reviewed-on: https://review.openocd.org/c/openocd/+/7483 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/drivers/cmsis_dap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 0c42a7f1e0..1e7a851e4b 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -1001,12 +1001,14 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) block_cmd); unsigned int resp_size = cmsis_dap_tfer_resp_size(write_count, read_count, block_cmd); + unsigned int max_transfer_count = block_cmd ? 65535 : 255; /* Does the DAP Transfer command and the expected response fit into one packet? * Run the queue also before a targetsel - it cannot be queued */ if (cmd_size > tfer_max_command_size || resp_size > tfer_max_response_size - || targetsel_cmd) { + || targetsel_cmd + || write_count + read_count > max_transfer_count) { if (cmsis_dap_handle->pending_fifo_block_count) cmsis_dap_swd_read_process(cmsis_dap_handle, 0); From fc30feb51a76e893646e2794c99a78dbdc0d251f Mon Sep 17 00:00:00 2001 From: Tomas Deingruber Date: Tue, 28 Feb 2023 23:17:56 +0000 Subject: [PATCH 31/50] tlc/interface: does fix source of raspberrypi-gpio-connector.cfg in raspberrypi-native.cfg Fixes: bec6c0eb094f (tcl/interface: universal config for all Raspberry Pi models) Signed-off-by: Tomas Deingruber Change-Id: I632c8acd84974937849b5fdf2943239def17bd6d Reviewed-on: https://review.openocd.org/c/openocd/+/7512 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- tcl/interface/raspberrypi-native.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/interface/raspberrypi-native.cfg b/tcl/interface/raspberrypi-native.cfg index 95426c2263..7224723d63 100644 --- a/tcl/interface/raspberrypi-native.cfg +++ b/tcl/interface/raspberrypi-native.cfg @@ -68,4 +68,4 @@ set speed_coeff [expr { $clock / $clocks_per_timing_loop }] # The coefficients depend on system clock and CPU frequency scaling. bcm2835gpio speed_coeffs $speed_coeff $speed_offset -source raspberrypi-gpio-connector.cfg +source [find interface/raspberrypi-gpio-connector.cfg] From e1b0d5759a1e9221d534400505c6eb7e43abd051 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 3 Mar 2023 16:50:38 +0100 Subject: [PATCH 32/50] tcl/board/at91sam9g20-ek: remove outdated FIXME It was fixed by e94180571 ("at91sam9: factorise cpu support") in 2011. Signed-off-by: Wolfram Sang Change-Id: I95ea149b45a9902424bf9068b4a2830c17ddc6be Reviewed-on: https://review.openocd.org/c/openocd/+/7525 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/board/at91sam9g20-ek.cfg | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tcl/board/at91sam9g20-ek.cfg b/tcl/board/at91sam9g20-ek.cfg index a5831cd91c..4740471c89 100644 --- a/tcl/board/at91sam9g20-ek.cfg +++ b/tcl/board/at91sam9g20-ek.cfg @@ -7,10 +7,6 @@ # # ################################################################################################# -# FIXME use some standard target config, maybe create one from this -# -# source [find target/...cfg] - source [find target/at91sam9g20.cfg] set _FLASHTYPE nandflash_cs3 From c8f56b4f00a1b8d7cc74f08b34466b2017c1f1dc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 3 Mar 2023 17:00:19 +0100 Subject: [PATCH 33/50] TODO: remove outdated AT91SAM92xx entry SAM9260 gained good generic infrastructure since 2009. And we always want "improvements", no need for a TODO item. Signed-off-by: Wolfram Sang Change-Id: I92551ef9d42ee47ad7441f2354587bbb45edc97e Reviewed-on: https://review.openocd.org/c/openocd/+/7526 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index ebb6c99808..e4dded0ce6 100644 --- a/TODO +++ b/TODO @@ -202,8 +202,6 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html - MC1322x support (JW/DE?) - integrate and test support from JW (and DE?) - get working with a known good interface (i.e. not today's jlink) -- AT91SAM92xx: - - improvements for unknown-board-atmel-at91sam9260.cfg (RD) - STR9x: (ZW) - improvements to str912.cfg to be more general purpose - AVR: (SQ) From c7e0040689db1fc2673c117e038ffb3a88f6562b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 6 Mar 2023 15:31:08 +0100 Subject: [PATCH 34/50] drivers/libusb_helper: allow external use of jtag_libusb_match_ids() Can be employed by a driver with custom libusb open. Change-Id: I00c8a01df8780891a8b7c30e2e34ab191acdf9a8 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7528 Tested-by: jenkins Reviewed-by: Wolfram Sang Reviewed-by: Antonio Borneo --- src/jtag/drivers/libusb_helper.c | 2 +- src/jtag/drivers/libusb_helper.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/libusb_helper.c b/src/jtag/drivers/libusb_helper.c index 53dfd502d3..4b098b482f 100644 --- a/src/jtag/drivers/libusb_helper.c +++ b/src/jtag/drivers/libusb_helper.c @@ -50,7 +50,7 @@ static int jtag_libusb_error(int err) } } -static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, +bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, const uint16_t vids[], const uint16_t pids[]) { for (unsigned i = 0; vids[i]; i++) { diff --git a/src/jtag/drivers/libusb_helper.h b/src/jtag/drivers/libusb_helper.h index 172c345981..799e3e6a91 100644 --- a/src/jtag/drivers/libusb_helper.h +++ b/src/jtag/drivers/libusb_helper.h @@ -30,6 +30,8 @@ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *device, struct libusb_device_descriptor *dev_desc); +bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, + const uint16_t vids[], const uint16_t pids[]); int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial); From a8bc4e75b3dda3d32345fa310a3be724235d8fa8 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 6 Mar 2023 15:37:43 +0100 Subject: [PATCH 35/50] drivers/ftdi: prevent misleading error msg when more vid/pids configured The driver tries to open mpsse engine for each vid pid pair in sequence. If more vid/pid pairs are configured and the USB device does not correspond to the first pair, the driver shows 'unable to open ftdi device ...' error. Match vid pid with the whole list as used in jtag_libusb_open() instead of multiple mpsse_open() in for loop over vid/pid pairs. Change-Id: I8ef55205be221c727607fe25b81ae21de0d96f02 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7529 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Wolfram Sang --- src/jtag/drivers/ftdi.c | 7 +------ src/jtag/drivers/mpsse.c | 20 +++++++------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 3097d41296..6356a4929b 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -658,13 +658,8 @@ static int ftdi_initialize(void) return ERROR_JTAG_INIT_FAILED; } - for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) { - mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc, + mpsse_ctx = mpsse_open(ftdi_vid, ftdi_pid, ftdi_device_desc, adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel); - if (mpsse_ctx) - break; - } - if (!mpsse_ctx) return ERROR_JTAG_INIT_FAILED; diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index 18aeb38a48..9f2fdde9fb 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -13,6 +13,7 @@ #include "helper/log.h" #include "helper/replacements.h" #include "helper/time_support.h" +#include "libusb_helper.h" #include /* Compatibility define for older libusb-1.0 */ @@ -148,7 +149,7 @@ static bool device_location_equal(struct libusb_device *device, const char *loca * Set any field to 0 as a wildcard. If the device is found true is returned, with ctx containing * the already opened handle. ctx->interface must be set to the desired interface (channel) number * prior to calling this function. */ -static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, const uint16_t *pid, +static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t vids[], const uint16_t pids[], const char *product, const char *serial, const char *location) { struct libusb_device **list; @@ -169,9 +170,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con continue; } - if (vid && *vid != desc.idVendor) - continue; - if (pid && *pid != desc.idProduct) + if (!jtag_libusb_match_ids(&desc, vids, pids)) continue; err = libusb_open(device, &ctx->usb_dev); @@ -203,7 +202,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con libusb_free_device_list(list, 1); if (!found) { - LOG_ERROR("no device found"); + /* The caller reports detailed error desc */ return false; } @@ -307,7 +306,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con return false; } -struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const char *description, +struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const char *description, const char *serial, const char *location, int channel) { struct mpsse_ctx *ctx = calloc(1, sizeof(*ctx)); @@ -343,14 +342,9 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha goto error; } - if (!open_matching_device(ctx, vid, pid, description, serial, location)) { - /* Four hex digits plus terminating zero each */ - char vidstr[5]; - char pidstr[5]; - LOG_ERROR("unable to open ftdi device with vid %s, pid %s, description '%s', " + if (!open_matching_device(ctx, vids, pids, description, serial, location)) { + LOG_ERROR("unable to open ftdi device with description '%s', " "serial '%s' at bus location '%s'", - vid ? sprintf(vidstr, "%04x", *vid), vidstr : "*", - pid ? sprintf(pidstr, "%04x", *pid), pidstr : "*", description ? description : "*", serial ? serial : "*", location ? location : "*"); From 70d771c7b7d488c76452191fb1a2a8bdfa9a2f25 Mon Sep 17 00:00:00 2001 From: Andrew Lalaev Date: Sun, 5 Mar 2023 20:36:32 +0100 Subject: [PATCH 36/50] flash/nor/at91samd: fix RAM size for SAMR34/35 According to the datasheets these MCUs have 40Kb RAM. Signed-off-by: Andrew Lalaev Change-Id: I52b8a0c86035bccd6f3c1a478bb2e558bca4ae86 Reviewed-on: https://review.openocd.org/c/openocd/+/7520 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/at91samd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 33e86c76e9..b3252e8704 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -243,8 +243,8 @@ static const struct samd_part saml21_parts[] = { { 0x1F, "SAMR30E18A", 256, 32 }, /* SAMR34/R35 parts have integrated SAML21 with a lora radio */ - { 0x28, "SAMR34J18", 256, 32 }, - { 0x2B, "SAMR35J18", 256, 32 }, + { 0x28, "SAMR34J18", 256, 40 }, + { 0x2B, "SAMR35J18", 256, 40 }, }; /* Known SAML22 parts. */ From 8d1261c248796d5eee9ec8e646d16d653be984a6 Mon Sep 17 00:00:00 2001 From: Andrew Lalaev Date: Sun, 5 Mar 2023 20:41:14 +0100 Subject: [PATCH 37/50] flash/nor/at91samd: add missing SAMR34/35 part numbers All DIDs are taken from "SAM R34/R35 Errata Sheet" (DS80000834A). Signed-off-by: Andrew Lalaev Change-Id: Ie35f58e61bb02919c0676c91938c90192481d995 Reviewed-on: https://review.openocd.org/c/openocd/+/7521 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/at91samd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index b3252e8704..416f077783 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -244,7 +244,11 @@ static const struct samd_part saml21_parts[] = { /* SAMR34/R35 parts have integrated SAML21 with a lora radio */ { 0x28, "SAMR34J18", 256, 40 }, + { 0x29, "SAMR34J17", 128, 24 }, + { 0x2A, "SAMR34J16", 64, 12 }, { 0x2B, "SAMR35J18", 256, 40 }, + { 0x2C, "SAMR35J17", 128, 24 }, + { 0x2D, "SAMR35J16", 64, 12 }, }; /* Known SAML22 parts. */ From a7f8a1d7fb8e6628f34340a5777ce600dc27f8d8 Mon Sep 17 00:00:00 2001 From: Chao Du Date: Wed, 8 Mar 2023 07:17:13 +0000 Subject: [PATCH 38/50] doc: add missing FreeRTOS symbol A new FreeRTOS symbol xSchedulerRunning was added into the symbol list. But the doc was not updated accordingly. Signed-off-by: Chao Du Change-Id: If1b18591e2681477ad96f1dea566cc2547097767 Reviewed-on: https://review.openocd.org/c/openocd/+/7531 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- doc/openocd.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 6c853f2ce4..414b4c4057 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11887,7 +11887,7 @@ _tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count. @raggedright pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2, pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList, -uxCurrentNumberOfTasks, uxTopUsedPriority. +uxCurrentNumberOfTasks, uxTopUsedPriority, xSchedulerRunning. @end raggedright @item linux symbols init_task. From 047b1a8fc237af480e3bab66a9827a358afd7547 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 1 Mar 2023 20:20:29 -0800 Subject: [PATCH 39/50] target/image: zero-initialize ELF segments up to p_memsz We were previously not zero-initializing ELF segments between p_filesz and p_memsz (aka BSS). However, this may be necessary depending on the user's application. Therefore, start doing so. Change-Id: I5a743390069583aca7ee276f53afeccf2cac0855 Signed-off-by: Peter Collingbourne Reviewed-on: https://review.openocd.org/c/openocd/+/7513 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/image.c | 54 +++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/src/target/image.c b/src/target/image.c index f8de7a23e3..6aa609d397 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -407,12 +407,10 @@ static int image_elf32_read_headers(struct image *image) return ERROR_FILEIO_OPERATION_FAILED; } - /* count useful segments (loadable), ignore BSS section */ + /* count useful segments (loadable) */ image->num_sections = 0; for (i = 0; i < elf->segment_count; i++) - if ((field32(elf, - elf->segments32[i].p_type) == PT_LOAD) && - (field32(elf, elf->segments32[i].p_filesz) != 0)) + if (field32(elf, elf->segments32[i].p_type) == PT_LOAD) image->num_sections++; if (image->num_sections == 0) { @@ -449,10 +447,8 @@ static int image_elf32_read_headers(struct image *image) } for (i = 0, j = 0; i < elf->segment_count; i++) { - if ((field32(elf, - elf->segments32[i].p_type) == PT_LOAD) && - (field32(elf, elf->segments32[i].p_filesz) != 0)) { - image->sections[j].size = field32(elf, elf->segments32[i].p_filesz); + if (field32(elf, elf->segments32[i].p_type) == PT_LOAD) { + image->sections[j].size = field32(elf, elf->segments32[i].p_memsz); if (load_to_vaddr) image->sections[j].base_address = field32(elf, elf->segments32[i].p_vaddr); @@ -532,12 +528,10 @@ static int image_elf64_read_headers(struct image *image) return ERROR_FILEIO_OPERATION_FAILED; } - /* count useful segments (loadable), ignore BSS section */ + /* count useful segments (loadable) */ image->num_sections = 0; for (i = 0; i < elf->segment_count; i++) - if ((field32(elf, - elf->segments64[i].p_type) == PT_LOAD) && - (field64(elf, elf->segments64[i].p_filesz) != 0)) + if (field32(elf, elf->segments64[i].p_type) == PT_LOAD) image->num_sections++; if (image->num_sections == 0) { @@ -574,10 +568,8 @@ static int image_elf64_read_headers(struct image *image) } for (i = 0, j = 0; i < elf->segment_count; i++) { - if ((field32(elf, - elf->segments64[i].p_type) == PT_LOAD) && - (field64(elf, elf->segments64[i].p_filesz) != 0)) { - image->sections[j].size = field64(elf, elf->segments64[i].p_filesz); + if (field32(elf, elf->segments64[i].p_type) == PT_LOAD) { + image->sections[j].size = field64(elf, elf->segments64[i].p_memsz); if (load_to_vaddr) image->sections[j].base_address = field64(elf, elf->segments64[i].p_vaddr); @@ -651,6 +643,8 @@ static int image_elf32_read_section(struct image *image, { struct image_elf *elf = image->type_private; Elf32_Phdr *segment = (Elf32_Phdr *)image->sections[section].private; + uint32_t filesz = field32(elf, segment->p_filesz); + uint32_t memsz = field32(elf, segment->p_memsz); size_t read_size, really_read; int retval; @@ -659,9 +653,9 @@ static int image_elf32_read_section(struct image *image, LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); /* read initialized data in current segment if any */ - if (offset < field32(elf, segment->p_filesz)) { + if (offset < filesz) { /* maximal size present in file for the current segment */ - read_size = MIN(size, field32(elf, segment->p_filesz) - offset); + read_size = MIN(size, filesz - offset); LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, field32(elf, segment->p_offset) + offset); /* read initialized area of the segment */ @@ -675,6 +669,8 @@ static int image_elf32_read_section(struct image *image, LOG_ERROR("cannot read ELF segment content, read failed"); return retval; } + buffer += read_size; + offset += read_size; size -= read_size; *size_read += read_size; /* need more data ? */ @@ -682,6 +678,13 @@ static int image_elf32_read_section(struct image *image, return ERROR_OK; } + /* clear bss in current segment if any */ + if (offset >= filesz) { + uint32_t memset_size = MIN(size, memsz - filesz); + memset(buffer, 0, memset_size); + *size_read += memset_size; + } + return ERROR_OK; } @@ -694,6 +697,8 @@ static int image_elf64_read_section(struct image *image, { struct image_elf *elf = image->type_private; Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private; + uint64_t filesz = field64(elf, segment->p_filesz); + uint64_t memsz = field64(elf, segment->p_memsz); size_t read_size, really_read; int retval; @@ -702,9 +707,9 @@ static int image_elf64_read_section(struct image *image, LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); /* read initialized data in current segment if any */ - if (offset < field64(elf, segment->p_filesz)) { + if (offset < filesz) { /* maximal size present in file for the current segment */ - read_size = MIN(size, field64(elf, segment->p_filesz) - offset); + read_size = MIN(size, filesz - offset); LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, field64(elf, segment->p_offset) + offset); /* read initialized area of the segment */ @@ -718,6 +723,8 @@ static int image_elf64_read_section(struct image *image, LOG_ERROR("cannot read ELF segment content, read failed"); return retval; } + buffer += read_size; + offset += read_size; size -= read_size; *size_read += read_size; /* need more data ? */ @@ -725,6 +732,13 @@ static int image_elf64_read_section(struct image *image, return ERROR_OK; } + /* clear bss in current segment if any */ + if (offset >= filesz) { + uint64_t memset_size = MIN(size, memsz - filesz); + memset(buffer, 0, memset_size); + *size_read += memset_size; + } + return ERROR_OK; } From 904d58c208ab03f09f8d8e7184d49f42f6e16533 Mon Sep 17 00:00:00 2001 From: Ian Thompson Date: Fri, 4 Nov 2022 14:54:24 -0700 Subject: [PATCH 40/50] target/xtensa: add NX support - Manual integration of NX support from xt0.2 release - No new clang static analysis warnings Signed-off-by: Ian Thompson Change-Id: I95b51ccc83e56c0d4dbf09e01969ed6a4a93d497 Reviewed-on: https://review.openocd.org/c/openocd/+/7356 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/xtensa/xtensa.c | 367 ++++++++++++++++++++---- src/target/xtensa/xtensa.h | 40 +++ src/target/xtensa/xtensa_debug_module.h | 15 + 3 files changed, 370 insertions(+), 52 deletions(-) diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index b57e2d6601..fcd00487c8 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -165,6 +165,7 @@ #define XT_SR_DDR (xtensa_regs[XT_REG_IDX_DDR].reg_num) #define XT_SR_PS (xtensa_regs[XT_REG_IDX_PS].reg_num) #define XT_SR_WB (xtensa_regs[XT_REG_IDX_WINDOWBASE].reg_num) +#define XT_REG_A0 (xtensa_regs[XT_REG_IDX_AR0].reg_num) #define XT_REG_A3 (xtensa_regs[XT_REG_IDX_AR3].reg_num) #define XT_REG_A4 (xtensa_regs[XT_REG_IDX_AR4].reg_num) @@ -173,6 +174,7 @@ #define XT_EPC_REG_NUM_BASE (0xb0U) /* (EPC1 - 1), for adding DBGLEVEL */ #define XT_PC_REG_NUM_VIRTUAL (0xffU) /* Marker for computing PC (EPC[DBGLEVEL) */ #define XT_PC_DBREG_NUM_BASE (0x20U) /* External (i.e., GDB) access */ +#define XT_NX_IBREAKC_BASE (0xc0U) /* (IBREAKC0..IBREAKC1) for NX */ #define XT_SW_BREAKPOINTS_MAX_NUM 32 #define XT_HW_IBREAK_MAX_NUM 2 @@ -476,7 +478,9 @@ static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(struct xtensa *x LOG_ERROR("Error: can't convert register %d to non-windowbased register!", reg_idx); return -1; } - return ((idx + windowbase * 4) & (xtensa->core_config->aregs_num - 1)) + XT_REG_IDX_AR0; + /* Each windowbase value represents 4 registers on LX and 8 on NX */ + int base_inc = (xtensa->core_config->core_type == XT_LX) ? 4 : 8; + return ((idx + windowbase * base_inc) & (xtensa->core_config->aregs_num - 1)) + XT_REG_IDX_AR0; } static enum xtensa_reg_id xtensa_canonical_to_windowbase_offset(struct xtensa *xtensa, @@ -526,26 +530,29 @@ static int xtensa_queue_pwr_reg_write(struct xtensa *xtensa, unsigned int reg, u static int xtensa_window_state_save(struct target *target, uint32_t *woe) { struct xtensa *xtensa = target_to_xtensa(target); - int woe_dis; + unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB; + uint32_t woe_dis; uint8_t woe_buf[4]; if (xtensa->core_config->windowed) { - /* Save PS (LX) and disable window overflow exceptions prior to AR save */ - xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_PS, XT_REG_A3)); + /* Save PS (LX) or WB (NX) and disable window overflow exceptions prior to AR save */ + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, woe_sr, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, woe_buf); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { - LOG_ERROR("Failed to read PS (%d)!", res); + LOG_TARGET_ERROR(target, "Failed to read %s (%d)!", + (woe_sr == XT_SR_PS) ? "PS" : "WB", res); return res; } xtensa_core_status_check(target); *woe = buf_get_u32(woe_buf, 0, 32); - woe_dis = *woe & ~XT_PS_WOE_MSK; - LOG_DEBUG("Clearing PS.WOE (0x%08" PRIx32 " -> 0x%08" PRIx32 ")", *woe, woe_dis); + woe_dis = *woe & ~((woe_sr == XT_SR_PS) ? XT_PS_WOE_MSK : XT_WB_S_MSK); + LOG_TARGET_DEBUG(target, "Clearing %s (0x%08" PRIx32 " -> 0x%08" PRIx32 ")", + (woe_sr == XT_SR_PS) ? "PS.WOE" : "WB.S", *woe, woe_dis); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe_dis); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); - xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3)); } return ERROR_OK; } @@ -554,12 +561,14 @@ static int xtensa_window_state_save(struct target *target, uint32_t *woe) static void xtensa_window_state_restore(struct target *target, uint32_t woe) { struct xtensa *xtensa = target_to_xtensa(target); + unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB; if (xtensa->core_config->windowed) { /* Restore window overflow exception state */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); - xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3)); - LOG_DEBUG("Restored PS.WOE (0x%08" PRIx32 ")", woe); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3)); + LOG_TARGET_DEBUG(target, "Restored %s (0x%08" PRIx32 ")", + (woe_sr == XT_SR_PS) ? "PS.WOE" : "WB", woe); } } @@ -596,6 +605,10 @@ static int xtensa_write_dirty_registers(struct target *target) bool preserve_a3 = false; uint8_t a3_buf[4]; xtensa_reg_val_t a3 = 0, woe; + unsigned int ms_idx = (xtensa->core_config->core_type == XT_NX) ? + xtensa->nx_reg_idx[XT_NX_REG_IDX_MS] : reg_list_size; + xtensa_reg_val_t ms; + bool restore_ms = false; LOG_TARGET_DEBUG(target, "start"); @@ -627,13 +640,25 @@ static int xtensa_write_dirty_registers(struct target *target) } else if (rlist[ridx].type == XT_REG_FR) { xtensa_queue_exec_ins(xtensa, XT_INS_WFR(xtensa, reg_num, XT_REG_A3)); } else {/*SFR */ - if (reg_num == XT_PC_REG_NUM_VIRTUAL) - /* reg number of PC for debug interrupt depends on NDEBUGLEVEL - **/ - reg_num = - (XT_EPC_REG_NUM_BASE + - xtensa->core_config->debug.irq_level); - xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3)); + if (reg_num == XT_PC_REG_NUM_VIRTUAL) { + if (xtensa->core_config->core_type == XT_LX) { + /* reg number of PC for debug interrupt depends on NDEBUGLEVEL */ + reg_num = (XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3)); + } else { + /* NX PC set through issuing a jump instruction */ + xtensa_queue_exec_ins(xtensa, XT_INS_JX(xtensa, XT_REG_A3)); + } + } else if (i == ms_idx) { + /* MS must be restored after ARs. This ensures ARs remain in correct + * order even for reversed register groups (overflow/underflow). + */ + ms = regval; + restore_ms = true; + LOG_TARGET_DEBUG(target, "Delaying MS write: 0x%x", ms); + } else { + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3)); + } } } reg_list[i].dirty = false; @@ -648,12 +673,12 @@ static int xtensa_write_dirty_registers(struct target *target) xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, - xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, - XT_REG_A3)); + xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, + XT_REG_A3)); reg_list[XT_REG_IDX_CPENABLE].dirty = false; } - preserve_a3 = (xtensa->core_config->windowed); + preserve_a3 = (xtensa->core_config->windowed) || (xtensa->core_config->core_type == XT_NX); if (preserve_a3) { /* Save (windowed) A3 for scratch use */ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); @@ -670,7 +695,12 @@ static int xtensa_write_dirty_registers(struct target *target) if (res != ERROR_OK) return res; /* Grab the windowbase, we need it. */ - windowbase = xtensa_reg_get(target, XT_REG_IDX_WINDOWBASE); + uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? + XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; + windowbase = xtensa_reg_get(target, wb_idx); + if (xtensa->core_config->core_type == XT_NX) + windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; + /* Check if there are mismatches between the ARx and corresponding Ax registers. * When the user sets a register on a windowed config, xt-gdb may set the ARx * register directly. Thus we take ARx as priority over Ax if both are dirty @@ -748,10 +778,12 @@ static int xtensa_write_dirty_registers(struct target *target) } } } - /*Now rotate the window so we'll see the next 16 registers. The final rotate - * will wraparound, */ - /*leaving us in the state we were. */ - xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, 4)); + + /* Now rotate the window so we'll see the next 16 registers. The final rotate + * will wraparound, leaving us in the state we were. + * Each ROTW rotates 4 registers on LX and 8 on NX */ + int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2; + xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg)); } xtensa_window_state_restore(target, woe); @@ -760,6 +792,14 @@ static int xtensa_write_dirty_registers(struct target *target) xtensa->scratch_ars[s].intval = false; } + if (restore_ms) { + uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num; + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, ms); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3)); + LOG_TARGET_DEBUG(target, "Delayed MS (0x%x) write complete: 0x%x", ms_regno, ms); + } + if (preserve_a3) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, a3); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); @@ -877,10 +917,41 @@ static inline void xtensa_reg_set_value(struct reg *reg, xtensa_reg_val_t value) reg->dirty = true; } +static int xtensa_imprecise_exception_occurred(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESR; idx++) { + enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx]; + if (xtensa->nx_reg_idx[idx]) { + xtensa_reg_val_t reg = xtensa_reg_get(target, xtensa->nx_reg_idx[idx]); + if (reg & XT_IMPR_EXC_MSK) { + LOG_TARGET_DEBUG(target, "Imprecise exception: %s: 0x%x", + xtensa->core_cache->reg_list[ridx].name, reg); + return true; + } + } + } + return false; +} + +static void xtensa_imprecise_exception_clear(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESRCLR; idx++) { + enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx]; + if (ridx && idx != XT_NX_REG_IDX_MESR) { + xtensa_reg_val_t value = (idx == XT_NX_REG_IDX_MESRCLR) ? XT_MESRCLR_IMPR_EXC_MSK : 0; + xtensa_reg_set(target, ridx, value); + LOG_TARGET_DEBUG(target, "Imprecise exception: clearing %s (0x%x)", + xtensa->core_cache->reg_list[ridx].name, value); + } + } +} + int xtensa_core_status_check(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); - int res, needclear = 0; + int res, needclear = 0, needimprclear = 0; xtensa_dm_core_status_read(&xtensa->dbg_mod); xtensa_dsr_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod); @@ -904,11 +975,20 @@ int xtensa_core_status_check(struct target *target) dsr); needclear = 1; } + if (xtensa->core_config->core_type == XT_NX && (xtensa_imprecise_exception_occurred(target))) { + if (!xtensa->suppress_dsr_errors) + LOG_TARGET_ERROR(target, + "%s: Imprecise exception occurred!", target_name(target)); + needclear = 1; + needimprclear = 1; + } if (needclear) { res = xtensa_dm_core_status_clear(&xtensa->dbg_mod, OCDDSR_EXECEXCEPTION | OCDDSR_EXECOVERRUN); if (res != ERROR_OK && !xtensa->suppress_dsr_errors) LOG_TARGET_ERROR(target, "clearing DSR failed!"); + if (xtensa->core_config->core_type == XT_NX && needimprclear) + xtensa_imprecise_exception_clear(target); return ERROR_FAIL; } return ERROR_OK; @@ -934,8 +1014,12 @@ void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value) { struct xtensa *xtensa = target_to_xtensa(target); + uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? + XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; uint32_t windowbase = (xtensa->core_config->windowed ? - xtensa_reg_get(target, XT_REG_IDX_WINDOWBASE) : 0); + xtensa_reg_get(target, wb_idx) : 0); + if (xtensa->core_config->core_type == XT_NX) + windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; int ar_idx = xtensa_windowbase_offset_to_canonical(xtensa, a_idx, windowbase); xtensa_reg_set(target, a_idx, value); xtensa_reg_set(target, ar_idx, value); @@ -944,14 +1028,68 @@ void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, /* Read cause for entering halted state; return bitmask in DEBUGCAUSE_* format */ uint32_t xtensa_cause_get(struct target *target) { - return xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE); + struct xtensa *xtensa = target_to_xtensa(target); + if (xtensa->core_config->core_type == XT_LX) { + /* LX cause in DEBUGCAUSE */ + return xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE); + } + if (xtensa->nx_stop_cause & DEBUGCAUSE_VALID) + return xtensa->nx_stop_cause; + + /* NX cause determined from DSR.StopCause */ + if (xtensa_dm_core_status_read(&xtensa->dbg_mod) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Read DSR error"); + } else { + uint32_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod); + /* NX causes are prioritized; only 1 bit can be set */ + switch ((dsr & OCDDSR_STOPCAUSE) >> OCDDSR_STOPCAUSE_SHIFT) { + case OCDDSR_STOPCAUSE_DI: + xtensa->nx_stop_cause = DEBUGCAUSE_DI; + break; + case OCDDSR_STOPCAUSE_SS: + xtensa->nx_stop_cause = DEBUGCAUSE_IC; + break; + case OCDDSR_STOPCAUSE_IB: + xtensa->nx_stop_cause = DEBUGCAUSE_IB; + break; + case OCDDSR_STOPCAUSE_B: + case OCDDSR_STOPCAUSE_B1: + xtensa->nx_stop_cause = DEBUGCAUSE_BI; + break; + case OCDDSR_STOPCAUSE_BN: + xtensa->nx_stop_cause = DEBUGCAUSE_BN; + break; + case OCDDSR_STOPCAUSE_DB0: + case OCDDSR_STOPCAUSE_DB1: + xtensa->nx_stop_cause = DEBUGCAUSE_DB; + break; + default: + LOG_TARGET_ERROR(target, "Unknown stop cause (DSR: 0x%08x)", dsr); + break; + } + if (xtensa->nx_stop_cause) + xtensa->nx_stop_cause |= DEBUGCAUSE_VALID; + } + return xtensa->nx_stop_cause; } void xtensa_cause_clear(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); - xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0); - xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false; + if (xtensa->core_config->core_type == XT_LX) { + xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0); + xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false; + } else { + /* NX DSR.STOPCAUSE is not writeable; clear cached copy but leave it valid */ + xtensa->nx_stop_cause = DEBUGCAUSE_VALID; + } +} + +void xtensa_cause_reset(struct target *target) +{ + /* Clear DEBUGCAUSE_VALID to trigger re-read (on NX) */ + struct xtensa *xtensa = target_to_xtensa(target); + xtensa->nx_stop_cause = 0; } int xtensa_assert_reset(struct target *target) @@ -1008,9 +1146,11 @@ int xtensa_fetch_all_regs(struct target *target) struct xtensa *xtensa = target_to_xtensa(target); struct reg *reg_list = xtensa->core_cache->reg_list; unsigned int reg_list_size = xtensa->core_cache->num_regs; - xtensa_reg_val_t cpenable = 0, windowbase = 0, a3; + xtensa_reg_val_t cpenable = 0, windowbase = 0, a0 = 0, a3; + unsigned int ms_idx = reg_list_size; + uint32_t ms = 0; uint32_t woe; - uint8_t a3_buf[4]; + uint8_t a0_buf[4], a3_buf[4], ms_buf[4]; bool debug_dsrs = !xtensa->regs_fetched || LOG_LEVEL_IS(LOG_LVL_DEBUG); union xtensa_reg_val_u *regvals = calloc(reg_list_size, sizeof(*regvals)); @@ -1030,6 +1170,25 @@ int xtensa_fetch_all_regs(struct target *target) /* Save (windowed) A3 so cache matches physical AR3; A3 usable as scratch */ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a3_buf); + if (xtensa->core_config->core_type == XT_NX) { + /* Save (windowed) A0 as well--it will be required for reading PC */ + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a0_buf); + + /* Set MS.DispSt, clear MS.DE prior to accessing ARs. This ensures ARs remain + * in correct order even for reversed register groups (overflow/underflow). + */ + ms_idx = xtensa->nx_reg_idx[XT_NX_REG_IDX_MS]; + uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num; + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, ms_regno, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, ms_buf); + LOG_TARGET_DEBUG(target, "Overriding MS (0x%x): 0x%x", ms_regno, XT_MS_DISPST_DBG); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, XT_MS_DISPST_DBG); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3)); + } + int res = xtensa_window_state_save(target, &woe); if (res != ERROR_OK) goto xtensa_fetch_all_regs_done; @@ -1052,11 +1211,13 @@ int xtensa_fetch_all_regs(struct target *target) dsrs[XT_REG_IDX_AR0 + i + j].buf); } } - if (xtensa->core_config->windowed) + if (xtensa->core_config->windowed) { /* Now rotate the window so we'll see the next 16 registers. The final rotate - * will wraparound, */ - /* leaving us in the state we were. */ - xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, 4)); + * will wraparound, leaving us in the state we were. + * Each ROTW rotates 4 registers on LX and 8 on NX */ + int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2; + xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg)); + } } xtensa_window_state_restore(target, woe); @@ -1074,6 +1235,10 @@ int xtensa_fetch_all_regs(struct target *target) xtensa_core_status_check(target); a3 = buf_get_u32(a3_buf, 0, 32); + if (xtensa->core_config->core_type == XT_NX) { + a0 = buf_get_u32(a0_buf, 0, 32); + ms = buf_get_u32(ms_buf, 0, 32); + } if (xtensa->core_config->coproc) { cpenable = buf_get_u32(regvals[XT_REG_IDX_CPENABLE].buf, 0, 32); @@ -1104,17 +1269,30 @@ int xtensa_fetch_all_regs(struct target *target) break; case XT_REG_SPECIAL: if (reg_num == XT_PC_REG_NUM_VIRTUAL) { - /* reg number of PC for debug interrupt depends on NDEBUGLEVEL */ - reg_num = XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level; - } else if (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num) { + if (xtensa->core_config->core_type == XT_LX) { + /* reg number of PC for debug interrupt depends on NDEBUGLEVEL */ + reg_num = XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level; + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); + } else { + /* NX PC read through CALL0(0) and reading A0 */ + xtensa_queue_exec_ins(xtensa, XT_INS_CALL0(xtensa, 0)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[i].buf); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, dsrs[i].buf); + reg_fetched = false; + } + } else if ((xtensa->core_config->core_type == XT_LX) + && (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num)) { /* reg number of PS for debug interrupt depends on NDEBUGLEVEL */ reg_num = XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level; + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); } else if (reg_num == xtensa_regs[XT_REG_IDX_CPENABLE].reg_num) { /* CPENABLE already read/updated; don't re-read */ reg_fetched = false; break; + } else { + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); } - xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); break; default: reg_fetched = false; @@ -1154,9 +1332,15 @@ int xtensa_fetch_all_regs(struct target *target) } } - if (xtensa->core_config->windowed) + if (xtensa->core_config->windowed) { /* We need the windowbase to decode the general addresses. */ - windowbase = buf_get_u32(regvals[XT_REG_IDX_WINDOWBASE].buf, 0, 32); + uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? + XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; + windowbase = buf_get_u32(regvals[wb_idx].buf, 0, 32); + if (xtensa->core_config->core_type == XT_NX) + windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; + } + /* Decode the result and update the cache. */ for (unsigned int i = 0; i < reg_list_size; i++) { struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; @@ -1180,6 +1364,16 @@ int xtensa_fetch_all_regs(struct target *target) bool is_dirty = (i == XT_REG_IDX_CPENABLE); if (xtensa_extra_debug_log) LOG_INFO("Register %s: 0x%X", reg_list[i].name, regval); + if (rlist[ridx].reg_num == XT_PC_REG_NUM_VIRTUAL && + xtensa->core_config->core_type == XT_NX) { + /* A0 from prior CALL0 points to next instruction; decrement it */ + regval -= 3; + is_dirty = 1; + } else if (i == ms_idx) { + LOG_TARGET_DEBUG(target, "Caching MS: 0x%x", ms); + regval = ms; + is_dirty = 1; + } xtensa_reg_set(target, i, regval); reg_list[i].dirty = is_dirty; /*always do this _after_ xtensa_reg_set! */ } @@ -1214,6 +1408,11 @@ int xtensa_fetch_all_regs(struct target *target) /* We have used A3 (XT_REG_RELGEN) as a scratch register. Restore and flag for write-back. */ xtensa_reg_set(target, XT_REG_IDX_A3, a3); xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); + if (xtensa->core_config->core_type == XT_NX) { + xtensa_reg_set(target, XT_REG_IDX_A0, a0); + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A0); + } + xtensa->regs_fetched = true; xtensa_fetch_all_regs_done: free(regvals); @@ -1262,7 +1461,7 @@ int xtensa_get_gdb_reg_list(struct target *target, struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; int sparse_idx = rlist[ridx].dbreg_num; - if (i == XT_REG_IDX_PS) { + if (i == XT_REG_IDX_PS && xtensa->core_config->core_type == XT_LX) { if (xtensa->eps_dbglevel_idx == 0) { LOG_ERROR("eps_dbglevel_idx not set\n"); return ERROR_FAIL; @@ -1372,10 +1571,13 @@ int xtensa_prepare_resume(struct target *target, if (xtensa->hw_brps[slot]) { /* Write IBREAKA[slot] and set bit #slot in IBREAKENABLE */ xtensa_reg_set(target, XT_REG_IDX_IBREAKA0 + slot, xtensa->hw_brps[slot]->address); + if (xtensa->core_config->core_type == XT_NX) + xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, XT_IBREAKC_FB); bpena |= BIT(slot); } } - xtensa_reg_set(target, XT_REG_IDX_IBREAKENABLE, bpena); + if (xtensa->core_config->core_type == XT_LX) + xtensa_reg_set(target, XT_REG_IDX_IBREAKENABLE, bpena); /* Here we write all registers to the targets */ int res = xtensa_write_dirty_registers(target); @@ -1390,6 +1592,7 @@ int xtensa_do_resume(struct target *target) LOG_TARGET_DEBUG(target, "start"); + xtensa_cause_reset(target); xtensa_queue_exec_ins(xtensa, XT_INS_RFDO(xtensa)); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { @@ -1467,13 +1670,14 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in return ERROR_TARGET_NOT_HALTED; } - if (xtensa->eps_dbglevel_idx == 0) { - LOG_ERROR("eps_dbglevel_idx not set\n"); + if (xtensa->eps_dbglevel_idx == 0 && xtensa->core_config->core_type == XT_LX) { + LOG_TARGET_ERROR(target, "eps_dbglevel_idx not set\n"); return ERROR_FAIL; } /* Save old ps (EPS[dbglvl] on LX), pc */ - oldps = xtensa_reg_get(target, xtensa->eps_dbglevel_idx); + oldps = xtensa_reg_get(target, (xtensa->core_config->core_type == XT_LX) ? + xtensa->eps_dbglevel_idx : XT_REG_IDX_PS); oldpc = xtensa_reg_get(target, XT_REG_IDX_PC); cause = xtensa_cause_get(target); @@ -1542,7 +1746,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in if (!handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))) /* handle normal SW breakpoint */ xtensa_cause_clear(target); /* so we don't recurse into the same routine */ - if ((oldps & 0xf) >= icountlvl) { + if (xtensa->core_config->core_type == XT_LX && ((oldps & 0xf) >= icountlvl)) { /* Lower interrupt level to allow stepping, but flag eps[dbglvl] to be restored */ ps_lowered = true; uint32_t newps = (oldps & ~0xf) | (icountlvl - 1); @@ -1554,10 +1758,16 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in oldps); } do { - xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, icountlvl); - xtensa_reg_set(target, XT_REG_IDX_ICOUNT, icount_val); + if (xtensa->core_config->core_type == XT_LX) { + xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, icountlvl); + xtensa_reg_set(target, XT_REG_IDX_ICOUNT, icount_val); + } else { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, OCDDCR_STEPREQUEST); + } - /* Now ICOUNT is set, we can resume as if we were going to run */ + /* Now that ICOUNT (LX) or DCR.StepRequest (NX) is set, + * we can resume as if we were going to run + */ res = xtensa_prepare_resume(target, current, address, 0, 0); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to prepare resume for single step"); @@ -2108,6 +2318,22 @@ int xtensa_poll(struct target *target) OCDDSR_DEBUGPENDBREAK | OCDDSR_DEBUGINTBREAK | OCDDSR_DEBUGPENDTRAX | OCDDSR_DEBUGINTTRAX | OCDDSR_DEBUGPENDHOST | OCDDSR_DEBUGINTHOST); + if (xtensa->core_config->core_type == XT_NX) { + /* Enable imprecise exceptions while in halted state */ + xtensa_reg_val_t ps = xtensa_reg_get(target, XT_REG_IDX_PS); + xtensa_reg_val_t newps = ps & ~(XT_PS_DIEXC_MSK); + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_PS); + LOG_TARGET_DEBUG(target, "Enabling PS.DIEXC: 0x%08x -> 0x%08x", ps, newps); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, newps); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3)); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to write PS.DIEXC (%d)!", res); + return res; + } + xtensa_core_status_check(target); + } } } else { target->debug_reason = DBG_REASON_NOTHALTED; @@ -2326,6 +2552,8 @@ int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoin return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } xtensa->hw_brps[slot] = NULL; + if (xtensa->core_config->core_type == XT_NX) + xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, 0); LOG_TARGET_DEBUG(target, "cleared HW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address); return ERROR_OK; } @@ -3073,8 +3301,10 @@ COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa) const char *core_name = CMD_ARGV[0]; if (strcasecmp(core_name, "LX") == 0) { xtensa->core_config->core_type = XT_LX; + } else if (strcasecmp(core_name, "NX") == 0) { + xtensa->core_config->core_type = XT_NX; } else { - LOG_ERROR("xtdef [LX]\n"); + LOG_ERROR("xtdef [LX|NX]\n"); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; @@ -3456,6 +3686,33 @@ COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa) xtensa->eps_dbglevel_idx = XT_NUM_REGS + xtensa->num_optregs - 1; LOG_DEBUG("Setting PS (%s) index to %d", rptr->name, xtensa->eps_dbglevel_idx); } + if (xtensa->core_config->core_type == XT_NX) { + enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_NUM; + if (strcmp(rptr->name, "ibreakc0") == 0) + idx = XT_NX_REG_IDX_IBREAKC0; + else if (strcmp(rptr->name, "wb") == 0) + idx = XT_NX_REG_IDX_WB; + else if (strcmp(rptr->name, "ms") == 0) + idx = XT_NX_REG_IDX_MS; + else if (strcmp(rptr->name, "ievec") == 0) + idx = XT_NX_REG_IDX_IEVEC; + else if (strcmp(rptr->name, "ieextern") == 0) + idx = XT_NX_REG_IDX_IEEXTERN; + else if (strcmp(rptr->name, "mesr") == 0) + idx = XT_NX_REG_IDX_MESR; + else if (strcmp(rptr->name, "mesrclr") == 0) + idx = XT_NX_REG_IDX_MESRCLR; + if (idx < XT_NX_REG_IDX_NUM) { + if (xtensa->nx_reg_idx[idx] != 0) { + LOG_ERROR("nx_reg_idx[%d] previously set to %d", + idx, xtensa->nx_reg_idx[idx]); + return ERROR_FAIL; + } + xtensa->nx_reg_idx[idx] = XT_NUM_REGS + xtensa->num_optregs - 1; + LOG_DEBUG("NX reg %s: index %d (%d)", + rptr->name, xtensa->nx_reg_idx[idx], idx); + } + } } else if (strcmp(rptr->name, "cpenable") == 0) { xtensa->core_config->coproc = true; } @@ -3640,6 +3897,12 @@ COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa) command_print(CMD, "Current ISR step mode: %s", st); return ERROR_OK; } + + if (xtensa->core_config->core_type == XT_NX) { + command_print(CMD, "ERROR: ISR step mode only supported on Xtensa LX"); + return ERROR_FAIL; + } + /* Masking is ON -> interrupts during stepping are OFF, and vice versa */ if (!strcasecmp(CMD_ARGV[0], "off")) state = XT_STEPPING_ISR_ON; diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h index 4d98f3a36a..4216ae24f6 100644 --- a/src/target/xtensa/xtensa.h +++ b/src/target/xtensa/xtensa.h @@ -35,6 +35,7 @@ #define XT_ISNS_SZ_MAX 3 +/* PS register bits (LX) */ #define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6) #define XT_PS_RING_MSK (0x3 << 6) #define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3) @@ -42,6 +43,31 @@ #define XT_PS_OWB_MSK (0xF << 8) #define XT_PS_WOE_MSK BIT(18) +/* PS register bits (NX) */ +#define XT_PS_DIEXC_MSK BIT(2) + +/* MS register bits (NX) */ +#define XT_MS_DE_MSK BIT(5) +#define XT_MS_DISPST_MSK (0x1f) +#define XT_MS_DISPST_DBG (0x10) + +/* WB register bits (NX) */ +#define XT_WB_P_SHIFT (0) +#define XT_WB_P_MSK (0x7U << XT_WB_P_SHIFT) +#define XT_WB_C_SHIFT (4) +#define XT_WB_C_MSK (0x7U << XT_WB_C_SHIFT) +#define XT_WB_N_SHIFT (8) +#define XT_WB_N_MSK (0x7U << XT_WB_N_SHIFT) +#define XT_WB_S_SHIFT (30) +#define XT_WB_S_MSK (0x3U << XT_WB_S_SHIFT) + +/* IBREAKC register bits (NX) */ +#define XT_IBREAKC_FB (0x80000000) + +/* Definitions for imprecise exception registers (NX) */ +#define XT_IMPR_EXC_MSK (0x00000013) +#define XT_MESRCLR_IMPR_EXC_MSK (0x00000090) + #define XT_LOCAL_MEM_REGIONS_NUM_MAX 8 #define XT_AREGS_NUM_MAX 64 @@ -79,6 +105,7 @@ struct xtensa_keyval_info_s { enum xtensa_type { XT_UNDEF = 0, XT_LX, + XT_NX, }; struct xtensa_cache_config { @@ -167,6 +194,17 @@ enum xtensa_stepping_isr_mode { XT_STEPPING_ISR_ON, /* interrupts are enabled during stepping */ }; +enum xtensa_nx_reg_idx { + XT_NX_REG_IDX_IBREAKC0 = 0, + XT_NX_REG_IDX_WB, + XT_NX_REG_IDX_MS, + XT_NX_REG_IDX_IEVEC, /* IEVEC, IEEXTERN, and MESR must be contiguous */ + XT_NX_REG_IDX_IEEXTERN, + XT_NX_REG_IDX_MESR, + XT_NX_REG_IDX_MESRCLR, + XT_NX_REG_IDX_NUM +}; + /* Only supported in cores with in-CPU MMU. None of Espressif chips as of now. */ enum xtensa_mode { XT_MODE_RING0, @@ -232,6 +270,8 @@ struct xtensa { uint8_t come_online_probes_num; bool proc_syscall; bool halt_request; + uint32_t nx_stop_cause; + uint32_t nx_reg_idx[XT_NX_REG_IDX_NUM]; struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM]; bool regs_fetched; /* true after first register fetch completed successfully */ }; diff --git a/src/target/xtensa/xtensa_debug_module.h b/src/target/xtensa/xtensa_debug_module.h index b382e03db6..46b29354cd 100644 --- a/src/target/xtensa/xtensa_debug_module.h +++ b/src/target/xtensa/xtensa_debug_module.h @@ -246,6 +246,7 @@ struct xtensa_dm_reg_offsets { #define OCDDCR_ENABLEOCD BIT(0) #define OCDDCR_DEBUGINTERRUPT BIT(1) #define OCDDCR_INTERRUPTALLCONDS BIT(2) +#define OCDDCR_STEPREQUEST BIT(3) /* NX only */ #define OCDDCR_BREAKINEN BIT(16) #define OCDDCR_BREAKOUTEN BIT(17) #define OCDDCR_DEBUGSWACTIVE BIT(20) @@ -259,6 +260,8 @@ struct xtensa_dm_reg_offsets { #define OCDDSR_EXECBUSY BIT(2) #define OCDDSR_EXECOVERRUN BIT(3) #define OCDDSR_STOPPED BIT(4) +#define OCDDSR_STOPCAUSE (0xF << 5) /* NX only */ +#define OCDDSR_STOPCAUSE_SHIFT (5) /* NX only */ #define OCDDSR_COREWROTEDDR BIT(10) #define OCDDSR_COREREADDDR BIT(11) #define OCDDSR_HOSTWROTEDDR BIT(14) @@ -275,12 +278,24 @@ struct xtensa_dm_reg_offsets { #define OCDDSR_BREAKINITI BIT(26) #define OCDDSR_DBGMODPOWERON BIT(31) +/* NX stop cause */ +#define OCDDSR_STOPCAUSE_DI (0) /* Debug Interrupt */ +#define OCDDSR_STOPCAUSE_SS (1) /* Single-step completed */ +#define OCDDSR_STOPCAUSE_IB (2) /* HW breakpoint (IBREAKn match) */ +#define OCDDSR_STOPCAUSE_B1 (4) /* SW breakpoint (BREAK.1 instruction) */ +#define OCDDSR_STOPCAUSE_BN (5) /* SW breakpoint (BREAK.N instruction) */ +#define OCDDSR_STOPCAUSE_B (6) /* SW breakpoint (BREAK instruction) */ +#define OCDDSR_STOPCAUSE_DB0 (8) /* HW watchpoint (DBREAK0 match) */ +#define OCDDSR_STOPCAUSE_DB1 (9) /* HW watchpoint (DBREAK0 match) */ + +/* LX stop cause */ #define DEBUGCAUSE_IC BIT(0) /* ICOUNT exception */ #define DEBUGCAUSE_IB BIT(1) /* IBREAK exception */ #define DEBUGCAUSE_DB BIT(2) /* DBREAK exception */ #define DEBUGCAUSE_BI BIT(3) /* BREAK instruction encountered */ #define DEBUGCAUSE_BN BIT(4) /* BREAK.N instruction encountered */ #define DEBUGCAUSE_DI BIT(5) /* Debug Interrupt */ +#define DEBUGCAUSE_VALID BIT(31) /* Pseudo-value to trigger reread (NX only) */ #define TRAXCTRL_TREN BIT(0) /* Trace enable. Tracing starts on 0->1 */ #define TRAXCTRL_TRSTP BIT(1) /* Trace Stop. Make 1 to stop trace. */ From e8f376e3c1874ccd14e148164d9695a93c575def Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 4 Mar 2023 23:56:35 +0100 Subject: [PATCH 41/50] helper: add compiler.h to handle compiler specific workarounds Not all compilers nor compiler versions supports the attributes used in OpenOCD code. Collect in a single file the workaround to handle them. Change-Id: I92d871337281169134ce8e40b2064591518be71f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7519 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/helper/Makefile.am | 3 ++- src/helper/compiler.h | 44 ++++++++++++++++++++++++++++++++++++++++++ src/helper/nvp.h | 6 ++++-- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/helper/compiler.h diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index e9c05cfc5d..e0fa331ea2 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -34,7 +34,8 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/jep106.h \ %D%/jep106.inc \ %D%/jim-nvp.h \ - %D%/nvp.h + %D%/nvp.h \ + %D%/compiler.h STARTUP_TCL_SRCS += %D%/startup.tcl EXTRA_DIST += \ diff --git a/src/helper/compiler.h b/src/helper/compiler.h new file mode 100644 index 0000000000..8f6c09950b --- /dev/null +++ b/src/helper/compiler.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * This file contains compiler specific workarounds to handle different + * compilers and different compiler versions. + * Inspired by Linux's include/linux/compiler_attributes.h + * and file sys/cdefs.h in libc and newlib. + */ + +#ifndef OPENOCD_HELPER_COMPILER_H +#define OPENOCD_HELPER_COMPILER_H + +/* + * __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17. + */ +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + +/* + * The __returns_nonnull function attribute marks the return type of the function + * as always being non-null. + */ +#ifndef __returns_nonnull +# if __has_attribute(__returns_nonnull__) +# define __returns_nonnull __attribute__((__returns_nonnull__)) +# else +# define __returns_nonnull +# endif +#endif + +/* + * The __nonnull function attribute marks pointer parameters that + * must not be NULL. + */ +#ifndef __nonnull +# if __has_attribute(__nonnull__) +# define __nonnull(params) __attribute__ ((__nonnull__ params)) +# else +# define __nonnull(params) +# endif +#endif + +#endif /* OPENOCD_HELPER_COMPILER_H */ diff --git a/src/helper/nvp.h b/src/helper/nvp.h index 125164e4ed..14bd9b028c 100644 --- a/src/helper/nvp.h +++ b/src/helper/nvp.h @@ -20,6 +20,8 @@ #ifndef OPENOCD_HELPER_NVP_H #define OPENOCD_HELPER_NVP_H +#include + /** Name Value Pairs, aka: NVP * - Given a string - return the associated int. * - Given a number - return the associated string. @@ -65,9 +67,9 @@ struct command_invocation; /* Name Value Pairs Operations */ const struct nvp *nvp_name2value(const struct nvp *nvp_table, const char *name) - __attribute__((returns_nonnull, nonnull(1))); + __returns_nonnull __nonnull((1)); const struct nvp *nvp_value2name(const struct nvp *nvp_table, int v) - __attribute__((returns_nonnull, nonnull(1))); + __returns_nonnull __nonnull((1)); void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp, const char *param_name, const char *param_value); From 642735449a3a7297126a3dd9b76ffaaca74a1752 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 4 Mar 2023 19:19:16 +0100 Subject: [PATCH 42/50] openocd: drop JIM_EMBEDDED macro The macro JIM_EMBEDDED was required to be defined before including jim.h in applications that embed jimtcl. This requirement has been dropped in 2010 by removing the file dos/Embedder-HOWTO.txt from jimtcl in https://github.com/msteveb/jimtcl/commit/2d8564100c86#diff-3e93fa55e666 Drop the macro definition and the comment that mandates it. Change-Id: I36883f60f25bb25839e4ebf908159569659764dd Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7518 Tested-by: jenkins --- src/helper/command.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/helper/command.c b/src/helper/command.c index 12434ec90e..b358e18aa4 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -18,9 +18,6 @@ #include "config.h" #endif -/* see Embedded-HOWTO.txt in Jim Tcl project hosted on BerliOS*/ -#define JIM_EMBEDDED - /* @todo the inclusion of target.h here is a layering violation */ #include #include From 45eeeab3080991168a07854af5dded926a22253c Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 6 Mar 2023 00:27:58 +0100 Subject: [PATCH 43/50] build: fix distcheck for jimtcl The issues have been highlighted while integrated jimtcl 0.82, but were already present. While building jimtcl as submodule, OpenOCD generates the file jimtcl/configure.gnu to pass specific configure flags. Issue 1: this file is not included in the distribution. This causes the rebuild from the distribution to have a jimtcl built with different (the default) configure flags. With jimtcl 0.82 the new default is to enable all the features, but a bug causes the build to fail when openssl is not installed in the build system (the bug is already fixed but after 0.82 [1]). All these together cause OpenOCD Jenkins to fail the build for target 'distcheck' with jimtcl 0.82. Add jimtcl/configure.gnu to OpenOCD distribution's file list. The build system considers jimtcl/configure.gnu as a temporarily file that should be removed during 'distclean'. Issue 2: 'distcheck' set read-only permission to the source files, including jimtcl/configure.gnu, so 'distclean' fails removing it. Add a leading '-' to ignore errors while trying to remove the file. Issue 3: Now that 'distcheck' properly configures and builds jimtcl, 'distcheck' still fails because we have enabled jimtcl json support in [2] and jimtcl 'distclean' fails to properly remove one object file (fixed after 0.82 [3]). Make OpenOCD removing the file jimtcl/jsmn/jsmn.o to complete the execution of 'distcheck'. Add a comment specifying which of the jimtcl versions are affected. Change-Id: I2f9153c5a41ba66b989b27c7bc57b38d1744cc29 Signed-off-by: Antonio Borneo Link: [1] https://github.com/msteveb/jimtcl/commit/22277943a19c Link: [2] 0a36acbf6ac6 ("configure: build jimtcl with json extension") Link: [3] https://github.com/msteveb/jimtcl/commit/32a488587a3e Reviewed-on: https://review.openocd.org/c/openocd/+/7527 Tested-by: jenkins Reviewed-by: zapb --- Makefile.am | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 41daf9522c..fa92da9127 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,10 +26,14 @@ noinst_LTLIBRARIES = info_TEXINFOS = dist_man_MANS = EXTRA_DIST = +DISTCLEANFILES = if INTERNAL_JIMTCL SUBDIRS += jimtcl DIST_SUBDIRS += jimtcl +EXTRA_DIST += jimtcl/configure.gnu +# jimtcl from 0.79 to 0.82 miss cleaning jsmn.o +DISTCLEANFILES += jimtcl/jsmn/jsmn.o endif # common flags used in openocd build @@ -129,9 +133,9 @@ uninstall-hook: distclean-local: rm -rf Doxyfile doxygen - rm -f $(srcdir)/jimtcl/configure.gnu + -rm -f $(srcdir)/jimtcl/configure.gnu -DISTCLEANFILES = doxygen.log +DISTCLEANFILES += doxygen.log METASOURCES = AUTO From dccf323c1f78d015f75db4cef8cdc33523e1abd6 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 4 Mar 2023 12:08:58 +0100 Subject: [PATCH 44/50] jimtcl: update to version 0.82 The new version modifies it's auto configure in change https://github.com/msteveb/jimtcl/commit/ccd47be13019 stating: configure: Default to --full Now use --minimal and/or --without-ext to disable things. With such change jimtcl doesn't build anymore as OpenOCD submodule because of errors linking with new dependencies openssl and zlib. Use option --minimal to keep the same build configuration as with former jimtcl 0.81. Add option --disable-ssl to avoid a build error on system with no ssl libraries installed. This is already fixed in jimtcl upstream but not part of 0.82. Note that ssl is not currently used by OpenOCD. Change-Id: I0879891dbd083bfbff1e904daf6cd549c3329bbf Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7517 Tested-by: jenkins --- configure.ac | 4 ++-- jimtcl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index cc7139c7c3..ac2808e1f5 100644 --- a/configure.ac +++ b/configure.ac @@ -571,9 +571,9 @@ AS_IF([test "x$enable_buspirate" != "xno"], [ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test -f "$srcdir/jimtcl/configure"], [ AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [ - jimtcl_config_options="--disable-install-jim --with-ext=json --maintainer" + jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl --maintainer" ], [ - jimtcl_config_options="--disable-install-jim --with-ext=json" + jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl" ]) AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options]) ], [ diff --git a/jimtcl b/jimtcl index a77ef1a621..1933e5457b 160000 --- a/jimtcl +++ b/jimtcl @@ -1 +1 @@ -Subproject commit a77ef1a6218fad4c928ddbdc03c1aedc41007e70 +Subproject commit 1933e5457b9512d39ebbe11ed32578aada149f49 From 1528845331ad260bebda6b88b880baf725ffb3c3 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 9 Feb 2023 11:23:28 +0100 Subject: [PATCH 45/50] tcl/tools/test_cpu_speed: Fix register name Use correct register name after it has beed changed in commit 11ee500bffe4 ("target/armv7m: Rename xPSR to xpsr") Change-Id: I3648848f4b47af2d20d60c3e0ecef78f75f6d605 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/7473 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/tools/test_cpu_speed.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/tools/test_cpu_speed.tcl b/tcl/tools/test_cpu_speed.tcl index cef2bbbd73..f1a3fb30e0 100644 --- a/tcl/tools/test_cpu_speed.tcl +++ b/tcl/tools/test_cpu_speed.tcl @@ -18,7 +18,7 @@ proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } { halt # Backup registers and memory. - set backup_regs [get_reg -force {pc r0 xPSR}] + set backup_regs [get_reg -force {pc r0 xpsr}] set backup_mem [read_memory $address 16 3] # We place the following code at the given address to measure the From b4e28446b8f2a116b088eef78744c8b529c1a747 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 6 Mar 2023 23:18:35 +0100 Subject: [PATCH 46/50] tcl: remove exec permission to tcl config files With the new checkpatch we will not get this type of issues anymore. In mean time, let's fix what we have missed during the review process. Change-Id: Iecebf9d43f51a29ee09505d360792793afd24b40 Signed-off-by: Antonio Borneo Fixes: 53556fcded05 ("tcl/interface: add Ashling Opella-LD FTDI config files") Reviewed-on: https://review.openocd.org/c/openocd/+/7530 Tested-by: jenkins --- tcl/interface/ftdi/ashling-opella-ld-jtag.cfg | 0 tcl/interface/ftdi/ashling-opella-ld-swd.cfg | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tcl/interface/ftdi/ashling-opella-ld-jtag.cfg mode change 100755 => 100644 tcl/interface/ftdi/ashling-opella-ld-swd.cfg diff --git a/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg b/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg old mode 100755 new mode 100644 diff --git a/tcl/interface/ftdi/ashling-opella-ld-swd.cfg b/tcl/interface/ftdi/ashling-opella-ld-swd.cfg old mode 100755 new mode 100644 From b6b4f9d46a48aadc1de6bb5152ff4913661c9059 Mon Sep 17 00:00:00 2001 From: Kai Schmitz Date: Thu, 5 Jan 2023 13:50:53 +0100 Subject: [PATCH 47/50] svf: new command line options -noreset and -addcycles -noreset: when using several SVF input files in a sequence it is not always desireable to have a JTAG reset between the execution of the files. The -noreset option skips this unwanted reset. -addcycles : some tests rely on a certain number of extra clock cycles between the actual JTAG commands. The -addcycles option injects a number x cycles after each SDR instruction. Signed-off-by: Kai Schmitz Change-Id: I31932d6041dbc803be00016cd0a4f23fb2e7dbe1 Reviewed-on: https://review.openocd.org/c/openocd/+/7433 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 7 ++++++- src/svf/svf.c | 29 +++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 414b4c4057..0de101b6da 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11433,7 +11433,8 @@ In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. @deffn {Command} {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{[-]quiet}] @ - [@option{[-]nil}] [@option{[-]progress}] [@option{[-]ignore_error}] + [@option{[-]nil}] [@option{[-]progress}] [@option{[-]ignore_error}] @ + [@option{-noreset}] [@option{-addcycles @var{cyclecount}}] This issues a JTAG reset (Test-Logic-Reset) and then runs the SVF script from @file{filename}. @@ -11452,6 +11453,10 @@ on the real interface; @item @option{[-]progress} enable progress indication; @item @option{[-]ignore_error} continue execution despite TDO check errors. +@item @option{-noreset} omit JTAG reset (Test-Logic-Reset) before executing +content of the SVF file; +@item @option{-addcycles @var{cyclecount}} inject @var{cyclecount} number of +additional TCLK cycles after each SDR scan instruction; @end itemize @end deffn diff --git a/src/svf/svf.c b/src/svf/svf.c index a5374316ea..7195880670 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -22,6 +22,7 @@ #include "svf.h" #include "helper/system.h" #include +#include /* SVF command */ enum svf_command { @@ -139,6 +140,9 @@ static const struct svf_statemove svf_statemoves[] = { #define XXR_TDO (1 << 1) #define XXR_MASK (1 << 2) #define XXR_SMASK (1 << 3) + +#define SVF_MAX_ADDCYCLES 255 + struct svf_xxr_para { int len; int data_mask; @@ -220,6 +224,8 @@ static int svf_buffer_index, svf_buffer_size; static int svf_quiet; static int svf_nil; static int svf_ignore_error; +static bool svf_noreset; +static int svf_addcycles; /* Targeting particular tap */ static int svf_tap_is_specified; @@ -343,7 +349,7 @@ int svf_add_statemove(tap_state_t state_to) COMMAND_HANDLER(handle_svf_command) { #define SVF_MIN_NUM_OF_OPTIONS 1 -#define SVF_MAX_NUM_OF_OPTIONS 5 +#define SVF_MAX_NUM_OF_OPTIONS 8 int command_num = 0; int ret = ERROR_OK; int64_t time_measure_ms; @@ -363,8 +369,18 @@ COMMAND_HANDLER(handle_svf_command) svf_nil = 0; svf_progress_enabled = 0; svf_ignore_error = 0; + svf_noreset = false; + svf_addcycles = 0; + for (unsigned int i = 0; i < CMD_ARGC; i++) { - if (strcmp(CMD_ARGV[i], "-tap") == 0) { + if (strcmp(CMD_ARGV[i], "-addcycles") == 0) { + svf_addcycles = atoi(CMD_ARGV[i + 1]); + if (svf_addcycles > SVF_MAX_ADDCYCLES) { + command_print(CMD, "addcycles: %s out of range", CMD_ARGV[i + 1]); + return ERROR_FAIL; + } + i++; + } else if (strcmp(CMD_ARGV[i], "-tap") == 0) { tap = jtag_tap_by_string(CMD_ARGV[i+1]); if (!tap) { command_print(CMD, "Tap: %s unknown", CMD_ARGV[i+1]); @@ -382,6 +398,8 @@ COMMAND_HANDLER(handle_svf_command) else if ((strcmp(CMD_ARGV[i], "ignore_error") == 0) || (strcmp(CMD_ARGV[i], "-ignore_error") == 0)) svf_ignore_error = 1; + else if (strcmp(CMD_ARGV[i], "-noreset") == 0) + svf_noreset = true; else { svf_fd = fopen(CMD_ARGV[i], "r"); if (!svf_fd) { @@ -424,7 +442,7 @@ COMMAND_HANDLER(handle_svf_command) memcpy(&svf_para, &svf_para_init, sizeof(svf_para)); - if (!svf_nil) { + if (!svf_nil && !svf_noreset) { /* TAP_RESET */ jtag_add_tlr(); } @@ -1189,6 +1207,9 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) svf_para.dr_end_state); } + if (svf_addcycles) + jtag_add_clocks(svf_addcycles); + svf_buffer_index += (i + 7) >> 3; } else if (command == SIR) { /* check buffer size first, reallocate if necessary */ @@ -1545,7 +1566,7 @@ static const struct command_registration svf_command_handlers[] = { .handler = handle_svf_command, .mode = COMMAND_EXEC, .help = "Runs a SVF file.", - .usage = "[-tap device.tap] [quiet] [nil] [progress] [ignore_error]", + .usage = "[-tap device.tap] [quiet] [nil] [progress] [ignore_error] [-noreset] [-addcycles numcycles]", }, COMMAND_REGISTRATION_DONE }; From 9ce6b0898e5c0b2d6b6928b93b18137fecd6a32d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 19 Mar 2023 10:57:04 +0100 Subject: [PATCH 48/50] helper/compiler: fix build on MacOS On MacOS, clang defines [1]: #define __nonnull _Nonnull that creates incompatibility with GCC and with the macro __nonnull defined in some libc. Detect clang on MacOS and undefine __nonnull. Change-Id: I64fcf51b102ea91c196e657debd8c267943a2b08 Signed-off-by: Antonio Borneo Links: [1] https://github.com/llvm/llvm-project/blob/llvmorg-16.0.0/clang/lib/Frontend/InitPreprocessor.cpp#L1226 Reviewed-on: https://review.openocd.org/c/openocd/+/7544 Tested-by: jenkins --- src/helper/compiler.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/helper/compiler.h b/src/helper/compiler.h index 8f6c09950b..33a075d64f 100644 --- a/src/helper/compiler.h +++ b/src/helper/compiler.h @@ -32,7 +32,15 @@ /* * The __nonnull function attribute marks pointer parameters that * must not be NULL. + * + * clang for Apple defines + * #define __nonnull _Nonnull + * that is a per argument attribute, incompatible with the gcc per function attribute __nonnull__. + * Undefine it to keep compatibility among compilers. */ +#if defined(__clang__) && defined(__APPLE__) +# undef __nonnull +#endif #ifndef __nonnull # if __has_attribute(__nonnull__) # define __nonnull(params) __attribute__ ((__nonnull__ params)) From ee31f1578a333a75737bc5b183cd4ae98cdaf798 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 22 Jan 2023 23:43:03 +0100 Subject: [PATCH 49/50] rtos/nuttx: add Espressif target support and refactoring Almost written from the beginning in a modern OpenOCD way. - Endiannes support - Proper variable types - Align with the other rtos implementations Signed-off-by: Erhan Kurubas Change-Id: I0868a22da2ed2ab664c82b17c171dc59ede78d10 Reviewed-on: https://review.openocd.org/c/openocd/+/7444 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/Makefile.am | 3 +- src/rtos/nuttx.c | 541 +++++++++++++++++++------------- src/rtos/nuttx_header.h | 60 ---- src/rtos/rtos_nuttx_stackings.h | 3 + 4 files changed, 329 insertions(+), 278 deletions(-) delete mode 100644 src/rtos/nuttx_header.h diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index b0f7daf5f4..0796910de8 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -34,5 +34,4 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/rtos_mqx_stackings.h \ %D%/rtos_riot_stackings.h \ %D%/rtos_ucos_iii_stackings.h \ - %D%/rtos_nuttx_stackings.h \ - %D%/nuttx_header.h + %D%/rtos_nuttx_stackings.h diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 78271181e2..0616af0f4c 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -18,53 +18,60 @@ #include "rtos.h" #include "helper/log.h" #include "helper/types.h" -#include "server/gdb_server.h" - -#include "nuttx_header.h" +#include "target/register.h" #include "rtos_nuttx_stackings.h" -int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); - -#ifdef CONFIG_DISABLE_SIGNALS -#define SIG_QUEUE_NUM 0 -#else -#define SIG_QUEUE_NUM 1 -#endif /* CONFIG_DISABLE_SIGNALS */ - -#ifdef CONFIG_DISABLE_MQUEUE -#define M_QUEUE_NUM 0 -#else -#define M_QUEUE_NUM 2 -#endif /* CONFIG_DISABLE_MQUEUE */ - -#ifdef CONFIG_PAGING -#define PAGING_QUEUE_NUM 1 -#else -#define PAGING_QUEUE_NUM 0 -#endif /* CONFIG_PAGING */ +#define NAME_SIZE 32 +#define EXTRAINFO_SIZE 256 +/* Only 32-bit CPUs are supported by the current implementation. Supporting + * other CPUs will require reading this information from the target and + * adapting the code accordingly. + */ +#define PTR_WIDTH 4 -#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM) +struct nuttx_params { + const char *target_name; + const struct rtos_register_stacking *stacking; + const struct rtos_register_stacking *(*select_stackinfo)(struct target *target); +}; +/* + * struct tcbinfo_s is located in the sched.h + * https://github.com/apache/nuttx/blob/master/include/nuttx/sched.h + */ +#define TCBINFO_TARGET_SIZE 22 +struct tcbinfo { + uint16_t pid_off; /* Offset of tcb.pid */ + uint16_t state_off; /* Offset of tcb.task_state */ + uint16_t pri_off; /* Offset of tcb.sched_priority */ + uint16_t name_off; /* Offset of tcb.name */ + uint16_t regs_off; /* Offset of tcb.regs */ + uint16_t basic_num; /* Num of genernal regs */ + uint16_t total_num; /* Num of regs in tcbinfo.reg_offs */ + target_addr_t xcpreg_off; /* Offset pointer of xcp.regs */ +}; -/* see nuttx/sched/os_start.c */ -static char *nuttx_symbol_list[] = { - "g_readytorun", /* 0: must be top of this array */ - "g_tasklisttable", - NULL +struct symbols { + const char *name; + bool optional; }; -/* see nuttx/include/nuttx/sched.h */ -struct tcb { - uint32_t flink; - uint32_t blink; - uint8_t dat[512]; +/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */ +enum nuttx_symbol_vals { + NX_SYM_READYTORUN = 0, + NX_SYM_PIDHASH, + NX_SYM_NPIDHASH, + NX_SYM_TCB_INFO, }; -static struct { - uint32_t addr; - uint32_t prio; -} g_tasklist[TASK_QUEUE_NUM]; +static const struct symbols nuttx_symbol_list[] = { + { "g_readytorun", false }, + { "g_pidhash", false }, + { "g_npidhash", false }, + { "g_tcbinfo", false }, + { NULL, false } +}; static char *task_state_str[] = { "INVALID", @@ -73,261 +80,363 @@ static char *task_state_str[] = { "RUNNING", "INACTIVE", "WAIT_SEM", -#ifndef CONFIG_DISABLE_SIGNALS "WAIT_SIG", -#endif /* CONFIG_DISABLE_SIGNALS */ -#ifndef CONFIG_DISABLE_MQUEUE "WAIT_MQNOTEMPTY", "WAIT_MQNOTFULL", -#endif /* CONFIG_DISABLE_MQUEUE */ -#ifdef CONFIG_PAGING "WAIT_PAGEFILL", -#endif /* CONFIG_PAGING */ + "STOPPED", }; -static int pid_offset = PID; -static int state_offset = STATE; -static int name_offset = NAME; -static int xcpreg_offset = XCPREG; -static int name_size = NAME_SIZE; +static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target); + +static const struct nuttx_params nuttx_params_list[] = { + { + .target_name = "cortex_m", + .stacking = NULL, + .select_stackinfo = cortexm_select_stackinfo, + }, + { + .target_name = "hla_target", + .stacking = NULL, + .select_stackinfo = cortexm_select_stackinfo, + }, + { + .target_name = "esp32", + .stacking = &nuttx_esp32_stacking, + }, + { + .target_name = "esp32s2", + .stacking = &nuttx_esp32s2_stacking, + }, + { + .target_name = "esp32s3", + .stacking = &nuttx_esp32s3_stacking, + }, + { + .target_name = "esp32c3", + .stacking = &nuttx_riscv_stacking, + }, +}; -static int rcmd_offset(const char *cmd, const char *name) +static bool cortexm_hasfpu(struct target *target) { - if (strncmp(cmd, name, strlen(name))) - return -1; + uint32_t cpacr; + struct armv7m_common *armv7m_target = target_to_armv7m(target); - if (strlen(cmd) <= strlen(name) + 1) - return -1; + if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE) + return false; - return atoi(cmd + strlen(name)); + int retval = target_read_u32(target, FPU_CPACR, &cpacr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read CPACR register to check FPU state"); + return false; + } + + return cpacr & 0x00F00000; } -static int nuttx_thread_packet(struct connection *connection, - char const *packet, int packet_size) +static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target) { - char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */ - - if (!strncmp(packet, "qRcmd", 5)) { - size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd)); - int offset; - - if (len <= 0) - goto pass; - - offset = rcmd_offset(cmd, "nuttx.pid_offset"); - - if (offset >= 0) { - LOG_INFO("pid_offset: %d", offset); - pid_offset = offset; - goto retok; - } - - offset = rcmd_offset(cmd, "nuttx.state_offset"); + return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m; +} - if (offset >= 0) { - LOG_INFO("state_offset: %d", offset); - state_offset = offset; - goto retok; - } +static bool nuttx_detect_rtos(struct target *target) +{ + if (target->rtos->symbols && + target->rtos->symbols[NX_SYM_READYTORUN].address != 0 && + target->rtos->symbols[NX_SYM_PIDHASH].address != 0) + return true; + return false; +} - offset = rcmd_offset(cmd, "nuttx.name_offset"); +static int nuttx_create(struct target *target) +{ + const struct nuttx_params *param; + unsigned int i; - if (offset >= 0) { - LOG_INFO("name_offset: %d", offset); - name_offset = offset; - goto retok; + for (i = 0; i < ARRAY_SIZE(nuttx_params_list); i++) { + param = &nuttx_params_list[i]; + if (strcmp(target_type_name(target), param->target_name) == 0) { + LOG_INFO("Detected target \"%s\"", param->target_name); + break; } + } - offset = rcmd_offset(cmd, "nuttx.xcpreg_offset"); - - if (offset >= 0) { - LOG_INFO("xcpreg_offset: %d", offset); - xcpreg_offset = offset; - goto retok; - } + if (i >= ARRAY_SIZE(nuttx_params_list)) { + LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target)); + return JIM_ERR; + } - offset = rcmd_offset(cmd, "nuttx.name_size"); + /* We found a target in our list, copy its reference. */ + target->rtos->rtos_specific_params = (void *)param; - if (offset >= 0) { - LOG_INFO("name_size: %d", offset); - name_size = offset; - goto retok; - } - } -pass: - return rtos_thread_packet(connection, packet, packet_size); -retok: - gdb_put_packet(connection, "OK", 2); - return ERROR_OK; + return JIM_OK; } - -static bool nuttx_detect_rtos(struct target *target) +static int nuttx_smp_init(struct target *target) { - if ((target->rtos->symbols) && - (target->rtos->symbols[0].address != 0) && - (target->rtos->symbols[1].address != 0)) { - return true; - } - return false; + /* Return OK for now so that the initialisation sequence doesn't stop. + * SMP case will be implemented later. */ + return ERROR_OK; } -static int nuttx_create(struct target *target) +static target_addr_t target_buffer_get_addr(struct target *target, const uint8_t *buffer) { - - target->rtos->gdb_thread_packet = nuttx_thread_packet; - LOG_INFO("target type name = %s", target->type->name); - return 0; +#if PTR_WIDTH == 8 + return target_buffer_get_u64(target, buffer); +#else + return target_buffer_get_u32(target, buffer); +#endif } static int nuttx_update_threads(struct rtos *rtos) { - uint32_t thread_count; - struct tcb tcb; - int ret; - uint32_t head; - uint32_t tcb_addr; - uint32_t i; + struct tcbinfo tcbinfo; + uint32_t pidhashaddr, npidhash, tcbaddr; + uint16_t pid; uint8_t state; if (!rtos->symbols) { - LOG_ERROR("No symbols for NuttX"); - return -3; + LOG_ERROR("No symbols for nuttx"); + return ERROR_FAIL; } - /* free previous thread details */ + /* Free previous thread details */ rtos_free_threadlist(rtos); - ret = target_read_buffer(rtos->target, rtos->symbols[1].address, - sizeof(g_tasklist), (uint8_t *)&g_tasklist); - if (ret) { - LOG_ERROR("target_read_buffer : ret = %d\n", ret); + /* NuttX provides a hash table that keeps track of all the TCBs. + * We first read its size from g_npidhash and its address from g_pidhash. + * Its content is then read from these values. + */ + int ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_NPIDHASH].address, &npidhash); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read g_npidhash: ret = %d", ret); return ERROR_FAIL; } - thread_count = 0; + LOG_DEBUG("Hash table size (g_npidhash) = %" PRId32, npidhash); + + ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_PIDHASH].address, &pidhashaddr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read g_pidhash address: ret = %d", ret); + return ERROR_FAIL; + } - for (i = 0; i < TASK_QUEUE_NUM; i++) { + LOG_DEBUG("Hash table address (g_pidhash) = %" PRIx32, pidhashaddr); + + uint8_t *pidhash = malloc(npidhash * PTR_WIDTH); + if (!pidhash) { + LOG_ERROR("Failed to allocate pidhash"); + return ERROR_FAIL; + } - if (g_tasklist[i].addr == 0) + ret = target_read_buffer(rtos->target, pidhashaddr, PTR_WIDTH * npidhash, pidhash); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read tcbhash: ret = %d", ret); + goto errout; + } + + /* NuttX provides a struct that contains TCB offsets for required members. + * Read its content from g_tcbinfo. + */ + uint8_t buff[TCBINFO_TARGET_SIZE]; + ret = target_read_buffer(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address, sizeof(buff), buff); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read tcbinfo: ret = %d", ret); + goto errout; + } + tcbinfo.pid_off = target_buffer_get_u16(rtos->target, buff); + tcbinfo.state_off = target_buffer_get_u16(rtos->target, buff + 2); + tcbinfo.pri_off = target_buffer_get_u16(rtos->target, buff + 4); + tcbinfo.name_off = target_buffer_get_u16(rtos->target, buff + 6); + tcbinfo.regs_off = target_buffer_get_u16(rtos->target, buff + 8); + tcbinfo.basic_num = target_buffer_get_u16(rtos->target, buff + 10); + tcbinfo.total_num = target_buffer_get_u16(rtos->target, buff + 12); + tcbinfo.xcpreg_off = target_buffer_get_addr(rtos->target, buff + 14); + + /* The head of the g_readytorun list is the currently running task. + * Reading in a temporary variable first to avoid endianness issues, + * rtos->current_thread is int64_t. */ + uint32_t current_thread; + ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_READYTORUN].address, ¤t_thread); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read g_readytorun: ret = %d", ret); + goto errout; + } + rtos->current_thread = current_thread; + + uint32_t thread_count = 0; + + for (unsigned int i = 0; i < npidhash; i++) { + tcbaddr = target_buffer_get_u32(rtos->target, &pidhash[i * PTR_WIDTH]); + + if (!tcbaddr) continue; - ret = target_read_u32(rtos->target, g_tasklist[i].addr, - &head); + ret = target_read_u16(rtos->target, tcbaddr + tcbinfo.pid_off, &pid); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read PID of TCB@0x%x from pidhash[%d]: ret = %d", + tcbaddr, i, ret); + goto errout; + } - if (ret) { - LOG_ERROR("target_read_u32 : ret = %d\n", ret); - return ERROR_FAIL; + ret = target_read_u8(rtos->target, tcbaddr + tcbinfo.state_off, &state); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read state of TCB@0x%x from pidhash[%d]: ret = %d", + tcbaddr, i, ret); + goto errout; } - /* readytorun head is current thread */ - if (g_tasklist[i].addr == rtos->symbols[0].address) - rtos->current_thread = head; + struct thread_detail *new_thread_details = realloc(rtos->thread_details, + sizeof(struct thread_detail) * (thread_count + 1)); + if (!new_thread_details) { + ret = ERROR_FAIL; + goto errout; + } + struct thread_detail *thread = &new_thread_details[thread_count]; + thread->threadid = tcbaddr; + thread->exists = true; + thread->extra_info_str = NULL; - tcb_addr = head; - while (tcb_addr) { - struct thread_detail *thread; - ret = target_read_buffer(rtos->target, tcb_addr, - sizeof(tcb), (uint8_t *)&tcb); - if (ret) { - LOG_ERROR("target_read_buffer : ret = %d\n", - ret); - return ERROR_FAIL; - } - thread_count++; - - rtos->thread_details = realloc(rtos->thread_details, - sizeof(struct thread_detail) * thread_count); - thread = &rtos->thread_details[thread_count - 1]; - thread->threadid = tcb_addr; - thread->exists = true; - - state = tcb.dat[state_offset - 8]; - thread->extra_info_str = NULL; - if (state < ARRAY_SIZE(task_state_str)) { - thread->extra_info_str = malloc(256); - snprintf(thread->extra_info_str, 256, "pid:%d, %s", - tcb.dat[pid_offset - 8] | - tcb.dat[pid_offset - 8 + 1] << 8, - task_state_str[state]); - } + rtos->thread_details = new_thread_details; + thread_count++; - if (name_offset) { - thread->thread_name_str = malloc(name_size + 1); - snprintf(thread->thread_name_str, name_size, - "%s", (char *)&tcb.dat[name_offset - 8]); - } else { - thread->thread_name_str = malloc(sizeof("None")); - strcpy(thread->thread_name_str, "None"); + if (state < ARRAY_SIZE(task_state_str)) { + thread->extra_info_str = malloc(EXTRAINFO_SIZE); + if (!thread->extra_info_str) { + ret = ERROR_FAIL; + goto errout; } + snprintf(thread->extra_info_str, EXTRAINFO_SIZE, "pid:%d, %s", + pid, + task_state_str[state]); + } - tcb_addr = tcb.flink; + if (tcbinfo.name_off) { + thread->thread_name_str = calloc(NAME_SIZE + 1, sizeof(char)); + if (!thread->thread_name_str) { + ret = ERROR_FAIL; + goto errout; + } + ret = target_read_buffer(rtos->target, tcbaddr + tcbinfo.name_off, + sizeof(char) * NAME_SIZE, (uint8_t *)thread->thread_name_str); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read thread's name: ret = %d", ret); + goto errout; + } + } else { + thread->thread_name_str = strdup("None"); } } - rtos->thread_count = thread_count; - return 0; + ret = ERROR_OK; + rtos->thread_count = thread_count; +errout: + free(pidhash); + return ret; } - -/* - * thread_id = tcb address; - */ -static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static int nuttx_getreg_current_thread(struct rtos *rtos, struct rtos_reg **reg_list, int *num_regs) { - int retval; - - /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ - bool cm4_fpu_enabled = false; - struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); - if (is_armv7m(armv7m_target)) { - if (armv7m_target->fp_feature == FPV4_SP) { - /* Found ARM v7m target which includes a FPU */ - uint32_t cpacr; - - retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); - if (retval != ERROR_OK) { - LOG_ERROR("Could not read CPACR register to check FPU state"); - return -1; - } + struct reg **gdb_reg_list; + + /* Registers for currently running thread are not on task's stack and + * should be retrieved from reg caches via target_get_gdb_reg_list */ + int ret = target_get_gdb_reg_list(rtos->target, &gdb_reg_list, num_regs, + REG_CLASS_GENERAL); + if (ret != ERROR_OK) { + LOG_ERROR("target_get_gdb_reg_list failed %d", ret); + return ret; + } - /* Check if CP10 and CP11 are set to full access. */ - if (cpacr & 0x00F00000) { - /* Found target with enabled FPU */ - cm4_fpu_enabled = 1; - } + *reg_list = calloc(*num_regs, sizeof(struct rtos_reg)); + if (!(*reg_list)) { + LOG_ERROR("Failed to alloc memory for %d", *num_regs); + free(gdb_reg_list); + return ERROR_FAIL; + } + + for (int i = 0; i < *num_regs; i++) { + (*reg_list)[i].number = gdb_reg_list[i]->number; + (*reg_list)[i].size = gdb_reg_list[i]->size; + memcpy((*reg_list)[i].value, gdb_reg_list[i]->value, ((*reg_list)[i].size + 7) / 8); + } + + free(gdb_reg_list); + + return ERROR_OK; +} + +static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) +{ + uint16_t xcpreg_off; + uint32_t regsaddr; + const struct nuttx_params *priv = rtos->rtos_specific_params; + const struct rtos_register_stacking *stacking = priv->stacking; + + if (!stacking) { + if (priv->select_stackinfo) { + stacking = priv->select_stackinfo(rtos->target); + } else { + LOG_ERROR("Can't find a way to get stacking info"); + return ERROR_FAIL; } } - const struct rtos_register_stacking *stacking; - if (cm4_fpu_enabled) - stacking = &nuttx_stacking_cortex_m_fpu; - else - stacking = &nuttx_stacking_cortex_m; + int ret = target_read_u16(rtos->target, + rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off), + &xcpreg_off); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read registers' offset: ret = %d", ret); + return ERROR_FAIL; + } + + ret = target_read_u32(rtos->target, thread_id + xcpreg_off, ®saddr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read registers' address: ret = %d", ret); + return ERROR_FAIL; + } - return rtos_generic_stack_read(rtos->target, stacking, - (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs); + return rtos_generic_stack_read(rtos->target, stacking, regsaddr, reg_list, num_regs); } -static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) +static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { - unsigned int i; + if (!rtos) { + LOG_ERROR("NUTTX: out of memory"); + return ERROR_FAIL; + } + + if (thread_id == rtos->current_thread) + return nuttx_getreg_current_thread(rtos, reg_list, num_regs); + return nuttx_getregs_fromstack(rtos, thread_id, reg_list, num_regs); +} - *symbol_list = (struct symbol_table_elem *) calloc(1, - sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list)); +static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) +{ + *symbol_list = calloc(ARRAY_SIZE(nuttx_symbol_list), sizeof(**symbol_list)); + if (!*symbol_list) { + LOG_ERROR("NUTTX: out of memory"); + return ERROR_FAIL; + } - for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) - (*symbol_list)[i].symbol_name = nuttx_symbol_list[i]; + for (unsigned int i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) { + (*symbol_list)[i].symbol_name = nuttx_symbol_list[i].name; + (*symbol_list)[i].optional = nuttx_symbol_list[i].optional; + } - return 0; + return ERROR_OK; } const struct rtos_type nuttx_rtos = { .name = "nuttx", .detect_rtos = nuttx_detect_rtos, .create = nuttx_create, + .smp_init = nuttx_smp_init, .update_threads = nuttx_update_threads, .get_thread_reg_list = nuttx_get_thread_reg_list, .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup, diff --git a/src/rtos/nuttx_header.h b/src/rtos/nuttx_header.h deleted file mode 100644 index 3436df1eb5..0000000000 --- a/src/rtos/nuttx_header.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/*************************************************************************** - * Copyright 2016,2017 Sony Video & Sound Products Inc. * - * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com * - * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com * - ***************************************************************************/ - -#ifndef OPENOCD_RTOS_NUTTX_HEADER_H -#define OPENOCD_RTOS_NUTTX_HEADER_H - -/* gdb script to update the header file - according to kernel version and build option - before executing function awareness - kernel symbol must be loaded : symbol nuttx - -define awareness - set logging off - set logging file nuttx_header.h - set logging on - - printf "#define PID %p\n",&((struct tcb_s *)(0))->pid - printf "#define XCPREG %p\n",&((struct tcb_s *)(0))->xcp.regs - printf "#define STATE %p\n",&((struct tcb_s *)(0))->task_state - printf "#define NAME %p\n",&((struct tcb_s *)(0))->name - printf "#define NAME_SIZE %d\n",sizeof(((struct tcb_s *)(0))->name) - end - - - OR ~/.gdbinit - - -define hookpost-file - - if &g_readytorun != 0 - eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid - eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs - eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state - eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name - eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) - end - -end - -*/ - -/* default offset */ -#define PID 0xc -#define XCPREG 0x70 -#define STATE 0x19 -#define NAME 0xb8 -#define NAME_SIZE 32 - -/* defconfig of nuttx */ -/* #define CONFIG_DISABLE_SIGNALS */ -#define CONFIG_DISABLE_MQUEUE -/* #define CONFIG_PAGING */ - - -#endif /* OPENOCD_RTOS_NUTTX_HEADER_H */ diff --git a/src/rtos/rtos_nuttx_stackings.h b/src/rtos/rtos_nuttx_stackings.h index 2e5f092121..213a060336 100644 --- a/src/rtos/rtos_nuttx_stackings.h +++ b/src/rtos/rtos_nuttx_stackings.h @@ -8,5 +8,8 @@ extern const struct rtos_register_stacking nuttx_stacking_cortex_m; extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu; extern const struct rtos_register_stacking nuttx_riscv_stacking; +extern const struct rtos_register_stacking nuttx_esp32_stacking; +extern const struct rtos_register_stacking nuttx_esp32s2_stacking; +extern const struct rtos_register_stacking nuttx_esp32s3_stacking; #endif /* INCLUDED_RTOS_NUTTX_STACKINGS_H */ From fb26f4f89dbfe51f4d14ba029cd7a8cd36a8b84f Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 12 Sep 2023 12:59:17 -0700 Subject: [PATCH 50/50] target/xtensa: Fix build warning. Change-Id: I9ee69807bec729480dd94da874fe1771d8f06078 Signed-off-by: Tim Newsome --- src/target/xtensa/xtensa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index fcd00487c8..18bdaa00ec 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -607,7 +607,7 @@ static int xtensa_write_dirty_registers(struct target *target) xtensa_reg_val_t a3 = 0, woe; unsigned int ms_idx = (xtensa->core_config->core_type == XT_NX) ? xtensa->nx_reg_idx[XT_NX_REG_IDX_MS] : reg_list_size; - xtensa_reg_val_t ms; + xtensa_reg_val_t ms = 0; bool restore_ms = false; LOG_TARGET_DEBUG(target, "start");