semihosting: use macro COMMAND_HANDLER
[openocd.git] / src / target / semihosting_common.c
1 /***************************************************************************
2 * Copyright (C) 2018 by Liviu Ionescu *
3 * <ilg@livius.net> *
4 * *
5 * Copyright (C) 2018 by Marvell Technology Group Ltd. *
6 * Written by Nicolas Pitre <nico@marvell.com> *
7 * *
8 * Copyright (C) 2010 by Spencer Oliver *
9 * spen@spen-soft.co.uk *
10 * *
11 * Copyright (C) 2016 by Square, Inc. *
12 * Steven Stallion <stallion@squareup.com> *
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
26 ***************************************************************************/
27
28 /**
29 * @file
30 * Common ARM semihosting support.
31 *
32 * Semihosting enables code running on a target to use some of the I/O
33 * facilities on the host computer. The target application must be linked
34 * against a library that forwards operation requests by using an
35 * instruction trapped by the debugger.
36 *
37 * Details can be found in
38 * "Semihosting for AArch32 and AArch64, Release 2.0"
39 * https://static.docs.arm.com/100863/0200/semihosting.pdf
40 * from ARM Ltd.
41 */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include "target.h"
48 #include "target_type.h"
49 #include "semihosting_common.h"
50
51 #include <helper/binarybuffer.h>
52 #include <helper/log.h>
53 #include <sys/stat.h>
54
55 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
68 };
69
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);
74
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);
84
85 /* Attempts to include gdb_server.h failed. */
86 extern int gdb_actual_connections;
87
88 /**
89 * Initialize common semihosting support.
90 *
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.
95 */
96 int semihosting_common_init(struct target *target, void *setup,
97 void *post_result)
98 {
99 LOG_DEBUG(" ");
100
101 target->fileio_info = malloc(sizeof(*target->fileio_info));
102 if (!target->fileio_info) {
103 LOG_ERROR("out of memory");
104 return ERROR_FAIL;
105 }
106 memset(target->fileio_info, 0, sizeof(*target->fileio_info));
107
108 struct semihosting *semihosting;
109 semihosting = malloc(sizeof(*target->semihosting));
110 if (!semihosting) {
111 LOG_ERROR("out of memory");
112 return ERROR_FAIL;
113 }
114
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;
126
127 /* If possible, update it in setup(). */
128 semihosting->setup_time = clock();
129
130 semihosting->setup = setup;
131 semihosting->post_result = post_result;
132
133 target->semihosting = semihosting;
134
135 target->type->get_gdb_fileio_info = semihosting_common_fileio_info;
136 target->type->gdb_fileio_end = semihosting_common_fileio_end;
137
138 return ERROR_OK;
139 }
140
141 /**
142 * Portable implementation of ARM semihosting calls.
143 * Performs the currently pending semihosting operation
144 * encoded in target->semihosting.
145 */
146 int semihosting_common(struct target *target)
147 {
148 struct semihosting *semihosting = target->semihosting;
149 if (!semihosting) {
150 /* Silently ignore if the semihosting field was not set. */
151 return ERROR_OK;
152 }
153
154 struct gdb_fileio_info *fileio_info = target->fileio_info;
155
156 /*
157 * By default return an error.
158 * The actual result must be set by each function
159 */
160 semihosting->result = -1;
161
162 /* Most operations are resumable, except the two exit calls. */
163 semihosting->is_resumable = true;
164
165 int retval;
166
167 /* Enough space to hold 4 long words. */
168 uint8_t fields[4*8];
169
170 LOG_DEBUG("op=0x%x, param=0x%" PRIx64, (int)semihosting->op,
171 semihosting->param);
172
173 switch (semihosting->op) {
174
175 case SEMIHOSTING_SYS_CLOCK: /* 0x10 */
176 /*
177 * Returns the number of centiseconds (hundredths of a second)
178 * since the execution started.
179 *
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.
186 *
187 * Use this function to calculate time intervals, by calculating
188 * differences between intervals with and without the code
189 * sequence to be timed.
190 *
191 * Entry
192 * The PARAMETER REGISTER must contain 0. There are no other
193 * parameters.
194 *
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.
201 */
202 {
203 clock_t delta = clock() - semihosting->setup_time;
204
205 semihosting->result = delta / (CLOCKS_PER_SEC / 100);
206 }
207 break;
208
209 case SEMIHOSTING_SYS_CLOSE: /* 0x02 */
210 /*
211 * Closes a file on the host system. The handle must reference
212 * a file that was opened with SYS_OPEN.
213 *
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.
218 *
219 * Return
220 * On exit, the RETURN REGISTER contains:
221 * - 0 if the call is successful
222 * - –1 if the call is not successful.
223 */
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;
240 }
241 break;
242 }
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);
252 }
253 }
254 break;
255
256 case SEMIHOSTING_SYS_ERRNO: /* 0x13 */
257 /*
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.
268 *
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.
272 *
273 * Entry
274 * There are no parameters. The PARAMETER REGISTER must be 0.
275 *
276 * Return
277 * On exit, the RETURN REGISTER contains the value of the C
278 * library errno variable.
279 */
280 semihosting->result = semihosting->sys_errno;
281 break;
282
283 case SEMIHOSTING_SYS_EXIT: /* 0x18 */
284 /*
285 * Note: SYS_EXIT was called angel_SWIreason_ReportException in
286 * previous versions of the documentation.
287 *
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.
291 *
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.
298 *
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:
304 *
305 * - ADP_Stopped_ApplicationExit 0x20026
306 * - ADP_Stopped_RunTimeErrorUnknown 0x20023
307 *
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.
320 *
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.
328 */
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);
336
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);
344 }
345 } else {
346 fprintf(stderr,
347 "semihosting: application exception %#x\n",
348 type);
349 }
350 }
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");
358 }
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");
367 }
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);
375 }
376 }
377 }
378 if (!semihosting->has_resumable_exit) {
379 semihosting->is_resumable = false;
380 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
381 }
382 break;
383
384 case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */
385 /*
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.
392 *
393 * The implementation must provide the semihosting call
394 * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs.
395 *
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.
400 *
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.
413 *
414 * Return
415 * No return is expected from these calls.
416 *
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.
420 */
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);
427
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);
435 }
436 } else {
437 fprintf(stderr, "semihosting: exception %#x\n",
438 type);
439 }
440 }
441 if (!semihosting->has_resumable_exit) {
442 semihosting->is_resumable = false;
443 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
444 }
445 break;
446
447 case SEMIHOSTING_SYS_FLEN: /* 0x0C */
448 /*
449 * Returns the length of a specified file.
450 *
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.
456 *
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.
462 */
463 if (semihosting->is_fileio) {
464 semihosting->result = -1;
465 semihosting->sys_errno = EINVAL;
466 }
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;
478 }
479 LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
480 semihosting->result = buf.st_size;
481 }
482 break;
483
484 case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */
485 /*
486 * Returns the command line that is used for the call to the
487 * executable, that is, argc and argv.
488 *
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.
495 *
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.
506 *
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.
511 */
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);
518
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;
531
532 retval = semihosting_write_fields(target, 2, fields);
533 if (retval != ERROR_OK)
534 return retval;
535 }
536 LOG_DEBUG("SYS_GET_CMDLINE=[%s],%d", arg,
537 (int)semihosting->result);
538 }
539 break;
540
541 case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */
542 /*
543 * Returns the system stack and heap parameters.
544 *
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 * };
556 *
557 * Return
558 * On exit, the PARAMETER REGISTER is unchanged and the data
559 * block has been updated.
560 */
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;
574 }
575 break;
576
577 case SEMIHOSTING_SYS_ISERROR: /* 0x08 */
578 /*
579 * Determines whether the return code from another semihosting
580 * call is an error status or not.
581 *
582 * This call is passed a parameter block containing the error
583 * code to examine.
584 *
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.
589 *
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.
594 */
595 retval = semihosting_read_fields(target, 1, fields);
596 if (retval != ERROR_OK)
597 return retval;
598
599 uint64_t code = semihosting_get_field(target, 0, fields);
600 semihosting->result = (code != 0);
601 break;
602
603 case SEMIHOSTING_SYS_ISTTY: /* 0x09 */
604 /*
605 * Checks whether a file is connected to an interactive device.
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 file object.
611 *
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.
617 */
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);
630 }
631 break;
632
633 case SEMIHOSTING_SYS_OPEN: /* 0x01 */
634 /*
635 * Opens a file on the host system.
636 *
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.
640 *
641 * Semihosting implementations must support opening the special
642 * path name :semihosting-features as part of the semihosting
643 * extensions reporting mechanism.
644 *
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.
656 *
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.
665 *
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.
674 *
675 * The length does not include the terminating null character
676 * that must be present.
677 *
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.
682 */
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);
690
691 if (mode > 11) {
692 semihosting->result = -1;
693 semihosting->sys_errno = EINVAL;
694 break;
695 }
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;
705 }
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;
729 }
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);
754 }
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);
765 }
766 }
767 free(fn);
768 }
769 }
770 break;
771
772 case SEMIHOSTING_SYS_READ: /* 0x06 */
773 /*
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.
779 *
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.
785 *
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.
794 *
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.
806 */
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",
829 fd,
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;
840 }
841 /* the number of bytes NOT filled in */
842 semihosting->result = len -
843 semihosting->result;
844 }
845 free(buf);
846 }
847 }
848 }
849 break;
850
851 case SEMIHOSTING_SYS_READC: /* 0x07 */
852 /*
853 * Reads a byte from the console.
854 *
855 * Entry
856 * The PARAMETER REGISTER must contain 0. There are no other
857 * parameters or values possible.
858 *
859 * Return
860 * On exit, the RETURN REGISTER contains the byte read from
861 * the console.
862 */
863 if (semihosting->is_fileio) {
864 LOG_ERROR("SYS_READC not supported by semihosting fileio");
865 return ERROR_FAIL;
866 }
867 semihosting->result = getchar();
868 LOG_DEBUG("getchar()=%d", (int)semihosting->result);
869 break;
870
871 case SEMIHOSTING_SYS_REMOVE: /* 0x0E */
872 /*
873 * Deletes a specified file on the host filing system.
874 *
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.
881 *
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.
886 */
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;
910 }
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);
916
917 free(fn);
918 }
919 }
920 }
921 break;
922
923 case SEMIHOSTING_SYS_RENAME: /* 0x0F */
924 /*
925 * Renames a specified file.
926 *
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.
935 *
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.
940 */
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;
971 }
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;
978 }
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);
986
987 free(fn1);
988 free(fn2);
989 }
990 }
991 }
992 break;
993
994 case SEMIHOSTING_SYS_SEEK: /* 0x0A */
995 /*
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.
999 *
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.
1005 *
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.
1012 *
1013 * Note: The effect of seeking outside the current extent of
1014 * the file object is undefined.
1015 */
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;
1035 }
1036 }
1037 break;
1038
1039 case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */
1040 /*
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.
1045 *
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.
1052 *
1053 * Return
1054 * On exit, the RETURN REGISTER contains the return status.
1055 */
1056
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.
1061 */
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,
1081 1,
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);
1094 }
1095
1096 free(cmd);
1097 }
1098 }
1099 }
1100 break;
1101
1102 case SEMIHOSTING_SYS_TIME: /* 0x11 */
1103 /*
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.
1107 *
1108 * Entry
1109 * There are no parameters.
1110 *
1111 * Return
1112 * On exit, the RETURN REGISTER contains the number of seconds.
1113 */
1114 semihosting->result = time(NULL);
1115 break;
1116
1117 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1118 /*
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.
1124 *
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.
1127 *
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.
1131 *
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.
1140 *
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.
1145 */
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;
1169 }
1170 semihosting->result = write(fd, buf, len);
1171 semihosting->sys_errno = errno;
1172 LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d",
1173 fd,
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;
1182 }
1183
1184 free(buf);
1185 }
1186 }
1187 }
1188 break;
1189
1190 case SEMIHOSTING_SYS_WRITEC: /* 0x03 */
1191 /*
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.
1195 *
1196 * Entry
1197 * On entry, the PARAMETER REGISTER contains a pointer to the
1198 * character.
1199 *
1200 * Return
1201 * None. The RETURN REGISTER is corrupted.
1202 */
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;
1217 }
1218 break;
1219
1220 case SEMIHOSTING_SYS_WRITE0: /* 0x04 */
1221 /*
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.
1225 *
1226 * Entry
1227 * On entry, the PARAMETER REGISTER contains a pointer to the
1228 * first byte of the string.
1229 *
1230 * Return
1231 * None. The RETURN REGISTER is corrupted.
1232 */
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++;
1244 }
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;
1262 }
1263 break;
1264
1265 case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */
1266 /*
1267 * Returns the number of elapsed target ticks since execution
1268 * started.
1269 * Use SYS_TICKFREQ to determine the tick frequency.
1270 *
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.
1276 *
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.
1281 *
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.
1290 *
1291 * Note: Some semihosting implementations might not support this
1292 * semihosting operation, and they always return -1 in the
1293 * RETURN REGISTER.
1294 */
1295
1296 case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */
1297 /*
1298 * Returns the tick frequency.
1299 *
1300 * Entry
1301 * The PARAMETER REGISTER must contain 0 on entry to this routine.
1302 *
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.
1307 *
1308 * Note: Some semihosting implementations might not support
1309 * this semihosting operation, and they always return -1 in the
1310 * RETURN REGISTER.
1311 */
1312
1313 case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */
1314 /*
1315 * Returns a temporary name for a file identified by a system
1316 * file identifier.
1317 *
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.
1326 *
1327 * Return
1328 * On exit, the RETURN REGISTER contains:
1329 * - 0 if the call is successful.
1330 * - –1 if an error occurs.
1331 *
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.
1336 *
1337 * Note: The returned string must be null-terminated.
1338 */
1339
1340 default:
1341 fprintf(stderr, "semihosting: unsupported call %#x\n",
1342 (unsigned) semihosting->op);
1343 semihosting->result = -1;
1344 semihosting->sys_errno = ENOTSUP;
1345 }
1346
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;
1352 }
1353 }
1354
1355 return ERROR_OK;
1356 }
1357
1358 /* -------------------------------------------------------------------------
1359 * Local functions. */
1360
1361 static int semihosting_common_fileio_info(struct target *target,
1362 struct gdb_fileio_info *fileio_info)
1363 {
1364 struct semihosting *semihosting = target->semihosting;
1365 if (!semihosting)
1366 return ERROR_FAIL;
1367
1368 /*
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.
1372 */
1373 if (!semihosting->is_fileio || !semihosting->hit_fileio)
1374 return ERROR_FAIL;
1375
1376 return ERROR_OK;
1377 }
1378
1379 static int semihosting_common_fileio_end(struct target *target, int result,
1380 int fileio_errno, bool ctrl_c)
1381 {
1382 struct gdb_fileio_info *fileio_info = target->fileio_info;
1383 struct semihosting *semihosting = target->semihosting;
1384 if (!semihosting)
1385 return ERROR_FAIL;
1386
1387 /* clear pending status */
1388 semihosting->hit_fileio = false;
1389
1390 semihosting->result = result;
1391 semihosting->sys_errno = fileio_errno;
1392
1393 /*
1394 * Some fileio results do not match up with what the semihosting
1395 * operation expects; for these operations, we munge the results
1396 * below:
1397 */
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;
1405
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;
1412
1413 case SEMIHOSTING_SYS_SEEK: /* 0x0a */
1414 if (result > 0)
1415 semihosting->result = 0;
1416 break;
1417 }
1418
1419 return semihosting->post_result(target);
1420 }
1421
1422 /**
1423 * Read all fields of a command from target to buffer.
1424 */
1425 static int semihosting_read_fields(struct target *target, size_t number,
1426 uint8_t *fields)
1427 {
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);
1432 }
1433
1434 /**
1435 * Write all fields of a command from buffer to target.
1436 */
1437 static int semihosting_write_fields(struct target *target, size_t number,
1438 uint8_t *fields)
1439 {
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);
1444 }
1445
1446 /**
1447 * Extract a field from the buffer, considering register size and endianness.
1448 */
1449 static uint64_t semihosting_get_field(struct target *target, size_t index,
1450 uint8_t *fields)
1451 {
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));
1457 }
1458
1459 /**
1460 * Store a field in the buffer, considering register size and endianness.
1461 */
1462 static void semihosting_set_field(struct target *target, uint64_t value,
1463 size_t index,
1464 uint8_t *fields)
1465 {
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);
1471 }
1472
1473
1474 /* -------------------------------------------------------------------------
1475 * Common semihosting commands handlers. */
1476
1477 COMMAND_HANDLER(handle_common_semihosting_command)
1478 {
1479 struct target *target = get_current_target(CMD_CTX);
1480
1481 if (!target) {
1482 LOG_ERROR("No target selected");
1483 return ERROR_FAIL;
1484 }
1485
1486 struct semihosting *semihosting = target->semihosting;
1487 if (!semihosting) {
1488 command_print(CMD, "semihosting not supported for current target");
1489 return ERROR_FAIL;
1490 }
1491
1492 if (CMD_ARGC > 0) {
1493 int is_active;
1494
1495 COMMAND_PARSE_ENABLE(CMD_ARGV[0], is_active);
1496
1497 if (!target_was_examined(target)) {
1498 LOG_ERROR("Target not examined yet");
1499 return ERROR_FAIL;
1500 }
1501
1502 if (semihosting && semihosting->setup(target, is_active) != ERROR_OK) {
1503 LOG_ERROR("Failed to Configure semihosting");
1504 return ERROR_FAIL;
1505 }
1506
1507 /* FIXME never let that "catch" be dropped! (???) */
1508 semihosting->is_active = is_active;
1509 }
1510
1511 command_print(CMD, "semihosting is %s",
1512 semihosting->is_active
1513 ? "enabled" : "disabled");
1514
1515 return ERROR_OK;
1516 }
1517
1518 COMMAND_HANDLER(handle_common_semihosting_fileio_command)
1519 {
1520 struct target *target = get_current_target(CMD_CTX);
1521
1522 if (!target) {
1523 LOG_ERROR("No target selected");
1524 return ERROR_FAIL;
1525 }
1526
1527 struct semihosting *semihosting = target->semihosting;
1528 if (!semihosting) {
1529 command_print(CMD, "semihosting not supported for current target");
1530 return ERROR_FAIL;
1531 }
1532
1533 if (!semihosting->is_active) {
1534 command_print(CMD, "semihosting not yet enabled for current target");
1535 return ERROR_FAIL;
1536 }
1537
1538 if (CMD_ARGC > 0)
1539 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->is_fileio);
1540
1541 command_print(CMD, "semihosting fileio is %s",
1542 semihosting->is_fileio
1543 ? "enabled" : "disabled");
1544
1545 return ERROR_OK;
1546 }
1547
1548 COMMAND_HANDLER(handle_common_semihosting_cmdline)
1549 {
1550 struct target *target = get_current_target(CMD_CTX);
1551 unsigned int i;
1552
1553 if (!target) {
1554 LOG_ERROR("No target selected");
1555 return ERROR_FAIL;
1556 }
1557
1558 struct semihosting *semihosting = target->semihosting;
1559 if (!semihosting) {
1560 command_print(CMD, "semihosting not supported for current target");
1561 return ERROR_FAIL;
1562 }
1563
1564 free(semihosting->cmdline);
1565 semihosting->cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL;
1566
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;
1573 }
1574
1575 command_print(CMD, "semihosting command line is [%s]",
1576 semihosting->cmdline);
1577
1578 return ERROR_OK;
1579 }
1580
1581 COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
1582 {
1583 struct target *target = get_current_target(CMD_CTX);
1584
1585 if (!target) {
1586 LOG_ERROR("No target selected");
1587 return ERROR_FAIL;
1588 }
1589
1590 struct semihosting *semihosting = target->semihosting;
1591 if (!semihosting) {
1592 command_print(CMD, "semihosting not supported for current target");
1593 return ERROR_FAIL;
1594 }
1595
1596 if (!semihosting->is_active) {
1597 command_print(CMD, "semihosting not yet enabled for current target");
1598 return ERROR_FAIL;
1599 }
1600
1601 if (CMD_ARGC > 0)
1602 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->has_resumable_exit);
1603
1604 command_print(CMD, "semihosting resumable exit is %s",
1605 semihosting->has_resumable_exit
1606 ? "enabled" : "disabled");
1607
1608 return ERROR_OK;
1609 }
1610
1611 const struct command_registration semihosting_common_handlers[] = {
1612 {
1613 "semihosting",
1614 .handler = handle_common_semihosting_command,
1615 .mode = COMMAND_EXEC,
1616 .usage = "['enable'|'disable']",
1617 .help = "activate support for semihosting operations",
1618 },
1619 {
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",
1625 },
1626 {
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",
1632 },
1633 {
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",
1639 },
1640 COMMAND_REGISTRATION_DONE
1641 };

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)