dcba8381cb976a476fddb4603f16578dd959f3fe
[fw/openocd] / src / rtos / riot.c
1 /***************************************************************************
2  *   Copyright (C) 2015 by Daniel Krebs                                    *
3  *   Daniel Krebs - github@daniel-krebs.net                                *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
17  ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <helper/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
27 #include "rtos.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "target/armv7m.h"
31 #include "rtos_riot_stackings.h"
32
33 static bool riot_detect_rtos(struct target *target);
34 static int riot_create(struct target *target);
35 static int riot_update_threads(struct rtos *rtos);
36 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
37         struct rtos_reg **reg_list, int *num_regs);
38 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
39
40 struct riot_thread_state {
41         int value;
42         const char *desc;
43 };
44
45 /* refer RIOT sched.h */
46 static const struct riot_thread_state riot_thread_states[] = {
47         { 0, "Stopped" },
48         { 1, "Zombie" },
49         { 2, "Sleeping" },
50         { 3, "Blocked mutex" },
51         { 4, "Blocked receive" },
52         { 5, "Blocked send" },
53         { 6, "Blocked reply" },
54         { 7, "Blocked any flag" },
55         { 8, "Blocked all flags" },
56         { 9, "Blocked mbox" },
57         { 10, "Blocked condition" },
58         { 11, "Running" },
59         { 12, "Pending" },
60 };
61 #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
62
63 struct riot_params {
64         const char *target_name;
65         unsigned char thread_sp_offset;
66         unsigned char thread_status_offset;
67 };
68
69 static const struct riot_params riot_params_list[] = {
70         {
71                 "cortex_m",             /* target_name */
72                 0x00,                                   /* thread_sp_offset */
73                 0x04,                                   /* thread_status_offset */
74         },
75         {       /* STLink */
76                 "hla_target",           /* target_name */
77                 0x00,                   /* thread_sp_offset */
78                 0x04,                   /* thread_status_offset */
79         }
80 };
81 #define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list)
82
83 /* Initialize in riot_create() depending on architecture */
84 static const struct rtos_register_stacking *stacking_info;
85
86 enum riot_symbol_values {
87         RIOT_THREADS_BASE = 0,
88         RIOT_NUM_THREADS,
89         RIOT_ACTIVE_PID,
90         RIOT_MAX_THREADS,
91         RIOT_NAME_OFFSET,
92 };
93
94 /* refer RIOT core/sched.c */
95 static const char *const riot_symbol_list[] = {
96         "sched_threads",
97         "sched_num_threads",
98         "sched_active_pid",
99         "max_threads",
100         "_tcb_name_offset",
101         NULL
102 };
103
104 /* Define which symbols are not mandatory */
105 static const enum riot_symbol_values riot_optional_symbols[] = {
106         RIOT_NAME_OFFSET,
107 };
108
109 const struct rtos_type riot_rtos = {
110         .name = "RIOT",
111         .detect_rtos = riot_detect_rtos,
112         .create = riot_create,
113         .update_threads = riot_update_threads,
114         .get_thread_reg_list = riot_get_thread_reg_list,
115         .get_symbol_list_to_lookup = riot_get_symbol_list_to_lookup,
116 };
117
118 static int riot_update_threads(struct rtos *rtos)
119 {
120         int retval;
121         unsigned int tasks_found = 0;
122         const struct riot_params *param;
123
124         if (rtos == NULL)
125                 return ERROR_FAIL;
126
127         if (rtos->rtos_specific_params == NULL)
128                 return ERROR_FAIL;
129
130         param = (const struct riot_params *)rtos->rtos_specific_params;
131
132         if (rtos->symbols == NULL) {
133                 LOG_ERROR("No symbols for RIOT");
134                 return ERROR_FAIL;
135         }
136
137         if (rtos->symbols[RIOT_THREADS_BASE].address == 0) {
138                 LOG_ERROR("Can't find symbol `%s`",
139                         riot_symbol_list[RIOT_THREADS_BASE]);
140                 return ERROR_FAIL;
141         }
142
143         /* wipe out previous thread details if any */
144         rtos_free_threadlist(rtos);
145
146         /* Reset values */
147         rtos->current_thread = 0;
148         rtos->thread_count = 0;
149
150         /* read the current thread id */
151         int16_t active_pid = 0;
152         retval = target_read_u16(rtos->target,
153                         rtos->symbols[RIOT_ACTIVE_PID].address,
154                         (uint16_t *)&active_pid);
155         if (retval != ERROR_OK) {
156                 LOG_ERROR("Can't read symbol `%s`",
157                         riot_symbol_list[RIOT_ACTIVE_PID]);
158                 return retval;
159         }
160         rtos->current_thread = active_pid;
161
162         /* read the current thread count
163          * It's `int` in RIOT, but this is Cortex M* only anyway */
164         int32_t thread_count = 0;
165         retval = target_read_u16(rtos->target,
166                         rtos->symbols[RIOT_NUM_THREADS].address,
167                         (uint16_t *)&thread_count);
168         if (retval != ERROR_OK) {
169                 LOG_ERROR("Can't read symbol `%s`",
170                         riot_symbol_list[RIOT_NUM_THREADS]);
171                 return retval;
172         }
173         rtos->thread_count = thread_count;
174
175         /* read the maximum number of threads */
176         uint8_t max_threads = 0;
177         retval = target_read_u8(rtos->target,
178                         rtos->symbols[RIOT_MAX_THREADS].address,
179                         &max_threads);
180         if (retval != ERROR_OK) {
181                 LOG_ERROR("Can't read symbol `%s`",
182                         riot_symbol_list[RIOT_MAX_THREADS]);
183                 return retval;
184         }
185
186         /* Base address of thread array */
187         uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
188
189         /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled
190          * with DEVELHELP, so there are no thread names */
191         uint8_t name_offset = 0;
192         if (rtos->symbols[RIOT_NAME_OFFSET].address != 0) {
193                 retval = target_read_u8(rtos->target,
194                                 rtos->symbols[RIOT_NAME_OFFSET].address,
195                                 &name_offset);
196                 if (retval != ERROR_OK) {
197                         LOG_ERROR("Can't read symbol `%s`",
198                                 riot_symbol_list[RIOT_NAME_OFFSET]);
199                         return retval;
200                 }
201         }
202
203         /* Allocate memory for thread description */
204         rtos->thread_details = calloc(thread_count, sizeof(struct thread_detail));
205         if (rtos->thread_details == NULL) {
206                 LOG_ERROR("RIOT: out of memory");
207                 return ERROR_FAIL;
208         }
209
210         /* Buffer for thread names, maximum to display is 32 */
211         char buffer[32];
212
213         for (unsigned int i = 0; i < max_threads; i++) {
214                 /* get pointer to tcb_t */
215                 uint32_t tcb_pointer = 0;
216                 retval = target_read_u32(rtos->target,
217                                 threads_base + (i * 4),
218                                 &tcb_pointer);
219                 if (retval != ERROR_OK) {
220                         LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
221                         goto error;
222                 }
223
224                 if (tcb_pointer == 0) {
225                         /* PID unused */
226                         continue;
227                 }
228
229                 /* Index is PID */
230                 rtos->thread_details[tasks_found].threadid = i;
231
232                 /* read thread state */
233                 uint8_t status = 0;
234                 retval = target_read_u8(rtos->target,
235                                 tcb_pointer + param->thread_status_offset,
236                                 &status);
237                 if (retval != ERROR_OK) {
238                         LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
239                         goto error;
240                 }
241
242                 /* Search for state */
243                 unsigned int k;
244                 for (k = 0; k < RIOT_NUM_STATES; k++) {
245                         if (riot_thread_states[k].value == status)
246                                 break;
247                 }
248
249                 /* Copy state string */
250                 if (k >= RIOT_NUM_STATES) {
251                         rtos->thread_details[tasks_found].extra_info_str =
252                         strdup("unknown state");
253                 } else {
254                         rtos->thread_details[tasks_found].extra_info_str =
255                         strdup(riot_thread_states[k].desc);
256                 }
257
258                 if (rtos->thread_details[tasks_found].extra_info_str == NULL) {
259                         LOG_ERROR("RIOT: out of memory");
260                         retval = ERROR_FAIL;
261                         goto error;
262                 }
263
264                 /* Thread names are only available if compiled with DEVELHELP */
265                 if (name_offset != 0) {
266                         uint32_t name_pointer = 0;
267                         retval = target_read_u32(rtos->target,
268                                         tcb_pointer + name_offset,
269                                         &name_pointer);
270                         if (retval != ERROR_OK) {
271                                 LOG_ERROR("Can't parse `%s`",
272                                         riot_symbol_list[RIOT_THREADS_BASE]);
273                                 goto error;
274                         }
275
276                         /* read thread name */
277                         retval = target_read_buffer(rtos->target,
278                                         name_pointer,
279                                         sizeof(buffer),
280                                         (uint8_t *)&buffer);
281                         if (retval != ERROR_OK) {
282                                 LOG_ERROR("Can't parse `%s`",
283                                         riot_symbol_list[RIOT_THREADS_BASE]);
284                                 goto error;
285                         }
286
287                         /* Make sure the string in the buffer terminates */
288                         if (buffer[sizeof(buffer) - 1] != 0)
289                                 buffer[sizeof(buffer) - 1] = 0;
290
291                         /* Copy thread name */
292                         rtos->thread_details[tasks_found].thread_name_str =
293                         strdup(buffer);
294
295                 } else {
296                         rtos->thread_details[tasks_found].thread_name_str =
297                         strdup("Enable DEVELHELP to see task names");
298                 }
299
300                 if (rtos->thread_details[tasks_found].thread_name_str == NULL) {
301                         LOG_ERROR("RIOT: out of memory");
302                         retval = ERROR_FAIL;
303                         goto error;
304                 }
305
306                 rtos->thread_details[tasks_found].exists = true;
307
308                 tasks_found++;
309         }
310
311         return ERROR_OK;
312
313 error:
314         rtos_free_threadlist(rtos);
315         return retval;
316 }
317
318 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
319                 struct rtos_reg **reg_list, int *num_regs)
320 {
321         int retval;
322         const struct riot_params *param;
323
324         if (rtos == NULL)
325                 return ERROR_FAIL;
326
327         if (thread_id == 0)
328                 return ERROR_FAIL;
329
330         if (rtos->rtos_specific_params == NULL)
331                 return ERROR_FAIL;
332
333         param = (const struct riot_params *)rtos->rtos_specific_params;
334
335         /* find the thread with given thread id */
336         uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
337         uint32_t tcb_pointer = 0;
338         retval = target_read_u32(rtos->target,
339                         threads_base + (thread_id * 4),
340                         &tcb_pointer);
341         if (retval != ERROR_OK) {
342                 LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
343                 return retval;
344         }
345
346         /* read stack pointer for that thread */
347         uint32_t stackptr = 0;
348         retval = target_read_u32(rtos->target,
349                         tcb_pointer + param->thread_sp_offset,
350                         &stackptr);
351         if (retval != ERROR_OK) {
352                 LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
353                 return retval;
354         }
355
356         return rtos_generic_stack_read(rtos->target,
357                         stacking_info,
358                         stackptr,
359                         reg_list,
360                         num_regs);
361 }
362
363 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
364 {
365         *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem));
366
367         if (*symbol_list == NULL) {
368                 LOG_ERROR("RIOT: out of memory");
369                 return ERROR_FAIL;
370         }
371
372         for (unsigned int i = 0; i < ARRAY_SIZE(riot_symbol_list); i++) {
373                 (*symbol_list)[i].symbol_name = riot_symbol_list[i];
374                 (*symbol_list)[i].optional = false;
375
376                 /* Lookup if symbol is optional */
377                 for (unsigned int k = 0; k < sizeof(riot_optional_symbols); k++) {
378                         if (i == riot_optional_symbols[k]) {
379                                 (*symbol_list)[i].optional = true;
380                                 break;
381                         }
382                 }
383         }
384
385         return ERROR_OK;
386 }
387
388 static bool riot_detect_rtos(struct target *target)
389 {
390         if ((target->rtos->symbols != NULL) &&
391                 (target->rtos->symbols[RIOT_THREADS_BASE].address != 0)) {
392                 /* looks like RIOT */
393                 return true;
394         }
395         return false;
396 }
397
398 static int riot_create(struct target *target)
399 {
400         unsigned int i = 0;
401
402         /* lookup if target is supported by RIOT */
403         while ((i < RIOT_NUM_PARAMS) &&
404                 (0 != strcmp(riot_params_list[i].target_name, target->type->name))) {
405                 i++;
406         }
407         if (i >= RIOT_NUM_PARAMS) {
408                 LOG_ERROR("Could not find target in RIOT compatibility list");
409                 return ERROR_FAIL;
410         }
411
412         target->rtos->rtos_specific_params = (void *)&riot_params_list[i];
413         target->rtos->current_thread = 0;
414         target->rtos->thread_details = NULL;
415
416         /* Stacking is different depending on architecture */
417         struct armv7m_common *armv7m_target = target_to_armv7m(target);
418
419         if (armv7m_target->arm.is_armv6m)
420                 stacking_info = &rtos_riot_cortex_m0_stacking;
421         else if (is_armv7m(armv7m_target))
422                 stacking_info = &rtos_riot_cortex_m34_stacking;
423         else {
424                 LOG_ERROR("No stacking info for architecture");
425                 return ERROR_FAIL;
426         }
427         return ERROR_OK;
428 }