diff --git a/src/rtos/freertos.c b/src/rtos/freertos.c index 5a9224ec0..515208912 100644 --- a/src/rtos/freertos.c +++ b/src/rtos/freertos.c @@ -39,6 +39,8 @@ struct freertos_params { 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; + const struct rtos_register_stacking *stacking_info_cm33; + const struct rtos_register_stacking *stacking_info_cm33_fpu; }; static const struct freertos_params freertos_params_list[] = { @@ -55,6 +57,8 @@ static const struct freertos_params freertos_params_list[] = { &rtos_standard_cortex_m3_stacking, /* stacking_info */ &rtos_standard_cortex_m4f_stacking, &rtos_standard_cortex_m4f_fpu_stacking, + &rtos_standard_cortex_m33_stacking, + &rtos_standard_cortex_m33_fpu_stacking, }, { "hla_target", /* target_name */ @@ -69,6 +73,8 @@ static const struct freertos_params freertos_params_list[] = { &rtos_standard_cortex_m3_stacking, /* stacking_info */ &rtos_standard_cortex_m4f_stacking, &rtos_standard_cortex_m4f_fpu_stacking, + &rtos_standard_cortex_m33_stacking, + &rtos_standard_cortex_m33_fpu_stacking, }, }; @@ -417,9 +423,35 @@ static int freertos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, thread_id + param->thread_stack_offset, stack_ptr); + struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); + + /* ARMv8-M FreeRTOS ports (Cortex-M33/M23, e.g. RP2350_ARM_NTZ) always push + * two extra software-saved words (PSPLIM, then EXC_RETURN) ahead of R4-R11, + * so both the EXC_RETURN position and all register offsets differ from the + * classic Cortex-M3/M4F layouts. The software-saved EXC_RETURN (at offset + * 0x04) is the authoritative indicator of whether the extended FPU frame + * was stacked, so use it directly here. Note we deliberately do NOT gate + * this on the armv7m FPU detection below (fp_feature / CPACR): that probe + * does not reliably report the FPU on ARMv8-M cores, and getting it wrong + * would silently misread every FPU-frame task with the basic layout. */ + if (is_armv7m(armv7m_target) && armv7m_target->arm.arch == ARM_ARCH_V8M) { + uint32_t exc_return = 0; + retval = target_read_u32(rtos->target, stack_ptr + 0x04, &exc_return); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading EXC_RETURN from FreeRTOS thread stack"); + return retval; + } + /* EXC_RETURN bit 4 == 0 means the extended (FPU) frame is in use. */ + const struct rtos_register_stacking *stacking; + if ((exc_return & 0x10) == 0) + stacking = param->stacking_info_cm33_fpu; + else + stacking = param->stacking_info_cm33; + return rtos_generic_stack_read(rtos->target, stacking, stack_ptr, reg_list, num_regs); + } + /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ int cm4_fpu_enabled = 0; - struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { if ((armv7m_target->fp_feature == FPV4_SP) || (armv7m_target->fp_feature == FPV5_SP) || (armv7m_target->fp_feature == FPV5_DP)) { diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index 99cd1540f..bdbf474c7 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -74,6 +74,61 @@ static const struct stack_register_offset rtos_standard_cortex_m4f_fpu_stack_off }; +/* + * ARMv8-M (Cortex-M33/M23) FreeRTOS ports (e.g. RP2350_ARM_NTZ) push an extra + * software-saved frame that the classic Cortex-M3/M4F layouts do not: + * + * [low addr = saved pxTopOfStack] + * 0x00 PSPLIM + * 0x04 EXC_RETURN (software-saved LR) + * 0x08 R4 .. 0x24 R11 + * (0x28 S16..S31, only when the task used the FPU - extended frame) + * + * + * Compared to rtos_standard_cortex_m4f*, every register is shifted by the two + * leading PSPLIM/EXC_RETURN words and R4-R11 follow EXC_RETURN rather than + * preceding it. Using the M4F tables here yields a garbage call stack. + */ +static const struct stack_register_offset rtos_standard_cortex_m33_stack_offsets[] = { + { 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, -2, 32 }, /* sp */ + { ARMV7M_R14, 0x3c, 32 }, /* lr */ + { ARMV7M_PC, 0x40, 32 }, /* pc */ + { ARMV7M_XPSR, 0x44, 32 }, /* xPSR */ +}; + +static const struct stack_register_offset rtos_standard_cortex_m33_fpu_stack_offsets[] = { + { ARMV7M_R0, 0x68, 32 }, /* r0 */ + { ARMV7M_R1, 0x6c, 32 }, /* r1 */ + { ARMV7M_R2, 0x70, 32 }, /* r2 */ + { ARMV7M_R3, 0x74, 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, 0x78, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, 0x7c, 32 }, /* lr */ + { ARMV7M_PC, 0x80, 32 }, /* pc */ + { ARMV7M_XPSR, 0x84, 32 }, /* xPSR */ +}; + static const struct stack_register_offset rtos_standard_cortex_r4_stack_offsets[] = { { 0, 0x08, 32 }, /* r0 (a1) */ { 1, 0x0c, 32 }, /* r1 (a2) */ @@ -196,6 +251,24 @@ static target_addr_t rtos_standard_cortex_m4f_fpu_stack_align(struct target *tar stack_ptr, XPSR_OFFSET); } +static target_addr_t rtos_standard_cortex_m33_stack_align(struct target *target, + const uint8_t *stack_data, const struct rtos_register_stacking *stacking, + target_addr_t stack_ptr) +{ + const int XPSR_OFFSET = 0x44; + return rtos_cortex_m_stack_align(target, stack_data, stacking, + stack_ptr, XPSR_OFFSET); +} + +static target_addr_t rtos_standard_cortex_m33_fpu_stack_align(struct target *target, + const uint8_t *stack_data, const struct rtos_register_stacking *stacking, + target_addr_t stack_ptr) +{ + const int XPSR_OFFSET = 0x84; + return rtos_cortex_m_stack_align(target, stack_data, stacking, + stack_ptr, XPSR_OFFSET); +} + const struct rtos_register_stacking rtos_standard_cortex_m3_stacking = { .stack_registers_size = 0x40, @@ -221,6 +294,22 @@ const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking = { .register_offsets = rtos_standard_cortex_m4f_fpu_stack_offsets }; +const struct rtos_register_stacking rtos_standard_cortex_m33_stacking = { + .stack_registers_size = 0x48, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_standard_cortex_m33_stack_align, + .register_offsets = rtos_standard_cortex_m33_stack_offsets +}; + +const struct rtos_register_stacking rtos_standard_cortex_m33_fpu_stacking = { + .stack_registers_size = 0xd0, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_standard_cortex_m33_fpu_stack_align, + .register_offsets = rtos_standard_cortex_m33_fpu_stack_offsets +}; + const struct rtos_register_stacking rtos_standard_cortex_r4_stacking = { .stack_registers_size = 0x48, .stack_growth_direction = -1, diff --git a/src/rtos/rtos_standard_stackings.h b/src/rtos/rtos_standard_stackings.h index 99fbe07e4..6b4acff9d 100644 --- a/src/rtos/rtos_standard_stackings.h +++ b/src/rtos/rtos_standard_stackings.h @@ -13,6 +13,8 @@ extern const struct rtos_register_stacking rtos_standard_cortex_m3_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking; +extern const struct rtos_register_stacking rtos_standard_cortex_m33_stacking; +extern const struct rtos_register_stacking rtos_standard_cortex_m33_fpu_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_r4_stacking; target_addr_t rtos_generic_stack_align8(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking,