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

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)