This is an automated email from Gerrit.

"Philip Kirkpatrick <p.kirkpatr...@reflexaerospace.com>" just uploaded a new 
patch set to Gerrit, which you can find at 
https://review.openocd.org/c/openocd/+/7683

-- gerrit

commit 04dfc7f4d60cddbb714110d979aee704e7b55662
Author: Phil Kirkpatrick <p.kirkpatr...@reflexaerospace.com>
Date:   Tue May 9 11:57:59 2023 +0200

    src/rtos/ : Add support for RTEMS
    
    Added support for task aware debugging of RTEMS.
    This currently supports Cortex-R4 and R5 processors.
    Designed and tested against TMS570LC4357 on a launchxl2-570lc43 board.
    This currently does NOT support SMP.
    
    Change-Id: I83c55bc095a0bf23420656628a2f9df3ec8add56
    Signed-off-by: Phil Kirkpatrick <p.kirkpatr...@reflexaerospace.com>

diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am
index 0796910de8..91cddc4577 100644
--- a/src/rtos/Makefile.am
+++ b/src/rtos/Makefile.am
@@ -11,6 +11,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
        %D%/rtos_ucos_iii_stackings.c \
        %D%/rtos_riot_stackings.c \
        %D%/rtos_nuttx_stackings.c \
+       %D%/rtos_rtems_stackings.c \
        %D%/FreeRTOS.c \
        %D%/ThreadX.c \
        %D%/eCos.c \
@@ -26,6 +27,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
        %D%/zephyr.c \
        %D%/riot.c \
        %D%/rtos.h \
+       %D%/rtems.c \
        %D%/rtos_standard_stackings.h \
        %D%/rtos_ecos_stackings.h \
        %D%/linux_header.h \
@@ -34,4 +36,5 @@ 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%/rtos_nuttx_stackings.h \
+       %D%/rtos_rtems_stackings.h
diff --git a/src/rtos/rtems.c b/src/rtos/rtems.c
new file mode 100644
index 0000000000..2e8e2b8142
--- /dev/null
+++ b/src/rtos/rtems.c
@@ -0,0 +1,724 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2023 by Reflex Aerospace                                *
+ *   Philip Kirkpatrick - p.kirkpatr...@reflexaerospace.com                *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/time_support.h>
+#include <jtag/jtag.h>
+#include "target/target.h"
+#include "target/target_type.h"
+#include "rtos.h"
+#include "helper/log.h"
+#include "helper/types.h"
+#include "helper/list.h"
+#include "rtos_standard_stackings.h"
+#include "rtos_rtems_stackings.h"
+#include "target/armv7m.h"
+#include "target/cortex_m.h"
+
+/*
+ * This file implements RTOS debugging of RTEMS.  It implements api hooks to 
rtos.c in
+ * the rtos_type rtems_rtos struct below.  These hooks implement extracting 
various task
+ * related data from the RTEMS kernel.
+ * The method of accessing the kernel's data was based on analysis of the 
following RTEMS source files:
+ *   For getting a list of tasks:
+ *     git://git.rtems.org/rtems.git/cpukit/score/src/threaditerate.c
+ *   For getting data out of a TCB:
+ *     git://git.rtems.org/rtems.git/cpukit/include/rtems/score/thread.h
+ *     
git://git.rtems.org/rtems.git/cpukit/score/cpu/arm/include/rtems/score/cpu.h
+ *   For finding a task based on a task ID:
+ *     git://git.rtems.org/rtems.git/cpukit/score/src/threadget.c
+ */
+
+/* Some defines from RTEMS object.h */
+#define RTEMS_OBJECTS_API_START_BIT   24U
+#define RTEMS_OBJECTS_API_VALID_BITS  0x00000007U
+#define RTEMS_OBJECTS_INDEX_VALID_BITS  0x0000ffffU
+#define RTEMS_OBJECTS_APIS_LAST 3U
+/* Some defines from RTEMS objectimpl.h */
+#define RTEMS_OBJECTS_INDEX_MINIMUM 1U
+/* Some defines from RTEMS sysstate.h */
+#define RTEMS_SYSTEM_STATE_BEFORE_INITIALIZATION 0U
+#define RTEMS_SYSTEM_STATE_BEFORE_MULTITASKING   1U
+#define RTEMS_SYSTEM_STATE_UP                    2U
+#define RTEMS_SYSTEM_STATE_TERMINATED            3U
+
+// This structure contains the offsets needed to extract task data from the 
various RTEMS structs
+// The offsets may vary depending on the specific target port.
+struct rtems_params {
+       const char *target_name;
+       const unsigned char pointer_width;
+       const unsigned char sizeof_objects_information;
+       const unsigned char sizeof_objects_id;
+       const unsigned char sizeof_objects_control;
+       const unsigned char sizeof_chain_node;
+       const unsigned char offsetof_tcb_registers;
+       const unsigned char offsetof_tcb_is_fp;
+       const unsigned char offsetof_tcb_current_state;
+       const unsigned char offsetof_per_cpu_executing;
+       const struct rtos_register_stacking *stacking_info;
+       const struct rtos_register_stacking *stacking_info_fpu;
+};
+
+// The actual implemenations of supported targets' offsets
+static const struct rtems_params rtems_params_list[] = {
+       {
+       "cortex_r4",                    /* target_name */
+       4,                                              /* pointer_width; */
+       48,                                             /* RTEMS 
sizeof(Objects_Information) */
+       4,                                              /* RTEMS 
sizeof(Objects_Id) */
+       16,                                             /* RTEMS 
sizeof(Objects_Control) */
+       8,                                              /* RTEMS 
sizeof(Chain_Node) */
+       136,                                    /* RTEMS 
offsetof(_Thread_Control, Registers) */
+       250,                                    /* RTEMS 
offsetof(_Thread_Control, is_fp) */
+       28,                                             /* RTEMS 
offsetof(_Thread_Control, current_state) */
+       24,                                             /* RTEMS 
offsetof(Per_CPU_Control, executing) */
+       &rtos_rtems_arm_v7r_stacking,
+       &rtos_rtems_arm_v7r_stacking_fpu
+       },
+};
+
+/*
+ * The following implement the API to rtos.c
+ *   rtems_detect_rtos               : Checks for RTEMS symbols to detect the 
RTOS
+ *   rtems_create                    : Checks the rtems_params_list to load 
the correct offsets for the running target
+ *   rtems_update_threads            : Gets a list of all created tasks, 
including name and state of the tasks
+ *   rtems_get_thread_reg_list       : Gets the registers for a specified 
sleeping task
+ *   rtems_get_symbol_list_to_lookup : Reports what RTOS symbols are needed
+ */
+static bool rtems_detect_rtos(struct target *target);
+static int rtems_create(struct target *target);
+static int rtems_update_threads(struct rtos *rtos);
+static int rtems_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+               struct rtos_reg **reg_list, int *num_regs);
+static int rtems_get_symbol_list_to_lookup(struct symbol_table_elem 
*symbol_list[]);
+
+const struct rtos_type rtems_rtos = {
+       .name = "RTEMS",
+
+       .detect_rtos = rtems_detect_rtos,
+       .create = rtems_create,
+       .update_threads = rtems_update_threads,
+       .get_thread_reg_list = rtems_get_thread_reg_list,
+       .get_symbol_list_to_lookup = rtems_get_symbol_list_to_lookup,
+};
+
+enum rtems_symbol_values {
+       RTEMS_VAL_CPU_INFO = 0,
+       RTEMS_VAL_OBJECTS_INFO = 1,
+       RTEMS_VAL_SYSTEM_STATE = 2,
+};
+
+static const struct symbol_table_elem rtems_symbol_list[] = {
+    /* Array of structs that contain info on the state of each CPU (currently 
only supporting 1 CPU) */
+       { "_Per_CPU_Information", 0, false },
+    /* This is the root data structure for accessing the list of tasks */
+       { "_Objects_Information_table", 0, false },
+    /* Contains the current kernel state */
+       { "_System_state_Current", 0, false },
+       { NULL, 0, false }
+};
+
+// This data structure with list.h supports storing treads in a link list
+struct rtems_task_list {
+       struct list_head lh;
+       struct thread_detail thread_details;
+};
+
+// This is a clean up function used in rtems_update_threads() in certain error 
returns.
+static void rtems_task_list_destroy(struct list_head *task_list)
+{
+       /* Cleanup any task list that did get allocated */
+       struct rtems_task_list *tmp_task1;
+       struct rtems_task_list *tmp_task2;
+       list_for_each_entry_safe(tmp_task1, tmp_task2, task_list, lh) {
+               // Cleanup item
+               list_del(&tmp_task1->lh);
+               free(tmp_task1->thread_details.thread_name_str);
+               free(tmp_task1->thread_details.extra_info_str);
+               free(tmp_task1);
+       }
+}
+
+// Conversion of state bits to strings
+// No bits set is "Ready"
+// This is derived from RTEMS statesimpl.h
+static const char * const task_state_bits[] = {
+       "Wait_Mutex",           /*0x00000001*/
+       "Wait_Semaphore",       /*0x00000002*/
+       "Wait_Event",           /*0x00000004*/
+       "Wait_Sys_Event",       /*0x00000008*/
+       "Wait_Msg",                     /*0x00000010*/
+       "Wait_Cond_Var",        /*0x00000020*/
+       "Wait_Futex",           /*0x00000040*/
+       "Wait_BSD_Wake",        /*0x00000080*/
+       "Wait_Time",            /*0x00000100*/
+       "Wait_Period",          /*0x00000200*/
+       "Wait_Signal",          /*0x00000400*/
+       "Wait_Barrier",         /*0x00000800*/
+       "Wait_RWLock",          /*0x00001000*/
+       "Wait_JoinExit",        /*0x00002000*/
+       "Wait_Join",            /*0x00004000*/
+       "Suspend",                      /*0x00008000*/
+       "Wait_Segment",         /*0x00010000*/
+       "Life_Changing",        /*0x00020000*/
+       "Undef",                        /*0x00040000*/
+       "Undef",                        /*0x00080000*/
+       "Undef",                        /*0x00100000*/
+       "Undef",                        /*0x00200000*/
+       "Undef",                        /*0x00400000*/
+       "Undef",                        /*0x00800000*/
+       "Undef",                        /*0x01000000*/
+       "Undef",                        /*0x02000000*/
+       "Undef",                        /*0x04000000*/
+       "Debugger",                     /*0x08000000*/
+       "INT_Signal",           /*0x10000000*/
+       "Wait_RPC_Reply",       /*0x20000000*/
+       "Zombie",                       /*0x40000000*/
+       "Dormant",                      /*0x80000000*/
+};
+
+
+/* TODO: */
+/* SMP is not supported */
+static int rtems_update_threads(struct rtos *rtos)
+{
+       int retval;
+       const struct rtems_params *param;
+       unsigned int tasks_found = 0;
+       target_addr_t tmp_address;
+       uint32_t pointer_casts_are_bad;
+
+       if (!rtos->rtos_specific_params)
+               return -1;
+
+       param = (const struct rtems_params *)rtos->rtos_specific_params;
+
+       if (!rtos->symbols) {
+               LOG_ERROR("No symbols for RTEMS");
+               return -3;
+       }
+
+       /* wipe out previous thread details if any */
+       rtos_free_threadlist(rtos);
+
+       // Check if kernel is started
+       uint32_t kernel_state;
+       tmp_address = rtos->symbols[RTEMS_VAL_SYSTEM_STATE].address;
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &kernel_state);
+       LOG_DEBUG("RTEMS: Read _System_state_Current at 0x%" PRIx64 ", value 
0x%" PRIx32,
+                                                                               
tmp_address,
+                                                                               
kernel_state);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read kernel state");
+               return retval;
+       }
+
+       if (kernel_state != RTEMS_SYSTEM_STATE_UP) {
+               // Handle kernel not running case
+               char tmp_str[] = "Current Execution";
+               tasks_found++;
+               rtos->thread_details = malloc(sizeof(struct thread_detail));
+               if (!rtos->thread_details) {
+                       LOG_ERROR("Error allocating memory for 1 thread");
+                       return ERROR_FAIL;
+               }
+               rtos->current_thread = 1;
+               rtos->thread_details->threadid = rtos->current_thread;
+               rtos->thread_details->exists = true;
+               rtos->thread_details->extra_info_str = NULL;
+               rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
+               strcpy(rtos->thread_details->thread_name_str, tmp_str);
+               rtos->thread_count = 1;
+               return ERROR_OK;
+       }
+
+       /* Get the TCB address of the running thread */
+       target_addr_t executing_tcb_address;
+
+       tmp_address = rtos->symbols[RTEMS_VAL_CPU_INFO].address + 
param->offsetof_per_cpu_executing;
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &pointer_casts_are_bad);
+       executing_tcb_address = pointer_casts_are_bad;
+       LOG_DEBUG("RTEMS: Read executing TBC address at 0x%" PRIx64 ", value 
0x%" PRIx32,
+                                                                               
tmp_address,
+                                                                               
pointer_casts_are_bad);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read executing TBC address");
+               return retval;
+       }
+       /* Get Thread ID */
+       /* 2nd item, just after `Chain_Node Node` */
+       tmp_address = executing_tcb_address + param->sizeof_chain_node;
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &pointer_casts_are_bad);
+       rtos->current_thread = pointer_casts_are_bad;
+       LOG_DEBUG("RTEMS: Read Thread ID at 0x%" PRIx64 ", value 0x%" PRIx32,
+                                                                               
tmp_address,
+                                                                               
pointer_casts_are_bad);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read executing thread ID");
+               return retval;
+       }
+
+       /* Figuring out how many task requires traversing various structs */
+       /*  that would have to be re-traversed when getting data on the tasks */
+       /* Instead, use a list to get data for all of the tasks, then allocate 
*/
+       /*  an array and copy the data to the array */
+       LIST_HEAD(task_list);
+
+       /* Find and iterate over each task.
+          Based on analyzing:
+               git://git.rtems.org/rtems.git/cpukit/score/src/threaditerate.c
+               Comments below in / *** *** / blocks reference code in 
threaditerate.c
+       */
+       /* From this point on, task_list may contain malloced items
+               and must be destroyed with rtems_task_list_destroy() if 
returning an error
+       */
+       uint32_t api_index;
+       for (api_index = 1; api_index <= RTEMS_OBJECTS_APIS_LAST; ++api_index) {
+               uint32_t task_index;
+               target_addr_t api_info_table_address;
+               target_addr_t class_info_table_address;
+               uint32_t maximim_index;
+               target_addr_t local_table_address;
+
+               /*** Do: `information = _Objects_Information_table[ api_index 
][ 1 ];` ***/
+               /* Get the pointer to the API's object table */
+               tmp_address = rtos->symbols[RTEMS_VAL_OBJECTS_INFO].address;
+               tmp_address += param->pointer_width * api_index;
+
+               retval = target_read_u32(rtos->target,
+                               tmp_address,
+                               &pointer_casts_are_bad);
+               api_info_table_address = pointer_casts_are_bad;
+               LOG_DEBUG("RTEMS: Read api_info_table_address at 0x%" PRIx64 ", 
value 0x%" PRIx32,
+                                                                               
        tmp_address,
+                                                                               
        pointer_casts_are_bad);
+
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Could not read RTEMS api %d object table 
address", api_index);
+                       rtems_task_list_destroy(&task_list);
+                       return retval;
+               }
+
+               /* Get the pointer to the API's first object */
+               tmp_address = api_info_table_address + param->pointer_width;
+
+               retval = target_read_u32(rtos->target,
+                               tmp_address,
+                               &pointer_casts_are_bad);
+               class_info_table_address = pointer_casts_are_bad;
+               LOG_DEBUG("RTEMS: Read class_info_table_address at 0x%" PRIx64 
", value 0x%" PRIx32,
+                                                                               
        tmp_address,
+                                                                               
        pointer_casts_are_bad);
+
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Could not read RTEMS class info table 
address");
+                       rtems_task_list_destroy(&task_list);
+                       return retval;
+               }
+
+               if (class_info_table_address == 0)
+                       continue;
+
+               /*** Do: `maximum = _Objects_Get_maximum_index( information );` 
***/
+               /* `maximum_id` is the first element in info table */
+               tmp_address = class_info_table_address;
+               retval = target_read_u32(rtos->target,
+                               tmp_address,
+                               &maximim_index);
+               LOG_DEBUG("RTEMS: Read object maximim index at 0x%" PRIx64 ", 
value 0x%" PRIx32,
+                                                                               
        tmp_address,
+                                                                               
        maximim_index);
+
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Could not read object maximim index");
+                       rtems_task_list_destroy(&task_list);
+                       return retval;
+               }
+
+               // Get the index bits from `maximim_id`
+               maximim_index = maximim_index & RTEMS_OBJECTS_INDEX_VALID_BITS;
+
+               /*** Prepare for `information->local_table[ index ]` in loop 
***/
+               /* Get pointer to `local_table` */
+               /* 2nd item in info table */
+               tmp_address = class_info_table_address + 
param->sizeof_objects_id;
+               retval = target_read_u32(rtos->target,
+                               tmp_address,
+                               &pointer_casts_are_bad);
+               local_table_address = pointer_casts_are_bad;
+               LOG_DEBUG("RTEMS: Read local table address at 0x%" PRIx64 ", 
value 0x%" PRIx32,
+                                                                               
        tmp_address,
+                                                                               
        pointer_casts_are_bad);
+
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Could not read local table address");
+                       rtems_task_list_destroy(&task_list);
+                       return retval;
+               }
+
+               for (task_index = 0; task_index < maximim_index; ++task_index) {
+                       target_addr_t task_tcb_address;
+
+                       tmp_address = local_table_address + 
param->pointer_width * task_index;
+                       retval = target_read_u32(rtos->target,
+                                       tmp_address,
+                                       &pointer_casts_are_bad);
+                       task_tcb_address = pointer_casts_are_bad;
+                       LOG_DEBUG("RTEMS: Read task tcb address at 0x%" PRIx64 
", value 0x%" PRIx32,
+                                                                               
                tmp_address,
+                                                                               
                pointer_casts_are_bad);
+
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Could not read task %d tcb address", 
task_index);
+                               rtems_task_list_destroy(&task_list);
+                               return retval;
+                       }
+
+                       if (task_tcb_address != 0) {
+                               /* Here we finally have a TCB */
+                               /* This section of code will iterate over all 
TCBs */
+                               /* Extract the needed info*/
+
+                               struct rtems_task_list *new_task;
+                               uint32_t name_u32;
+
+                               new_task = malloc(sizeof(struct 
rtems_task_list));
+                               if (!new_task) {
+                                       LOG_ERROR("Error allocating memory for 
thread");
+                                       rtems_task_list_destroy(&task_list);
+                                       return ERROR_FAIL;
+                               }
+
+                               new_task->thread_details.exists = true;
+
+                               /* Get Thread ID */
+                               /* 2nd item, just after `Chain_Node Node` */
+                               tmp_address = task_tcb_address + 
param->sizeof_chain_node;
+                               retval = target_read_u32(rtos->target,
+                                               tmp_address,
+                                               &pointer_casts_are_bad);
+                               new_task->thread_details.threadid = 
pointer_casts_are_bad;
+                               LOG_DEBUG("RTEMS: Read Thread ID at 0x%" PRIx64 
", value 0x%" PRIx32,
+                                                                               
                        tmp_address,
+                                                                               
                        pointer_casts_are_bad);
+                               if (retval != ERROR_OK) {
+                                       LOG_ERROR("Could not read thread ID");
+                                       rtems_task_list_destroy(&task_list);
+                                       return retval;
+                               }
+
+                               /* Get Thread Name */
+                               /* Want `name_u32`, just after Thread ID */
+                               tmp_address = task_tcb_address +
+                                       param->sizeof_chain_node +
+                                       4                   /* u32 id */;
+                               retval = target_read_u32(rtos->target,
+                                               tmp_address,
+                                               &name_u32);
+                               LOG_DEBUG("RTEMS: Read Thread Name at 0x%" 
PRIx64 ", value 0x%" PRIx32,
+                                                                               
                        tmp_address,
+                                                                               
                        name_u32);
+                               if (retval != ERROR_OK) {
+                                       LOG_ERROR("Could not read thread name");
+                                       rtems_task_list_destroy(&task_list);
+                                       return retval;
+                               }
+                               /* Decode u32 to string */
+                               new_task->thread_details.thread_name_str = 
malloc(4 + 1);
+                               new_task->thread_details.thread_name_str[0] = 
(char)((name_u32 >> 24) & 0xFF);
+                               new_task->thread_details.thread_name_str[1] = 
(char)((name_u32 >> 16) & 0xFF);
+                               new_task->thread_details.thread_name_str[2] = 
(char)((name_u32 >> 8) & 0xFF);
+                               new_task->thread_details.thread_name_str[3] = 
(char)((name_u32 >> 0) & 0xFF);
+                               new_task->thread_details.thread_name_str[4] = 
0x00;
+                               LOG_DEBUG("RTEMS: Read Thread Name '%s'",
+                                                                               
new_task->thread_details.thread_name_str);
+
+                               /* Get the task state */
+                               uint32_t task_state;
+                               tmp_address = task_tcb_address + 
param->offsetof_tcb_current_state;
+                               retval = target_read_u32(rtos->target,
+                                               tmp_address,
+                                               &task_state);
+                               LOG_DEBUG("RTEMS: Read Thread state at 0x%" 
PRIx64 ", value 0x%" PRIx32,
+                                                                               
                        tmp_address,
+                                                                               
                        task_state);
+                               if (retval != ERROR_OK) {
+                                       LOG_ERROR("Could not read thread 
state");
+                                       rtems_task_list_destroy(&task_list);
+                                       return retval;
+                               }
+
+                               /* Decode the state */
+                               if (task_state == 0) {
+                                       char ready_str[] = "State: Ready";
+                                       new_task->thread_details.extra_info_str 
= malloc(sizeof(ready_str));
+                                       
strcpy(new_task->thread_details.extra_info_str, ready_str);
+                               } else {
+                                       bool first = true;
+                                       uint8_t bit_index;
+                                       uint32_t info_len;
+                                       /* State is not 0 (Ready), scan each 
bit to determine what state conditions are */
+                                       for (bit_index = 0; bit_index < 32; 
bit_index++) {
+                                               if ((1 << bit_index) & 
task_state) {
+                                                       if (first) {
+                                                               /* This is the 
first matched condition, allocate space and copy the condition */
+                                                               first = false;
+                                                               info_len = 
strlen(task_state_bits[bit_index]) + 1;
+                                                               
new_task->thread_details.extra_info_str = malloc(info_len);
+                                                               
strcpy(new_task->thread_details.extra_info_str, task_state_bits[bit_index]);
+                                                       } else {
+                                                               /* This is not 
the first matched condition, allocate space for a conatenated string, */
+                                                               /*  concatenate 
the condition strings, and free the old condition string */
+                                                               char *tmp_str;
+
+                                                               info_len = 
strlen(new_task->thread_details.extra_info_str) +
+                                                                       2 + 
strlen(task_state_bits[bit_index]) + 1;
+                                                               tmp_str = 
malloc(info_len);
+                                                               
sprintf(tmp_str, "%s, %s",
+                                                                       
new_task->thread_details.extra_info_str, task_state_bits[bit_index]);
+
+                                                               
free(new_task->thread_details.extra_info_str);
+                                                               
new_task->thread_details.extra_info_str = tmp_str;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               /* Add to list */
+                               list_add_tail(&new_task->lh, &task_list);
+                               tasks_found++;
+                       }
+               }
+       }
+
+       /* create space for new thread details */
+       rtos->thread_details = malloc(sizeof(struct thread_detail) * 
tasks_found);
+       if (!rtos->thread_details) {
+               LOG_ERROR("Error allocating memory for %d threads", 
tasks_found);
+               rtems_task_list_destroy(&task_list);
+               return ERROR_FAIL;
+       }
+
+       /* Copy data to array and cleanup task list */
+       uint32_t tmp_index = 0;
+       struct rtems_task_list *tmp_task1;
+       struct rtems_task_list *tmp_task2;
+       list_for_each_entry_safe(tmp_task1, tmp_task2, &task_list, lh) {
+               // Copy data
+               memcpy(&rtos->thread_details[tmp_index], 
&tmp_task1->thread_details, sizeof(struct thread_detail));
+               // Cleanup item
+               list_del(&tmp_task1->lh);
+               free(tmp_task1);
+               tmp_index++;
+       }
+       rtos->thread_count = tasks_found;
+
+       return 0;
+}
+
+static bool rtems_use_fpu_stack(struct rtos *rtos, const struct rtems_params 
*param, int64_t tcb_ptr)
+{
+       int retval;
+       target_addr_t tmp_address;
+       uint32_t pointer_casts_are_bad;
+       bool is_fp;
+
+       /* Get the pointer to the API's first object */
+       tmp_address = tcb_ptr + param->offsetof_tcb_is_fp;
+
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &pointer_casts_are_bad);
+       is_fp = pointer_casts_are_bad;
+       LOG_DEBUG("RTEMS: Read is_fp at 0x%" PRIx64 ", value 0x%" PRIx32,
+                                                                               
tmp_address,
+                                                                               
pointer_casts_are_bad);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read RTEMS is_fp");
+               return false;
+       }
+
+       return is_fp;
+}
+
+static int rtems_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+               struct rtos_reg **reg_list, int *num_regs)
+{
+       int retval;
+       const struct rtems_params *param;
+
+       target_addr_t tmp_address;
+       uint32_t pointer_casts_are_bad;
+
+       uint32_t task_index;
+       target_addr_t api_info_table_address;
+       target_addr_t class_info_table_address;
+       target_addr_t local_table_address;
+       target_addr_t task_tcb_address;
+
+       if (!rtos->rtos_specific_params)
+               return -1;
+
+       param = (const struct rtems_params *)rtos->rtos_specific_params;
+
+       /* Use the thread ID to look up the TCB */
+       /* Based on
+               git://git.rtems.org/rtems.git/cpukit/score/src/threadget.c */
+
+       /*** Do: _Thread_Get_objects_information_by_id() ***/
+       uint32_t api_index;
+       api_index = ((thread_id >> RTEMS_OBJECTS_API_START_BIT) & 
RTEMS_OBJECTS_API_VALID_BITS);
+
+       /* Get the pointer to the API's object table */
+       tmp_address = rtos->symbols[RTEMS_VAL_OBJECTS_INFO].address;
+       tmp_address += param->pointer_width * api_index;
+
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &pointer_casts_are_bad);
+       api_info_table_address = pointer_casts_are_bad;
+       LOG_DEBUG("RTEMS: Read api_info_table_address at 0x%" PRIx64 ", value 
0x%" PRIx32,
+                                                                               
tmp_address,
+                                                                               
pointer_casts_are_bad);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read RTEMS api %d object table address", 
api_index);
+               return retval;
+       }
+
+       /* Get the pointer to the API's first object */
+       tmp_address = api_info_table_address + param->pointer_width;
+
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &pointer_casts_are_bad);
+       class_info_table_address = pointer_casts_are_bad;
+       LOG_DEBUG("RTEMS: Read class_info_table_address at 0x%" PRIx64 ", value 
0x%" PRIx32,
+                                                                               
tmp_address,
+                                                                               
pointer_casts_are_bad);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read RTEMS class info table address");
+               return retval;
+       }
+
+       /*** Do: _Objects_Get() ***/
+       uint32_t maximim_id;
+       uint32_t maximim_index;
+       uint32_t delta;
+       /* `maximum_id` is the first element in info table */
+       tmp_address = class_info_table_address;
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &maximim_id);
+       LOG_DEBUG("RTEMS: Read object maximim index at 0x%" PRIx64 ", value 
0x%" PRIx32,
+                                                                               
tmp_address,
+                                                                               
maximim_id);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read object maximim index");
+               return retval;
+       }
+
+       delta = maximim_id - thread_id;
+       /* Get the index bits from `maximim_id` */
+       maximim_index = maximim_id & RTEMS_OBJECTS_INDEX_VALID_BITS;
+       /* Check numbers are in range */
+       if (delta >= maximim_index) {
+               LOG_DEBUG("RTEMS: Invalid tasx ID 0x%" PRIx64 ", maximim 0x%" 
PRIx32,
+                                                                               
thread_id,
+                                                                               
maximim_id);
+       }
+       task_index = maximim_index - RTEMS_OBJECTS_INDEX_MINIMUM - delta;
+
+       /* Get pointer to `local_table` */
+       /* 2nd item in info table */
+       tmp_address = class_info_table_address + param->sizeof_objects_id;
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &pointer_casts_are_bad);
+       local_table_address = pointer_casts_are_bad;
+       LOG_DEBUG("RTEMS: Read local table address at 0x%" PRIx64 ", value 0x%" 
PRIx32,
+                                                                               
tmp_address,
+                                                                               
pointer_casts_are_bad);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read local table address");
+               return retval;
+       }
+
+       tmp_address = local_table_address + param->pointer_width * task_index;
+       retval = target_read_u32(rtos->target,
+                       tmp_address,
+                       &pointer_casts_are_bad);
+       task_tcb_address = pointer_casts_are_bad;
+       LOG_DEBUG("RTEMS: Read task tcb address at 0x%" PRIx64 ", value 0x%" 
PRIx32,
+                                                                               
tmp_address,
+                                                                               
pointer_casts_are_bad);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Could not read task %d tcb address", task_index);
+               return retval;
+       }
+
+       /* Get register list offset */
+       /* Note: RTEMS stores the registers in the TCB and not on the stack */
+       /*       Find the registers in the TCB and read like a stack */
+       tmp_address = task_tcb_address + param->offsetof_tcb_registers;
+       if (param->stacking_info->stack_growth_direction == 1)
+               tmp_address += param->stacking_info->stack_registers_size;
+
+       if (rtems_use_fpu_stack(rtos, param, task_tcb_address))
+               return rtos_generic_stack_read(rtos->target, 
param->stacking_info_fpu, tmp_address, reg_list, num_regs);
+       else
+               return rtos_generic_stack_read(rtos->target, 
param->stacking_info, tmp_address, reg_list, num_regs);
+}
+
+static int rtems_get_symbol_list_to_lookup(struct symbol_table_elem 
*symbol_list[])
+{
+       *symbol_list = malloc(sizeof(rtems_symbol_list));
+
+       if (!*symbol_list)
+               return ERROR_FAIL;
+
+       memcpy(*symbol_list, rtems_symbol_list, sizeof(rtems_symbol_list));
+
+       return 0;
+}
+
+static bool rtems_detect_rtos(struct target *target)
+{
+       if (target->rtos->symbols &&
+                       target->rtos->symbols[RTEMS_VAL_CPU_INFO].address != 0) 
{
+               /* looks like RTEMS */
+               return true;
+       }
+       return false;
+}
+
+static int rtems_create(struct target *target)
+{
+       for (unsigned int i = 0; i < ARRAY_SIZE(rtems_params_list); i++)
+               if (strcmp(rtems_params_list[i].target_name, 
target->type->name) == 0) {
+                       target->rtos->rtos_specific_params = (void 
*)&rtems_params_list[i];
+                       return 0;
+               }
+
+       LOG_ERROR("Could not find target \"%s\" in RTEMS compatibility "
+                               "list", target->type->name);
+       return -1;
+}
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index f1e8956a38..0f97781955 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -30,6 +30,7 @@ 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;
+extern const struct rtos_type rtems_rtos;
 
 static const struct rtos_type *rtos_types[] = {
        &threadx_rtos,
@@ -45,6 +46,7 @@ static const struct rtos_type *rtos_types[] = {
        &riot_rtos,
        &zephyr_rtos,
        &rtkernel_rtos,
+       &rtems_rtos,
        /* keep this as last, as it always matches with rtos auto */
        &hwthread_rtos,
        NULL
diff --git a/src/rtos/rtos_rtems_stackings.c b/src/rtos/rtos_rtems_stackings.c
new file mode 100644
index 0000000000..61c219f8cd
--- /dev/null
+++ b/src/rtos/rtos_rtems_stackings.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2023 by Reflex Aerospace                                *
+ *   Philip Kirkpatrick - p.kirkpatr...@reflexaerospace.com                *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rtos.h"
+#include "target/armv7m.h"
+#include "rtos_rtems_stackings.h"
+
+static const struct stack_register_offset rtos_rtems_arm_v7r_stack_offsets[] = 
{
+       { 0,  -1, 32 },         /* r0  (a1)   */
+       { 1,  -1, 32 },         /* r1  (a2)  */
+       { 2,  -1, 32 },         /* r2  (a3)  */
+       { 3,  -1, 32 },         /* r3  (a4)  */
+       { 4,  0x00, 32 },       /* r4  (v1)  */
+       { 5,  0x04, 32 },       /* r5  (v2)  */
+       { 6,  0x08, 32 },       /* r6  (v3)  */
+       { 7,  0x0C, 32 },       /* r7  (v4)  */
+       { 8,  0x10, 32 },       /* r8  (a1)  */
+       { 10, 0x14, 32 },       /* r9  (sb)  */
+       { 11, 0x18, 32 },       /* r10 (sl) */
+       { 12, 0x1C, 32 },       /* r11 (fp) */
+       { 13, -1, 32 },         /* r12 (ip) */
+       { 14, 0x20, 32 },       /* sp_usr   */
+       { 15, -1, 32 },         /* lr_usr   */
+       { 16, 0x24, 32 },       /* pc   */
+       { 17, -1, 32 },         /* SPSR */
+};
+
+const struct rtos_register_stacking rtos_rtems_arm_v7r_stacking = {
+       .stack_registers_size = 0x28,
+       .stack_growth_direction = -1,
+       .num_output_registers = ARRAY_SIZE(rtos_rtems_arm_v7r_stack_offsets),
+       .register_offsets = rtos_rtems_arm_v7r_stack_offsets
+};
+
+static const struct stack_register_offset 
rtos_rtems_arm_v7r_stack_offsets_fpu[] = {
+       { 0,  -1, 32 },         /* r0  (a1)   */
+       { 1,  -1, 32 },         /* r1  (a2)  */
+       { 2,  -1, 32 },         /* r2  (a3)  */
+       { 3,  -1, 32 },         /* r3  (a4)  */
+       { 4,  0x00, 32 },       /* r4  (v1)  */
+       { 5,  0x04, 32 },       /* r5  (v2)  */
+       { 6,  0x08, 32 },       /* r6  (v3)  */
+       { 7,  0x0C, 32 },       /* r7  (v4)  */
+       { 8,  0x10, 32 },       /* r8  (a1)  */
+       { 10, 0x14, 32 },       /* r9  (sb)  */
+       { 11, 0x18, 32 },       /* r10 (sl) */
+       { 12, 0x1C, 32 },       /* r11 (fp) */
+       { 13, -1, 32 },         /* r12 (ip) */
+       { 14, 0x20, 32 },       /* sp_usr   */
+       { 15, -1, 32 },         /* lr_usr   */
+       { 16, 0x24, 32 },       /* pc   */
+       { 17, -1, 32 },         /* SPSR */
+};
+
+const struct rtos_register_stacking rtos_rtems_arm_v7r_stacking_fpu = {
+       .stack_registers_size = 0x28,
+       .stack_growth_direction = -1,
+       .num_output_registers = 
ARRAY_SIZE(rtos_rtems_arm_v7r_stack_offsets_fpu),
+       .register_offsets = rtos_rtems_arm_v7r_stack_offsets_fpu
+};
diff --git a/src/rtos/rtos_rtems_stackings.h b/src/rtos/rtos_rtems_stackings.h
new file mode 100644
index 0000000000..4494a9a7e0
--- /dev/null
+++ b/src/rtos/rtos_rtems_stackings.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2023 by Reflex Aerospace                                *
+ *   Philip Kirkpatrick - p.kirkpatr...@reflexaerospace.com                *
+ ***************************************************************************/
+
+#ifndef OPENOCD_RTOS_RTOS_RTEMS_STACKINGS_H
+#define OPENOCD_RTOS_RTOS_RTEMS_STACKINGS_H
+
+#include "rtos.h"
+
+extern const struct rtos_register_stacking rtos_rtems_arm_v7r_stacking;
+extern const struct rtos_register_stacking rtos_rtems_arm_v7r_stacking_fpu;
+
+#endif /* OPENOCD_RTOS_RTOS_RTEMS_STACKINGS_H */

-- 

Reply via email to