drivers/ftdi: prevent misleading error msg when more vid/pids configured
[openocd.git] / src / rtos / nuttx.c
blob78271181e2e13bcfb43c98d883e4c7f57323a483
1 // SPDX-License-Identifier: GPL-2.0-or-later
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 ***************************************************************************/
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
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"
23 #include "nuttx_header.h"
24 #include "rtos_nuttx_stackings.h"
26 int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
28 #ifdef CONFIG_DISABLE_SIGNALS
29 #define SIG_QUEUE_NUM 0
30 #else
31 #define SIG_QUEUE_NUM 1
32 #endif /* CONFIG_DISABLE_SIGNALS */
34 #ifdef CONFIG_DISABLE_MQUEUE
35 #define M_QUEUE_NUM 0
36 #else
37 #define M_QUEUE_NUM 2
38 #endif /* CONFIG_DISABLE_MQUEUE */
40 #ifdef CONFIG_PAGING
41 #define PAGING_QUEUE_NUM 1
42 #else
43 #define PAGING_QUEUE_NUM 0
44 #endif /* CONFIG_PAGING */
47 #define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
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
57 /* see nuttx/include/nuttx/sched.h */
58 struct tcb {
59 uint32_t flink;
60 uint32_t blink;
61 uint8_t dat[512];
64 static struct {
65 uint32_t addr;
66 uint32_t prio;
67 } g_tasklist[TASK_QUEUE_NUM];
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 */
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;
94 static int rcmd_offset(const char *cmd, const char *name)
96 if (strncmp(cmd, name, strlen(name)))
97 return -1;
99 if (strlen(cmd) <= strlen(name) + 1)
100 return -1;
102 return atoi(cmd + strlen(name));
105 static int nuttx_thread_packet(struct connection *connection,
106 char const *packet, int packet_size)
108 char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
110 if (!strncmp(packet, "qRcmd", 5)) {
111 size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
112 int offset;
114 if (len <= 0)
115 goto pass;
117 offset = rcmd_offset(cmd, "nuttx.pid_offset");
119 if (offset >= 0) {
120 LOG_INFO("pid_offset: %d", offset);
121 pid_offset = offset;
122 goto retok;
125 offset = rcmd_offset(cmd, "nuttx.state_offset");
127 if (offset >= 0) {
128 LOG_INFO("state_offset: %d", offset);
129 state_offset = offset;
130 goto retok;
133 offset = rcmd_offset(cmd, "nuttx.name_offset");
135 if (offset >= 0) {
136 LOG_INFO("name_offset: %d", offset);
137 name_offset = offset;
138 goto retok;
141 offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
143 if (offset >= 0) {
144 LOG_INFO("xcpreg_offset: %d", offset);
145 xcpreg_offset = offset;
146 goto retok;
149 offset = rcmd_offset(cmd, "nuttx.name_size");
151 if (offset >= 0) {
152 LOG_INFO("name_size: %d", offset);
153 name_size = offset;
154 goto retok;
157 pass:
158 return rtos_thread_packet(connection, packet, packet_size);
159 retok:
160 gdb_put_packet(connection, "OK", 2);
161 return ERROR_OK;
165 static bool nuttx_detect_rtos(struct target *target)
167 if ((target->rtos->symbols) &&
168 (target->rtos->symbols[0].address != 0) &&
169 (target->rtos->symbols[1].address != 0)) {
170 return true;
172 return false;
175 static int nuttx_create(struct target *target)
178 target->rtos->gdb_thread_packet = nuttx_thread_packet;
179 LOG_INFO("target type name = %s", target->type->name);
180 return 0;
183 static int nuttx_update_threads(struct rtos *rtos)
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;
193 if (!rtos->symbols) {
194 LOG_ERROR("No symbols for NuttX");
195 return -3;
198 /* free previous thread details */
199 rtos_free_threadlist(rtos);
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;
208 thread_count = 0;
210 for (i = 0; i < TASK_QUEUE_NUM; i++) {
212 if (g_tasklist[i].addr == 0)
213 continue;
215 ret = target_read_u32(rtos->target, g_tasklist[i].addr,
216 &head);
218 if (ret) {
219 LOG_ERROR("target_read_u32 : ret = %d\n", ret);
220 return ERROR_FAIL;
223 /* readytorun head is current thread */
224 if (g_tasklist[i].addr == rtos->symbols[0].address)
225 rtos->current_thread = head;
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;
238 thread_count++;
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;
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]);
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");
265 tcb_addr = tcb.flink;
268 rtos->thread_count = thread_count;
270 return 0;
275 * thread_id = tcb address;
277 static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
278 struct rtos_reg **reg_list, int *num_regs)
280 int retval;
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;
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;
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;
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;
310 return rtos_generic_stack_read(rtos->target, stacking,
311 (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
314 static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
316 unsigned int i;
318 *symbol_list = (struct symbol_table_elem *) calloc(1,
319 sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list));
321 for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
322 (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
324 return 0;
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,