aboutsummaryrefslogtreecommitdiff
path: root/src/target/semihosting_common.h
blob: a1848b4881fb3d08b3a5b7f1b1d3d57bc369aeab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/* SPDX-License-Identifier: GPL-2.0-or-later */

/***************************************************************************
 *   Copyright (C) 2018 by Liviu Ionescu                                   *
 *   <ilg@livius.net>                                                      *
 *                                                                         *
 *   Copyright (C) 2009 by Marvell Technology Group Ltd.                   *
 *   Written by Nicolas Pitre <nico@marvell.com>                           *
 ***************************************************************************/

#ifndef OPENOCD_TARGET_SEMIHOSTING_COMMON_H
#define OPENOCD_TARGET_SEMIHOSTING_COMMON_H

#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include "helper/replacements.h"
#include <server/server.h>

/*
 * According to:
 * "Semihosting for AArch32 and AArch64, Release 2.0"
 * https://static.docs.arm.com/100863/0200/semihosting.pdf
 * from ARM Ltd.
 *
 * The available semihosting operation numbers passed in R0 are allocated
 * as follows:
 * - 0x00-0x31 Used by ARM.
 * - 0x32-0xFF Reserved for future use by ARM.
 * - 0x100-0x1FF Reserved for user applications. These are not used by ARM.
 *   However, if you are writing your own SVC operations, you are advised
 *   to use a different SVC number rather than using the semihosted
 *   SVC number and these operation type numbers.
 * - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended
 *   that you do not use these.
 */

enum semihosting_operation_numbers {
	/*
	 * ARM semihosting operations, in lexicographic order.
	 */
	SEMIHOSTING_ENTER_SVC = 0x17,	/* DEPRECATED */

	SEMIHOSTING_SYS_CLOSE = 0x02,
	SEMIHOSTING_SYS_CLOCK = 0x10,
	SEMIHOSTING_SYS_ELAPSED = 0x30,
	SEMIHOSTING_SYS_ERRNO = 0x13,
	SEMIHOSTING_SYS_EXIT = 0x18,
	SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20,
	SEMIHOSTING_SYS_FLEN = 0x0C,
	SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
	SEMIHOSTING_SYS_HEAPINFO = 0x16,
	SEMIHOSTING_SYS_ISERROR = 0x08,
	SEMIHOSTING_SYS_ISTTY = 0x09,
	SEMIHOSTING_SYS_OPEN = 0x01,
	SEMIHOSTING_SYS_READ = 0x06,
	SEMIHOSTING_SYS_READC = 0x07,
	SEMIHOSTING_SYS_REMOVE = 0x0E,
	SEMIHOSTING_SYS_RENAME = 0x0F,
	SEMIHOSTING_SYS_SEEK = 0x0A,
	SEMIHOSTING_SYS_SYSTEM = 0x12,
	SEMIHOSTING_SYS_TICKFREQ = 0x31,
	SEMIHOSTING_SYS_TIME = 0x11,
	SEMIHOSTING_SYS_TMPNAM = 0x0D,
	SEMIHOSTING_SYS_WRITE = 0x05,
	SEMIHOSTING_SYS_WRITEC = 0x03,
	SEMIHOSTING_SYS_WRITE0 = 0x04,
	SEMIHOSTING_ARM_RESERVED_START = 0x32,
	SEMIHOSTING_ARM_RESERVED_END = 0xFF,
	SEMIHOSTING_USER_CMD_0X100 = 0x100, /* First user cmd op code */
	SEMIHOSTING_USER_CMD_0X107 = 0x107, /* Last supported user cmd op code */
	SEMIHOSTING_USER_CMD_0X1FF = 0x1FF, /* Last user cmd op code */
};

/** Maximum allowed Tcl command segment length in bytes*/
#define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024)

/*
 * Codes used by SEMIHOSTING_SYS_EXIT (formerly
 * SEMIHOSTING_REPORT_EXCEPTION).
 * On 64-bits, the exit code is passed explicitly.
 */
enum semihosting_reported_exceptions {
	/* On 32 bits, use it for exit(0) */
	ADP_STOPPED_APPLICATION_EXIT = ((2 << 16) + 38),
	/* On 32 bits, use it for exit(1) */
	ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35),
};

enum semihosting_redirect_config {
	SEMIHOSTING_REDIRECT_CFG_NONE,
	SEMIHOSTING_REDIRECT_CFG_DEBUG,
	SEMIHOSTING_REDIRECT_CFG_STDIO,
	SEMIHOSTING_REDIRECT_CFG_ALL,
};

enum semihosting_result {
	SEMIHOSTING_NONE,		/* Not halted for a semihosting call. */
	SEMIHOSTING_HANDLED,	/* Call handled, and target was resumed. */
	SEMIHOSTING_WAITING,	/* Call handled, target is halted waiting until we can resume. */
	SEMIHOSTING_ERROR		/* Something went wrong. */
};

struct target;

/*
 * A pointer to this structure was added to the target structure.
 */
struct semihosting {

	/** A flag reporting whether semihosting is active. */
	bool is_active;

	/** Semihosting STDIO file descriptors */
	int stdin_fd, stdout_fd, stderr_fd;

	/** redirection configuration, NONE by default */
	enum semihosting_redirect_config redirect_cfg;

	/** Handle to redirect semihosting print via tcp */
	struct connection *tcp_connection;

	/** A flag reporting whether semihosting fileio is active. */
	bool is_fileio;

	/** A flag reporting whether semihosting fileio operation is active. */
	bool hit_fileio;

	/** Most are resumable, except the two exit calls. */
	bool is_resumable;

	/**
	 * When SEMIHOSTING_SYS_EXIT is called outside a debug session,
	 * things are simple, the openocd process calls exit() and passes
	 * the value returned by the target.
	 * When SEMIHOSTING_SYS_EXIT is called during a debug session,
	 * by default execution returns to the debugger, leaving the
	 * debugger in a HALT state, similar to the state entered when
	 * encountering a break.
	 * In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT
	 * return normally, as any semihosting call, and do not break
	 * to the debugger.
	 * The standard allows this to happen, but the condition
	 * to trigger it is a bit obscure ("by performing an RDI_Execute
	 * request or equivalent").
	 *
	 * To make the SEMIHOSTING_SYS_EXIT call return normally, enable
	 * this variable via the dedicated command (default: disabled).
	 */
	bool has_resumable_exit;

	/** The Target (hart) word size; 8 for 64-bits targets. */
	size_t word_size_bytes;

	/** The current semihosting operation (R0 on ARM). */
	int op;

	/** The current semihosting parameter (R1 or ARM). */
	uint64_t param;

	/**
	 * The current semihosting result to be returned to the application.
	 * Usually 0 for success, -1 for error,
	 * but sometimes a useful value, even a pointer.
	 */
	int64_t result;

	/** The value to be returned by semihosting SYS_ERRNO request. */
	int sys_errno;

	/** The semihosting command line to be passed to the target. */
	char *cmdline;

	/** The current time when 'execution starts' */
	clock_t setup_time;

	/** Base directory for semihosting I/O operations. */
	char *basedir;

	/**
	 * Target's extension of semihosting user commands.
	 * @returns ERROR_NOT_IMPLEMENTED when user command is not handled, otherwise
	 * sets semihosting->result and semihosting->sys_errno and returns ERROR_OK.
	 */
	int (*user_command_extension)(struct target *target);

	int (*setup)(struct target *target, int enable);
	int (*post_result)(struct target *target);
};

/**
 * @brief Convert the syscall opcode to a human-readable string
 * @param[in] opcode Syscall opcode
 * @return String representation of syscall opcode
 */
const char *semihosting_opcode_to_str(uint64_t opcode);

int semihosting_common_init(struct target *target, void *setup,
	void *post_result);
int semihosting_common(struct target *target);

/* utility functions which may also be used by semihosting extensions (custom vendor-defined syscalls) */
int semihosting_read_fields(struct target *target, size_t number,
	uint8_t *fields);
int semihosting_write_fields(struct target *target, size_t number,
	uint8_t *fields);
uint64_t semihosting_get_field(struct target *target, size_t index,
	uint8_t *fields);
void semihosting_set_field(struct target *target, uint64_t value,
	size_t index,
	uint8_t *fields);

extern const struct command_registration semihosting_common_handlers[];

#endif	/* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */