OpenOCD
embKernel.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2011 by Broadcom Corporation *
5  * Evan Hunter - ehunter@broadcom.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 "rtos.h"
16 #include "helper/log.h"
17 #include "helper/types.h"
19 
20 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
21 
22 static bool embkernel_detect_rtos(struct target *target);
23 static int embkernel_create(struct target *target);
24 static int embkernel_update_threads(struct rtos *rtos);
25 static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
26  struct rtos_reg **reg_list, int *num_regs);
27 static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
28 
29 const struct rtos_type embkernel_rtos = {
30  .name = "embKernel",
31  .detect_rtos = embkernel_detect_rtos,
32  .create = embkernel_create,
33  .update_threads = embkernel_update_threads,
34  .get_thread_reg_list =
36  .get_symbol_list_to_lookup = embkernel_get_symbol_list_to_lookup,
37 };
38 
39 enum {
46 };
47 
48 static const char * const embkernel_symbol_list[] = {
49  "Rtos::sCurrentTask",
50  "Rtos::sListReady",
51  "Rtos::sListSleep",
52  "Rtos::sListSuspended",
53  "Rtos::sMaxPriorities",
54  "Rtos::sCurrentTaskCount",
55  NULL };
56 
58  const char *target_name;
59  const unsigned char pointer_width;
60  const unsigned char thread_count_width;
61  const unsigned char rtos_list_size;
62  const unsigned char thread_stack_offset;
63  const unsigned char thread_name_offset;
64  const unsigned char thread_priority_offset;
65  const unsigned char thread_priority_width;
66  const unsigned char iterable_next_offset;
67  const unsigned char iterable_task_owner_offset;
69 };
70 
71 static const struct embkernel_params embkernel_params_list[] = {
72  {
73  "cortex_m", /* target_name */
74  4, /* pointer_width */
75  4, /* thread_count_width */
76  8, /*rtos_list_size */
77  0, /*thread_stack_offset */
78  4, /*thread_name_offset */
79  8, /*thread_priority_offset */
80  4, /*thread_priority_width */
81  4, /*iterable_next_offset */
82  12, /*iterable_task_owner_offset */
83  &rtos_embkernel_cortex_m_stacking, /* stacking_info*/
84  },
85  { "hla_target", /* target_name */
86  4, /* pointer_width */
87  4, /* thread_count_width */
88  8, /*rtos_list_size */
89  0, /*thread_stack_offset */
90  4, /*thread_name_offset */
91  8, /*thread_priority_offset */
92  4, /*thread_priority_width */
93  4, /*iterable_next_offset */
94  12, /*iterable_task_owner_offset */
95  &rtos_embkernel_cortex_m_stacking, /* stacking_info */
96  }
97 };
98 
99 static bool embkernel_detect_rtos(struct target *target)
100 {
101  if (target->rtos->symbols) {
103  return true;
104  }
105  return false;
106 }
107 
108 static int embkernel_create(struct target *target)
109 {
110  size_t i = 0;
111  while ((i < ARRAY_SIZE(embkernel_params_list)) &&
113  i++;
114 
115  if (i >= ARRAY_SIZE(embkernel_params_list)) {
116  LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
117  "list", target_type_name(target));
118  return -1;
119  }
120 
122  return 0;
123 }
124 
125 static int embkernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embkernel_params *param,
126  struct thread_detail *details, const char *state_str)
127 {
128  int64_t task = 0;
129  int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
130  (uint8_t *) &task);
131  if (retval != ERROR_OK)
132  return retval;
133  details->threadid = (threadid_t) task;
134  details->exists = true;
135 
136  int64_t name_ptr = 0;
137  retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width,
138  (uint8_t *) &name_ptr);
139  if (retval != ERROR_OK)
140  return retval;
141 
143  if (name_ptr) {
145  (uint8_t *) details->thread_name_str);
146  if (retval != ERROR_OK)
147  return retval;
149  } else {
150  snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task);
151  }
152 
153  int64_t priority = 0;
155  (uint8_t *) &priority);
156  if (retval != ERROR_OK)
157  return retval;
159  if (task == rtos->current_thread) {
160  snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: Running, Priority: %u",
161  (unsigned int) priority);
162  } else {
163  snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: %s, Priority: %u",
164  state_str, (unsigned int) priority);
165  }
166 
167  LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
168  (unsigned int)task, details->thread_name_str);
169  return 0;
170 }
171 
172 static int embkernel_update_threads(struct rtos *rtos)
173 {
174  /* int i = 0; */
175  int retval;
176  const struct embkernel_params *param;
177 
178  if (!rtos)
179  return -1;
180 
182  return -3;
183 
184  if (!rtos->symbols) {
185  LOG_ERROR("No symbols for embKernel");
186  return -4;
187  }
188 
190  LOG_ERROR("Don't have the thread list head");
191  return -2;
192  }
193 
194  /* wipe out previous thread details if any */
196 
197  param = (const struct embkernel_params *) rtos->rtos_specific_params;
198 
200  (uint8_t *) &rtos->current_thread);
201  if (retval != ERROR_OK) {
202  LOG_ERROR("Error reading current thread in embKernel thread list");
203  return retval;
204  }
205 
206  int64_t max_used_priority = 0;
208  (uint8_t *) &max_used_priority);
209  if (retval != ERROR_OK)
210  return retval;
211 
212  int thread_list_size = 0;
214  param->thread_count_width, (uint8_t *) &thread_list_size);
215 
216  if (retval != ERROR_OK) {
217  LOG_ERROR("Could not read embKernel thread count from target");
218  return retval;
219  }
220 
221  /* create space for new thread details */
222  rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
223  if (!rtos->thread_details) {
224  LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
225  return ERROR_FAIL;
226  }
227 
228  int thread_idx = 0;
229  /* Look for ready tasks */
230  for (int pri = 0; pri < max_used_priority; pri++) {
231  /* Get first item in queue */
232  int64_t iterable = 0;
233  retval = target_read_buffer(rtos->target,
235  (uint8_t *) &iterable);
236  if (retval != ERROR_OK)
237  return retval;
238  for (; iterable && thread_idx < thread_list_size; thread_idx++) {
239  /* Get info from this iterable item */
240  retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Ready");
241  if (retval != ERROR_OK)
242  return retval;
243  /* Get next iterable item */
244  retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
245  (uint8_t *) &iterable);
246  if (retval != ERROR_OK)
247  return retval;
248  }
249  }
250  /* Look for sleeping tasks */
251  int64_t iterable = 0;
253  (uint8_t *) &iterable);
254  if (retval != ERROR_OK)
255  return retval;
256  for (; iterable && thread_idx < thread_list_size; thread_idx++) {
257  /*Get info from this iterable item */
258  retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Sleeping");
259  if (retval != ERROR_OK)
260  return retval;
261  /*Get next iterable item */
262  retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
263  (uint8_t *) &iterable);
264  if (retval != ERROR_OK)
265  return retval;
266  }
267 
268  /* Look for suspended tasks */
269  iterable = 0;
271  (uint8_t *) &iterable);
272  if (retval != ERROR_OK)
273  return retval;
274  for (; iterable && thread_idx < thread_list_size; thread_idx++) {
275  /* Get info from this iterable item */
276  retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Suspended");
277  if (retval != ERROR_OK)
278  return retval;
279  /*Get next iterable item */
280  retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
281  (uint8_t *) &iterable);
282  if (retval != ERROR_OK)
283  return retval;
284  }
285 
286  rtos->thread_count = 0;
287  rtos->thread_count = thread_idx;
288  LOG_OUTPUT("Found %u tasks\n", (unsigned int)thread_idx);
289  return 0;
290 }
291 
292 static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
293  struct rtos_reg **reg_list, int *num_regs)
294 {
295  int retval;
296  const struct embkernel_params *param;
297  int64_t stack_ptr = 0;
298 
299  if (!rtos)
300  return -1;
301 
302  if (thread_id == 0)
303  return -2;
304 
306  return -1;
307 
308  param = (const struct embkernel_params *) rtos->rtos_specific_params;
309 
310  /* Read the stack pointer */
311  retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width,
312  (uint8_t *) &stack_ptr);
313  if (retval != ERROR_OK) {
314  LOG_ERROR("Error reading stack frame from embKernel thread");
315  return retval;
316  }
317 
318  return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
319 }
320 
322 {
323  unsigned int i;
324  *symbol_list = calloc(ARRAY_SIZE(embkernel_symbol_list), sizeof(struct symbol_table_elem));
325 
326  for (i = 0; i < ARRAY_SIZE(embkernel_symbol_list); i++)
327  (*symbol_list)[i].symbol_name = embkernel_symbol_list[i];
328 
329  return 0;
330 }
const struct rtos_type embkernel_rtos
Definition: embKernel.c:29
@ SYMBOL_ID_S_MAX_PRIORITIES
Definition: embKernel.c:44
@ SYMBOL_ID_S_LIST_SLEEP
Definition: embKernel.c:42
@ SYMBOL_ID_S_CURRENT_TASK
Definition: embKernel.c:40
@ SYMBOL_ID_S_LIST_READY
Definition: embKernel.c:41
@ SYMBOL_ID_S_CURRENT_TASK_COUNT
Definition: embKernel.c:45
@ SYMBOL_ID_S_LIST_SUSPENDED
Definition: embKernel.c:43
static int embkernel_create(struct target *target)
Definition: embKernel.c:108
static bool embkernel_detect_rtos(struct target *target)
Definition: embKernel.c:99
static int embkernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embkernel_params *param, struct thread_detail *details, const char *state_str)
Definition: embKernel.c:125
static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: embKernel.c:321
static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: embKernel.c:292
static const struct embkernel_params embkernel_params_list[]
Definition: embKernel.c:71
static const char *const embkernel_symbol_list[]
Definition: embKernel.c:48
static int embkernel_update_threads(struct rtos *rtos)
Definition: embKernel.c:172
#define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
Definition: embKernel.c:20
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_OUTPUT(expr ...)
Definition: log.h:141
#define LOG_WARNING(expr ...)
Definition: log.h:129
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define ERROR_OK
Definition: log.h:164
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
int64_t threadid_t
Definition: rtos.h:15
const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking
const unsigned char thread_name_offset
Definition: embKernel.c:63
const unsigned char iterable_next_offset
Definition: embKernel.c:66
const struct rtos_register_stacking * stacking_info
Definition: embKernel.c:68
const unsigned char thread_count_width
Definition: embKernel.c:60
const unsigned char thread_stack_offset
Definition: embKernel.c:62
const unsigned char rtos_list_size
Definition: embKernel.c:61
const unsigned char pointer_width
Definition: embKernel.c:59
const unsigned char iterable_task_owner_offset
Definition: embKernel.c:67
const char * target_name
Definition: embKernel.c:58
const unsigned char thread_priority_width
Definition: embKernel.c:65
const unsigned char thread_priority_offset
Definition: embKernel.c:64
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: target.h:116
struct rtos * rtos
Definition: target.h:183
char * extra_info_str
Definition: rtos.h:33
char * thread_name_str
Definition: rtos.h:32
bool exists
Definition: rtos.h:31
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
const char * target_type_name(const struct target *target)
Get the target type name.
Definition: target.c:736
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