blob: f7b7bff522852e94d001cd3fc725b1689b7bebed [file] [log] [blame]
bellarda4f81972005-04-23 18:25:41 +00001/*
2 * Arm "Angel" semihosting syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
pbrook8e716212007-01-20 17:12:09 +00004 * Copyright (c) 2005, 2007 CodeSourcery.
Alex Bennée4cb28db2019-05-14 12:08:39 +01005 * Copyright (c) 2019 Linaro
pbrook8e716212007-01-20 17:12:09 +00006 * Written by Paul Brook.
bellarda4f81972005-04-23 18:25:41 +00007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000019 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Alex Bennée4cb28db2019-05-14 12:08:39 +010020 *
21 * ARM Semihosting is documented in:
22 * Semihosting for AArch32 and AArch64 Release 2.0
23 * https://static.docs.arm.com/100863/0200/semihosting.pdf
bellarda4f81972005-04-23 18:25:41 +000024 */
25
Peter Maydell74c21bd2015-12-07 16:23:44 +000026#include "qemu/osdep.h"
bellarda4f81972005-04-23 18:25:41 +000027
pbrook8e716212007-01-20 17:12:09 +000028#include "cpu.h"
Alex Bennéef1672e62019-05-13 14:43:57 +010029#include "hw/semihosting/semihost.h"
Alex Bennée0dc07722019-05-14 11:07:15 +010030#include "hw/semihosting/console.h"
Alex Bennéea1317952019-05-14 12:15:38 +010031#include "qemu/log.h"
pbrook8e716212007-01-20 17:12:09 +000032#ifdef CONFIG_USER_ONLY
bellarda4f81972005-04-23 18:25:41 +000033#include "qemu.h"
34
35#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
pbrook8e716212007-01-20 17:12:09 +000036#else
Paolo Bonzini022c62c2012-12-17 18:19:49 +010037#include "exec/gdbstub.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020038#include "qemu/cutils.h"
Peter Maydell69515952020-11-19 09:23:46 +000039#include "hw/arm/boot.h"
Paolo Bonzini6e504a92020-10-28 06:18:20 -040040#include "hw/boards.h"
pbrook8e716212007-01-20 17:12:09 +000041#endif
bellarda4f81972005-04-23 18:25:41 +000042
Stefan Weil38817252012-04-28 05:07:47 +000043#define TARGET_SYS_OPEN 0x01
44#define TARGET_SYS_CLOSE 0x02
45#define TARGET_SYS_WRITEC 0x03
46#define TARGET_SYS_WRITE0 0x04
47#define TARGET_SYS_WRITE 0x05
48#define TARGET_SYS_READ 0x06
49#define TARGET_SYS_READC 0x07
50#define TARGET_SYS_ISTTY 0x09
51#define TARGET_SYS_SEEK 0x0a
52#define TARGET_SYS_FLEN 0x0c
53#define TARGET_SYS_TMPNAM 0x0d
54#define TARGET_SYS_REMOVE 0x0e
55#define TARGET_SYS_RENAME 0x0f
56#define TARGET_SYS_CLOCK 0x10
57#define TARGET_SYS_TIME 0x11
58#define TARGET_SYS_SYSTEM 0x12
59#define TARGET_SYS_ERRNO 0x13
60#define TARGET_SYS_GET_CMDLINE 0x15
61#define TARGET_SYS_HEAPINFO 0x16
62#define TARGET_SYS_EXIT 0x18
Peter Maydelle9ebfbf2015-09-07 10:39:28 +010063#define TARGET_SYS_SYNCCACHE 0x19
Peter Maydell22a43bb2019-09-16 15:15:43 +010064#define TARGET_SYS_EXIT_EXTENDED 0x20
bellarda4f81972005-04-23 18:25:41 +000065
Liviu Ionescu1ecc3a22014-12-11 12:07:48 +000066/* ADP_Stopped_ApplicationExit is used for exit(0),
67 * anything else is implemented as exit(1) */
68#define ADP_Stopped_ApplicationExit (0x20026)
69
bellarda4f81972005-04-23 18:25:41 +000070#ifndef O_BINARY
71#define O_BINARY 0
72#endif
73
pbrooka2d1eba2007-01-28 03:10:55 +000074#define GDB_O_RDONLY 0x000
75#define GDB_O_WRONLY 0x001
76#define GDB_O_RDWR 0x002
77#define GDB_O_APPEND 0x008
78#define GDB_O_CREAT 0x200
79#define GDB_O_TRUNC 0x400
80#define GDB_O_BINARY 0
81
82static int gdb_open_modeflags[12] = {
83 GDB_O_RDONLY,
84 GDB_O_RDONLY | GDB_O_BINARY,
85 GDB_O_RDWR,
86 GDB_O_RDWR | GDB_O_BINARY,
87 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
88 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
89 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
90 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
91 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
92 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
93 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
94 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
95};
96
97static int open_modeflags[12] = {
bellarda4f81972005-04-23 18:25:41 +000098 O_RDONLY,
99 O_RDONLY | O_BINARY,
100 O_RDWR,
101 O_RDWR | O_BINARY,
102 O_WRONLY | O_CREAT | O_TRUNC,
103 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
104 O_RDWR | O_CREAT | O_TRUNC,
105 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
106 O_WRONLY | O_CREAT | O_APPEND,
107 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
108 O_RDWR | O_CREAT | O_APPEND,
109 O_RDWR | O_CREAT | O_APPEND | O_BINARY
110};
111
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100112typedef enum GuestFDType {
113 GuestFDUnused = 0,
114 GuestFDHost = 1,
Peter Maydell263eb622019-09-16 15:15:36 +0100115 GuestFDGDB = 2,
Peter Maydellc46a6532019-09-16 15:15:42 +0100116 GuestFDFeatureFile = 3,
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100117} GuestFDType;
118
119/*
120 * Guest file descriptors are integer indexes into an array of
121 * these structures (we will dynamically resize as necessary).
122 */
123typedef struct GuestFD {
124 GuestFDType type;
Peter Maydellc46a6532019-09-16 15:15:42 +0100125 union {
126 int hostfd;
127 target_ulong featurefile_offset;
128 };
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100129} GuestFD;
130
131static GArray *guestfd_array;
132
133/*
134 * Allocate a new guest file descriptor and return it; if we
135 * couldn't allocate a new fd then return -1.
136 * This is a fairly simplistic implementation because we don't
137 * expect that most semihosting guest programs will make very
138 * heavy use of opening and closing fds.
139 */
140static int alloc_guestfd(void)
141{
142 guint i;
143
144 if (!guestfd_array) {
145 /* New entries zero-initialized, i.e. type GuestFDUnused */
146 guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
147 }
148
Masahiro Yamada21bf9b02020-01-17 14:09:30 +0000149 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
150 for (i = 1; i < guestfd_array->len; i++) {
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100151 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
152
153 if (gf->type == GuestFDUnused) {
154 return i;
155 }
156 }
157
158 /* All elements already in use: expand the array */
159 g_array_set_size(guestfd_array, i + 1);
160 return i;
161}
162
163/*
164 * Look up the guestfd in the data structure; return NULL
165 * for out of bounds, but don't check whether the slot is unused.
166 * This is used internally by the other guestfd functions.
167 */
168static GuestFD *do_get_guestfd(int guestfd)
169{
170 if (!guestfd_array) {
171 return NULL;
172 }
173
Masahiro Yamada21bf9b02020-01-17 14:09:30 +0000174 if (guestfd <= 0 || guestfd >= guestfd_array->len) {
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100175 return NULL;
176 }
177
178 return &g_array_index(guestfd_array, GuestFD, guestfd);
179}
180
181/*
182 * Associate the specified guest fd (which must have been
183 * allocated via alloc_fd() and not previously used) with
Peter Maydell263eb622019-09-16 15:15:36 +0100184 * the specified host/gdb fd.
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100185 */
186static void associate_guestfd(int guestfd, int hostfd)
187{
188 GuestFD *gf = do_get_guestfd(guestfd);
189
190 assert(gf);
Peter Maydell263eb622019-09-16 15:15:36 +0100191 gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100192 gf->hostfd = hostfd;
193}
194
195/*
196 * Deallocate the specified guest file descriptor. This doesn't
197 * close the host fd, it merely undoes the work of alloc_fd().
198 */
199static void dealloc_guestfd(int guestfd)
200{
201 GuestFD *gf = do_get_guestfd(guestfd);
202
203 assert(gf);
204 gf->type = GuestFDUnused;
205}
206
207/*
208 * Given a guest file descriptor, get the associated struct.
209 * If the fd is not valid, return NULL. This is the function
210 * used by the various semihosting calls to validate a handle
211 * from the guest.
212 * Note: calling alloc_guestfd() or dealloc_guestfd() will
213 * invalidate any GuestFD* obtained by calling this function.
214 */
215static GuestFD *get_guestfd(int guestfd)
216{
217 GuestFD *gf = do_get_guestfd(guestfd);
218
219 if (!gf || gf->type == GuestFDUnused) {
220 return NULL;
221 }
222 return gf;
223}
224
Peter Maydell6ed68452019-09-16 15:15:34 +0100225/*
226 * The semihosting API has no concept of its errno being thread-safe,
227 * as the API design predates SMP CPUs and was intended as a simple
228 * real-hardware set of debug functionality. For QEMU, we make the
229 * errno be per-thread in linux-user mode; in softmmu it is a simple
230 * global, and we assume that the guest takes care of avoiding any races.
231 */
232#ifndef CONFIG_USER_ONLY
Peter Maydell1b003822019-09-16 15:15:30 +0100233static target_ulong syscall_err;
234
Peter Maydell6ed68452019-09-16 15:15:34 +0100235#include "exec/softmmu-semi.h"
236#endif
237
Andreas Färber81926f42012-03-14 01:38:23 +0100238static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
pbrook8e716212007-01-20 17:12:09 +0000239{
Peter Maydell1b003822019-09-16 15:15:30 +0100240 if (code == (uint32_t)-1) {
Peter Maydell6ed68452019-09-16 15:15:34 +0100241#ifdef CONFIG_USER_ONLY
242 CPUState *cs = env_cpu(env);
243 TaskState *ts = cs->opaque;
244
245 ts->swi_errno = errno;
246#else
Peter Maydell1b003822019-09-16 15:15:30 +0100247 syscall_err = errno;
Peter Maydell6ed68452019-09-16 15:15:34 +0100248#endif
Peter Maydell1b003822019-09-16 15:15:30 +0100249 }
pbrook8e716212007-01-20 17:12:09 +0000250 return code;
251}
252
Peter Maydell6ed68452019-09-16 15:15:34 +0100253static inline uint32_t get_swi_errno(CPUARMState *env)
254{
255#ifdef CONFIG_USER_ONLY
256 CPUState *cs = env_cpu(env);
257 TaskState *ts = cs->opaque;
258
259 return ts->swi_errno;
260#else
261 return syscall_err;
pbrook8e716212007-01-20 17:12:09 +0000262#endif
Peter Maydell6ed68452019-09-16 15:15:34 +0100263}
bellarda4f81972005-04-23 18:25:41 +0000264
pbrooka2d1eba2007-01-28 03:10:55 +0000265static target_ulong arm_semi_syscall_len;
266
Andreas Färber9e0c5422013-06-27 17:45:01 +0200267static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
pbrooka2d1eba2007-01-28 03:10:55 +0000268{
Andreas Färber9e0c5422013-06-27 17:45:01 +0200269 ARMCPU *cpu = ARM_CPU(cs);
270 CPUARMState *env = &cpu->env;
Peter Maydellfaacc042015-09-07 10:39:28 +0100271 target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
pbrook33d9cc82007-06-09 14:44:00 +0000272
pbrooka2d1eba2007-01-28 03:10:55 +0000273 if (ret == (target_ulong)-1) {
Peter Maydell939f5b42019-09-16 15:15:35 +0100274 errno = err;
275 set_swi_errno(env, -1);
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100276 reg0 = ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000277 } else {
278 /* Fixup syscalls that use nonstardard return conventions. */
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100279 switch (reg0) {
Stefan Weil38817252012-04-28 05:07:47 +0000280 case TARGET_SYS_WRITE:
281 case TARGET_SYS_READ:
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100282 reg0 = arm_semi_syscall_len - ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000283 break;
Stefan Weil38817252012-04-28 05:07:47 +0000284 case TARGET_SYS_SEEK:
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100285 reg0 = 0;
pbrooka2d1eba2007-01-28 03:10:55 +0000286 break;
287 default:
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100288 reg0 = ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000289 break;
290 }
291 }
Peter Maydellfaacc042015-09-07 10:39:28 +0100292 if (is_a64(env)) {
293 env->xregs[0] = reg0;
294 } else {
295 env->regs[0] = reg0;
296 }
297}
298
299static target_ulong arm_flen_buf(ARMCPU *cpu)
300{
301 /* Return an address in target memory of 64 bytes where the remote
302 * gdb should write its stat struct. (The format of this structure
303 * is defined by GDB's remote protocol and is not target-specific.)
304 * We put this on the guest's stack just below SP.
305 */
306 CPUARMState *env = &cpu->env;
307 target_ulong sp;
308
309 if (is_a64(env)) {
310 sp = env->xregs[31];
311 } else {
312 sp = env->regs[13];
313 }
314
315 return sp - 64;
pbrooka2d1eba2007-01-28 03:10:55 +0000316}
317
Andreas Färber9e0c5422013-06-27 17:45:01 +0200318static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
pbrook33d9cc82007-06-09 14:44:00 +0000319{
Andreas Färber9e0c5422013-06-27 17:45:01 +0200320 ARMCPU *cpu = ARM_CPU(cs);
321 CPUARMState *env = &cpu->env;
pbrook33d9cc82007-06-09 14:44:00 +0000322 /* The size is always stored in big-endian order, extract
323 the value. We assume the size always fit in 32 bits. */
324 uint32_t size;
Peter Maydellfaacc042015-09-07 10:39:28 +0100325 cpu_memory_rw_debug(cs, arm_flen_buf(cpu) + 32, (uint8_t *)&size, 4, 0);
326 size = be32_to_cpu(size);
327 if (is_a64(env)) {
328 env->xregs[0] = size;
329 } else {
330 env->regs[0] = size;
331 }
Peter Maydell939f5b42019-09-16 15:15:35 +0100332 errno = err;
333 set_swi_errno(env, -1);
pbrook33d9cc82007-06-09 14:44:00 +0000334}
335
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100336static int arm_semi_open_guestfd;
337
338static void arm_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
339{
340 ARMCPU *cpu = ARM_CPU(cs);
341 CPUARMState *env = &cpu->env;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100342 if (ret == (target_ulong)-1) {
Peter Maydell939f5b42019-09-16 15:15:35 +0100343 errno = err;
344 set_swi_errno(env, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100345 dealloc_guestfd(arm_semi_open_guestfd);
346 } else {
347 associate_guestfd(arm_semi_open_guestfd, ret);
348 ret = arm_semi_open_guestfd;
349 }
350
351 if (is_a64(env)) {
352 env->xregs[0] = ret;
353 } else {
354 env->regs[0] = ret;
355 }
356}
357
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100358static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
359 const char *fmt, ...)
360{
361 va_list va;
362 CPUARMState *env = &cpu->env;
363
364 va_start(va, fmt);
365 gdb_do_syscallv(cb, fmt, va);
366 va_end(va);
367
Peter Maydellf8ad2302019-09-16 15:15:32 +0100368 /*
369 * FIXME: in softmmu mode, the gdbstub will schedule our callback
370 * to occur, but will not actually call it to complete the syscall
371 * until after this function has returned and we are back in the
372 * CPU main loop. Therefore callers to this function must not
373 * do anything with its return value, because it is not necessarily
374 * the result of the syscall, but could just be the old value of X0.
375 * The only thing safe to do with this is that the callers of
376 * do_arm_semihosting() will write it straight back into X0.
377 * (In linux-user mode, the callback will have happened before
378 * gdb_do_syscallv() returns.)
379 *
380 * We should tidy this up so neither this function nor
381 * do_arm_semihosting() return a value, so the mistake of
382 * doing something with the return value is not possible to make.
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100383 */
384
Peter Maydellfaacc042015-09-07 10:39:28 +0100385 return is_a64(env) ? env->xregs[0] : env->regs[0];
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100386}
387
Peter Maydell263eb622019-09-16 15:15:36 +0100388/*
389 * Types for functions implementing various semihosting calls
390 * for specific types of guest file descriptor. These must all
391 * do the work and return the required return value for the guest,
392 * setting the guest errno if appropriate.
393 */
394typedef uint32_t sys_closefn(ARMCPU *cpu, GuestFD *gf);
Peter Maydell52c8a162019-09-16 15:15:37 +0100395typedef uint32_t sys_writefn(ARMCPU *cpu, GuestFD *gf,
396 target_ulong buf, uint32_t len);
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100397typedef uint32_t sys_readfn(ARMCPU *cpu, GuestFD *gf,
398 target_ulong buf, uint32_t len);
Peter Maydell0213fa42019-09-16 15:15:39 +0100399typedef uint32_t sys_isattyfn(ARMCPU *cpu, GuestFD *gf);
Peter Maydell45e88ff2019-09-16 15:15:40 +0100400typedef uint32_t sys_seekfn(ARMCPU *cpu, GuestFD *gf,
401 target_ulong offset);
Peter Maydell1631a7b2019-09-16 15:15:41 +0100402typedef uint32_t sys_flenfn(ARMCPU *cpu, GuestFD *gf);
Peter Maydell263eb622019-09-16 15:15:36 +0100403
404static uint32_t host_closefn(ARMCPU *cpu, GuestFD *gf)
405{
406 CPUARMState *env = &cpu->env;
407
Peter Maydell16ab12a2020-01-30 16:02:01 +0000408 /*
409 * Only close the underlying host fd if it's one we opened on behalf
410 * of the guest in SYS_OPEN.
411 */
412 if (gf->hostfd == STDIN_FILENO ||
413 gf->hostfd == STDOUT_FILENO ||
414 gf->hostfd == STDERR_FILENO) {
415 return 0;
416 }
Peter Maydell263eb622019-09-16 15:15:36 +0100417 return set_swi_errno(env, close(gf->hostfd));
418}
419
Peter Maydell52c8a162019-09-16 15:15:37 +0100420static uint32_t host_writefn(ARMCPU *cpu, GuestFD *gf,
421 target_ulong buf, uint32_t len)
422{
423 uint32_t ret;
424 CPUARMState *env = &cpu->env;
425 char *s = lock_user(VERIFY_READ, buf, len, 1);
426 if (!s) {
427 /* Return bytes not written on error */
428 return len;
429 }
430 ret = set_swi_errno(env, write(gf->hostfd, s, len));
431 unlock_user(s, buf, 0);
432 if (ret == (uint32_t)-1) {
433 ret = 0;
434 }
435 /* Return bytes not written */
436 return len - ret;
437}
438
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100439static uint32_t host_readfn(ARMCPU *cpu, GuestFD *gf,
440 target_ulong buf, uint32_t len)
441{
442 uint32_t ret;
443 CPUARMState *env = &cpu->env;
444 char *s = lock_user(VERIFY_WRITE, buf, len, 0);
445 if (!s) {
446 /* return bytes not read */
447 return len;
448 }
449 do {
450 ret = set_swi_errno(env, read(gf->hostfd, s, len));
451 } while (ret == -1 && errno == EINTR);
452 unlock_user(s, buf, len);
453 if (ret == (uint32_t)-1) {
454 ret = 0;
455 }
456 /* Return bytes not read */
457 return len - ret;
458}
459
Peter Maydell0213fa42019-09-16 15:15:39 +0100460static uint32_t host_isattyfn(ARMCPU *cpu, GuestFD *gf)
461{
462 return isatty(gf->hostfd);
463}
464
Peter Maydell45e88ff2019-09-16 15:15:40 +0100465static uint32_t host_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
466{
467 CPUARMState *env = &cpu->env;
468 uint32_t ret = set_swi_errno(env, lseek(gf->hostfd, offset, SEEK_SET));
469 if (ret == (uint32_t)-1) {
470 return -1;
471 }
472 return 0;
473}
474
Peter Maydell1631a7b2019-09-16 15:15:41 +0100475static uint32_t host_flenfn(ARMCPU *cpu, GuestFD *gf)
476{
477 CPUARMState *env = &cpu->env;
478 struct stat buf;
479 uint32_t ret = set_swi_errno(env, fstat(gf->hostfd, &buf));
480 if (ret == (uint32_t)-1) {
481 return -1;
482 }
483 return buf.st_size;
484}
485
Peter Maydell263eb622019-09-16 15:15:36 +0100486static uint32_t gdb_closefn(ARMCPU *cpu, GuestFD *gf)
487{
488 return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", gf->hostfd);
489}
490
Peter Maydell52c8a162019-09-16 15:15:37 +0100491static uint32_t gdb_writefn(ARMCPU *cpu, GuestFD *gf,
492 target_ulong buf, uint32_t len)
493{
494 arm_semi_syscall_len = len;
495 return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
496 gf->hostfd, buf, len);
497}
498
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100499static uint32_t gdb_readfn(ARMCPU *cpu, GuestFD *gf,
500 target_ulong buf, uint32_t len)
501{
502 arm_semi_syscall_len = len;
503 return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
504 gf->hostfd, buf, len);
505}
506
Peter Maydell0213fa42019-09-16 15:15:39 +0100507static uint32_t gdb_isattyfn(ARMCPU *cpu, GuestFD *gf)
508{
509 return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", gf->hostfd);
510}
511
Peter Maydell45e88ff2019-09-16 15:15:40 +0100512static uint32_t gdb_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
513{
514 return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
515 gf->hostfd, offset);
516}
517
Peter Maydell1631a7b2019-09-16 15:15:41 +0100518static uint32_t gdb_flenfn(ARMCPU *cpu, GuestFD *gf)
519{
520 return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
521 gf->hostfd, arm_flen_buf(cpu));
522}
523
Peter Maydellc46a6532019-09-16 15:15:42 +0100524#define SHFB_MAGIC_0 0x53
525#define SHFB_MAGIC_1 0x48
526#define SHFB_MAGIC_2 0x46
527#define SHFB_MAGIC_3 0x42
528
Peter Maydell22a43bb2019-09-16 15:15:43 +0100529/* Feature bits reportable in feature byte 0 */
530#define SH_EXT_EXIT_EXTENDED (1 << 0)
Peter Maydell6ee18642019-09-16 15:15:44 +0100531#define SH_EXT_STDOUT_STDERR (1 << 1)
Peter Maydell22a43bb2019-09-16 15:15:43 +0100532
Peter Maydellc46a6532019-09-16 15:15:42 +0100533static const uint8_t featurefile_data[] = {
534 SHFB_MAGIC_0,
535 SHFB_MAGIC_1,
536 SHFB_MAGIC_2,
537 SHFB_MAGIC_3,
Peter Maydell6ee18642019-09-16 15:15:44 +0100538 SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
Peter Maydellc46a6532019-09-16 15:15:42 +0100539};
540
541static void init_featurefile_guestfd(int guestfd)
542{
543 GuestFD *gf = do_get_guestfd(guestfd);
544
545 assert(gf);
546 gf->type = GuestFDFeatureFile;
547 gf->featurefile_offset = 0;
548}
549
550static uint32_t featurefile_closefn(ARMCPU *cpu, GuestFD *gf)
551{
552 /* Nothing to do */
553 return 0;
554}
555
556static uint32_t featurefile_writefn(ARMCPU *cpu, GuestFD *gf,
557 target_ulong buf, uint32_t len)
558{
559 /* This fd can never be open for writing */
560 CPUARMState *env = &cpu->env;
561
562 errno = EBADF;
563 return set_swi_errno(env, -1);
564}
565
566static uint32_t featurefile_readfn(ARMCPU *cpu, GuestFD *gf,
567 target_ulong buf, uint32_t len)
568{
569 uint32_t i;
570#ifndef CONFIG_USER_ONLY
571 CPUARMState *env = &cpu->env;
572#endif
573 char *s;
574
575 s = lock_user(VERIFY_WRITE, buf, len, 0);
576 if (!s) {
577 return len;
578 }
579
580 for (i = 0; i < len; i++) {
581 if (gf->featurefile_offset >= sizeof(featurefile_data)) {
582 break;
583 }
584 s[i] = featurefile_data[gf->featurefile_offset];
585 gf->featurefile_offset++;
586 }
587
588 unlock_user(s, buf, len);
589
590 /* Return number of bytes not read */
591 return len - i;
592}
593
594static uint32_t featurefile_isattyfn(ARMCPU *cpu, GuestFD *gf)
595{
596 return 0;
597}
598
599static uint32_t featurefile_seekfn(ARMCPU *cpu, GuestFD *gf,
600 target_ulong offset)
601{
602 gf->featurefile_offset = offset;
603 return 0;
604}
605
606static uint32_t featurefile_flenfn(ARMCPU *cpu, GuestFD *gf)
607{
608 return sizeof(featurefile_data);
609}
610
Peter Maydell263eb622019-09-16 15:15:36 +0100611typedef struct GuestFDFunctions {
612 sys_closefn *closefn;
Peter Maydell52c8a162019-09-16 15:15:37 +0100613 sys_writefn *writefn;
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100614 sys_readfn *readfn;
Peter Maydell0213fa42019-09-16 15:15:39 +0100615 sys_isattyfn *isattyfn;
Peter Maydell45e88ff2019-09-16 15:15:40 +0100616 sys_seekfn *seekfn;
Peter Maydell1631a7b2019-09-16 15:15:41 +0100617 sys_flenfn *flenfn;
Peter Maydell263eb622019-09-16 15:15:36 +0100618} GuestFDFunctions;
619
620static const GuestFDFunctions guestfd_fns[] = {
621 [GuestFDHost] = {
622 .closefn = host_closefn,
Peter Maydell52c8a162019-09-16 15:15:37 +0100623 .writefn = host_writefn,
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100624 .readfn = host_readfn,
Peter Maydell0213fa42019-09-16 15:15:39 +0100625 .isattyfn = host_isattyfn,
Peter Maydell45e88ff2019-09-16 15:15:40 +0100626 .seekfn = host_seekfn,
Peter Maydell1631a7b2019-09-16 15:15:41 +0100627 .flenfn = host_flenfn,
Peter Maydell263eb622019-09-16 15:15:36 +0100628 },
629 [GuestFDGDB] = {
630 .closefn = gdb_closefn,
Peter Maydell52c8a162019-09-16 15:15:37 +0100631 .writefn = gdb_writefn,
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100632 .readfn = gdb_readfn,
Peter Maydell0213fa42019-09-16 15:15:39 +0100633 .isattyfn = gdb_isattyfn,
Peter Maydell45e88ff2019-09-16 15:15:40 +0100634 .seekfn = gdb_seekfn,
Peter Maydell1631a7b2019-09-16 15:15:41 +0100635 .flenfn = gdb_flenfn,
Peter Maydell263eb622019-09-16 15:15:36 +0100636 },
Peter Maydellc46a6532019-09-16 15:15:42 +0100637 [GuestFDFeatureFile] = {
638 .closefn = featurefile_closefn,
639 .writefn = featurefile_writefn,
640 .readfn = featurefile_readfn,
641 .isattyfn = featurefile_isattyfn,
642 .seekfn = featurefile_seekfn,
643 .flenfn = featurefile_flenfn,
644 },
Peter Maydell263eb622019-09-16 15:15:36 +0100645};
646
Peter Maydellf296c0d2012-10-14 09:52:27 +0000647/* Read the input value from the argument block; fail the semihosting
648 * call if the memory read fails.
649 */
650#define GET_ARG(n) do { \
Peter Maydellfaacc042015-09-07 10:39:28 +0100651 if (is_a64(env)) { \
652 if (get_user_u64(arg ## n, args + (n) * 8)) { \
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100653 errno = EFAULT; \
Peter Maydell6ed68452019-09-16 15:15:34 +0100654 return set_swi_errno(env, -1); \
Peter Maydellfaacc042015-09-07 10:39:28 +0100655 } \
656 } else { \
657 if (get_user_u32(arg ## n, args + (n) * 4)) { \
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100658 errno = EFAULT; \
Peter Maydell6ed68452019-09-16 15:15:34 +0100659 return set_swi_errno(env, -1); \
Peter Maydellfaacc042015-09-07 10:39:28 +0100660 } \
Peter Maydellf296c0d2012-10-14 09:52:27 +0000661 } \
662} while (0)
663
Peter Maydellfaacc042015-09-07 10:39:28 +0100664#define SET_ARG(n, val) \
665 (is_a64(env) ? \
666 put_user_u64(val, args + (n) * 8) : \
667 put_user_u32(val, args + (n) * 4))
668
Alex Bennée4cb28db2019-05-14 12:08:39 +0100669/*
670 * Do a semihosting call.
671 *
672 * The specification always says that the "return register" either
673 * returns a specific value or is corrupted, so we don't need to
674 * report to our caller whether we are returning a value or trying to
675 * leave the register unchanged. We use 0xdeadbeef as the return value
676 * when there isn't a defined return value for the call.
677 */
Peter Maydellfaacc042015-09-07 10:39:28 +0100678target_ulong do_arm_semihosting(CPUARMState *env)
bellarda4f81972005-04-23 18:25:41 +0000679{
Richard Henderson2fc0cc02019-03-22 17:41:14 -0700680 ARMCPU *cpu = env_archcpu(env);
681 CPUState *cs = env_cpu(env);
pbrook53a59602006-03-25 19:31:22 +0000682 target_ulong args;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000683 target_ulong arg0, arg1, arg2, arg3;
bellarda4f81972005-04-23 18:25:41 +0000684 char * s;
685 int nr;
686 uint32_t ret;
pbrook8e716212007-01-20 17:12:09 +0000687 uint32_t len;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100688 GuestFD *gf;
bellarda4f81972005-04-23 18:25:41 +0000689
Peter Maydellfaacc042015-09-07 10:39:28 +0100690 if (is_a64(env)) {
691 /* Note that the syscall number is in W0, not X0 */
692 nr = env->xregs[0] & 0xffffffffU;
693 args = env->xregs[1];
694 } else {
695 nr = env->regs[0];
696 args = env->regs[1];
697 }
698
bellarda4f81972005-04-23 18:25:41 +0000699 switch (nr) {
Stefan Weil38817252012-04-28 05:07:47 +0000700 case TARGET_SYS_OPEN:
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100701 {
702 int guestfd;
703
Peter Maydellf296c0d2012-10-14 09:52:27 +0000704 GET_ARG(0);
705 GET_ARG(1);
706 GET_ARG(2);
707 s = lock_user_string(arg0);
708 if (!s) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100709 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +0100710 return set_swi_errno(env, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +0000711 }
712 if (arg1 >= 12) {
713 unlock_user(s, arg0, 0);
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100714 errno = EINVAL;
Peter Maydell6ed68452019-09-16 15:15:34 +0100715 return set_swi_errno(env, -1);
Jim Meyering396bef42012-08-22 13:55:55 +0200716 }
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100717
718 guestfd = alloc_guestfd();
719 if (guestfd < 0) {
720 unlock_user(s, arg0, 0);
721 errno = EMFILE;
Peter Maydell6ed68452019-09-16 15:15:34 +0100722 return set_swi_errno(env, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100723 }
724
bellarda4f81972005-04-23 18:25:41 +0000725 if (strcmp(s, ":tt") == 0) {
Peter Maydell6ee18642019-09-16 15:15:44 +0100726 int result_fileno;
727
728 /*
729 * We implement SH_EXT_STDOUT_STDERR, so:
730 * open for read == stdin
731 * open for write == stdout
732 * open for append == stderr
733 */
734 if (arg1 < 4) {
735 result_fileno = STDIN_FILENO;
736 } else if (arg1 < 8) {
737 result_fileno = STDOUT_FILENO;
738 } else {
739 result_fileno = STDERR_FILENO;
740 }
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100741 associate_guestfd(guestfd, result_fileno);
Peter Maydellf296c0d2012-10-14 09:52:27 +0000742 unlock_user(s, arg0, 0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100743 return guestfd;
bellarda4f81972005-04-23 18:25:41 +0000744 }
Peter Maydellc46a6532019-09-16 15:15:42 +0100745 if (strcmp(s, ":semihosting-features") == 0) {
746 unlock_user(s, arg0, 0);
747 /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
748 if (arg1 != 0 && arg1 != 1) {
749 dealloc_guestfd(guestfd);
750 errno = EACCES;
751 return set_swi_errno(env, -1);
752 }
753 init_featurefile_guestfd(guestfd);
754 return guestfd;
755 }
756
pbrooka2d1eba2007-01-28 03:10:55 +0000757 if (use_gdb_syscalls()) {
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100758 arm_semi_open_guestfd = guestfd;
759 ret = arm_gdb_syscall(cpu, arm_semi_open_cb, "open,%s,%x,1a4", arg0,
Xinhao Zhangbdc3b6f2020-11-03 19:45:27 +0800760 (int)arg2 + 1, gdb_open_modeflags[arg1]);
pbrooka2d1eba2007-01-28 03:10:55 +0000761 } else {
Peter Maydell6ed68452019-09-16 15:15:34 +0100762 ret = set_swi_errno(env, open(s, open_modeflags[arg1], 0644));
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100763 if (ret == (uint32_t)-1) {
764 dealloc_guestfd(guestfd);
765 } else {
766 associate_guestfd(guestfd, ret);
767 ret = guestfd;
768 }
pbrooka2d1eba2007-01-28 03:10:55 +0000769 }
Peter Maydellf296c0d2012-10-14 09:52:27 +0000770 unlock_user(s, arg0, 0);
pbrook8e716212007-01-20 17:12:09 +0000771 return ret;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100772 }
Stefan Weil38817252012-04-28 05:07:47 +0000773 case TARGET_SYS_CLOSE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000774 GET_ARG(0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100775
776 gf = get_guestfd(arg0);
777 if (!gf) {
778 errno = EBADF;
Peter Maydell6ed68452019-09-16 15:15:34 +0100779 return set_swi_errno(env, -1);
pbrooka2d1eba2007-01-28 03:10:55 +0000780 }
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100781
Peter Maydell263eb622019-09-16 15:15:36 +0100782 ret = guestfd_fns[gf->type].closefn(cpu, gf);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100783 dealloc_guestfd(arg0);
784 return ret;
Stefan Weil38817252012-04-28 05:07:47 +0000785 case TARGET_SYS_WRITEC:
Alex Bennée78e24842019-05-30 15:35:14 +0100786 qemu_semihosting_console_outc(env, args);
Alex Bennée0dc07722019-05-14 11:07:15 +0100787 return 0xdeadbeef;
Stefan Weil38817252012-04-28 05:07:47 +0000788 case TARGET_SYS_WRITE0:
Alex Bennée78e24842019-05-30 15:35:14 +0100789 return qemu_semihosting_console_outs(env, args);
Stefan Weil38817252012-04-28 05:07:47 +0000790 case TARGET_SYS_WRITE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000791 GET_ARG(0);
792 GET_ARG(1);
793 GET_ARG(2);
794 len = arg2;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100795
796 gf = get_guestfd(arg0);
797 if (!gf) {
798 errno = EBADF;
Peter Maydell6ed68452019-09-16 15:15:34 +0100799 return set_swi_errno(env, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100800 }
801
Peter Maydell52c8a162019-09-16 15:15:37 +0100802 return guestfd_fns[gf->type].writefn(cpu, gf, arg1, len);
Stefan Weil38817252012-04-28 05:07:47 +0000803 case TARGET_SYS_READ:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000804 GET_ARG(0);
805 GET_ARG(1);
806 GET_ARG(2);
807 len = arg2;
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100808
809 gf = get_guestfd(arg0);
810 if (!gf) {
811 errno = EBADF;
Peter Maydell6ed68452019-09-16 15:15:34 +0100812 return set_swi_errno(env, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100813 }
814
Peter Maydell2c3a09a2019-09-16 15:15:38 +0100815 return guestfd_fns[gf->type].readfn(cpu, gf, arg1, len);
Stefan Weil38817252012-04-28 05:07:47 +0000816 case TARGET_SYS_READC:
Keith Packard8de702c2019-11-04 12:42:30 -0800817 return qemu_semihosting_console_inc(env);
Stefan Weil38817252012-04-28 05:07:47 +0000818 case TARGET_SYS_ISTTY:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000819 GET_ARG(0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100820
821 gf = get_guestfd(arg0);
822 if (!gf) {
823 errno = EBADF;
Peter Maydell6ed68452019-09-16 15:15:34 +0100824 return set_swi_errno(env, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100825 }
826
Peter Maydell0213fa42019-09-16 15:15:39 +0100827 return guestfd_fns[gf->type].isattyfn(cpu, gf);
Stefan Weil38817252012-04-28 05:07:47 +0000828 case TARGET_SYS_SEEK:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000829 GET_ARG(0);
830 GET_ARG(1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100831
832 gf = get_guestfd(arg0);
833 if (!gf) {
834 errno = EBADF;
Peter Maydell6ed68452019-09-16 15:15:34 +0100835 return set_swi_errno(env, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100836 }
837
Peter Maydell45e88ff2019-09-16 15:15:40 +0100838 return guestfd_fns[gf->type].seekfn(cpu, gf, arg1);
Stefan Weil38817252012-04-28 05:07:47 +0000839 case TARGET_SYS_FLEN:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000840 GET_ARG(0);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100841
842 gf = get_guestfd(arg0);
843 if (!gf) {
844 errno = EBADF;
Peter Maydell6ed68452019-09-16 15:15:34 +0100845 return set_swi_errno(env, -1);
Peter Maydell35e9a0a2019-09-16 15:15:33 +0100846 }
847
Peter Maydell1631a7b2019-09-16 15:15:41 +0100848 return guestfd_fns[gf->type].flenfn(cpu, gf);
Stefan Weil38817252012-04-28 05:07:47 +0000849 case TARGET_SYS_TMPNAM:
Alex Bennéea1317952019-05-14 12:15:38 +0100850 qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
bellarda4f81972005-04-23 18:25:41 +0000851 return -1;
Stefan Weil38817252012-04-28 05:07:47 +0000852 case TARGET_SYS_REMOVE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000853 GET_ARG(0);
854 GET_ARG(1);
pbrooka2d1eba2007-01-28 03:10:55 +0000855 if (use_gdb_syscalls()) {
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100856 ret = arm_gdb_syscall(cpu, arm_semi_cb, "unlink,%s",
Xinhao Zhangbdc3b6f2020-11-03 19:45:27 +0800857 arg0, (int)arg1 + 1);
pbrooka2d1eba2007-01-28 03:10:55 +0000858 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000859 s = lock_user_string(arg0);
860 if (!s) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100861 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +0100862 return set_swi_errno(env, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +0000863 }
Peter Maydell6ed68452019-09-16 15:15:34 +0100864 ret = set_swi_errno(env, remove(s));
Peter Maydellf296c0d2012-10-14 09:52:27 +0000865 unlock_user(s, arg0, 0);
pbrooka2d1eba2007-01-28 03:10:55 +0000866 }
pbrook8e716212007-01-20 17:12:09 +0000867 return ret;
Stefan Weil38817252012-04-28 05:07:47 +0000868 case TARGET_SYS_RENAME:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000869 GET_ARG(0);
870 GET_ARG(1);
871 GET_ARG(2);
872 GET_ARG(3);
pbrooka2d1eba2007-01-28 03:10:55 +0000873 if (use_gdb_syscalls()) {
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100874 return arm_gdb_syscall(cpu, arm_semi_cb, "rename,%s,%s",
Xinhao Zhangbdc3b6f2020-11-03 19:45:27 +0800875 arg0, (int)arg1 + 1, arg2, (int)arg3 + 1);
pbrooka2d1eba2007-01-28 03:10:55 +0000876 } else {
pbrook8e716212007-01-20 17:12:09 +0000877 char *s2;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000878 s = lock_user_string(arg0);
879 s2 = lock_user_string(arg2);
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100880 if (!s || !s2) {
881 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +0100882 ret = set_swi_errno(env, -1);
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100883 } else {
Peter Maydell6ed68452019-09-16 15:15:34 +0100884 ret = set_swi_errno(env, rename(s, s2));
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100885 }
bellard579a97f2007-11-11 14:26:47 +0000886 if (s2)
Peter Maydellf296c0d2012-10-14 09:52:27 +0000887 unlock_user(s2, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +0000888 if (s)
Peter Maydellf296c0d2012-10-14 09:52:27 +0000889 unlock_user(s, arg0, 0);
pbrook8e716212007-01-20 17:12:09 +0000890 return ret;
891 }
Stefan Weil38817252012-04-28 05:07:47 +0000892 case TARGET_SYS_CLOCK:
bellarda4f81972005-04-23 18:25:41 +0000893 return clock() / (CLOCKS_PER_SEC / 100);
Stefan Weil38817252012-04-28 05:07:47 +0000894 case TARGET_SYS_TIME:
Peter Maydell6ed68452019-09-16 15:15:34 +0100895 return set_swi_errno(env, time(NULL));
Stefan Weil38817252012-04-28 05:07:47 +0000896 case TARGET_SYS_SYSTEM:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000897 GET_ARG(0);
898 GET_ARG(1);
pbrooka2d1eba2007-01-28 03:10:55 +0000899 if (use_gdb_syscalls()) {
Peter Maydellbb19cbc2015-09-07 10:39:27 +0100900 return arm_gdb_syscall(cpu, arm_semi_cb, "system,%s",
Xinhao Zhangbdc3b6f2020-11-03 19:45:27 +0800901 arg0, (int)arg1 + 1);
pbrooka2d1eba2007-01-28 03:10:55 +0000902 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000903 s = lock_user_string(arg0);
904 if (!s) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100905 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +0100906 return set_swi_errno(env, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +0000907 }
Peter Maydell6ed68452019-09-16 15:15:34 +0100908 ret = set_swi_errno(env, system(s));
Peter Maydellf296c0d2012-10-14 09:52:27 +0000909 unlock_user(s, arg0, 0);
thsa982b532008-07-01 16:40:04 +0000910 return ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000911 }
Stefan Weil38817252012-04-28 05:07:47 +0000912 case TARGET_SYS_ERRNO:
Peter Maydell6ed68452019-09-16 15:15:34 +0100913 return get_swi_errno(env);
Stefan Weil38817252012-04-28 05:07:47 +0000914 case TARGET_SYS_GET_CMDLINE:
pbrook38d06622006-11-19 20:29:35 +0000915 {
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200916 /* Build a command-line from the original argv.
917 *
918 * The inputs are:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000919 * * arg0, pointer to a buffer of at least the size
920 * specified in arg1.
921 * * arg1, size of the buffer pointed to by arg0 in
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200922 * bytes.
923 *
924 * The outputs are:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000925 * * arg0, pointer to null-terminated string of the
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200926 * command line.
Peter Maydellf296c0d2012-10-14 09:52:27 +0000927 * * arg1, length of the string pointed to by arg0.
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200928 */
bellard579a97f2007-11-11 14:26:47 +0000929
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200930 char *output_buffer;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000931 size_t input_size;
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200932 size_t output_size;
933 int status = 0;
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +0100934#if !defined(CONFIG_USER_ONLY)
935 const char *cmdline;
Peter Maydell6ed68452019-09-16 15:15:34 +0100936#else
937 TaskState *ts = cs->opaque;
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +0100938#endif
Peter Maydellf296c0d2012-10-14 09:52:27 +0000939 GET_ARG(0);
940 GET_ARG(1);
941 input_size = arg1;
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200942 /* Compute the size of the output string. */
943#if !defined(CONFIG_USER_ONLY)
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +0100944 cmdline = semihosting_get_cmdline();
945 if (cmdline == NULL) {
946 cmdline = ""; /* Default to an empty line. */
947 }
948 output_size = strlen(cmdline) + 1; /* Count terminating 0. */
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200949#else
Wolfgang Schildbach2e8785a2010-12-06 15:06:05 +0000950 unsigned int i;
pbrook38d06622006-11-19 20:29:35 +0000951
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200952 output_size = ts->info->arg_end - ts->info->arg_start;
953 if (!output_size) {
Alex Bennée4cb28db2019-05-14 12:08:39 +0100954 /*
955 * We special-case the "empty command line" case (argc==0).
956 * Just provide the terminating 0.
957 */
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200958 output_size = 1;
Wolfgang Schildbach2e8785a2010-12-06 15:06:05 +0000959 }
pbrook8e716212007-01-20 17:12:09 +0000960#endif
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200961
962 if (output_size > input_size) {
Alex Bennée4cb28db2019-05-14 12:08:39 +0100963 /* Not enough space to store command-line arguments. */
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100964 errno = E2BIG;
Peter Maydell6ed68452019-09-16 15:15:34 +0100965 return set_swi_errno(env, -1);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200966 }
967
968 /* Adjust the command-line length. */
Peter Maydellf296c0d2012-10-14 09:52:27 +0000969 if (SET_ARG(1, output_size - 1)) {
970 /* Couldn't write back to argument block */
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100971 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +0100972 return set_swi_errno(env, -1);
Peter Maydellf296c0d2012-10-14 09:52:27 +0000973 }
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200974
975 /* Lock the buffer on the ARM side. */
Peter Maydellf296c0d2012-10-14 09:52:27 +0000976 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200977 if (!output_buffer) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100978 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +0100979 return set_swi_errno(env, -1);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200980 }
981
982 /* Copy the command-line arguments. */
983#if !defined(CONFIG_USER_ONLY)
Liviu Ionescuf3c2bda2015-06-26 14:22:36 +0100984 pstrcpy(output_buffer, output_size, cmdline);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200985#else
986 if (output_size == 1) {
987 /* Empty command-line. */
988 output_buffer[0] = '\0';
989 goto out;
990 }
991
992 if (copy_from_user(output_buffer, ts->info->arg_start,
993 output_size)) {
Peter Maydellf7d38cf2019-09-16 15:15:31 +0100994 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +0100995 status = set_swi_errno(env, -1);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200996 goto out;
997 }
998
999 /* Separate arguments by white spaces. */
1000 for (i = 0; i < output_size - 1; i++) {
1001 if (output_buffer[i] == 0) {
1002 output_buffer[i] = ' ';
1003 }
1004 }
1005 out:
1006#endif
1007 /* Unlock the buffer on the ARM side. */
Peter Maydellf296c0d2012-10-14 09:52:27 +00001008 unlock_user(output_buffer, arg0, output_size);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +02001009
1010 return status;
1011 }
Stefan Weil38817252012-04-28 05:07:47 +00001012 case TARGET_SYS_HEAPINFO:
bellarda4f81972005-04-23 18:25:41 +00001013 {
Peter Maydellf5666412016-07-04 13:06:35 +01001014 target_ulong retvals[4];
Peter Maydell90e26f52016-07-07 13:47:00 +01001015 target_ulong limit;
Peter Maydellf5666412016-07-04 13:06:35 +01001016 int i;
Peter Maydell6ed68452019-09-16 15:15:34 +01001017#ifdef CONFIG_USER_ONLY
1018 TaskState *ts = cs->opaque;
Peter Maydell69515952020-11-19 09:23:46 +00001019#else
1020 const struct arm_boot_info *info = env->boot_info;
1021 target_ulong rambase = info->loader_start;
Peter Maydell6ed68452019-09-16 15:15:34 +01001022#endif
Peter Maydellf5666412016-07-04 13:06:35 +01001023
Peter Maydellf296c0d2012-10-14 09:52:27 +00001024 GET_ARG(0);
bellarda4f81972005-04-23 18:25:41 +00001025
pbrook8e716212007-01-20 17:12:09 +00001026#ifdef CONFIG_USER_ONLY
Alex Bennée4cb28db2019-05-14 12:08:39 +01001027 /*
1028 * Some C libraries assume the heap immediately follows .bss, so
1029 * allocate it using sbrk.
1030 */
bellarda4f81972005-04-23 18:25:41 +00001031 if (!ts->heap_limit) {
Peter Maydell206ae742011-04-18 16:34:25 +01001032 abi_ulong ret;
bellarda4f81972005-04-23 18:25:41 +00001033
pbrook53a59602006-03-25 19:31:22 +00001034 ts->heap_base = do_brk(0);
bellarda4f81972005-04-23 18:25:41 +00001035 limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
1036 /* Try a big heap, and reduce the size if that fails. */
1037 for (;;) {
pbrook53a59602006-03-25 19:31:22 +00001038 ret = do_brk(limit);
Peter Maydell206ae742011-04-18 16:34:25 +01001039 if (ret >= limit) {
bellarda4f81972005-04-23 18:25:41 +00001040 break;
Peter Maydell206ae742011-04-18 16:34:25 +01001041 }
bellarda4f81972005-04-23 18:25:41 +00001042 limit = (ts->heap_base >> 1) + (limit >> 1);
1043 }
1044 ts->heap_limit = limit;
1045 }
ths3b46e622007-09-17 08:09:54 +00001046
Peter Maydellf5666412016-07-04 13:06:35 +01001047 retvals[0] = ts->heap_base;
1048 retvals[1] = ts->heap_limit;
1049 retvals[2] = ts->stack_base;
1050 retvals[3] = 0; /* Stack limit. */
pbrook8e716212007-01-20 17:12:09 +00001051#else
Paolo Bonzini6e504a92020-10-28 06:18:20 -04001052 limit = current_machine->ram_size;
pbrook8e716212007-01-20 17:12:09 +00001053 /* TODO: Make this use the limit of the loaded application. */
Peter Maydell69515952020-11-19 09:23:46 +00001054 retvals[0] = rambase + limit / 2;
1055 retvals[1] = rambase + limit;
1056 retvals[2] = rambase + limit; /* Stack base */
1057 retvals[3] = rambase; /* Stack limit. */
pbrook8e716212007-01-20 17:12:09 +00001058#endif
Peter Maydellf5666412016-07-04 13:06:35 +01001059
1060 for (i = 0; i < ARRAY_SIZE(retvals); i++) {
1061 bool fail;
1062
1063 if (is_a64(env)) {
1064 fail = put_user_u64(retvals[i], arg0 + i * 8);
1065 } else {
1066 fail = put_user_u32(retvals[i], arg0 + i * 4);
1067 }
1068
1069 if (fail) {
1070 /* Couldn't write back to argument block */
Peter Maydellf7d38cf2019-09-16 15:15:31 +01001071 errno = EFAULT;
Peter Maydell6ed68452019-09-16 15:15:34 +01001072 return set_swi_errno(env, -1);
Peter Maydellf5666412016-07-04 13:06:35 +01001073 }
1074 }
bellarda4f81972005-04-23 18:25:41 +00001075 return 0;
1076 }
Stefan Weil38817252012-04-28 05:07:47 +00001077 case TARGET_SYS_EXIT:
Peter Maydell22a43bb2019-09-16 15:15:43 +01001078 case TARGET_SYS_EXIT_EXTENDED:
1079 if (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(env)) {
Alex Bennée4cb28db2019-05-14 12:08:39 +01001080 /*
Peter Maydell22a43bb2019-09-16 15:15:43 +01001081 * The A64 version of SYS_EXIT takes a parameter block,
Peter Maydell7446d352015-09-07 10:39:28 +01001082 * so the application-exit type can return a subcode which
1083 * is the exit status code from the application.
Peter Maydell22a43bb2019-09-16 15:15:43 +01001084 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1085 * which allows A32/T32 guests to also provide a status code.
Peter Maydell7446d352015-09-07 10:39:28 +01001086 */
1087 GET_ARG(0);
1088 GET_ARG(1);
1089
1090 if (arg0 == ADP_Stopped_ApplicationExit) {
1091 ret = arg1;
1092 } else {
1093 ret = 1;
1094 }
1095 } else {
Alex Bennée4cb28db2019-05-14 12:08:39 +01001096 /*
Peter Maydell22a43bb2019-09-16 15:15:43 +01001097 * The A32/T32 version of SYS_EXIT specifies only
1098 * Stopped_ApplicationExit as normal exit, but does not
1099 * allow the guest to specify the exit status code.
1100 * Everything else is considered an error.
Alex Bennée4cb28db2019-05-14 12:08:39 +01001101 */
Peter Maydell7446d352015-09-07 10:39:28 +01001102 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
1103 }
Liviu Ionescu1ecc3a22014-12-11 12:07:48 +00001104 gdb_exit(env, ret);
1105 exit(ret);
Peter Maydelle9ebfbf2015-09-07 10:39:28 +01001106 case TARGET_SYS_SYNCCACHE:
Alex Bennée4cb28db2019-05-14 12:08:39 +01001107 /*
1108 * Clean the D-cache and invalidate the I-cache for the specified
Peter Maydelle9ebfbf2015-09-07 10:39:28 +01001109 * virtual address range. This is a nop for us since we don't
1110 * implement caches. This is only present on A64.
1111 */
1112 if (is_a64(env)) {
1113 return 0;
1114 }
1115 /* fall through -- invalid for A32/T32 */
bellarda4f81972005-04-23 18:25:41 +00001116 default:
1117 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
Markus Armbruster90c84c52019-04-17 21:18:02 +02001118 cpu_dump_state(cs, stderr, 0);
bellarda4f81972005-04-23 18:25:41 +00001119 abort();
1120 }
1121}