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

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)