oocd_trace: drop the code, deprecated in v0.10.0
[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 == NULL) {
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 == NULL) {
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 if (semihosting->is_fileio) {
230 if (fd == 0 || fd == 1 || fd == 2) {
231 semihosting->result = 0;
232 break;
233 }
234 semihosting->hit_fileio = true;
235 fileio_info->identifier = "close";
236 fileio_info->param_1 = fd;
237 } else {
238 semihosting->result = close(fd);
239 semihosting->sys_errno = errno;
240
241 LOG_DEBUG("close(%d)=%d", fd, (int)semihosting->result);
242 }
243 }
244 break;
245
246 case SEMIHOSTING_SYS_ERRNO: /* 0x13 */
247 /*
248 * Returns the value of the C library errno variable that is
249 * associated with the semihosting implementation. The errno
250 * variable can be set by a number of C library semihosted
251 * functions, including:
252 * - SYS_REMOVE
253 * - SYS_OPEN
254 * - SYS_CLOSE
255 * - SYS_READ
256 * - SYS_WRITE
257 * - SYS_SEEK.
258 *
259 * Whether errno is set or not, and to what value, is entirely
260 * host-specific, except where the ISO C standard defines the
261 * behavior.
262 *
263 * Entry
264 * There are no parameters. The PARAMETER REGISTER must be 0.
265 *
266 * Return
267 * On exit, the RETURN REGISTER contains the value of the C
268 * library errno variable.
269 */
270 semihosting->result = semihosting->sys_errno;
271 break;
272
273 case SEMIHOSTING_SYS_EXIT: /* 0x18 */
274 /*
275 * Note: SYS_EXIT was called angel_SWIreason_ReportException in
276 * previous versions of the documentation.
277 *
278 * An application calls this operation to report an exception
279 * to the debugger directly. The most common use is to report
280 * that execution has completed, using ADP_Stopped_ApplicationExit.
281 *
282 * Note: This semihosting operation provides no means for 32-bit
283 * callers to indicate an application exit with a specified exit
284 * code. Semihosting callers may prefer to check for the presence
285 * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use
286 * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it
287 * is available.
288 *
289 * Entry (32-bit)
290 * On entry, the PARAMETER register is set to a reason code
291 * describing the cause of the trap. Not all semihosting client
292 * implementations will necessarily trap every corresponding
293 * event. Important reason codes are:
294 *
295 * - ADP_Stopped_ApplicationExit 0x20026
296 * - ADP_Stopped_RunTimeErrorUnknown 0x20023
297 *
298 * Entry (64-bit)
299 * On entry, the PARAMETER REGISTER contains a pointer to a
300 * two-field argument block:
301 * - field 1 The exception type, which is one of the set of
302 * reason codes in the above tables.
303 * - field 2 A subcode, whose meaning depends on the reason
304 * code in field 1.
305 * In particular, if field 1 is ADP_Stopped_ApplicationExit
306 * then field 2 is an exit status code, as passed to the C
307 * standard library exit() function. A simulator receiving
308 * this request must notify a connected debugger, if present,
309 * and then exit with the specified status.
310 *
311 * Return
312 * No return is expected from these calls. However, it is
313 * possible for the debugger to request that the application
314 * continues by performing an RDI_Execute request or equivalent.
315 * In this case, execution continues with the registers as they
316 * were on entry to the operation, or as subsequently modified
317 * by the debugger.
318 */
319 if (semihosting->word_size_bytes == 8) {
320 retval = semihosting_read_fields(target, 2, fields);
321 if (retval != ERROR_OK)
322 return retval;
323 else {
324 int type = semihosting_get_field(target, 0, fields);
325 int code = semihosting_get_field(target, 1, fields);
326
327 if (type == ADP_STOPPED_APPLICATION_EXIT) {
328 if (!gdb_actual_connections)
329 exit(code);
330 else {
331 fprintf(stderr,
332 "semihosting: *** application exited with %d ***\n",
333 code);
334 }
335 } else {
336 fprintf(stderr,
337 "semihosting: application exception %#x\n",
338 type);
339 }
340 }
341 } else {
342 if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) {
343 if (!gdb_actual_connections)
344 exit(0);
345 else {
346 fprintf(stderr,
347 "semihosting: *** application exited normally ***\n");
348 }
349 } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) {
350 /* Chosen more or less arbitrarily to have a nicer message,
351 * otherwise all other return the same exit code 1. */
352 if (!gdb_actual_connections)
353 exit(1);
354 else {
355 fprintf(stderr,
356 "semihosting: *** application exited with error ***\n");
357 }
358 } else {
359 if (!gdb_actual_connections)
360 exit(1);
361 else {
362 fprintf(stderr,
363 "semihosting: application exception %#x\n",
364 (unsigned) semihosting->param);
365 }
366 }
367 }
368 if (!semihosting->has_resumable_exit) {
369 semihosting->is_resumable = false;
370 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
371 }
372 break;
373
374 case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */
375 /*
376 * This operation is only supported if the semihosting extension
377 * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is
378 * reported using feature byte 0, bit 0. If this extension is
379 * supported, then the implementation provides a means to
380 * report a normal exit with a nonzero exit status in both 32-bit
381 * and 64-bit semihosting APIs.
382 *
383 * The implementation must provide the semihosting call
384 * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs.
385 *
386 * SYS_EXIT_EXTENDED is used by an application to report an
387 * exception or exit to the debugger directly. The most common
388 * use is to report that execution has completed, using
389 * ADP_Stopped_ApplicationExit.
390 *
391 * Entry
392 * On entry, the PARAMETER REGISTER contains a pointer to a
393 * two-field argument block:
394 * - field 1 The exception type, which should be one of the set
395 * of reason codes that are documented for the SYS_EXIT
396 * (0x18) call. For example, ADP_Stopped_ApplicationExit.
397 * - field 2 A subcode, whose meaning depends on the reason
398 * code in field 1. In particular, if field 1 is
399 * ADP_Stopped_ApplicationExit then field 2 is an exit status
400 * code, as passed to the C standard library exit() function.
401 * A simulator receiving this request must notify a connected
402 * debugger, if present, and then exit with the specified status.
403 *
404 * Return
405 * No return is expected from these calls.
406 *
407 * For the A64 API, this call is identical to the behavior of
408 * the mandatory SYS_EXIT (0x18) call. If this extension is
409 * supported, then both calls must be implemented.
410 */
411 retval = semihosting_read_fields(target, 2, fields);
412 if (retval != ERROR_OK)
413 return retval;
414 else {
415 int type = semihosting_get_field(target, 0, fields);
416 int code = semihosting_get_field(target, 1, fields);
417
418 if (type == ADP_STOPPED_APPLICATION_EXIT) {
419 if (!gdb_actual_connections)
420 exit(code);
421 else {
422 fprintf(stderr,
423 "semihosting: *** application exited with %d ***\n",
424 code);
425 }
426 } else {
427 fprintf(stderr, "semihosting: exception %#x\n",
428 type);
429 }
430 }
431 if (!semihosting->has_resumable_exit) {
432 semihosting->is_resumable = false;
433 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
434 }
435 break;
436
437 case SEMIHOSTING_SYS_FLEN: /* 0x0C */
438 /*
439 * Returns the length of a specified file.
440 *
441 * Entry
442 * On entry, the PARAMETER REGISTER contains a pointer to a
443 * one-field argument block:
444 * - field 1 A handle for a previously opened, seekable file
445 * object.
446 *
447 * Return
448 * On exit, the RETURN REGISTER contains:
449 * - The current length of the file object, if the call is
450 * successful.
451 * - –1 if an error occurs.
452 */
453 if (semihosting->is_fileio) {
454 semihosting->result = -1;
455 semihosting->sys_errno = EINVAL;
456 }
457 retval = semihosting_read_fields(target, 1, fields);
458 if (retval != ERROR_OK)
459 return retval;
460 else {
461 int fd = semihosting_get_field(target, 0, fields);
462 struct stat buf;
463 semihosting->result = fstat(fd, &buf);
464 if (semihosting->result == -1) {
465 semihosting->sys_errno = errno;
466 LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
467 break;
468 }
469 LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result);
470 semihosting->result = buf.st_size;
471 }
472 break;
473
474 case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */
475 /*
476 * Returns the command line that is used for the call to the
477 * executable, that is, argc and argv.
478 *
479 * Entry
480 * On entry, the PARAMETER REGISTER points to a two-field data
481 * block to be used for returning the command string and its length:
482 * - field 1 A pointer to a buffer of at least the size that is
483 * specified in field 2.
484 * - field 2 The length of the buffer in bytes.
485 *
486 * Return
487 * On exit:
488 * If the call is successful, then the RETURN REGISTER contains 0,
489 * the PARAMETER REGISTER is unchanged, and the data block is
490 * updated as follows:
491 * - field 1 A pointer to a null-terminated string of the command
492 * line.
493 * - field 2 The length of the string in bytes.
494 * If the call is not successful, then the RETURN REGISTER
495 * contains -1.
496 *
497 * Note: The semihosting implementation might impose limits on
498 * the maximum length of the string that can be transferred.
499 * However, the implementation must be able to support a
500 * command-line length of at least 80 bytes.
501 */
502 retval = semihosting_read_fields(target, 2, fields);
503 if (retval != ERROR_OK)
504 return retval;
505 else {
506 uint64_t addr = semihosting_get_field(target, 0, fields);
507 size_t size = semihosting_get_field(target, 1, fields);
508
509 char *arg = semihosting->cmdline != NULL ?
510 semihosting->cmdline : "";
511 uint32_t len = strlen(arg) + 1;
512 if (len > size)
513 semihosting->result = -1;
514 else {
515 semihosting_set_field(target, len, 1, fields);
516 retval = target_write_buffer(target, addr, len,
517 (uint8_t *)arg);
518 if (retval != ERROR_OK)
519 return retval;
520 semihosting->result = 0;
521
522 retval = semihosting_write_fields(target, 2, fields);
523 if (retval != ERROR_OK)
524 return retval;
525 }
526 LOG_DEBUG("SYS_GET_CMDLINE=[%s],%d", arg,
527 (int)semihosting->result);
528 }
529 break;
530
531 case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */
532 /*
533 * Returns the system stack and heap parameters.
534 *
535 * Entry
536 * On entry, the PARAMETER REGISTER contains the address of a
537 * pointer to a four-field data block. The contents of the data
538 * block are filled by the function. The following C-like
539 * pseudocode describes the layout of the block:
540 * struct block {
541 * void* heap_base;
542 * void* heap_limit;
543 * void* stack_base;
544 * void* stack_limit;
545 * };
546 *
547 * Return
548 * On exit, the PARAMETER REGISTER is unchanged and the data
549 * block has been updated.
550 */
551 retval = semihosting_read_fields(target, 1, fields);
552 if (retval != ERROR_OK)
553 return retval;
554 else {
555 uint64_t addr = semihosting_get_field(target, 0, fields);
556 /* tell the remote we have no idea */
557 memset(fields, 0, 4 * semihosting->word_size_bytes);
558 retval = target_write_memory(target, addr, 4,
559 semihosting->word_size_bytes,
560 fields);
561 if (retval != ERROR_OK)
562 return retval;
563 semihosting->result = 0;
564 }
565 break;
566
567 case SEMIHOSTING_SYS_ISERROR: /* 0x08 */
568 /*
569 * Determines whether the return code from another semihosting
570 * call is an error status or not.
571 *
572 * This call is passed a parameter block containing the error
573 * code to examine.
574 *
575 * Entry
576 * On entry, the PARAMETER REGISTER contains a pointer to a
577 * one-field data block:
578 * - field 1 The required status word to check.
579 *
580 * Return
581 * On exit, the RETURN REGISTER contains:
582 * - 0 if the status field is not an error indication
583 * - A nonzero value if the status field is an error indication.
584 */
585 retval = semihosting_read_fields(target, 1, fields);
586 if (retval != ERROR_OK)
587 return retval;
588
589 uint64_t code = semihosting_get_field(target, 0, fields);
590 semihosting->result = (code != 0);
591 break;
592
593 case SEMIHOSTING_SYS_ISTTY: /* 0x09 */
594 /*
595 * Checks whether a file is connected to an interactive device.
596 *
597 * Entry
598 * On entry, the PARAMETER REGISTER contains a pointer to a
599 * one-field argument block:
600 * field 1 A handle for a previously opened file object.
601 *
602 * Return
603 * On exit, the RETURN REGISTER contains:
604 * - 1 if the handle identifies an interactive device.
605 * - 0 if the handle identifies a file.
606 * - A value other than 1 or 0 if an error occurs.
607 */
608 if (semihosting->is_fileio) {
609 semihosting->hit_fileio = true;
610 fileio_info->identifier = "isatty";
611 fileio_info->param_1 = semihosting->param;
612 } else {
613 retval = semihosting_read_fields(target, 1, fields);
614 if (retval != ERROR_OK)
615 return retval;
616 int fd = semihosting_get_field(target, 0, fields);
617 semihosting->result = isatty(fd);
618 LOG_DEBUG("isatty(%d)=%d", fd, (int)semihosting->result);
619 }
620 break;
621
622 case SEMIHOSTING_SYS_OPEN: /* 0x01 */
623 /*
624 * Opens a file on the host system.
625 *
626 * The file path is specified either as relative to the current
627 * directory of the host process, or absolute, using the path
628 * conventions of the host operating system.
629 *
630 * Semihosting implementations must support opening the special
631 * path name :semihosting-features as part of the semihosting
632 * extensions reporting mechanism.
633 *
634 * ARM targets interpret the special path name :tt as meaning
635 * the console input stream, for an open-read or the console
636 * output stream, for an open-write. Opening these streams is
637 * performed as part of the standard startup code for those
638 * applications that reference the C stdio streams. The
639 * semihosting extension SH_EXT_STDOUT_STDERR allows the
640 * semihosting caller to open separate output streams
641 * corresponding to stdout and stderr. This extension is
642 * reported using feature byte 0, bit 1. Use SYS_OPEN with
643 * the special path name :semihosting-features to access the
644 * feature bits.
645 *
646 * If this extension is supported, the implementation must
647 * support the following additional semantics to SYS_OPEN:
648 * - If the special path name :tt is opened with an fopen
649 * mode requesting write access (w, wb, w+, or w+b), then
650 * this is a request to open stdout.
651 * - If the special path name :tt is opened with a mode
652 * requesting append access (a, ab, a+, or a+b), then this is
653 * a request to open stderr.
654 *
655 * Entry
656 * On entry, the PARAMETER REGISTER contains a pointer to a
657 * three-field argument block:
658 * - field 1 A pointer to a null-terminated string containing
659 * a file or device name.
660 * - field 2 An integer that specifies the file opening mode.
661 * - field 3 An integer that gives the length of the string
662 * pointed to by field 1.
663 *
664 * The length does not include the terminating null character
665 * that must be present.
666 *
667 * Return
668 * On exit, the RETURN REGISTER contains:
669 * - A nonzero handle if the call is successful.
670 * - –1 if the call is not successful.
671 */
672 retval = semihosting_read_fields(target, 3, fields);
673 if (retval != ERROR_OK)
674 return retval;
675 else {
676 uint64_t addr = semihosting_get_field(target, 0, fields);
677 uint32_t mode = semihosting_get_field(target, 1, fields);
678 size_t len = semihosting_get_field(target, 2, fields);
679
680 if (mode > 11) {
681 semihosting->result = -1;
682 semihosting->sys_errno = EINVAL;
683 break;
684 }
685 uint8_t *fn = malloc(len+1);
686 if (!fn) {
687 semihosting->result = -1;
688 semihosting->sys_errno = ENOMEM;
689 } else {
690 retval = target_read_memory(target, addr, 1, len, fn);
691 if (retval != ERROR_OK) {
692 free(fn);
693 return retval;
694 }
695 fn[len] = 0;
696 /* TODO: implement the :semihosting-features special file.
697 * */
698 if (semihosting->is_fileio) {
699 if (strcmp((char *)fn, ":semihosting-features") == 0) {
700 semihosting->result = -1;
701 semihosting->sys_errno = EINVAL;
702 } else if (strcmp((char *)fn, ":tt") == 0) {
703 if (mode == 0)
704 semihosting->result = 0;
705 else if (mode == 4)
706 semihosting->result = 1;
707 else if (mode == 8)
708 semihosting->result = 2;
709 else
710 semihosting->result = -1;
711 } else {
712 semihosting->hit_fileio = true;
713 fileio_info->identifier = "open";
714 fileio_info->param_1 = addr;
715 fileio_info->param_2 = len;
716 fileio_info->param_3 = open_modeflags[mode];
717 fileio_info->param_4 = 0644;
718 }
719 } else {
720 if (strcmp((char *)fn, ":tt") == 0) {
721 /* Mode is:
722 * - 0-3 ("r") for stdin,
723 * - 4-7 ("w") for stdout,
724 * - 8-11 ("a") for stderr */
725 if (mode < 4) {
726 semihosting->result = dup(
727 STDIN_FILENO);
728 semihosting->sys_errno = errno;
729 LOG_DEBUG("dup(STDIN)=%d",
730 (int)semihosting->result);
731 } else if (mode < 8) {
732 semihosting->result = dup(
733 STDOUT_FILENO);
734 semihosting->sys_errno = errno;
735 LOG_DEBUG("dup(STDOUT)=%d",
736 (int)semihosting->result);
737 } else {
738 semihosting->result = dup(
739 STDERR_FILENO);
740 semihosting->sys_errno = errno;
741 LOG_DEBUG("dup(STDERR)=%d",
742 (int)semihosting->result);
743 }
744 } else {
745 /* cygwin requires the permission setting
746 * otherwise it will fail to reopen a previously
747 * written file */
748 semihosting->result = open((char *)fn,
749 open_modeflags[mode],
750 0644);
751 semihosting->sys_errno = errno;
752 LOG_DEBUG("open('%s')=%d", fn,
753 (int)semihosting->result);
754 }
755 }
756 free(fn);
757 }
758 }
759 break;
760
761 case SEMIHOSTING_SYS_READ: /* 0x06 */
762 /*
763 * Reads the contents of a file into a buffer. The file position
764 * is specified either:
765 * - Explicitly by a SYS_SEEK.
766 * - Implicitly one byte beyond the previous SYS_READ or
767 * SYS_WRITE request.
768 *
769 * The file position is at the start of the file when it is
770 * opened, and is lost when the file is closed. Perform the
771 * file operation as a single action whenever possible. For
772 * example, do not split a read of 16KB into four 4KB chunks
773 * unless there is no alternative.
774 *
775 * Entry
776 * On entry, the PARAMETER REGISTER contains a pointer to a
777 * three-field data block:
778 * - field 1 Contains a handle for a file previously opened
779 * with SYS_OPEN.
780 * - field 2 Points to a buffer.
781 * - field 3 Contains the number of bytes to read to the buffer
782 * from the file.
783 *
784 * Return
785 * On exit, the RETURN REGISTER contains the number of bytes not
786 * filled in the buffer (buffer_length - bytes_read) as follows:
787 * - If the RETURN REGISTER is 0, the entire buffer was
788 * successfully filled.
789 * - If the RETURN REGISTER is the same as field 3, no bytes
790 * were read (EOF can be assumed).
791 * - If the RETURN REGISTER contains a value smaller than
792 * field 3, the read succeeded but the buffer was only partly
793 * filled. For interactive devices, this is the most common
794 * return value.
795 */
796 retval = semihosting_read_fields(target, 3, fields);
797 if (retval != ERROR_OK)
798 return retval;
799 else {
800 int fd = semihosting_get_field(target, 0, fields);
801 uint64_t addr = semihosting_get_field(target, 1, fields);
802 size_t len = semihosting_get_field(target, 2, fields);
803 if (semihosting->is_fileio) {
804 semihosting->hit_fileio = true;
805 fileio_info->identifier = "read";
806 fileio_info->param_1 = fd;
807 fileio_info->param_2 = addr;
808 fileio_info->param_3 = len;
809 } else {
810 uint8_t *buf = malloc(len);
811 if (!buf) {
812 semihosting->result = -1;
813 semihosting->sys_errno = ENOMEM;
814 } else {
815 semihosting->result = read(fd, buf, len);
816 semihosting->sys_errno = errno;
817 LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d",
818 fd,
819 addr,
820 len,
821 (int)semihosting->result);
822 if (semihosting->result >= 0) {
823 retval = target_write_buffer(target, addr,
824 semihosting->result,
825 buf);
826 if (retval != ERROR_OK) {
827 free(buf);
828 return retval;
829 }
830 /* the number of bytes NOT filled in */
831 semihosting->result = len -
832 semihosting->result;
833 }
834 free(buf);
835 }
836 }
837 }
838 break;
839
840 case SEMIHOSTING_SYS_READC: /* 0x07 */
841 /*
842 * Reads a byte from the console.
843 *
844 * Entry
845 * The PARAMETER REGISTER must contain 0. There are no other
846 * parameters or values possible.
847 *
848 * Return
849 * On exit, the RETURN REGISTER contains the byte read from
850 * the console.
851 */
852 if (semihosting->is_fileio) {
853 LOG_ERROR("SYS_READC not supported by semihosting fileio");
854 return ERROR_FAIL;
855 }
856 semihosting->result = getchar();
857 LOG_DEBUG("getchar()=%d", (int)semihosting->result);
858 break;
859
860 case SEMIHOSTING_SYS_REMOVE: /* 0x0E */
861 /*
862 * Deletes a specified file on the host filing system.
863 *
864 * Entry
865 * On entry, the PARAMETER REGISTER contains a pointer to a
866 * two-field argument block:
867 * - field 1 Points to a null-terminated string that gives the
868 * path name of the file to be deleted.
869 * - field 2 The length of the string.
870 *
871 * Return
872 * On exit, the RETURN REGISTER contains:
873 * - 0 if the delete is successful
874 * - A nonzero, host-specific error code if the delete fails.
875 */
876 retval = semihosting_read_fields(target, 2, fields);
877 if (retval != ERROR_OK)
878 return retval;
879 else {
880 uint64_t addr = semihosting_get_field(target, 0, fields);
881 size_t len = semihosting_get_field(target, 1, fields);
882 if (semihosting->is_fileio) {
883 semihosting->hit_fileio = true;
884 fileio_info->identifier = "unlink";
885 fileio_info->param_1 = addr;
886 fileio_info->param_2 = len;
887 } else {
888 uint8_t *fn = malloc(len+1);
889 if (!fn) {
890 semihosting->result = -1;
891 semihosting->sys_errno = ENOMEM;
892 } else {
893 retval =
894 target_read_memory(target, addr, 1, len,
895 fn);
896 if (retval != ERROR_OK) {
897 free(fn);
898 return retval;
899 }
900 fn[len] = 0;
901 semihosting->result = remove((char *)fn);
902 semihosting->sys_errno = errno;
903 LOG_DEBUG("remove('%s')=%d", fn,
904 (int)semihosting->result);
905
906 free(fn);
907 }
908 }
909 }
910 break;
911
912 case SEMIHOSTING_SYS_RENAME: /* 0x0F */
913 /*
914 * Renames a specified file.
915 *
916 * Entry
917 * On entry, the PARAMETER REGISTER contains a pointer to a
918 * four-field data block:
919 * - field 1 A pointer to the name of the old file.
920 * - field 2 The length of the old filename.
921 * - field 3 A pointer to the new filename.
922 * - field 4 The length of the new filename. Both strings are
923 * null-terminated.
924 *
925 * Return
926 * On exit, the RETURN REGISTER contains:
927 * - 0 if the rename is successful.
928 * - A nonzero, host-specific error code if the rename fails.
929 */
930 retval = semihosting_read_fields(target, 4, fields);
931 if (retval != ERROR_OK)
932 return retval;
933 else {
934 uint64_t addr1 = semihosting_get_field(target, 0, fields);
935 size_t len1 = semihosting_get_field(target, 1, fields);
936 uint64_t addr2 = semihosting_get_field(target, 2, fields);
937 size_t len2 = semihosting_get_field(target, 3, fields);
938 if (semihosting->is_fileio) {
939 semihosting->hit_fileio = true;
940 fileio_info->identifier = "rename";
941 fileio_info->param_1 = addr1;
942 fileio_info->param_2 = len1;
943 fileio_info->param_3 = addr2;
944 fileio_info->param_4 = len2;
945 } else {
946 uint8_t *fn1 = malloc(len1+1);
947 uint8_t *fn2 = malloc(len2+1);
948 if (!fn1 || !fn2) {
949 free(fn1);
950 free(fn2);
951 semihosting->result = -1;
952 semihosting->sys_errno = ENOMEM;
953 } else {
954 retval = target_read_memory(target, addr1, 1, len1,
955 fn1);
956 if (retval != ERROR_OK) {
957 free(fn1);
958 free(fn2);
959 return retval;
960 }
961 retval = target_read_memory(target, addr2, 1, len2,
962 fn2);
963 if (retval != ERROR_OK) {
964 free(fn1);
965 free(fn2);
966 return retval;
967 }
968 fn1[len1] = 0;
969 fn2[len2] = 0;
970 semihosting->result = rename((char *)fn1,
971 (char *)fn2);
972 semihosting->sys_errno = errno;
973 LOG_DEBUG("rename('%s', '%s')=%d", fn1, fn2,
974 (int)semihosting->result);
975
976 free(fn1);
977 free(fn2);
978 }
979 }
980 }
981 break;
982
983 case SEMIHOSTING_SYS_SEEK: /* 0x0A */
984 /*
985 * Seeks to a specified position in a file using an offset
986 * specified from the start of the file. The file is assumed
987 * to be a byte array and the offset is given in bytes.
988 *
989 * Entry
990 * On entry, the PARAMETER REGISTER contains a pointer to a
991 * two-field data block:
992 * - field 1 A handle for a seekable file object.
993 * - field 2 The absolute byte position to seek to.
994 *
995 * Return
996 * On exit, the RETURN REGISTER contains:
997 * - 0 if the request is successful.
998 * - A negative value if the request is not successful.
999 * Use SYS_ERRNO to read the value of the host errno variable
1000 * describing the error.
1001 *
1002 * Note: The effect of seeking outside the current extent of
1003 * the file object is undefined.
1004 */
1005 retval = semihosting_read_fields(target, 2, fields);
1006 if (retval != ERROR_OK)
1007 return retval;
1008 else {
1009 int fd = semihosting_get_field(target, 0, fields);
1010 off_t pos = semihosting_get_field(target, 1, fields);
1011 if (semihosting->is_fileio) {
1012 semihosting->hit_fileio = true;
1013 fileio_info->identifier = "lseek";
1014 fileio_info->param_1 = fd;
1015 fileio_info->param_2 = pos;
1016 fileio_info->param_3 = SEEK_SET;
1017 } else {
1018 semihosting->result = lseek(fd, pos, SEEK_SET);
1019 semihosting->sys_errno = errno;
1020 LOG_DEBUG("lseek(%d, %d)=%d", fd, (int)pos,
1021 (int)semihosting->result);
1022 if (semihosting->result == pos)
1023 semihosting->result = 0;
1024 }
1025 }
1026 break;
1027
1028 case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */
1029 /*
1030 * Passes a command to the host command-line interpreter.
1031 * This enables you to execute a system command such as dir,
1032 * ls, or pwd. The terminal I/O is on the host, and is not
1033 * visible to the target.
1034 *
1035 * Entry
1036 * On entry, the PARAMETER REGISTER contains a pointer to a
1037 * two-field argument block:
1038 * - field 1 Points to a string to be passed to the host
1039 * command-line interpreter.
1040 * - field 2 The length of the string.
1041 *
1042 * Return
1043 * On exit, the RETURN REGISTER contains the return status.
1044 */
1045
1046 /* Provide SYS_SYSTEM functionality. Uses the
1047 * libc system command, there may be a reason *NOT*
1048 * to use this, but as I can't think of one, I
1049 * implemented it this way.
1050 */
1051 retval = semihosting_read_fields(target, 2, fields);
1052 if (retval != ERROR_OK)
1053 return retval;
1054 else {
1055 uint64_t addr = semihosting_get_field(target, 0, fields);
1056 size_t len = semihosting_get_field(target, 1, fields);
1057 if (semihosting->is_fileio) {
1058 semihosting->hit_fileio = true;
1059 fileio_info->identifier = "system";
1060 fileio_info->param_1 = addr;
1061 fileio_info->param_2 = len;
1062 } else {
1063 uint8_t *cmd = malloc(len+1);
1064 if (!cmd) {
1065 semihosting->result = -1;
1066 semihosting->sys_errno = ENOMEM;
1067 } else {
1068 retval = target_read_memory(target,
1069 addr,
1070 1,
1071 len,
1072 cmd);
1073 if (retval != ERROR_OK) {
1074 free(cmd);
1075 return retval;
1076 } else {
1077 cmd[len] = 0;
1078 semihosting->result = system(
1079 (const char *)cmd);
1080 LOG_DEBUG("system('%s')=%d",
1081 cmd,
1082 (int)semihosting->result);
1083 }
1084
1085 free(cmd);
1086 }
1087 }
1088 }
1089 break;
1090
1091 case SEMIHOSTING_SYS_TIME: /* 0x11 */
1092 /*
1093 * Returns the number of seconds since 00:00 January 1, 1970.
1094 * This value is real-world time, regardless of any debug agent
1095 * configuration.
1096 *
1097 * Entry
1098 * There are no parameters.
1099 *
1100 * Return
1101 * On exit, the RETURN REGISTER contains the number of seconds.
1102 */
1103 semihosting->result = time(NULL);
1104 break;
1105
1106 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1107 /*
1108 * Writes the contents of a buffer to a specified file at the
1109 * current file position. The file position is specified either:
1110 * - Explicitly, by a SYS_SEEK.
1111 * - Implicitly as one byte beyond the previous SYS_READ or
1112 * SYS_WRITE request.
1113 *
1114 * The file position is at the start of the file when the file
1115 * is opened, and is lost when the file is closed.
1116 *
1117 * Perform the file operation as a single action whenever
1118 * possible. For example, do not split a write of 16KB into
1119 * four 4KB chunks unless there is no alternative.
1120 *
1121 * Entry
1122 * On entry, the PARAMETER REGISTER contains a pointer to a
1123 * three-field data block:
1124 * - field 1 Contains a handle for a file previously opened
1125 * with SYS_OPEN.
1126 * - field 2 Points to the memory containing the data to be written.
1127 * - field 3 Contains the number of bytes to be written from
1128 * the buffer to the file.
1129 *
1130 * Return
1131 * On exit, the RETURN REGISTER contains:
1132 * - 0 if the call is successful.
1133 * - The number of bytes that are not written, if there is an error.
1134 */
1135 retval = semihosting_read_fields(target, 3, fields);
1136 if (retval != ERROR_OK)
1137 return retval;
1138 else {
1139 int fd = semihosting_get_field(target, 0, fields);
1140 uint64_t addr = semihosting_get_field(target, 1, fields);
1141 size_t len = semihosting_get_field(target, 2, fields);
1142 if (semihosting->is_fileio) {
1143 semihosting->hit_fileio = true;
1144 fileio_info->identifier = "write";
1145 fileio_info->param_1 = fd;
1146 fileio_info->param_2 = addr;
1147 fileio_info->param_3 = len;
1148 } else {
1149 uint8_t *buf = malloc(len);
1150 if (!buf) {
1151 semihosting->result = -1;
1152 semihosting->sys_errno = ENOMEM;
1153 } else {
1154 retval = target_read_buffer(target, addr, len, buf);
1155 if (retval != ERROR_OK) {
1156 free(buf);
1157 return retval;
1158 }
1159 semihosting->result = write(fd, buf, len);
1160 semihosting->sys_errno = errno;
1161 LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d",
1162 fd,
1163 addr,
1164 len,
1165 (int)semihosting->result);
1166 if (semihosting->result >= 0) {
1167 /* The number of bytes that are NOT written.
1168 * */
1169 semihosting->result = len -
1170 semihosting->result;
1171 }
1172
1173 free(buf);
1174 }
1175 }
1176 }
1177 break;
1178
1179 case SEMIHOSTING_SYS_WRITEC: /* 0x03 */
1180 /*
1181 * Writes a character byte, pointed to by the PARAMETER REGISTER,
1182 * to the debug channel. When executed under a semihosting
1183 * debugger, the character appears on the host debugger console.
1184 *
1185 * Entry
1186 * On entry, the PARAMETER REGISTER contains a pointer to the
1187 * character.
1188 *
1189 * Return
1190 * None. The RETURN REGISTER is corrupted.
1191 */
1192 if (semihosting->is_fileio) {
1193 semihosting->hit_fileio = true;
1194 fileio_info->identifier = "write";
1195 fileio_info->param_1 = 1;
1196 fileio_info->param_2 = semihosting->param;
1197 fileio_info->param_3 = 1;
1198 } else {
1199 uint64_t addr = semihosting->param;
1200 unsigned char c;
1201 retval = target_read_memory(target, addr, 1, 1, &c);
1202 if (retval != ERROR_OK)
1203 return retval;
1204 putchar(c);
1205 semihosting->result = 0;
1206 }
1207 break;
1208
1209 case SEMIHOSTING_SYS_WRITE0: /* 0x04 */
1210 /*
1211 * Writes a null-terminated string to the debug channel.
1212 * When executed under a semihosting debugger, the characters
1213 * appear on the host debugger console.
1214 *
1215 * Entry
1216 * On entry, the PARAMETER REGISTER contains a pointer to the
1217 * first byte of the string.
1218 *
1219 * Return
1220 * None. The RETURN REGISTER is corrupted.
1221 */
1222 if (semihosting->is_fileio) {
1223 size_t count = 0;
1224 uint64_t addr = semihosting->param;
1225 for (;; addr++) {
1226 unsigned char c;
1227 retval = target_read_memory(target, addr, 1, 1, &c);
1228 if (retval != ERROR_OK)
1229 return retval;
1230 if (c == '\0')
1231 break;
1232 count++;
1233 }
1234 semihosting->hit_fileio = true;
1235 fileio_info->identifier = "write";
1236 fileio_info->param_1 = 1;
1237 fileio_info->param_2 = semihosting->param;
1238 fileio_info->param_3 = count;
1239 } else {
1240 uint64_t addr = semihosting->param;
1241 do {
1242 unsigned char c;
1243 retval = target_read_memory(target, addr++, 1, 1, &c);
1244 if (retval != ERROR_OK)
1245 return retval;
1246 if (!c)
1247 break;
1248 putchar(c);
1249 } while (1);
1250 semihosting->result = 0;
1251 }
1252 break;
1253
1254 case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */
1255 /*
1256 * Returns the number of elapsed target ticks since execution
1257 * started.
1258 * Use SYS_TICKFREQ to determine the tick frequency.
1259 *
1260 * Entry (32-bit)
1261 * On entry, the PARAMETER REGISTER points to a two-field data
1262 * block to be used for returning the number of elapsed ticks:
1263 * - field 1 The least significant field and is at the low address.
1264 * - field 2 The most significant field and is at the high address.
1265 *
1266 * Entry (64-bit)
1267 * On entry the PARAMETER REGISTER points to a one-field data
1268 * block to be used for returning the number of elapsed ticks:
1269 * - field 1 The number of elapsed ticks as a 64-bit value.
1270 *
1271 * Return
1272 * On exit:
1273 * - On success, the RETURN REGISTER contains 0, the PARAMETER
1274 * REGISTER is unchanged, and the data block pointed to by the
1275 * PARAMETER REGISTER is filled in with the number of elapsed
1276 * ticks.
1277 * - On failure, the RETURN REGISTER contains -1, and the
1278 * PARAMETER REGISTER contains -1.
1279 *
1280 * Note: Some semihosting implementations might not support this
1281 * semihosting operation, and they always return -1 in the
1282 * RETURN REGISTER.
1283 */
1284
1285 case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */
1286 /*
1287 * Returns the tick frequency.
1288 *
1289 * Entry
1290 * The PARAMETER REGISTER must contain 0 on entry to this routine.
1291 *
1292 * Return
1293 * On exit, the RETURN REGISTER contains either:
1294 * - The number of ticks per second.
1295 * - –1 if the target does not know the value of one tick.
1296 *
1297 * Note: Some semihosting implementations might not support
1298 * this semihosting operation, and they always return -1 in the
1299 * RETURN REGISTER.
1300 */
1301
1302 case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */
1303 /*
1304 * Returns a temporary name for a file identified by a system
1305 * file identifier.
1306 *
1307 * Entry
1308 * On entry, the PARAMETER REGISTER contains a pointer to a
1309 * three-word argument block:
1310 * - field 1 A pointer to a buffer.
1311 * - field 2 A target identifier for this filename. Its value
1312 * must be an integer in the range 0-255.
1313 * - field 3 Contains the length of the buffer. The length must
1314 * be at least the value of L_tmpnam on the host system.
1315 *
1316 * Return
1317 * On exit, the RETURN REGISTER contains:
1318 * - 0 if the call is successful.
1319 * - –1 if an error occurs.
1320 *
1321 * The buffer pointed to by the PARAMETER REGISTER contains
1322 * the filename, prefixed with a suitable directory name.
1323 * If you use the same target identifier again, the same
1324 * filename is returned.
1325 *
1326 * Note: The returned string must be null-terminated.
1327 */
1328
1329 default:
1330 fprintf(stderr, "semihosting: unsupported call %#x\n",
1331 (unsigned) semihosting->op);
1332 semihosting->result = -1;
1333 semihosting->sys_errno = ENOTSUP;
1334 }
1335
1336 if (!semihosting->hit_fileio) {
1337 retval = semihosting->post_result(target);
1338 if (retval != ERROR_OK) {
1339 LOG_ERROR("Failed to post semihosting result");
1340 return retval;
1341 }
1342 }
1343
1344 return ERROR_OK;
1345 }
1346
1347 /* -------------------------------------------------------------------------
1348 * Local functions. */
1349
1350 static int semihosting_common_fileio_info(struct target *target,
1351 struct gdb_fileio_info *fileio_info)
1352 {
1353 struct semihosting *semihosting = target->semihosting;
1354 if (!semihosting)
1355 return ERROR_FAIL;
1356
1357 /*
1358 * To avoid unnecessary duplication, semihosting prepares the
1359 * fileio_info structure out-of-band when the target halts. See
1360 * do_semihosting for more detail.
1361 */
1362 if (!semihosting->is_fileio || !semihosting->hit_fileio)
1363 return ERROR_FAIL;
1364
1365 return ERROR_OK;
1366 }
1367
1368 static int semihosting_common_fileio_end(struct target *target, int result,
1369 int fileio_errno, bool ctrl_c)
1370 {
1371 struct gdb_fileio_info *fileio_info = target->fileio_info;
1372 struct semihosting *semihosting = target->semihosting;
1373 if (!semihosting)
1374 return ERROR_FAIL;
1375
1376 /* clear pending status */
1377 semihosting->hit_fileio = false;
1378
1379 semihosting->result = result;
1380 semihosting->sys_errno = fileio_errno;
1381
1382 /*
1383 * Some fileio results do not match up with what the semihosting
1384 * operation expects; for these operations, we munge the results
1385 * below:
1386 */
1387 switch (semihosting->op) {
1388 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1389 if (result < 0)
1390 semihosting->result = fileio_info->param_3;
1391 else
1392 semihosting->result = 0;
1393 break;
1394
1395 case SEMIHOSTING_SYS_READ: /* 0x06 */
1396 if (result == (int)fileio_info->param_3)
1397 semihosting->result = 0;
1398 if (result <= 0)
1399 semihosting->result = fileio_info->param_3;
1400 break;
1401
1402 case SEMIHOSTING_SYS_SEEK: /* 0x0a */
1403 if (result > 0)
1404 semihosting->result = 0;
1405 break;
1406 }
1407
1408 return semihosting->post_result(target);
1409 }
1410
1411 /**
1412 * Read all fields of a command from target to buffer.
1413 */
1414 static int semihosting_read_fields(struct target *target, size_t number,
1415 uint8_t *fields)
1416 {
1417 struct semihosting *semihosting = target->semihosting;
1418 /* Use 4-byte multiples to trigger fast memory access. */
1419 return target_read_memory(target, semihosting->param, 4,
1420 number * (semihosting->word_size_bytes / 4), fields);
1421 }
1422
1423 /**
1424 * Write all fields of a command from buffer to target.
1425 */
1426 static int semihosting_write_fields(struct target *target, size_t number,
1427 uint8_t *fields)
1428 {
1429 struct semihosting *semihosting = target->semihosting;
1430 /* Use 4-byte multiples to trigger fast memory access. */
1431 return target_write_memory(target, semihosting->param, 4,
1432 number * (semihosting->word_size_bytes / 4), fields);
1433 }
1434
1435 /**
1436 * Extract a field from the buffer, considering register size and endianness.
1437 */
1438 static uint64_t semihosting_get_field(struct target *target, size_t index,
1439 uint8_t *fields)
1440 {
1441 struct semihosting *semihosting = target->semihosting;
1442 if (semihosting->word_size_bytes == 8)
1443 return target_buffer_get_u64(target, fields + (index * 8));
1444 else
1445 return target_buffer_get_u32(target, fields + (index * 4));
1446 }
1447
1448 /**
1449 * Store a field in the buffer, considering register size and endianness.
1450 */
1451 static void semihosting_set_field(struct target *target, uint64_t value,
1452 size_t index,
1453 uint8_t *fields)
1454 {
1455 struct semihosting *semihosting = target->semihosting;
1456 if (semihosting->word_size_bytes == 8)
1457 target_buffer_set_u64(target, fields + (index * 8), value);
1458 else
1459 target_buffer_set_u32(target, fields + (index * 4), value);
1460 }
1461
1462
1463 /* -------------------------------------------------------------------------
1464 * Common semihosting commands handlers. */
1465
1466 static __COMMAND_HANDLER(handle_common_semihosting_command)
1467 {
1468 struct target *target = get_current_target(CMD_CTX);
1469
1470 if (target == NULL) {
1471 LOG_ERROR("No target selected");
1472 return ERROR_FAIL;
1473 }
1474
1475 struct semihosting *semihosting = target->semihosting;
1476 if (!semihosting) {
1477 command_print(CMD, "semihosting not supported for current target");
1478 return ERROR_FAIL;
1479 }
1480
1481 if (CMD_ARGC > 0) {
1482 int is_active;
1483
1484 COMMAND_PARSE_ENABLE(CMD_ARGV[0], is_active);
1485
1486 if (!target_was_examined(target)) {
1487 LOG_ERROR("Target not examined yet");
1488 return ERROR_FAIL;
1489 }
1490
1491 if (semihosting && semihosting->setup(target, is_active) != ERROR_OK) {
1492 LOG_ERROR("Failed to Configure semihosting");
1493 return ERROR_FAIL;
1494 }
1495
1496 /* FIXME never let that "catch" be dropped! (???) */
1497 semihosting->is_active = is_active;
1498 }
1499
1500 command_print(CMD, "semihosting is %s",
1501 semihosting->is_active
1502 ? "enabled" : "disabled");
1503
1504 return ERROR_OK;
1505 }
1506
1507 static __COMMAND_HANDLER(handle_common_semihosting_fileio_command)
1508 {
1509 struct target *target = get_current_target(CMD_CTX);
1510
1511 if (target == NULL) {
1512 LOG_ERROR("No target selected");
1513 return ERROR_FAIL;
1514 }
1515
1516 struct semihosting *semihosting = target->semihosting;
1517 if (!semihosting) {
1518 command_print(CMD, "semihosting not supported for current target");
1519 return ERROR_FAIL;
1520 }
1521
1522 if (!semihosting->is_active) {
1523 command_print(CMD, "semihosting not yet enabled for current target");
1524 return ERROR_FAIL;
1525 }
1526
1527 if (CMD_ARGC > 0)
1528 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->is_fileio);
1529
1530 command_print(CMD, "semihosting fileio is %s",
1531 semihosting->is_fileio
1532 ? "enabled" : "disabled");
1533
1534 return ERROR_OK;
1535 }
1536
1537 static __COMMAND_HANDLER(handle_common_semihosting_cmdline)
1538 {
1539 struct target *target = get_current_target(CMD_CTX);
1540 unsigned int i;
1541
1542 if (target == NULL) {
1543 LOG_ERROR("No target selected");
1544 return ERROR_FAIL;
1545 }
1546
1547 struct semihosting *semihosting = target->semihosting;
1548 if (!semihosting) {
1549 command_print(CMD, "semihosting not supported for current target");
1550 return ERROR_FAIL;
1551 }
1552
1553 free(semihosting->cmdline);
1554 semihosting->cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL;
1555
1556 for (i = 1; i < CMD_ARGC; i++) {
1557 char *cmdline = alloc_printf("%s %s", semihosting->cmdline, CMD_ARGV[i]);
1558 if (cmdline == NULL)
1559 break;
1560 free(semihosting->cmdline);
1561 semihosting->cmdline = cmdline;
1562 }
1563
1564 command_print(CMD, "semihosting command line is [%s]",
1565 semihosting->cmdline);
1566
1567 return ERROR_OK;
1568 }
1569
1570 static __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
1571 {
1572 struct target *target = get_current_target(CMD_CTX);
1573
1574 if (target == NULL) {
1575 LOG_ERROR("No target selected");
1576 return ERROR_FAIL;
1577 }
1578
1579 struct semihosting *semihosting = target->semihosting;
1580 if (!semihosting) {
1581 command_print(CMD, "semihosting not supported for current target");
1582 return ERROR_FAIL;
1583 }
1584
1585 if (!semihosting->is_active) {
1586 command_print(CMD, "semihosting not yet enabled for current target");
1587 return ERROR_FAIL;
1588 }
1589
1590 if (CMD_ARGC > 0)
1591 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->has_resumable_exit);
1592
1593 command_print(CMD, "semihosting resumable exit is %s",
1594 semihosting->has_resumable_exit
1595 ? "enabled" : "disabled");
1596
1597 return ERROR_OK;
1598 }
1599
1600 const struct command_registration semihosting_common_handlers[] = {
1601 {
1602 "semihosting",
1603 .handler = handle_common_semihosting_command,
1604 .mode = COMMAND_EXEC,
1605 .usage = "['enable'|'disable']",
1606 .help = "activate support for semihosting operations",
1607 },
1608 {
1609 "semihosting_cmdline",
1610 .handler = handle_common_semihosting_cmdline,
1611 .mode = COMMAND_EXEC,
1612 .usage = "arguments",
1613 .help = "command line arguments to be passed to program",
1614 },
1615 {
1616 "semihosting_fileio",
1617 .handler = handle_common_semihosting_fileio_command,
1618 .mode = COMMAND_EXEC,
1619 .usage = "['enable'|'disable']",
1620 .help = "activate support for semihosting fileio operations",
1621 },
1622 {
1623 "semihosting_resexit",
1624 .handler = handle_common_semihosting_resumable_exit_command,
1625 .mode = COMMAND_EXEC,
1626 .usage = "['enable'|'disable']",
1627 .help = "activate support for semihosting resumable exit",
1628 },
1629 COMMAND_REGISTRATION_DONE
1630 };

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)