]> git.sur5r.net Git - openocd/blob - src/rtos/nuttx.c
rtos: support gdb_get_register_packet
[openocd] / 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