jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / rtos / linux.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2011 by STEricsson *
5 * Heythem Bouhaja heythem.bouhaja@stericsson.com : creation *
6 * Michel JAOUEN michel.jaouen@stericsson.com : adaptation to rtos *
7 ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include <helper/time_support.h>
14 #include <jtag/jtag.h>
15 #include "target/target.h"
16 #include "target/target_type.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "rtos.h"
20 #include "rtos_standard_stackings.h"
21 #include <target/register.h>
22 #include <target/smp.h>
23 #include "server/gdb_server.h"
24
25 #define LINUX_USER_KERNEL_BORDER 0xc0000000
26 #include "linux_header.h"
27 #define PHYS
28 #define MAX_THREADS 200
29 /* specific task */
30 struct linux_os {
31 const char *name;
32 uint32_t init_task_addr;
33 int thread_count;
34 int threadid_count;
35 int preupdtate_threadid_count;
36 int nr_cpus;
37 int threads_lookup;
38 int threads_needs_update;
39 struct current_thread *current_threads;
40 struct threads *thread_list;
41 /* virt2phys parameter */
42 uint32_t phys_mask;
43 uint32_t phys_base;
44 };
45
46 struct current_thread {
47 int64_t threadid;
48 int32_t core_id;
49 #ifdef PID_CHECK
50 uint32_t pid;
51 #endif
52 uint32_t TS;
53 struct current_thread *next;
54 };
55
56 struct threads {
57 char name[17];
58 uint32_t base_addr; /* address to read magic */
59 uint32_t state; /* magic value : filled only at creation */
60 uint32_t pid; /* linux pid : id for identifying a thread */
61 uint32_t oncpu; /* content cpu number in current thread */
62 uint32_t asid; /* filled only at creation */
63 int64_t threadid;
64 int status; /* dead = 1 alive = 2 current = 3 alive and current */
65 /* value that should not change during the live of a thread ? */
66 uint32_t thread_info_addr; /* contain latest thread_info_addr computed */
67 /* retrieve from thread_info */
68 struct cpu_context *context;
69 struct threads *next;
70 };
71
72 struct cpu_context {
73 uint32_t R4;
74 uint32_t R5;
75 uint32_t R6;
76 uint32_t R7;
77 uint32_t R8;
78 uint32_t R9;
79 uint32_t IP;
80 uint32_t FP;
81 uint32_t SP;
82 uint32_t PC;
83 uint32_t preempt_count;
84 };
85 static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
86 uint32_t *info_addr);
87 static int insert_into_threadlist(struct target *target, struct threads *t);
88
89 static int linux_os_create(struct target *target);
90
91 static int linux_os_dummy_update(struct rtos *rtos)
92 {
93 /* update is done only when thread request come
94 * too many thread to do it on each stop */
95 return 0;
96 }
97
98 static int linux_compute_virt2phys(struct target *target, target_addr_t address)
99 {
100 struct linux_os *linux_os = (struct linux_os *)
101 target->rtos->rtos_specific_params;
102 target_addr_t pa = 0;
103 int retval = target->type->virt2phys(target, address, &pa);
104 if (retval != ERROR_OK) {
105 LOG_ERROR("Cannot compute linux virt2phys translation");
106 /* fixes default address */
107 linux_os->phys_base = 0;
108 return ERROR_FAIL;
109 }
110
111 linux_os->init_task_addr = address;
112 address = address & linux_os->phys_mask;
113 linux_os->phys_base = pa - address;
114 return ERROR_OK;
115 }
116
117 static int linux_read_memory(struct target *target,
118 uint32_t address, uint32_t size, uint32_t count,
119 uint8_t *buffer)
120 {
121 #ifdef PHYS
122 struct linux_os *linux_os = (struct linux_os *)
123 target->rtos->rtos_specific_params;
124 uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base;
125 #endif
126 if (address < 0xc0000000) {
127 LOG_ERROR("linux awareness : address in user space");
128 return ERROR_FAIL;
129 }
130 #ifdef PHYS
131 target_read_phys_memory(target, pa, size, count, buffer);
132 #endif
133 target_read_memory(target, address, size, count, buffer);
134 return ERROR_OK;
135 }
136
137 static int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
138 {
139
140 if ((addr & 0xfffffffc) != addr)
141 LOG_INFO("unaligned address %" PRIx32 "!!", addr);
142
143 int retval = linux_read_memory(target, addr, 4, 1, buffer);
144 return retval;
145
146 }
147
148 static uint32_t get_buffer(struct target *target, const uint8_t *buffer)
149 {
150 uint32_t value = 0;
151 const uint8_t *value_ptr = buffer;
152 value = target_buffer_get_u32(target, value_ptr);
153 return value;
154 }
155
156 static int linux_os_thread_reg_list(struct rtos *rtos,
157 int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
158 {
159 struct target *target = rtos->target;
160 struct linux_os *linux_os = (struct linux_os *)
161 target->rtos->rtos_specific_params;
162 struct current_thread *tmp = linux_os->current_threads;
163 struct current_thread *next;
164 int found = 0;
165 int retval;
166 /* check if a current thread is requested */
167 next = tmp;
168
169 do {
170 if (next->threadid == thread_id)
171 found = 1;
172 else
173 next = next->next;
174 } while ((found == 0) && (next != tmp) && (next));
175
176 if (found == 0) {
177 LOG_ERROR("could not find thread: %" PRIx64, thread_id);
178 return ERROR_FAIL;
179 }
180
181 /* search target to perform the access */
182 struct reg **gdb_reg_list;
183 struct target_list *head;
184 found = 0;
185 foreach_smp_target(head, target->smp_targets) {
186 if (head->target->coreid == next->core_id) {
187 target = head->target;
188 found = 1;
189 break;
190 }
191 }
192
193 if (found == 0) {
194 LOG_ERROR
195 (
196 "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32,
197 thread_id,
198 next->core_id);
199 return ERROR_FAIL;
200 }
201
202 /*LOG_INFO("thread %lx current on core %x",thread_id, target->coreid);*/
203 retval = target_get_gdb_reg_list(target, &gdb_reg_list, num_regs, REG_CLASS_GENERAL);
204 if (retval != ERROR_OK)
205 return retval;
206
207 *reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
208
209 for (int i = 0; i < *num_regs; ++i) {
210 if (!gdb_reg_list[i]->valid)
211 gdb_reg_list[i]->type->get(gdb_reg_list[i]);
212
213 (*reg_list)[i].number = gdb_reg_list[i]->number;
214 (*reg_list)[i].size = gdb_reg_list[i]->size;
215
216 buf_cpy(gdb_reg_list[i]->value, (*reg_list)[i].value, (*reg_list)[i].size);
217 }
218
219 return ERROR_OK;
220 }
221
222 static bool linux_os_detect(struct target *target)
223 {
224 LOG_INFO("should no be called");
225 return false;
226 }
227
228 static int linux_os_smp_init(struct target *target);
229 static int linux_os_clean(struct target *target);
230 #define INIT_TASK 0
231 static const char * const linux_symbol_list[] = {
232 "init_task",
233 NULL
234 };
235
236 static int linux_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
237 {
238 unsigned int i;
239 *symbol_list = (struct symbol_table_elem *)
240 calloc(ARRAY_SIZE(linux_symbol_list), sizeof(struct symbol_table_elem));
241
242 for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++)
243 (*symbol_list)[i].symbol_name = linux_symbol_list[i];
244
245 return 0;
246 }
247
248 static char *linux_ps_command(struct target *target);
249
250 const struct rtos_type linux_rtos = {
251 .name = "linux",
252 .detect_rtos = linux_os_detect,
253 .create = linux_os_create,
254 .smp_init = linux_os_smp_init,
255 .update_threads = linux_os_dummy_update,
256 .get_thread_reg_list = linux_os_thread_reg_list,
257 .get_symbol_list_to_lookup = linux_get_symbol_list_to_lookup,
258 .clean = linux_os_clean,
259 .ps_command = linux_ps_command,
260 };
261
262 static int linux_thread_packet(struct connection *connection, char const *packet,
263 int packet_size);
264 static void linux_identify_current_threads(struct target *target);
265
266 #ifdef PID_CHECK
267 int fill_task_pid(struct target *target, struct threads *t)
268 {
269 uint32_t pid_addr = t->base_addr + PID;
270 uint8_t buffer[4];
271 int retval = fill_buffer(target, pid_addr, buffer);
272
273 if (retval == ERROR_OK) {
274 uint32_t val = get_buffer(target, buffer);
275 t->pid = val;
276 } else
277 LOG_ERROR("fill_task_pid: unable to read memory");
278
279 return retval;
280 }
281 #endif
282
283 static int fill_task(struct target *target, struct threads *t)
284 {
285 int retval;
286 uint32_t pid_addr = t->base_addr + PID;
287 uint32_t mem_addr = t->base_addr + MEM;
288 uint32_t on_cpu = t->base_addr + ONCPU;
289 uint8_t *buffer = calloc(1, 4);
290 retval = fill_buffer(target, t->base_addr, buffer);
291
292 if (retval == ERROR_OK) {
293 uint32_t val = get_buffer(target, buffer);
294 t->state = val;
295 } else
296 LOG_ERROR("fill_task: unable to read memory");
297
298 retval = fill_buffer(target, pid_addr, buffer);
299
300 if (retval == ERROR_OK) {
301 uint32_t val = get_buffer(target, buffer);
302 t->pid = val;
303 } else
304 LOG_ERROR("fill task: unable to read memory");
305
306 retval = fill_buffer(target, on_cpu, buffer);
307
308 if (retval == ERROR_OK) {
309 uint32_t val = get_buffer(target, buffer);
310 t->oncpu = val;
311 } else
312 LOG_ERROR("fill task: unable to read memory");
313
314 retval = fill_buffer(target, mem_addr, buffer);
315
316 if (retval == ERROR_OK) {
317 uint32_t val = get_buffer(target, buffer);
318
319 if (val != 0) {
320 uint32_t asid_addr = val + MM_CTX;
321 retval = fill_buffer(target, asid_addr, buffer);
322
323 if (retval == ERROR_OK) {
324 val = get_buffer(target, buffer);
325 t->asid = val;
326 } else
327 LOG_ERROR
328 ("fill task: unable to read memory -- ASID");
329 } else
330 t->asid = 0;
331 } else
332 LOG_ERROR("fill task: unable to read memory");
333
334 free(buffer);
335
336 return retval;
337 }
338
339 static int get_name(struct target *target, struct threads *t)
340 {
341 int retval;
342 uint32_t full_name[4];
343 uint32_t comm = t->base_addr + COMM;
344 int i;
345
346 for (i = 0; i < 17; i++)
347 t->name[i] = 0;
348
349 retval = linux_read_memory(target, comm, 4, 4, (uint8_t *) full_name);
350
351 if (retval != ERROR_OK) {
352 LOG_ERROR("get_name: unable to read memory\n");
353 return ERROR_FAIL;
354 }
355
356 uint32_t raw_name = target_buffer_get_u32(target,
357 (const uint8_t *)
358 &full_name[0]);
359 t->name[3] = raw_name >> 24;
360 t->name[2] = raw_name >> 16;
361 t->name[1] = raw_name >> 8;
362 t->name[0] = raw_name;
363 raw_name =
364 target_buffer_get_u32(target, (const uint8_t *)&full_name[1]);
365 t->name[7] = raw_name >> 24;
366 t->name[6] = raw_name >> 16;
367 t->name[5] = raw_name >> 8;
368 t->name[4] = raw_name;
369 raw_name =
370 target_buffer_get_u32(target, (const uint8_t *)&full_name[2]);
371 t->name[11] = raw_name >> 24;
372 t->name[10] = raw_name >> 16;
373 t->name[9] = raw_name >> 8;
374 t->name[8] = raw_name;
375 raw_name =
376 target_buffer_get_u32(target, (const uint8_t *)&full_name[3]);
377 t->name[15] = raw_name >> 24;
378 t->name[14] = raw_name >> 16;
379 t->name[13] = raw_name >> 8;
380 t->name[12] = raw_name;
381 return ERROR_OK;
382
383 }
384
385 static int get_current(struct target *target, int create)
386 {
387 struct target_list *head;
388 uint8_t *buf;
389 uint32_t val;
390 uint32_t ti_addr;
391 uint8_t *buffer = calloc(1, 4);
392 struct linux_os *linux_os = (struct linux_os *)
393 target->rtos->rtos_specific_params;
394 struct current_thread *ctt = linux_os->current_threads;
395
396 /* invalid current threads content */
397 while (ctt) {
398 ctt->threadid = -1;
399 ctt->TS = 0xdeadbeef;
400 ctt = ctt->next;
401 }
402
403 foreach_smp_target(head, target->smp_targets) {
404 struct reg **reg_list;
405 int reg_list_size;
406 int retval;
407
408 if (target_get_gdb_reg_list(head->target, &reg_list,
409 &reg_list_size, REG_CLASS_GENERAL) != ERROR_OK) {
410 free(buffer);
411 return ERROR_TARGET_FAILURE;
412 }
413
414 if (!reg_list[13]->valid)
415 reg_list[13]->type->get(reg_list[13]);
416
417 buf = reg_list[13]->value;
418 val = get_buffer(target, buf);
419 ti_addr = (val & 0xffffe000);
420 uint32_t ts_addr = ti_addr + 0xc;
421 retval = fill_buffer(target, ts_addr, buffer);
422
423 if (retval == ERROR_OK) {
424 uint32_t TS = get_buffer(target, buffer);
425 uint32_t cpu, on_cpu = TS + ONCPU;
426 retval = fill_buffer(target, on_cpu, buffer);
427
428 if (retval == ERROR_OK) {
429 /*uint32_t cpu = get_buffer(target, buffer);*/
430 struct current_thread *ct =
431 linux_os->current_threads;
432 cpu = head->target->coreid;
433
434 while ((ct) && (ct->core_id != (int32_t) cpu))
435 ct = ct->next;
436
437 if ((ct) && (ct->TS == 0xdeadbeef))
438 ct->TS = TS;
439 else
440 LOG_ERROR
441 ("error in linux current thread update");
442
443 if (create && ct) {
444 struct threads *t;
445 t = calloc(1, sizeof(struct threads));
446 t->base_addr = ct->TS;
447 fill_task(target, t);
448 get_name(target, t);
449 t->oncpu = cpu;
450 insert_into_threadlist(target, t);
451 t->status = 3;
452 t->thread_info_addr = 0xdeadbeef;
453 ct->threadid = t->threadid;
454 linux_os->thread_count++;
455 #ifdef PID_CHECK
456 ct->pid = t->pid;
457 #endif
458 /*LOG_INFO("Creation of current thread %s",t->name);*/
459 }
460 }
461 }
462
463 free(reg_list);
464 }
465
466 free(buffer);
467
468 return ERROR_OK;
469 }
470
471 static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
472 uint32_t *thread_info_addr_old)
473 {
474 struct cpu_context *context = calloc(1, sizeof(struct cpu_context));
475 uint32_t preempt_count_addr = 0;
476 uint32_t registers[10];
477 uint8_t *buffer = calloc(1, 4);
478 uint32_t stack = base_addr + QAT;
479 uint32_t thread_info_addr = 0;
480 uint32_t thread_info_addr_update = 0;
481 int retval = ERROR_FAIL;
482 context->R4 = 0xdeadbeef;
483 context->R5 = 0xdeadbeef;
484 context->R6 = 0xdeadbeef;
485 context->R7 = 0xdeadbeef;
486 context->R8 = 0xdeadbeef;
487 context->R9 = 0xdeadbeef;
488 context->IP = 0xdeadbeef;
489 context->FP = 0xdeadbeef;
490 context->SP = 0xdeadbeef;
491 context->PC = 0xdeadbeef;
492 retry:
493
494 if (*thread_info_addr_old == 0xdeadbeef) {
495 retval = fill_buffer(target, stack, buffer);
496
497 if (retval == ERROR_OK)
498 thread_info_addr = get_buffer(target, buffer);
499 else
500 LOG_ERROR("cpu_context: unable to read memory");
501
502 thread_info_addr_update = thread_info_addr;
503 } else
504 thread_info_addr = *thread_info_addr_old;
505
506 preempt_count_addr = thread_info_addr + PREEMPT;
507 retval = fill_buffer(target, preempt_count_addr, buffer);
508
509 if (retval == ERROR_OK)
510 context->preempt_count = get_buffer(target, buffer);
511 else {
512 if (*thread_info_addr_old != 0xdeadbeef) {
513 LOG_ERROR
514 ("cpu_context: cannot read at thread_info_addr");
515
516 if (*thread_info_addr_old < LINUX_USER_KERNEL_BORDER)
517 LOG_INFO
518 ("cpu_context : thread_info_addr in userspace!!!");
519
520 *thread_info_addr_old = 0xdeadbeef;
521 goto retry;
522 }
523
524 LOG_ERROR("cpu_context: unable to read memory");
525 }
526
527 thread_info_addr += CPU_CONT;
528
529 retval = linux_read_memory(target, thread_info_addr, 4, 10,
530 (uint8_t *) registers);
531
532 if (retval != ERROR_OK) {
533 free(buffer);
534 LOG_ERROR("cpu_context: unable to read memory\n");
535 return context;
536 }
537
538 context->R4 =
539 target_buffer_get_u32(target, (const uint8_t *)&registers[0]);
540 context->R5 =
541 target_buffer_get_u32(target, (const uint8_t *)&registers[1]);
542 context->R6 =
543 target_buffer_get_u32(target, (const uint8_t *)&registers[2]);
544 context->R7 =
545 target_buffer_get_u32(target, (const uint8_t *)&registers[3]);
546 context->R8 =
547 target_buffer_get_u32(target, (const uint8_t *)&registers[4]);
548 context->R9 =
549 target_buffer_get_u32(target, (const uint8_t *)&registers[5]);
550 context->IP =
551 target_buffer_get_u32(target, (const uint8_t *)&registers[6]);
552 context->FP =
553 target_buffer_get_u32(target, (const uint8_t *)&registers[7]);
554 context->SP =
555 target_buffer_get_u32(target, (const uint8_t *)&registers[8]);
556 context->PC =
557 target_buffer_get_u32(target, (const uint8_t *)&registers[9]);
558
559 if (*thread_info_addr_old == 0xdeadbeef)
560 *thread_info_addr_old = thread_info_addr_update;
561
562 free(buffer);
563
564 return context;
565 }
566
567 static uint32_t next_task(struct target *target, struct threads *t)
568 {
569 uint8_t *buffer = calloc(1, 4);
570 uint32_t next_addr = t->base_addr + NEXT;
571 int retval = fill_buffer(target, next_addr, buffer);
572
573 if (retval == ERROR_OK) {
574 uint32_t val = get_buffer(target, buffer);
575 val = val - NEXT;
576 free(buffer);
577 return val;
578 } else
579 LOG_ERROR("next task: unable to read memory");
580
581 free(buffer);
582
583 return 0;
584 }
585
586 static struct current_thread *add_current_thread(struct current_thread *currents,
587 struct current_thread *ct)
588 {
589 ct->next = NULL;
590
591 if (!currents) {
592 currents = ct;
593 return currents;
594 } else {
595 struct current_thread *temp = currents;
596
597 while (temp->next)
598 temp = temp->next;
599
600 temp->next = ct;
601 return currents;
602 }
603 }
604
605 static struct threads *liste_del_task(struct threads *task_list, struct threads **t,
606 struct threads *prev)
607 {
608 LOG_INFO("del task %" PRId64, (*t)->threadid);
609 if (prev)
610 prev->next = (*t)->next;
611 else
612 task_list = (*t)->next;
613
614 /* free content of threads */
615 free((*t)->context);
616
617 free(*t);
618 *t = prev ? prev : task_list;
619 return task_list;
620 }
621
622 static struct threads *liste_add_task(struct threads *task_list, struct threads *t,
623 struct threads **last)
624 {
625 t->next = NULL;
626
627 if (!*last)
628 if (!task_list) {
629 task_list = t;
630 return task_list;
631 } else {
632 struct threads *temp = task_list;
633
634 while (temp->next)
635 temp = temp->next;
636
637 temp->next = t;
638 *last = t;
639 return task_list;
640 } else {
641 (*last)->next = t;
642 *last = t;
643 return task_list;
644 }
645 }
646
647 #ifdef PID_CHECK
648 static int current_pid(struct linux_os *linux_os, uint32_t pid)
649 #else
650 static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr)
651 #endif
652 {
653 struct current_thread *ct = linux_os->current_threads;
654 #ifdef PID_CHECK
655
656 while ((ct) && (ct->pid != pid))
657 #else
658 while ((ct) && (ct->TS != base_addr))
659 #endif
660 ct = ct->next;
661 #ifdef PID_CHECK
662 if ((ct) && (ct->pid == pid))
663 #else
664 if ((ct) && (ct->TS == base_addr))
665 #endif
666 return 1;
667
668 return 0;
669 }
670
671 static int linux_get_tasks(struct target *target, int context)
672 {
673 int loop = 0;
674 int retval = 0;
675 struct linux_os *linux_os = (struct linux_os *)
676 target->rtos->rtos_specific_params;
677 linux_os->thread_list = NULL;
678 linux_os->thread_count = 0;
679
680 if (linux_os->init_task_addr == 0xdeadbeef) {
681 LOG_INFO("no init symbol\n");
682 return ERROR_FAIL;
683 }
684
685 int64_t start = timeval_ms();
686
687 struct threads *t = calloc(1, sizeof(struct threads));
688 struct threads *last = NULL;
689 t->base_addr = linux_os->init_task_addr;
690 /* retrieve the thread id , currently running in the different smp core */
691 get_current(target, 1);
692
693 while (((t->base_addr != linux_os->init_task_addr) &&
694 (t->base_addr != 0)) || (loop == 0)) {
695 loop++;
696 fill_task(target, t);
697 retval = get_name(target, t);
698
699 if (loop > MAX_THREADS) {
700 free(t);
701 LOG_INFO("more than %d threads !!", MAX_THREADS);
702 return ERROR_FAIL;
703 }
704
705 if (retval != ERROR_OK) {
706 free(t);
707 return ERROR_FAIL;
708 }
709
710 /* check that this thread is not one the current threads already
711 * created */
712 uint32_t base_addr;
713 #ifdef PID_CHECK
714
715 if (!current_pid(linux_os, t->pid)) {
716 #else
717 if (!current_base_addr(linux_os, t->base_addr)) {
718 #endif
719 t->threadid = linux_os->threadid_count;
720 t->status = 1;
721 linux_os->threadid_count++;
722
723 linux_os->thread_list =
724 liste_add_task(linux_os->thread_list, t, &last);
725 /* no interest to fill the context if it is a current thread. */
726 linux_os->thread_count++;
727 t->thread_info_addr = 0xdeadbeef;
728
729 if (context)
730 t->context =
731 cpu_context_read(target, t->base_addr,
732 &t->thread_info_addr);
733 base_addr = next_task(target, t);
734 } else {
735 /*LOG_INFO("thread %s is a current thread already created",t->name); */
736 base_addr = next_task(target, t);
737 free(t);
738 }
739
740 t = calloc(1, sizeof(struct threads));
741 t->base_addr = base_addr;
742 }
743
744 linux_os->threads_lookup = 1;
745 linux_os->threads_needs_update = 0;
746 linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1;
747 /* check that all current threads have been identified */
748
749 LOG_INFO("complete time %" PRId64 ", thread mean %" PRId64 "\n",
750 (timeval_ms() - start),
751 (timeval_ms() - start) / linux_os->threadid_count);
752
753 LOG_INFO("threadid count %d", linux_os->threadid_count);
754 free(t);
755
756 return ERROR_OK;
757 }
758
759 static int clean_threadlist(struct target *target)
760 {
761 struct linux_os *linux_os = (struct linux_os *)
762 target->rtos->rtos_specific_params;
763 struct threads *old, *temp = linux_os->thread_list;
764
765 while (temp) {
766 old = temp;
767
768 free(temp->context);
769
770 temp = temp->next;
771 free(old);
772 }
773
774 return ERROR_OK;
775 }
776
777 static int linux_os_clean(struct target *target)
778 {
779 struct linux_os *os_linux = (struct linux_os *)
780 target->rtos->rtos_specific_params;
781 clean_threadlist(target);
782 os_linux->init_task_addr = 0xdeadbeef;
783 os_linux->name = "linux";
784 os_linux->thread_list = NULL;
785 os_linux->thread_count = 0;
786 os_linux->nr_cpus = 0;
787 os_linux->threads_lookup = 0;
788 os_linux->threads_needs_update = 0;
789 os_linux->threadid_count = 1;
790 return ERROR_OK;
791 }
792
793 static int insert_into_threadlist(struct target *target, struct threads *t)
794 {
795 struct linux_os *linux_os = (struct linux_os *)
796 target->rtos->rtos_specific_params;
797 struct threads *temp = linux_os->thread_list;
798 t->threadid = linux_os->threadid_count;
799 linux_os->threadid_count++;
800 t->status = 1;
801 t->next = NULL;
802
803 if (!temp)
804 linux_os->thread_list = t;
805 else {
806 while (temp->next)
807 temp = temp->next;
808
809 t->next = NULL;
810 temp->next = t;
811 }
812
813 return ERROR_OK;
814 }
815
816 static void linux_identify_current_threads(struct target *target)
817 {
818 struct linux_os *linux_os = (struct linux_os *)
819 target->rtos->rtos_specific_params;
820 struct threads *thread_list = linux_os->thread_list;
821 struct current_thread *ct = linux_os->current_threads;
822 struct threads *t = NULL;
823
824 while ((ct)) {
825 if (ct->threadid == -1) {
826
827 /* un-identified thread */
828 int found = 0;
829 t = calloc(1, sizeof(struct threads));
830 t->base_addr = ct->TS;
831 #ifdef PID_CHECK
832
833 if (fill_task_pid(target, t) != ERROR_OK) {
834 error_handling:
835 free(t);
836 LOG_ERROR
837 ("linux identify_current_threads: unable to read pid");
838 return;
839 }
840 #endif
841
842 /* search in the list of threads if pid
843 already present */
844 while ((thread_list) && (found == 0)) {
845 #ifdef PID_CHECK
846 if (thread_list->pid == t->pid) {
847 #else
848 if (thread_list->base_addr == t->base_addr) {
849 #endif
850 free(t);
851 t = thread_list;
852 found = 1;
853 }
854 thread_list = thread_list->next;
855 }
856
857 if (!found) {
858 /* it is a new thread */
859 if (fill_task(target, t) != ERROR_OK)
860 goto error_handling;
861
862 get_name(target, t);
863 insert_into_threadlist(target, t);
864 t->thread_info_addr = 0xdeadbeef;
865 }
866
867 t->status = 3;
868 ct->threadid = t->threadid;
869 #ifdef PID_CHECK
870 ct->pid = t->pid;
871 #endif
872 linux_os->thread_count++;
873 #if 0
874 if (found == 0)
875 LOG_INFO("current thread core %x identified %s",
876 ct->core_id, t->name);
877 else
878 LOG_INFO("current thread core %x, reused %s",
879 ct->core_id, t->name);
880 #endif
881 }
882 #if 0
883 else {
884 struct threads tmp;
885 tmp.base_addr = ct->TS;
886 get_name(target, &tmp);
887 LOG_INFO("current thread core %x , already identified %s !!!",
888 ct->core_id, tmp.name);
889 }
890 #endif
891 ct = ct->next;
892 }
893
894 return;
895 #ifndef PID_CHECK
896 error_handling:
897 free(t);
898 LOG_ERROR("unable to read pid");
899 return;
900
901 #endif
902 }
903
904 static int linux_task_update(struct target *target, int context)
905 {
906 struct linux_os *linux_os = (struct linux_os *)
907 target->rtos->rtos_specific_params;
908 struct threads *thread_list = linux_os->thread_list;
909 int retval;
910 int loop = 0;
911 linux_os->thread_count = 0;
912
913 /*thread_list = thread_list->next; skip init_task*/
914 while (thread_list) {
915 thread_list->status = 0; /*setting all tasks to dead state*/
916
917 free(thread_list->context);
918 thread_list->context = NULL;
919
920 thread_list = thread_list->next;
921 }
922
923 int found = 0;
924
925 if (linux_os->init_task_addr == 0xdeadbeef) {
926 LOG_INFO("no init symbol\n");
927 return ERROR_FAIL;
928 }
929 int64_t start = timeval_ms();
930 struct threads *t = calloc(1, sizeof(struct threads));
931 uint32_t previous = 0xdeadbeef;
932 t->base_addr = linux_os->init_task_addr;
933 retval = get_current(target, 0);
934 /*check that all current threads have been identified */
935 linux_identify_current_threads(target);
936
937 while (((t->base_addr != linux_os->init_task_addr) &&
938 (t->base_addr != previous)) || (loop == 0)) {
939 /* for avoiding any permanent loop for any reason possibly due to
940 * target */
941 loop++;
942 previous = t->base_addr;
943 /* read only pid */
944 #ifdef PID_CHECK
945 retval = fill_task_pid(target, t);
946 #endif
947
948 if (retval != ERROR_OK) {
949 free(t);
950 return ERROR_FAIL;
951 }
952
953 thread_list = linux_os->thread_list;
954
955 while (thread_list) {
956 #ifdef PID_CHECK
957 if (t->pid == thread_list->pid) {
958 #else
959 if (t->base_addr == thread_list->base_addr) {
960 #endif
961 if (!thread_list->status) {
962 #ifdef PID_CHECK
963 if (t->base_addr != thread_list->base_addr)
964 LOG_INFO("thread base_addr has changed !!");
965 #endif
966 /* this is not a current thread */
967 thread_list->base_addr = t->base_addr;
968 thread_list->status = 1;
969
970 /* we don 't update this field any more */
971
972 /*thread_list->state = t->state;
973 thread_list->oncpu = t->oncpu;
974 thread_list->asid = t->asid;
975 */
976 if (context)
977 thread_list->context =
978 cpu_context_read(target,
979 thread_list->base_addr,
980 &thread_list->thread_info_addr);
981 } else {
982 /* it is a current thread no need to read context */
983 }
984
985 linux_os->thread_count++;
986 found = 1;
987 break;
988 } else {
989 found = 0;
990 thread_list = thread_list->next;
991 }
992 }
993
994 if (found == 0) {
995 uint32_t base_addr;
996 fill_task(target, t);
997 get_name(target, t);
998 retval = insert_into_threadlist(target, t);
999 t->thread_info_addr = 0xdeadbeef;
1000
1001 if (context)
1002 t->context =
1003 cpu_context_read(target, t->base_addr,
1004 &t->thread_info_addr);
1005
1006 base_addr = next_task(target, t);
1007 t = calloc(1, sizeof(struct threads));
1008 t->base_addr = base_addr;
1009 linux_os->thread_count++;
1010 } else
1011 t->base_addr = next_task(target, t);
1012 }
1013
1014 LOG_INFO("update thread done %" PRId64 ", mean%" PRId64 "\n",
1015 (timeval_ms() - start), (timeval_ms() - start) / loop);
1016 free(t);
1017 linux_os->threads_needs_update = 0;
1018 return ERROR_OK;
1019 }
1020
1021 static int linux_gdb_thread_packet(struct target *target,
1022 struct connection *connection, char const *packet,
1023 int packet_size)
1024 {
1025 int retval;
1026 struct linux_os *linux_os =
1027 (struct linux_os *)target->rtos->rtos_specific_params;
1028
1029 if (linux_os->init_task_addr == 0xdeadbeef) {
1030 /* it has not been initialized */
1031 LOG_INFO("received thread request without init task address");
1032 gdb_put_packet(connection, "l", 1);
1033 return ERROR_OK;
1034 }
1035
1036 retval = linux_get_tasks(target, 1);
1037
1038 if (retval != ERROR_OK)
1039 return ERROR_TARGET_FAILURE;
1040
1041 char *out_str = calloc(MAX_THREADS * 17 + 10, 1);
1042 char *tmp_str = out_str;
1043 tmp_str += sprintf(tmp_str, "m");
1044 struct threads *temp = linux_os->thread_list;
1045
1046 while (temp) {
1047 tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid);
1048 temp = temp->next;
1049 if (temp)
1050 tmp_str += sprintf(tmp_str, ",");
1051 }
1052
1053 gdb_put_packet(connection, out_str, strlen(out_str));
1054 free(out_str);
1055 return ERROR_OK;
1056 }
1057
1058 static int linux_gdb_thread_update(struct target *target,
1059 struct connection *connection, char const *packet,
1060 int packet_size)
1061 {
1062 int found = 0;
1063 struct linux_os *linux_os = (struct linux_os *)
1064 target->rtos->rtos_specific_params;
1065 struct threads *temp = linux_os->thread_list;
1066
1067 while (temp) {
1068 if (temp->threadid == linux_os->preupdtate_threadid_count + 1) {
1069 /*LOG_INFO("FOUND");*/
1070 found = 1;
1071 break;
1072 } else
1073 temp = temp->next;
1074 }
1075
1076 if (found == 1) {
1077 /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/
1078 char *out_strr = calloc(MAX_THREADS * 17 + 10, 1);
1079 char *tmp_strr = out_strr;
1080 tmp_strr += sprintf(tmp_strr, "m");
1081 /*LOG_INFO("CHAR MALLOC & M DONE");*/
1082 tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid);
1083
1084 temp = temp->next;
1085
1086 while (temp) {
1087 /*LOG_INFO("INTO GDB THREAD UPDATE WHILE");*/
1088 tmp_strr += sprintf(tmp_strr, ",");
1089 tmp_strr +=
1090 sprintf(tmp_strr, "%016" PRIx64, temp->threadid);
1091 temp = temp->next;
1092 }
1093
1094 /*tmp_str[0] = 0;*/
1095 gdb_put_packet(connection, out_strr, strlen(out_strr));
1096 linux_os->preupdtate_threadid_count =
1097 linux_os->threadid_count - 1;
1098 free(out_strr);
1099 } else
1100 gdb_put_packet(connection, "l", 1);
1101
1102 return ERROR_OK;
1103 }
1104
1105 static int linux_thread_extra_info(struct target *target,
1106 struct connection *connection, char const *packet,
1107 int packet_size)
1108 {
1109 int64_t threadid = 0;
1110 struct linux_os *linux_os = (struct linux_os *)
1111 target->rtos->rtos_specific_params;
1112 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
1113 /*LOG_INFO("lookup extra info for thread %" SCNx64, threadid);*/
1114 struct threads *temp = linux_os->thread_list;
1115
1116 while (temp) {
1117 if (temp->threadid == threadid) {
1118 char *pid = " PID: ";
1119 char *pid_current = "*PID: ";
1120 char *name = "Name: ";
1121 int str_size = strlen(pid) + strlen(name);
1122 char *tmp_str = calloc(1, str_size + 50);
1123 char *tmp_str_ptr = tmp_str;
1124
1125 /* discriminate current task */
1126 if (temp->status == 3)
1127 tmp_str_ptr += sprintf(tmp_str_ptr, "%s",
1128 pid_current);
1129 else
1130 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid);
1131
1132 tmp_str_ptr += sprintf(tmp_str_ptr, "%d, ", (int)temp->pid);
1133 sprintf(tmp_str_ptr, "%s", name);
1134 sprintf(tmp_str_ptr, "%s", temp->name);
1135 char *hex_str = calloc(1, strlen(tmp_str) * 2 + 1);
1136 size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str,
1137 strlen(tmp_str), strlen(tmp_str) * 2 + 1);
1138 gdb_put_packet(connection, hex_str, pkt_len);
1139 free(hex_str);
1140 free(tmp_str);
1141 return ERROR_OK;
1142 }
1143
1144 temp = temp->next;
1145 }
1146
1147 LOG_INFO("thread not found");
1148 return ERROR_OK;
1149 }
1150
1151 static int linux_gdb_t_packet(struct connection *connection,
1152 struct target *target, char const *packet, int packet_size)
1153 {
1154 int64_t threadid;
1155 struct linux_os *linux_os = (struct linux_os *)
1156 target->rtos->rtos_specific_params;
1157 int retval = ERROR_OK;
1158 sscanf(packet, "T%" SCNx64, &threadid);
1159
1160 if (linux_os->threads_needs_update == 0) {
1161 struct threads *temp = linux_os->thread_list;
1162 struct threads *prev = NULL;
1163
1164 while (temp) {
1165 if (temp->threadid == threadid) {
1166 if (temp->status != 0) {
1167 gdb_put_packet(connection, "OK", 2);
1168 return ERROR_OK;
1169 } else {
1170 /* delete item in the list */
1171 linux_os->thread_list =
1172 liste_del_task(linux_os->thread_list,
1173 &temp, prev);
1174 linux_os->thread_count--;
1175 gdb_put_packet(connection, "E01", 3);
1176 return ERROR_OK;
1177 }
1178 }
1179
1180 /* for deletion */
1181 prev = temp;
1182 temp = temp->next;
1183 }
1184
1185 LOG_INFO("gdb requested status on non existing thread");
1186 gdb_put_packet(connection, "E01", 3);
1187 return ERROR_OK;
1188
1189 } else {
1190 retval = linux_task_update(target, 1);
1191 struct threads *temp = linux_os->thread_list;
1192
1193 while (temp) {
1194 if (temp->threadid == threadid) {
1195 if (temp->status == 1) {
1196 gdb_put_packet(connection, "OK", 2);
1197 return ERROR_OK;
1198 } else {
1199 gdb_put_packet(connection, "E01", 3);
1200 return ERROR_OK;
1201 }
1202 }
1203
1204 temp = temp->next;
1205 }
1206 }
1207
1208 return retval;
1209 }
1210
1211 static int linux_gdb_h_packet(struct connection *connection,
1212 struct target *target, char const *packet, int packet_size)
1213 {
1214 struct linux_os *linux_os = (struct linux_os *)
1215 target->rtos->rtos_specific_params;
1216 struct current_thread *ct = linux_os->current_threads;
1217
1218 /* select to display the current thread of the selected target */
1219 while ((ct) && (ct->core_id != target->coreid))
1220 ct = ct->next;
1221
1222 int64_t current_gdb_thread_rq;
1223
1224 if (linux_os->threads_lookup == 1) {
1225 if ((ct) && (ct->threadid == -1)) {
1226 ct = linux_os->current_threads;
1227
1228 while ((ct) && (ct->threadid == -1))
1229 ct = ct->next;
1230 }
1231
1232 if (!ct) {
1233 /* no current thread can be identified
1234 * any way with smp */
1235 LOG_INFO("no current thread identified");
1236 /* attempt to display the name of the 2 threads identified with
1237 * get_current */
1238 struct threads t;
1239 ct = linux_os->current_threads;
1240
1241 while ((ct) && (ct->threadid == -1)) {
1242 t.base_addr = ct->TS;
1243 get_name(target, &t);
1244 LOG_INFO("name of unidentified thread %s",
1245 t.name);
1246 ct = ct->next;
1247 }
1248
1249 gdb_put_packet(connection, "OK", 2);
1250 return ERROR_OK;
1251 }
1252
1253 if (packet[1] == 'g') {
1254 sscanf(packet, "Hg%16" SCNx64, &current_gdb_thread_rq);
1255
1256 if (current_gdb_thread_rq == 0) {
1257 target->rtos->current_threadid = ct->threadid;
1258 gdb_put_packet(connection, "OK", 2);
1259 } else {
1260 target->rtos->current_threadid =
1261 current_gdb_thread_rq;
1262 gdb_put_packet(connection, "OK", 2);
1263 }
1264 } else if (packet[1] == 'c') {
1265 sscanf(packet, "Hc%16" SCNx64, &current_gdb_thread_rq);
1266
1267 if ((current_gdb_thread_rq == 0) ||
1268 (current_gdb_thread_rq == ct->threadid)) {
1269 target->rtos->current_threadid = ct->threadid;
1270 gdb_put_packet(connection, "OK", 2);
1271 } else
1272 gdb_put_packet(connection, "E01", 3);
1273 }
1274 } else
1275 gdb_put_packet(connection, "OK", 2);
1276
1277 return ERROR_OK;
1278 }
1279
1280 static int linux_thread_packet(struct connection *connection, char const *packet,
1281 int packet_size)
1282 {
1283 int retval = ERROR_OK;
1284 struct current_thread *ct;
1285 struct target *target = get_target_from_connection(connection);
1286 struct linux_os *linux_os = (struct linux_os *)
1287 target->rtos->rtos_specific_params;
1288
1289 switch (packet[0]) {
1290 case 'T': /* Is thread alive?*/
1291
1292 linux_gdb_t_packet(connection, target, packet, packet_size);
1293 break;
1294 case 'H': /* Set current thread */
1295 /* ( 'c' for step and continue, 'g' for all other operations )*/
1296 /*LOG_INFO(" H packet received '%s'", packet);*/
1297 linux_gdb_h_packet(connection, target, packet, packet_size);
1298 break;
1299 case 'q':
1300
1301 if (strncmp(packet, "qSymbol", 7) == 0) {
1302 if (rtos_qsymbol(connection, packet, packet_size) == 1) {
1303 linux_compute_virt2phys(target,
1304 target->rtos->symbols[INIT_TASK].address);
1305 }
1306
1307 break;
1308 } else if (strncmp(packet, "qfThreadInfo", 12) == 0) {
1309 if (!linux_os->thread_list) {
1310 retval = linux_gdb_thread_packet(target,
1311 connection,
1312 packet,
1313 packet_size);
1314 break;
1315 } else {
1316 retval = linux_gdb_thread_update(target,
1317 connection,
1318 packet,
1319 packet_size);
1320 break;
1321 }
1322 } else if (strncmp(packet, "qsThreadInfo", 12) == 0) {
1323 gdb_put_packet(connection, "l", 1);
1324 break;
1325 } else if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) {
1326 linux_thread_extra_info(target, connection, packet,
1327 packet_size);
1328 break;
1329 } else {
1330 retval = GDB_THREAD_PACKET_NOT_CONSUMED;
1331 break;
1332 }
1333
1334 case 'Q':
1335 /* previously response was : thread not found
1336 * gdb_put_packet(connection, "E01", 3); */
1337 retval = GDB_THREAD_PACKET_NOT_CONSUMED;
1338 break;
1339 case 'c':
1340 case 's': {
1341 if (linux_os->threads_lookup == 1) {
1342 ct = linux_os->current_threads;
1343
1344 while ((ct) && (ct->core_id) != target->coreid)
1345 ct = ct->next;
1346
1347 if ((ct) && (ct->threadid == -1)) {
1348 ct = linux_os->current_threads;
1349
1350 while ((ct) && (ct->threadid == -1))
1351 ct = ct->next;
1352 }
1353
1354 if ((ct) && (ct->threadid !=
1355 target->rtos->current_threadid)
1356 && (target->rtos->current_threadid != -1))
1357 LOG_WARNING("WARNING! current GDB thread do not match "
1358 "current thread running. "
1359 "Switch thread in GDB to threadid %d",
1360 (int)ct->threadid);
1361
1362 LOG_INFO("threads_needs_update = 1");
1363 linux_os->threads_needs_update = 1;
1364 }
1365 }
1366
1367 /* if a packet handler returned an error, exit input loop */
1368 if (retval != ERROR_OK)
1369 return retval;
1370 }
1371
1372 return retval;
1373 }
1374
1375 static int linux_os_smp_init(struct target *target)
1376 {
1377 struct target_list *head;
1378 /* keep only target->rtos */
1379 struct rtos *rtos = target->rtos;
1380 struct linux_os *os_linux =
1381 (struct linux_os *)rtos->rtos_specific_params;
1382 struct current_thread *ct;
1383
1384 foreach_smp_target(head, target->smp_targets) {
1385 if (head->target->rtos != rtos) {
1386 struct linux_os *smp_os_linux =
1387 (struct linux_os *)head->target->rtos->rtos_specific_params;
1388 /* remap smp target on rtos */
1389 free(head->target->rtos);
1390 head->target->rtos = rtos;
1391 /* reuse allocated ct */
1392 ct = smp_os_linux->current_threads;
1393 ct->threadid = -1;
1394 ct->TS = 0xdeadbeef;
1395 ct->core_id = head->target->coreid;
1396 os_linux->current_threads =
1397 add_current_thread(os_linux->current_threads, ct);
1398 os_linux->nr_cpus++;
1399 free(smp_os_linux);
1400 }
1401 }
1402
1403 return ERROR_OK;
1404 }
1405
1406 static int linux_os_create(struct target *target)
1407 {
1408 struct linux_os *os_linux = calloc(1, sizeof(struct linux_os));
1409 struct current_thread *ct = calloc(1, sizeof(struct current_thread));
1410 LOG_INFO("linux os creation\n");
1411 os_linux->init_task_addr = 0xdeadbeef;
1412 os_linux->name = "linux";
1413 os_linux->thread_list = NULL;
1414 os_linux->thread_count = 0;
1415 target->rtos->current_threadid = -1;
1416 os_linux->nr_cpus = 1;
1417 os_linux->threads_lookup = 0;
1418 os_linux->threads_needs_update = 0;
1419 os_linux->threadid_count = 1;
1420 os_linux->current_threads = NULL;
1421 target->rtos->rtos_specific_params = os_linux;
1422 ct->core_id = target->coreid;
1423 ct->threadid = -1;
1424 ct->TS = 0xdeadbeef;
1425 os_linux->current_threads =
1426 add_current_thread(os_linux->current_threads, ct);
1427 /* overload rtos thread default handler */
1428 target->rtos->gdb_thread_packet = linux_thread_packet;
1429 /* initialize a default virt 2 phys translation */
1430 os_linux->phys_mask = ~0xc0000000;
1431 os_linux->phys_base = 0x0;
1432 return JIM_OK;
1433 }
1434
1435 static char *linux_ps_command(struct target *target)
1436 {
1437 struct linux_os *linux_os = (struct linux_os *)
1438 target->rtos->rtos_specific_params;
1439 int retval = ERROR_OK;
1440 char *display;
1441
1442 if (linux_os->threads_lookup == 0)
1443 retval = linux_get_tasks(target, 1);
1444 else {
1445 if (linux_os->threads_needs_update != 0)
1446 retval = linux_task_update(target, 0);
1447 }
1448
1449 if (retval == ERROR_OK) {
1450 struct threads *temp = linux_os->thread_list;
1451 char *tmp;
1452 LOG_INFO("allocation for %d threads line",
1453 linux_os->thread_count);
1454 display = calloc((linux_os->thread_count + 2) * 80, 1);
1455
1456 if (!display)
1457 goto error;
1458
1459 tmp = display;
1460 tmp += sprintf(tmp, "PID\t\tCPU\t\tASID\t\tNAME\n");
1461 tmp += sprintf(tmp, "---\t\t---\t\t----\t\t----\n");
1462
1463 while (temp) {
1464 if (temp->status) {
1465 if (temp->context)
1466 tmp +=
1467 sprintf(tmp,
1468 "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n",
1469 temp->pid, temp->oncpu,
1470 temp->asid, temp->name);
1471 else
1472 tmp +=
1473 sprintf(tmp,
1474 "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n",
1475 temp->pid, temp->oncpu,
1476 temp->asid, temp->name);
1477 }
1478
1479 temp = temp->next;
1480 }
1481
1482 return display;
1483 }
1484
1485 error:
1486 display = calloc(40, 1);
1487 sprintf(display, "linux_ps_command failed\n");
1488 return display;
1489 }

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)