blob: 1c29146dcfa6dfc44c9e4fcf3a43b8d2674f8495 [file] [log] [blame]
bellarda4f81972005-04-23 18:25:41 +00001/*
Keith Packard0bb446d2021-01-08 22:42:49 +00002 * Semihosting support for systems modeled on the Arm "Angel"
Keith Packarda10b9d92021-01-08 22:42:52 +00003 * semihosting syscalls design. This includes Arm and RISC-V processors
ths5fafdf22007-09-16 21:08:06 +00004 *
pbrook8e716212007-01-20 17:12:09 +00005 * Copyright (c) 2005, 2007 CodeSourcery.
Alex Bennée4cb28db2019-05-14 12:08:39 +01006 * Copyright (c) 2019 Linaro
pbrook8e716212007-01-20 17:12:09 +00007 * Written by Paul Brook.
bellarda4f81972005-04-23 18:25:41 +00008 *
Keith Packard0bb446d2021-01-08 22:42:49 +00009 * Copyright © 2020 by Keith Packard <keithp@keithp.com>
10 * Adapted for systems other than ARM, including RISC-V, by Keith Packard
11 *
bellarda4f81972005-04-23 18:25:41 +000012 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000023 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Alex Bennée4cb28db2019-05-14 12:08:39 +010024 *
25 * ARM Semihosting is documented in:
26 * Semihosting for AArch32 and AArch64 Release 2.0
27 * https://static.docs.arm.com/100863/0200/semihosting.pdf
Keith Packarda10b9d92021-01-08 22:42:52 +000028 *
29 * RISC-V Semihosting is documented in:
30 * RISC-V Semihosting
31 * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
bellarda4f81972005-04-23 18:25:41 +000032 */
33
Peter Maydell74c21bd2015-12-07 16:23:44 +000034#include "qemu/osdep.h"
bellarda4f81972005-04-23 18:25:41 +000035
Philippe Mathieu-Daudé6b5fe132021-03-05 13:54:49 +000036#include "semihosting/semihost.h"
37#include "semihosting/console.h"
38#include "semihosting/common-semi.h"
Keith Packard4d834032021-01-08 22:42:54 +000039#include "qemu/timer.h"
pbrook8e716212007-01-20 17:12:09 +000040#ifdef CONFIG_USER_ONLY
bellarda4f81972005-04-23 18:25:41 +000041#include "qemu.h"
42
Keith Packard3c37cfe2021-01-08 22:42:50 +000043#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
pbrook8e716212007-01-20 17:12:09 +000044#else
Paolo Bonzini022c62c2012-12-17 18:19:49 +010045#include "exec/gdbstub.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020046#include "qemu/cutils.h"
Keith Packard3c37cfe2021-01-08 22:42:50 +000047#ifdef TARGET_ARM
Peter Maydell69515952020-11-19 09:23:46 +000048#include "hw/arm/boot.h"
Keith Packard3c37cfe2021-01-08 22:42:50 +000049#endif
Paolo Bonzini6e504a92020-10-28 06:18:20 -040050#include "hw/boards.h"
pbrook8e716212007-01-20 17:12:09 +000051#endif
bellarda4f81972005-04-23 18:25:41 +000052
Stefan Weil38817252012-04-28 05:07:47 +000053#define TARGET_SYS_OPEN 0x01
54#define TARGET_SYS_CLOSE 0x02
55#define TARGET_SYS_WRITEC 0x03
56#define TARGET_SYS_WRITE0 0x04
57#define TARGET_SYS_WRITE 0x05
58#define TARGET_SYS_READ 0x06
59#define TARGET_SYS_READC 0x07
Keith Packard767ba042021-01-08 22:42:56 +000060#define TARGET_SYS_ISERROR 0x08
Stefan Weil38817252012-04-28 05:07:47 +000061#define TARGET_SYS_ISTTY 0x09
62#define TARGET_SYS_SEEK 0x0a
63#define TARGET_SYS_FLEN 0x0c
64#define TARGET_SYS_TMPNAM 0x0d
65#define TARGET_SYS_REMOVE 0x0e
66#define TARGET_SYS_RENAME 0x0f
67#define TARGET_SYS_CLOCK 0x10
68#define TARGET_SYS_TIME 0x11
69#define TARGET_SYS_SYSTEM 0x12
70#define TARGET_SYS_ERRNO 0x13
71#define TARGET_SYS_GET_CMDLINE 0x15
72#define TARGET_SYS_HEAPINFO 0x16
73#define TARGET_SYS_EXIT 0x18
Peter Maydelle9ebfbf2015-09-07 10:39:28 +010074#define TARGET_SYS_SYNCCACHE 0x19
Peter Maydell22a43bb2019-09-16 15:15:43 +010075#define TARGET_SYS_EXIT_EXTENDED 0x20
Keith Packard4d834032021-01-08 22:42:54 +000076#define TARGET_SYS_ELAPSED 0x30
77#define TARGET_SYS_TICKFREQ 0x31
bellarda4f81972005-04-23 18:25:41 +000078
Liviu Ionescu1ecc3a22014-12-11 12:07:48 +000079/* ADP_Stopped_ApplicationExit is used for exit(0),
80 * anything else is implemented as exit(1) */
81#define ADP_Stopped_ApplicationExit (0x20026)
82
bellarda4f81972005-04-23 18:25:41 +000083#ifndef O_BINARY
84#define O_BINARY 0
85#endif
86
pbrooka2d1eba2007-01-28 03:10:55 +000087#define GDB_O_RDONLY 0x000
88#define GDB_O_WRONLY 0x001
89#define GDB_O_RDWR 0x002
90#define GDB_O_APPEND 0x008
91#define GDB_O_CREAT 0x200
92#define GDB_O_TRUNC 0x400
93#define GDB_O_BINARY 0
94
95static int gdb_open_modeflags[12] = {
96 GDB_O_RDONLY,
97 GDB_O_RDONLY | GDB_O_BINARY,
98 GDB_O_RDWR,
99 GDB_O_RDWR | GDB_O_BINARY,
100 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
101 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
102 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
103 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
104 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
105 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
106 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
107 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
108};
109
110static int open_modeflags[12] = {
bellarda4f81972005-04-23 18:25:41 +0000111 O_RDONLY,
112 O_RDONLY | O_BINARY,
113 O_RDWR,
114 O_RDWR | O_BINARY,
115 O_WRONLY | O_CREAT | O_TRUNC,
116 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
117 O_RDWR | O_CREAT | O_TRUNC,
118 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
119 O_WRONLY | O_CREAT | O_APPEND,
120 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
121 O_RDWR | O_CREAT | O_APPEND,
122 O_RDWR | O_CREAT | O_APPEND | O_BINARY
123};
124
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100125typedef enum GuestFDType {
126 GuestFDUnused = 0,
127 GuestFDHost = 1,
Peter Maydell263eb622019-09-16 15:15:36 +0100128 GuestFDGDB = 2,
Peter Maydellc46a6532019-09-16 15:15:42 +0100129 GuestFDFeatureFile = 3,
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100130} GuestFDType;
131
132/*
133 * Guest file descriptors are integer indexes into an array of
134 * these structures (we will dynamically resize as necessary).
135 */
136typedef struct GuestFD {
137 GuestFDType type;
Peter Maydellc46a6532019-09-16 15:15:42 +0100138 union {
139 int hostfd;
140 target_ulong featurefile_offset;
141 };
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100142} GuestFD;
143
144static GArray *guestfd_array;
145
Keith Packard095f8c02021-01-08 22:42:51 +0000146#ifndef CONFIG_USER_ONLY
147#include "exec/address-spaces.h"
148/*
149 * Find the base of a RAM region containing the specified address
150 */
151static inline hwaddr
152common_semi_find_region_base(hwaddr addr)
153{
154 MemoryRegion *subregion;
155
156 /*
157 * Find the chunk of R/W memory containing the address. This is
158 * used for the SYS_HEAPINFO semihosting call, which should
159 * probably be using information from the loaded application.
160 */
161 QTAILQ_FOREACH(subregion, &get_system_memory()->subregions,
162 subregions_link) {
163 if (subregion->ram && !subregion->readonly) {
164 Int128 top128 = int128_add(int128_make64(subregion->addr),
165 subregion->size);
166 Int128 addr128 = int128_make64(addr);
167 if (subregion->addr <= addr && int128_lt(addr128, top128)) {
168 return subregion->addr;
169 }
170 }
171 }
172 return 0;
173}
174#endif
175
Keith Packard3c37cfe2021-01-08 22:42:50 +0000176#ifdef TARGET_ARM
177static inline target_ulong
178common_semi_arg(CPUState *cs, int argno)
179{
180 ARMCPU *cpu = ARM_CPU(cs);
181 CPUARMState *env = &cpu->env;
182 if (is_a64(env)) {
183 return env->xregs[argno];
184 } else {
185 return env->regs[argno];
186 }
187}
188
189static inline void
190common_semi_set_ret(CPUState *cs, target_ulong ret)
191{
192 ARMCPU *cpu = ARM_CPU(cs);
193 CPUARMState *env = &cpu->env;
194 if (is_a64(env)) {
195 env->xregs[0] = ret;
196 } else {
197 env->regs[0] = ret;
198 }
199}
200
201static inline bool
202common_semi_sys_exit_extended(CPUState *cs, int nr)
203{
204 return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
205}
206
207#ifndef CONFIG_USER_ONLY
208#include "hw/arm/boot.h"
209static inline target_ulong
210common_semi_rambase(CPUState *cs)
211{
212 CPUArchState *env = cs->env_ptr;
213 const struct arm_boot_info *info = env->boot_info;
Keith Packard095f8c02021-01-08 22:42:51 +0000214 target_ulong sp;
215
216 if (info) {
217 return info->loader_start;
218 }
219
220 if (is_a64(env)) {
221 sp = env->xregs[31];
222 } else {
223 sp = env->regs[13];
224 }
225 return common_semi_find_region_base(sp);
Keith Packard3c37cfe2021-01-08 22:42:50 +0000226}
227#endif
228
229#endif /* TARGET_ARM */
230
Keith Packarda10b9d92021-01-08 22:42:52 +0000231#ifdef TARGET_RISCV
232static inline target_ulong
233common_semi_arg(CPUState *cs, int argno)
234{
235 RISCVCPU *cpu = RISCV_CPU(cs);
236 CPURISCVState *env = &cpu->env;
237 return env->gpr[xA0 + argno];
238}
239
240static inline void
241common_semi_set_ret(CPUState *cs, target_ulong ret)
242{
243 RISCVCPU *cpu = RISCV_CPU(cs);
244 CPURISCVState *env = &cpu->env;
245 env->gpr[xA0] = ret;
246}
247
248static inline bool
249common_semi_sys_exit_extended(CPUState *cs, int nr)
250{
251 return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
252}
253
254#ifndef CONFIG_USER_ONLY
255
256static inline target_ulong
257common_semi_rambase(CPUState *cs)
258{
259 RISCVCPU *cpu = RISCV_CPU(cs);
260 CPURISCVState *env = &cpu->env;
261 return common_semi_find_region_base(env->gpr[xSP]);
262}
263#endif
264
265#endif
266
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100267/*
268 * Allocate a new guest file descriptor and return it; if we
269 * couldn't allocate a new fd then return -1.
270 * This is a fairly simplistic implementation because we don't
271 * expect that most semihosting guest programs will make very
272 * heavy use of opening and closing fds.
273 */
274static int alloc_guestfd(void)
275{
276 guint i;
277
278 if (!guestfd_array) {
279 /* New entries zero-initialized, i.e. type GuestFDUnused */
280 guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
281 }
282
Masahiro Yamada21bf9b02020-01-17 14:09:30 +0000283 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
284 for (i = 1; i < guestfd_array->len; i++) {
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100285 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
286
287 if (gf->type == GuestFDUnused) {
288 return i;
289 }
290 }
291
292 /* All elements already in use: expand the array */
293 g_array_set_size(guestfd_array, i + 1);
294 return i;
295}
296
297/*
298 * Look up the guestfd in the data structure; return NULL
299 * for out of bounds, but don't check whether the slot is unused.
300 * This is used internally by the other guestfd functions.
301 */
302static GuestFD *do_get_guestfd(int guestfd)
303{
304 if (!guestfd_array) {
305 return NULL;
306 }
307
Masahiro Yamada21bf9b02020-01-17 14:09:30 +0000308 if (guestfd <= 0 || guestfd >= guestfd_array->len) {
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100309 return NULL;
310 }
311
312 return &g_array_index(guestfd_array, GuestFD, guestfd);
313}
314
315/*
316 * Associate the specified guest fd (which must have been
317 * allocated via alloc_fd() and not previously used) with
Peter Maydell263eb622019-09-16 15:15:36 +0100318 * the specified host/gdb fd.
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100319 */
320static void associate_guestfd(int guestfd, int hostfd)
321{
322 GuestFD *gf = do_get_guestfd(guestfd);
323
324 assert(gf);
Peter Maydell263eb622019-09-16 15:15:36 +0100325 gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100326 gf->hostfd = hostfd;
327}
328
329/*
330 * Deallocate the specified guest file descriptor. This doesn't
331 * close the host fd, it merely undoes the work of alloc_fd().
332 */
333static void dealloc_guestfd(int guestfd)
334{
335 GuestFD *gf = do_get_guestfd(guestfd);
336
337 assert(gf);
338 gf->type = GuestFDUnused;
339}
340
341/*
342 * Given a guest file descriptor, get the associated struct.
343 * If the fd is not valid, return NULL. This is the function
344 * used by the various semihosting calls to validate a handle
345 * from the guest.
346 * Note: calling alloc_guestfd() or dealloc_guestfd() will
347 * invalidate any GuestFD* obtained by calling this function.
348 */
349static GuestFD *get_guestfd(int guestfd)
350{
351 GuestFD *gf = do_get_guestfd(guestfd);
352
353 if (!gf || gf->type == GuestFDUnused) {
354 return NULL;
355 }
356 return gf;
357}
358
Peter Maydell6ed68452019-09-16 15:15:34 +0100359/*
360 * The semihosting API has no concept of its errno being thread-safe,
361 * as the API design predates SMP CPUs and was intended as a simple
362 * real-hardware set of debug functionality. For QEMU, we make the
363 * errno be per-thread in linux-user mode; in softmmu it is a simple
364 * global, and we assume that the guest takes care of avoiding any races.
365 */
366#ifndef CONFIG_USER_ONLY
Peter Maydell1b003822019-09-16 15:15:30 +0100367static target_ulong syscall_err;
368
Peter Maydell6ed68452019-09-16 15:15:34 +0100369#include "exec/softmmu-semi.h"
370#endif
371
Keith Packard3c37cfe2021-01-08 22:42:50 +0000372static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
pbrook8e716212007-01-20 17:12:09 +0000373{
Peter Maydell1b003822019-09-16 15:15:30 +0100374 if (code == (uint32_t)-1) {
Peter Maydell6ed68452019-09-16 15:15:34 +0100375#ifdef CONFIG_USER_ONLY
Peter Maydell6ed68452019-09-16 15:15:34 +0100376 TaskState *ts = cs->opaque;
377
378 ts->swi_errno = errno;
379#else
Peter Maydell1b003822019-09-16 15:15:30 +0100380 syscall_err = errno;
Peter Maydell6ed68452019-09-16 15:15:34 +0100381#endif
Peter Maydell1b003822019-09-16 15:15:30 +0100382 }
pbrook8e716212007-01-20 17:12:09 +0000383 return code;
384}
385
Keith Packard3c37cfe2021-01-08 22:42:50 +0000386static inline uint32_t get_swi_errno(CPUState *cs)
Peter Maydell6ed68452019-09-16 15:15:34 +0100387{
388#ifdef CONFIG_USER_ONLY
Peter Maydell6ed68452019-09-16 15:15:34 +0100389 TaskState *ts = cs->opaque;
390
391 return ts->swi_errno;
392#else
393 return syscall_err;
pbrook8e716212007-01-20 17:12:09 +0000394#endif
Peter Maydell6ed68452019-09-16 15:15:34 +0100395}
bellarda4f81972005-04-23 18:25:41 +0000396
Keith Packard3c37cfe2021-01-08 22:42:50 +0000397static target_ulong common_semi_syscall_len;
pbrooka2d1eba2007-01-28 03:10:55 +0000398
Keith Packard3c37cfe2021-01-08 22:42:50 +0000399static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
pbrooka2d1eba2007-01-28 03:10:55 +0000400{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000401 target_ulong reg0 = common_semi_arg(cs, 0);
pbrook33d9cc82007-06-09 14:44:00 +0000402
pbrooka2d1eba2007-01-28 03:10:55 +0000403 if (ret == (target_ulong)-1) {
Peter Maydell939f5b42019-09-16 15:15:35 +0100404 errno = err;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000405 set_swi_errno(cs, -1);
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100406 reg0 = ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000407 } else {
408 /* Fixup syscalls that use nonstardard return conventions. */
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100409 switch (reg0) {
Stefan Weil38817252012-04-28 05:07:47 +0000410 case TARGET_SYS_WRITE:
411 case TARGET_SYS_READ:
Keith Packard3c37cfe2021-01-08 22:42:50 +0000412 reg0 = common_semi_syscall_len - ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000413 break;
Stefan Weil38817252012-04-28 05:07:47 +0000414 case TARGET_SYS_SEEK:
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100415 reg0 = 0;
pbrooka2d1eba2007-01-28 03:10:55 +0000416 break;
417 default:
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100418 reg0 = ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000419 break;
420 }
421 }
Keith Packard3c37cfe2021-01-08 22:42:50 +0000422 common_semi_set_ret(cs, reg0);
Peter Maydellfaacc042015-09-07 10:39:28 +0100423}
424
Keith Packard3c37cfe2021-01-08 22:42:50 +0000425static target_ulong common_semi_flen_buf(CPUState *cs)
Peter Maydellfaacc042015-09-07 10:39:28 +0100426{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000427 target_ulong sp;
428#ifdef TARGET_ARM
Peter Maydellfaacc042015-09-07 10:39:28 +0100429 /* Return an address in target memory of 64 bytes where the remote
430 * gdb should write its stat struct. (The format of this structure
431 * is defined by GDB's remote protocol and is not target-specific.)
432 * We put this on the guest's stack just below SP.
433 */
Keith Packard3c37cfe2021-01-08 22:42:50 +0000434 ARMCPU *cpu = ARM_CPU(cs);
Peter Maydellfaacc042015-09-07 10:39:28 +0100435 CPUARMState *env = &cpu->env;
Peter Maydellfaacc042015-09-07 10:39:28 +0100436
437 if (is_a64(env)) {
438 sp = env->xregs[31];
439 } else {
440 sp = env->regs[13];
441 }
Keith Packard3c37cfe2021-01-08 22:42:50 +0000442#endif
Keith Packarda10b9d92021-01-08 22:42:52 +0000443#ifdef TARGET_RISCV
444 RISCVCPU *cpu = RISCV_CPU(cs);
445 CPURISCVState *env = &cpu->env;
446
447 sp = env->gpr[xSP];
448#endif
Peter Maydellfaacc042015-09-07 10:39:28 +0100449
450 return sp - 64;
pbrooka2d1eba2007-01-28 03:10:55 +0000451}
452
Keith Packard3c37cfe2021-01-08 22:42:50 +0000453static void
454common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
pbrook33d9cc82007-06-09 14:44:00 +0000455{
456 /* The size is always stored in big-endian order, extract
457 the value. We assume the size always fit in 32 bits. */
458 uint32_t size;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000459 cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32,
460 (uint8_t *)&size, 4, 0);
Peter Maydellfaacc042015-09-07 10:39:28 +0100461 size = be32_to_cpu(size);
Keith Packard3c37cfe2021-01-08 22:42:50 +0000462 common_semi_set_ret(cs, size);
Peter Maydell939f5b42019-09-16 15:15:35 +0100463 errno = err;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000464 set_swi_errno(cs, -1);
pbrook33d9cc82007-06-09 14:44:00 +0000465}
466
Keith Packard3c37cfe2021-01-08 22:42:50 +0000467static int common_semi_open_guestfd;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100468
Keith Packard3c37cfe2021-01-08 22:42:50 +0000469static void
470common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100471{
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100472 if (ret == (target_ulong)-1) {
Peter Maydell939f5b42019-09-16 15:15:35 +0100473 errno = err;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000474 set_swi_errno(cs, -1);
475 dealloc_guestfd(common_semi_open_guestfd);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100476 } else {
Keith Packard3c37cfe2021-01-08 22:42:50 +0000477 associate_guestfd(common_semi_open_guestfd, ret);
478 ret = common_semi_open_guestfd;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100479 }
Keith Packard3c37cfe2021-01-08 22:42:50 +0000480 common_semi_set_ret(cs, ret);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100481}
482
Keith Packard3c37cfe2021-01-08 22:42:50 +0000483static target_ulong
484common_semi_gdb_syscall(CPUState *cs, gdb_syscall_complete_cb cb,
485 const char *fmt, ...)
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100486{
487 va_list va;
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100488
489 va_start(va, fmt);
490 gdb_do_syscallv(cb, fmt, va);
491 va_end(va);
492
Peter Maydellf8ad2302019-09-16 15:15:32 +0100493 /*
494 * FIXME: in softmmu mode, the gdbstub will schedule our callback
495 * to occur, but will not actually call it to complete the syscall
496 * until after this function has returned and we are back in the
497 * CPU main loop. Therefore callers to this function must not
498 * do anything with its return value, because it is not necessarily
499 * the result of the syscall, but could just be the old value of X0.
500 * The only thing safe to do with this is that the callers of
Keith Packard0bb446d2021-01-08 22:42:49 +0000501 * do_common_semihosting() will write it straight back into X0.
Peter Maydellf8ad2302019-09-16 15:15:32 +0100502 * (In linux-user mode, the callback will have happened before
503 * gdb_do_syscallv() returns.)
504 *
505 * We should tidy this up so neither this function nor
Keith Packard0bb446d2021-01-08 22:42:49 +0000506 * do_common_semihosting() return a value, so the mistake of
Peter Maydellf8ad2302019-09-16 15:15:32 +0100507 * doing something with the return value is not possible to make.
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100508 */
509
Keith Packard3c37cfe2021-01-08 22:42:50 +0000510 return common_semi_arg(cs, 0);
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100511}
512
Peter Maydell263eb622019-09-16 15:15:36 +0100513/*
514 * Types for functions implementing various semihosting calls
515 * for specific types of guest file descriptor. These must all
516 * do the work and return the required return value for the guest,
517 * setting the guest errno if appropriate.
518 */
Keith Packard3c37cfe2021-01-08 22:42:50 +0000519typedef uint32_t sys_closefn(CPUState *cs, GuestFD *gf);
520typedef uint32_t sys_writefn(CPUState *cs, GuestFD *gf,
Peter Maydell52c8a162019-09-16 15:15:37 +0100521 target_ulong buf, uint32_t len);
Keith Packard3c37cfe2021-01-08 22:42:50 +0000522typedef uint32_t sys_readfn(CPUState *cs, GuestFD *gf,
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100523 target_ulong buf, uint32_t len);
Keith Packard3c37cfe2021-01-08 22:42:50 +0000524typedef uint32_t sys_isattyfn(CPUState *cs, GuestFD *gf);
525typedef uint32_t sys_seekfn(CPUState *cs, GuestFD *gf,
Peter Maydell45e88ff2019-09-16 15:15:40 +0100526 target_ulong offset);
Keith Packard3c37cfe2021-01-08 22:42:50 +0000527typedef uint32_t sys_flenfn(CPUState *cs, GuestFD *gf);
Peter Maydell263eb622019-09-16 15:15:36 +0100528
Keith Packard3c37cfe2021-01-08 22:42:50 +0000529static uint32_t host_closefn(CPUState *cs, GuestFD *gf)
Peter Maydell263eb622019-09-16 15:15:36 +0100530{
Peter Maydell16ab12a2020-01-30 16:02:01 +0000531 /*
532 * Only close the underlying host fd if it's one we opened on behalf
533 * of the guest in SYS_OPEN.
534 */
535 if (gf->hostfd == STDIN_FILENO ||
536 gf->hostfd == STDOUT_FILENO ||
537 gf->hostfd == STDERR_FILENO) {
538 return 0;
539 }
Keith Packard3c37cfe2021-01-08 22:42:50 +0000540 return set_swi_errno(cs, close(gf->hostfd));
Peter Maydell263eb622019-09-16 15:15:36 +0100541}
542
Keith Packard3c37cfe2021-01-08 22:42:50 +0000543static uint32_t host_writefn(CPUState *cs, GuestFD *gf,
Peter Maydell52c8a162019-09-16 15:15:37 +0100544 target_ulong buf, uint32_t len)
545{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000546 CPUArchState *env = cs->env_ptr;
Peter Maydell52c8a162019-09-16 15:15:37 +0100547 uint32_t ret;
Peter Maydell52c8a162019-09-16 15:15:37 +0100548 char *s = lock_user(VERIFY_READ, buf, len, 1);
Keith Packard3c37cfe2021-01-08 22:42:50 +0000549 (void) env; /* Used in arm softmmu lock_user implicitly */
Peter Maydell52c8a162019-09-16 15:15:37 +0100550 if (!s) {
551 /* Return bytes not written on error */
552 return len;
553 }
Keith Packard3c37cfe2021-01-08 22:42:50 +0000554 ret = set_swi_errno(cs, write(gf->hostfd, s, len));
Peter Maydell52c8a162019-09-16 15:15:37 +0100555 unlock_user(s, buf, 0);
556 if (ret == (uint32_t)-1) {
557 ret = 0;
558 }
559 /* Return bytes not written */
560 return len - ret;
561}
562
Keith Packard3c37cfe2021-01-08 22:42:50 +0000563static uint32_t host_readfn(CPUState *cs, GuestFD *gf,
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100564 target_ulong buf, uint32_t len)
565{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000566 CPUArchState *env = cs->env_ptr;
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100567 uint32_t ret;
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100568 char *s = lock_user(VERIFY_WRITE, buf, len, 0);
Keith Packard3c37cfe2021-01-08 22:42:50 +0000569 (void) env; /* Used in arm softmmu lock_user implicitly */
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100570 if (!s) {
571 /* return bytes not read */
572 return len;
573 }
574 do {
Keith Packard3c37cfe2021-01-08 22:42:50 +0000575 ret = set_swi_errno(cs, read(gf->hostfd, s, len));
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100576 } while (ret == -1 && errno == EINTR);
577 unlock_user(s, buf, len);
578 if (ret == (uint32_t)-1) {
579 ret = 0;
580 }
581 /* Return bytes not read */
582 return len - ret;
583}
584
Keith Packard3c37cfe2021-01-08 22:42:50 +0000585static uint32_t host_isattyfn(CPUState *cs, GuestFD *gf)
Peter Maydell0213fa42019-09-16 15:15:39 +0100586{
587 return isatty(gf->hostfd);
588}
589
Keith Packard3c37cfe2021-01-08 22:42:50 +0000590static uint32_t host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
Peter Maydell45e88ff2019-09-16 15:15:40 +0100591{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000592 uint32_t ret = set_swi_errno(cs, lseek(gf->hostfd, offset, SEEK_SET));
Peter Maydell45e88ff2019-09-16 15:15:40 +0100593 if (ret == (uint32_t)-1) {
594 return -1;
595 }
596 return 0;
597}
598
Keith Packard3c37cfe2021-01-08 22:42:50 +0000599static uint32_t host_flenfn(CPUState *cs, GuestFD *gf)
Peter Maydell1631a7b2019-09-16 15:15:41 +0100600{
Peter Maydell1631a7b2019-09-16 15:15:41 +0100601 struct stat buf;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000602 uint32_t ret = set_swi_errno(cs, fstat(gf->hostfd, &buf));
Peter Maydell1631a7b2019-09-16 15:15:41 +0100603 if (ret == (uint32_t)-1) {
604 return -1;
605 }
606 return buf.st_size;
607}
608
Keith Packard3c37cfe2021-01-08 22:42:50 +0000609static uint32_t gdb_closefn(CPUState *cs, GuestFD *gf)
Peter Maydell263eb622019-09-16 15:15:36 +0100610{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000611 return common_semi_gdb_syscall(cs, common_semi_cb, "close,%x", gf->hostfd);
Peter Maydell263eb622019-09-16 15:15:36 +0100612}
613
Keith Packard3c37cfe2021-01-08 22:42:50 +0000614static uint32_t gdb_writefn(CPUState *cs, GuestFD *gf,
Peter Maydell52c8a162019-09-16 15:15:37 +0100615 target_ulong buf, uint32_t len)
616{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000617 common_semi_syscall_len = len;
618 return common_semi_gdb_syscall(cs, common_semi_cb, "write,%x,%x,%x",
619 gf->hostfd, buf, len);
Peter Maydell52c8a162019-09-16 15:15:37 +0100620}
621
Keith Packard3c37cfe2021-01-08 22:42:50 +0000622static uint32_t gdb_readfn(CPUState *cs, GuestFD *gf,
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100623 target_ulong buf, uint32_t len)
624{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000625 common_semi_syscall_len = len;
626 return common_semi_gdb_syscall(cs, common_semi_cb, "read,%x,%x,%x",
627 gf->hostfd, buf, len);
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100628}
629
Keith Packard3c37cfe2021-01-08 22:42:50 +0000630static uint32_t gdb_isattyfn(CPUState *cs, GuestFD *gf)
Peter Maydell0213fa42019-09-16 15:15:39 +0100631{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000632 return common_semi_gdb_syscall(cs, common_semi_cb, "isatty,%x", gf->hostfd);
Peter Maydell0213fa42019-09-16 15:15:39 +0100633}
634
Keith Packard3c37cfe2021-01-08 22:42:50 +0000635static uint32_t gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
Peter Maydell45e88ff2019-09-16 15:15:40 +0100636{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000637 return common_semi_gdb_syscall(cs, common_semi_cb, "lseek,%x,%x,0",
638 gf->hostfd, offset);
Peter Maydell45e88ff2019-09-16 15:15:40 +0100639}
640
Keith Packard3c37cfe2021-01-08 22:42:50 +0000641static uint32_t gdb_flenfn(CPUState *cs, GuestFD *gf)
Peter Maydell1631a7b2019-09-16 15:15:41 +0100642{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000643 return common_semi_gdb_syscall(cs, common_semi_flen_cb, "fstat,%x,%x",
644 gf->hostfd, common_semi_flen_buf(cs));
Peter Maydell1631a7b2019-09-16 15:15:41 +0100645}
646
Peter Maydellc46a6532019-09-16 15:15:42 +0100647#define SHFB_MAGIC_0 0x53
648#define SHFB_MAGIC_1 0x48
649#define SHFB_MAGIC_2 0x46
650#define SHFB_MAGIC_3 0x42
651
Peter Maydell22a43bb2019-09-16 15:15:43 +0100652/* Feature bits reportable in feature byte 0 */
653#define SH_EXT_EXIT_EXTENDED (1 << 0)
Peter Maydell6ee18642019-09-16 15:15:44 +0100654#define SH_EXT_STDOUT_STDERR (1 << 1)
Peter Maydell22a43bb2019-09-16 15:15:43 +0100655
Peter Maydellc46a6532019-09-16 15:15:42 +0100656static const uint8_t featurefile_data[] = {
657 SHFB_MAGIC_0,
658 SHFB_MAGIC_1,
659 SHFB_MAGIC_2,
660 SHFB_MAGIC_3,
Peter Maydell6ee18642019-09-16 15:15:44 +0100661 SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
Peter Maydellc46a6532019-09-16 15:15:42 +0100662};
663
664static void init_featurefile_guestfd(int guestfd)
665{
666 GuestFD *gf = do_get_guestfd(guestfd);
667
668 assert(gf);
669 gf->type = GuestFDFeatureFile;
670 gf->featurefile_offset = 0;
671}
672
Keith Packard3c37cfe2021-01-08 22:42:50 +0000673static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf)
Peter Maydellc46a6532019-09-16 15:15:42 +0100674{
675 /* Nothing to do */
676 return 0;
677}
678
Keith Packard3c37cfe2021-01-08 22:42:50 +0000679static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf,
Peter Maydellc46a6532019-09-16 15:15:42 +0100680 target_ulong buf, uint32_t len)
681{
682 /* This fd can never be open for writing */
Peter Maydellc46a6532019-09-16 15:15:42 +0100683
684 errno = EBADF;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000685 return set_swi_errno(cs, -1);
Peter Maydellc46a6532019-09-16 15:15:42 +0100686}
687
Keith Packard3c37cfe2021-01-08 22:42:50 +0000688static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
Peter Maydellc46a6532019-09-16 15:15:42 +0100689 target_ulong buf, uint32_t len)
690{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000691 CPUArchState *env = cs->env_ptr;
Peter Maydellc46a6532019-09-16 15:15:42 +0100692 uint32_t i;
Peter Maydellc46a6532019-09-16 15:15:42 +0100693 char *s;
694
Keith Packard3c37cfe2021-01-08 22:42:50 +0000695 (void) env; /* Used in arm softmmu lock_user implicitly */
Peter Maydellc46a6532019-09-16 15:15:42 +0100696 s = lock_user(VERIFY_WRITE, buf, len, 0);
697 if (!s) {
698 return len;
699 }
700
701 for (i = 0; i < len; i++) {
702 if (gf->featurefile_offset >= sizeof(featurefile_data)) {
703 break;
704 }
705 s[i] = featurefile_data[gf->featurefile_offset];
706 gf->featurefile_offset++;
707 }
708
709 unlock_user(s, buf, len);
710
711 /* Return number of bytes not read */
712 return len - i;
713}
714
Keith Packard3c37cfe2021-01-08 22:42:50 +0000715static uint32_t featurefile_isattyfn(CPUState *cs, GuestFD *gf)
Peter Maydellc46a6532019-09-16 15:15:42 +0100716{
717 return 0;
718}
719
Keith Packard3c37cfe2021-01-08 22:42:50 +0000720static uint32_t featurefile_seekfn(CPUState *cs, GuestFD *gf,
Peter Maydellc46a6532019-09-16 15:15:42 +0100721 target_ulong offset)
722{
723 gf->featurefile_offset = offset;
724 return 0;
725}
726
Keith Packard3c37cfe2021-01-08 22:42:50 +0000727static uint32_t featurefile_flenfn(CPUState *cs, GuestFD *gf)
Peter Maydellc46a6532019-09-16 15:15:42 +0100728{
729 return sizeof(featurefile_data);
730}
731
Peter Maydell263eb622019-09-16 15:15:36 +0100732typedef struct GuestFDFunctions {
733 sys_closefn *closefn;
Peter Maydell52c8a162019-09-16 15:15:37 +0100734 sys_writefn *writefn;
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100735 sys_readfn *readfn;
Peter Maydell0213fa42019-09-16 15:15:39 +0100736 sys_isattyfn *isattyfn;
Peter Maydell45e88ff2019-09-16 15:15:40 +0100737 sys_seekfn *seekfn;
Peter Maydell1631a7b2019-09-16 15:15:41 +0100738 sys_flenfn *flenfn;
Peter Maydell263eb622019-09-16 15:15:36 +0100739} GuestFDFunctions;
740
741static const GuestFDFunctions guestfd_fns[] = {
742 [GuestFDHost] = {
743 .closefn = host_closefn,
Peter Maydell52c8a162019-09-16 15:15:37 +0100744 .writefn = host_writefn,
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100745 .readfn = host_readfn,
Peter Maydell0213fa42019-09-16 15:15:39 +0100746 .isattyfn = host_isattyfn,
Peter Maydell45e88ff2019-09-16 15:15:40 +0100747 .seekfn = host_seekfn,
Peter Maydell1631a7b2019-09-16 15:15:41 +0100748 .flenfn = host_flenfn,
Peter Maydell263eb622019-09-16 15:15:36 +0100749 },
750 [GuestFDGDB] = {
751 .closefn = gdb_closefn,
Peter Maydell52c8a162019-09-16 15:15:37 +0100752 .writefn = gdb_writefn,
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100753 .readfn = gdb_readfn,
Peter Maydell0213fa42019-09-16 15:15:39 +0100754 .isattyfn = gdb_isattyfn,
Peter Maydell45e88ff2019-09-16 15:15:40 +0100755 .seekfn = gdb_seekfn,
Peter Maydell1631a7b2019-09-16 15:15:41 +0100756 .flenfn = gdb_flenfn,
Peter Maydell263eb622019-09-16 15:15:36 +0100757 },
Peter Maydellc46a6532019-09-16 15:15:42 +0100758 [GuestFDFeatureFile] = {
759 .closefn = featurefile_closefn,
760 .writefn = featurefile_writefn,
761 .readfn = featurefile_readfn,
762 .isattyfn = featurefile_isattyfn,
763 .seekfn = featurefile_seekfn,
764 .flenfn = featurefile_flenfn,
765 },
Peter Maydell263eb622019-09-16 15:15:36 +0100766};
767
Alex Bennée3960ca52021-03-23 16:52:52 +0000768/*
769 * Read the input value from the argument block; fail the semihosting
770 * call if the memory read fails. Eventually we could use a generic
771 * CPUState helper function here.
Peter Maydellf296c0d2012-10-14 09:52:27 +0000772 */
Alex Bennée3960ca52021-03-23 16:52:52 +0000773static inline bool is_64bit_semihosting(CPUArchState *env)
774{
775#if defined(TARGET_ARM)
776 return is_a64(env);
777#elif defined(TARGET_RISCV)
778 return !riscv_cpu_is_32bit(env);
779#else
780#error un-handled architecture
781#endif
782}
783
784
Peter Maydellf296c0d2012-10-14 09:52:27 +0000785#define GET_ARG(n) do { \
Alex Bennée3960ca52021-03-23 16:52:52 +0000786 if (is_64bit_semihosting(env)) { \
Peter Maydellfaacc042015-09-07 10:39:28 +0100787 if (get_user_u64(arg ## n, args + (n) * 8)) { \
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100788 errno = EFAULT; \
Alex Bennée3960ca52021-03-23 16:52:52 +0000789 return set_swi_errno(cs, -1); \
Peter Maydellfaacc042015-09-07 10:39:28 +0100790 } \
791 } else { \
792 if (get_user_u32(arg ## n, args + (n) * 4)) { \
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100793 errno = EFAULT; \
Keith Packard3c37cfe2021-01-08 22:42:50 +0000794 return set_swi_errno(cs, -1); \
Peter Maydellfaacc042015-09-07 10:39:28 +0100795 } \
Peter Maydellf296c0d2012-10-14 09:52:27 +0000796 } \
797} while (0)
798
Peter Maydellfaacc042015-09-07 10:39:28 +0100799#define SET_ARG(n, val) \
Alex Bennée3960ca52021-03-23 16:52:52 +0000800 (is_64bit_semihosting(env) ? \
Peter Maydellfaacc042015-09-07 10:39:28 +0100801 put_user_u64(val, args + (n) * 8) : \
802 put_user_u32(val, args + (n) * 4))
803
Keith Packarda10b9d92021-01-08 22:42:52 +0000804
Alex Bennée4cb28db2019-05-14 12:08:39 +0100805/*
806 * Do a semihosting call.
807 *
808 * The specification always says that the "return register" either
809 * returns a specific value or is corrupted, so we don't need to
810 * report to our caller whether we are returning a value or trying to
811 * leave the register unchanged. We use 0xdeadbeef as the return value
812 * when there isn't a defined return value for the call.
813 */
Keith Packard0bb446d2021-01-08 22:42:49 +0000814target_ulong do_common_semihosting(CPUState *cs)
bellarda4f81972005-04-23 18:25:41 +0000815{
Keith Packard3c37cfe2021-01-08 22:42:50 +0000816 CPUArchState *env = cs->env_ptr;
pbrook53a59602006-03-25 19:31:22 +0000817 target_ulong args;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000818 target_ulong arg0, arg1, arg2, arg3;
Keith Packard27e3b102021-01-08 22:42:55 +0000819 target_ulong ul_ret;
bellarda4f81972005-04-23 18:25:41 +0000820 char * s;
821 int nr;
822 uint32_t ret;
pbrook8e716212007-01-20 17:12:09 +0000823 uint32_t len;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100824 GuestFD *gf;
Keith Packard4d834032021-01-08 22:42:54 +0000825 int64_t elapsed;
bellarda4f81972005-04-23 18:25:41 +0000826
Keith Packard3c37cfe2021-01-08 22:42:50 +0000827 (void) env; /* Used implicitly by arm lock_user macro */
828 nr = common_semi_arg(cs, 0) & 0xffffffffU;
829 args = common_semi_arg(cs, 1);
Peter Maydellfaacc042015-09-07 10:39:28 +0100830
bellarda4f81972005-04-23 18:25:41 +0000831 switch (nr) {
Stefan Weil38817252012-04-28 05:07:47 +0000832 case TARGET_SYS_OPEN:
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100833 {
834 int guestfd;
835
Peter Maydellf296c0d2012-10-14 09:52:27 +0000836 GET_ARG(0);
837 GET_ARG(1);
838 GET_ARG(2);
839 s = lock_user_string(arg0);
840 if (!s) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100841 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000842 return set_swi_errno(cs, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +0000843 }
844 if (arg1 >= 12) {
845 unlock_user(s, arg0, 0);
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100846 errno = EINVAL;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000847 return set_swi_errno(cs, -1);
Jim Meyering396bef42012-08-22 13:55:55 +0200848 }
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100849
850 guestfd = alloc_guestfd();
851 if (guestfd < 0) {
852 unlock_user(s, arg0, 0);
853 errno = EMFILE;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000854 return set_swi_errno(cs, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100855 }
856
bellarda4f81972005-04-23 18:25:41 +0000857 if (strcmp(s, ":tt") == 0) {
Peter Maydell6ee18642019-09-16 15:15:44 +0100858 int result_fileno;
859
860 /*
861 * We implement SH_EXT_STDOUT_STDERR, so:
862 * open for read == stdin
863 * open for write == stdout
864 * open for append == stderr
865 */
866 if (arg1 < 4) {
867 result_fileno = STDIN_FILENO;
868 } else if (arg1 < 8) {
869 result_fileno = STDOUT_FILENO;
870 } else {
871 result_fileno = STDERR_FILENO;
872 }
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100873 associate_guestfd(guestfd, result_fileno);
Peter Maydellf296c0d2012-10-14 09:52:27 +0000874 unlock_user(s, arg0, 0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100875 return guestfd;
bellarda4f81972005-04-23 18:25:41 +0000876 }
Peter Maydellc46a6532019-09-16 15:15:42 +0100877 if (strcmp(s, ":semihosting-features") == 0) {
878 unlock_user(s, arg0, 0);
879 /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
880 if (arg1 != 0 && arg1 != 1) {
881 dealloc_guestfd(guestfd);
882 errno = EACCES;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000883 return set_swi_errno(cs, -1);
Peter Maydellc46a6532019-09-16 15:15:42 +0100884 }
885 init_featurefile_guestfd(guestfd);
886 return guestfd;
887 }
888
pbrooka2d1eba2007-01-28 03:10:55 +0000889 if (use_gdb_syscalls()) {
Keith Packard3c37cfe2021-01-08 22:42:50 +0000890 common_semi_open_guestfd = guestfd;
891 ret = common_semi_gdb_syscall(cs, common_semi_open_cb,
892 "open,%s,%x,1a4", arg0, (int)arg2 + 1,
893 gdb_open_modeflags[arg1]);
pbrooka2d1eba2007-01-28 03:10:55 +0000894 } else {
Keith Packard3c37cfe2021-01-08 22:42:50 +0000895 ret = set_swi_errno(cs, open(s, open_modeflags[arg1], 0644));
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100896 if (ret == (uint32_t)-1) {
897 dealloc_guestfd(guestfd);
898 } else {
899 associate_guestfd(guestfd, ret);
900 ret = guestfd;
901 }
pbrooka2d1eba2007-01-28 03:10:55 +0000902 }
Peter Maydellf296c0d2012-10-14 09:52:27 +0000903 unlock_user(s, arg0, 0);
pbrook8e716212007-01-20 17:12:09 +0000904 return ret;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100905 }
Stefan Weil38817252012-04-28 05:07:47 +0000906 case TARGET_SYS_CLOSE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000907 GET_ARG(0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100908
909 gf = get_guestfd(arg0);
910 if (!gf) {
911 errno = EBADF;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000912 return set_swi_errno(cs, -1);
pbrooka2d1eba2007-01-28 03:10:55 +0000913 }
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100914
Keith Packard3c37cfe2021-01-08 22:42:50 +0000915 ret = guestfd_fns[gf->type].closefn(cs, gf);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100916 dealloc_guestfd(arg0);
917 return ret;
Stefan Weil38817252012-04-28 05:07:47 +0000918 case TARGET_SYS_WRITEC:
Keith Packard3c37cfe2021-01-08 22:42:50 +0000919 qemu_semihosting_console_outc(cs->env_ptr, args);
Alex Bennée0dc07722019-05-14 11:07:15 +0100920 return 0xdeadbeef;
Stefan Weil38817252012-04-28 05:07:47 +0000921 case TARGET_SYS_WRITE0:
Keith Packard3c37cfe2021-01-08 22:42:50 +0000922 return qemu_semihosting_console_outs(cs->env_ptr, args);
Stefan Weil38817252012-04-28 05:07:47 +0000923 case TARGET_SYS_WRITE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000924 GET_ARG(0);
925 GET_ARG(1);
926 GET_ARG(2);
927 len = arg2;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100928
929 gf = get_guestfd(arg0);
930 if (!gf) {
931 errno = EBADF;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000932 return set_swi_errno(cs, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100933 }
934
Keith Packard3c37cfe2021-01-08 22:42:50 +0000935 return guestfd_fns[gf->type].writefn(cs, gf, arg1, len);
Stefan Weil38817252012-04-28 05:07:47 +0000936 case TARGET_SYS_READ:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000937 GET_ARG(0);
938 GET_ARG(1);
939 GET_ARG(2);
940 len = arg2;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100941
942 gf = get_guestfd(arg0);
943 if (!gf) {
944 errno = EBADF;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000945 return set_swi_errno(cs, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100946 }
947
Keith Packard3c37cfe2021-01-08 22:42:50 +0000948 return guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
Stefan Weil38817252012-04-28 05:07:47 +0000949 case TARGET_SYS_READC:
Keith Packard3c37cfe2021-01-08 22:42:50 +0000950 return qemu_semihosting_console_inc(cs->env_ptr);
Keith Packard767ba042021-01-08 22:42:56 +0000951 case TARGET_SYS_ISERROR:
952 GET_ARG(0);
953 return (target_long) arg0 < 0 ? 1 : 0;
Stefan Weil38817252012-04-28 05:07:47 +0000954 case TARGET_SYS_ISTTY:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000955 GET_ARG(0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100956
957 gf = get_guestfd(arg0);
958 if (!gf) {
959 errno = EBADF;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000960 return set_swi_errno(cs, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100961 }
962
Keith Packard3c37cfe2021-01-08 22:42:50 +0000963 return guestfd_fns[gf->type].isattyfn(cs, gf);
Stefan Weil38817252012-04-28 05:07:47 +0000964 case TARGET_SYS_SEEK:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000965 GET_ARG(0);
966 GET_ARG(1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100967
968 gf = get_guestfd(arg0);
969 if (!gf) {
970 errno = EBADF;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000971 return set_swi_errno(cs, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100972 }
973
Keith Packard3c37cfe2021-01-08 22:42:50 +0000974 return guestfd_fns[gf->type].seekfn(cs, gf, arg1);
Stefan Weil38817252012-04-28 05:07:47 +0000975 case TARGET_SYS_FLEN:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000976 GET_ARG(0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100977
978 gf = get_guestfd(arg0);
979 if (!gf) {
980 errno = EBADF;
Keith Packard3c37cfe2021-01-08 22:42:50 +0000981 return set_swi_errno(cs, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100982 }
983
Keith Packard3c37cfe2021-01-08 22:42:50 +0000984 return guestfd_fns[gf->type].flenfn(cs, gf);
Stefan Weil38817252012-04-28 05:07:47 +0000985 case TARGET_SYS_TMPNAM:
Keith Packard27e3b102021-01-08 22:42:55 +0000986 GET_ARG(0);
987 GET_ARG(1);
988 GET_ARG(2);
989 if (asprintf(&s, "/tmp/qemu-%x%02x", getpid(),
990 (int) (arg1 & 0xff)) < 0) {
991 return -1;
992 }
993 ul_ret = (target_ulong) -1;
994
995 /* Make sure there's enough space in the buffer */
996 if (strlen(s) < arg2) {
997 char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0);
998 strcpy(output, s);
999 unlock_user(output, arg0, arg2);
1000 ul_ret = 0;
1001 }
1002 free(s);
1003 return ul_ret;
Stefan Weil38817252012-04-28 05:07:47 +00001004 case TARGET_SYS_REMOVE:
Peter Maydellf296c0d2012-10-14 09:52:27 +00001005 GET_ARG(0);
1006 GET_ARG(1);
pbrooka2d1eba2007-01-28 03:10:55 +00001007 if (use_gdb_syscalls()) {
Keith Packard3c37cfe2021-01-08 22:42:50 +00001008 ret = common_semi_gdb_syscall(cs, common_semi_cb, "unlink,%s",
1009 arg0, (int)arg1 + 1);
pbrooka2d1eba2007-01-28 03:10:55 +00001010 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +00001011 s = lock_user_string(arg0);
1012 if (!s) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001013 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001014 return set_swi_errno(cs, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +00001015 }
Keith Packard3c37cfe2021-01-08 22:42:50 +00001016 ret = set_swi_errno(cs, remove(s));
Peter Maydellf296c0d2012-10-14 09:52:27 +00001017 unlock_user(s, arg0, 0);
pbrooka2d1eba2007-01-28 03:10:55 +00001018 }
pbrook8e716212007-01-20 17:12:09 +00001019 return ret;
Stefan Weil38817252012-04-28 05:07:47 +00001020 case TARGET_SYS_RENAME:
Peter Maydellf296c0d2012-10-14 09:52:27 +00001021 GET_ARG(0);
1022 GET_ARG(1);
1023 GET_ARG(2);
1024 GET_ARG(3);
pbrooka2d1eba2007-01-28 03:10:55 +00001025 if (use_gdb_syscalls()) {
Keith Packard3c37cfe2021-01-08 22:42:50 +00001026 return common_semi_gdb_syscall(cs, common_semi_cb, "rename,%s,%s",
1027 arg0, (int)arg1 + 1, arg2,
1028 (int)arg3 + 1);
pbrooka2d1eba2007-01-28 03:10:55 +00001029 } else {
pbrook8e716212007-01-20 17:12:09 +00001030 char *s2;
Peter Maydellf296c0d2012-10-14 09:52:27 +00001031 s = lock_user_string(arg0);
1032 s2 = lock_user_string(arg2);
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001033 if (!s || !s2) {
1034 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001035 ret = set_swi_errno(cs, -1);
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001036 } else {
Keith Packard3c37cfe2021-01-08 22:42:50 +00001037 ret = set_swi_errno(cs, rename(s, s2));
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001038 }
bellard579a97f2007-11-11 14:26:47 +00001039 if (s2)
Peter Maydellf296c0d2012-10-14 09:52:27 +00001040 unlock_user(s2, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00001041 if (s)
Peter Maydellf296c0d2012-10-14 09:52:27 +00001042 unlock_user(s, arg0, 0);
pbrook8e716212007-01-20 17:12:09 +00001043 return ret;
1044 }
Stefan Weil38817252012-04-28 05:07:47 +00001045 case TARGET_SYS_CLOCK:
bellarda4f81972005-04-23 18:25:41 +00001046 return clock() / (CLOCKS_PER_SEC / 100);
Stefan Weil38817252012-04-28 05:07:47 +00001047 case TARGET_SYS_TIME:
Keith Packard3c37cfe2021-01-08 22:42:50 +00001048 return set_swi_errno(cs, time(NULL));
Stefan Weil38817252012-04-28 05:07:47 +00001049 case TARGET_SYS_SYSTEM:
Peter Maydellf296c0d2012-10-14 09:52:27 +00001050 GET_ARG(0);
1051 GET_ARG(1);
pbrooka2d1eba2007-01-28 03:10:55 +00001052 if (use_gdb_syscalls()) {
Keith Packard3c37cfe2021-01-08 22:42:50 +00001053 return common_semi_gdb_syscall(cs, common_semi_cb, "system,%s",
1054 arg0, (int)arg1 + 1);
pbrooka2d1eba2007-01-28 03:10:55 +00001055 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +00001056 s = lock_user_string(arg0);
1057 if (!s) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001058 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001059 return set_swi_errno(cs, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +00001060 }
Keith Packard3c37cfe2021-01-08 22:42:50 +00001061 ret = set_swi_errno(cs, system(s));
Peter Maydellf296c0d2012-10-14 09:52:27 +00001062 unlock_user(s, arg0, 0);
thsa982b532008-07-01 16:40:04 +00001063 return ret;
pbrooka2d1eba2007-01-28 03:10:55 +00001064 }
Stefan Weil38817252012-04-28 05:07:47 +00001065 case TARGET_SYS_ERRNO:
Keith Packard3c37cfe2021-01-08 22:42:50 +00001066 return get_swi_errno(cs);
Stefan Weil38817252012-04-28 05:07:47 +00001067 case TARGET_SYS_GET_CMDLINE:
pbrook38d06622006-11-19 20:29:35 +00001068 {
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001069 /* Build a command-line from the original argv.
1070 *
1071 * The inputs are:
Peter Maydellf296c0d2012-10-14 09:52:27 +00001072 * * arg0, pointer to a buffer of at least the size
1073 * specified in arg1.
1074 * * arg1, size of the buffer pointed to by arg0 in
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001075 * bytes.
1076 *
1077 * The outputs are:
Peter Maydellf296c0d2012-10-14 09:52:27 +00001078 * * arg0, pointer to null-terminated string of the
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001079 * command line.
Peter Maydellf296c0d2012-10-14 09:52:27 +00001080 * * arg1, length of the string pointed to by arg0.
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001081 */
bellard579a97f2007-11-11 14:26:47 +00001082
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001083 char *output_buffer;
Peter Maydellf296c0d2012-10-14 09:52:27 +00001084 size_t input_size;
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001085 size_t output_size;
1086 int status = 0;
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +01001087#if !defined(CONFIG_USER_ONLY)
1088 const char *cmdline;
Peter Maydell6ed68452019-09-16 15:15:34 +01001089#else
1090 TaskState *ts = cs->opaque;
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +01001091#endif
Peter Maydellf296c0d2012-10-14 09:52:27 +00001092 GET_ARG(0);
1093 GET_ARG(1);
1094 input_size = arg1;
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001095 /* Compute the size of the output string. */
1096#if !defined(CONFIG_USER_ONLY)
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +01001097 cmdline = semihosting_get_cmdline();
1098 if (cmdline == NULL) {
1099 cmdline = ""; /* Default to an empty line. */
1100 }
1101 output_size = strlen(cmdline) + 1; /* Count terminating 0. */
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001102#else
Wolfgang Schildbach2e8785a2010-12-06 15:06:05 +00001103 unsigned int i;
pbrook38d06622006-11-19 20:29:35 +00001104
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001105 output_size = ts->info->arg_end - ts->info->arg_start;
1106 if (!output_size) {
Alex Bennée4cb28db2019-05-14 12:08:39 +01001107 /*
1108 * We special-case the "empty command line" case (argc==0).
1109 * Just provide the terminating 0.
1110 */
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001111 output_size = 1;
Wolfgang Schildbach2e8785a2010-12-06 15:06:05 +00001112 }
pbrook8e716212007-01-20 17:12:09 +00001113#endif
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001114
1115 if (output_size > input_size) {
Alex Bennée4cb28db2019-05-14 12:08:39 +01001116 /* Not enough space to store command-line arguments. */
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001117 errno = E2BIG;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001118 return set_swi_errno(cs, -1);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001119 }
1120
1121 /* Adjust the command-line length. */
Peter Maydellf296c0d2012-10-14 09:52:27 +00001122 if (SET_ARG(1, output_size - 1)) {
1123 /* Couldn't write back to argument block */
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001124 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001125 return set_swi_errno(cs, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +00001126 }
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001127
1128 /* Lock the buffer on the ARM side. */
Peter Maydellf296c0d2012-10-14 09:52:27 +00001129 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001130 if (!output_buffer) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001131 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001132 return set_swi_errno(cs, -1);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001133 }
1134
1135 /* Copy the command-line arguments. */
1136#if !defined(CONFIG_USER_ONLY)
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +01001137 pstrcpy(output_buffer, output_size, cmdline);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001138#else
1139 if (output_size == 1) {
1140 /* Empty command-line. */
1141 output_buffer[0] = '\0';
1142 goto out;
1143 }
1144
1145 if (copy_from_user(output_buffer, ts->info->arg_start,
1146 output_size)) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001147 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001148 status = set_swi_errno(cs, -1);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001149 goto out;
1150 }
1151
1152 /* Separate arguments by white spaces. */
1153 for (i = 0; i < output_size - 1; i++) {
1154 if (output_buffer[i] == 0) {
1155 output_buffer[i] = ' ';
1156 }
1157 }
1158 out:
1159#endif
1160 /* Unlock the buffer on the ARM side. */
Peter Maydellf296c0d2012-10-14 09:52:27 +00001161 unlock_user(output_buffer, arg0, output_size);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001162
1163 return status;
1164 }
Stefan Weil38817252012-04-28 05:07:47 +00001165 case TARGET_SYS_HEAPINFO:
bellarda4f81972005-04-23 18:25:41 +00001166 {
Peter Maydellf5666412016-07-04 13:06:35 +01001167 target_ulong retvals[4];
Peter Maydell90e26f52016-07-07 13:47:00 +01001168 target_ulong limit;
Peter Maydellf5666412016-07-04 13:06:35 +01001169 int i;
Peter Maydell6ed68452019-09-16 15:15:34 +01001170#ifdef CONFIG_USER_ONLY
1171 TaskState *ts = cs->opaque;
Peter Maydell69515952020-11-19 09:23:46 +00001172#else
Keith Packard3c37cfe2021-01-08 22:42:50 +00001173 target_ulong rambase = common_semi_rambase(cs);
Peter Maydell6ed68452019-09-16 15:15:34 +01001174#endif
Peter Maydellf5666412016-07-04 13:06:35 +01001175
Peter Maydellf296c0d2012-10-14 09:52:27 +00001176 GET_ARG(0);
bellarda4f81972005-04-23 18:25:41 +00001177
pbrook8e716212007-01-20 17:12:09 +00001178#ifdef CONFIG_USER_ONLY
Alex Bennée4cb28db2019-05-14 12:08:39 +01001179 /*
1180 * Some C libraries assume the heap immediately follows .bss, so
1181 * allocate it using sbrk.
1182 */
bellarda4f81972005-04-23 18:25:41 +00001183 if (!ts->heap_limit) {
Peter Maydell206ae742011-04-18 16:34:25 +01001184 abi_ulong ret;
bellarda4f81972005-04-23 18:25:41 +00001185
pbrook53a59602006-03-25 19:31:22 +00001186 ts->heap_base = do_brk(0);
Keith Packard3c37cfe2021-01-08 22:42:50 +00001187 limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE;
bellarda4f81972005-04-23 18:25:41 +00001188 /* Try a big heap, and reduce the size if that fails. */
1189 for (;;) {
pbrook53a59602006-03-25 19:31:22 +00001190 ret = do_brk(limit);
Peter Maydell206ae742011-04-18 16:34:25 +01001191 if (ret >= limit) {
bellarda4f81972005-04-23 18:25:41 +00001192 break;
Peter Maydell206ae742011-04-18 16:34:25 +01001193 }
bellarda4f81972005-04-23 18:25:41 +00001194 limit = (ts->heap_base >> 1) + (limit >> 1);
1195 }
1196 ts->heap_limit = limit;
1197 }
ths3b46e622007-09-17 08:09:54 +00001198
Peter Maydellf5666412016-07-04 13:06:35 +01001199 retvals[0] = ts->heap_base;
1200 retvals[1] = ts->heap_limit;
1201 retvals[2] = ts->stack_base;
1202 retvals[3] = 0; /* Stack limit. */
pbrook8e716212007-01-20 17:12:09 +00001203#else
Paolo Bonzini6e504a92020-10-28 06:18:20 -04001204 limit = current_machine->ram_size;
pbrook8e716212007-01-20 17:12:09 +00001205 /* TODO: Make this use the limit of the loaded application. */
Peter Maydell69515952020-11-19 09:23:46 +00001206 retvals[0] = rambase + limit / 2;
1207 retvals[1] = rambase + limit;
1208 retvals[2] = rambase + limit; /* Stack base */
1209 retvals[3] = rambase; /* Stack limit. */
pbrook8e716212007-01-20 17:12:09 +00001210#endif
Peter Maydellf5666412016-07-04 13:06:35 +01001211
1212 for (i = 0; i < ARRAY_SIZE(retvals); i++) {
1213 bool fail;
1214
Alex Bennée35e3f022021-03-23 16:52:53 +00001215 if (is_64bit_semihosting(env)) {
1216 fail = put_user_u64(retvals[i], arg0 + i * 8);
1217 } else {
1218 fail = put_user_u32(retvals[i], arg0 + i * 4);
1219 }
Peter Maydellf5666412016-07-04 13:06:35 +01001220
1221 if (fail) {
1222 /* Couldn't write back to argument block */
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001223 errno = EFAULT;
Keith Packard3c37cfe2021-01-08 22:42:50 +00001224 return set_swi_errno(cs, -1);
Peter Maydellf5666412016-07-04 13:06:35 +01001225 }
1226 }
bellarda4f81972005-04-23 18:25:41 +00001227 return 0;
1228 }
Stefan Weil38817252012-04-28 05:07:47 +00001229 case TARGET_SYS_EXIT:
Peter Maydell22a43bb2019-09-16 15:15:43 +01001230 case TARGET_SYS_EXIT_EXTENDED:
Keith Packard3c37cfe2021-01-08 22:42:50 +00001231 if (common_semi_sys_exit_extended(cs, nr)) {
Alex Bennée4cb28db2019-05-14 12:08:39 +01001232 /*
Peter Maydell22a43bb2019-09-16 15:15:43 +01001233 * The A64 version of SYS_EXIT takes a parameter block,
Peter Maydell7446d352015-09-07 10:39:28 +01001234 * so the application-exit type can return a subcode which
1235 * is the exit status code from the application.
Peter Maydell22a43bb2019-09-16 15:15:43 +01001236 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1237 * which allows A32/T32 guests to also provide a status code.
Peter Maydell7446d352015-09-07 10:39:28 +01001238 */
1239 GET_ARG(0);
1240 GET_ARG(1);
1241
1242 if (arg0 == ADP_Stopped_ApplicationExit) {
1243 ret = arg1;
1244 } else {
1245 ret = 1;
1246 }
1247 } else {
Alex Bennée4cb28db2019-05-14 12:08:39 +01001248 /*
Peter Maydell22a43bb2019-09-16 15:15:43 +01001249 * The A32/T32 version of SYS_EXIT specifies only
1250 * Stopped_ApplicationExit as normal exit, but does not
1251 * allow the guest to specify the exit status code.
1252 * Everything else is considered an error.
Alex Bennée4cb28db2019-05-14 12:08:39 +01001253 */
Peter Maydell7446d352015-09-07 10:39:28 +01001254 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
1255 }
Alex Bennéead9dcb22021-01-08 22:42:43 +00001256 gdb_exit(ret);
Liviu Ionescu1ecc3a22014-12-11 12:07:48 +00001257 exit(ret);
Keith Packard4d834032021-01-08 22:42:54 +00001258 case TARGET_SYS_ELAPSED:
1259 elapsed = get_clock() - clock_start;
1260 if (sizeof(target_ulong) == 8) {
1261 SET_ARG(0, elapsed);
1262 } else {
1263 SET_ARG(0, (uint32_t) elapsed);
1264 SET_ARG(1, (uint32_t) (elapsed >> 32));
1265 }
1266 return 0;
1267 case TARGET_SYS_TICKFREQ:
1268 /* qemu always uses nsec */
1269 return 1000000000;
Peter Maydelle9ebfbf2015-09-07 10:39:28 +01001270 case TARGET_SYS_SYNCCACHE:
Alex Bennée4cb28db2019-05-14 12:08:39 +01001271 /*
1272 * Clean the D-cache and invalidate the I-cache for the specified
Peter Maydelle9ebfbf2015-09-07 10:39:28 +01001273 * virtual address range. This is a nop for us since we don't
1274 * implement caches. This is only present on A64.
1275 */
Keith Packard3c37cfe2021-01-08 22:42:50 +00001276#ifdef TARGET_ARM
1277 if (is_a64(cs->env_ptr)) {
Peter Maydelle9ebfbf2015-09-07 10:39:28 +01001278 return 0;
1279 }
Keith Packard3c37cfe2021-01-08 22:42:50 +00001280#endif
Keith Packarda10b9d92021-01-08 22:42:52 +00001281#ifdef TARGET_RISCV
1282 return 0;
1283#endif
Peter Maydelle9ebfbf2015-09-07 10:39:28 +01001284 /* fall through -- invalid for A32/T32 */
bellarda4f81972005-04-23 18:25:41 +00001285 default:
1286 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
Markus Armbruster90c84c52019-04-17 21:18:02 +02001287 cpu_dump_state(cs, stderr, 0);
bellarda4f81972005-04-23 18:25:41 +00001288 abort();
1289 }
1290}