This is an automated email from Gerrit.

"Jan Matyas <[email protected]>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/9757

-- gerrit

commit 733641b208cd2f5a9e07e4b5b0d62efd9e4ae93e
Author: Jan Matyas <[email protected]>
Date:   Thu Jun 25 15:14:04 2026 +0200

    rtos/freertos: Experiments with FreeRTOS on RISC-V
    
    Not to be merged.
    
    This is a draft that documents my quick-and-dirty experiments
    with adding FreeRTOS support on RISC-V into mainline OpenOCD.
    
    The findings, hints and instructions from this draft may be useful
    for other developers that will try to add proper support, hence
    I am publishing them in a draft form.
    
    Change-Id: I3fb6214d1b891cdede101011c97f60dedba631f7
    Signed-off-by: Jan Matyas <[email protected]>

diff --git a/src/rtos/freertos.c b/src/rtos/freertos.c
index 5a9224ec08..eb245f8f33 100644
--- a/src/rtos/freertos.c
+++ b/src/rtos/freertos.c
@@ -18,9 +18,58 @@
 #include "rtos_standard_stackings.h"
 #include "target/armv7m.h"
 #include "target/cortex_m.h"
+#include "target/riscv/gdb_regs.h"
 
 #define FREERTOS_MAX_PRIORITIES        63
 
+#define RISCV_NUM_CORE_REGS 33 // TODO: Needs to be double-checked
+
+// TODO: Needs to be double-checked
+static const struct stack_register_offset 
freertos_riscv_rv32i_offsets[RISCV_NUM_CORE_REGS] = {
+       { GDB_REGNO_ZERO, -1, 32 }, // not on the stack - denoted by the 
special value -1
+       { GDB_REGNO_RA,  0x04, 32 },
+       { GDB_REGNO_SP,  -2, 32 },  // SP: Not on the stack, taken from the TCB.
+       { GDB_REGNO_GP,  -1, 32 },  // GP: Not on the stack. TODO: What to do 
about this register?
+       { GDB_REGNO_TP,  -1, 32 },  // TP: Not on the stack. TODO: What to do 
about this register?
+       { GDB_REGNO_T0,  0x08, 32 },
+       { GDB_REGNO_T1,  0x0c, 32 },
+       { GDB_REGNO_T2,  0x10, 32 },
+       { GDB_REGNO_FP,  0x14, 32 },
+       { GDB_REGNO_S1,  0x18, 32 },
+       { GDB_REGNO_A0, 0x1c, 32 },
+       { GDB_REGNO_A1, 0x20, 32 },
+       { GDB_REGNO_A2, 0x24, 32 },
+       { GDB_REGNO_A3, 0x28, 32 },
+       { GDB_REGNO_A4, 0x2c, 32 },
+       { GDB_REGNO_A5, 0x30, 32 },
+       { GDB_REGNO_A6, 0x34, 32 },
+       { GDB_REGNO_A7, 0x38, 32 },
+       { GDB_REGNO_S2, 0x3c, 32 },
+       { GDB_REGNO_S3, 0x40, 32 },
+       { GDB_REGNO_S4, 0x44, 32 },
+       { GDB_REGNO_S5, 0x48, 32 },
+       { GDB_REGNO_S6, 0x4c, 32 },
+       { GDB_REGNO_S7, 0x50, 32 },
+       { GDB_REGNO_S8, 0x54, 32 },
+       { GDB_REGNO_S9, 0x58, 32 },
+       { GDB_REGNO_S10, 0x5c, 32 },
+       { GDB_REGNO_S11, 0x60, 32 },
+       { GDB_REGNO_T3, 0x64, 32 },
+       { GDB_REGNO_T4, 0x68, 32 },
+       { GDB_REGNO_T5, 0x6c, 32 },
+       { GDB_REGNO_T6, 0x70, 32 },
+       { GDB_REGNO_PC, 0x00, 32 },
+};
+
+// TODO: Needs to be double-checked
+const struct rtos_register_stacking freertos_riscv_rv32i_stacking = {
+       .stack_registers_size = 31 * 4, // see portCONTEXT_SIZE in 
RISC-V/portContext.h
+       .stack_growth_direction = -1,
+       .num_output_registers = RISCV_NUM_CORE_REGS,
+       .calculate_process_stack = NULL, 
/*rtos_standard_cortex_m3_stack_align,*/ // TODO: needed?
+       .register_offsets = freertos_riscv_rv32i_offsets
+};
+
 /* FIXME: none of the _width parameters are actually observed properly!
  * you WILL need to edit more if you actually attempt to target a 8/16/64
  * bit target!
@@ -36,9 +85,13 @@ struct freertos_params {
        const unsigned char list_elem_content_offset;   /* offsetof(ListItem_t, 
pvOwner) */
        const unsigned char thread_stack_offset;                /* 
offsetof(TCB_t, pxTopOfStack) */
        const unsigned char thread_name_offset;                 /* 
offsetof(TCB_t, pcTaskName) */
+
+       // TODO: This part needs better solution - how to work with different
+       // stackings across different targets.
        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_rv32i;
 };
 
 static const struct freertos_params freertos_params_list[] = {
@@ -55,6 +108,7 @@ 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,
+       NULL,
        },
        {
        "hla_target",                   /* target_name */
@@ -69,6 +123,23 @@ 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,
+       NULL,
+       },
+       {
+       // TODO: This part needs to be double-checked
+       "riscv",                                /* target_name */
+       4,                                              /* thread_count_width; 
*/
+       4,                                              /* pointer_width; */
+       12,                                             /* list_next_offset; */
+       20,                                             /* list_width; */
+       4,                                              /* 
list_elem_next_offset; */
+       12,                                             /* 
list_elem_content_offset */
+       0,                                              /* thread_stack_offset; 
*/
+       52,                                             /* thread_name_offset; 
*/
+       NULL,   /* stacking_info */
+       NULL,
+       NULL,
+       &freertos_riscv_rv32i_stacking,
        },
 };
 
@@ -409,7 +480,7 @@ static int freertos_get_thread_reg_list(struct rtos *rtos, 
int64_t thread_id,
                        thread_id + param->thread_stack_offset,
                        &pointer_casts_are_bad);
        if (retval != ERROR_OK) {
-               LOG_ERROR("Error reading stack frame from FreeRTOS thread");
+               LOG_ERROR("Error reading stack frame address from FreeRTOS 
thread control block");
                return retval;
        }
        stack_ptr = pointer_casts_are_bad;
@@ -417,45 +488,59 @@ static int freertos_get_thread_reg_list(struct rtos 
*rtos, int64_t thread_id,
                                                                                
thread_id + param->thread_stack_offset,
                                                                                
stack_ptr);
 
-       /* 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)) {
-                       /* 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;
+       // TODO: This part (selecting the register stacking) needs better 
solution
+       // than the hardcoded version below.
+       if (strcmp(param->target_name, "hla_target") == 0 || 
strcmp(param->target_name, "cortex_m") == 0) {
+               /* 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)) 
{
+                               /* 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 = 1;
+                               }
                        }
+               }
 
-                       /* Check if CP10 and CP11 are set to full access. */
-                       if (cpacr & 0x00F00000) {
-                               /* Found target with enabled FPU */
-                               cm4_fpu_enabled = 1;
+               if (cm4_fpu_enabled == 1) {
+                       /* Read the LR to decide between stacking with or 
without FPU */
+                       uint32_t lr_svc = 0;
+                       retval = target_read_u32(rtos->target,
+                                       stack_ptr + 0x20,
+                                       &lr_svc);
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Error reading stack frame from 
FreeRTOS thread");
+                               return retval;
                        }
+                       if ((lr_svc & 0x10) == 0)
+                               return rtos_generic_stack_read(rtos->target, 
param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs);
+                       else
+                               return rtos_generic_stack_read(rtos->target, 
param->stacking_info_cm4f, stack_ptr, reg_list, num_regs);
+               } else {
+                       return rtos_generic_stack_read(rtos->target, 
param->stacking_info_cm3, stack_ptr, reg_list, num_regs);
                }
+       } else if (strcmp(param->target_name, "riscv") == 0) {
+               // TODO: This part blindly assumes a RV32I target (without V 
and F/D extensions).
+               //
+               // Proper RISC-V FreeRTOS support should be aware of multiple 
possible RISC-V stackings,
+               // depending on the RISC-V ISA width (32/64) and the 
implemented extensions.
+               // See: FreeRTOS/Source/portable/GCC/RISC-V/portContext.h
+               return rtos_generic_stack_read(rtos->target, 
param->stacking_info_rv32i, stack_ptr, reg_list, num_regs);
+       } else {
+               assert(false && "Unexpected target_name in 
freertos_get_thread_reg_list");
        }
-
-       if (cm4_fpu_enabled == 1) {
-               /* Read the LR to decide between stacking with or without FPU */
-               uint32_t lr_svc = 0;
-               retval = target_read_u32(rtos->target,
-                               stack_ptr + 0x20,
-                               &lr_svc);
-               if (retval != ERROR_OK) {
-                       LOG_OUTPUT("Error reading stack frame from FreeRTOS 
thread");
-                       return retval;
-               }
-               if ((lr_svc & 0x10) == 0)
-                       return rtos_generic_stack_read(rtos->target, 
param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs);
-               else
-                       return rtos_generic_stack_read(rtos->target, 
param->stacking_info_cm4f, stack_ptr, reg_list, num_regs);
-       } else
-               return rtos_generic_stack_read(rtos->target, 
param->stacking_info_cm3, stack_ptr, reg_list, num_regs);
 }
 
 static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem 
*symbol_list[])
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index cc0e92edff..9654f880af 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -490,6 +490,14 @@ int rtos_thread_packet(struct connection *connection, char 
const *packet, int pa
                if ((packet[1] == 'g') && (target->rtos)) {
                        threadid_t threadid;
                        sscanf(packet, "Hg%16" SCNx64, &threadid);
+
+                       // TODO: There is a GDB bug that occurs for thread IDs
+                       // >= 0x8000_0000: GDB truncates it to negative values.
+                       // https://sourceware.org/bugzilla/show_bug.cgi?id=34316
+                       //
+                       // Quick and dirty workaround could be:
+                       // threadid = (uint32_t)threadid;
+
                        LOG_DEBUG("RTOS: GDB requested to set current thread to 
0x%" PRIx64, threadid);
                        /* threadid of 0 indicates target should choose */
                        if (threadid == 0)
@@ -617,7 +625,7 @@ int rtos_get_gdb_reg_list(struct connection *connection)
                int num_regs;
 
                LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
-                                 ", target->rtos->current_thread=0x%" PRIx64 
"\r\n",
+                                 ", target->rtos->current_thread=0x%" PRIx64,
                                                                                
current_threadid,
                                                                                
target->rtos->current_thread);
 
@@ -664,21 +672,25 @@ int rtos_generic_stack_read(struct target *target,
                LOG_ERROR("null stack pointer in thread");
                return -5;
        }
+
        /* Read the stack */
        uint8_t *stack_data = malloc(stacking->stack_registers_size);
        uint32_t address = stack_ptr;
 
        if (stacking->stack_growth_direction == 1)
                address -= stacking->stack_registers_size;
+
        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");
                return retval;
        }
+
        LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32, address);
 
 #if 0
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 6bbf01cc98..73f000cb90 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -3105,6 +3105,13 @@ static bool gdb_handle_vcont_packet(struct connection 
*connection, const char *p
                        thread_id = 0;
                }
 
+               // TODO: There is a GDB bug that occurs for thread IDs
+               // >= 0x8000_0000: GDB truncates it to negative values.
+               // https://sourceware.org/bugzilla/show_bug.cgi?id=34316
+               //
+               // Quick and dirty workaround could be:
+               // thread_id = (uint32_t)thread_id;
+
                if (target->rtos) {
                        /* Sometimes this results in picking a different thread 
than
                         * gdb just requested to step. Then we fake it, and now 
there's

-- 

Reply via email to