rtos: Support for "none" rtos
[openocd.git] / src / rtos / nuttx.c
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;
67 } g_tasklist[TASK_QUEUE_NUM];
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 */
89 static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
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
117 static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
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
137 static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
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
161 static int nuttx_thread_packet(struct connection *connection,
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);
185 state_offset = 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);
193 name_offset = 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);
201 xcpreg_offset = 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
234 target->rtos->gdb_thread_packet = nuttx_thread_packet;
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 */
255 rtos_free_threadlist(rtos);
256
257 ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
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
296 rtos->thread_details = realloc(rtos->thread_details,
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;
304 if (state < ARRAY_SIZE(task_state_str)) {
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,
309 task_state_str[state]);
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,
375 sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list));
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 };

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)