From b14f63e0045557118a5296e6049a3642011bf431 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 1 Aug 2024 15:48:25 -0700 Subject: [PATCH 1/6] aarch64: Invalidate caches on reset When a target is reset we must invalidate register caches in order to avoid showing stale register values or writing them back to registers. Use EDPRSR.SR to detect a previous reset, and EDPRSR.R to detect a current reset state. Change-Id: Ia1e97d7154cf7789d392274eee475733086a835b Signed-off-by: Peter Collingbourne Reviewed-on: https://review.openocd.org/c/openocd/+/8425 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/target/aarch64.c | 49 +++++++++++++++++++++++++++++++++----------- src/target/armv8.h | 2 ++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 6a70b2ddf..f0d486f58 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -193,6 +193,20 @@ static int aarch64_mmu_modify(struct target *target, int enable) return retval; } +static int aarch64_read_prsr(struct target *target, uint32_t *prsr) +{ + struct armv8_common *armv8 = target_to_armv8(target); + int retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRSR, prsr); + if (retval != ERROR_OK) + return retval; + + armv8->sticky_reset |= *prsr & PRSR_SR; + return ERROR_OK; +} + /* * Basic debug access, very low level assumes state is saved */ @@ -213,8 +227,7 @@ static int aarch64_init_debug_access(struct target *target) /* Clear Sticky Power Down status Bit in PRSR to enable access to the registers in the Core Power Domain */ - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &dummy); + retval = aarch64_read_prsr(target, &dummy); if (retval != ERROR_OK) return retval; @@ -281,12 +294,10 @@ static int aarch64_set_dscr_bits(struct target *target, unsigned long bit_mask, static int aarch64_check_state_one(struct target *target, uint32_t mask, uint32_t val, int *p_result, uint32_t *p_prsr) { - struct armv8_common *armv8 = target_to_armv8(target); uint32_t prsr; int retval; - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &prsr); + retval = aarch64_read_prsr(target, &prsr); if (retval != ERROR_OK) return retval; @@ -506,16 +517,28 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug static int aarch64_poll(struct target *target) { + struct armv8_common *armv8 = target_to_armv8(target); enum target_state prev_target_state; int retval = ERROR_OK; - int halted; + uint32_t prsr; - retval = aarch64_check_state_one(target, - PRSR_HALT, PRSR_HALT, &halted, NULL); + retval = aarch64_read_prsr(target, &prsr); if (retval != ERROR_OK) return retval; - if (halted) { + if (armv8->sticky_reset) { + armv8->sticky_reset = false; + if (target->state != TARGET_RESET) { + target->state = TARGET_RESET; + LOG_TARGET_INFO(target, "external reset detected"); + if (armv8->arm.core_cache) { + register_cache_invalidate(armv8->arm.core_cache); + register_cache_invalidate(armv8->arm.core_cache->next); + } + } + } + + if (prsr & PRSR_HALT) { prev_target_state = target->state; if (prev_target_state != TARGET_HALTED) { enum target_debug_reason debug_reason = target->debug_reason; @@ -546,8 +569,11 @@ static int aarch64_poll(struct target *target) break; } } - } else + } else if (prsr & PRSR_RESET) { + target->state = TARGET_RESET; + } else { target->state = TARGET_RUNNING; + } return retval; } @@ -663,8 +689,7 @@ static int aarch64_prepare_restart_one(struct target *target) if (retval == ERROR_OK) { /* clear sticky bits in PRSR, SDR is now 0 */ - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &tmp); + retval = aarch64_read_prsr(target, &tmp); } return retval; diff --git a/src/target/armv8.h b/src/target/armv8.h index f5aa21109..156b5f8bb 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -213,6 +213,8 @@ struct armv8_common { /* True if OpenOCD provides pointer auth related info to GDB */ bool enable_pauth; + bool sticky_reset; + /* last run-control command issued to this target (resume, halt, step) */ enum run_control_op last_run_control_op; From 5159c599157cc878521ae64e836675f7939c6a09 Mon Sep 17 00:00:00 2001 From: daniellizewski Date: Thu, 21 Mar 2024 09:58:34 -0400 Subject: [PATCH 2/6] src/rtos/rtos_nuttx_stackings.c: Fix stack alignment for cortex-m targets Backtraces performed by GDB on any thread other than the current thread would fail if hardware 8 byte ISR stack alignment was enabled on cortex_m targets. Stack reads now adjust the stored SP to account for a potential offset introduced by hardware. Fixed incorrect register offsets for cortex_m Nuttx frames by reading the TCB info symbols to determine correct offsets. Fixed offsets can no longer be used since the offsets have changed multiple times for different Nuttx versions. Tested on nuttx-12.1.0. Tested using custom stm32h7 board and custom s32k148 board variants. Built with CONFIG_ARCH_FPU enabled and disabled to test FPU and non FPU frame logic. Change-Id: Ifcbeefb0ddcfbcb528daa9d1d95732ca9584c9ef Signed-off-by: daniellizewski Reviewed-on: https://review.openocd.org/c/openocd/+/8180 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/rtos/nuttx.c | 54 ++----------- src/rtos/rtos_nuttx_stackings.c | 134 +++++++++++++++++++++----------- src/rtos/rtos_nuttx_stackings.h | 9 +++ 3 files changed, 104 insertions(+), 93 deletions(-) diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 910014889..821e55088 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -32,7 +32,6 @@ struct nuttx_params { const char *target_name; const struct rtos_register_stacking *stacking; - const struct rtos_register_stacking *(*select_stackinfo)(struct target *target); }; /* @@ -56,19 +55,12 @@ struct symbols { bool optional; }; -/* 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 const struct symbols nuttx_symbol_list[] = { { "g_readytorun", false }, { "g_pidhash", false }, { "g_npidhash", false }, { "g_tcbinfo", false }, + { "g_reg_offs", false}, { NULL, false } }; @@ -86,18 +78,14 @@ static char *task_state_str[] = { "STOPPED", }; -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, + .stacking = &nuttx_stacking_cortex_m, }, { .target_name = "hla_target", - .stacking = NULL, - .select_stackinfo = cortexm_select_stackinfo, + .stacking = &nuttx_stacking_cortex_m, }, { .target_name = "esp32", @@ -117,28 +105,6 @@ static const struct nuttx_params nuttx_params_list[] = { }, }; -static bool cortexm_hasfpu(struct target *target) -{ - uint32_t cpacr; - struct armv7m_common *armv7m_target = target_to_armv7m(target); - - if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE) - return false; - - 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 const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target) -{ - return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m; -} - static bool nuttx_detect_rtos(struct target *target) { if (target->rtos->symbols && @@ -371,29 +337,25 @@ static int nuttx_getreg_current_thread(struct rtos *rtos, static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { - uint16_t xcpreg_off; + uint16_t regs_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; - } + LOG_ERROR("Can't find a way to get stacking info"); + return ERROR_FAIL; } int ret = target_read_u16(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off), - &xcpreg_off); + ®s_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); + ret = target_read_u32(rtos->target, thread_id + regs_off, ®saddr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read registers' address: ret = %d", ret); return ERROR_FAIL; diff --git a/src/rtos/rtos_nuttx_stackings.c b/src/rtos/rtos_nuttx_stackings.c index b70cccb33..6faa56a66 100644 --- a/src/rtos/rtos_nuttx_stackings.c +++ b/src/rtos/rtos_nuttx_stackings.c @@ -9,62 +9,102 @@ #include "rtos_nuttx_stackings.h" #include "rtos_standard_stackings.h" #include +#include -/* see arch/arm/include/armv7-m/irq_cmnvector.h */ +/* The cortex_m target uses nuttx_tcbinfo_stack_read which uses a symbol + * provided by Nuttx to read the registers from memory and place them directly + * in the order we need. This is because the register offsets change with + * different versions of Nuttx, FPU vs non-FPU and ARMv7 vs ARMv8. + * This allows a single function to work with many versions. + */ static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { - { ARMV7M_R0, 0x28, 32 }, /* r0 */ - { ARMV7M_R1, 0x2c, 32 }, /* r1 */ - { ARMV7M_R2, 0x30, 32 }, /* r2 */ - { ARMV7M_R3, 0x34, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x38, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x3c, 32 }, /* lr */ - { ARMV7M_PC, 0x40, 32 }, /* pc */ - { ARMV7M_XPSR, 0x44, 32 }, /* xPSR */ + { ARMV7M_R0, 0, 32 }, /* r0 */ + { ARMV7M_R1, 4, 32 }, /* r1 */ + { ARMV7M_R2, 8, 32 }, /* r2 */ + { ARMV7M_R3, 12, 32 }, /* r3 */ + { ARMV7M_R4, 16, 32 }, /* r4 */ + { ARMV7M_R5, 20, 32 }, /* r5 */ + { ARMV7M_R6, 24, 32 }, /* r6 */ + { ARMV7M_R7, 28, 32 }, /* r7 */ + { ARMV7M_R8, 32, 32 }, /* r8 */ + { ARMV7M_R9, 36, 32 }, /* r9 */ + { ARMV7M_R10, 40, 32 }, /* r10 */ + { ARMV7M_R11, 44, 32 }, /* r11 */ + { ARMV7M_R12, 48, 32 }, /* r12 */ + { ARMV7M_R13, 52, 32 }, /* sp */ + { ARMV7M_R14, 56, 32 }, /* lr */ + { ARMV7M_PC, 60, 32 }, /* pc */ + { ARMV7M_XPSR, 64, 32 }, /* xPSR */ }; +/* The Nuttx stack frame for most architectures has some registers placed + * by hardware and some by software. The hardware register order and number does not change + * but the software registers may change with different versions of Nuttx. + * For example with ARMv7, nuttx-12.3.0 added a new register which changed all + * the offsets. We can either create separate offset tables for each version of Nuttx + * which will break again in the future, or read the offsets from the TCB info. + * Nuttx provides a symbol (g_reg_offs) which holds all the offsets for each stored register. + * This offset table is stored in GDB org.gnu.gdb.xxx feature order. + * The same order we need. + * Please refer: + * https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Features.html + * https://sourceware.org/gdb/current/onlinedocs/gdb/RISC_002dV-Features.html + */ +static int nuttx_cortex_m_tcbinfo_stack_read(struct target *target, + int64_t stack_ptr, const struct rtos_register_stacking *stacking, + uint8_t *stack_data) +{ + struct rtos *rtos = target->rtos; + target_addr_t xcpreg_off = rtos->symbols[NX_SYM_REG_OFFSETS].address; + + for (int i = 0; i < stacking->num_output_registers; ++i) { + uint16_t stack_reg_offset; + int ret = target_read_u16(rtos->target, xcpreg_off + 2 * i, &stack_reg_offset); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read stack_reg_offset: ret = %d", ret); + return ret; + } + if (stack_reg_offset != UINT16_MAX && stacking->register_offsets[i].offset >= 0) { + ret = target_read_buffer(target, + stack_ptr + stack_reg_offset, + stacking->register_offsets[i].width_bits / 8, + &stack_data[stacking->register_offsets[i].offset]); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read register: ret = %d", ret); + return ret; + } + } + } + + /* Offset match nuttx_stack_offsets_cortex_m */ + const int XPSR_OFFSET = 64; + const int SP_OFFSET = 52; + /* Nuttx stack frames (produced in exception_common) store the SP of the ISR minus + * the hardware stack frame size. This SP may include an additional 4 byte alignment + * depending in xPSR[9]. The Nuttx stack frame stores post alignment since the + * hardware will add/remove automatically on both enter/exit. + * We need to adjust the SP to get the real SP of the stack. + * See Arm Reference manual "Stack alignment on exception entry" + */ + uint32_t xpsr = target_buffer_get_u32(target, &stack_data[XPSR_OFFSET]); + if (xpsr & BIT(9)) { + uint32_t sp = target_buffer_get_u32(target, &stack_data[SP_OFFSET]); + target_buffer_set_u32(target, &stack_data[SP_OFFSET], sp - 4 * stacking->stack_growth_direction); + } + + return ERROR_OK; +} + const struct rtos_register_stacking nuttx_stacking_cortex_m = { - .stack_registers_size = 0x48, + /* nuttx_tcbinfo_stack_read transforms the stack into just output registers */ + .stack_registers_size = ARRAY_SIZE(nuttx_stack_offsets_cortex_m) * 4, .stack_growth_direction = -1, - .num_output_registers = 17, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_cortex_m), + .read_stack = nuttx_cortex_m_tcbinfo_stack_read, + .calculate_process_stack = NULL, /* Stack alignment done in nuttx_cortex_m_tcbinfo_stack_read */ .register_offsets = nuttx_stack_offsets_cortex_m, }; -static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { - { ARMV7M_R0, 0x6c, 32 }, /* r0 */ - { ARMV7M_R1, 0x70, 32 }, /* r1 */ - { ARMV7M_R2, 0x74, 32 }, /* r2 */ - { ARMV7M_R3, 0x78, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x7c, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x80, 32 }, /* lr */ - { ARMV7M_PC, 0x84, 32 }, /* pc */ - { ARMV7M_XPSR, 0x88, 32 }, /* xPSR */ -}; - -const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { - .stack_registers_size = 0x8c, - .stack_growth_direction = -1, - .num_output_registers = 17, - .register_offsets = nuttx_stack_offsets_cortex_m_fpu, -}; - static const struct stack_register_offset nuttx_stack_offsets_riscv[] = { { GDB_REGNO_ZERO, -1, 32 }, { GDB_REGNO_RA, 0x04, 32 }, diff --git a/src/rtos/rtos_nuttx_stackings.h b/src/rtos/rtos_nuttx_stackings.h index 213a06033..5d55e7545 100644 --- a/src/rtos/rtos_nuttx_stackings.h +++ b/src/rtos/rtos_nuttx_stackings.h @@ -5,6 +5,15 @@ #include "rtos.h" +/* 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, + NX_SYM_REG_OFFSETS, +}; + 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; From 1ae6b07b45198618c3f0975fd49de59cf6c04e7a Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Fri, 13 Sep 2024 18:10:48 +0100 Subject: [PATCH 3/6] binarybuffer: Invert buf_cmp* return value and rename to buf_eq* The current semantics are a bit confusing, as the return value looks like memcmp (0/false being equal) but the bool return type means one likely expects true to mean equal. Make this clearer by switching them out for buf_eq* functions that do that instead. Checkpatch-ignore: UNSPECIFIED_INT Change-Id: Iee0c5af794316aab5327cb9c168051fabd3bc1cb Signed-off-by: Jessica Clarke Reviewed-on: https://review.openocd.org/c/openocd/+/8490 Tested-by: jenkins Reviewed-by: Evgeniy Naydanov Reviewed-by: Antonio Borneo --- src/helper/binarybuffer.c | 30 +++++++++++++++--------------- src/helper/binarybuffer.h | 4 ++-- src/jtag/core.c | 4 ++-- src/svf/svf.c | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c index c25383dc6..a7ca5af9d 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -57,49 +57,49 @@ void *buf_cpy(const void *from, void *_to, unsigned size) return _to; } -static bool buf_cmp_masked(uint8_t a, uint8_t b, uint8_t m) +static bool buf_eq_masked(uint8_t a, uint8_t b, uint8_t m) { - return (a & m) != (b & m); + return (a & m) == (b & m); } -static bool buf_cmp_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing) +static bool buf_eq_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing) { uint8_t mask = (1 << trailing) - 1; - return buf_cmp_masked(a, b, mask & m); + return buf_eq_masked(a, b, mask & m); } -bool buf_cmp(const void *_buf1, const void *_buf2, unsigned size) +bool buf_eq(const void *_buf1, const void *_buf2, unsigned size) { if (!_buf1 || !_buf2) - return _buf1 != _buf2; + return _buf1 == _buf2; unsigned last = size / 8; if (memcmp(_buf1, _buf2, last) != 0) - return true; + return false; unsigned trailing = size % 8; if (!trailing) - return false; + return true; const uint8_t *buf1 = _buf1, *buf2 = _buf2; - return buf_cmp_trailing(buf1[last], buf2[last], 0xff, trailing); + return buf_eq_trailing(buf1[last], buf2[last], 0xff, trailing); } -bool buf_cmp_mask(const void *_buf1, const void *_buf2, +bool buf_eq_mask(const void *_buf1, const void *_buf2, const void *_mask, unsigned size) { if (!_buf1 || !_buf2) - return _buf1 != _buf2 || _buf1 != _mask; + return _buf1 == _buf2 && _buf1 == _mask; const uint8_t *buf1 = _buf1, *buf2 = _buf2, *mask = _mask; unsigned last = size / 8; for (unsigned i = 0; i < last; i++) { - if (buf_cmp_masked(buf1[i], buf2[i], mask[i])) - return true; + if (!buf_eq_masked(buf1[i], buf2[i], mask[i])) + return false; } unsigned trailing = size % 8; if (!trailing) - return false; - return buf_cmp_trailing(buf1[last], buf2[last], mask[last], trailing); + return true; + return buf_eq_trailing(buf1[last], buf2[last], mask[last], trailing); } void *buf_set_ones(void *_buf, unsigned size) diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index df4199837..ed13b980f 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -172,8 +172,8 @@ static inline uint64_t buf_get_u64(const uint8_t *_buffer, */ uint32_t flip_u32(uint32_t value, unsigned width); -bool buf_cmp(const void *buf1, const void *buf2, unsigned size); -bool buf_cmp_mask(const void *buf1, const void *buf2, +bool buf_eq(const void *buf1, const void *buf2, unsigned size); +bool buf_eq_mask(const void *buf1, const void *buf2, const void *mask, unsigned size); /** diff --git a/src/jtag/core.c b/src/jtag/core.c index 9eae5e74b..a6f38a19d 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -881,9 +881,9 @@ static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, int compare_failed; if (in_check_mask) - compare_failed = buf_cmp_mask(captured, in_check_value, in_check_mask, num_bits); + compare_failed = !buf_eq_mask(captured, in_check_value, in_check_mask, num_bits); else - compare_failed = buf_cmp(captured, in_check_value, num_bits); + compare_failed = !buf_eq(captured, in_check_value, num_bits); if (compare_failed) { char *captured_str, *in_check_value_str; diff --git a/src/svf/svf.c b/src/svf/svf.c index dd3d5175c..470889948 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -932,7 +932,7 @@ static int svf_check_tdo(void) index_var = svf_check_tdo_para[i].buffer_offset; len = svf_check_tdo_para[i].bit_len; if ((svf_check_tdo_para[i].enabled) - && buf_cmp_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var], + && !buf_eq_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var], &svf_mask_buffer[index_var], len)) { LOG_ERROR("tdo check error at line %d", svf_check_tdo_para[i].line_num); From e6ade35305fa32674d615a26713487b5ad00b352 Mon Sep 17 00:00:00 2001 From: Evgeniy Naydanov Date: Thu, 12 Sep 2024 15:16:45 +0300 Subject: [PATCH 4/6] server/gdb_server: improve error handling for `Z/z` packet * Report errors for `z` packet. * Report not supported types as required by GDB Remote Protocol's documentation: > Implementation notes: A remote target shall return an empty string for an unrecognized breakpoint or watchpoint packet type. Link: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Packets.html#insert-breakpoint-or-watchpoint-packet Change-Id: I9130400aca5dbc54fefb413ed74f27d75fe50640 Signed-off-by: Evgeniy Naydanov Reviewed-on: https://review.openocd.org/c/openocd/+/8488 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 2db3123a0..854c4dc65 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1781,18 +1781,9 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, case 1: if (packet[0] == 'Z') { retval = breakpoint_add(target, address, size, bp_type); - if (retval == ERROR_NOT_IMPLEMENTED) { - /* Send empty reply to report that breakpoints of this type are not supported */ - gdb_put_packet(connection, "", 0); - } else if (retval != ERROR_OK) { - retval = gdb_error(connection, retval); - if (retval != ERROR_OK) - return retval; - } else - gdb_put_packet(connection, "OK", 2); } else { - breakpoint_remove(target, address); - gdb_put_packet(connection, "OK", 2); + assert(packet[0] == 'z'); + retval = breakpoint_remove(target, address); } break; case 2: @@ -1801,26 +1792,26 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, { if (packet[0] == 'Z') { retval = watchpoint_add(target, address, size, wp_type, 0, WATCHPOINT_IGNORE_DATA_VALUE_MASK); - if (retval == ERROR_NOT_IMPLEMENTED) { - /* Send empty reply to report that watchpoints of this type are not supported */ - gdb_put_packet(connection, "", 0); - } else if (retval != ERROR_OK) { - retval = gdb_error(connection, retval); - if (retval != ERROR_OK) - return retval; - } else - gdb_put_packet(connection, "OK", 2); } else { - watchpoint_remove(target, address); - gdb_put_packet(connection, "OK", 2); + assert(packet[0] == 'z'); + retval = watchpoint_remove(target, address); } break; } default: + { + retval = ERROR_NOT_IMPLEMENTED; break; + } } - return ERROR_OK; + if (retval == ERROR_NOT_IMPLEMENTED) { + /* Send empty reply to report that watchpoints of this type are not supported */ + return gdb_put_packet(connection, "", 0); + } + if (retval != ERROR_OK) + return gdb_error(connection, retval); + return gdb_put_packet(connection, "OK", 2); } /* print out a string and allocate more space as needed, From ad216136180e0cd482f414eb072c9dd25dd1c559 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 24 Jun 2024 16:26:02 +0200 Subject: [PATCH 5/6] server/telnet: Restructure commands Use a command group 'telnet' with subcommands instead of individual commands with 'telnet_' prefix. Even though there is only one subcommand at the moment, make this change to ensure consistency with other commands. The old command is still available to ensure backwards compatibility, but are marked as deprecated. Change-Id: I5e88632fa0d0ce5a8129e9fcf5ae743fc5b093cb Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/8378 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 2 +- src/server/startup.tcl | 6 ++++++ src/server/telnet_server.c | 24 +++++++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index e8a1f33b5..97396c7b7 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2227,7 +2227,7 @@ the port @var{number} defaults to 6666. When specified as "disabled", this service is not activated. @end deffn -@deffn {Config Command} {telnet_port} [number] +@deffn {Config Command} {telnet port} [number] Specify or query the port on which to listen for incoming telnet connections. This port is intended for interaction with one human through TCL commands. diff --git a/src/server/startup.tcl b/src/server/startup.tcl index ebfb0562e..cf3eca36e 100644 --- a/src/server/startup.tcl +++ b/src/server/startup.tcl @@ -113,3 +113,9 @@ proc "tcl_trace" {state} { echo "DEPRECATED! use 'tcl trace' not 'tcl_trace'" eval tcl trace $state } + +lappend _telnet_autocomplete_skip "telnet_port" +proc "telnet_port" {args} { + echo "DEPRECATED! use 'telnet port', not 'telnet_port'" + eval telnet port $args +} diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 02d450fbd..a596afef0 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -967,7 +967,6 @@ int telnet_init(char *banner) return ERROR_OK; } -/* daemon configuration command telnet_port */ COMMAND_HANDLER(handle_telnet_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port); @@ -978,6 +977,19 @@ COMMAND_HANDLER(handle_exit_command) return ERROR_COMMAND_CLOSE_CONNECTION; } +static const struct command_registration telnet_subcommand_handlers[] = { + { + .name = "port", + .handler = handle_telnet_port_command, + .mode = COMMAND_CONFIG, + .help = "Specify port on which to listen " + "for incoming telnet connections. " + "Read help on 'gdb port'.", + .usage = "[port_num]", + }, + COMMAND_REGISTRATION_DONE +}; + static const struct command_registration telnet_command_handlers[] = { { .name = "exit", @@ -987,13 +999,11 @@ static const struct command_registration telnet_command_handlers[] = { .help = "exit telnet session", }, { - .name = "telnet_port", - .handler = handle_telnet_port_command, + .name = "telnet", + .chain = telnet_subcommand_handlers, .mode = COMMAND_CONFIG, - .help = "Specify port on which to listen " - "for incoming telnet connections. " - "Read help on 'gdb port'.", - .usage = "[port_num]", + .help = "telnet commands", + .usage = "", }, COMMAND_REGISTRATION_DONE }; From 1173473f662bbdf6d1499654568256257eee6cdd Mon Sep 17 00:00:00 2001 From: Matt Trescott Date: Wed, 10 Jul 2024 14:46:28 -0400 Subject: [PATCH 6/6] flash/nor/atsame5: add PIC32CX-SG device IDs These devices are essentially the same as the E54 series with the exception of immutable boot (SG41, SG61) and HSM (SG60, SG61), and some bug fixes found only in E54 revision F. When the security features are not enabled, they behave identically except for the different DIDs. Signed-off-by: Matt Trescott Change-Id: Ic93313f3e20af0ed4a5768880d17b335a7b7bb04 Reviewed-on: https://review.openocd.org/c/openocd/+/8355 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/atsame5.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index c590081fc..a6ac9060a 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -85,6 +85,9 @@ #define SAME_SERIES_51 0x01 #define SAME_SERIES_53 0x03 #define SAME_SERIES_54 0x04 +#define PIC32CXSG_SERIES_41 0x07 +#define PIC32CXSG_SERIES_60 0x00 +#define PIC32CXSG_SERIES_61 0x02 /* Device ID macros */ #define SAMD_GET_PROCESSOR(id) (id >> 28) @@ -148,6 +151,27 @@ static const struct samd_part same54_parts[] = { { 0x03, "SAME54N19A", 512, 192 }, }; +/* See PIC32CX SG41/SG60/SG61 Family Silicon Errata and Datasheet Clarifications + * DS80000985G */ +/* Known PIC32CX-SG41 parts. */ +static const struct samd_part pic32cxsg41_parts[] = { + { 0x00, "PIC32CX1025SG41128", 1024, 256 }, + { 0x01, "PIC32CX1025SG41100", 1024, 256 }, + { 0x02, "PIC32CX1025SG41064", 1024, 256 }, +}; + +/* Known PIC32CX-SG60 parts. */ +static const struct samd_part pic32cxsg60_parts[] = { + { 0x00, "PIC32CX1025SG60128", 1024, 256 }, + { 0x01, "PIC32CX1025SG60100", 1024, 256 }, +}; + +/* Known PIC32CX-SG61 parts. */ +static const struct samd_part pic32cxsg61_parts[] = { + { 0x00, "PIC32CX1025SG61128", 1024, 256 }, + { 0x01, "PIC32CX1025SG61100", 1024, 256 }, +}; + /* Each family of parts contains a parts table in the DEVSEL field of DID. The * processor ID, family ID, and series ID are used to determine which exact * family this is and then we can use the corresponding table. */ @@ -169,6 +193,12 @@ static const struct samd_family samd_families[] = { same53_parts, ARRAY_SIZE(same53_parts) }, { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54, same54_parts, ARRAY_SIZE(same54_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_41, + pic32cxsg41_parts, ARRAY_SIZE(pic32cxsg41_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_60, + pic32cxsg60_parts, ARRAY_SIZE(pic32cxsg60_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_61, + pic32cxsg61_parts, ARRAY_SIZE(pic32cxsg61_parts) }, }; struct samd_info {