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/target_type.h"
16 #include "target/armv7m.h"
17 #include "target/cortex_m.h"
18 #include "rtos.h"
19 #include "helper/log.h"
20 #include "helper/types.h"
21 #include "server/gdb_server.h"
22 
23 #include "nuttx_header.h"
24 
25 
26 int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
27 
28 #ifdef CONFIG_DISABLE_SIGNALS
29 #define SIG_QUEUE_NUM 0
30 #else
31 #define SIG_QUEUE_NUM 1
32 #endif /* CONFIG_DISABLE_SIGNALS */
33 
34 #ifdef CONFIG_DISABLE_MQUEUE
35 #define M_QUEUE_NUM 0
36 #else
37 #define M_QUEUE_NUM 2
38 #endif /* CONFIG_DISABLE_MQUEUE */
39 
40 #ifdef CONFIG_PAGING
41 #define PAGING_QUEUE_NUM 1
42 #else
43 #define PAGING_QUEUE_NUM 0
44 #endif /* CONFIG_PAGING */
45 
46 
47 #define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
48 
49 
50 /* see nuttx/sched/os_start.c */
51 static char *nuttx_symbol_list[] = {
52  "g_readytorun", /* 0: must be top of this array */
53  "g_tasklisttable",
54  NULL
55 };
56 
57 /* see nuttx/include/nuttx/sched.h */
58 struct tcb {
59  uint32_t flink;
60  uint32_t blink;
61  uint8_t dat[512];
62 };
63 
64 static struct {
65  uint32_t addr;
66  uint32_t prio;
68 
69 static char *task_state_str[] = {
70  "INVALID",
71  "PENDING",
72  "READYTORUN",
73  "RUNNING",
74  "INACTIVE",
75  "WAIT_SEM",
76 #ifndef CONFIG_DISABLE_SIGNALS
77  "WAIT_SIG",
78 #endif /* CONFIG_DISABLE_SIGNALS */
79 #ifndef CONFIG_DISABLE_MQUEUE
80  "WAIT_MQNOTEMPTY",
81  "WAIT_MQNOTFULL",
82 #endif /* CONFIG_DISABLE_MQUEUE */
83 #ifdef CONFIG_PAGING
84  "WAIT_PAGEFILL",
85 #endif /* CONFIG_PAGING */
86 };
87 
88 /* see arch/arm/include/armv7-m/irq_cmnvector.h */
90  { ARMV7M_R0, 0x28, 32 }, /* r0 */
91  { ARMV7M_R1, 0x2c, 32 }, /* r1 */
92  { ARMV7M_R2, 0x30, 32 }, /* r2 */
93  { ARMV7M_R3, 0x34, 32 }, /* r3 */
94  { ARMV7M_R4, 0x08, 32 }, /* r4 */
95  { ARMV7M_R5, 0x0c, 32 }, /* r5 */
96  { ARMV7M_R6, 0x10, 32 }, /* r6 */
97  { ARMV7M_R7, 0x14, 32 }, /* r7 */
98  { ARMV7M_R8, 0x18, 32 }, /* r8 */
99  { ARMV7M_R9, 0x1c, 32 }, /* r9 */
100  { ARMV7M_R10, 0x20, 32 }, /* r10 */
101  { ARMV7M_R11, 0x24, 32 }, /* r11 */
102  { ARMV7M_R12, 0x38, 32 }, /* r12 */
103  { ARMV7M_R13, 0, 32 }, /* sp */
104  { ARMV7M_R14, 0x3c, 32 }, /* lr */
105  { ARMV7M_PC, 0x40, 32 }, /* pc */
106  { ARMV7M_XPSR, 0x44, 32 }, /* xPSR */
107 };
108 
109 
110 static const struct rtos_register_stacking nuttx_stacking_cortex_m = {
111  .stack_registers_size = 0x48,
112  .stack_growth_direction = -1,
113  .num_output_registers = 17,
114  .register_offsets = nuttx_stack_offsets_cortex_m
115 };
116 
118  { ARMV7M_R0, 0x6c, 32 }, /* r0 */
119  { ARMV7M_R1, 0x70, 32 }, /* r1 */
120  { ARMV7M_R2, 0x74, 32 }, /* r2 */
121  { ARMV7M_R3, 0x78, 32 }, /* r3 */
122  { ARMV7M_R4, 0x08, 32 }, /* r4 */
123  { ARMV7M_R5, 0x0c, 32 }, /* r5 */
124  { ARMV7M_R6, 0x10, 32 }, /* r6 */
125  { ARMV7M_R7, 0x14, 32 }, /* r7 */
126  { ARMV7M_R8, 0x18, 32 }, /* r8 */
127  { ARMV7M_R9, 0x1c, 32 }, /* r9 */
128  { ARMV7M_R10, 0x20, 32 }, /* r10 */
129  { ARMV7M_R11, 0x24, 32 }, /* r11 */
130  { ARMV7M_R12, 0x7c, 32 }, /* r12 */
131  { ARMV7M_R13, 0, 32 }, /* sp */
132  { ARMV7M_R14, 0x80, 32 }, /* lr */
133  { ARMV7M_PC, 0x84, 32 }, /* pc */
134  { ARMV7M_XPSR, 0x88, 32 }, /* xPSR */
135 };
136 
138  .stack_registers_size = 0x8c,
139  .stack_growth_direction = -1,
140  .num_output_registers = 17,
141  .register_offsets = nuttx_stack_offsets_cortex_m_fpu
142 };
143 
144 static int pid_offset = PID;
145 static int state_offset = STATE;
146 static int name_offset = NAME;
147 static int xcpreg_offset = XCPREG;
148 static int name_size = NAME_SIZE;
149 
150 static int rcmd_offset(const char *cmd, const char *name)
151 {
152  if (strncmp(cmd, name, strlen(name)))
153  return -1;
154 
155  if (strlen(cmd) <= strlen(name) + 1)
156  return -1;
157 
158  return atoi(cmd + strlen(name));
159 }
160 
162  char const *packet, int packet_size)
163 {
164  char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
165 
166  if (!strncmp(packet, "qRcmd", 5)) {
167  size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
168  int offset;
169 
170  if (len <= 0)
171  goto pass;
172 
173  offset = rcmd_offset(cmd, "nuttx.pid_offset");
174 
175  if (offset >= 0) {
176  LOG_INFO("pid_offset: %d", offset);
177  pid_offset = offset;
178  goto retok;
179  }
180 
181  offset = rcmd_offset(cmd, "nuttx.state_offset");
182 
183  if (offset >= 0) {
184  LOG_INFO("state_offset: %d", offset);
186  goto retok;
187  }
188 
189  offset = rcmd_offset(cmd, "nuttx.name_offset");
190 
191  if (offset >= 0) {
192  LOG_INFO("name_offset: %d", offset);
194  goto retok;
195  }
196 
197  offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
198 
199  if (offset >= 0) {
200  LOG_INFO("xcpreg_offset: %d", offset);
202  goto retok;
203  }
204 
205  offset = rcmd_offset(cmd, "nuttx.name_size");
206 
207  if (offset >= 0) {
208  LOG_INFO("name_size: %d", offset);
209  name_size = offset;
210  goto retok;
211  }
212  }
213 pass:
214  return rtos_thread_packet(connection, packet, packet_size);
215 retok:
216  gdb_put_packet(connection, "OK", 2);
217  return ERROR_OK;
218 }
219 
220 
221 static bool nuttx_detect_rtos(struct target *target)
222 {
223  if ((target->rtos->symbols) &&
224  (target->rtos->symbols[0].address != 0) &&
225  (target->rtos->symbols[1].address != 0)) {
226  return true;
227  }
228  return false;
229 }
230 
231 static int nuttx_create(struct target *target)
232 {
233 
235  LOG_INFO("target type name = %s", target->type->name);
236  return 0;
237 }
238 
239 static int nuttx_update_threads(struct rtos *rtos)
240 {
241  uint32_t thread_count;
242  struct tcb tcb;
243  int ret;
244  uint32_t head;
245  uint32_t tcb_addr;
246  uint32_t i;
247  uint8_t state;
248 
249  if (!rtos->symbols) {
250  LOG_ERROR("No symbols for NuttX");
251  return -3;
252  }
253 
254  /* free previous thread details */
256 
258  sizeof(g_tasklist), (uint8_t *)&g_tasklist);
259  if (ret) {
260  LOG_ERROR("target_read_buffer : ret = %d\n", ret);
261  return ERROR_FAIL;
262  }
263 
264  thread_count = 0;
265 
266  for (i = 0; i < TASK_QUEUE_NUM; i++) {
267 
268  if (g_tasklist[i].addr == 0)
269  continue;
270 
271  ret = target_read_u32(rtos->target, g_tasklist[i].addr,
272  &head);
273 
274  if (ret) {
275  LOG_ERROR("target_read_u32 : ret = %d\n", ret);
276  return ERROR_FAIL;
277  }
278 
279  /* readytorun head is current thread */
280  if (g_tasklist[i].addr == rtos->symbols[0].address)
281  rtos->current_thread = head;
282 
283 
284  tcb_addr = head;
285  while (tcb_addr) {
286  struct thread_detail *thread;
287  ret = target_read_buffer(rtos->target, tcb_addr,
288  sizeof(tcb), (uint8_t *)&tcb);
289  if (ret) {
290  LOG_ERROR("target_read_buffer : ret = %d\n",
291  ret);
292  return ERROR_FAIL;
293  }
294  thread_count++;
295 
297  sizeof(struct thread_detail) * thread_count);
298  thread = &rtos->thread_details[thread_count - 1];
299  thread->threadid = tcb_addr;
300  thread->exists = true;
301 
302  state = tcb.dat[state_offset - 8];
303  thread->extra_info_str = NULL;
305  thread->extra_info_str = malloc(256);
306  snprintf(thread->extra_info_str, 256, "pid:%d, %s",
307  tcb.dat[pid_offset - 8] |
308  tcb.dat[pid_offset - 8 + 1] << 8,
310  }
311 
312  if (name_offset) {
313  thread->thread_name_str = malloc(name_size + 1);
314  snprintf(thread->thread_name_str, name_size,
315  "%s", (char *)&tcb.dat[name_offset - 8]);
316  } else {
317  thread->thread_name_str = malloc(sizeof("None"));
318  strcpy(thread->thread_name_str, "None");
319  }
320 
321  tcb_addr = tcb.flink;
322  }
323  }
324  rtos->thread_count = thread_count;
325 
326  return 0;
327 }
328 
329 
330 /*
331  * thread_id = tcb address;
332  */
333 static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
334  struct rtos_reg **reg_list, int *num_regs)
335 {
336  int retval;
337 
338  /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
339  bool cm4_fpu_enabled = false;
340  struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
341  if (is_armv7m(armv7m_target)) {
342  if (armv7m_target->fp_feature == FPV4_SP) {
343  /* Found ARM v7m target which includes a FPU */
344  uint32_t cpacr;
345 
346  retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
347  if (retval != ERROR_OK) {
348  LOG_ERROR("Could not read CPACR register to check FPU state");
349  return -1;
350  }
351 
352  /* Check if CP10 and CP11 are set to full access. */
353  if (cpacr & 0x00F00000) {
354  /* Found target with enabled FPU */
355  cm4_fpu_enabled = 1;
356  }
357  }
358  }
359 
360  const struct rtos_register_stacking *stacking;
361  if (cm4_fpu_enabled)
362  stacking = &nuttx_stacking_cortex_m_fpu;
363  else
364  stacking = &nuttx_stacking_cortex_m;
365 
366  return rtos_generic_stack_read(rtos->target, stacking,
367  (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
368 }
369 
370 static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
371 {
372  unsigned int i;
373 
374  *symbol_list = (struct symbol_table_elem *) calloc(1,
376 
377  for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
378  (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
379 
380  return 0;
381 }
382 
383 struct rtos_type nuttx_rtos = {
384  .name = "nuttx",
385  .detect_rtos = nuttx_detect_rtos,
386  .create = nuttx_create,
387  .update_threads = nuttx_update_threads,
388  .get_thread_reg_list = nuttx_get_thread_reg_list,
389  .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
390 };
const char * name
Definition: armv4_5.c:76
@ ARMV7M_R1
Definition: armv7m.h:108
@ ARMV7M_R6
Definition: armv7m.h:114
@ ARMV7M_R2
Definition: armv7m.h:109
@ ARMV7M_R3
Definition: armv7m.h:110
@ ARMV7M_R14
Definition: armv7m.h:124
@ ARMV7M_R9
Definition: armv7m.h:118
@ ARMV7M_R12
Definition: armv7m.h:122
@ ARMV7M_R0
Definition: armv7m.h:107
@ ARMV7M_R13
Definition: armv7m.h:123
@ ARMV7M_PC
Definition: armv7m.h:125
@ ARMV7M_R7
Definition: armv7m.h:115
@ ARMV7M_R4
Definition: armv7m.h:112
@ ARMV7M_XPSR
Definition: armv7m.h:127
@ ARMV7M_R8
Definition: armv7m.h:117
@ ARMV7M_R11
Definition: armv7m.h:120
@ ARMV7M_R10
Definition: armv7m.h:119
@ ARMV7M_R5
Definition: armv7m.h:113
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:260
@ FPV4_SP
Definition: armv7m.h:211
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:248
size_t unhexify(uint8_t *bin, const char *hex, size_t count)
Convert a string of hexadecimal pairs into its binary representation.
Definition: binarybuffer.c:354
#define FPU_CPACR
Definition: cortex_m.h:97
int gdb_put_packet(struct connection *connection, char *buffer, int len)
Definition: gdb_server.c:531
#define GDB_BUFFER_SIZE
Definition: gdb_server.h:24
The JTAG interface can be implemented with a software or hardware fifo.
#define PID
Definition: kitprog.c:38
#define ERROR_FAIL
Definition: log.h:161
#define LOG_ERROR(expr ...)
Definition: log.h:123
#define LOG_INFO(expr ...)
Definition: log.h:117
#define ERROR_OK
Definition: log.h:155
static int state_offset
Definition: nuttx.c:145
static int nuttx_thread_packet(struct connection *connection, char const *packet, int packet_size)
Definition: nuttx.c:161
static char * nuttx_symbol_list[]
Definition: nuttx.c:51
static int pid_offset
Definition: nuttx.c:144
int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size)
Definition: rtos.c:346
static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: nuttx.c:370
static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[]
Definition: nuttx.c:117
static const struct stack_register_offset nuttx_stack_offsets_cortex_m[]
Definition: nuttx.c:89
static int rcmd_offset(const char *cmd, const char *name)
Definition: nuttx.c:150
static bool nuttx_detect_rtos(struct target *target)
Definition: nuttx.c:221
static int nuttx_create(struct target *target)
Definition: nuttx.c:231
uint32_t prio
Definition: nuttx.c:66
static struct @51 g_tasklist[TASK_QUEUE_NUM]
struct rtos_type nuttx_rtos
Definition: nuttx.c:383
static int nuttx_update_threads(struct rtos *rtos)
Definition: nuttx.c:239
static int name_size
Definition: nuttx.c:148
static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu
Definition: nuttx.c:137
#define TASK_QUEUE_NUM
Definition: nuttx.c:47
static char * task_state_str[]
Definition: nuttx.c:69
static const struct rtos_register_stacking nuttx_stacking_cortex_m
Definition: nuttx.c:110
uint32_t addr
Definition: nuttx.c:65
static int xcpreg_offset
Definition: nuttx.c:147
static int name_offset
Definition: nuttx.c:146
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:333
#define NAME
Definition: nuttx_header.h:51
#define NAME_SIZE
Definition: nuttx_header.h:52
#define XCPREG
Definition: nuttx_header.h:49
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
int fp_feature
Definition: armv7m.h:230
Definition: rtos.h:53
unsigned char stack_registers_size
Definition: rtos.h:92
Definition: rtos.h:59
const char * name
Definition: rtos.h:60
Definition: rtos.h:36
int thread_count
Definition: rtos.h:47
int(* gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size)
Definition: rtos.h:48
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
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 * symbol_name
Definition: rtos.h:24
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
Definition: nuttx.c:58
uint32_t blink
Definition: nuttx.c:60
uint32_t flink
Definition: nuttx.c:59
uint8_t dat[512]
Definition: nuttx.c:61
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
@ STATE
Definition: svf.c:38
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2473
int target_read_u32(struct target *target, target_addr_t address, uint32_t *value)
Definition: target.c:2616
#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 cmd
Definition: vdebug.c:1
uint8_t offset[4]
Definition: vdebug.c:9
uint8_t state[4]
Definition: vdebug.c:21