rtos: remove config.h includes from stackings headers
[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 #include "rtos_nuttx_stackings.h"
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 static int pid_offset = PID;
89 static int state_offset = STATE;
90 static int name_offset = NAME;
91 static int xcpreg_offset = XCPREG;
92 static int name_size = NAME_SIZE;
93
94 static int rcmd_offset(const char *cmd, const char *name)
95 {
96 if (strncmp(cmd, name, strlen(name)))
97 return -1;
98
99 if (strlen(cmd) <= strlen(name) + 1)
100 return -1;
101
102 return atoi(cmd + strlen(name));
103 }
104
105 static int nuttx_thread_packet(struct connection *connection,
106 char const *packet, int packet_size)
107 {
108 char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
109
110 if (!strncmp(packet, "qRcmd", 5)) {
111 size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
112 int offset;
113
114 if (len <= 0)
115 goto pass;
116
117 offset = rcmd_offset(cmd, "nuttx.pid_offset");
118
119 if (offset >= 0) {
120 LOG_INFO("pid_offset: %d", offset);
121 pid_offset = offset;
122 goto retok;
123 }
124
125 offset = rcmd_offset(cmd, "nuttx.state_offset");
126
127 if (offset >= 0) {
128 LOG_INFO("state_offset: %d", offset);
129 state_offset = offset;
130 goto retok;
131 }
132
133 offset = rcmd_offset(cmd, "nuttx.name_offset");
134
135 if (offset >= 0) {
136 LOG_INFO("name_offset: %d", offset);
137 name_offset = offset;
138 goto retok;
139 }
140
141 offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
142
143 if (offset >= 0) {
144 LOG_INFO("xcpreg_offset: %d", offset);
145 xcpreg_offset = offset;
146 goto retok;
147 }
148
149 offset = rcmd_offset(cmd, "nuttx.name_size");
150
151 if (offset >= 0) {
152 LOG_INFO("name_size: %d", offset);
153 name_size = offset;
154 goto retok;
155 }
156 }
157 pass:
158 return rtos_thread_packet(connection, packet, packet_size);
159 retok:
160 gdb_put_packet(connection, "OK", 2);
161 return ERROR_OK;
162 }
163
164
165 static bool nuttx_detect_rtos(struct target *target)
166 {
167 if ((target->rtos->symbols) &&
168 (target->rtos->symbols[0].address != 0) &&
169 (target->rtos->symbols[1].address != 0)) {
170 return true;
171 }
172 return false;
173 }
174
175 static int nuttx_create(struct target *target)
176 {
177
178 target->rtos->gdb_thread_packet = nuttx_thread_packet;
179 LOG_INFO("target type name = %s", target->type->name);
180 return 0;
181 }
182
183 static int nuttx_update_threads(struct rtos *rtos)
184 {
185 uint32_t thread_count;
186 struct tcb tcb;
187 int ret;
188 uint32_t head;
189 uint32_t tcb_addr;
190 uint32_t i;
191 uint8_t state;
192
193 if (!rtos->symbols) {
194 LOG_ERROR("No symbols for NuttX");
195 return -3;
196 }
197
198 /* free previous thread details */
199 rtos_free_threadlist(rtos);
200
201 ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
202 sizeof(g_tasklist), (uint8_t *)&g_tasklist);
203 if (ret) {
204 LOG_ERROR("target_read_buffer : ret = %d\n", ret);
205 return ERROR_FAIL;
206 }
207
208 thread_count = 0;
209
210 for (i = 0; i < TASK_QUEUE_NUM; i++) {
211
212 if (g_tasklist[i].addr == 0)
213 continue;
214
215 ret = target_read_u32(rtos->target, g_tasklist[i].addr,
216 &head);
217
218 if (ret) {
219 LOG_ERROR("target_read_u32 : ret = %d\n", ret);
220 return ERROR_FAIL;
221 }
222
223 /* readytorun head is current thread */
224 if (g_tasklist[i].addr == rtos->symbols[0].address)
225 rtos->current_thread = head;
226
227
228 tcb_addr = head;
229 while (tcb_addr) {
230 struct thread_detail *thread;
231 ret = target_read_buffer(rtos->target, tcb_addr,
232 sizeof(tcb), (uint8_t *)&tcb);
233 if (ret) {
234 LOG_ERROR("target_read_buffer : ret = %d\n",
235 ret);
236 return ERROR_FAIL;
237 }
238 thread_count++;
239
240 rtos->thread_details = realloc(rtos->thread_details,
241 sizeof(struct thread_detail) * thread_count);
242 thread = &rtos->thread_details[thread_count - 1];
243 thread->threadid = tcb_addr;
244 thread->exists = true;
245
246 state = tcb.dat[state_offset - 8];
247 thread->extra_info_str = NULL;
248 if (state < ARRAY_SIZE(task_state_str)) {
249 thread->extra_info_str = malloc(256);
250 snprintf(thread->extra_info_str, 256, "pid:%d, %s",
251 tcb.dat[pid_offset - 8] |
252 tcb.dat[pid_offset - 8 + 1] << 8,
253 task_state_str[state]);
254 }
255
256 if (name_offset) {
257 thread->thread_name_str = malloc(name_size + 1);
258 snprintf(thread->thread_name_str, name_size,
259 "%s", (char *)&tcb.dat[name_offset - 8]);
260 } else {
261 thread->thread_name_str = malloc(sizeof("None"));
262 strcpy(thread->thread_name_str, "None");
263 }
264
265 tcb_addr = tcb.flink;
266 }
267 }
268 rtos->thread_count = thread_count;
269
270 return 0;
271 }
272
273
274 /*
275 * thread_id = tcb address;
276 */
277 static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
278 struct rtos_reg **reg_list, int *num_regs)
279 {
280 int retval;
281
282 /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
283 bool cm4_fpu_enabled = false;
284 struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
285 if (is_armv7m(armv7m_target)) {
286 if (armv7m_target->fp_feature == FPV4_SP) {
287 /* Found ARM v7m target which includes a FPU */
288 uint32_t cpacr;
289
290 retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
291 if (retval != ERROR_OK) {
292 LOG_ERROR("Could not read CPACR register to check FPU state");
293 return -1;
294 }
295
296 /* Check if CP10 and CP11 are set to full access. */
297 if (cpacr & 0x00F00000) {
298 /* Found target with enabled FPU */
299 cm4_fpu_enabled = 1;
300 }
301 }
302 }
303
304 const struct rtos_register_stacking *stacking;
305 if (cm4_fpu_enabled)
306 stacking = &nuttx_stacking_cortex_m_fpu;
307 else
308 stacking = &nuttx_stacking_cortex_m;
309
310 return rtos_generic_stack_read(rtos->target, stacking,
311 (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
312 }
313
314 static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
315 {
316 unsigned int i;
317
318 *symbol_list = (struct symbol_table_elem *) calloc(1,
319 sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list));
320
321 for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
322 (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
323
324 return 0;
325 }
326
327 const struct rtos_type nuttx_rtos = {
328 .name = "nuttx",
329 .detect_rtos = nuttx_detect_rtos,
330 .create = nuttx_create,
331 .update_threads = nuttx_update_threads,
332 .get_thread_reg_list = nuttx_get_thread_reg_list,
333 .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
334 };

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)