target/cortex_m: remove fp_code_available counting
[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_list(struct rtos *rtos, int64_t thread_id,
35                                         struct rtos_reg **reg_list, int *num_regs);
36 static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
37 static int hwthread_smp_init(struct target *target);
38
39 #define HW_THREAD_NAME_STR_SIZE (32)
40
41 extern int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
42
43 static inline threadid_t threadid_from_target(const struct target *target)
44 {
45         return target->coreid + 1;
46 }
47
48 const struct rtos_type hwthread_rtos = {
49         .name = "hwthread",
50         .detect_rtos = hwthread_detect_rtos,
51         .create = hwthread_create,
52         .update_threads = hwthread_update_threads,
53         .get_thread_reg_list = hwthread_get_thread_reg_list,
54         .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
55         .smp_init = hwthread_smp_init,
56 };
57
58 struct hwthread_params {
59         int dummy_param;
60 };
61
62 static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num)
63 {
64         char tmp_str[HW_THREAD_NAME_STR_SIZE];
65         threadid_t tid = threadid_from_target(curr);
66
67         memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);
68
69         /* thread-id is the core-id of this core inside the SMP group plus 1 */
70         rtos->thread_details[thread_num].threadid = tid;
71         /* create the thread name */
72         rtos->thread_details[thread_num].exists = true;
73         rtos->thread_details[thread_num].thread_name_str = strdup(target_name(curr));
74         snprintf(tmp_str, HW_THREAD_NAME_STR_SIZE-1, "state: %s", debug_reason_name(curr));
75         rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str);
76
77         return ERROR_OK;
78 }
79
80 static int hwthread_update_threads(struct rtos *rtos)
81 {
82         int threads_found = 0;
83         int thread_list_size = 0;
84         struct target_list *head;
85         struct target *target;
86         int64_t current_thread = 0;
87         enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
88
89         if (rtos == NULL)
90                 return -1;
91
92         target = rtos->target;
93
94         /* wipe out previous thread details if any */
95         rtos_free_threadlist(rtos);
96
97         /* determine the number of "threads" */
98         if (target->smp) {
99                 for (head = target->head; head != NULL; head = head->next) {
100                         struct target *curr = head->target;
101
102                         if (!target_was_examined(curr))
103                                 continue;
104
105                         ++thread_list_size;
106                 }
107         } else
108                 thread_list_size = 1;
109
110         /* create space for new thread details */
111         rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
112
113         if (target->smp) {
114                 /* loop over all threads */
115                 for (head = target->head; head != NULL; head = head->next) {
116                         struct target *curr = head->target;
117
118                         if (!target_was_examined(curr))
119                                 continue;
120
121                         threadid_t tid = threadid_from_target(curr);
122
123                         hwthread_fill_thread(rtos, curr, threads_found);
124
125                         /* find an interesting thread to set as current */
126                         switch (current_reason) {
127                         case DBG_REASON_UNDEFINED:
128                                 current_reason = curr->debug_reason;
129                                 current_thread = tid;
130                                 break;
131                         case DBG_REASON_SINGLESTEP:
132                                 /* single-step can only be overridden by itself */
133                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
134                                         if (tid == rtos->current_threadid)
135                                                 current_thread = tid;
136                                 }
137                                 break;
138                         case DBG_REASON_BREAKPOINT:
139                                 /* single-step overrides breakpoint */
140                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
141                                         current_reason = curr->debug_reason;
142                                         current_thread = tid;
143                                 } else
144                                 /* multiple breakpoints, prefer gdbs' threadid */
145                                 if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
146                                         if (tid == rtos->current_threadid)
147                                                 current_thread = tid;
148                                 }
149                                 break;
150                         case DBG_REASON_WATCHPOINT:
151                                 /* breakpoint and single-step override watchpoint */
152                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
153                                                 curr->debug_reason == DBG_REASON_BREAKPOINT) {
154                                         current_reason = curr->debug_reason;
155                                         current_thread = tid;
156                                 }
157                                 break;
158                         case DBG_REASON_DBGRQ:
159                                 /* all other reasons override debug-request */
160                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
161                                                 curr->debug_reason == DBG_REASON_WATCHPOINT ||
162                                                 curr->debug_reason == DBG_REASON_BREAKPOINT) {
163                                         current_reason = curr->debug_reason;
164                                         current_thread = tid;
165                                 } else
166                                 if (curr->debug_reason == DBG_REASON_DBGRQ) {
167                                         if (tid == rtos->current_threadid)
168                                                 current_thread = tid;
169                                 }
170
171                                 break;
172
173                         default:
174                                 break;
175                         }
176
177                         threads_found++;
178                 }
179         } else {
180                 hwthread_fill_thread(rtos, target, threads_found);
181                 current_thread = threadid_from_target(target);
182                 threads_found++;
183         }
184
185         rtos->thread_count = threads_found;
186
187         /* we found an interesting thread, set it as current */
188         if (current_thread != 0)
189                 rtos->current_thread = current_thread;
190         else if (rtos->current_threadid != 0)
191                 rtos->current_thread = rtos->current_threadid;
192         else
193                 rtos->current_thread = threadid_from_target(target);
194
195         LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
196         return 0;
197 }
198
199 static int hwthread_smp_init(struct target *target)
200 {
201         return hwthread_update_threads(target->rtos);
202 }
203
204 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
205                                         struct rtos_reg **rtos_reg_list, int *num_regs)
206 {
207         struct target_list *head;
208         struct target *target;
209         struct target *curr;
210         struct reg **reg_list;
211         int retval;
212
213         if (rtos == NULL)
214                 return ERROR_FAIL;
215
216         target = rtos->target;
217
218         /* Find the thread with that thread_id */
219         if (target->smp) {
220                 curr = NULL;
221                 for (head = target->head; head != NULL; head = head->next) {
222                         curr = head->target;
223
224                         if (thread_id == threadid_from_target(curr))
225                                 break;
226                 }
227
228                 if (head == NULL)
229                         return ERROR_FAIL;
230         } else {
231                 curr = target;
232                 if (thread_id != threadid_from_target(curr))
233                         return ERROR_FAIL;
234
235         }
236
237         if (!target_was_examined(curr))
238                 return ERROR_FAIL;
239
240         retval = target_get_gdb_reg_list(curr, &reg_list, num_regs,
241                         REG_CLASS_GENERAL);
242         if (retval != ERROR_OK)
243                 return retval;
244
245         *rtos_reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
246         if (*rtos_reg_list == NULL) {
247                 free(reg_list);
248                 return ERROR_FAIL;
249         }
250
251         for (int i = 0; i < *num_regs; i++) {
252                 (*rtos_reg_list)[i].number = (*reg_list)[i].number;
253                 (*rtos_reg_list)[i].size = (*reg_list)[i].size;
254                 memcpy((*rtos_reg_list)[i].value, (*reg_list)[i].value,
255                        ((*reg_list)[i].size + 7) / 8);
256         }
257
258         free(reg_list);
259
260         return ERROR_OK;
261
262 }
263
264 static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
265 {
266         /* return an empty list, we don't have any symbols to look up */
267         *symbol_list = calloc(1, sizeof(symbol_table_elem_t));
268         (*symbol_list)[0].symbol_name = NULL;
269         return 0;
270 }
271
272 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
273 {
274         struct target *target = get_target_from_connection(connection);
275         struct target_list *head;
276         struct target *curr;
277
278         if (target->smp) {
279                 /* Find the thread with that thread_id */
280                 curr = NULL;
281                 for (head = target->head; head != NULL; head = head->next) {
282                         curr = head->target;
283
284                         if (thread_id == threadid_from_target(curr))
285                                 break;
286                 }
287
288                 if (head == NULL)
289                         return ERROR_FAIL;
290         } else {
291                 curr = target;
292                 if (thread_id != threadid_from_target(curr))
293                         return ERROR_FAIL;
294         }
295
296         *p_target = curr;
297
298         return ERROR_OK;
299 }
300
301 static bool hwthread_detect_rtos(struct target *target)
302 {
303         /* always return 0, avoid auto-detection */
304         return false;
305 }
306
307 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
308 {
309         struct target *target = get_target_from_connection(connection);
310
311         struct target *curr = NULL;
312         int64_t current_threadid;
313
314         if (packet[0] == 'H' && packet[1] == 'g') {
315                 sscanf(packet, "Hg%16" SCNx64, &current_threadid);
316
317                 if (current_threadid > 0) {
318                         if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
319                                 LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid);
320                                 gdb_put_packet(connection, "E01", 3);
321                                 return ERROR_FAIL;
322                         }
323                         target->rtos->current_thread = current_threadid;
324                 } else
325                 if (current_threadid == 0 || current_threadid == -1)
326                         target->rtos->current_thread = threadid_from_target(target);
327
328                 target->rtos->current_threadid = current_threadid;
329
330                 gdb_put_packet(connection, "OK", 2);
331                 return ERROR_OK;
332         }
333
334         return rtos_thread_packet(connection, packet, packet_size);
335 }
336
337 static int hwthread_create(struct target *target)
338 {
339         LOG_INFO("Hardware thread awareness created");
340
341         target->rtos->rtos_specific_params = NULL;
342         target->rtos->current_thread = 0;
343         target->rtos->thread_details = NULL;
344         target->rtos->gdb_target_for_threadid = hwthread_target_for_threadid;
345         target->rtos->gdb_thread_packet = hwthread_thread_packet;
346         return 0;
347 }