rtos: Remove typedef'd struct
[fw/openocd] / src / rtos / hwthread.c
1 /***************************************************************************
2  *                                                                         *
3  *   This program is free software; you can redistribute it and/or modify  *
4  *   it under the terms of the GNU General Public License as published by  *
5  *   the Free Software Foundation; either version 2 of the License, or     *
6  *   (at your option) any later version.                                   *
7  *                                                                         *
8  *   This program is distributed in the hope that it will be useful,       *
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
11  *   GNU General Public License for more details.                          *
12  *                                                                         *
13  *   You should have received a copy of the GNU General Public License     *
14  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
15  ***************************************************************************/
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <helper/time_support.h>
22 #include <jtag/jtag.h>
23 #include "target/target.h"
24 #include "target/target_type.h"
25 #include "target/register.h"
26 #include "rtos.h"
27 #include "helper/log.h"
28 #include "helper/types.h"
29 #include "server/gdb_server.h"
30
31 static bool hwthread_detect_rtos(struct target *target);
32 static int hwthread_create(struct target *target);
33 static int hwthread_update_threads(struct rtos *rtos);
34 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
35                 uint32_t reg_num, struct rtos_reg *rtos_reg);
36 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
37                 struct rtos_reg **reg_list, int *num_regs);
38 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
39 static int hwthread_smp_init(struct target *target);
40 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
41
42 #define HW_THREAD_NAME_STR_SIZE (32)
43
44 extern int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
45
46 static inline threadid_t threadid_from_target(const struct target *target)
47 {
48         return target->coreid + 1;
49 }
50
51 const struct rtos_type hwthread_rtos = {
52         .name = "hwthread",
53         .detect_rtos = hwthread_detect_rtos,
54         .create = hwthread_create,
55         .update_threads = hwthread_update_threads,
56         .get_thread_reg_list = hwthread_get_thread_reg_list,
57         .get_thread_reg = hwthread_get_thread_reg,
58         .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
59         .smp_init = hwthread_smp_init,
60         .set_reg = hwthread_set_reg,
61 };
62
63 struct hwthread_params {
64         int dummy_param;
65 };
66
67 static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num)
68 {
69         char tmp_str[HW_THREAD_NAME_STR_SIZE];
70         threadid_t tid = threadid_from_target(curr);
71
72         memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);
73
74         /* thread-id is the core-id of this core inside the SMP group plus 1 */
75         rtos->thread_details[thread_num].threadid = tid;
76         /* create the thread name */
77         rtos->thread_details[thread_num].exists = true;
78         rtos->thread_details[thread_num].thread_name_str = strdup(target_name(curr));
79         snprintf(tmp_str, HW_THREAD_NAME_STR_SIZE-1, "state: %s", debug_reason_name(curr));
80         rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str);
81
82         return ERROR_OK;
83 }
84
85 static int hwthread_update_threads(struct rtos *rtos)
86 {
87         int threads_found = 0;
88         int thread_list_size = 0;
89         struct target_list *head;
90         struct target *target;
91         int64_t current_thread = 0;
92         enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
93
94         if (rtos == NULL)
95                 return -1;
96
97         target = rtos->target;
98
99         /* wipe out previous thread details if any */
100         rtos_free_threadlist(rtos);
101
102         /* determine the number of "threads" */
103         if (target->smp) {
104                 for (head = target->head; head != NULL; head = head->next) {
105                         struct target *curr = head->target;
106
107                         if (!target_was_examined(curr))
108                                 continue;
109
110                         ++thread_list_size;
111                 }
112         } else
113                 thread_list_size = 1;
114
115         /* create space for new thread details */
116         rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
117
118         if (target->smp) {
119                 /* loop over all threads */
120                 for (head = target->head; head != NULL; head = head->next) {
121                         struct target *curr = head->target;
122
123                         if (!target_was_examined(curr))
124                                 continue;
125
126                         threadid_t tid = threadid_from_target(curr);
127
128                         hwthread_fill_thread(rtos, curr, threads_found);
129
130                         /* find an interesting thread to set as current */
131                         switch (current_reason) {
132                         case DBG_REASON_UNDEFINED:
133                                 current_reason = curr->debug_reason;
134                                 current_thread = tid;
135                                 break;
136                         case DBG_REASON_SINGLESTEP:
137                                 /* single-step can only be overridden by itself */
138                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
139                                         if (tid == rtos->current_threadid)
140                                                 current_thread = tid;
141                                 }
142                                 break;
143                         case DBG_REASON_BREAKPOINT:
144                                 /* single-step overrides breakpoint */
145                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
146                                         current_reason = curr->debug_reason;
147                                         current_thread = tid;
148                                 } else
149                                 /* multiple breakpoints, prefer gdbs' threadid */
150                                 if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
151                                         if (tid == rtos->current_threadid)
152                                                 current_thread = tid;
153                                 }
154                                 break;
155                         case DBG_REASON_WATCHPOINT:
156                                 /* breakpoint and single-step override watchpoint */
157                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
158                                                 curr->debug_reason == DBG_REASON_BREAKPOINT) {
159                                         current_reason = curr->debug_reason;
160                                         current_thread = tid;
161                                 }
162                                 break;
163                         case DBG_REASON_DBGRQ:
164                                 /* all other reasons override debug-request */
165                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
166                                                 curr->debug_reason == DBG_REASON_WATCHPOINT ||
167                                                 curr->debug_reason == DBG_REASON_BREAKPOINT) {
168                                         current_reason = curr->debug_reason;
169                                         current_thread = tid;
170                                 } else
171                                 if (curr->debug_reason == DBG_REASON_DBGRQ) {
172                                         if (tid == rtos->current_threadid)
173                                                 current_thread = tid;
174                                 }
175
176                                 break;
177
178                         default:
179                                 break;
180                         }
181
182                         threads_found++;
183                 }
184         } else {
185                 hwthread_fill_thread(rtos, target, threads_found);
186                 current_thread = threadid_from_target(target);
187                 threads_found++;
188         }
189
190         rtos->thread_count = threads_found;
191
192         /* we found an interesting thread, set it as current */
193         if (current_thread != 0)
194                 rtos->current_thread = current_thread;
195         else if (rtos->current_threadid != 0)
196                 rtos->current_thread = rtos->current_threadid;
197         else
198                 rtos->current_thread = threadid_from_target(target);
199
200         LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
201         return 0;
202 }
203
204 static int hwthread_smp_init(struct target *target)
205 {
206         return hwthread_update_threads(target->rtos);
207 }
208
209 static struct target *hwthread_find_thread(struct target *target, int64_t thread_id)
210 {
211         /* Find the thread with that thread_id */
212         if (target == NULL)
213                 return NULL;
214         if (target->smp) {
215                 for (struct target_list *head = target->head; head != NULL; head = head->next) {
216                         if (thread_id == threadid_from_target(head->target))
217                                 return head->target;
218                 }
219         } else if (thread_id == threadid_from_target(target)) {
220                 return target;
221         }
222         return NULL;
223 }
224
225 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
226                 struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
227 {
228         if (rtos == NULL)
229                 return ERROR_FAIL;
230
231         struct target *target = rtos->target;
232
233         struct target *curr = hwthread_find_thread(target, thread_id);
234         if (curr == NULL)
235                 return ERROR_FAIL;
236
237         if (!target_was_examined(curr))
238                 return ERROR_FAIL;
239
240         int reg_list_size;
241         struct reg **reg_list;
242         int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
243                         REG_CLASS_GENERAL);
244         if (retval != ERROR_OK)
245                 return retval;
246
247         int j = 0;
248         for (int i = 0; i < reg_list_size; i++) {
249                 if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
250                         continue;
251                 j++;
252         }
253         *rtos_reg_list_size = j;
254         *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
255         if (*rtos_reg_list == NULL) {
256                 free(reg_list);
257                 return ERROR_FAIL;
258         }
259
260         j = 0;
261         for (int i = 0; i < reg_list_size; i++) {
262                 if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
263                         continue;
264                 (*rtos_reg_list)[j].number = (*reg_list)[i].number;
265                 (*rtos_reg_list)[j].size = (*reg_list)[i].size;
266                 memcpy((*rtos_reg_list)[j].value, (*reg_list)[i].value,
267                                 ((*reg_list)[i].size + 7) / 8);
268                 j++;
269         }
270         free(reg_list);
271
272         return ERROR_OK;
273 }
274
275 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
276                 uint32_t reg_num, struct rtos_reg *rtos_reg)
277 {
278         if (rtos == NULL)
279                 return ERROR_FAIL;
280
281         struct target *target = rtos->target;
282
283         struct target *curr = hwthread_find_thread(target, thread_id);
284         if (curr == NULL) {
285                 LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id);
286                 return ERROR_FAIL;
287         }
288
289         if (!target_was_examined(curr)) {
290                 LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid);
291                 return ERROR_FAIL;
292         }
293
294         struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
295         if (!reg) {
296                 LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num,
297                                 thread_id);
298                 return ERROR_FAIL;
299         }
300
301         if (reg->type->get(reg) != ERROR_OK)
302                 return ERROR_FAIL;
303
304         rtos_reg->number = reg->number;
305         rtos_reg->size = reg->size;
306         unsigned bytes = (reg->size + 7) / 8;
307         assert(bytes <= sizeof(rtos_reg->value));
308         memcpy(rtos_reg->value, reg->value, bytes);
309
310         return ERROR_OK;
311 }
312
313 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
314 {
315         if (rtos == NULL)
316                 return ERROR_FAIL;
317
318         struct target *target = rtos->target;
319
320         struct target *curr = hwthread_find_thread(target, rtos->current_thread);
321         if (curr == NULL)
322                 return ERROR_FAIL;
323
324         struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
325         if (!reg)
326                 return ERROR_FAIL;
327
328         return reg->type->set(reg, reg_value);
329 }
330
331 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
332 {
333         /* return an empty list, we don't have any symbols to look up */
334         *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
335         (*symbol_list)[0].symbol_name = NULL;
336         return 0;
337 }
338
339 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
340 {
341         struct target *target = get_target_from_connection(connection);
342
343         struct target *curr = hwthread_find_thread(target, thread_id);
344         if (curr == NULL)
345                 return ERROR_FAIL;
346
347         *p_target = curr;
348
349         return ERROR_OK;
350 }
351
352 static bool hwthread_detect_rtos(struct target *target)
353 {
354         /* always return 0, avoid auto-detection */
355         return false;
356 }
357
358 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
359 {
360         struct target *target = get_target_from_connection(connection);
361
362         struct target *curr = NULL;
363         int64_t current_threadid;
364
365         if (packet[0] == 'H' && packet[1] == 'g') {
366                 sscanf(packet, "Hg%16" SCNx64, &current_threadid);
367
368                 if (current_threadid > 0) {
369                         if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
370                                 LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid);
371                                 gdb_put_packet(connection, "E01", 3);
372                                 return ERROR_FAIL;
373                         }
374                         target->rtos->current_thread = current_threadid;
375                 } else
376                 if (current_threadid == 0 || current_threadid == -1)
377                         target->rtos->current_thread = threadid_from_target(target);
378
379                 target->rtos->current_threadid = current_threadid;
380
381                 gdb_put_packet(connection, "OK", 2);
382                 return ERROR_OK;
383         }
384
385         return rtos_thread_packet(connection, packet, packet_size);
386 }
387
388 static int hwthread_create(struct target *target)
389 {
390         LOG_INFO("Hardware thread awareness created");
391
392         target->rtos->rtos_specific_params = NULL;
393         target->rtos->current_thread = 0;
394         target->rtos->thread_details = NULL;
395         target->rtos->gdb_target_for_threadid = hwthread_target_for_threadid;
396         target->rtos->gdb_thread_packet = hwthread_thread_packet;
397         return 0;
398 }