scripts: kernel-doc: allow passing desired Sphinx C domain dialect
[qemu/ar7.git] / target / arm / arm-semi.c
blobf7b7bff522852e94d001cd3fc725b1689b7bebed
1 /*
2 * Arm "Angel" semihosting syscalls
4 * Copyright (c) 2005, 2007 CodeSourcery.
5 * Copyright (c) 2019 Linaro
6 * Written by Paul Brook.
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.
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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
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
26 #include "qemu/osdep.h"
28 #include "cpu.h"
29 #include "hw/semihosting/semihost.h"
30 #include "hw/semihosting/console.h"
31 #include "qemu/log.h"
32 #ifdef CONFIG_USER_ONLY
33 #include "qemu.h"
35 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
36 #else
37 #include "exec/gdbstub.h"
38 #include "qemu/cutils.h"
39 #include "hw/arm/boot.h"
40 #include "hw/boards.h"
41 #endif
43 #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
63 #define TARGET_SYS_SYNCCACHE 0x19
64 #define TARGET_SYS_EXIT_EXTENDED 0x20
66 /* ADP_Stopped_ApplicationExit is used for exit(0),
67 * anything else is implemented as exit(1) */
68 #define ADP_Stopped_ApplicationExit (0x20026)
70 #ifndef O_BINARY
71 #define O_BINARY 0
72 #endif
74 #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
82 static 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
97 static int open_modeflags[12] = {
98 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
112 typedef enum GuestFDType {
113 GuestFDUnused = 0,
114 GuestFDHost = 1,
115 GuestFDGDB = 2,
116 GuestFDFeatureFile = 3,
117 } GuestFDType;
120 * Guest file descriptors are integer indexes into an array of
121 * these structures (we will dynamically resize as necessary).
123 typedef struct GuestFD {
124 GuestFDType type;
125 union {
126 int hostfd;
127 target_ulong featurefile_offset;
129 } GuestFD;
131 static GArray *guestfd_array;
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.
140 static int alloc_guestfd(void)
142 guint i;
144 if (!guestfd_array) {
145 /* New entries zero-initialized, i.e. type GuestFDUnused */
146 guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
149 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
150 for (i = 1; i < guestfd_array->len; i++) {
151 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
153 if (gf->type == GuestFDUnused) {
154 return i;
158 /* All elements already in use: expand the array */
159 g_array_set_size(guestfd_array, i + 1);
160 return i;
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.
168 static GuestFD *do_get_guestfd(int guestfd)
170 if (!guestfd_array) {
171 return NULL;
174 if (guestfd <= 0 || guestfd >= guestfd_array->len) {
175 return NULL;
178 return &g_array_index(guestfd_array, GuestFD, guestfd);
182 * Associate the specified guest fd (which must have been
183 * allocated via alloc_fd() and not previously used) with
184 * the specified host/gdb fd.
186 static void associate_guestfd(int guestfd, int hostfd)
188 GuestFD *gf = do_get_guestfd(guestfd);
190 assert(gf);
191 gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
192 gf->hostfd = hostfd;
196 * Deallocate the specified guest file descriptor. This doesn't
197 * close the host fd, it merely undoes the work of alloc_fd().
199 static void dealloc_guestfd(int guestfd)
201 GuestFD *gf = do_get_guestfd(guestfd);
203 assert(gf);
204 gf->type = GuestFDUnused;
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.
215 static GuestFD *get_guestfd(int guestfd)
217 GuestFD *gf = do_get_guestfd(guestfd);
219 if (!gf || gf->type == GuestFDUnused) {
220 return NULL;
222 return gf;
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.
232 #ifndef CONFIG_USER_ONLY
233 static target_ulong syscall_err;
235 #include "exec/softmmu-semi.h"
236 #endif
238 static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
240 if (code == (uint32_t)-1) {
241 #ifdef CONFIG_USER_ONLY
242 CPUState *cs = env_cpu(env);
243 TaskState *ts = cs->opaque;
245 ts->swi_errno = errno;
246 #else
247 syscall_err = errno;
248 #endif
250 return code;
253 static inline uint32_t get_swi_errno(CPUARMState *env)
255 #ifdef CONFIG_USER_ONLY
256 CPUState *cs = env_cpu(env);
257 TaskState *ts = cs->opaque;
259 return ts->swi_errno;
260 #else
261 return syscall_err;
262 #endif
265 static target_ulong arm_semi_syscall_len;
267 static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
269 ARMCPU *cpu = ARM_CPU(cs);
270 CPUARMState *env = &cpu->env;
271 target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
273 if (ret == (target_ulong)-1) {
274 errno = err;
275 set_swi_errno(env, -1);
276 reg0 = ret;
277 } else {
278 /* Fixup syscalls that use nonstardard return conventions. */
279 switch (reg0) {
280 case TARGET_SYS_WRITE:
281 case TARGET_SYS_READ:
282 reg0 = arm_semi_syscall_len - ret;
283 break;
284 case TARGET_SYS_SEEK:
285 reg0 = 0;
286 break;
287 default:
288 reg0 = ret;
289 break;
292 if (is_a64(env)) {
293 env->xregs[0] = reg0;
294 } else {
295 env->regs[0] = reg0;
299 static target_ulong arm_flen_buf(ARMCPU *cpu)
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.
306 CPUARMState *env = &cpu->env;
307 target_ulong sp;
309 if (is_a64(env)) {
310 sp = env->xregs[31];
311 } else {
312 sp = env->regs[13];
315 return sp - 64;
318 static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
320 ARMCPU *cpu = ARM_CPU(cs);
321 CPUARMState *env = &cpu->env;
322 /* 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;
325 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;
332 errno = err;
333 set_swi_errno(env, -1);
336 static int arm_semi_open_guestfd;
338 static void arm_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
340 ARMCPU *cpu = ARM_CPU(cs);
341 CPUARMState *env = &cpu->env;
342 if (ret == (target_ulong)-1) {
343 errno = err;
344 set_swi_errno(env, -1);
345 dealloc_guestfd(arm_semi_open_guestfd);
346 } else {
347 associate_guestfd(arm_semi_open_guestfd, ret);
348 ret = arm_semi_open_guestfd;
351 if (is_a64(env)) {
352 env->xregs[0] = ret;
353 } else {
354 env->regs[0] = ret;
358 static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
359 const char *fmt, ...)
361 va_list va;
362 CPUARMState *env = &cpu->env;
364 va_start(va, fmt);
365 gdb_do_syscallv(cb, fmt, va);
366 va_end(va);
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.)
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.
385 return is_a64(env) ? env->xregs[0] : env->regs[0];
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.
394 typedef uint32_t sys_closefn(ARMCPU *cpu, GuestFD *gf);
395 typedef uint32_t sys_writefn(ARMCPU *cpu, GuestFD *gf,
396 target_ulong buf, uint32_t len);
397 typedef uint32_t sys_readfn(ARMCPU *cpu, GuestFD *gf,
398 target_ulong buf, uint32_t len);
399 typedef uint32_t sys_isattyfn(ARMCPU *cpu, GuestFD *gf);
400 typedef uint32_t sys_seekfn(ARMCPU *cpu, GuestFD *gf,
401 target_ulong offset);
402 typedef uint32_t sys_flenfn(ARMCPU *cpu, GuestFD *gf);
404 static uint32_t host_closefn(ARMCPU *cpu, GuestFD *gf)
406 CPUARMState *env = &cpu->env;
409 * Only close the underlying host fd if it's one we opened on behalf
410 * of the guest in SYS_OPEN.
412 if (gf->hostfd == STDIN_FILENO ||
413 gf->hostfd == STDOUT_FILENO ||
414 gf->hostfd == STDERR_FILENO) {
415 return 0;
417 return set_swi_errno(env, close(gf->hostfd));
420 static uint32_t host_writefn(ARMCPU *cpu, GuestFD *gf,
421 target_ulong buf, uint32_t len)
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;
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;
435 /* Return bytes not written */
436 return len - ret;
439 static uint32_t host_readfn(ARMCPU *cpu, GuestFD *gf,
440 target_ulong buf, uint32_t len)
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;
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;
456 /* Return bytes not read */
457 return len - ret;
460 static uint32_t host_isattyfn(ARMCPU *cpu, GuestFD *gf)
462 return isatty(gf->hostfd);
465 static uint32_t host_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
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;
472 return 0;
475 static uint32_t host_flenfn(ARMCPU *cpu, GuestFD *gf)
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;
483 return buf.st_size;
486 static uint32_t gdb_closefn(ARMCPU *cpu, GuestFD *gf)
488 return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", gf->hostfd);
491 static uint32_t gdb_writefn(ARMCPU *cpu, GuestFD *gf,
492 target_ulong buf, uint32_t len)
494 arm_semi_syscall_len = len;
495 return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
496 gf->hostfd, buf, len);
499 static uint32_t gdb_readfn(ARMCPU *cpu, GuestFD *gf,
500 target_ulong buf, uint32_t len)
502 arm_semi_syscall_len = len;
503 return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
504 gf->hostfd, buf, len);
507 static uint32_t gdb_isattyfn(ARMCPU *cpu, GuestFD *gf)
509 return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", gf->hostfd);
512 static uint32_t gdb_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
514 return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
515 gf->hostfd, offset);
518 static uint32_t gdb_flenfn(ARMCPU *cpu, GuestFD *gf)
520 return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
521 gf->hostfd, arm_flen_buf(cpu));
524 #define SHFB_MAGIC_0 0x53
525 #define SHFB_MAGIC_1 0x48
526 #define SHFB_MAGIC_2 0x46
527 #define SHFB_MAGIC_3 0x42
529 /* Feature bits reportable in feature byte 0 */
530 #define SH_EXT_EXIT_EXTENDED (1 << 0)
531 #define SH_EXT_STDOUT_STDERR (1 << 1)
533 static const uint8_t featurefile_data[] = {
534 SHFB_MAGIC_0,
535 SHFB_MAGIC_1,
536 SHFB_MAGIC_2,
537 SHFB_MAGIC_3,
538 SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
541 static void init_featurefile_guestfd(int guestfd)
543 GuestFD *gf = do_get_guestfd(guestfd);
545 assert(gf);
546 gf->type = GuestFDFeatureFile;
547 gf->featurefile_offset = 0;
550 static uint32_t featurefile_closefn(ARMCPU *cpu, GuestFD *gf)
552 /* Nothing to do */
553 return 0;
556 static uint32_t featurefile_writefn(ARMCPU *cpu, GuestFD *gf,
557 target_ulong buf, uint32_t len)
559 /* This fd can never be open for writing */
560 CPUARMState *env = &cpu->env;
562 errno = EBADF;
563 return set_swi_errno(env, -1);
566 static uint32_t featurefile_readfn(ARMCPU *cpu, GuestFD *gf,
567 target_ulong buf, uint32_t len)
569 uint32_t i;
570 #ifndef CONFIG_USER_ONLY
571 CPUARMState *env = &cpu->env;
572 #endif
573 char *s;
575 s = lock_user(VERIFY_WRITE, buf, len, 0);
576 if (!s) {
577 return len;
580 for (i = 0; i < len; i++) {
581 if (gf->featurefile_offset >= sizeof(featurefile_data)) {
582 break;
584 s[i] = featurefile_data[gf->featurefile_offset];
585 gf->featurefile_offset++;
588 unlock_user(s, buf, len);
590 /* Return number of bytes not read */
591 return len - i;
594 static uint32_t featurefile_isattyfn(ARMCPU *cpu, GuestFD *gf)
596 return 0;
599 static uint32_t featurefile_seekfn(ARMCPU *cpu, GuestFD *gf,
600 target_ulong offset)
602 gf->featurefile_offset = offset;
603 return 0;
606 static uint32_t featurefile_flenfn(ARMCPU *cpu, GuestFD *gf)
608 return sizeof(featurefile_data);
611 typedef struct GuestFDFunctions {
612 sys_closefn *closefn;
613 sys_writefn *writefn;
614 sys_readfn *readfn;
615 sys_isattyfn *isattyfn;
616 sys_seekfn *seekfn;
617 sys_flenfn *flenfn;
618 } GuestFDFunctions;
620 static const GuestFDFunctions guestfd_fns[] = {
621 [GuestFDHost] = {
622 .closefn = host_closefn,
623 .writefn = host_writefn,
624 .readfn = host_readfn,
625 .isattyfn = host_isattyfn,
626 .seekfn = host_seekfn,
627 .flenfn = host_flenfn,
629 [GuestFDGDB] = {
630 .closefn = gdb_closefn,
631 .writefn = gdb_writefn,
632 .readfn = gdb_readfn,
633 .isattyfn = gdb_isattyfn,
634 .seekfn = gdb_seekfn,
635 .flenfn = gdb_flenfn,
637 [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,
647 /* Read the input value from the argument block; fail the semihosting
648 * call if the memory read fails.
650 #define GET_ARG(n) do { \
651 if (is_a64(env)) { \
652 if (get_user_u64(arg ## n, args + (n) * 8)) { \
653 errno = EFAULT; \
654 return set_swi_errno(env, -1); \
656 } else { \
657 if (get_user_u32(arg ## n, args + (n) * 4)) { \
658 errno = EFAULT; \
659 return set_swi_errno(env, -1); \
662 } while (0)
664 #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))
670 * Do a semihosting call.
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.
678 target_ulong do_arm_semihosting(CPUARMState *env)
680 ARMCPU *cpu = env_archcpu(env);
681 CPUState *cs = env_cpu(env);
682 target_ulong args;
683 target_ulong arg0, arg1, arg2, arg3;
684 char * s;
685 int nr;
686 uint32_t ret;
687 uint32_t len;
688 GuestFD *gf;
690 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];
699 switch (nr) {
700 case TARGET_SYS_OPEN:
702 int guestfd;
704 GET_ARG(0);
705 GET_ARG(1);
706 GET_ARG(2);
707 s = lock_user_string(arg0);
708 if (!s) {
709 errno = EFAULT;
710 return set_swi_errno(env, -1);
712 if (arg1 >= 12) {
713 unlock_user(s, arg0, 0);
714 errno = EINVAL;
715 return set_swi_errno(env, -1);
718 guestfd = alloc_guestfd();
719 if (guestfd < 0) {
720 unlock_user(s, arg0, 0);
721 errno = EMFILE;
722 return set_swi_errno(env, -1);
725 if (strcmp(s, ":tt") == 0) {
726 int result_fileno;
729 * We implement SH_EXT_STDOUT_STDERR, so:
730 * open for read == stdin
731 * open for write == stdout
732 * open for append == stderr
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;
741 associate_guestfd(guestfd, result_fileno);
742 unlock_user(s, arg0, 0);
743 return guestfd;
745 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);
753 init_featurefile_guestfd(guestfd);
754 return guestfd;
757 if (use_gdb_syscalls()) {
758 arm_semi_open_guestfd = guestfd;
759 ret = arm_gdb_syscall(cpu, arm_semi_open_cb, "open,%s,%x,1a4", arg0,
760 (int)arg2 + 1, gdb_open_modeflags[arg1]);
761 } else {
762 ret = set_swi_errno(env, open(s, open_modeflags[arg1], 0644));
763 if (ret == (uint32_t)-1) {
764 dealloc_guestfd(guestfd);
765 } else {
766 associate_guestfd(guestfd, ret);
767 ret = guestfd;
770 unlock_user(s, arg0, 0);
771 return ret;
773 case TARGET_SYS_CLOSE:
774 GET_ARG(0);
776 gf = get_guestfd(arg0);
777 if (!gf) {
778 errno = EBADF;
779 return set_swi_errno(env, -1);
782 ret = guestfd_fns[gf->type].closefn(cpu, gf);
783 dealloc_guestfd(arg0);
784 return ret;
785 case TARGET_SYS_WRITEC:
786 qemu_semihosting_console_outc(env, args);
787 return 0xdeadbeef;
788 case TARGET_SYS_WRITE0:
789 return qemu_semihosting_console_outs(env, args);
790 case TARGET_SYS_WRITE:
791 GET_ARG(0);
792 GET_ARG(1);
793 GET_ARG(2);
794 len = arg2;
796 gf = get_guestfd(arg0);
797 if (!gf) {
798 errno = EBADF;
799 return set_swi_errno(env, -1);
802 return guestfd_fns[gf->type].writefn(cpu, gf, arg1, len);
803 case TARGET_SYS_READ:
804 GET_ARG(0);
805 GET_ARG(1);
806 GET_ARG(2);
807 len = arg2;
809 gf = get_guestfd(arg0);
810 if (!gf) {
811 errno = EBADF;
812 return set_swi_errno(env, -1);
815 return guestfd_fns[gf->type].readfn(cpu, gf, arg1, len);
816 case TARGET_SYS_READC:
817 return qemu_semihosting_console_inc(env);
818 case TARGET_SYS_ISTTY:
819 GET_ARG(0);
821 gf = get_guestfd(arg0);
822 if (!gf) {
823 errno = EBADF;
824 return set_swi_errno(env, -1);
827 return guestfd_fns[gf->type].isattyfn(cpu, gf);
828 case TARGET_SYS_SEEK:
829 GET_ARG(0);
830 GET_ARG(1);
832 gf = get_guestfd(arg0);
833 if (!gf) {
834 errno = EBADF;
835 return set_swi_errno(env, -1);
838 return guestfd_fns[gf->type].seekfn(cpu, gf, arg1);
839 case TARGET_SYS_FLEN:
840 GET_ARG(0);
842 gf = get_guestfd(arg0);
843 if (!gf) {
844 errno = EBADF;
845 return set_swi_errno(env, -1);
848 return guestfd_fns[gf->type].flenfn(cpu, gf);
849 case TARGET_SYS_TMPNAM:
850 qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
851 return -1;
852 case TARGET_SYS_REMOVE:
853 GET_ARG(0);
854 GET_ARG(1);
855 if (use_gdb_syscalls()) {
856 ret = arm_gdb_syscall(cpu, arm_semi_cb, "unlink,%s",
857 arg0, (int)arg1 + 1);
858 } else {
859 s = lock_user_string(arg0);
860 if (!s) {
861 errno = EFAULT;
862 return set_swi_errno(env, -1);
864 ret = set_swi_errno(env, remove(s));
865 unlock_user(s, arg0, 0);
867 return ret;
868 case TARGET_SYS_RENAME:
869 GET_ARG(0);
870 GET_ARG(1);
871 GET_ARG(2);
872 GET_ARG(3);
873 if (use_gdb_syscalls()) {
874 return arm_gdb_syscall(cpu, arm_semi_cb, "rename,%s,%s",
875 arg0, (int)arg1 + 1, arg2, (int)arg3 + 1);
876 } else {
877 char *s2;
878 s = lock_user_string(arg0);
879 s2 = lock_user_string(arg2);
880 if (!s || !s2) {
881 errno = EFAULT;
882 ret = set_swi_errno(env, -1);
883 } else {
884 ret = set_swi_errno(env, rename(s, s2));
886 if (s2)
887 unlock_user(s2, arg2, 0);
888 if (s)
889 unlock_user(s, arg0, 0);
890 return ret;
892 case TARGET_SYS_CLOCK:
893 return clock() / (CLOCKS_PER_SEC / 100);
894 case TARGET_SYS_TIME:
895 return set_swi_errno(env, time(NULL));
896 case TARGET_SYS_SYSTEM:
897 GET_ARG(0);
898 GET_ARG(1);
899 if (use_gdb_syscalls()) {
900 return arm_gdb_syscall(cpu, arm_semi_cb, "system,%s",
901 arg0, (int)arg1 + 1);
902 } else {
903 s = lock_user_string(arg0);
904 if (!s) {
905 errno = EFAULT;
906 return set_swi_errno(env, -1);
908 ret = set_swi_errno(env, system(s));
909 unlock_user(s, arg0, 0);
910 return ret;
912 case TARGET_SYS_ERRNO:
913 return get_swi_errno(env);
914 case TARGET_SYS_GET_CMDLINE:
916 /* Build a command-line from the original argv.
918 * The inputs are:
919 * * 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
922 * bytes.
924 * The outputs are:
925 * * arg0, pointer to null-terminated string of the
926 * command line.
927 * * arg1, length of the string pointed to by arg0.
930 char *output_buffer;
931 size_t input_size;
932 size_t output_size;
933 int status = 0;
934 #if !defined(CONFIG_USER_ONLY)
935 const char *cmdline;
936 #else
937 TaskState *ts = cs->opaque;
938 #endif
939 GET_ARG(0);
940 GET_ARG(1);
941 input_size = arg1;
942 /* Compute the size of the output string. */
943 #if !defined(CONFIG_USER_ONLY)
944 cmdline = semihosting_get_cmdline();
945 if (cmdline == NULL) {
946 cmdline = ""; /* Default to an empty line. */
948 output_size = strlen(cmdline) + 1; /* Count terminating 0. */
949 #else
950 unsigned int i;
952 output_size = ts->info->arg_end - ts->info->arg_start;
953 if (!output_size) {
955 * We special-case the "empty command line" case (argc==0).
956 * Just provide the terminating 0.
958 output_size = 1;
960 #endif
962 if (output_size > input_size) {
963 /* Not enough space to store command-line arguments. */
964 errno = E2BIG;
965 return set_swi_errno(env, -1);
968 /* Adjust the command-line length. */
969 if (SET_ARG(1, output_size - 1)) {
970 /* Couldn't write back to argument block */
971 errno = EFAULT;
972 return set_swi_errno(env, -1);
975 /* Lock the buffer on the ARM side. */
976 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
977 if (!output_buffer) {
978 errno = EFAULT;
979 return set_swi_errno(env, -1);
982 /* Copy the command-line arguments. */
983 #if !defined(CONFIG_USER_ONLY)
984 pstrcpy(output_buffer, output_size, cmdline);
985 #else
986 if (output_size == 1) {
987 /* Empty command-line. */
988 output_buffer[0] = '\0';
989 goto out;
992 if (copy_from_user(output_buffer, ts->info->arg_start,
993 output_size)) {
994 errno = EFAULT;
995 status = set_swi_errno(env, -1);
996 goto out;
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] = ' ';
1005 out:
1006 #endif
1007 /* Unlock the buffer on the ARM side. */
1008 unlock_user(output_buffer, arg0, output_size);
1010 return status;
1012 case TARGET_SYS_HEAPINFO:
1014 target_ulong retvals[4];
1015 target_ulong limit;
1016 int i;
1017 #ifdef CONFIG_USER_ONLY
1018 TaskState *ts = cs->opaque;
1019 #else
1020 const struct arm_boot_info *info = env->boot_info;
1021 target_ulong rambase = info->loader_start;
1022 #endif
1024 GET_ARG(0);
1026 #ifdef CONFIG_USER_ONLY
1028 * Some C libraries assume the heap immediately follows .bss, so
1029 * allocate it using sbrk.
1031 if (!ts->heap_limit) {
1032 abi_ulong ret;
1034 ts->heap_base = do_brk(0);
1035 limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
1036 /* Try a big heap, and reduce the size if that fails. */
1037 for (;;) {
1038 ret = do_brk(limit);
1039 if (ret >= limit) {
1040 break;
1042 limit = (ts->heap_base >> 1) + (limit >> 1);
1044 ts->heap_limit = limit;
1047 retvals[0] = ts->heap_base;
1048 retvals[1] = ts->heap_limit;
1049 retvals[2] = ts->stack_base;
1050 retvals[3] = 0; /* Stack limit. */
1051 #else
1052 limit = current_machine->ram_size;
1053 /* TODO: Make this use the limit of the loaded application. */
1054 retvals[0] = rambase + limit / 2;
1055 retvals[1] = rambase + limit;
1056 retvals[2] = rambase + limit; /* Stack base */
1057 retvals[3] = rambase; /* Stack limit. */
1058 #endif
1060 for (i = 0; i < ARRAY_SIZE(retvals); i++) {
1061 bool fail;
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);
1069 if (fail) {
1070 /* Couldn't write back to argument block */
1071 errno = EFAULT;
1072 return set_swi_errno(env, -1);
1075 return 0;
1077 case TARGET_SYS_EXIT:
1078 case TARGET_SYS_EXIT_EXTENDED:
1079 if (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(env)) {
1081 * The A64 version of SYS_EXIT takes a parameter block,
1082 * so the application-exit type can return a subcode which
1083 * is the exit status code from the application.
1084 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1085 * which allows A32/T32 guests to also provide a status code.
1087 GET_ARG(0);
1088 GET_ARG(1);
1090 if (arg0 == ADP_Stopped_ApplicationExit) {
1091 ret = arg1;
1092 } else {
1093 ret = 1;
1095 } else {
1097 * 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.
1102 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
1104 gdb_exit(env, ret);
1105 exit(ret);
1106 case TARGET_SYS_SYNCCACHE:
1108 * Clean the D-cache and invalidate the I-cache for the specified
1109 * virtual address range. This is a nop for us since we don't
1110 * implement caches. This is only present on A64.
1112 if (is_a64(env)) {
1113 return 0;
1115 /* fall through -- invalid for A32/T32 */
1116 default:
1117 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
1118 cpu_dump_state(cs, stderr, 0);
1119 abort();