OpenOCD
rtkernel.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2016-2023 by Andreas Fritiofson *
5  * andreas.fritiofson@gmail.com *
6  ***************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11 
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "rtos.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
20 #include "target/armv7m.h"
21 #include "target/cortex_m.h"
22 
23 #define ST_DEAD BIT(0) /* Task is waiting to be deleted */
24 #define ST_WAIT BIT(1) /* Task is blocked: */
25 #define ST_SEM BIT(2) /* on semaphore */
26 #define ST_MTX BIT(3) /* on mutex */
27 #define ST_SIG BIT(4) /* on signal */
28 #define ST_DLY BIT(5) /* on timer */
29 #define ST_FLAG BIT(6) /* on flag */
30 #define ST_FLAG_ALL BIT(7) /* on flag and flag mode is "ALL" */
31 #define ST_MBOX BIT(8) /* on mailbox */
32 #define ST_STP BIT(9) /* self stopped */
33 #define ST_SUSPEND BIT(10) /* Task is suspended */
34 #define ST_TT BIT(11) /* Time triggered task */
35 #define ST_TT_YIELD BIT(12) /* Time triggered task that yields */
36 #define ST_CREATE BIT(13) /* Task was created by task_create() */
37 
39  const char *target_name;
43 };
44 
45 static const struct rtkernel_params rtkernel_params_list[] = {
46  {
47  "cortex_m", /* target_name */
48  &rtos_standard_cortex_m3_stacking, /* stacking_info */
51  },
52  {
53  "hla_target", /* target_name */
54  &rtos_standard_cortex_m3_stacking, /* stacking_info */
57  },
58 };
59 
70 };
71 
72 struct symbols {
73  const char *name;
74  bool optional;
75 };
76 
77 static const struct symbols rtkernel_symbol_list[] = {
78  { "os_state", false },
79  { "__off_os_state2chain", false },
80  { "__off_os_state2current", false },
81  { "__off_task2chain", false },
82  { "__off_task2magic", false },
83  { "__off_task2stack", false },
84  { "__off_task2state", false },
85  { "__off_task2name", false },
86  { "__val_task_magic", false },
87  { NULL, false }
88 };
89 
90 static void *realloc_preserve(void *ptr, size_t old_size, size_t new_size)
91 {
92  void *new_ptr = malloc(new_size);
93 
94  if (new_ptr) {
95  memcpy(new_ptr, ptr, MIN(old_size, new_size));
96  free(ptr);
97  }
98 
99  return new_ptr;
100 }
101 
102 static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task)
103 {
104  int retval;
105  int new_thread_count = rtos->thread_count + 1;
106  struct thread_detail *new_thread_details = realloc_preserve(rtos->thread_details,
107  rtos->thread_count * sizeof(struct thread_detail),
108  new_thread_count * sizeof(struct thread_detail));
109  if (!new_thread_details) {
110  LOG_ERROR("Error growing memory to %d threads", new_thread_count);
111  return ERROR_FAIL;
112  }
113  rtos->thread_details = new_thread_details;
114  struct thread_detail *thread = &new_thread_details[rtos->thread_count];
115 
116  *thread = (struct thread_detail){ .threadid = task, .exists = true };
117 
118  /* Read the task name */
119  uint32_t name;
121  if (retval != ERROR_OK) {
122  LOG_ERROR("Could not read task name pointer from target");
123  return retval;
124  }
125  uint8_t tmp_str[33];
126  retval = target_read_buffer(rtos->target, name, sizeof(tmp_str) - 1, tmp_str);
127  if (retval != ERROR_OK) {
128  LOG_ERROR("Error reading task name from target");
129  return retval;
130  }
131  tmp_str[sizeof(tmp_str) - 1] = '\0';
132  LOG_DEBUG("task name at 0x%" PRIx32 ", value \"%s\"", name, tmp_str);
133 
134  if (tmp_str[0] != '\0')
135  thread->thread_name_str = strdup((char *)tmp_str);
136  else
137  thread->thread_name_str = strdup("No Name");
138 
139  /* Read the task state */
140  uint16_t state;
142  if (retval != ERROR_OK) {
143  LOG_ERROR("Could not read task state from target");
144  return retval;
145  }
146 
147  LOG_DEBUG("task state 0x%" PRIx16, state);
148 
149  char state_str[64] = "";
150  if (state & ST_TT)
151  strcat(state_str, "TT|");
152  if (task == current_task) {
153  strcat(state_str, "RUN");
154  } else {
155  if (state & (ST_TT | ST_TT_YIELD))
156  strcat(state_str, "YIELD");
157  else if (state & ST_DEAD)
158  strcat(state_str, "DEAD");
159  else if (state & ST_WAIT)
160  strcat(state_str, "WAIT");
161  else if (state & ST_SUSPEND)
162  strcat(state_str, "SUSP");
163  else
164  strcat(state_str, "READY");
165  }
166  if (state & ST_SEM)
167  strcat(state_str, "|SEM");
168  if (state & ST_MTX)
169  strcat(state_str, "|MTX");
170  if (state & ST_SIG)
171  strcat(state_str, "|SIG");
172  if (state & ST_DLY)
173  strcat(state_str, "|DLY");
174  if ((state & ST_FLAG) || (state & ST_FLAG_ALL))
175  strcat(state_str, "|FLAG");
176  if (state & ST_FLAG_ALL)
177  strcat(state_str, "_ALL");
178  if (state & ST_MBOX)
179  strcat(state_str, "|MBOX");
180  if (state & ST_STP)
181  strcat(state_str, "|STP");
182 
183  thread->extra_info_str = strdup(state_str);
184 
185  rtos->thread_count = new_thread_count;
186  if (task == current_task)
187  rtos->current_thread = task;
188  return ERROR_OK;
189 }
190 
191 static int rtkernel_verify_task(struct rtos *rtos, uint32_t task)
192 {
193  int retval;
194  uint32_t magic;
195  retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2magic].address, &magic);
196  if (retval != ERROR_OK) {
197  LOG_ERROR("Could not read task magic from target");
198  return retval;
199  }
200  if (magic != rtos->symbols[sym___val_task_magic].address) {
201  LOG_ERROR("Invalid task found (magic=0x%" PRIx32 ")", magic);
202  return ERROR_FAIL;
203  }
204  return retval;
205 }
206 
207 static int rtkernel_update_threads(struct rtos *rtos)
208 {
209  /* wipe out previous thread details if any */
210  /* do this first because rtos layer does not check our retval */
212  rtos->current_thread = 0;
213 
214  if (!rtos->symbols) {
215  LOG_ERROR("No symbols for rt-kernel");
216  return -3;
217  }
218 
219  /* read the current task */
220  uint32_t current_task;
221  int retval = target_read_u32(rtos->target,
223  &current_task);
224  if (retval != ERROR_OK) {
225  LOG_ERROR("Error reading current task");
226  return retval;
227  }
228  LOG_DEBUG("current task is 0x%" PRIx32, current_task);
229 
230  retval = rtkernel_verify_task(rtos, current_task);
231  if (retval != ERROR_OK) {
232  LOG_ERROR("Current task is invalid");
233  return retval;
234  }
235 
236  /* loop through kernel task list */
238  LOG_DEBUG("chain start at 0x%" PRIx32, chain);
239 
240  uint32_t next = chain;
241  for (;;) {
242  retval = target_read_u32(rtos->target, next, &next);
243  if (retval != ERROR_OK) {
244  LOG_ERROR("Could not read rt-kernel data structure from target");
245  return retval;
246  }
247  LOG_DEBUG("next entry at 0x%" PRIx32, next);
248  if (next == chain) {
249  LOG_DEBUG("end of chain detected");
250  break;
251  }
252  uint32_t task = next - rtos->symbols[sym___off_task2chain].address;
253  LOG_DEBUG("found task at 0x%" PRIx32, task);
254 
255  retval = rtkernel_verify_task(rtos, task);
256  if (retval != ERROR_OK) {
257  LOG_ERROR("Invalid task found");
258  return retval;
259  }
260 
261  retval = rtkernel_add_task(rtos, task, current_task);
262  if (retval != ERROR_OK) {
263  LOG_ERROR("Could not add task to rtos system");
264  return retval;
265  }
266  }
267  return ERROR_OK;
268 }
269 
270 static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
271  struct rtos_reg **reg_list, int *num_regs)
272 {
273  uint32_t stack_ptr = 0;
274 
275  if (!rtos)
276  return -1;
277 
278  if (thread_id == 0)
279  return -2;
280 
282  return -1;
283 
284  const struct rtkernel_params *param = rtos->rtos_specific_params;
285 
286  /* Read the stack pointer */
287  int retval = target_read_u32(rtos->target, thread_id + rtos->symbols[sym___off_task2stack].address, &stack_ptr);
288  if (retval != ERROR_OK) {
289  LOG_ERROR("Error reading stack pointer from rtkernel thread");
290  return retval;
291  }
292  LOG_DEBUG("stack pointer at 0x%" PRIx64 ", value 0x%" PRIx32,
294  stack_ptr);
295 
296  /* Adjust stack pointer to ignore non-standard BASEPRI register stacking */
297  stack_ptr += 4;
298 
299  /* Check for armv7m with *enabled* FPU, i.e. a Cortex M4F */
300  bool cm4_fpu_enabled = false;
301  struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
302  if (is_armv7m(armv7m_target)) {
303  if (armv7m_target->fp_feature != FP_NONE) {
304  /* Found ARM v7m target which includes a FPU */
305  uint32_t cpacr;
306 
307  retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
308  if (retval != ERROR_OK) {
309  LOG_ERROR("Could not read CPACR register to check FPU state");
310  return -1;
311  }
312 
313  /* Check if CP10 and CP11 are set to full access. */
314  if (cpacr & 0x00F00000) {
315  /* Found target with enabled FPU */
316  cm4_fpu_enabled = true;
317  }
318  }
319  }
320 
321  if (!cm4_fpu_enabled) {
322  LOG_DEBUG("cm3 stacking");
323  return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs);
324  }
325 
326  /* Read the LR to decide between stacking with or without FPU */
327  uint32_t lr_svc;
328  retval = target_read_u32(rtos->target, stack_ptr + 0x20, &lr_svc);
329  if (retval != ERROR_OK) {
330  LOG_OUTPUT("Error reading stack frame from rtkernel thread\r\n");
331  return retval;
332  }
333 
334  if ((lr_svc & 0x10) == 0) {
335  LOG_DEBUG("cm4f_fpu stacking");
336  return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs);
337  }
338 
339  LOG_DEBUG("cm4f stacking");
340  return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs);
341 }
342 
343 static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
344 {
345  *symbol_list = calloc(ARRAY_SIZE(rtkernel_symbol_list), sizeof(struct symbol_table_elem));
346  if (!*symbol_list)
347  return ERROR_FAIL;
348 
349  for (size_t i = 0; i < ARRAY_SIZE(rtkernel_symbol_list); i++) {
350  (*symbol_list)[i].symbol_name = rtkernel_symbol_list[i].name;
351  (*symbol_list)[i].optional = rtkernel_symbol_list[i].optional;
352  }
353 
354  return ERROR_OK;
355 }
356 
357 static bool rtkernel_detect_rtos(struct target *target)
358 {
359  return (target->rtos->symbols) &&
361 }
362 
363 static int rtkernel_create(struct target *target)
364 {
365  for (size_t i = 0; i < ARRAY_SIZE(rtkernel_params_list); i++) {
366  if (strcmp(rtkernel_params_list[i].target_name, target->type->name) == 0) {
368  return 0;
369  }
370  }
371 
372  LOG_ERROR("Could not find target in rt-kernel compatibility list");
373  return -1;
374 }
375 
376 const struct rtos_type rtkernel_rtos = {
377  .name = "rtkernel",
378 
379  .detect_rtos = rtkernel_detect_rtos,
380  .create = rtkernel_create,
381  .update_threads = rtkernel_update_threads,
382  .get_thread_reg_list = rtkernel_get_thread_reg_list,
383  .get_symbol_list_to_lookup = rtkernel_get_symbol_list_to_lookup,
384 };
const char * name
Definition: armv4_5.c:76
@ FP_NONE
Definition: armv7m.h:210
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:262
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:250
#define FPU_CPACR
Definition: cortex_m.h:111
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_OUTPUT(expr ...)
Definition: log.h:141
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
#define MIN(a, b)
Definition: replacements.h:22
static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: rtkernel.c:343
#define ST_SIG
Definition: rtkernel.c:27
static void * realloc_preserve(void *ptr, size_t old_size, size_t new_size)
Definition: rtkernel.c:90
#define ST_DLY
Definition: rtkernel.c:28
static int rtkernel_verify_task(struct rtos *rtos, uint32_t task)
Definition: rtkernel.c:191
#define ST_SEM
Definition: rtkernel.c:25
static bool rtkernel_detect_rtos(struct target *target)
Definition: rtkernel.c:357
rtkernel_symbol_values
Definition: rtkernel.c:60
@ sym___off_os_state2chain
Definition: rtkernel.c:62
@ sym___val_task_magic
Definition: rtkernel.c:69
@ sym___off_os_state2current
Definition: rtkernel.c:63
@ sym___off_task2magic
Definition: rtkernel.c:65
@ sym___off_task2name
Definition: rtkernel.c:68
@ sym_os_state
Definition: rtkernel.c:61
@ sym___off_task2chain
Definition: rtkernel.c:64
@ sym___off_task2stack
Definition: rtkernel.c:66
@ sym___off_task2state
Definition: rtkernel.c:67
#define ST_FLAG
Definition: rtkernel.c:29
static int rtkernel_update_threads(struct rtos *rtos)
Definition: rtkernel.c:207
#define ST_MBOX
Definition: rtkernel.c:31
static const struct symbols rtkernel_symbol_list[]
Definition: rtkernel.c:77
static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task)
Definition: rtkernel.c:102
#define ST_TT_YIELD
Definition: rtkernel.c:35
static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: rtkernel.c:270
#define ST_DEAD
Definition: rtkernel.c:23
#define ST_FLAG_ALL
Definition: rtkernel.c:30
static const struct rtkernel_params rtkernel_params_list[]
Definition: rtkernel.c:45
#define ST_TT
Definition: rtkernel.c:34
#define ST_WAIT
Definition: rtkernel.c:24
static int rtkernel_create(struct target *target)
Definition: rtkernel.c:363
const struct rtos_type rtkernel_rtos
Definition: rtkernel.c:376
#define ST_MTX
Definition: rtkernel.c:26
#define ST_SUSPEND
Definition: rtkernel.c:33
#define ST_STP
Definition: rtkernel.c:32
int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs)
Definition: rtos.c:602
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:695
const struct rtos_register_stacking rtos_standard_cortex_m3_stacking
const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking
const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking
int fp_feature
Definition: armv7m.h:232
const struct rtos_register_stacking * stacking_info_cm4f_fpu
Definition: rtkernel.c:42
const char * target_name
Definition: rtkernel.c:39
const struct rtos_register_stacking * stacking_info_cm4f
Definition: rtkernel.c:41
const struct rtos_register_stacking * stacking_info_cm3
Definition: rtkernel.c:40
Definition: rtos.h:53
Definition: rtos.h:59
const char * name
Definition: rtos.h:60
Definition: rtos.h:36
int thread_count
Definition: rtos.h:47
struct thread_detail * thread_details
Definition: rtos.h:46
struct symbol_table_elem * symbols
Definition: rtos.h:39
struct target * target
Definition: rtos.h:40
void * rtos_specific_params
Definition: rtos.h:50
threadid_t current_thread
Definition: rtos.h:45
Table should be terminated by an element with NULL in symbol_name.
Definition: rtos.h:23
symbol_address_t address
Definition: rtos.h:25
Definition: eCos.c:369
const char * name
Definition: eCos.c:370
bool optional
Definition: eCos.c:372
const char * name
Name of this type of target.
Definition: target_type.h:31
Definition: target.h:116
struct rtos * rtos
Definition: target.h:183
struct target_type * type
Definition: target.h:117
char * extra_info_str
Definition: rtos.h:33
char * thread_name_str
Definition: rtos.h:32
threadid_t threadid
Definition: rtos.h:30
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2407
int target_read_u16(struct target *target, target_addr_t address, uint16_t *value)
Definition: target.c:2574
int target_read_u32(struct target *target, target_addr_t address, uint32_t *value)
Definition: target.c:2550
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
#define NULL
Definition: usb.h:16
uint8_t state[4]
Definition: vdebug.c:21