tcl/target/renesas_rz_five: Added RZ/Five
[openocd.git] / src / target / semihosting_common.c
1 /***************************************************************************
2 * Copyright (C) 2018 by Liviu Ionescu *
3 * <ilg@livius.net> *
4 * *
5 * Copyright (C) 2018 by Marvell Technology Group Ltd. *
6 * Written by Nicolas Pitre <nico@marvell.com> *
7 * *
8 * Copyright (C) 2010 by Spencer Oliver *
9 * spen@spen-soft.co.uk *
10 * *
11 * Copyright (C) 2016 by Square, Inc. *
12 * Steven Stallion <stallion@squareup.com> *
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
26 ***************************************************************************/
27
28 /**
29 * @file
30 * Common ARM semihosting support.
31 *
32 * Semihosting enables code running on a target to use some of the I/O
33 * facilities on the host computer. The target application must be linked
34 * against a library that forwards operation requests by using an
35 * instruction trapped by the debugger.
36 *
37 * Details can be found in
38 * "Semihosting for AArch32 and AArch64, Release 2.0"
39 * https://static.docs.arm.com/100863/0200/semihosting.pdf
40 * from ARM Ltd.
41 */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include "target.h"
48 #include "target_type.h"
49 #include "semihosting_common.h"
50
51 #include <helper/binarybuffer.h>
52 #include <helper/log.h>
53 #include <sys/stat.h>
54
55 /**
56 * It is not possible to use O_... flags defined in sys/stat.h because they
57 * are not guaranteed to match the values defined by the GDB Remote Protocol.
58 * See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags
59 */
60 enum {
61 TARGET_O_RDONLY = 0x000,
62 TARGET_O_WRONLY = 0x001,
63 TARGET_O_RDWR = 0x002,
64 TARGET_O_APPEND = 0x008,
65 TARGET_O_CREAT = 0x200,
66 TARGET_O_TRUNC = 0x400,
67 /* O_EXCL=0x800 is not required in this implementation. */
68 };
69
70 /* GDB remote protocol does not differentiate between text and binary open modes. */
71 static const int open_gdb_modeflags[12] = {
72 TARGET_O_RDONLY,
73 TARGET_O_RDONLY,
74 TARGET_O_RDWR,
75 TARGET_O_RDWR,
76 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,
77 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,
78 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,
79 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,
80 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,
81 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,
82 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND,
83 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND
84 };
85
86 static const int open_host_modeflags[12] = {
87 O_RDONLY,
88 O_RDONLY | O_BINARY,
89 O_RDWR,
90 O_RDWR | O_BINARY,
91 O_WRONLY | O_CREAT | O_TRUNC,
92 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
93 O_RDWR | O_CREAT | O_TRUNC,
94 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
95 O_WRONLY | O_CREAT | O_APPEND,
96 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
97 O_RDWR | O_CREAT | O_APPEND,
98 O_RDWR | O_CREAT | O_APPEND | O_BINARY
99 };
100
101 static int semihosting_common_fileio_info(struct target *target,
102 struct gdb_fileio_info *fileio_info);
103 static int semihosting_common_fileio_end(struct target *target, int result,
104 int fileio_errno, bool ctrl_c);
105
106 static int semihosting_read_fields(struct target *target, size_t number,
107 uint8_t *fields);
108 static int semihosting_write_fields(struct target *target, size_t number,
109 uint8_t *fields);
110 static uint64_t semihosting_get_field(struct target *target, size_t index,
111 uint8_t *fields);
112 static void semihosting_set_field(struct target *target, uint64_t value,
113 size_t index,
114 uint8_t *fields);
115
116 /* Attempts to include gdb_server.h failed. */
117 extern int gdb_actual_connections;
118
119 /**
120 * Initialize common semihosting support.
121 *
122 * @param target Pointer to the target to initialize.
123 * @param setup
124 * @param post_result
125 * @return An error status if there is a problem during initialization.
126 */
127 int semihosting_common_init(struct target *target, void *setup,
128 void *post_result)
129 {
130 LOG_DEBUG(" ");
131
132 target->fileio_info = malloc(sizeof(*target->fileio_info));
133 if (!target->fileio_info) {
134 LOG_ERROR("out of memory");
135 return ERROR_FAIL;
136 }
137 memset(target->fileio_info, 0, sizeof(*target->fileio_info));
138
139 struct semihosting *semihosting;
140 semihosting = malloc(sizeof(*target->semihosting));
141 if (!semihosting) {
142 LOG_ERROR("out of memory");
143 return ERROR_FAIL;
144 }
145
146 semihosting->is_active = false;
147 semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE;
148 semihosting->tcp_connection = NULL;
149 semihosting->stdin_fd = -1;
150 semihosting->stdout_fd = -1;
151 semihosting->stderr_fd = -1;
152 semihosting->is_fileio = false;
153 semihosting->hit_fileio = false;
154 semihosting->is_resumable = false;
155 semihosting->has_resumable_exit = false;
156 semihosting->word_size_bytes = 0;
157 semihosting->op = -1;
158 semihosting->param = 0;
159 semihosting->result = -1;
160 semihosting->sys_errno = -1;
161 semihosting->cmdline = NULL;
162
163 /* If possible, update it in setup(). */
164 semihosting->setup_time = clock();
165
166 semihosting->setup = setup;
167 semihosting->post_result = post_result;
168
169 target->semihosting = semihosting;
170
171 target->type->get_gdb_fileio_info = semihosting_common_fileio_info;
172 target->type->gdb_fileio_end = semihosting_common_fileio_end;
173
174 return ERROR_OK;
175 }
176
177 struct semihosting_tcp_service {
178 struct semihosting *semihosting;
179 char *name;
180 int error;
181 };
182
183 static bool semihosting_is_redirected(struct semihosting *semihosting, int fd)
184 {
185 if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_NONE)
186 return false;
187
188 bool is_read_op = false;
189
190 switch (semihosting->op) {
191 /* check debug semihosting operations: READC, WRITEC and WRITE0 */
192 case SEMIHOSTING_SYS_READC:
193 is_read_op = true;
194 /* fall through */
195 case SEMIHOSTING_SYS_WRITEC:
196 case SEMIHOSTING_SYS_WRITE0:
197 /* debug operations are redirected when CFG is either DEBUG or ALL */
198 if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_STDIO)
199 return false;
200 break;
201
202 /* check stdio semihosting operations: READ and WRITE */
203 case SEMIHOSTING_SYS_READ:
204 is_read_op = true;
205 /* fall through */
206 case SEMIHOSTING_SYS_WRITE:
207 /* stdio operations are redirected when CFG is either STDIO or ALL */
208 if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_DEBUG)
209 return false;
210 break;
211
212 default:
213 return false;
214 }
215
216 if (is_read_op)
217 return fd == semihosting->stdin_fd;
218
219 /* write operation */
220 return fd == semihosting->stdout_fd || fd == semihosting->stderr_fd;
221 }
222
223 static ssize_t semihosting_redirect_write(struct semihosting *semihosting, void *buf, int size)
224 {
225 if (!semihosting->tcp_connection) {
226 LOG_ERROR("No connected TCP client for semihosting");
227 semihosting->sys_errno = EBADF; /* Bad file number */
228 return -1;
229 }
230
231 struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv;
232
233 int retval = connection_write(semihosting->tcp_connection, buf, size);
234
235 if (retval < 0)
236 log_socket_error(service->name);
237
238 return retval;
239 }
240
241 static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *buf, int size)
242 {
243 if (semihosting_is_redirected(semihosting, fd))
244 return semihosting_redirect_write(semihosting, buf, size);
245
246 /* default write */
247 return write(fd, buf, size);
248 }
249
250 static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size)
251 {
252 if (!semihosting->tcp_connection) {
253 LOG_ERROR("No connected TCP client for semihosting");
254 semihosting->sys_errno = EBADF; /* Bad file number */
255 return -1;
256 }
257
258 struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv;
259
260 service->error = ERROR_OK;
261 semihosting->tcp_connection->input_pending = true;
262
263 int retval = connection_read(semihosting->tcp_connection, buf, size);
264
265 if (retval <= 0)
266 service->error = ERROR_SERVER_REMOTE_CLOSED;
267
268 if (retval < 0)
269 log_socket_error(service->name);
270
271 semihosting->tcp_connection->input_pending = false;
272
273 return retval;
274 }
275
276 static inline int semihosting_putchar(struct semihosting *semihosting, int fd, int c)
277 {
278 if (semihosting_is_redirected(semihosting, fd))
279 return semihosting_redirect_write(semihosting, &c, 1);
280
281 /* default putchar */
282 return putchar(c);
283 }
284
285 static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, void *buf, int size)
286 {
287 if (semihosting_is_redirected(semihosting, fd))
288 return semihosting_redirect_read(semihosting, buf, size);
289
290 /* default read */
291 ssize_t result = read(fd, buf, size);
292 semihosting->sys_errno = errno;
293
294 return result;
295 }
296
297 static inline int semihosting_getchar(struct semihosting *semihosting, int fd)
298 {
299 if (semihosting_is_redirected(semihosting, fd)) {
300 unsigned char c;
301
302 if (semihosting_redirect_read(semihosting, &c, 1) > 0)
303 return c;
304
305 return EOF;
306 }
307
308 /* default getchar */
309 return getchar();
310 }
311
312 /**
313 * User operation parameter string storage buffer. Contains valid data when the
314 * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running.
315 */
316 static char *semihosting_user_op_params;
317
318 /**
319 * Portable implementation of ARM semihosting calls.
320 * Performs the currently pending semihosting operation
321 * encoded in target->semihosting.
322 */
323 int semihosting_common(struct target *target)
324 {
325 struct semihosting *semihosting = target->semihosting;
326 if (!semihosting) {
327 /* Silently ignore if the semihosting field was not set. */
328 return ERROR_OK;
329 }
330
331 struct gdb_fileio_info *fileio_info = target->fileio_info;
332
333 /*
334 * By default return an error.
335 * The actual result must be set by each function
336 */
337 semihosting->result = -1;
338
339 /* Most operations are resumable, except the two exit calls. */
340 semihosting->is_resumable = true;
341
342 int retval;
343
344 /* Enough space to hold 4 long words. */
345 uint8_t fields[4*8];
346
347 LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op,
348 semihosting->param);
349
350 switch (semihosting->op) {
351
352 case SEMIHOSTING_SYS_CLOCK: /* 0x10 */
353 /*
354 * Returns the number of centiseconds (hundredths of a second)
355 * since the execution started.
356 *
357 * Values returned can be of limited use for some benchmarking
358 * purposes because of communication overhead or other
359 * agent-specific factors. For example, with a debug hardware
360 * unit the request is passed back to the host for execution.
361 * This can lead to unpredictable delays in transmission and
362 * process scheduling.
363 *
364 * Use this function to calculate time intervals, by calculating
365 * differences between intervals with and without the code
366 * sequence to be timed.
367 *
368 * Entry
369 * The PARAMETER REGISTER must contain 0. There are no other
370 * parameters.
371 *
372 * Return
373 * On exit, the RETURN REGISTER contains:
374 * - The number of centiseconds since some arbitrary start
375 * point, if the call is successful.
376 * - –1 if the call is not successful. For example, because
377 * of a communications error.
378 */
379 {
380 clock_t delta = clock() - semihosting->setup_time;
381
382 semihosting->result = delta / (CLOCKS_PER_SEC / 100);
383 }
384 break;
385
386 case SEMIHOSTING_SYS_CLOSE: /* 0x02 */
387 /*
388 * Closes a file on the host system. The handle must reference
389 * a file that was opened with SYS_OPEN.
390 *
391 * Entry
392 * On entry, the PARAMETER REGISTER contains a pointer to a
393 * one-field argument block:
394 * - field 1 Contains a handle for an open file.
395 *
396 * Return
397 * On exit, the RETURN REGISTER contains:
398 * - 0 if the call is successful
399 * - –1 if the call is not successful.
400 */
401 retval = semihosting_read_fields(target, 1, fields);
402 if (retval != ERROR_OK)
403 return retval;
404 else {
405 int fd = semihosting_get_field(target, 0, fields);
406 /* Do not allow to close OpenOCD's own standard streams */
407 if (fd == 0 || fd == 1 || fd == 2) {
408 LOG_DEBUG("ignoring semihosting attempt to close %s",
409 (fd == 0) ? "stdin" :
410 (fd == 1) ? "stdout" : "stderr");
411 /* Just pretend success */
412 if (semihosting->is_fileio) {
413 semihosting->result = 0;
414 } else {
415 semihosting->result = 0;
416 semihosting->sys_errno = 0;
417 }
418 break;
419 }
420 /* Close the descriptor */
421 if (semihosting->is_fileio) {
422 semihosting->hit_fileio = true;
423 fileio_info->identifier = "close";
424 fileio_info->param_1 = fd;
425 } else {
426 semihosting->result = close(fd);
427 semihosting->sys_errno = errno;
428 LOG_DEBUG("close(%d)=%d", fd, (int)semihosting->result);
429 }
430 }
431 break;
432
433 case SEMIHOSTING_SYS_ERRNO: /* 0x13 */
434 /*
435 * Returns the value of the C library errno variable that is
436 * associated with the semihosting implementation. The errno
437 * variable can be set by a number of C library semihosted
438 * functions, including:
439 * - SYS_REMOVE
440 * - SYS_OPEN
441 * - SYS_CLOSE
442 * - SYS_READ
443 * - SYS_WRITE
444 * - SYS_SEEK.
445 *
446 * Whether errno is set or not, and to what value, is entirely
447 * host-specific, except where the ISO C standard defines the
448 * behavior.
449 *
450 * Entry
451 * There are no parameters. The PARAMETER REGISTER must be 0.
452 *
453 * Return
454 * On exit, the RETURN REGISTER contains the value of the C
455 * library errno variable.
456 */
457 semihosting->result = semihosting->sys_errno;
458 break;
459
460 case SEMIHOSTING_SYS_EXIT: /* 0x18 */
461 /*
462 * Note: SYS_EXIT was called angel_SWIreason_ReportException in
463 * previous versions of the documentation.
464 *
465 * An application calls this operation to report an exception
466 * to the debugger directly. The most common use is to report
467 * that execution has completed, using ADP_Stopped_ApplicationExit.
468 *
469 * Note: This semihosting operation provides no means for 32-bit
470 * callers to indicate an application exit with a specified exit
471 * code. Semihosting callers may prefer to check for the presence
472 * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use
473 * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it
474 * is available.
475 *
476 * Entry (32-bit)
477 * On entry, the PARAMETER register is set to a reason code
478 * describing the cause of the trap. Not all semihosting client
479 * implementations will necessarily trap every corresponding
480 * event. Important reason codes are:
481 *
482 * - ADP_Stopped_ApplicationExit 0x20026
483 * - ADP_Stopped_RunTimeErrorUnknown 0x20023
484 *
485 * Entry (64-bit)
486 * On entry, the PARAMETER REGISTER contains a pointer to a
487 * two-field argument block:
488 * - field 1 The exception type, which is one of the set of
489 * reason codes in the above tables.
490 * - field 2 A subcode, whose meaning depends on the reason
491 * code in field 1.
492 * In particular, if field 1 is ADP_Stopped_ApplicationExit
493 * then field 2 is an exit status code, as passed to the C
494 * standard library exit() function. A simulator receiving
495 * this request must notify a connected debugger, if present,
496 * and then exit with the specified status.
497 *
498 * Return
499 * No return is expected from these calls. However, it is
500 * possible for the debugger to request that the application
501 * continues by performing an RDI_Execute request or equivalent.
502 * In this case, execution continues with the registers as they
503 * were on entry to the operation, or as subsequently modified
504 * by the debugger.
505 */
506 if (semihosting->word_size_bytes == 8) {
507 retval = semihosting_read_fields(target, 2, fields);
508 if (retval != ERROR_OK)
509 return retval;
510 else {
511 int type = semihosting_get_field(target, 0, fields);
512 int code = semihosting_get_field(target, 1, fields);
513
514 if (type == ADP_STOPPED_APPLICATION_EXIT) {
515 if (!gdb_actual_connections)
516 exit(code);
517 else {
518 fprintf(stderr,
519 "semihosting: *** application exited with %d ***\n",
520 code);
521 }
522 } else {
523 fprintf(stderr,
524 "semihosting: application exception %#x\n",
525 type);
526 }
527 }
528 } else {
529 if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) {
530 if (!gdb_actual_connections)
531 exit(0);
532 else {
533 fprintf(stderr,
534 "semihosting: *** application exited normally ***\n");
535 }
536 } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) {
537 /* Chosen more or less arbitrarily to have a nicer message,
538 * otherwise all other return the same exit code 1. */
539 if (!gdb_actual_connections)
540 exit(1);
541 else {
542 fprintf(stderr,
543 "semihosting: *** application exited with error ***\n");
544 }
545 } else {
546 if (!gdb_actual_connections)
547 exit(1);
548 else {
549 fprintf(stderr,
550 "semihosting: application exception %#x\n",
551 (unsigned) semihosting->param);
552 }
553 }
554 }
555 if (!semihosting->has_resumable_exit) {
556 semihosting->is_resumable = false;
557 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
558 }
559 break;
560
561 case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */
562 /*
563 * This operation is only supported if the semihosting extension
564 * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is
565 * reported using feature byte 0, bit 0. If this extension is
566 * supported, then the implementation provides a means to
567 * report a normal exit with a nonzero exit status in both 32-bit
568 * and 64-bit semihosting APIs.
569 *
570 * The implementation must provide the semihosting call
571 * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs.
572 *
573 * SYS_EXIT_EXTENDED is used by an application to report an
574 * exception or exit to the debugger directly. The most common
575 * use is to report that execution has completed, using
576 * ADP_Stopped_ApplicationExit.
577 *
578 * Entry
579 * On entry, the PARAMETER REGISTER contains a pointer to a
580 * two-field argument block:
581 * - field 1 The exception type, which should be one of the set
582 * of reason codes that are documented for the SYS_EXIT
583 * (0x18) call. For example, ADP_Stopped_ApplicationExit.
584 * - field 2 A subcode, whose meaning depends on the reason
585 * code in field 1. In particular, if field 1 is
586 * ADP_Stopped_ApplicationExit then field 2 is an exit status
587 * code, as passed to the C standard library exit() function.
588 * A simulator receiving this request must notify a connected
589 * debugger, if present, and then exit with the specified status.
590 *
591 * Return
592 * No return is expected from these calls.
593 *
594 * For the A64 API, this call is identical to the behavior of
595 * the mandatory SYS_EXIT (0x18) call. If this extension is
596 * supported, then both calls must be implemented.
597 */
598 retval = semihosting_read_fields(target, 2, fields);
599 if (retval != ERROR_OK)
600 return retval;
601 else {
602 int type = semihosting_get_field(target, 0, fields);
603 int code = semihosting_get_field(target, 1, fields);
604
605 if (type == ADP_STOPPED_APPLICATION_EXIT) {
606 if (!gdb_actual_connections)
607 exit(code);
608 else {
609 fprintf(stderr,
610 "semihosting: *** application exited with %d ***\n",
611 code);
612 }
613 } else {
614 fprintf(stderr, "semihosting: exception %#x\n",
615 type);
616 }
617 }
618 if (!semihosting->has_resumable_exit) {
619 semihosting->is_resumable = false;
620 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
621 }
622 break;
623
624 case SEMIHOSTING_SYS_FLEN: /* 0x0C */
625 /*
626 * Returns the length of a specified file.
627 *
628 * Entry
629 * On entry, the PARAMETER REGISTER contains a pointer to a
630 * one-field argument block:
631 * - field 1 A handle for a previously opened, seekable file
632 * object.
633 *
634 * Return
635 * On exit, the RETURN REGISTER contains:
636 * - The current length of the file object, if the call is
637 * successful.
638 * - –1 if an error occurs.
639 */
640 if (semihosting->is_fileio) {
641 semihosting->result = -1;
642 semihosting->sys_errno = EINVAL;
643 }
644 retval = semihosting_read_fields(target, 1, fields);
645 if (retval != ERROR_OK)
646 return retval;
647 else {
648 int fd = semihosting_get_field(target, 0, fields);
649 struct stat buf;
650 semihosting->result = fstat(fd, &buf);
651 if (semihosting->result == -1) {
652 semihosting->sys_errno = errno;
653 LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
654 break;
655 }
656 LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
657 semihosting->result = buf.st_size;
658 }
659 break;
660
661 case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */
662 /*
663 * Returns the command line that is used for the call to the
664 * executable, that is, argc and argv.
665 *
666 * Entry
667 * On entry, the PARAMETER REGISTER points to a two-field data
668 * block to be used for returning the command string and its length:
669 * - field 1 A pointer to a buffer of at least the size that is
670 * specified in field 2.
671 * - field 2 The length of the buffer in bytes.
672 *
673 * Return
674 * On exit:
675 * If the call is successful, then the RETURN REGISTER contains 0,
676 * the PARAMETER REGISTER is unchanged, and the data block is
677 * updated as follows:
678 * - field 1 A pointer to a null-terminated string of the command
679 * line.
680 * - field 2 The length of the string in bytes.
681 * If the call is not successful, then the RETURN REGISTER
682 * contains -1.
683 *
684 * Note: The semihosting implementation might impose limits on
685 * the maximum length of the string that can be transferred.
686 * However, the implementation must be able to support a
687 * command-line length of at least 80 bytes.
688 */
689 retval = semihosting_read_fields(target, 2, fields);
690 if (retval != ERROR_OK)
691 return retval;
692 else {
693 uint64_t addr = semihosting_get_field(target, 0, fields);
694 size_t size = semihosting_get_field(target, 1, fields);
695
696 char *arg = semihosting->cmdline ?
697 semihosting->cmdline : "";
698 uint32_t len = strlen(arg) + 1;
699 if (len > size)
700 semihosting->result = -1;
701 else {
702 semihosting_set_field(target, len, 1, fields);
703 retval = target_write_buffer(target, addr, len,
704 (uint8_t *)arg);
705 if (retval != ERROR_OK)
706 return retval;
707 semihosting->result = 0;
708
709 retval = semihosting_write_fields(target, 2, fields);
710 if (retval != ERROR_OK)
711 return retval;
712 }
713 LOG_DEBUG("SYS_GET_CMDLINE=[%s],%d", arg,
714 (int)semihosting->result);
715 }
716 break;
717
718 case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */
719 /*
720 * Returns the system stack and heap parameters.
721 *
722 * Entry
723 * On entry, the PARAMETER REGISTER contains the address of a
724 * pointer to a four-field data block. The contents of the data
725 * block are filled by the function. The following C-like
726 * pseudocode describes the layout of the block:
727 * struct block {
728 * void* heap_base;
729 * void* heap_limit;
730 * void* stack_base;
731 * void* stack_limit;
732 * };
733 *
734 * Return
735 * On exit, the PARAMETER REGISTER is unchanged and the data
736 * block has been updated.
737 */
738 retval = semihosting_read_fields(target, 1, fields);
739 if (retval != ERROR_OK)
740 return retval;
741 else {
742 uint64_t addr = semihosting_get_field(target, 0, fields);
743 /* tell the remote we have no idea */
744 memset(fields, 0, 4 * semihosting->word_size_bytes);
745 retval = target_write_memory(target, addr, 4,
746 semihosting->word_size_bytes,
747 fields);
748 if (retval != ERROR_OK)
749 return retval;
750 semihosting->result = 0;
751 }
752 break;
753
754 case SEMIHOSTING_SYS_ISERROR: /* 0x08 */
755 /*
756 * Determines whether the return code from another semihosting
757 * call is an error status or not.
758 *
759 * This call is passed a parameter block containing the error
760 * code to examine.
761 *
762 * Entry
763 * On entry, the PARAMETER REGISTER contains a pointer to a
764 * one-field data block:
765 * - field 1 The required status word to check.
766 *
767 * Return
768 * On exit, the RETURN REGISTER contains:
769 * - 0 if the status field is not an error indication
770 * - A nonzero value if the status field is an error indication.
771 */
772 retval = semihosting_read_fields(target, 1, fields);
773 if (retval != ERROR_OK)
774 return retval;
775
776 uint64_t code = semihosting_get_field(target, 0, fields);
777 semihosting->result = (code != 0);
778 break;
779
780 case SEMIHOSTING_SYS_ISTTY: /* 0x09 */
781 /*
782 * Checks whether a file is connected to an interactive device.
783 *
784 * Entry
785 * On entry, the PARAMETER REGISTER contains a pointer to a
786 * one-field argument block:
787 * field 1 A handle for a previously opened file object.
788 *
789 * Return
790 * On exit, the RETURN REGISTER contains:
791 * - 1 if the handle identifies an interactive device.
792 * - 0 if the handle identifies a file.
793 * - A value other than 1 or 0 if an error occurs.
794 */
795 if (semihosting->is_fileio) {
796 semihosting->hit_fileio = true;
797 fileio_info->identifier = "isatty";
798 fileio_info->param_1 = semihosting->param;
799 } else {
800 retval = semihosting_read_fields(target, 1, fields);
801 if (retval != ERROR_OK)
802 return retval;
803 int fd = semihosting_get_field(target, 0, fields);
804 semihosting->result = isatty(fd);
805 semihosting->sys_errno = errno;
806 LOG_DEBUG("isatty(%d)=%d", fd, (int)semihosting->result);
807 }
808 break;
809
810 case SEMIHOSTING_SYS_OPEN: /* 0x01 */
811 /*
812 * Opens a file on the host system.
813 *
814 * The file path is specified either as relative to the current
815 * directory of the host process, or absolute, using the path
816 * conventions of the host operating system.
817 *
818 * Semihosting implementations must support opening the special
819 * path name :semihosting-features as part of the semihosting
820 * extensions reporting mechanism.
821 *
822 * ARM targets interpret the special path name :tt as meaning
823 * the console input stream, for an open-read or the console
824 * output stream, for an open-write. Opening these streams is
825 * performed as part of the standard startup code for those
826 * applications that reference the C stdio streams. The
827 * semihosting extension SH_EXT_STDOUT_STDERR allows the
828 * semihosting caller to open separate output streams
829 * corresponding to stdout and stderr. This extension is
830 * reported using feature byte 0, bit 1. Use SYS_OPEN with
831 * the special path name :semihosting-features to access the
832 * feature bits.
833 *
834 * If this extension is supported, the implementation must
835 * support the following additional semantics to SYS_OPEN:
836 * - If the special path name :tt is opened with an fopen
837 * mode requesting write access (w, wb, w+, or w+b), then
838 * this is a request to open stdout.
839 * - If the special path name :tt is opened with a mode
840 * requesting append access (a, ab, a+, or a+b), then this is
841 * a request to open stderr.
842 *
843 * Entry
844 * On entry, the PARAMETER REGISTER contains a pointer to a
845 * three-field argument block:
846 * - field 1 A pointer to a null-terminated string containing
847 * a file or device name.
848 * - field 2 An integer that specifies the file opening mode.
849 * - field 3 An integer that gives the length of the string
850 * pointed to by field 1.
851 *
852 * The length does not include the terminating null character
853 * that must be present.
854 *
855 * Return
856 * On exit, the RETURN REGISTER contains:
857 * - A nonzero handle if the call is successful.
858 * - –1 if the call is not successful.
859 */
860 retval = semihosting_read_fields(target, 3, fields);
861 if (retval != ERROR_OK)
862 return retval;
863 else {
864 uint64_t addr = semihosting_get_field(target, 0, fields);
865 uint32_t mode = semihosting_get_field(target, 1, fields);
866 size_t len = semihosting_get_field(target, 2, fields);
867
868 if (mode > 11) {
869 semihosting->result = -1;
870 semihosting->sys_errno = EINVAL;
871 break;
872 }
873 uint8_t *fn = malloc(len+1);
874 if (!fn) {
875 semihosting->result = -1;
876 semihosting->sys_errno = ENOMEM;
877 } else {
878 retval = target_read_memory(target, addr, 1, len, fn);
879 if (retval != ERROR_OK) {
880 free(fn);
881 return retval;
882 }
883 fn[len] = 0;
884 /* TODO: implement the :semihosting-features special file.
885 * */
886 if (semihosting->is_fileio) {
887 if (strcmp((char *)fn, ":semihosting-features") == 0) {
888 semihosting->result = -1;
889 semihosting->sys_errno = EINVAL;
890 } else if (strcmp((char *)fn, ":tt") == 0) {
891 if (mode == 0)
892 semihosting->result = 0;
893 else if (mode == 4)
894 semihosting->result = 1;
895 else if (mode == 8)
896 semihosting->result = 2;
897 else
898 semihosting->result = -1;
899 } else {
900 semihosting->hit_fileio = true;
901 fileio_info->identifier = "open";
902 fileio_info->param_1 = addr;
903 fileio_info->param_2 = len;
904 fileio_info->param_3 = open_gdb_modeflags[mode];
905 fileio_info->param_4 = 0644;
906 }
907 } else {
908 if (strcmp((char *)fn, ":tt") == 0) {
909 /* Mode is:
910 * - 0-3 ("r") for stdin,
911 * - 4-7 ("w") for stdout,
912 * - 8-11 ("a") for stderr */
913 if (mode < 4) {
914 int fd = dup(STDIN_FILENO);
915 semihosting->result = fd;
916 semihosting->stdin_fd = fd;
917 semihosting->sys_errno = errno;
918 LOG_DEBUG("dup(STDIN)=%d",
919 (int)semihosting->result);
920 } else if (mode < 8) {
921 int fd = dup(STDOUT_FILENO);
922 semihosting->result = fd;
923 semihosting->stdout_fd = fd;
924 semihosting->sys_errno = errno;
925 LOG_DEBUG("dup(STDOUT)=%d",
926 (int)semihosting->result);
927 } else {
928 int fd = dup(STDERR_FILENO);
929 semihosting->result = fd;
930 semihosting->stderr_fd = fd;
931 semihosting->sys_errno = errno;
932 LOG_DEBUG("dup(STDERR)=%d",
933 (int)semihosting->result);
934 }
935 } else {
936 /* cygwin requires the permission setting
937 * otherwise it will fail to reopen a previously
938 * written file */
939 semihosting->result = open((char *)fn,
940 open_host_modeflags[mode],
941 0644);
942 semihosting->sys_errno = errno;
943 LOG_DEBUG("open('%s')=%d", fn,
944 (int)semihosting->result);
945 }
946 }
947 free(fn);
948 }
949 }
950 break;
951
952 case SEMIHOSTING_SYS_READ: /* 0x06 */
953 /*
954 * Reads the contents of a file into a buffer. The file position
955 * is specified either:
956 * - Explicitly by a SYS_SEEK.
957 * - Implicitly one byte beyond the previous SYS_READ or
958 * SYS_WRITE request.
959 *
960 * The file position is at the start of the file when it is
961 * opened, and is lost when the file is closed. Perform the
962 * file operation as a single action whenever possible. For
963 * example, do not split a read of 16KB into four 4KB chunks
964 * unless there is no alternative.
965 *
966 * Entry
967 * On entry, the PARAMETER REGISTER contains a pointer to a
968 * three-field data block:
969 * - field 1 Contains a handle for a file previously opened
970 * with SYS_OPEN.
971 * - field 2 Points to a buffer.
972 * - field 3 Contains the number of bytes to read to the buffer
973 * from the file.
974 *
975 * Return
976 * On exit, the RETURN REGISTER contains the number of bytes not
977 * filled in the buffer (buffer_length - bytes_read) as follows:
978 * - If the RETURN REGISTER is 0, the entire buffer was
979 * successfully filled.
980 * - If the RETURN REGISTER is the same as field 3, no bytes
981 * were read (EOF can be assumed).
982 * - If the RETURN REGISTER contains a value smaller than
983 * field 3, the read succeeded but the buffer was only partly
984 * filled. For interactive devices, this is the most common
985 * return value.
986 */
987 retval = semihosting_read_fields(target, 3, fields);
988 if (retval != ERROR_OK)
989 return retval;
990 else {
991 int fd = semihosting_get_field(target, 0, fields);
992 uint64_t addr = semihosting_get_field(target, 1, fields);
993 size_t len = semihosting_get_field(target, 2, fields);
994 if (semihosting->is_fileio) {
995 semihosting->hit_fileio = true;
996 fileio_info->identifier = "read";
997 fileio_info->param_1 = fd;
998 fileio_info->param_2 = addr;
999 fileio_info->param_3 = len;
1000 } else {
1001 uint8_t *buf = malloc(len);
1002 if (!buf) {
1003 semihosting->result = -1;
1004 semihosting->sys_errno = ENOMEM;
1005 } else {
1006 semihosting->result = semihosting_read(semihosting, fd, buf, len);
1007 LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d",
1008 fd,
1009 addr,
1010 len,
1011 (int)semihosting->result);
1012 if (semihosting->result >= 0) {
1013 retval = target_write_buffer(target, addr,
1014 semihosting->result,
1015 buf);
1016 if (retval != ERROR_OK) {
1017 free(buf);
1018 return retval;
1019 }
1020 /* the number of bytes NOT filled in */
1021 semihosting->result = len -
1022 semihosting->result;
1023 }
1024 free(buf);
1025 }
1026 }
1027 }
1028 break;
1029
1030 case SEMIHOSTING_SYS_READC: /* 0x07 */
1031 /*
1032 * Reads a byte from the console.
1033 *
1034 * Entry
1035 * The PARAMETER REGISTER must contain 0. There are no other
1036 * parameters or values possible.
1037 *
1038 * Return
1039 * On exit, the RETURN REGISTER contains the byte read from
1040 * the console.
1041 */
1042 if (semihosting->is_fileio) {
1043 LOG_ERROR("SYS_READC not supported by semihosting fileio");
1044 return ERROR_FAIL;
1045 }
1046 semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd);
1047 LOG_DEBUG("getchar()=%d", (int)semihosting->result);
1048 break;
1049
1050 case SEMIHOSTING_SYS_REMOVE: /* 0x0E */
1051 /*
1052 * Deletes a specified file on the host filing system.
1053 *
1054 * Entry
1055 * On entry, the PARAMETER REGISTER contains a pointer to a
1056 * two-field argument block:
1057 * - field 1 Points to a null-terminated string that gives the
1058 * path name of the file to be deleted.
1059 * - field 2 The length of the string.
1060 *
1061 * Return
1062 * On exit, the RETURN REGISTER contains:
1063 * - 0 if the delete is successful
1064 * - A nonzero, host-specific error code if the delete fails.
1065 */
1066 retval = semihosting_read_fields(target, 2, fields);
1067 if (retval != ERROR_OK)
1068 return retval;
1069 else {
1070 uint64_t addr = semihosting_get_field(target, 0, fields);
1071 size_t len = semihosting_get_field(target, 1, fields);
1072 if (semihosting->is_fileio) {
1073 semihosting->hit_fileio = true;
1074 fileio_info->identifier = "unlink";
1075 fileio_info->param_1 = addr;
1076 fileio_info->param_2 = len;
1077 } else {
1078 uint8_t *fn = malloc(len+1);
1079 if (!fn) {
1080 semihosting->result = -1;
1081 semihosting->sys_errno = ENOMEM;
1082 } else {
1083 retval =
1084 target_read_memory(target, addr, 1, len,
1085 fn);
1086 if (retval != ERROR_OK) {
1087 free(fn);
1088 return retval;
1089 }
1090 fn[len] = 0;
1091 semihosting->result = remove((char *)fn);
1092 semihosting->sys_errno = errno;
1093 LOG_DEBUG("remove('%s')=%d", fn,
1094 (int)semihosting->result);
1095
1096 free(fn);
1097 }
1098 }
1099 }
1100 break;
1101
1102 case SEMIHOSTING_SYS_RENAME: /* 0x0F */
1103 /*
1104 * Renames a specified file.
1105 *
1106 * Entry
1107 * On entry, the PARAMETER REGISTER contains a pointer to a
1108 * four-field data block:
1109 * - field 1 A pointer to the name of the old file.
1110 * - field 2 The length of the old filename.
1111 * - field 3 A pointer to the new filename.
1112 * - field 4 The length of the new filename. Both strings are
1113 * null-terminated.
1114 *
1115 * Return
1116 * On exit, the RETURN REGISTER contains:
1117 * - 0 if the rename is successful.
1118 * - A nonzero, host-specific error code if the rename fails.
1119 */
1120 retval = semihosting_read_fields(target, 4, fields);
1121 if (retval != ERROR_OK)
1122 return retval;
1123 else {
1124 uint64_t addr1 = semihosting_get_field(target, 0, fields);
1125 size_t len1 = semihosting_get_field(target, 1, fields);
1126 uint64_t addr2 = semihosting_get_field(target, 2, fields);
1127 size_t len2 = semihosting_get_field(target, 3, fields);
1128 if (semihosting->is_fileio) {
1129 semihosting->hit_fileio = true;
1130 fileio_info->identifier = "rename";
1131 fileio_info->param_1 = addr1;
1132 fileio_info->param_2 = len1;
1133 fileio_info->param_3 = addr2;
1134 fileio_info->param_4 = len2;
1135 } else {
1136 uint8_t *fn1 = malloc(len1+1);
1137 uint8_t *fn2 = malloc(len2+1);
1138 if (!fn1 || !fn2) {
1139 free(fn1);
1140 free(fn2);
1141 semihosting->result = -1;
1142 semihosting->sys_errno = ENOMEM;
1143 } else {
1144 retval = target_read_memory(target, addr1, 1, len1,
1145 fn1);
1146 if (retval != ERROR_OK) {
1147 free(fn1);
1148 free(fn2);
1149 return retval;
1150 }
1151 retval = target_read_memory(target, addr2, 1, len2,
1152 fn2);
1153 if (retval != ERROR_OK) {
1154 free(fn1);
1155 free(fn2);
1156 return retval;
1157 }
1158 fn1[len1] = 0;
1159 fn2[len2] = 0;
1160 semihosting->result = rename((char *)fn1,
1161 (char *)fn2);
1162 semihosting->sys_errno = errno;
1163 LOG_DEBUG("rename('%s', '%s')=%d", fn1, fn2,
1164 (int)semihosting->result);
1165
1166 free(fn1);
1167 free(fn2);
1168 }
1169 }
1170 }
1171 break;
1172
1173 case SEMIHOSTING_SYS_SEEK: /* 0x0A */
1174 /*
1175 * Seeks to a specified position in a file using an offset
1176 * specified from the start of the file. The file is assumed
1177 * to be a byte array and the offset is given in bytes.
1178 *
1179 * Entry
1180 * On entry, the PARAMETER REGISTER contains a pointer to a
1181 * two-field data block:
1182 * - field 1 A handle for a seekable file object.
1183 * - field 2 The absolute byte position to seek to.
1184 *
1185 * Return
1186 * On exit, the RETURN REGISTER contains:
1187 * - 0 if the request is successful.
1188 * - A negative value if the request is not successful.
1189 * Use SYS_ERRNO to read the value of the host errno variable
1190 * describing the error.
1191 *
1192 * Note: The effect of seeking outside the current extent of
1193 * the file object is undefined.
1194 */
1195 retval = semihosting_read_fields(target, 2, fields);
1196 if (retval != ERROR_OK)
1197 return retval;
1198 else {
1199 int fd = semihosting_get_field(target, 0, fields);
1200 off_t pos = semihosting_get_field(target, 1, fields);
1201 if (semihosting->is_fileio) {
1202 semihosting->hit_fileio = true;
1203 fileio_info->identifier = "lseek";
1204 fileio_info->param_1 = fd;
1205 fileio_info->param_2 = pos;
1206 fileio_info->param_3 = SEEK_SET;
1207 } else {
1208 semihosting->result = lseek(fd, pos, SEEK_SET);
1209 semihosting->sys_errno = errno;
1210 LOG_DEBUG("lseek(%d, %d)=%d", fd, (int)pos,
1211 (int)semihosting->result);
1212 if (semihosting->result == pos)
1213 semihosting->result = 0;
1214 }
1215 }
1216 break;
1217
1218 case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */
1219 /*
1220 * Passes a command to the host command-line interpreter.
1221 * This enables you to execute a system command such as dir,
1222 * ls, or pwd. The terminal I/O is on the host, and is not
1223 * visible to the target.
1224 *
1225 * Entry
1226 * On entry, the PARAMETER REGISTER contains a pointer to a
1227 * two-field argument block:
1228 * - field 1 Points to a string to be passed to the host
1229 * command-line interpreter.
1230 * - field 2 The length of the string.
1231 *
1232 * Return
1233 * On exit, the RETURN REGISTER contains the return status.
1234 */
1235
1236 /* Provide SYS_SYSTEM functionality. Uses the
1237 * libc system command, there may be a reason *NOT*
1238 * to use this, but as I can't think of one, I
1239 * implemented it this way.
1240 */
1241 retval = semihosting_read_fields(target, 2, fields);
1242 if (retval != ERROR_OK)
1243 return retval;
1244 else {
1245 uint64_t addr = semihosting_get_field(target, 0, fields);
1246 size_t len = semihosting_get_field(target, 1, fields);
1247 if (semihosting->is_fileio) {
1248 semihosting->hit_fileio = true;
1249 fileio_info->identifier = "system";
1250 fileio_info->param_1 = addr;
1251 fileio_info->param_2 = len;
1252 } else {
1253 uint8_t *cmd = malloc(len+1);
1254 if (!cmd) {
1255 semihosting->result = -1;
1256 semihosting->sys_errno = ENOMEM;
1257 } else {
1258 retval = target_read_memory(target,
1259 addr,
1260 1,
1261 len,
1262 cmd);
1263 if (retval != ERROR_OK) {
1264 free(cmd);
1265 return retval;
1266 } else {
1267 cmd[len] = 0;
1268 semihosting->result = system(
1269 (const char *)cmd);
1270 LOG_DEBUG("system('%s')=%d",
1271 cmd,
1272 (int)semihosting->result);
1273 }
1274
1275 free(cmd);
1276 }
1277 }
1278 }
1279 break;
1280
1281 case SEMIHOSTING_SYS_TIME: /* 0x11 */
1282 /*
1283 * Returns the number of seconds since 00:00 January 1, 1970.
1284 * This value is real-world time, regardless of any debug agent
1285 * configuration.
1286 *
1287 * Entry
1288 * There are no parameters.
1289 *
1290 * Return
1291 * On exit, the RETURN REGISTER contains the number of seconds.
1292 */
1293 semihosting->result = time(NULL);
1294 break;
1295
1296 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1297 /*
1298 * Writes the contents of a buffer to a specified file at the
1299 * current file position. The file position is specified either:
1300 * - Explicitly, by a SYS_SEEK.
1301 * - Implicitly as one byte beyond the previous SYS_READ or
1302 * SYS_WRITE request.
1303 *
1304 * The file position is at the start of the file when the file
1305 * is opened, and is lost when the file is closed.
1306 *
1307 * Perform the file operation as a single action whenever
1308 * possible. For example, do not split a write of 16KB into
1309 * four 4KB chunks unless there is no alternative.
1310 *
1311 * Entry
1312 * On entry, the PARAMETER REGISTER contains a pointer to a
1313 * three-field data block:
1314 * - field 1 Contains a handle for a file previously opened
1315 * with SYS_OPEN.
1316 * - field 2 Points to the memory containing the data to be written.
1317 * - field 3 Contains the number of bytes to be written from
1318 * the buffer to the file.
1319 *
1320 * Return
1321 * On exit, the RETURN REGISTER contains:
1322 * - 0 if the call is successful.
1323 * - The number of bytes that are not written, if there is an error.
1324 */
1325 retval = semihosting_read_fields(target, 3, fields);
1326 if (retval != ERROR_OK)
1327 return retval;
1328 else {
1329 int fd = semihosting_get_field(target, 0, fields);
1330 uint64_t addr = semihosting_get_field(target, 1, fields);
1331 size_t len = semihosting_get_field(target, 2, fields);
1332 if (semihosting->is_fileio) {
1333 semihosting->hit_fileio = true;
1334 fileio_info->identifier = "write";
1335 fileio_info->param_1 = fd;
1336 fileio_info->param_2 = addr;
1337 fileio_info->param_3 = len;
1338 } else {
1339 uint8_t *buf = malloc(len);
1340 if (!buf) {
1341 semihosting->result = -1;
1342 semihosting->sys_errno = ENOMEM;
1343 } else {
1344 retval = target_read_buffer(target, addr, len, buf);
1345 if (retval != ERROR_OK) {
1346 free(buf);
1347 return retval;
1348 }
1349 semihosting->result = semihosting_write(semihosting, fd, buf, len);
1350 semihosting->sys_errno = errno;
1351 LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d",
1352 fd,
1353 addr,
1354 len,
1355 (int)semihosting->result);
1356 if (semihosting->result >= 0) {
1357 /* The number of bytes that are NOT written.
1358 * */
1359 semihosting->result = len -
1360 semihosting->result;
1361 }
1362
1363 free(buf);
1364 }
1365 }
1366 }
1367 break;
1368
1369 case SEMIHOSTING_SYS_WRITEC: /* 0x03 */
1370 /*
1371 * Writes a character byte, pointed to by the PARAMETER REGISTER,
1372 * to the debug channel. When executed under a semihosting
1373 * debugger, the character appears on the host debugger console.
1374 *
1375 * Entry
1376 * On entry, the PARAMETER REGISTER contains a pointer to the
1377 * character.
1378 *
1379 * Return
1380 * None. The RETURN REGISTER is corrupted.
1381 */
1382 if (semihosting->is_fileio) {
1383 semihosting->hit_fileio = true;
1384 fileio_info->identifier = "write";
1385 fileio_info->param_1 = 1;
1386 fileio_info->param_2 = semihosting->param;
1387 fileio_info->param_3 = 1;
1388 } else {
1389 uint64_t addr = semihosting->param;
1390 unsigned char c;
1391 retval = target_read_memory(target, addr, 1, 1, &c);
1392 if (retval != ERROR_OK)
1393 return retval;
1394 semihosting_putchar(semihosting, semihosting->stdout_fd, c);
1395 semihosting->result = 0;
1396 }
1397 break;
1398
1399 case SEMIHOSTING_SYS_WRITE0: /* 0x04 */
1400 /*
1401 * Writes a null-terminated string to the debug channel.
1402 * When executed under a semihosting debugger, the characters
1403 * appear on the host debugger console.
1404 *
1405 * Entry
1406 * On entry, the PARAMETER REGISTER contains a pointer to the
1407 * first byte of the string.
1408 *
1409 * Return
1410 * None. The RETURN REGISTER is corrupted.
1411 */
1412 if (semihosting->is_fileio) {
1413 size_t count = 0;
1414 uint64_t addr = semihosting->param;
1415 for (;; addr++) {
1416 unsigned char c;
1417 retval = target_read_memory(target, addr, 1, 1, &c);
1418 if (retval != ERROR_OK)
1419 return retval;
1420 if (c == '\0')
1421 break;
1422 count++;
1423 }
1424 semihosting->hit_fileio = true;
1425 fileio_info->identifier = "write";
1426 fileio_info->param_1 = 1;
1427 fileio_info->param_2 = semihosting->param;
1428 fileio_info->param_3 = count;
1429 } else {
1430 uint64_t addr = semihosting->param;
1431 do {
1432 unsigned char c;
1433 retval = target_read_memory(target, addr++, 1, 1, &c);
1434 if (retval != ERROR_OK)
1435 return retval;
1436 if (!c)
1437 break;
1438 semihosting_putchar(semihosting, semihosting->stdout_fd, c);
1439 } while (1);
1440 semihosting->result = 0;
1441 }
1442 break;
1443
1444 case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107:
1445 /**
1446 * This is a user defined operation (while user cmds 0x100-0x1ff
1447 * are possible, only 0x100-0x107 are currently implemented).
1448 *
1449 * Reads the user operation parameters from target, then fires the
1450 * corresponding target event. When the target callbacks returned,
1451 * cleans up the command parameter buffer.
1452 *
1453 * Entry
1454 * On entry, the PARAMETER REGISTER contains a pointer to a
1455 * two-field data block:
1456 * - field 1 Contains a pointer to the bound command parameter
1457 * string
1458 * - field 2 Contains the command parameter string length
1459 *
1460 * Return
1461 * On exit, the RETURN REGISTER contains the return status.
1462 */
1463 {
1464 assert(!semihosting_user_op_params);
1465
1466 retval = semihosting_read_fields(target, 2, fields);
1467 if (retval != ERROR_OK) {
1468 LOG_ERROR("Failed to read fields for user defined command"
1469 " op=0x%x", semihosting->op);
1470 return retval;
1471 }
1472
1473 uint64_t addr = semihosting_get_field(target, 0, fields);
1474
1475 size_t len = semihosting_get_field(target, 1, fields);
1476 if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) {
1477 LOG_ERROR("The maximum length for user defined command "
1478 "parameter is %u, received length is %zu (op=0x%x)",
1479 SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH,
1480 len,
1481 semihosting->op);
1482 return ERROR_FAIL;
1483 }
1484
1485 semihosting_user_op_params = malloc(len + 1);
1486 if (!semihosting_user_op_params)
1487 return ERROR_FAIL;
1488 semihosting_user_op_params[len] = 0;
1489
1490 retval = target_read_buffer(target, addr, len,
1491 (uint8_t *)(semihosting_user_op_params));
1492 if (retval != ERROR_OK) {
1493 LOG_ERROR("Failed to read from target, semihosting op=0x%x",
1494 semihosting->op);
1495 free(semihosting_user_op_params);
1496 semihosting_user_op_params = NULL;
1497 return retval;
1498 }
1499
1500 target_handle_event(target, semihosting->op);
1501 free(semihosting_user_op_params);
1502 semihosting_user_op_params = NULL;
1503
1504 semihosting->result = 0;
1505 break;
1506 }
1507
1508
1509 case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */
1510 /*
1511 * Returns the number of elapsed target ticks since execution
1512 * started.
1513 * Use SYS_TICKFREQ to determine the tick frequency.
1514 *
1515 * Entry (32-bit)
1516 * On entry, the PARAMETER REGISTER points to a two-field data
1517 * block to be used for returning the number of elapsed ticks:
1518 * - field 1 The least significant field and is at the low address.
1519 * - field 2 The most significant field and is at the high address.
1520 *
1521 * Entry (64-bit)
1522 * On entry the PARAMETER REGISTER points to a one-field data
1523 * block to be used for returning the number of elapsed ticks:
1524 * - field 1 The number of elapsed ticks as a 64-bit value.
1525 *
1526 * Return
1527 * On exit:
1528 * - On success, the RETURN REGISTER contains 0, the PARAMETER
1529 * REGISTER is unchanged, and the data block pointed to by the
1530 * PARAMETER REGISTER is filled in with the number of elapsed
1531 * ticks.
1532 * - On failure, the RETURN REGISTER contains -1, and the
1533 * PARAMETER REGISTER contains -1.
1534 *
1535 * Note: Some semihosting implementations might not support this
1536 * semihosting operation, and they always return -1 in the
1537 * RETURN REGISTER.
1538 */
1539
1540 case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */
1541 /*
1542 * Returns the tick frequency.
1543 *
1544 * Entry
1545 * The PARAMETER REGISTER must contain 0 on entry to this routine.
1546 *
1547 * Return
1548 * On exit, the RETURN REGISTER contains either:
1549 * - The number of ticks per second.
1550 * - –1 if the target does not know the value of one tick.
1551 *
1552 * Note: Some semihosting implementations might not support
1553 * this semihosting operation, and they always return -1 in the
1554 * RETURN REGISTER.
1555 */
1556
1557 case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */
1558 /*
1559 * Returns a temporary name for a file identified by a system
1560 * file identifier.
1561 *
1562 * Entry
1563 * On entry, the PARAMETER REGISTER contains a pointer to a
1564 * three-word argument block:
1565 * - field 1 A pointer to a buffer.
1566 * - field 2 A target identifier for this filename. Its value
1567 * must be an integer in the range 0-255.
1568 * - field 3 Contains the length of the buffer. The length must
1569 * be at least the value of L_tmpnam on the host system.
1570 *
1571 * Return
1572 * On exit, the RETURN REGISTER contains:
1573 * - 0 if the call is successful.
1574 * - –1 if an error occurs.
1575 *
1576 * The buffer pointed to by the PARAMETER REGISTER contains
1577 * the filename, prefixed with a suitable directory name.
1578 * If you use the same target identifier again, the same
1579 * filename is returned.
1580 *
1581 * Note: The returned string must be null-terminated.
1582 */
1583
1584 default:
1585 fprintf(stderr, "semihosting: unsupported call %#x\n",
1586 (unsigned) semihosting->op);
1587 semihosting->result = -1;
1588 semihosting->sys_errno = ENOTSUP;
1589 }
1590
1591 if (!semihosting->hit_fileio) {
1592 retval = semihosting->post_result(target);
1593 if (retval != ERROR_OK) {
1594 LOG_ERROR("Failed to post semihosting result");
1595 return retval;
1596 }
1597 }
1598
1599 return ERROR_OK;
1600 }
1601
1602 /* -------------------------------------------------------------------------
1603 * Local functions. */
1604
1605 static int semihosting_common_fileio_info(struct target *target,
1606 struct gdb_fileio_info *fileio_info)
1607 {
1608 struct semihosting *semihosting = target->semihosting;
1609 if (!semihosting)
1610 return ERROR_FAIL;
1611
1612 /*
1613 * To avoid unnecessary duplication, semihosting prepares the
1614 * fileio_info structure out-of-band when the target halts. See
1615 * do_semihosting for more detail.
1616 */
1617 if (!semihosting->is_fileio || !semihosting->hit_fileio)
1618 return ERROR_FAIL;
1619
1620 return ERROR_OK;
1621 }
1622
1623 static int semihosting_common_fileio_end(struct target *target, int result,
1624 int fileio_errno, bool ctrl_c)
1625 {
1626 struct gdb_fileio_info *fileio_info = target->fileio_info;
1627 struct semihosting *semihosting = target->semihosting;
1628 if (!semihosting)
1629 return ERROR_FAIL;
1630
1631 /* clear pending status */
1632 semihosting->hit_fileio = false;
1633
1634 semihosting->result = result;
1635 semihosting->sys_errno = fileio_errno;
1636
1637 /*
1638 * Some fileio results do not match up with what the semihosting
1639 * operation expects; for these operations, we munge the results
1640 * below:
1641 */
1642 switch (semihosting->op) {
1643 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1644 if (result < 0)
1645 semihosting->result = fileio_info->param_3;
1646 else
1647 semihosting->result = 0;
1648 break;
1649
1650 case SEMIHOSTING_SYS_READ: /* 0x06 */
1651 if (result == (int)fileio_info->param_3)
1652 semihosting->result = 0;
1653 if (result <= 0)
1654 semihosting->result = fileio_info->param_3;
1655 break;
1656
1657 case SEMIHOSTING_SYS_SEEK: /* 0x0a */
1658 if (result > 0)
1659 semihosting->result = 0;
1660 break;
1661 }
1662
1663 return semihosting->post_result(target);
1664 }
1665
1666 /**
1667 * Read all fields of a command from target to buffer.
1668 */
1669 static int semihosting_read_fields(struct target *target, size_t number,
1670 uint8_t *fields)
1671 {
1672 struct semihosting *semihosting = target->semihosting;
1673 /* Use 4-byte multiples to trigger fast memory access. */
1674 return target_read_memory(target, semihosting->param, 4,
1675 number * (semihosting->word_size_bytes / 4), fields);
1676 }
1677
1678 /**
1679 * Write all fields of a command from buffer to target.
1680 */
1681 static int semihosting_write_fields(struct target *target, size_t number,
1682 uint8_t *fields)
1683 {
1684 struct semihosting *semihosting = target->semihosting;
1685 /* Use 4-byte multiples to trigger fast memory access. */
1686 return target_write_memory(target, semihosting->param, 4,
1687 number * (semihosting->word_size_bytes / 4), fields);
1688 }
1689
1690 /**
1691 * Extract a field from the buffer, considering register size and endianness.
1692 */
1693 static uint64_t semihosting_get_field(struct target *target, size_t index,
1694 uint8_t *fields)
1695 {
1696 struct semihosting *semihosting = target->semihosting;
1697 if (semihosting->word_size_bytes == 8)
1698 return target_buffer_get_u64(target, fields + (index * 8));
1699 else
1700 return target_buffer_get_u32(target, fields + (index * 4));
1701 }
1702
1703 /**
1704 * Store a field in the buffer, considering register size and endianness.
1705 */
1706 static void semihosting_set_field(struct target *target, uint64_t value,
1707 size_t index,
1708 uint8_t *fields)
1709 {
1710 struct semihosting *semihosting = target->semihosting;
1711 if (semihosting->word_size_bytes == 8)
1712 target_buffer_set_u64(target, fields + (index * 8), value);
1713 else
1714 target_buffer_set_u32(target, fields + (index * 4), value);
1715 }
1716
1717 /* -------------------------------------------------------------------------
1718 * Semihosting redirect over TCP structs and functions */
1719
1720 static int semihosting_service_new_connection_handler(struct connection *connection)
1721 {
1722 struct semihosting_tcp_service *service = connection->service->priv;
1723 service->semihosting->tcp_connection = connection;
1724
1725 return ERROR_OK;
1726 }
1727
1728 static int semihosting_service_input_handler(struct connection *connection)
1729 {
1730 struct semihosting_tcp_service *service = connection->service->priv;
1731
1732 if (!connection->input_pending) {
1733 /* consume received data, not for semihosting IO */
1734 const int buf_len = 100;
1735 char buf[buf_len];
1736 int bytes_read = connection_read(connection, buf, buf_len);
1737
1738 if (bytes_read == 0) {
1739 return ERROR_SERVER_REMOTE_CLOSED;
1740 } else if (bytes_read == -1) {
1741 LOG_ERROR("error during read: %s", strerror(errno));
1742 return ERROR_SERVER_REMOTE_CLOSED;
1743 }
1744 } else if (service->error != ERROR_OK) {
1745 return ERROR_SERVER_REMOTE_CLOSED;
1746 }
1747
1748 return ERROR_OK;
1749 }
1750
1751 static int semihosting_service_connection_closed_handler(struct connection *connection)
1752 {
1753 struct semihosting_tcp_service *service = connection->service->priv;
1754 if (service) {
1755 free(service->name);
1756 free(service);
1757 }
1758
1759 return ERROR_OK;
1760 }
1761
1762 static void semihosting_tcp_close_cnx(struct semihosting *semihosting)
1763 {
1764 if (!semihosting->tcp_connection)
1765 return;
1766
1767 struct service *service = semihosting->tcp_connection->service;
1768 remove_service(service->name, service->port);
1769 semihosting->tcp_connection = NULL;
1770
1771 }
1772
1773 static const struct service_driver semihosting_service_driver = {
1774 .name = "semihosting",
1775 .new_connection_during_keep_alive_handler = NULL,
1776 .new_connection_handler = semihosting_service_new_connection_handler,
1777 .input_handler = semihosting_service_input_handler,
1778 .connection_closed_handler = semihosting_service_connection_closed_handler,
1779 .keep_client_alive_handler = NULL,
1780 };
1781
1782 /* -------------------------------------------------------------------------
1783 * Common semihosting commands handlers. */
1784
1785 COMMAND_HANDLER(handle_common_semihosting_command)
1786 {
1787 struct target *target = get_current_target(CMD_CTX);
1788
1789 if (!target) {
1790 LOG_ERROR("No target selected");
1791 return ERROR_FAIL;
1792 }
1793
1794 struct semihosting *semihosting = target->semihosting;
1795 if (!semihosting) {
1796 command_print(CMD, "semihosting not supported for current target");
1797 return ERROR_FAIL;
1798 }
1799
1800 if (CMD_ARGC > 0) {
1801 int is_active;
1802
1803 COMMAND_PARSE_ENABLE(CMD_ARGV[0], is_active);
1804
1805 if (!target_was_examined(target)) {
1806 LOG_ERROR("Target not examined yet");
1807 return ERROR_FAIL;
1808 }
1809
1810 if (semihosting && semihosting->setup(target, is_active) != ERROR_OK) {
1811 LOG_ERROR("Failed to Configure semihosting");
1812 return ERROR_FAIL;
1813 }
1814
1815 /* FIXME never let that "catch" be dropped! (???) */
1816 semihosting->is_active = is_active;
1817 }
1818
1819 command_print(CMD, "semihosting is %s",
1820 semihosting->is_active
1821 ? "enabled" : "disabled");
1822
1823 return ERROR_OK;
1824 }
1825
1826 COMMAND_HANDLER(handle_common_semihosting_redirect_command)
1827 {
1828 struct target *target = get_current_target(CMD_CTX);
1829
1830 if (target == NULL) {
1831 LOG_ERROR("No target selected");
1832 return ERROR_FAIL;
1833 }
1834
1835 struct semihosting *semihosting = target->semihosting;
1836 if (!semihosting) {
1837 command_print(CMD, "semihosting not supported for current target");
1838 return ERROR_FAIL;
1839 }
1840
1841 if (!semihosting->is_active) {
1842 command_print(CMD, "semihosting not yet enabled for current target");
1843 return ERROR_FAIL;
1844 }
1845
1846 enum semihosting_redirect_config cfg;
1847 const char *port;
1848
1849 if (CMD_ARGC < 1)
1850 return ERROR_COMMAND_SYNTAX_ERROR;
1851
1852 if (strcmp(CMD_ARGV[0], "disable") == 0) {
1853 cfg = SEMIHOSTING_REDIRECT_CFG_NONE;
1854 if (CMD_ARGC > 1)
1855 return ERROR_COMMAND_SYNTAX_ERROR;
1856 } else if (strcmp(CMD_ARGV[0], "tcp") == 0) {
1857 if (CMD_ARGC < 2 || CMD_ARGC > 3)
1858 return ERROR_COMMAND_SYNTAX_ERROR;
1859
1860 port = CMD_ARGV[1];
1861
1862 cfg = SEMIHOSTING_REDIRECT_CFG_ALL;
1863 if (CMD_ARGC == 3) {
1864 if (strcmp(CMD_ARGV[2], "debug") == 0)
1865 cfg = SEMIHOSTING_REDIRECT_CFG_DEBUG;
1866 else if (strcmp(CMD_ARGV[2], "stdio") == 0)
1867 cfg = SEMIHOSTING_REDIRECT_CFG_STDIO;
1868 else if (strcmp(CMD_ARGV[2], "all") != 0)
1869 return ERROR_COMMAND_SYNTAX_ERROR;
1870 }
1871 } else {
1872 return ERROR_COMMAND_SYNTAX_ERROR;
1873 }
1874
1875 semihosting_tcp_close_cnx(semihosting);
1876 semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE;
1877
1878 if (cfg != SEMIHOSTING_REDIRECT_CFG_NONE) {
1879 struct semihosting_tcp_service *service =
1880 calloc(1, sizeof(struct semihosting_tcp_service));
1881 if (!service) {
1882 LOG_ERROR("Failed to allocate semihosting TCP service.");
1883 return ERROR_FAIL;
1884 }
1885
1886 service->semihosting = semihosting;
1887
1888 service->name = alloc_printf("%s semihosting service", target_name(target));
1889 if (!service->name) {
1890 LOG_ERROR("Out of memory");
1891 free(service);
1892 return ERROR_FAIL;
1893 }
1894
1895 int ret = add_service(&semihosting_service_driver,
1896 port, 1, service);
1897
1898 if (ret != ERROR_OK) {
1899 LOG_ERROR("failed to initialize %s", service->name);
1900 free(service->name);
1901 free(service);
1902 return ERROR_FAIL;
1903 }
1904 }
1905
1906 semihosting->redirect_cfg = cfg;
1907
1908 return ERROR_OK;
1909 }
1910
1911 COMMAND_HANDLER(handle_common_semihosting_fileio_command)
1912 {
1913 struct target *target = get_current_target(CMD_CTX);
1914
1915 if (!target) {
1916 LOG_ERROR("No target selected");
1917 return ERROR_FAIL;
1918 }
1919
1920 struct semihosting *semihosting = target->semihosting;
1921 if (!semihosting) {
1922 command_print(CMD, "semihosting not supported for current target");
1923 return ERROR_FAIL;
1924 }
1925
1926 if (!semihosting->is_active) {
1927 command_print(CMD, "semihosting not yet enabled for current target");
1928 return ERROR_FAIL;
1929 }
1930
1931 if (CMD_ARGC > 0)
1932 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->is_fileio);
1933
1934 command_print(CMD, "semihosting fileio is %s",
1935 semihosting->is_fileio
1936 ? "enabled" : "disabled");
1937
1938 return ERROR_OK;
1939 }
1940
1941 COMMAND_HANDLER(handle_common_semihosting_cmdline)
1942 {
1943 struct target *target = get_current_target(CMD_CTX);
1944 unsigned int i;
1945
1946 if (!target) {
1947 LOG_ERROR("No target selected");
1948 return ERROR_FAIL;
1949 }
1950
1951 struct semihosting *semihosting = target->semihosting;
1952 if (!semihosting) {
1953 command_print(CMD, "semihosting not supported for current target");
1954 return ERROR_FAIL;
1955 }
1956
1957 free(semihosting->cmdline);
1958 semihosting->cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL;
1959
1960 for (i = 1; i < CMD_ARGC; i++) {
1961 char *cmdline = alloc_printf("%s %s", semihosting->cmdline, CMD_ARGV[i]);
1962 if (!cmdline)
1963 break;
1964 free(semihosting->cmdline);
1965 semihosting->cmdline = cmdline;
1966 }
1967
1968 command_print(CMD, "semihosting command line is [%s]",
1969 semihosting->cmdline);
1970
1971 return ERROR_OK;
1972 }
1973
1974 COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
1975 {
1976 struct target *target = get_current_target(CMD_CTX);
1977
1978 if (!target) {
1979 LOG_ERROR("No target selected");
1980 return ERROR_FAIL;
1981 }
1982
1983 struct semihosting *semihosting = target->semihosting;
1984 if (!semihosting) {
1985 command_print(CMD, "semihosting not supported for current target");
1986 return ERROR_FAIL;
1987 }
1988
1989 if (!semihosting->is_active) {
1990 command_print(CMD, "semihosting not yet enabled for current target");
1991 return ERROR_FAIL;
1992 }
1993
1994 if (CMD_ARGC > 0)
1995 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->has_resumable_exit);
1996
1997 command_print(CMD, "semihosting resumable exit is %s",
1998 semihosting->has_resumable_exit
1999 ? "enabled" : "disabled");
2000
2001 return ERROR_OK;
2002 }
2003
2004 COMMAND_HANDLER(handle_common_semihosting_read_user_param_command)
2005 {
2006 struct target *target = get_current_target(CMD_CTX);
2007 struct semihosting *semihosting = target->semihosting;
2008
2009 if (CMD_ARGC)
2010 return ERROR_COMMAND_SYNTAX_ERROR;
2011
2012 if (!semihosting->is_active) {
2013 LOG_ERROR("semihosting not yet enabled for current target");
2014 return ERROR_FAIL;
2015 }
2016
2017 if (!semihosting_user_op_params) {
2018 LOG_ERROR("This command is usable only from a registered user "
2019 "semihosting event callback.");
2020 return ERROR_FAIL;
2021 }
2022
2023 command_print_sameline(CMD, "%s", semihosting_user_op_params);
2024
2025 return ERROR_OK;
2026 }
2027
2028 const struct command_registration semihosting_common_handlers[] = {
2029 {
2030 .name = "semihosting",
2031 .handler = handle_common_semihosting_command,
2032 .mode = COMMAND_EXEC,
2033 .usage = "['enable'|'disable']",
2034 .help = "activate support for semihosting operations",
2035 },
2036 {
2037 .name = "semihosting_redirect",
2038 .handler = handle_common_semihosting_redirect_command,
2039 .mode = COMMAND_EXEC,
2040 .usage = "(disable | tcp <port> ['debug'|'stdio'|'all'])",
2041 .help = "redirect semihosting IO",
2042 },
2043 {
2044 .name = "semihosting_cmdline",
2045 .handler = handle_common_semihosting_cmdline,
2046 .mode = COMMAND_EXEC,
2047 .usage = "arguments",
2048 .help = "command line arguments to be passed to program",
2049 },
2050 {
2051 .name = "semihosting_fileio",
2052 .handler = handle_common_semihosting_fileio_command,
2053 .mode = COMMAND_EXEC,
2054 .usage = "['enable'|'disable']",
2055 .help = "activate support for semihosting fileio operations",
2056 },
2057 {
2058 .name = "semihosting_resexit",
2059 .handler = handle_common_semihosting_resumable_exit_command,
2060 .mode = COMMAND_EXEC,
2061 .usage = "['enable'|'disable']",
2062 .help = "activate support for semihosting resumable exit",
2063 },
2064 {
2065 .name = "semihosting_read_user_param",
2066 .handler = handle_common_semihosting_read_user_param_command,
2067 .mode = COMMAND_EXEC,
2068 .usage = "",
2069 .help = "read parameters in semihosting-user-cmd-0x10X callbacks",
2070 },
2071 COMMAND_REGISTRATION_DONE
2072 };

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)