drivers/ulink: Group adapter commands
[openocd.git] / src / target / semihosting_common.c
blob5c96e1cd666236061eda2c078142c9e81258f48b
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 ***************************************************************************/
28 /**
29 * @file
30 * Common ARM semihosting support.
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.
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.
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
47 #include "target.h"
48 #include "target_type.h"
49 #include "semihosting_common.h"
51 #include <helper/binarybuffer.h>
52 #include <helper/log.h>
53 #include <sys/stat.h>
55 static const int open_modeflags[12] = {
56 O_RDONLY,
57 O_RDONLY | O_BINARY,
58 O_RDWR,
59 O_RDWR | O_BINARY,
60 O_WRONLY | O_CREAT | O_TRUNC,
61 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
62 O_RDWR | O_CREAT | O_TRUNC,
63 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
64 O_WRONLY | O_CREAT | O_APPEND,
65 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
66 O_RDWR | O_CREAT | O_APPEND,
67 O_RDWR | O_CREAT | O_APPEND | O_BINARY
70 static int semihosting_common_fileio_info(struct target *target,
71 struct gdb_fileio_info *fileio_info);
72 static int semihosting_common_fileio_end(struct target *target, int result,
73 int fileio_errno, bool ctrl_c);
75 static int semihosting_read_fields(struct target *target, size_t number,
76 uint8_t *fields);
77 static int semihosting_write_fields(struct target *target, size_t number,
78 uint8_t *fields);
79 static uint64_t semihosting_get_field(struct target *target, size_t index,
80 uint8_t *fields);
81 static void semihosting_set_field(struct target *target, uint64_t value,
82 size_t index,
83 uint8_t *fields);
85 /* Attempts to include gdb_server.h failed. */
86 extern int gdb_actual_connections;
88 /**
89 * Initialize common semihosting support.
91 * @param target Pointer to the target to initialize.
92 * @param setup
93 * @param post_result
94 * @return An error status if there is a problem during initialization.
96 int semihosting_common_init(struct target *target, void *setup,
97 void *post_result)
99 LOG_DEBUG(" ");
101 target->fileio_info = malloc(sizeof(*target->fileio_info));
102 if (!target->fileio_info) {
103 LOG_ERROR("out of memory");
104 return ERROR_FAIL;
106 memset(target->fileio_info, 0, sizeof(*target->fileio_info));
108 struct semihosting *semihosting;
109 semihosting = malloc(sizeof(*target->semihosting));
110 if (!semihosting) {
111 LOG_ERROR("out of memory");
112 return ERROR_FAIL;
115 semihosting->is_active = false;
116 semihosting->is_fileio = false;
117 semihosting->hit_fileio = false;
118 semihosting->is_resumable = false;
119 semihosting->has_resumable_exit = false;
120 semihosting->word_size_bytes = 0;
121 semihosting->op = -1;
122 semihosting->param = 0;
123 semihosting->result = -1;
124 semihosting->sys_errno = -1;
125 semihosting->cmdline = NULL;
127 /* If possible, update it in setup(). */
128 semihosting->setup_time = clock();
130 semihosting->setup = setup;
131 semihosting->post_result = post_result;
133 target->semihosting = semihosting;
135 target->type->get_gdb_fileio_info = semihosting_common_fileio_info;
136 target->type->gdb_fileio_end = semihosting_common_fileio_end;
138 return ERROR_OK;
142 * Portable implementation of ARM semihosting calls.
143 * Performs the currently pending semihosting operation
144 * encoded in target->semihosting.
146 int semihosting_common(struct target *target)
148 struct semihosting *semihosting = target->semihosting;
149 if (!semihosting) {
150 /* Silently ignore if the semihosting field was not set. */
151 return ERROR_OK;
154 struct gdb_fileio_info *fileio_info = target->fileio_info;
157 * By default return an error.
158 * The actual result must be set by each function
160 semihosting->result = -1;
162 /* Most operations are resumable, except the two exit calls. */
163 semihosting->is_resumable = true;
165 int retval;
167 /* Enough space to hold 4 long words. */
168 uint8_t fields[4*8];
170 LOG_DEBUG("op=0x%x, param=0x%" PRIx64, (int)semihosting->op,
171 semihosting->param);
173 switch (semihosting->op) {
175 case SEMIHOSTING_SYS_CLOCK: /* 0x10 */
177 * Returns the number of centiseconds (hundredths of a second)
178 * since the execution started.
180 * Values returned can be of limited use for some benchmarking
181 * purposes because of communication overhead or other
182 * agent-specific factors. For example, with a debug hardware
183 * unit the request is passed back to the host for execution.
184 * This can lead to unpredictable delays in transmission and
185 * process scheduling.
187 * Use this function to calculate time intervals, by calculating
188 * differences between intervals with and without the code
189 * sequence to be timed.
191 * Entry
192 * The PARAMETER REGISTER must contain 0. There are no other
193 * parameters.
195 * Return
196 * On exit, the RETURN REGISTER contains:
197 * - The number of centiseconds since some arbitrary start
198 * point, if the call is successful.
199 * - –1 if the call is not successful. For example, because
200 * of a communications error.
203 clock_t delta = clock() - semihosting->setup_time;
205 semihosting->result = delta / (CLOCKS_PER_SEC / 100);
207 break;
209 case SEMIHOSTING_SYS_CLOSE: /* 0x02 */
211 * Closes a file on the host system. The handle must reference
212 * a file that was opened with SYS_OPEN.
214 * Entry
215 * On entry, the PARAMETER REGISTER contains a pointer to a
216 * one-field argument block:
217 * - field 1 Contains a handle for an open file.
219 * Return
220 * On exit, the RETURN REGISTER contains:
221 * - 0 if the call is successful
222 * - –1 if the call is not successful.
224 retval = semihosting_read_fields(target, 1, fields);
225 if (retval != ERROR_OK)
226 return retval;
227 else {
228 int fd = semihosting_get_field(target, 0, fields);
229 /* Do not allow to close OpenOCD's own standard streams */
230 if (fd == 0 || fd == 1 || fd == 2) {
231 LOG_DEBUG("ignoring semihosting attempt to close %s",
232 (fd == 0) ? "stdin" :
233 (fd == 1) ? "stdout" : "stderr");
234 /* Just pretend success */
235 if (semihosting->is_fileio) {
236 semihosting->result = 0;
237 } else {
238 semihosting->result = 0;
239 semihosting->sys_errno = 0;
241 break;
243 /* Close the descriptor */
244 if (semihosting->is_fileio) {
245 semihosting->hit_fileio = true;
246 fileio_info->identifier = "close";
247 fileio_info->param_1 = fd;
248 } else {
249 semihosting->result = close(fd);
250 semihosting->sys_errno = errno;
251 LOG_DEBUG("close(%d)=%d", fd, (int)semihosting->result);
254 break;
256 case SEMIHOSTING_SYS_ERRNO: /* 0x13 */
258 * Returns the value of the C library errno variable that is
259 * associated with the semihosting implementation. The errno
260 * variable can be set by a number of C library semihosted
261 * functions, including:
262 * - SYS_REMOVE
263 * - SYS_OPEN
264 * - SYS_CLOSE
265 * - SYS_READ
266 * - SYS_WRITE
267 * - SYS_SEEK.
269 * Whether errno is set or not, and to what value, is entirely
270 * host-specific, except where the ISO C standard defines the
271 * behavior.
273 * Entry
274 * There are no parameters. The PARAMETER REGISTER must be 0.
276 * Return
277 * On exit, the RETURN REGISTER contains the value of the C
278 * library errno variable.
280 semihosting->result = semihosting->sys_errno;
281 break;
283 case SEMIHOSTING_SYS_EXIT: /* 0x18 */
285 * Note: SYS_EXIT was called angel_SWIreason_ReportException in
286 * previous versions of the documentation.
288 * An application calls this operation to report an exception
289 * to the debugger directly. The most common use is to report
290 * that execution has completed, using ADP_Stopped_ApplicationExit.
292 * Note: This semihosting operation provides no means for 32-bit
293 * callers to indicate an application exit with a specified exit
294 * code. Semihosting callers may prefer to check for the presence
295 * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use
296 * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it
297 * is available.
299 * Entry (32-bit)
300 * On entry, the PARAMETER register is set to a reason code
301 * describing the cause of the trap. Not all semihosting client
302 * implementations will necessarily trap every corresponding
303 * event. Important reason codes are:
305 * - ADP_Stopped_ApplicationExit 0x20026
306 * - ADP_Stopped_RunTimeErrorUnknown 0x20023
308 * Entry (64-bit)
309 * On entry, the PARAMETER REGISTER contains a pointer to a
310 * two-field argument block:
311 * - field 1 The exception type, which is one of the set of
312 * reason codes in the above tables.
313 * - field 2 A subcode, whose meaning depends on the reason
314 * code in field 1.
315 * In particular, if field 1 is ADP_Stopped_ApplicationExit
316 * then field 2 is an exit status code, as passed to the C
317 * standard library exit() function. A simulator receiving
318 * this request must notify a connected debugger, if present,
319 * and then exit with the specified status.
321 * Return
322 * No return is expected from these calls. However, it is
323 * possible for the debugger to request that the application
324 * continues by performing an RDI_Execute request or equivalent.
325 * In this case, execution continues with the registers as they
326 * were on entry to the operation, or as subsequently modified
327 * by the debugger.
329 if (semihosting->word_size_bytes == 8) {
330 retval = semihosting_read_fields(target, 2, fields);
331 if (retval != ERROR_OK)
332 return retval;
333 else {
334 int type = semihosting_get_field(target, 0, fields);
335 int code = semihosting_get_field(target, 1, fields);
337 if (type == ADP_STOPPED_APPLICATION_EXIT) {
338 if (!gdb_actual_connections)
339 exit(code);
340 else {
341 fprintf(stderr,
342 "semihosting: *** application exited with %d ***\n",
343 code);
345 } else {
346 fprintf(stderr,
347 "semihosting: application exception %#x\n",
348 type);
351 } else {
352 if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) {
353 if (!gdb_actual_connections)
354 exit(0);
355 else {
356 fprintf(stderr,
357 "semihosting: *** application exited normally ***\n");
359 } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) {
360 /* Chosen more or less arbitrarily to have a nicer message,
361 * otherwise all other return the same exit code 1. */
362 if (!gdb_actual_connections)
363 exit(1);
364 else {
365 fprintf(stderr,
366 "semihosting: *** application exited with error ***\n");
368 } else {
369 if (!gdb_actual_connections)
370 exit(1);
371 else {
372 fprintf(stderr,
373 "semihosting: application exception %#x\n",
374 (unsigned) semihosting->param);
378 if (!semihosting->has_resumable_exit) {
379 semihosting->is_resumable = false;
380 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
382 break;
384 case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */
386 * This operation is only supported if the semihosting extension
387 * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is
388 * reported using feature byte 0, bit 0. If this extension is
389 * supported, then the implementation provides a means to
390 * report a normal exit with a nonzero exit status in both 32-bit
391 * and 64-bit semihosting APIs.
393 * The implementation must provide the semihosting call
394 * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs.
396 * SYS_EXIT_EXTENDED is used by an application to report an
397 * exception or exit to the debugger directly. The most common
398 * use is to report that execution has completed, using
399 * ADP_Stopped_ApplicationExit.
401 * Entry
402 * On entry, the PARAMETER REGISTER contains a pointer to a
403 * two-field argument block:
404 * - field 1 The exception type, which should be one of the set
405 * of reason codes that are documented for the SYS_EXIT
406 * (0x18) call. For example, ADP_Stopped_ApplicationExit.
407 * - field 2 A subcode, whose meaning depends on the reason
408 * code in field 1. In particular, if field 1 is
409 * ADP_Stopped_ApplicationExit then field 2 is an exit status
410 * code, as passed to the C standard library exit() function.
411 * A simulator receiving this request must notify a connected
412 * debugger, if present, and then exit with the specified status.
414 * Return
415 * No return is expected from these calls.
417 * For the A64 API, this call is identical to the behavior of
418 * the mandatory SYS_EXIT (0x18) call. If this extension is
419 * supported, then both calls must be implemented.
421 retval = semihosting_read_fields(target, 2, fields);
422 if (retval != ERROR_OK)
423 return retval;
424 else {
425 int type = semihosting_get_field(target, 0, fields);
426 int code = semihosting_get_field(target, 1, fields);
428 if (type == ADP_STOPPED_APPLICATION_EXIT) {
429 if (!gdb_actual_connections)
430 exit(code);
431 else {
432 fprintf(stderr,
433 "semihosting: *** application exited with %d ***\n",
434 code);
436 } else {
437 fprintf(stderr, "semihosting: exception %#x\n",
438 type);
441 if (!semihosting->has_resumable_exit) {
442 semihosting->is_resumable = false;
443 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
445 break;
447 case SEMIHOSTING_SYS_FLEN: /* 0x0C */
449 * Returns the length of a specified file.
451 * Entry
452 * On entry, the PARAMETER REGISTER contains a pointer to a
453 * one-field argument block:
454 * - field 1 A handle for a previously opened, seekable file
455 * object.
457 * Return
458 * On exit, the RETURN REGISTER contains:
459 * - The current length of the file object, if the call is
460 * successful.
461 * - –1 if an error occurs.
463 if (semihosting->is_fileio) {
464 semihosting->result = -1;
465 semihosting->sys_errno = EINVAL;
467 retval = semihosting_read_fields(target, 1, fields);
468 if (retval != ERROR_OK)
469 return retval;
470 else {
471 int fd = semihosting_get_field(target, 0, fields);
472 struct stat buf;
473 semihosting->result = fstat(fd, &buf);
474 if (semihosting->result == -1) {
475 semihosting->sys_errno = errno;
476 LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
477 break;
479 LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
480 semihosting->result = buf.st_size;
482 break;
484 case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */
486 * Returns the command line that is used for the call to the
487 * executable, that is, argc and argv.
489 * Entry
490 * On entry, the PARAMETER REGISTER points to a two-field data
491 * block to be used for returning the command string and its length:
492 * - field 1 A pointer to a buffer of at least the size that is
493 * specified in field 2.
494 * - field 2 The length of the buffer in bytes.
496 * Return
497 * On exit:
498 * If the call is successful, then the RETURN REGISTER contains 0,
499 * the PARAMETER REGISTER is unchanged, and the data block is
500 * updated as follows:
501 * - field 1 A pointer to a null-terminated string of the command
502 * line.
503 * - field 2 The length of the string in bytes.
504 * If the call is not successful, then the RETURN REGISTER
505 * contains -1.
507 * Note: The semihosting implementation might impose limits on
508 * the maximum length of the string that can be transferred.
509 * However, the implementation must be able to support a
510 * command-line length of at least 80 bytes.
512 retval = semihosting_read_fields(target, 2, fields);
513 if (retval != ERROR_OK)
514 return retval;
515 else {
516 uint64_t addr = semihosting_get_field(target, 0, fields);
517 size_t size = semihosting_get_field(target, 1, fields);
519 char *arg = semihosting->cmdline ?
520 semihosting->cmdline : "";
521 uint32_t len = strlen(arg) + 1;
522 if (len > size)
523 semihosting->result = -1;
524 else {
525 semihosting_set_field(target, len, 1, fields);
526 retval = target_write_buffer(target, addr, len,
527 (uint8_t *)arg);
528 if (retval != ERROR_OK)
529 return retval;
530 semihosting->result = 0;
532 retval = semihosting_write_fields(target, 2, fields);
533 if (retval != ERROR_OK)
534 return retval;
536 LOG_DEBUG("SYS_GET_CMDLINE=[%s],%d", arg,
537 (int)semihosting->result);
539 break;
541 case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */
543 * Returns the system stack and heap parameters.
545 * Entry
546 * On entry, the PARAMETER REGISTER contains the address of a
547 * pointer to a four-field data block. The contents of the data
548 * block are filled by the function. The following C-like
549 * pseudocode describes the layout of the block:
550 * struct block {
551 * void* heap_base;
552 * void* heap_limit;
553 * void* stack_base;
554 * void* stack_limit;
555 * };
557 * Return
558 * On exit, the PARAMETER REGISTER is unchanged and the data
559 * block has been updated.
561 retval = semihosting_read_fields(target, 1, fields);
562 if (retval != ERROR_OK)
563 return retval;
564 else {
565 uint64_t addr = semihosting_get_field(target, 0, fields);
566 /* tell the remote we have no idea */
567 memset(fields, 0, 4 * semihosting->word_size_bytes);
568 retval = target_write_memory(target, addr, 4,
569 semihosting->word_size_bytes,
570 fields);
571 if (retval != ERROR_OK)
572 return retval;
573 semihosting->result = 0;
575 break;
577 case SEMIHOSTING_SYS_ISERROR: /* 0x08 */
579 * Determines whether the return code from another semihosting
580 * call is an error status or not.
582 * This call is passed a parameter block containing the error
583 * code to examine.
585 * Entry
586 * On entry, the PARAMETER REGISTER contains a pointer to a
587 * one-field data block:
588 * - field 1 The required status word to check.
590 * Return
591 * On exit, the RETURN REGISTER contains:
592 * - 0 if the status field is not an error indication
593 * - A nonzero value if the status field is an error indication.
595 retval = semihosting_read_fields(target, 1, fields);
596 if (retval != ERROR_OK)
597 return retval;
599 uint64_t code = semihosting_get_field(target, 0, fields);
600 semihosting->result = (code != 0);
601 break;
603 case SEMIHOSTING_SYS_ISTTY: /* 0x09 */
605 * Checks whether a file is connected to an interactive device.
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 file object.
612 * Return
613 * On exit, the RETURN REGISTER contains:
614 * - 1 if the handle identifies an interactive device.
615 * - 0 if the handle identifies a file.
616 * - A value other than 1 or 0 if an error occurs.
618 if (semihosting->is_fileio) {
619 semihosting->hit_fileio = true;
620 fileio_info->identifier = "isatty";
621 fileio_info->param_1 = semihosting->param;
622 } else {
623 retval = semihosting_read_fields(target, 1, fields);
624 if (retval != ERROR_OK)
625 return retval;
626 int fd = semihosting_get_field(target, 0, fields);
627 semihosting->result = isatty(fd);
628 semihosting->sys_errno = errno;
629 LOG_DEBUG("isatty(%d)=%d", fd, (int)semihosting->result);
631 break;
633 case SEMIHOSTING_SYS_OPEN: /* 0x01 */
635 * Opens a file on the host system.
637 * The file path is specified either as relative to the current
638 * directory of the host process, or absolute, using the path
639 * conventions of the host operating system.
641 * Semihosting implementations must support opening the special
642 * path name :semihosting-features as part of the semihosting
643 * extensions reporting mechanism.
645 * ARM targets interpret the special path name :tt as meaning
646 * the console input stream, for an open-read or the console
647 * output stream, for an open-write. Opening these streams is
648 * performed as part of the standard startup code for those
649 * applications that reference the C stdio streams. The
650 * semihosting extension SH_EXT_STDOUT_STDERR allows the
651 * semihosting caller to open separate output streams
652 * corresponding to stdout and stderr. This extension is
653 * reported using feature byte 0, bit 1. Use SYS_OPEN with
654 * the special path name :semihosting-features to access the
655 * feature bits.
657 * If this extension is supported, the implementation must
658 * support the following additional semantics to SYS_OPEN:
659 * - If the special path name :tt is opened with an fopen
660 * mode requesting write access (w, wb, w+, or w+b), then
661 * this is a request to open stdout.
662 * - If the special path name :tt is opened with a mode
663 * requesting append access (a, ab, a+, or a+b), then this is
664 * a request to open stderr.
666 * Entry
667 * On entry, the PARAMETER REGISTER contains a pointer to a
668 * three-field argument block:
669 * - field 1 A pointer to a null-terminated string containing
670 * a file or device name.
671 * - field 2 An integer that specifies the file opening mode.
672 * - field 3 An integer that gives the length of the string
673 * pointed to by field 1.
675 * The length does not include the terminating null character
676 * that must be present.
678 * Return
679 * On exit, the RETURN REGISTER contains:
680 * - A nonzero handle if the call is successful.
681 * - –1 if the call is not successful.
683 retval = semihosting_read_fields(target, 3, fields);
684 if (retval != ERROR_OK)
685 return retval;
686 else {
687 uint64_t addr = semihosting_get_field(target, 0, fields);
688 uint32_t mode = semihosting_get_field(target, 1, fields);
689 size_t len = semihosting_get_field(target, 2, fields);
691 if (mode > 11) {
692 semihosting->result = -1;
693 semihosting->sys_errno = EINVAL;
694 break;
696 uint8_t *fn = malloc(len+1);
697 if (!fn) {
698 semihosting->result = -1;
699 semihosting->sys_errno = ENOMEM;
700 } else {
701 retval = target_read_memory(target, addr, 1, len, fn);
702 if (retval != ERROR_OK) {
703 free(fn);
704 return retval;
706 fn[len] = 0;
707 /* TODO: implement the :semihosting-features special file.
708 * */
709 if (semihosting->is_fileio) {
710 if (strcmp((char *)fn, ":semihosting-features") == 0) {
711 semihosting->result = -1;
712 semihosting->sys_errno = EINVAL;
713 } else if (strcmp((char *)fn, ":tt") == 0) {
714 if (mode == 0)
715 semihosting->result = 0;
716 else if (mode == 4)
717 semihosting->result = 1;
718 else if (mode == 8)
719 semihosting->result = 2;
720 else
721 semihosting->result = -1;
722 } else {
723 semihosting->hit_fileio = true;
724 fileio_info->identifier = "open";
725 fileio_info->param_1 = addr;
726 fileio_info->param_2 = len;
727 fileio_info->param_3 = open_modeflags[mode];
728 fileio_info->param_4 = 0644;
730 } else {
731 if (strcmp((char *)fn, ":tt") == 0) {
732 /* Mode is:
733 * - 0-3 ("r") for stdin,
734 * - 4-7 ("w") for stdout,
735 * - 8-11 ("a") for stderr */
736 if (mode < 4) {
737 semihosting->result = dup(
738 STDIN_FILENO);
739 semihosting->sys_errno = errno;
740 LOG_DEBUG("dup(STDIN)=%d",
741 (int)semihosting->result);
742 } else if (mode < 8) {
743 semihosting->result = dup(
744 STDOUT_FILENO);
745 semihosting->sys_errno = errno;
746 LOG_DEBUG("dup(STDOUT)=%d",
747 (int)semihosting->result);
748 } else {
749 semihosting->result = dup(
750 STDERR_FILENO);
751 semihosting->sys_errno = errno;
752 LOG_DEBUG("dup(STDERR)=%d",
753 (int)semihosting->result);
755 } else {
756 /* cygwin requires the permission setting
757 * otherwise it will fail to reopen a previously
758 * written file */
759 semihosting->result = open((char *)fn,
760 open_modeflags[mode],
761 0644);
762 semihosting->sys_errno = errno;
763 LOG_DEBUG("open('%s')=%d", fn,
764 (int)semihosting->result);
767 free(fn);
770 break;
772 case SEMIHOSTING_SYS_READ: /* 0x06 */
774 * Reads the contents of a file into a buffer. The file position
775 * is specified either:
776 * - Explicitly by a SYS_SEEK.
777 * - Implicitly one byte beyond the previous SYS_READ or
778 * SYS_WRITE request.
780 * The file position is at the start of the file when it is
781 * opened, and is lost when the file is closed. Perform the
782 * file operation as a single action whenever possible. For
783 * example, do not split a read of 16KB into four 4KB chunks
784 * unless there is no alternative.
786 * Entry
787 * On entry, the PARAMETER REGISTER contains a pointer to a
788 * three-field data block:
789 * - field 1 Contains a handle for a file previously opened
790 * with SYS_OPEN.
791 * - field 2 Points to a buffer.
792 * - field 3 Contains the number of bytes to read to the buffer
793 * from the file.
795 * Return
796 * On exit, the RETURN REGISTER contains the number of bytes not
797 * filled in the buffer (buffer_length - bytes_read) as follows:
798 * - If the RETURN REGISTER is 0, the entire buffer was
799 * successfully filled.
800 * - If the RETURN REGISTER is the same as field 3, no bytes
801 * were read (EOF can be assumed).
802 * - If the RETURN REGISTER contains a value smaller than
803 * field 3, the read succeeded but the buffer was only partly
804 * filled. For interactive devices, this is the most common
805 * return value.
807 retval = semihosting_read_fields(target, 3, fields);
808 if (retval != ERROR_OK)
809 return retval;
810 else {
811 int fd = semihosting_get_field(target, 0, fields);
812 uint64_t addr = semihosting_get_field(target, 1, fields);
813 size_t len = semihosting_get_field(target, 2, fields);
814 if (semihosting->is_fileio) {
815 semihosting->hit_fileio = true;
816 fileio_info->identifier = "read";
817 fileio_info->param_1 = fd;
818 fileio_info->param_2 = addr;
819 fileio_info->param_3 = len;
820 } else {
821 uint8_t *buf = malloc(len);
822 if (!buf) {
823 semihosting->result = -1;
824 semihosting->sys_errno = ENOMEM;
825 } else {
826 semihosting->result = read(fd, buf, len);
827 semihosting->sys_errno = errno;
828 LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d",
830 addr,
831 len,
832 (int)semihosting->result);
833 if (semihosting->result >= 0) {
834 retval = target_write_buffer(target, addr,
835 semihosting->result,
836 buf);
837 if (retval != ERROR_OK) {
838 free(buf);
839 return retval;
841 /* the number of bytes NOT filled in */
842 semihosting->result = len -
843 semihosting->result;
845 free(buf);
849 break;
851 case SEMIHOSTING_SYS_READC: /* 0x07 */
853 * Reads a byte from the console.
855 * Entry
856 * The PARAMETER REGISTER must contain 0. There are no other
857 * parameters or values possible.
859 * Return
860 * On exit, the RETURN REGISTER contains the byte read from
861 * the console.
863 if (semihosting->is_fileio) {
864 LOG_ERROR("SYS_READC not supported by semihosting fileio");
865 return ERROR_FAIL;
867 semihosting->result = getchar();
868 LOG_DEBUG("getchar()=%d", (int)semihosting->result);
869 break;
871 case SEMIHOSTING_SYS_REMOVE: /* 0x0E */
873 * Deletes a specified file on the host filing system.
875 * Entry
876 * On entry, the PARAMETER REGISTER contains a pointer to a
877 * two-field argument block:
878 * - field 1 Points to a null-terminated string that gives the
879 * path name of the file to be deleted.
880 * - field 2 The length of the string.
882 * Return
883 * On exit, the RETURN REGISTER contains:
884 * - 0 if the delete is successful
885 * - A nonzero, host-specific error code if the delete fails.
887 retval = semihosting_read_fields(target, 2, fields);
888 if (retval != ERROR_OK)
889 return retval;
890 else {
891 uint64_t addr = semihosting_get_field(target, 0, fields);
892 size_t len = semihosting_get_field(target, 1, fields);
893 if (semihosting->is_fileio) {
894 semihosting->hit_fileio = true;
895 fileio_info->identifier = "unlink";
896 fileio_info->param_1 = addr;
897 fileio_info->param_2 = len;
898 } else {
899 uint8_t *fn = malloc(len+1);
900 if (!fn) {
901 semihosting->result = -1;
902 semihosting->sys_errno = ENOMEM;
903 } else {
904 retval =
905 target_read_memory(target, addr, 1, len,
906 fn);
907 if (retval != ERROR_OK) {
908 free(fn);
909 return retval;
911 fn[len] = 0;
912 semihosting->result = remove((char *)fn);
913 semihosting->sys_errno = errno;
914 LOG_DEBUG("remove('%s')=%d", fn,
915 (int)semihosting->result);
917 free(fn);
921 break;
923 case SEMIHOSTING_SYS_RENAME: /* 0x0F */
925 * Renames a specified file.
927 * Entry
928 * On entry, the PARAMETER REGISTER contains a pointer to a
929 * four-field data block:
930 * - field 1 A pointer to the name of the old file.
931 * - field 2 The length of the old filename.
932 * - field 3 A pointer to the new filename.
933 * - field 4 The length of the new filename. Both strings are
934 * null-terminated.
936 * Return
937 * On exit, the RETURN REGISTER contains:
938 * - 0 if the rename is successful.
939 * - A nonzero, host-specific error code if the rename fails.
941 retval = semihosting_read_fields(target, 4, fields);
942 if (retval != ERROR_OK)
943 return retval;
944 else {
945 uint64_t addr1 = semihosting_get_field(target, 0, fields);
946 size_t len1 = semihosting_get_field(target, 1, fields);
947 uint64_t addr2 = semihosting_get_field(target, 2, fields);
948 size_t len2 = semihosting_get_field(target, 3, fields);
949 if (semihosting->is_fileio) {
950 semihosting->hit_fileio = true;
951 fileio_info->identifier = "rename";
952 fileio_info->param_1 = addr1;
953 fileio_info->param_2 = len1;
954 fileio_info->param_3 = addr2;
955 fileio_info->param_4 = len2;
956 } else {
957 uint8_t *fn1 = malloc(len1+1);
958 uint8_t *fn2 = malloc(len2+1);
959 if (!fn1 || !fn2) {
960 free(fn1);
961 free(fn2);
962 semihosting->result = -1;
963 semihosting->sys_errno = ENOMEM;
964 } else {
965 retval = target_read_memory(target, addr1, 1, len1,
966 fn1);
967 if (retval != ERROR_OK) {
968 free(fn1);
969 free(fn2);
970 return retval;
972 retval = target_read_memory(target, addr2, 1, len2,
973 fn2);
974 if (retval != ERROR_OK) {
975 free(fn1);
976 free(fn2);
977 return retval;
979 fn1[len1] = 0;
980 fn2[len2] = 0;
981 semihosting->result = rename((char *)fn1,
982 (char *)fn2);
983 semihosting->sys_errno = errno;
984 LOG_DEBUG("rename('%s', '%s')=%d", fn1, fn2,
985 (int)semihosting->result);
987 free(fn1);
988 free(fn2);
992 break;
994 case SEMIHOSTING_SYS_SEEK: /* 0x0A */
996 * Seeks to a specified position in a file using an offset
997 * specified from the start of the file. The file is assumed
998 * to be a byte array and the offset is given in bytes.
1000 * Entry
1001 * On entry, the PARAMETER REGISTER contains a pointer to a
1002 * two-field data block:
1003 * - field 1 A handle for a seekable file object.
1004 * - field 2 The absolute byte position to seek to.
1006 * Return
1007 * On exit, the RETURN REGISTER contains:
1008 * - 0 if the request is successful.
1009 * - A negative value if the request is not successful.
1010 * Use SYS_ERRNO to read the value of the host errno variable
1011 * describing the error.
1013 * Note: The effect of seeking outside the current extent of
1014 * the file object is undefined.
1016 retval = semihosting_read_fields(target, 2, fields);
1017 if (retval != ERROR_OK)
1018 return retval;
1019 else {
1020 int fd = semihosting_get_field(target, 0, fields);
1021 off_t pos = semihosting_get_field(target, 1, fields);
1022 if (semihosting->is_fileio) {
1023 semihosting->hit_fileio = true;
1024 fileio_info->identifier = "lseek";
1025 fileio_info->param_1 = fd;
1026 fileio_info->param_2 = pos;
1027 fileio_info->param_3 = SEEK_SET;
1028 } else {
1029 semihosting->result = lseek(fd, pos, SEEK_SET);
1030 semihosting->sys_errno = errno;
1031 LOG_DEBUG("lseek(%d, %d)=%d", fd, (int)pos,
1032 (int)semihosting->result);
1033 if (semihosting->result == pos)
1034 semihosting->result = 0;
1037 break;
1039 case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */
1041 * Passes a command to the host command-line interpreter.
1042 * This enables you to execute a system command such as dir,
1043 * ls, or pwd. The terminal I/O is on the host, and is not
1044 * visible to the target.
1046 * Entry
1047 * On entry, the PARAMETER REGISTER contains a pointer to a
1048 * two-field argument block:
1049 * - field 1 Points to a string to be passed to the host
1050 * command-line interpreter.
1051 * - field 2 The length of the string.
1053 * Return
1054 * On exit, the RETURN REGISTER contains the return status.
1057 /* Provide SYS_SYSTEM functionality. Uses the
1058 * libc system command, there may be a reason *NOT*
1059 * to use this, but as I can't think of one, I
1060 * implemented it this way.
1062 retval = semihosting_read_fields(target, 2, fields);
1063 if (retval != ERROR_OK)
1064 return retval;
1065 else {
1066 uint64_t addr = semihosting_get_field(target, 0, fields);
1067 size_t len = semihosting_get_field(target, 1, fields);
1068 if (semihosting->is_fileio) {
1069 semihosting->hit_fileio = true;
1070 fileio_info->identifier = "system";
1071 fileio_info->param_1 = addr;
1072 fileio_info->param_2 = len;
1073 } else {
1074 uint8_t *cmd = malloc(len+1);
1075 if (!cmd) {
1076 semihosting->result = -1;
1077 semihosting->sys_errno = ENOMEM;
1078 } else {
1079 retval = target_read_memory(target,
1080 addr,
1082 len,
1083 cmd);
1084 if (retval != ERROR_OK) {
1085 free(cmd);
1086 return retval;
1087 } else {
1088 cmd[len] = 0;
1089 semihosting->result = system(
1090 (const char *)cmd);
1091 LOG_DEBUG("system('%s')=%d",
1092 cmd,
1093 (int)semihosting->result);
1096 free(cmd);
1100 break;
1102 case SEMIHOSTING_SYS_TIME: /* 0x11 */
1104 * Returns the number of seconds since 00:00 January 1, 1970.
1105 * This value is real-world time, regardless of any debug agent
1106 * configuration.
1108 * Entry
1109 * There are no parameters.
1111 * Return
1112 * On exit, the RETURN REGISTER contains the number of seconds.
1114 semihosting->result = time(NULL);
1115 break;
1117 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1119 * Writes the contents of a buffer to a specified file at the
1120 * current file position. The file position is specified either:
1121 * - Explicitly, by a SYS_SEEK.
1122 * - Implicitly as one byte beyond the previous SYS_READ or
1123 * SYS_WRITE request.
1125 * The file position is at the start of the file when the file
1126 * is opened, and is lost when the file is closed.
1128 * Perform the file operation as a single action whenever
1129 * possible. For example, do not split a write of 16KB into
1130 * four 4KB chunks unless there is no alternative.
1132 * Entry
1133 * On entry, the PARAMETER REGISTER contains a pointer to a
1134 * three-field data block:
1135 * - field 1 Contains a handle for a file previously opened
1136 * with SYS_OPEN.
1137 * - field 2 Points to the memory containing the data to be written.
1138 * - field 3 Contains the number of bytes to be written from
1139 * the buffer to the file.
1141 * Return
1142 * On exit, the RETURN REGISTER contains:
1143 * - 0 if the call is successful.
1144 * - The number of bytes that are not written, if there is an error.
1146 retval = semihosting_read_fields(target, 3, fields);
1147 if (retval != ERROR_OK)
1148 return retval;
1149 else {
1150 int fd = semihosting_get_field(target, 0, fields);
1151 uint64_t addr = semihosting_get_field(target, 1, fields);
1152 size_t len = semihosting_get_field(target, 2, fields);
1153 if (semihosting->is_fileio) {
1154 semihosting->hit_fileio = true;
1155 fileio_info->identifier = "write";
1156 fileio_info->param_1 = fd;
1157 fileio_info->param_2 = addr;
1158 fileio_info->param_3 = len;
1159 } else {
1160 uint8_t *buf = malloc(len);
1161 if (!buf) {
1162 semihosting->result = -1;
1163 semihosting->sys_errno = ENOMEM;
1164 } else {
1165 retval = target_read_buffer(target, addr, len, buf);
1166 if (retval != ERROR_OK) {
1167 free(buf);
1168 return retval;
1170 semihosting->result = write(fd, buf, len);
1171 semihosting->sys_errno = errno;
1172 LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d",
1174 addr,
1175 len,
1176 (int)semihosting->result);
1177 if (semihosting->result >= 0) {
1178 /* The number of bytes that are NOT written.
1179 * */
1180 semihosting->result = len -
1181 semihosting->result;
1184 free(buf);
1188 break;
1190 case SEMIHOSTING_SYS_WRITEC: /* 0x03 */
1192 * Writes a character byte, pointed to by the PARAMETER REGISTER,
1193 * to the debug channel. When executed under a semihosting
1194 * debugger, the character appears on the host debugger console.
1196 * Entry
1197 * On entry, the PARAMETER REGISTER contains a pointer to the
1198 * character.
1200 * Return
1201 * None. The RETURN REGISTER is corrupted.
1203 if (semihosting->is_fileio) {
1204 semihosting->hit_fileio = true;
1205 fileio_info->identifier = "write";
1206 fileio_info->param_1 = 1;
1207 fileio_info->param_2 = semihosting->param;
1208 fileio_info->param_3 = 1;
1209 } else {
1210 uint64_t addr = semihosting->param;
1211 unsigned char c;
1212 retval = target_read_memory(target, addr, 1, 1, &c);
1213 if (retval != ERROR_OK)
1214 return retval;
1215 putchar(c);
1216 semihosting->result = 0;
1218 break;
1220 case SEMIHOSTING_SYS_WRITE0: /* 0x04 */
1222 * Writes a null-terminated string to the debug channel.
1223 * When executed under a semihosting debugger, the characters
1224 * appear on the host debugger console.
1226 * Entry
1227 * On entry, the PARAMETER REGISTER contains a pointer to the
1228 * first byte of the string.
1230 * Return
1231 * None. The RETURN REGISTER is corrupted.
1233 if (semihosting->is_fileio) {
1234 size_t count = 0;
1235 uint64_t addr = semihosting->param;
1236 for (;; addr++) {
1237 unsigned char c;
1238 retval = target_read_memory(target, addr, 1, 1, &c);
1239 if (retval != ERROR_OK)
1240 return retval;
1241 if (c == '\0')
1242 break;
1243 count++;
1245 semihosting->hit_fileio = true;
1246 fileio_info->identifier = "write";
1247 fileio_info->param_1 = 1;
1248 fileio_info->param_2 = semihosting->param;
1249 fileio_info->param_3 = count;
1250 } else {
1251 uint64_t addr = semihosting->param;
1252 do {
1253 unsigned char c;
1254 retval = target_read_memory(target, addr++, 1, 1, &c);
1255 if (retval != ERROR_OK)
1256 return retval;
1257 if (!c)
1258 break;
1259 putchar(c);
1260 } while (1);
1261 semihosting->result = 0;
1263 break;
1265 case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */
1267 * Returns the number of elapsed target ticks since execution
1268 * started.
1269 * Use SYS_TICKFREQ to determine the tick frequency.
1271 * Entry (32-bit)
1272 * On entry, the PARAMETER REGISTER points to a two-field data
1273 * block to be used for returning the number of elapsed ticks:
1274 * - field 1 The least significant field and is at the low address.
1275 * - field 2 The most significant field and is at the high address.
1277 * Entry (64-bit)
1278 * On entry the PARAMETER REGISTER points to a one-field data
1279 * block to be used for returning the number of elapsed ticks:
1280 * - field 1 The number of elapsed ticks as a 64-bit value.
1282 * Return
1283 * On exit:
1284 * - On success, the RETURN REGISTER contains 0, the PARAMETER
1285 * REGISTER is unchanged, and the data block pointed to by the
1286 * PARAMETER REGISTER is filled in with the number of elapsed
1287 * ticks.
1288 * - On failure, the RETURN REGISTER contains -1, and the
1289 * PARAMETER REGISTER contains -1.
1291 * Note: Some semihosting implementations might not support this
1292 * semihosting operation, and they always return -1 in the
1293 * RETURN REGISTER.
1296 case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */
1298 * Returns the tick frequency.
1300 * Entry
1301 * The PARAMETER REGISTER must contain 0 on entry to this routine.
1303 * Return
1304 * On exit, the RETURN REGISTER contains either:
1305 * - The number of ticks per second.
1306 * - –1 if the target does not know the value of one tick.
1308 * Note: Some semihosting implementations might not support
1309 * this semihosting operation, and they always return -1 in the
1310 * RETURN REGISTER.
1313 case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */
1315 * Returns a temporary name for a file identified by a system
1316 * file identifier.
1318 * Entry
1319 * On entry, the PARAMETER REGISTER contains a pointer to a
1320 * three-word argument block:
1321 * - field 1 A pointer to a buffer.
1322 * - field 2 A target identifier for this filename. Its value
1323 * must be an integer in the range 0-255.
1324 * - field 3 Contains the length of the buffer. The length must
1325 * be at least the value of L_tmpnam on the host system.
1327 * Return
1328 * On exit, the RETURN REGISTER contains:
1329 * - 0 if the call is successful.
1330 * - –1 if an error occurs.
1332 * The buffer pointed to by the PARAMETER REGISTER contains
1333 * the filename, prefixed with a suitable directory name.
1334 * If you use the same target identifier again, the same
1335 * filename is returned.
1337 * Note: The returned string must be null-terminated.
1340 default:
1341 fprintf(stderr, "semihosting: unsupported call %#x\n",
1342 (unsigned) semihosting->op);
1343 semihosting->result = -1;
1344 semihosting->sys_errno = ENOTSUP;
1347 if (!semihosting->hit_fileio) {
1348 retval = semihosting->post_result(target);
1349 if (retval != ERROR_OK) {
1350 LOG_ERROR("Failed to post semihosting result");
1351 return retval;
1355 return ERROR_OK;
1358 /* -------------------------------------------------------------------------
1359 * Local functions. */
1361 static int semihosting_common_fileio_info(struct target *target,
1362 struct gdb_fileio_info *fileio_info)
1364 struct semihosting *semihosting = target->semihosting;
1365 if (!semihosting)
1366 return ERROR_FAIL;
1369 * To avoid unnecessary duplication, semihosting prepares the
1370 * fileio_info structure out-of-band when the target halts. See
1371 * do_semihosting for more detail.
1373 if (!semihosting->is_fileio || !semihosting->hit_fileio)
1374 return ERROR_FAIL;
1376 return ERROR_OK;
1379 static int semihosting_common_fileio_end(struct target *target, int result,
1380 int fileio_errno, bool ctrl_c)
1382 struct gdb_fileio_info *fileio_info = target->fileio_info;
1383 struct semihosting *semihosting = target->semihosting;
1384 if (!semihosting)
1385 return ERROR_FAIL;
1387 /* clear pending status */
1388 semihosting->hit_fileio = false;
1390 semihosting->result = result;
1391 semihosting->sys_errno = fileio_errno;
1394 * Some fileio results do not match up with what the semihosting
1395 * operation expects; for these operations, we munge the results
1396 * below:
1398 switch (semihosting->op) {
1399 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1400 if (result < 0)
1401 semihosting->result = fileio_info->param_3;
1402 else
1403 semihosting->result = 0;
1404 break;
1406 case SEMIHOSTING_SYS_READ: /* 0x06 */
1407 if (result == (int)fileio_info->param_3)
1408 semihosting->result = 0;
1409 if (result <= 0)
1410 semihosting->result = fileio_info->param_3;
1411 break;
1413 case SEMIHOSTING_SYS_SEEK: /* 0x0a */
1414 if (result > 0)
1415 semihosting->result = 0;
1416 break;
1419 return semihosting->post_result(target);
1423 * Read all fields of a command from target to buffer.
1425 static int semihosting_read_fields(struct target *target, size_t number,
1426 uint8_t *fields)
1428 struct semihosting *semihosting = target->semihosting;
1429 /* Use 4-byte multiples to trigger fast memory access. */
1430 return target_read_memory(target, semihosting->param, 4,
1431 number * (semihosting->word_size_bytes / 4), fields);
1435 * Write all fields of a command from buffer to target.
1437 static int semihosting_write_fields(struct target *target, size_t number,
1438 uint8_t *fields)
1440 struct semihosting *semihosting = target->semihosting;
1441 /* Use 4-byte multiples to trigger fast memory access. */
1442 return target_write_memory(target, semihosting->param, 4,
1443 number * (semihosting->word_size_bytes / 4), fields);
1447 * Extract a field from the buffer, considering register size and endianness.
1449 static uint64_t semihosting_get_field(struct target *target, size_t index,
1450 uint8_t *fields)
1452 struct semihosting *semihosting = target->semihosting;
1453 if (semihosting->word_size_bytes == 8)
1454 return target_buffer_get_u64(target, fields + (index * 8));
1455 else
1456 return target_buffer_get_u32(target, fields + (index * 4));
1460 * Store a field in the buffer, considering register size and endianness.
1462 static void semihosting_set_field(struct target *target, uint64_t value,
1463 size_t index,
1464 uint8_t *fields)
1466 struct semihosting *semihosting = target->semihosting;
1467 if (semihosting->word_size_bytes == 8)
1468 target_buffer_set_u64(target, fields + (index * 8), value);
1469 else
1470 target_buffer_set_u32(target, fields + (index * 4), value);
1474 /* -------------------------------------------------------------------------
1475 * Common semihosting commands handlers. */
1477 static __COMMAND_HANDLER(handle_common_semihosting_command)
1479 struct target *target = get_current_target(CMD_CTX);
1481 if (!target) {
1482 LOG_ERROR("No target selected");
1483 return ERROR_FAIL;
1486 struct semihosting *semihosting = target->semihosting;
1487 if (!semihosting) {
1488 command_print(CMD, "semihosting not supported for current target");
1489 return ERROR_FAIL;
1492 if (CMD_ARGC > 0) {
1493 int is_active;
1495 COMMAND_PARSE_ENABLE(CMD_ARGV[0], is_active);
1497 if (!target_was_examined(target)) {
1498 LOG_ERROR("Target not examined yet");
1499 return ERROR_FAIL;
1502 if (semihosting && semihosting->setup(target, is_active) != ERROR_OK) {
1503 LOG_ERROR("Failed to Configure semihosting");
1504 return ERROR_FAIL;
1507 /* FIXME never let that "catch" be dropped! (???) */
1508 semihosting->is_active = is_active;
1511 command_print(CMD, "semihosting is %s",
1512 semihosting->is_active
1513 ? "enabled" : "disabled");
1515 return ERROR_OK;
1518 static __COMMAND_HANDLER(handle_common_semihosting_fileio_command)
1520 struct target *target = get_current_target(CMD_CTX);
1522 if (!target) {
1523 LOG_ERROR("No target selected");
1524 return ERROR_FAIL;
1527 struct semihosting *semihosting = target->semihosting;
1528 if (!semihosting) {
1529 command_print(CMD, "semihosting not supported for current target");
1530 return ERROR_FAIL;
1533 if (!semihosting->is_active) {
1534 command_print(CMD, "semihosting not yet enabled for current target");
1535 return ERROR_FAIL;
1538 if (CMD_ARGC > 0)
1539 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->is_fileio);
1541 command_print(CMD, "semihosting fileio is %s",
1542 semihosting->is_fileio
1543 ? "enabled" : "disabled");
1545 return ERROR_OK;
1548 static __COMMAND_HANDLER(handle_common_semihosting_cmdline)
1550 struct target *target = get_current_target(CMD_CTX);
1551 unsigned int i;
1553 if (!target) {
1554 LOG_ERROR("No target selected");
1555 return ERROR_FAIL;
1558 struct semihosting *semihosting = target->semihosting;
1559 if (!semihosting) {
1560 command_print(CMD, "semihosting not supported for current target");
1561 return ERROR_FAIL;
1564 free(semihosting->cmdline);
1565 semihosting->cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL;
1567 for (i = 1; i < CMD_ARGC; i++) {
1568 char *cmdline = alloc_printf("%s %s", semihosting->cmdline, CMD_ARGV[i]);
1569 if (!cmdline)
1570 break;
1571 free(semihosting->cmdline);
1572 semihosting->cmdline = cmdline;
1575 command_print(CMD, "semihosting command line is [%s]",
1576 semihosting->cmdline);
1578 return ERROR_OK;
1581 static __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
1583 struct target *target = get_current_target(CMD_CTX);
1585 if (!target) {
1586 LOG_ERROR("No target selected");
1587 return ERROR_FAIL;
1590 struct semihosting *semihosting = target->semihosting;
1591 if (!semihosting) {
1592 command_print(CMD, "semihosting not supported for current target");
1593 return ERROR_FAIL;
1596 if (!semihosting->is_active) {
1597 command_print(CMD, "semihosting not yet enabled for current target");
1598 return ERROR_FAIL;
1601 if (CMD_ARGC > 0)
1602 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->has_resumable_exit);
1604 command_print(CMD, "semihosting resumable exit is %s",
1605 semihosting->has_resumable_exit
1606 ? "enabled" : "disabled");
1608 return ERROR_OK;
1611 const struct command_registration semihosting_common_handlers[] = {
1613 "semihosting",
1614 .handler = handle_common_semihosting_command,
1615 .mode = COMMAND_EXEC,
1616 .usage = "['enable'|'disable']",
1617 .help = "activate support for semihosting operations",
1620 "semihosting_cmdline",
1621 .handler = handle_common_semihosting_cmdline,
1622 .mode = COMMAND_EXEC,
1623 .usage = "arguments",
1624 .help = "command line arguments to be passed to program",
1627 "semihosting_fileio",
1628 .handler = handle_common_semihosting_fileio_command,
1629 .mode = COMMAND_EXEC,
1630 .usage = "['enable'|'disable']",
1631 .help = "activate support for semihosting fileio operations",
1634 "semihosting_resexit",
1635 .handler = handle_common_semihosting_resumable_exit_command,
1636 .mode = COMMAND_EXEC,
1637 .usage = "['enable'|'disable']",
1638 .help = "activate support for semihosting resumable exit",
1640 COMMAND_REGISTRATION_DONE