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

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)