61fd9aa6ca1b366ef0894b8f6f002fad6d4d996c
[openocd.git] / src / rtos / nuttx.c
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 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
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"
33
34 #include "nuttx_header.h"
35
36
37 int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
38
39 #ifdef CONFIG_DISABLE_SIGNALS
40 #define SIG_QUEUE_NUM 0
41 #else
42 #define SIG_QUEUE_NUM 1
43 #endif /* CONFIG_DISABLE_SIGNALS */
44
45 #ifdef CONFIG_DISABLE_MQUEUE
46 #define M_QUEUE_NUM 0
47 #else
48 #define M_QUEUE_NUM 2
49 #endif /* CONFIG_DISABLE_MQUEUE */
50
51 #ifdef CONFIG_PAGING
52 #define PAGING_QUEUE_NUM 1
53 #else
54 #define PAGING_QUEUE_NUM 0
55 #endif /* CONFIG_PAGING */
56
57
58 #define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
59
60
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
66 };
67
68 /* see nuttx/include/nuttx/sched.h */
69 struct tcb {
70 uint32_t flink;
71 uint32_t blink;
72 uint8_t dat[512];
73 };
74
75 struct {
76 uint32_t addr;
77 uint32_t prio;
78 } g_tasklist[TASK_QUEUE_NUM];
79
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 */
97 };
98
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 */
118 };
119
120
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 */
127 };
128
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 */
147 };
148
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 */
155 };
156
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;
162
163 static int rcmd_offset(const char *cmd, const char *name)
164 {
165 if (strncmp(cmd, name, strlen(name)))
166 return -1;
167
168 if (strlen(cmd) <= strlen(name) + 1)
169 return -1;
170
171 return atoi(cmd + strlen(name));
172 }
173
174 static int nuttx_thread_packet(struct connection *connection,
175 char const *packet, int packet_size)
176 {
177 char cmd[GDB_BUFFER_SIZE / 2] = "";
178
179 if (!strncmp(packet, "qRcmd", 5)) {
180 size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
181 int offset;
182
183 if (len <= 0)
184 goto pass;
185
186 offset = rcmd_offset(cmd, "nuttx.pid_offset");
187
188 if (offset >= 0) {
189 LOG_INFO("pid_offset: %d", offset);
190 pid_offset = offset;
191 goto retok;
192 }
193
194 offset = rcmd_offset(cmd, "nuttx.state_offset");
195
196 if (offset >= 0) {
197 LOG_INFO("state_offset: %d", offset);
198 state_offset = offset;
199 goto retok;
200 }
201
202 offset = rcmd_offset(cmd, "nuttx.name_offset");
203
204 if (offset >= 0) {
205 LOG_INFO("name_offset: %d", offset);
206 name_offset = offset;
207 goto retok;
208 }
209
210 offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
211
212 if (offset >= 0) {
213 LOG_INFO("xcpreg_offset: %d", offset);
214 xcpreg_offset = offset;
215 goto retok;
216 }
217
218 offset = rcmd_offset(cmd, "nuttx.name_size");
219
220 if (offset >= 0) {
221 LOG_INFO("name_size: %d", offset);
222 name_size = offset;
223 goto retok;
224 }
225 }
226 pass:
227 return rtos_thread_packet(connection, packet, packet_size);
228 retok:
229 gdb_put_packet(connection, "OK", 2);
230 return ERROR_OK;
231 }
232
233
234 static bool nuttx_detect_rtos(struct target *target)
235 {
236 if ((target->rtos->symbols != NULL) &&
237 (target->rtos->symbols[0].address != 0) &&
238 (target->rtos->symbols[1].address != 0)) {
239 return true;
240 }
241 return false;
242 }
243
244 static int nuttx_create(struct target *target)
245 {
246
247 target->rtos->gdb_thread_packet = nuttx_thread_packet;
248 LOG_INFO("target type name = %s", target->type->name);
249 return 0;
250 }
251
252 static int nuttx_update_threads(struct rtos *rtos)
253 {
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;
261
262 if (rtos->symbols == NULL) {
263 LOG_ERROR("No symbols for NuttX");
264 return -3;
265 }
266
267 /* free previous thread details */
268 rtos_free_threadlist(rtos);
269
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;
275 }
276
277 thread_count = 0;
278
279 for (i = 0; i < TASK_QUEUE_NUM; i++) {
280
281 if (g_tasklist[i].addr == 0)
282 continue;
283
284 ret = target_read_u32(rtos->target, g_tasklist[i].addr,
285 &head);
286
287 if (ret) {
288 LOG_ERROR("target_read_u32 : ret = %d\n", ret);
289 return ERROR_FAIL;
290 }
291
292 /* readytorun head is current thread */
293 if (g_tasklist[i].addr == rtos->symbols[0].address)
294 rtos->current_thread = head;
295
296
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;
306 }
307 thread_count++;
308
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;
314
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]);
323 }
324
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");
332 }
333
334 tcb_addr = tcb.flink;
335 }
336 }
337 rtos->thread_count = thread_count;
338
339 return 0;
340 }
341
342
343 /*
344 * thread_id = tcb address;
345 */
346 static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
347 struct rtos_reg **reg_list, int *num_regs)
348 {
349 int retval;
350
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;
358
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;
363 }
364
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;
369 }
370 }
371 }
372
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;
378
379 return rtos_generic_stack_read(rtos->target, stacking,
380 (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
381 }
382
383 static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
384 {
385 unsigned int i;
386
387 *symbol_list = (symbol_table_elem_t *) calloc(1,
388 sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list));
389
390 for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
391 (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
392
393 return 0;
394 }
395
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,
403 };
404

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)