Fix 'adapter usb location' documentation
[openocd.git] / src / rtos / nuttx.c
blob61fd9aa6ca1b366ef0894b8f6f002fad6d4d996c
1 /***************************************************************************
2 * Copyright 2016,2017 Sony Video & Sound Products Inc. *
3 * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
4 * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
27 #include "target/armv7m.h"
28 #include "target/cortex_m.h"
29 #include "rtos.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "server/gdb_server.h"
34 #include "nuttx_header.h"
37 int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
39 #ifdef CONFIG_DISABLE_SIGNALS
40 #define SIG_QUEUE_NUM 0
41 #else
42 #define SIG_QUEUE_NUM 1
43 #endif /* CONFIG_DISABLE_SIGNALS */
45 #ifdef CONFIG_DISABLE_MQUEUE
46 #define M_QUEUE_NUM 0
47 #else
48 #define M_QUEUE_NUM 2
49 #endif /* CONFIG_DISABLE_MQUEUE */
51 #ifdef CONFIG_PAGING
52 #define PAGING_QUEUE_NUM 1
53 #else
54 #define PAGING_QUEUE_NUM 0
55 #endif /* CONFIG_PAGING */
58 #define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
61 /* see nuttx/sched/os_start.c */
62 static char *nuttx_symbol_list[] = {
63 "g_readytorun", /* 0: must be top of this array */
64 "g_tasklisttable",
65 NULL
68 /* see nuttx/include/nuttx/sched.h */
69 struct tcb {
70 uint32_t flink;
71 uint32_t blink;
72 uint8_t dat[512];
75 struct {
76 uint32_t addr;
77 uint32_t prio;
78 } g_tasklist[TASK_QUEUE_NUM];
80 static char *task_state_str[] = {
81 "INVALID",
82 "PENDING",
83 "READYTORUN",
84 "RUNNING",
85 "INACTIVE",
86 "WAIT_SEM",
87 #ifndef CONFIG_DISABLE_SIGNALS
88 "WAIT_SIG",
89 #endif /* CONFIG_DISABLE_SIGNALS */
90 #ifndef CONFIG_DISABLE_MQUEUE
91 "WAIT_MQNOTEMPTY",
92 "WAIT_MQNOTFULL",
93 #endif /* CONFIG_DISABLE_MQUEUE */
94 #ifdef CONFIG_PAGING
95 "WAIT_PAGEFILL",
96 #endif /* CONFIG_PAGING */
99 /* see arch/arm/include/armv7-m/irq_cmnvector.h */
100 static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
101 { ARMV7M_R0, 0x28, 32 }, /* r0 */
102 { ARMV7M_R1, 0x2c, 32 }, /* r1 */
103 { ARMV7M_R2, 0x30, 32 }, /* r2 */
104 { ARMV7M_R3, 0x34, 32 }, /* r3 */
105 { ARMV7M_R4, 0x08, 32 }, /* r4 */
106 { ARMV7M_R5, 0x0c, 32 }, /* r5 */
107 { ARMV7M_R6, 0x10, 32 }, /* r6 */
108 { ARMV7M_R7, 0x14, 32 }, /* r7 */
109 { ARMV7M_R8, 0x18, 32 }, /* r8 */
110 { ARMV7M_R9, 0x1c, 32 }, /* r9 */
111 { ARMV7M_R10, 0x20, 32 }, /* r10 */
112 { ARMV7M_R11, 0x24, 32 }, /* r11 */
113 { ARMV7M_R12, 0x38, 32 }, /* r12 */
114 { ARMV7M_R13, 0, 32 }, /* sp */
115 { ARMV7M_R14, 0x3c, 32 }, /* lr */
116 { ARMV7M_PC, 0x40, 32 }, /* pc */
117 { ARMV7M_xPSR, 0x44, 32 }, /* xPSR */
121 static const struct rtos_register_stacking nuttx_stacking_cortex_m = {
122 0x48, /* stack_registers_size */
123 -1, /* stack_growth_direction */
124 17, /* num_output_registers */
125 0, /* stack_alignment */
126 nuttx_stack_offsets_cortex_m /* register_offsets */
129 static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
130 { ARMV7M_R0, 0x6c, 32 }, /* r0 */
131 { ARMV7M_R1, 0x70, 32 }, /* r1 */
132 { ARMV7M_R2, 0x74, 32 }, /* r2 */
133 { ARMV7M_R3, 0x78, 32 }, /* r3 */
134 { ARMV7M_R4, 0x08, 32 }, /* r4 */
135 { ARMV7M_R5, 0x0c, 32 }, /* r5 */
136 { ARMV7M_R6, 0x10, 32 }, /* r6 */
137 { ARMV7M_R7, 0x14, 32 }, /* r7 */
138 { ARMV7M_R8, 0x18, 32 }, /* r8 */
139 { ARMV7M_R9, 0x1c, 32 }, /* r9 */
140 { ARMV7M_R10, 0x20, 32 }, /* r10 */
141 { ARMV7M_R11, 0x24, 32 }, /* r11 */
142 { ARMV7M_R12, 0x7c, 32 }, /* r12 */
143 { ARMV7M_R13, 0, 32 }, /* sp */
144 { ARMV7M_R14, 0x80, 32 }, /* lr */
145 { ARMV7M_PC, 0x84, 32 }, /* pc */
146 { ARMV7M_xPSR, 0x88, 32 }, /* xPSR */
149 static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
150 0x8c, /* stack_registers_size */
151 -1, /* stack_growth_direction */
152 17, /* num_output_registers */
153 0, /* stack_alignment */
154 nuttx_stack_offsets_cortex_m_fpu /* register_offsets */
157 static int pid_offset = PID;
158 static int state_offset = STATE;
159 static int name_offset = NAME;
160 static int xcpreg_offset = XCPREG;
161 static int name_size = NAME_SIZE;
163 static int rcmd_offset(const char *cmd, const char *name)
165 if (strncmp(cmd, name, strlen(name)))
166 return -1;
168 if (strlen(cmd) <= strlen(name) + 1)
169 return -1;
171 return atoi(cmd + strlen(name));
174 static int nuttx_thread_packet(struct connection *connection,
175 char const *packet, int packet_size)
177 char cmd[GDB_BUFFER_SIZE / 2] = "";
179 if (!strncmp(packet, "qRcmd", 5)) {
180 size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
181 int offset;
183 if (len <= 0)
184 goto pass;
186 offset = rcmd_offset(cmd, "nuttx.pid_offset");
188 if (offset >= 0) {
189 LOG_INFO("pid_offset: %d", offset);
190 pid_offset = offset;
191 goto retok;
194 offset = rcmd_offset(cmd, "nuttx.state_offset");
196 if (offset >= 0) {
197 LOG_INFO("state_offset: %d", offset);
198 state_offset = offset;
199 goto retok;
202 offset = rcmd_offset(cmd, "nuttx.name_offset");
204 if (offset >= 0) {
205 LOG_INFO("name_offset: %d", offset);
206 name_offset = offset;
207 goto retok;
210 offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
212 if (offset >= 0) {
213 LOG_INFO("xcpreg_offset: %d", offset);
214 xcpreg_offset = offset;
215 goto retok;
218 offset = rcmd_offset(cmd, "nuttx.name_size");
220 if (offset >= 0) {
221 LOG_INFO("name_size: %d", offset);
222 name_size = offset;
223 goto retok;
226 pass:
227 return rtos_thread_packet(connection, packet, packet_size);
228 retok:
229 gdb_put_packet(connection, "OK", 2);
230 return ERROR_OK;
234 static bool nuttx_detect_rtos(struct target *target)
236 if ((target->rtos->symbols != NULL) &&
237 (target->rtos->symbols[0].address != 0) &&
238 (target->rtos->symbols[1].address != 0)) {
239 return true;
241 return false;
244 static int nuttx_create(struct target *target)
247 target->rtos->gdb_thread_packet = nuttx_thread_packet;
248 LOG_INFO("target type name = %s", target->type->name);
249 return 0;
252 static int nuttx_update_threads(struct rtos *rtos)
254 uint32_t thread_count;
255 struct tcb tcb;
256 int ret;
257 uint32_t head;
258 uint32_t tcb_addr;
259 uint32_t i;
260 uint8_t state;
262 if (rtos->symbols == NULL) {
263 LOG_ERROR("No symbols for NuttX");
264 return -3;
267 /* free previous thread details */
268 rtos_free_threadlist(rtos);
270 ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
271 sizeof(g_tasklist), (uint8_t *)&g_tasklist);
272 if (ret) {
273 LOG_ERROR("target_read_buffer : ret = %d\n", ret);
274 return ERROR_FAIL;
277 thread_count = 0;
279 for (i = 0; i < TASK_QUEUE_NUM; i++) {
281 if (g_tasklist[i].addr == 0)
282 continue;
284 ret = target_read_u32(rtos->target, g_tasklist[i].addr,
285 &head);
287 if (ret) {
288 LOG_ERROR("target_read_u32 : ret = %d\n", ret);
289 return ERROR_FAIL;
292 /* readytorun head is current thread */
293 if (g_tasklist[i].addr == rtos->symbols[0].address)
294 rtos->current_thread = head;
297 tcb_addr = head;
298 while (tcb_addr) {
299 struct thread_detail *thread;
300 ret = target_read_buffer(rtos->target, tcb_addr,
301 sizeof(tcb), (uint8_t *)&tcb);
302 if (ret) {
303 LOG_ERROR("target_read_buffer : ret = %d\n",
304 ret);
305 return ERROR_FAIL;
307 thread_count++;
309 rtos->thread_details = realloc(rtos->thread_details,
310 sizeof(struct thread_detail) * thread_count);
311 thread = &rtos->thread_details[thread_count - 1];
312 thread->threadid = tcb_addr;
313 thread->exists = true;
315 state = tcb.dat[state_offset - 8];
316 thread->extra_info_str = NULL;
317 if (state < sizeof(task_state_str)/sizeof(char *)) {
318 thread->extra_info_str = malloc(256);
319 snprintf(thread->extra_info_str, 256, "pid:%d, %s",
320 tcb.dat[pid_offset - 8] |
321 tcb.dat[pid_offset - 8 + 1] << 8,
322 task_state_str[state]);
325 if (name_offset) {
326 thread->thread_name_str = malloc(name_size + 1);
327 snprintf(thread->thread_name_str, name_size,
328 "%s", (char *)&tcb.dat[name_offset - 8]);
329 } else {
330 thread->thread_name_str = malloc(sizeof("None"));
331 strcpy(thread->thread_name_str, "None");
334 tcb_addr = tcb.flink;
337 rtos->thread_count = thread_count;
339 return 0;
344 * thread_id = tcb address;
346 static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
347 struct rtos_reg **reg_list, int *num_regs)
349 int retval;
351 /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
352 bool cm4_fpu_enabled = false;
353 struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
354 if (is_armv7m(armv7m_target)) {
355 if (armv7m_target->fp_feature == FPv4_SP) {
356 /* Found ARM v7m target which includes a FPU */
357 uint32_t cpacr;
359 retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
360 if (retval != ERROR_OK) {
361 LOG_ERROR("Could not read CPACR register to check FPU state");
362 return -1;
365 /* Check if CP10 and CP11 are set to full access. */
366 if (cpacr & 0x00F00000) {
367 /* Found target with enabled FPU */
368 cm4_fpu_enabled = 1;
373 const struct rtos_register_stacking *stacking;
374 if (cm4_fpu_enabled)
375 stacking = &nuttx_stacking_cortex_m_fpu;
376 else
377 stacking = &nuttx_stacking_cortex_m;
379 return rtos_generic_stack_read(rtos->target, stacking,
380 (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
383 static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
385 unsigned int i;
387 *symbol_list = (symbol_table_elem_t *) calloc(1,
388 sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list));
390 for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
391 (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
393 return 0;
396 struct rtos_type nuttx_rtos = {
397 .name = "nuttx",
398 .detect_rtos = nuttx_detect_rtos,
399 .create = nuttx_create,
400 .update_threads = nuttx_update_threads,
401 .get_thread_reg_list = nuttx_get_thread_reg_list,
402 .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,