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