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