openocd: remove CamelCase symbols *xPSR*
[fw/openocd] / 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 };