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

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)