8ecf2e5263ad4f669db507b9344ad2c17ad38af2
[fw/openocd] / src / target / semihosting_common.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2018 by Liviu Ionescu                                   *
5  *   <ilg@livius.net>                                                      *
6  *                                                                         *
7  *   Copyright (C) 2009 by Marvell Technology Group Ltd.                   *
8  *   Written by Nicolas Pitre <nico@marvell.com>                           *
9  ***************************************************************************/
10
11 #ifndef OPENOCD_TARGET_SEMIHOSTING_COMMON_H
12 #define OPENOCD_TARGET_SEMIHOSTING_COMMON_H
13
14 #include <stdint.h>
15 #include <stdbool.h>
16 #include <time.h>
17 #include "helper/replacements.h"
18 #include <server/server.h>
19
20 /*
21  * According to:
22  * "Semihosting for AArch32 and AArch64, Release 2.0"
23  * https://static.docs.arm.com/100863/0200/semihosting.pdf
24  * from ARM Ltd.
25  *
26  * The available semihosting operation numbers passed in R0 are allocated
27  * as follows:
28  * - 0x00-0x31 Used by ARM.
29  * - 0x32-0xFF Reserved for future use by ARM.
30  * - 0x100-0x1FF Reserved for user applications. These are not used by ARM.
31  *   However, if you are writing your own SVC operations, you are advised
32  *   to use a different SVC number rather than using the semihosted
33  *   SVC number and these operation type numbers.
34  * - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended
35  *   that you do not use these.
36  */
37
38 enum semihosting_operation_numbers {
39         /*
40          * ARM semihosting operations, in lexicographic order.
41          */
42         SEMIHOSTING_ENTER_SVC = 0x17,   /* DEPRECATED */
43
44         SEMIHOSTING_SYS_CLOSE = 0x02,
45         SEMIHOSTING_SYS_CLOCK = 0x10,
46         SEMIHOSTING_SYS_ELAPSED = 0x30,
47         SEMIHOSTING_SYS_ERRNO = 0x13,
48         SEMIHOSTING_SYS_EXIT = 0x18,
49         SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20,
50         SEMIHOSTING_SYS_FLEN = 0x0C,
51         SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
52         SEMIHOSTING_SYS_HEAPINFO = 0x16,
53         SEMIHOSTING_SYS_ISERROR = 0x08,
54         SEMIHOSTING_SYS_ISTTY = 0x09,
55         SEMIHOSTING_SYS_OPEN = 0x01,
56         SEMIHOSTING_SYS_READ = 0x06,
57         SEMIHOSTING_SYS_READC = 0x07,
58         SEMIHOSTING_SYS_REMOVE = 0x0E,
59         SEMIHOSTING_SYS_RENAME = 0x0F,
60         SEMIHOSTING_SYS_SEEK = 0x0A,
61         SEMIHOSTING_SYS_SYSTEM = 0x12,
62         SEMIHOSTING_SYS_TICKFREQ = 0x31,
63         SEMIHOSTING_SYS_TIME = 0x11,
64         SEMIHOSTING_SYS_TMPNAM = 0x0D,
65         SEMIHOSTING_SYS_WRITE = 0x05,
66         SEMIHOSTING_SYS_WRITEC = 0x03,
67         SEMIHOSTING_SYS_WRITE0 = 0x04,
68         SEMIHOSTING_USER_CMD_0x100 = 0x100, /* First user cmd op code */
69         SEMIHOSTING_USER_CMD_0x107 = 0x107, /* Last supported user cmd op code */
70         SEMIHOSTING_USER_CMD_0x1FF = 0x1FF, /* Last user cmd op code */
71 };
72
73 /** Maximum allowed Tcl command segment length in bytes*/
74 #define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024)
75
76 /*
77  * Codes used by SEMIHOSTING_SYS_EXIT (formerly
78  * SEMIHOSTING_REPORT_EXCEPTION).
79  * On 64-bits, the exit code is passed explicitly.
80  */
81 enum semihosting_reported_exceptions {
82         /* On 32 bits, use it for exit(0) */
83         ADP_STOPPED_APPLICATION_EXIT = ((2 << 16) + 38),
84         /* On 32 bits, use it for exit(1) */
85         ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35),
86 };
87
88 enum semihosting_redirect_config {
89         SEMIHOSTING_REDIRECT_CFG_NONE,
90         SEMIHOSTING_REDIRECT_CFG_DEBUG,
91         SEMIHOSTING_REDIRECT_CFG_STDIO,
92         SEMIHOSTING_REDIRECT_CFG_ALL,
93 };
94
95 enum semihosting_result {
96         SEMIHOSTING_NONE,               /* Not halted for a semihosting call. */
97         SEMIHOSTING_HANDLED,    /* Call handled, and target was resumed. */
98         SEMIHOSTING_WAITING,    /* Call handled, target is halted waiting until we can resume. */
99         SEMIHOSTING_ERROR               /* Something went wrong. */
100 };
101
102 struct target;
103
104 /*
105  * A pointer to this structure was added to the target structure.
106  */
107 struct semihosting {
108
109         /** A flag reporting whether semihosting is active. */
110         bool is_active;
111
112         /** Semihosting STDIO file descriptors */
113         int stdin_fd, stdout_fd, stderr_fd;
114
115         /** redirection configuration, NONE by default */
116         enum semihosting_redirect_config redirect_cfg;
117
118         /** Handle to redirect semihosting print via tcp */
119         struct connection *tcp_connection;
120
121         /** A flag reporting whether semihosting fileio is active. */
122         bool is_fileio;
123
124         /** A flag reporting whether semihosting fileio operation is active. */
125         bool hit_fileio;
126
127         /** Most are resumable, except the two exit calls. */
128         bool is_resumable;
129
130         /**
131          * When SEMIHOSTING_SYS_EXIT is called outside a debug session,
132          * things are simple, the openocd process calls exit() and passes
133          * the value returned by the target.
134          * When SEMIHOSTING_SYS_EXIT is called during a debug session,
135          * by default execution returns to the debugger, leaving the
136          * debugger in a HALT state, similar to the state entered when
137          * encountering a break.
138          * In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT
139          * return normally, as any semihosting call, and do not break
140          * to the debugger.
141          * The standard allows this to happen, but the condition
142          * to trigger it is a bit obscure ("by performing an RDI_Execute
143          * request or equivalent").
144          *
145          * To make the SEMIHOSTING_SYS_EXIT call return normally, enable
146          * this variable via the dedicated command (default: disabled).
147          */
148         bool has_resumable_exit;
149
150         /** The Target (hart) word size; 8 for 64-bits targets. */
151         size_t word_size_bytes;
152
153         /** The current semihosting operation (R0 on ARM). */
154         int op;
155
156         /** The current semihosting parameter (R1 or ARM). */
157         uint64_t param;
158
159         /**
160          * The current semihosting result to be returned to the application.
161          * Usually 0 for success, -1 for error,
162          * but sometimes a useful value, even a pointer.
163          */
164         int64_t result;
165
166         /** The value to be returned by semihosting SYS_ERRNO request. */
167         int sys_errno;
168
169         /** The semihosting command line to be passed to the target. */
170         char *cmdline;
171
172         /** The current time when 'execution starts' */
173         clock_t setup_time;
174
175         /** Base directory for semihosting I/O operations. */
176         char *basedir;
177
178         /**
179          * Target's extension of semihosting user commands.
180          * @returns ERROR_NOT_IMPLEMENTED when user command is not handled, otherwise
181          * sets semihosting->result and semihosting->sys_errno and returns ERROR_OK.
182          */
183         int (*user_command_extension)(struct target *target);
184
185         int (*setup)(struct target *target, int enable);
186         int (*post_result)(struct target *target);
187 };
188
189 int semihosting_common_init(struct target *target, void *setup,
190         void *post_result);
191 int semihosting_common(struct target *target);
192
193 /* utility functions which may also be used by semihosting extensions (custom vendor-defined syscalls) */
194 int semihosting_read_fields(struct target *target, size_t number,
195         uint8_t *fields);
196 int semihosting_write_fields(struct target *target, size_t number,
197         uint8_t *fields);
198 uint64_t semihosting_get_field(struct target *target, size_t index,
199         uint8_t *fields);
200 void semihosting_set_field(struct target *target, uint64_t value,
201         size_t index,
202         uint8_t *fields);
203
204 extern const struct command_registration semihosting_common_handlers[];
205
206 #endif  /* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */