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