OpenOCD
nuttx.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright 2016,2017 Sony Video & Sound Products Inc. *
5  * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
6  * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
7  ***************************************************************************/
8 
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12 
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/armv7m.h"
16 #include "target/cortex_m.h"
17 #include "rtos.h"
18 #include "helper/log.h"
19 #include "helper/types.h"
20 #include "target/register.h"
21 #include "rtos_nuttx_stackings.h"
22 
23 #define NAME_SIZE 32
24 #define EXTRAINFO_SIZE 256
25 
26 /* Only 32-bit CPUs are supported by the current implementation. Supporting
27  * other CPUs will require reading this information from the target and
28  * adapting the code accordingly.
29  */
30 #define PTR_WIDTH 4
31 
32 struct nuttx_params {
33  const char *target_name;
35 };
36 
37 /*
38  * struct tcbinfo_s is located in the sched.h
39  * https://github.com/apache/nuttx/blob/master/include/nuttx/sched.h
40  */
41 #define TCBINFO_TARGET_SIZE 22
42 struct tcbinfo {
43  uint16_t pid_off; /* Offset of tcb.pid */
44  uint16_t state_off; /* Offset of tcb.task_state */
45  uint16_t pri_off; /* Offset of tcb.sched_priority */
46  uint16_t name_off; /* Offset of tcb.name */
47  uint16_t regs_off; /* Offset of tcb.regs */
48  uint16_t basic_num; /* Num of genernal regs */
49  uint16_t total_num; /* Num of regs in tcbinfo.reg_offs */
50  target_addr_t xcpreg_off; /* Offset pointer of xcp.regs */
51 };
52 
53 struct symbols {
54  const char *name;
55  bool optional;
56 };
57 
58 static const struct symbols nuttx_symbol_list[] = {
59  { "g_readytorun", false },
60  { "g_pidhash", false },
61  { "g_npidhash", false },
62  { "g_tcbinfo", false },
63  { "g_reg_offs", false},
64  { NULL, false }
65 };
66 
67 static char *task_state_str[] = {
68  "INVALID",
69  "PENDING",
70  "READYTORUN",
71  "RUNNING",
72  "INACTIVE",
73  "WAIT_SEM",
74  "WAIT_SIG",
75  "WAIT_MQNOTEMPTY",
76  "WAIT_MQNOTFULL",
77  "WAIT_PAGEFILL",
78  "STOPPED",
79 };
80 
81 static const struct nuttx_params nuttx_params_list[] = {
82  {
83  .target_name = "cortex_m",
84  .stacking = &nuttx_stacking_cortex_m,
85  },
86  {
87  .target_name = "hla_target",
88  .stacking = &nuttx_stacking_cortex_m,
89  },
90  {
91  .target_name = "esp32",
92  .stacking = &nuttx_esp32_stacking,
93  },
94  {
95  .target_name = "esp32s2",
96  .stacking = &nuttx_esp32s2_stacking,
97  },
98  {
99  .target_name = "esp32s3",
100  .stacking = &nuttx_esp32s3_stacking,
101  },
102  {
103  .target_name = "esp32c3",
104  .stacking = &nuttx_riscv_stacking,
105  },
106 };
107 
108 static bool nuttx_detect_rtos(struct target *target)
109 {
110  if (target->rtos->symbols &&
113  return true;
114  return false;
115 }
116 
117 static int nuttx_create(struct target *target)
118 {
119  const struct nuttx_params *param;
120  unsigned int i;
121 
122  for (i = 0; i < ARRAY_SIZE(nuttx_params_list); i++) {
123  param = &nuttx_params_list[i];
124  if (strcmp(target_type_name(target), param->target_name) == 0) {
125  LOG_INFO("Detected target \"%s\"", param->target_name);
126  break;
127  }
128  }
129 
130  if (i >= ARRAY_SIZE(nuttx_params_list)) {
131  LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target));
132  return JIM_ERR;
133  }
134 
135  /* We found a target in our list, copy its reference. */
136  target->rtos->rtos_specific_params = (void *)param;
137 
138  return JIM_OK;
139 }
140 
141 static int nuttx_smp_init(struct target *target)
142 {
143  /* Return OK for now so that the initialisation sequence doesn't stop.
144  * SMP case will be implemented later. */
145  return ERROR_OK;
146 }
147 
148 static target_addr_t target_buffer_get_addr(struct target *target, const uint8_t *buffer)
149 {
150 #if PTR_WIDTH == 8
152 #else
154 #endif
155 }
156 
157 static int nuttx_update_threads(struct rtos *rtos)
158 {
159  struct tcbinfo tcbinfo;
160  uint32_t pidhashaddr, npidhash, tcbaddr;
161  uint16_t pid;
162  uint8_t state;
163 
164  if (!rtos->symbols) {
165  LOG_ERROR("No symbols for nuttx");
166  return ERROR_FAIL;
167  }
168 
169  /* Free previous thread details */
171 
172  /* NuttX provides a hash table that keeps track of all the TCBs.
173  * We first read its size from g_npidhash and its address from g_pidhash.
174  * Its content is then read from these values.
175  */
176  int ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_NPIDHASH].address, &npidhash);
177  if (ret != ERROR_OK) {
178  LOG_ERROR("Failed to read g_npidhash: ret = %d", ret);
179  return ERROR_FAIL;
180  }
181 
182  LOG_DEBUG("Hash table size (g_npidhash) = %" PRId32, npidhash);
183 
184  ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_PIDHASH].address, &pidhashaddr);
185  if (ret != ERROR_OK) {
186  LOG_ERROR("Failed to read g_pidhash address: ret = %d", ret);
187  return ERROR_FAIL;
188  }
189 
190  LOG_DEBUG("Hash table address (g_pidhash) = %" PRIx32, pidhashaddr);
191 
192  uint8_t *pidhash = malloc(npidhash * PTR_WIDTH);
193  if (!pidhash) {
194  LOG_ERROR("Failed to allocate pidhash");
195  return ERROR_FAIL;
196  }
197 
198  ret = target_read_buffer(rtos->target, pidhashaddr, PTR_WIDTH * npidhash, pidhash);
199  if (ret != ERROR_OK) {
200  LOG_ERROR("Failed to read tcbhash: ret = %d", ret);
201  goto errout;
202  }
203 
204  /* NuttX provides a struct that contains TCB offsets for required members.
205  * Read its content from g_tcbinfo.
206  */
207  uint8_t buff[TCBINFO_TARGET_SIZE];
208  ret = target_read_buffer(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address, sizeof(buff), buff);
209  if (ret != ERROR_OK) {
210  LOG_ERROR("Failed to read tcbinfo: ret = %d", ret);
211  goto errout;
212  }
221 
222  /* The head of the g_readytorun list is the currently running task.
223  * Reading in a temporary variable first to avoid endianness issues,
224  * rtos->current_thread is int64_t. */
225  uint32_t current_thread;
227  if (ret != ERROR_OK) {
228  LOG_ERROR("Failed to read g_readytorun: ret = %d", ret);
229  goto errout;
230  }
232 
233  uint32_t thread_count = 0;
234 
235  for (unsigned int i = 0; i < npidhash; i++) {
236  tcbaddr = target_buffer_get_u32(rtos->target, &pidhash[i * PTR_WIDTH]);
237 
238  if (!tcbaddr)
239  continue;
240 
241  ret = target_read_u16(rtos->target, tcbaddr + tcbinfo.pid_off, &pid);
242  if (ret != ERROR_OK) {
243  LOG_ERROR("Failed to read PID of TCB@0x%x from pidhash[%d]: ret = %d",
244  tcbaddr, i, ret);
245  goto errout;
246  }
247 
248  ret = target_read_u8(rtos->target, tcbaddr + tcbinfo.state_off, &state);
249  if (ret != ERROR_OK) {
250  LOG_ERROR("Failed to read state of TCB@0x%x from pidhash[%d]: ret = %d",
251  tcbaddr, i, ret);
252  goto errout;
253  }
254 
255  struct thread_detail *new_thread_details = realloc(rtos->thread_details,
256  sizeof(struct thread_detail) * (thread_count + 1));
257  if (!new_thread_details) {
258  ret = ERROR_FAIL;
259  goto errout;
260  }
261 
262  struct thread_detail *thread = &new_thread_details[thread_count];
263  thread->threadid = tcbaddr;
264  thread->exists = true;
265  thread->extra_info_str = NULL;
266 
267  rtos->thread_details = new_thread_details;
268  thread_count++;
269 
271  thread->extra_info_str = malloc(EXTRAINFO_SIZE);
272  if (!thread->extra_info_str) {
273  ret = ERROR_FAIL;
274  goto errout;
275  }
276  snprintf(thread->extra_info_str, EXTRAINFO_SIZE, "pid:%d, %s",
277  pid,
279  }
280 
281  if (tcbinfo.name_off) {
282  thread->thread_name_str = calloc(NAME_SIZE + 1, sizeof(char));
283  if (!thread->thread_name_str) {
284  ret = ERROR_FAIL;
285  goto errout;
286  }
287  ret = target_read_buffer(rtos->target, tcbaddr + tcbinfo.name_off,
288  sizeof(char) * NAME_SIZE, (uint8_t *)thread->thread_name_str);
289  if (ret != ERROR_OK) {
290  LOG_ERROR("Failed to read thread's name: ret = %d", ret);
291  goto errout;
292  }
293  } else {
294  thread->thread_name_str = strdup("None");
295  }
296  }
297 
298  ret = ERROR_OK;
299  rtos->thread_count = thread_count;
300 errout:
301  free(pidhash);
302  return ret;
303 }
304 
306  struct rtos_reg **reg_list, int *num_regs)
307 {
308  struct reg **gdb_reg_list;
309 
310  /* Registers for currently running thread are not on task's stack and
311  * should be retrieved from reg caches via target_get_gdb_reg_list */
312  int ret = target_get_gdb_reg_list(rtos->target, &gdb_reg_list, num_regs,
314  if (ret != ERROR_OK) {
315  LOG_ERROR("target_get_gdb_reg_list failed %d", ret);
316  return ret;
317  }
318 
319  *reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
320  if (!(*reg_list)) {
321  LOG_ERROR("Failed to alloc memory for %d", *num_regs);
322  free(gdb_reg_list);
323  return ERROR_FAIL;
324  }
325 
326  for (int i = 0; i < *num_regs; i++) {
327  (*reg_list)[i].number = gdb_reg_list[i]->number;
328  (*reg_list)[i].size = gdb_reg_list[i]->size;
329  memcpy((*reg_list)[i].value, gdb_reg_list[i]->value, ((*reg_list)[i].size + 7) / 8);
330  }
331 
332  free(gdb_reg_list);
333 
334  return ERROR_OK;
335 }
336 
337 static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id,
338  struct rtos_reg **reg_list, int *num_regs)
339 {
340  uint16_t regs_off;
341  uint32_t regsaddr;
342  const struct nuttx_params *priv = rtos->rtos_specific_params;
343  const struct rtos_register_stacking *stacking = priv->stacking;
344 
345  if (!stacking) {
346  LOG_ERROR("Can't find a way to get stacking info");
347  return ERROR_FAIL;
348  }
349 
350  int ret = target_read_u16(rtos->target,
351  rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off),
352  &regs_off);
353  if (ret != ERROR_OK) {
354  LOG_ERROR("Failed to read registers' offset: ret = %d", ret);
355  return ERROR_FAIL;
356  }
357 
358  ret = target_read_u32(rtos->target, thread_id + regs_off, &regsaddr);
359  if (ret != ERROR_OK) {
360  LOG_ERROR("Failed to read registers' address: ret = %d", ret);
361  return ERROR_FAIL;
362  }
363 
364  return rtos_generic_stack_read(rtos->target, stacking, regsaddr, reg_list, num_regs);
365 }
366 
367 static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
368  struct rtos_reg **reg_list, int *num_regs)
369 {
370  if (!rtos) {
371  LOG_ERROR("NUTTX: out of memory");
372  return ERROR_FAIL;
373  }
374 
375  if (thread_id == rtos->current_thread)
376  return nuttx_getreg_current_thread(rtos, reg_list, num_regs);
377  return nuttx_getregs_fromstack(rtos, thread_id, reg_list, num_regs);
378 }
379 
380 static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
381 {
382  *symbol_list = calloc(ARRAY_SIZE(nuttx_symbol_list), sizeof(**symbol_list));
383  if (!*symbol_list) {
384  LOG_ERROR("NUTTX: out of memory");
385  return ERROR_FAIL;
386  }
387 
388  for (unsigned int i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) {
389  (*symbol_list)[i].symbol_name = nuttx_symbol_list[i].name;
390  (*symbol_list)[i].optional = nuttx_symbol_list[i].optional;
391  }
392 
393  return ERROR_OK;
394 }
395 
396 const struct rtos_type nuttx_rtos = {
397  .name = "nuttx",
398  .detect_rtos = nuttx_detect_rtos,
399  .create = nuttx_create,
400  .smp_init = nuttx_smp_init,
401  .update_threads = nuttx_update_threads,
402  .get_thread_reg_list = nuttx_get_thread_reg_list,
403  .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
404 };
static struct esp_usb_jtag * priv
Definition: esp_usb_jtag.c:219
The JTAG interface can be implemented with a software or hardware fifo.
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_INFO(expr ...)
Definition: log.h:126
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
#define PTR_WIDTH
Definition: nuttx.c:30
static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: nuttx.c:380
static const struct symbols nuttx_symbol_list[]
Definition: nuttx.c:58
static bool nuttx_detect_rtos(struct target *target)
Definition: nuttx.c:108
static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: nuttx.c:337
static int nuttx_create(struct target *target)
Definition: nuttx.c:117
static int nuttx_update_threads(struct rtos *rtos)
Definition: nuttx.c:157
static int nuttx_smp_init(struct target *target)
Definition: nuttx.c:141
#define TCBINFO_TARGET_SIZE
Definition: nuttx.c:41
#define NAME_SIZE
Definition: nuttx.c:23
const struct rtos_type nuttx_rtos
Definition: nuttx.c:396
static const struct nuttx_params nuttx_params_list[]
Definition: nuttx.c:81
static char * task_state_str[]
Definition: nuttx.c:67
static target_addr_t target_buffer_get_addr(struct target *target, const uint8_t *buffer)
Definition: nuttx.c:148
#define EXTRAINFO_SIZE
Definition: nuttx.c:24
static int nuttx_getreg_current_thread(struct rtos *rtos, struct rtos_reg **reg_list, int *num_regs)
Definition: nuttx.c:305
static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: nuttx.c:367
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 nuttx_esp32s2_stacking
const struct rtos_register_stacking nuttx_riscv_stacking
const struct rtos_register_stacking nuttx_esp32s3_stacking
const struct rtos_register_stacking nuttx_esp32_stacking
const struct rtos_register_stacking nuttx_stacking_cortex_m
@ NX_SYM_PIDHASH
@ NX_SYM_NPIDHASH
@ NX_SYM_READYTORUN
@ NX_SYM_TCB_INFO
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
const struct rtos_register_stacking * stacking
Definition: nuttx.c:34
const char * target_name
Definition: nuttx.c:33
Definition: register.h:111
uint32_t size
Definition: register.h:132
uint8_t * value
Definition: register.h:122
uint32_t number
Definition: register.h:115
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:368
const char * name
Definition: eCos.c:369
bool optional
Definition: eCos.c:371
Definition: target.h:116
struct rtos * rtos
Definition: target.h:183
Definition: nuttx.c:42
uint16_t pid_off
Definition: nuttx.c:43
uint16_t pri_off
Definition: nuttx.c:45
uint16_t regs_off
Definition: nuttx.c:47
target_addr_t xcpreg_off
Definition: nuttx.c:50
uint16_t basic_num
Definition: nuttx.c:48
uint16_t total_num
Definition: nuttx.c:49
uint16_t state_off
Definition: nuttx.c:44
uint16_t name_off
Definition: nuttx.c:46
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
uint64_t target_buffer_get_u64(struct target *target, const uint8_t *buffer)
Definition: target.c:307
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2407
int target_read_u8(struct target *target, target_addr_t address, uint8_t *value)
Definition: target.c:2598
int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class)
Obtain the registers for GDB.
Definition: target.c:1368
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
uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer)
Definition: target.c:334
uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
Definition: target.c:316
const char * target_type_name(const struct target *target)
Get the target type name.
Definition: target.c:736
@ REG_CLASS_GENERAL
Definition: target.h:112
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
uint64_t target_addr_t
Definition: types.h:335
#define NULL
Definition: usb.h:16
uint8_t state[4]
Definition: vdebug.c:21