Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2021-06-15-v2' into staging
[qemu/ar7.git] / semihosting / arm-compat-semi.c
blob1c29146dcfa6dfc44c9e4fcf3a43b8d2674f8495
1 /*
2 * Semihosting support for systems modeled on the Arm "Angel"
3 * semihosting syscalls design. This includes Arm and RISC-V processors
5 * Copyright (c) 2005, 2007 CodeSourcery.
6 * Copyright (c) 2019 Linaro
7 * Written by Paul Brook.
9 * Copyright © 2020 by Keith Packard <keithp@keithp.com>
10 * Adapted for systems other than ARM, including RISC-V, by Keith Packard
12 * 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.
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.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <http://www.gnu.org/licenses/>.
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
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
34 #include "qemu/osdep.h"
36 #include "semihosting/semihost.h"
37 #include "semihosting/console.h"
38 #include "semihosting/common-semi.h"
39 #include "qemu/timer.h"
40 #ifdef CONFIG_USER_ONLY
41 #include "qemu.h"
43 #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
44 #else
45 #include "exec/gdbstub.h"
46 #include "qemu/cutils.h"
47 #ifdef TARGET_ARM
48 #include "hw/arm/boot.h"
49 #endif
50 #include "hw/boards.h"
51 #endif
53 #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
60 #define TARGET_SYS_ISERROR 0x08
61 #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
74 #define TARGET_SYS_SYNCCACHE 0x19
75 #define TARGET_SYS_EXIT_EXTENDED 0x20
76 #define TARGET_SYS_ELAPSED 0x30
77 #define TARGET_SYS_TICKFREQ 0x31
79 /* ADP_Stopped_ApplicationExit is used for exit(0),
80 * anything else is implemented as exit(1) */
81 #define ADP_Stopped_ApplicationExit (0x20026)
83 #ifndef O_BINARY
84 #define O_BINARY 0
85 #endif
87 #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
95 static 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
110 static int open_modeflags[12] = {
111 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
125 typedef enum GuestFDType {
126 GuestFDUnused = 0,
127 GuestFDHost = 1,
128 GuestFDGDB = 2,
129 GuestFDFeatureFile = 3,
130 } GuestFDType;
133 * Guest file descriptors are integer indexes into an array of
134 * these structures (we will dynamically resize as necessary).
136 typedef struct GuestFD {
137 GuestFDType type;
138 union {
139 int hostfd;
140 target_ulong featurefile_offset;
142 } GuestFD;
144 static GArray *guestfd_array;
146 #ifndef CONFIG_USER_ONLY
147 #include "exec/address-spaces.h"
149 * Find the base of a RAM region containing the specified address
151 static inline hwaddr
152 common_semi_find_region_base(hwaddr addr)
154 MemoryRegion *subregion;
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.
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;
172 return 0;
174 #endif
176 #ifdef TARGET_ARM
177 static inline target_ulong
178 common_semi_arg(CPUState *cs, int argno)
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];
189 static inline void
190 common_semi_set_ret(CPUState *cs, target_ulong ret)
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;
201 static inline bool
202 common_semi_sys_exit_extended(CPUState *cs, int nr)
204 return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
207 #ifndef CONFIG_USER_ONLY
208 #include "hw/arm/boot.h"
209 static inline target_ulong
210 common_semi_rambase(CPUState *cs)
212 CPUArchState *env = cs->env_ptr;
213 const struct arm_boot_info *info = env->boot_info;
214 target_ulong sp;
216 if (info) {
217 return info->loader_start;
220 if (is_a64(env)) {
221 sp = env->xregs[31];
222 } else {
223 sp = env->regs[13];
225 return common_semi_find_region_base(sp);
227 #endif
229 #endif /* TARGET_ARM */
231 #ifdef TARGET_RISCV
232 static inline target_ulong
233 common_semi_arg(CPUState *cs, int argno)
235 RISCVCPU *cpu = RISCV_CPU(cs);
236 CPURISCVState *env = &cpu->env;
237 return env->gpr[xA0 + argno];
240 static inline void
241 common_semi_set_ret(CPUState *cs, target_ulong ret)
243 RISCVCPU *cpu = RISCV_CPU(cs);
244 CPURISCVState *env = &cpu->env;
245 env->gpr[xA0] = ret;
248 static inline bool
249 common_semi_sys_exit_extended(CPUState *cs, int nr)
251 return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
254 #ifndef CONFIG_USER_ONLY
256 static inline target_ulong
257 common_semi_rambase(CPUState *cs)
259 RISCVCPU *cpu = RISCV_CPU(cs);
260 CPURISCVState *env = &cpu->env;
261 return common_semi_find_region_base(env->gpr[xSP]);
263 #endif
265 #endif
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.
274 static int alloc_guestfd(void)
276 guint i;
278 if (!guestfd_array) {
279 /* New entries zero-initialized, i.e. type GuestFDUnused */
280 guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
283 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
284 for (i = 1; i < guestfd_array->len; i++) {
285 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
287 if (gf->type == GuestFDUnused) {
288 return i;
292 /* All elements already in use: expand the array */
293 g_array_set_size(guestfd_array, i + 1);
294 return i;
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.
302 static GuestFD *do_get_guestfd(int guestfd)
304 if (!guestfd_array) {
305 return NULL;
308 if (guestfd <= 0 || guestfd >= guestfd_array->len) {
309 return NULL;
312 return &g_array_index(guestfd_array, GuestFD, guestfd);
316 * Associate the specified guest fd (which must have been
317 * allocated via alloc_fd() and not previously used) with
318 * the specified host/gdb fd.
320 static void associate_guestfd(int guestfd, int hostfd)
322 GuestFD *gf = do_get_guestfd(guestfd);
324 assert(gf);
325 gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
326 gf->hostfd = hostfd;
330 * Deallocate the specified guest file descriptor. This doesn't
331 * close the host fd, it merely undoes the work of alloc_fd().
333 static void dealloc_guestfd(int guestfd)
335 GuestFD *gf = do_get_guestfd(guestfd);
337 assert(gf);
338 gf->type = GuestFDUnused;
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.
349 static GuestFD *get_guestfd(int guestfd)
351 GuestFD *gf = do_get_guestfd(guestfd);
353 if (!gf || gf->type == GuestFDUnused) {
354 return NULL;
356 return gf;
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.
366 #ifndef CONFIG_USER_ONLY
367 static target_ulong syscall_err;
369 #include "exec/softmmu-semi.h"
370 #endif
372 static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
374 if (code == (uint32_t)-1) {
375 #ifdef CONFIG_USER_ONLY
376 TaskState *ts = cs->opaque;
378 ts->swi_errno = errno;
379 #else
380 syscall_err = errno;
381 #endif
383 return code;
386 static inline uint32_t get_swi_errno(CPUState *cs)
388 #ifdef CONFIG_USER_ONLY
389 TaskState *ts = cs->opaque;
391 return ts->swi_errno;
392 #else
393 return syscall_err;
394 #endif
397 static target_ulong common_semi_syscall_len;
399 static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
401 target_ulong reg0 = common_semi_arg(cs, 0);
403 if (ret == (target_ulong)-1) {
404 errno = err;
405 set_swi_errno(cs, -1);
406 reg0 = ret;
407 } else {
408 /* Fixup syscalls that use nonstardard return conventions. */
409 switch (reg0) {
410 case TARGET_SYS_WRITE:
411 case TARGET_SYS_READ:
412 reg0 = common_semi_syscall_len - ret;
413 break;
414 case TARGET_SYS_SEEK:
415 reg0 = 0;
416 break;
417 default:
418 reg0 = ret;
419 break;
422 common_semi_set_ret(cs, reg0);
425 static target_ulong common_semi_flen_buf(CPUState *cs)
427 target_ulong sp;
428 #ifdef TARGET_ARM
429 /* 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.
434 ARMCPU *cpu = ARM_CPU(cs);
435 CPUARMState *env = &cpu->env;
437 if (is_a64(env)) {
438 sp = env->xregs[31];
439 } else {
440 sp = env->regs[13];
442 #endif
443 #ifdef TARGET_RISCV
444 RISCVCPU *cpu = RISCV_CPU(cs);
445 CPURISCVState *env = &cpu->env;
447 sp = env->gpr[xSP];
448 #endif
450 return sp - 64;
453 static void
454 common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
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;
459 cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32,
460 (uint8_t *)&size, 4, 0);
461 size = be32_to_cpu(size);
462 common_semi_set_ret(cs, size);
463 errno = err;
464 set_swi_errno(cs, -1);
467 static int common_semi_open_guestfd;
469 static void
470 common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
472 if (ret == (target_ulong)-1) {
473 errno = err;
474 set_swi_errno(cs, -1);
475 dealloc_guestfd(common_semi_open_guestfd);
476 } else {
477 associate_guestfd(common_semi_open_guestfd, ret);
478 ret = common_semi_open_guestfd;
480 common_semi_set_ret(cs, ret);
483 static target_ulong
484 common_semi_gdb_syscall(CPUState *cs, gdb_syscall_complete_cb cb,
485 const char *fmt, ...)
487 va_list va;
489 va_start(va, fmt);
490 gdb_do_syscallv(cb, fmt, va);
491 va_end(va);
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
501 * do_common_semihosting() will write it straight back into X0.
502 * (In linux-user mode, the callback will have happened before
503 * gdb_do_syscallv() returns.)
505 * We should tidy this up so neither this function nor
506 * do_common_semihosting() return a value, so the mistake of
507 * doing something with the return value is not possible to make.
510 return common_semi_arg(cs, 0);
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.
519 typedef uint32_t sys_closefn(CPUState *cs, GuestFD *gf);
520 typedef uint32_t sys_writefn(CPUState *cs, GuestFD *gf,
521 target_ulong buf, uint32_t len);
522 typedef uint32_t sys_readfn(CPUState *cs, GuestFD *gf,
523 target_ulong buf, uint32_t len);
524 typedef uint32_t sys_isattyfn(CPUState *cs, GuestFD *gf);
525 typedef uint32_t sys_seekfn(CPUState *cs, GuestFD *gf,
526 target_ulong offset);
527 typedef uint32_t sys_flenfn(CPUState *cs, GuestFD *gf);
529 static uint32_t host_closefn(CPUState *cs, GuestFD *gf)
532 * Only close the underlying host fd if it's one we opened on behalf
533 * of the guest in SYS_OPEN.
535 if (gf->hostfd == STDIN_FILENO ||
536 gf->hostfd == STDOUT_FILENO ||
537 gf->hostfd == STDERR_FILENO) {
538 return 0;
540 return set_swi_errno(cs, close(gf->hostfd));
543 static uint32_t host_writefn(CPUState *cs, GuestFD *gf,
544 target_ulong buf, uint32_t len)
546 CPUArchState *env = cs->env_ptr;
547 uint32_t ret;
548 char *s = lock_user(VERIFY_READ, buf, len, 1);
549 (void) env; /* Used in arm softmmu lock_user implicitly */
550 if (!s) {
551 /* Return bytes not written on error */
552 return len;
554 ret = set_swi_errno(cs, write(gf->hostfd, s, len));
555 unlock_user(s, buf, 0);
556 if (ret == (uint32_t)-1) {
557 ret = 0;
559 /* Return bytes not written */
560 return len - ret;
563 static uint32_t host_readfn(CPUState *cs, GuestFD *gf,
564 target_ulong buf, uint32_t len)
566 CPUArchState *env = cs->env_ptr;
567 uint32_t ret;
568 char *s = lock_user(VERIFY_WRITE, buf, len, 0);
569 (void) env; /* Used in arm softmmu lock_user implicitly */
570 if (!s) {
571 /* return bytes not read */
572 return len;
574 do {
575 ret = set_swi_errno(cs, read(gf->hostfd, s, len));
576 } while (ret == -1 && errno == EINTR);
577 unlock_user(s, buf, len);
578 if (ret == (uint32_t)-1) {
579 ret = 0;
581 /* Return bytes not read */
582 return len - ret;
585 static uint32_t host_isattyfn(CPUState *cs, GuestFD *gf)
587 return isatty(gf->hostfd);
590 static uint32_t host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
592 uint32_t ret = set_swi_errno(cs, lseek(gf->hostfd, offset, SEEK_SET));
593 if (ret == (uint32_t)-1) {
594 return -1;
596 return 0;
599 static uint32_t host_flenfn(CPUState *cs, GuestFD *gf)
601 struct stat buf;
602 uint32_t ret = set_swi_errno(cs, fstat(gf->hostfd, &buf));
603 if (ret == (uint32_t)-1) {
604 return -1;
606 return buf.st_size;
609 static uint32_t gdb_closefn(CPUState *cs, GuestFD *gf)
611 return common_semi_gdb_syscall(cs, common_semi_cb, "close,%x", gf->hostfd);
614 static uint32_t gdb_writefn(CPUState *cs, GuestFD *gf,
615 target_ulong buf, uint32_t len)
617 common_semi_syscall_len = len;
618 return common_semi_gdb_syscall(cs, common_semi_cb, "write,%x,%x,%x",
619 gf->hostfd, buf, len);
622 static uint32_t gdb_readfn(CPUState *cs, GuestFD *gf,
623 target_ulong buf, uint32_t len)
625 common_semi_syscall_len = len;
626 return common_semi_gdb_syscall(cs, common_semi_cb, "read,%x,%x,%x",
627 gf->hostfd, buf, len);
630 static uint32_t gdb_isattyfn(CPUState *cs, GuestFD *gf)
632 return common_semi_gdb_syscall(cs, common_semi_cb, "isatty,%x", gf->hostfd);
635 static uint32_t gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
637 return common_semi_gdb_syscall(cs, common_semi_cb, "lseek,%x,%x,0",
638 gf->hostfd, offset);
641 static uint32_t gdb_flenfn(CPUState *cs, GuestFD *gf)
643 return common_semi_gdb_syscall(cs, common_semi_flen_cb, "fstat,%x,%x",
644 gf->hostfd, common_semi_flen_buf(cs));
647 #define SHFB_MAGIC_0 0x53
648 #define SHFB_MAGIC_1 0x48
649 #define SHFB_MAGIC_2 0x46
650 #define SHFB_MAGIC_3 0x42
652 /* Feature bits reportable in feature byte 0 */
653 #define SH_EXT_EXIT_EXTENDED (1 << 0)
654 #define SH_EXT_STDOUT_STDERR (1 << 1)
656 static const uint8_t featurefile_data[] = {
657 SHFB_MAGIC_0,
658 SHFB_MAGIC_1,
659 SHFB_MAGIC_2,
660 SHFB_MAGIC_3,
661 SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
664 static void init_featurefile_guestfd(int guestfd)
666 GuestFD *gf = do_get_guestfd(guestfd);
668 assert(gf);
669 gf->type = GuestFDFeatureFile;
670 gf->featurefile_offset = 0;
673 static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf)
675 /* Nothing to do */
676 return 0;
679 static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf,
680 target_ulong buf, uint32_t len)
682 /* This fd can never be open for writing */
684 errno = EBADF;
685 return set_swi_errno(cs, -1);
688 static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
689 target_ulong buf, uint32_t len)
691 CPUArchState *env = cs->env_ptr;
692 uint32_t i;
693 char *s;
695 (void) env; /* Used in arm softmmu lock_user implicitly */
696 s = lock_user(VERIFY_WRITE, buf, len, 0);
697 if (!s) {
698 return len;
701 for (i = 0; i < len; i++) {
702 if (gf->featurefile_offset >= sizeof(featurefile_data)) {
703 break;
705 s[i] = featurefile_data[gf->featurefile_offset];
706 gf->featurefile_offset++;
709 unlock_user(s, buf, len);
711 /* Return number of bytes not read */
712 return len - i;
715 static uint32_t featurefile_isattyfn(CPUState *cs, GuestFD *gf)
717 return 0;
720 static uint32_t featurefile_seekfn(CPUState *cs, GuestFD *gf,
721 target_ulong offset)
723 gf->featurefile_offset = offset;
724 return 0;
727 static uint32_t featurefile_flenfn(CPUState *cs, GuestFD *gf)
729 return sizeof(featurefile_data);
732 typedef struct GuestFDFunctions {
733 sys_closefn *closefn;
734 sys_writefn *writefn;
735 sys_readfn *readfn;
736 sys_isattyfn *isattyfn;
737 sys_seekfn *seekfn;
738 sys_flenfn *flenfn;
739 } GuestFDFunctions;
741 static const GuestFDFunctions guestfd_fns[] = {
742 [GuestFDHost] = {
743 .closefn = host_closefn,
744 .writefn = host_writefn,
745 .readfn = host_readfn,
746 .isattyfn = host_isattyfn,
747 .seekfn = host_seekfn,
748 .flenfn = host_flenfn,
750 [GuestFDGDB] = {
751 .closefn = gdb_closefn,
752 .writefn = gdb_writefn,
753 .readfn = gdb_readfn,
754 .isattyfn = gdb_isattyfn,
755 .seekfn = gdb_seekfn,
756 .flenfn = gdb_flenfn,
758 [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,
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.
773 static inline bool is_64bit_semihosting(CPUArchState *env)
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
785 #define GET_ARG(n) do { \
786 if (is_64bit_semihosting(env)) { \
787 if (get_user_u64(arg ## n, args + (n) * 8)) { \
788 errno = EFAULT; \
789 return set_swi_errno(cs, -1); \
791 } else { \
792 if (get_user_u32(arg ## n, args + (n) * 4)) { \
793 errno = EFAULT; \
794 return set_swi_errno(cs, -1); \
797 } while (0)
799 #define SET_ARG(n, val) \
800 (is_64bit_semihosting(env) ? \
801 put_user_u64(val, args + (n) * 8) : \
802 put_user_u32(val, args + (n) * 4))
806 * Do a semihosting call.
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.
814 target_ulong do_common_semihosting(CPUState *cs)
816 CPUArchState *env = cs->env_ptr;
817 target_ulong args;
818 target_ulong arg0, arg1, arg2, arg3;
819 target_ulong ul_ret;
820 char * s;
821 int nr;
822 uint32_t ret;
823 uint32_t len;
824 GuestFD *gf;
825 int64_t elapsed;
827 (void) env; /* Used implicitly by arm lock_user macro */
828 nr = common_semi_arg(cs, 0) & 0xffffffffU;
829 args = common_semi_arg(cs, 1);
831 switch (nr) {
832 case TARGET_SYS_OPEN:
834 int guestfd;
836 GET_ARG(0);
837 GET_ARG(1);
838 GET_ARG(2);
839 s = lock_user_string(arg0);
840 if (!s) {
841 errno = EFAULT;
842 return set_swi_errno(cs, -1);
844 if (arg1 >= 12) {
845 unlock_user(s, arg0, 0);
846 errno = EINVAL;
847 return set_swi_errno(cs, -1);
850 guestfd = alloc_guestfd();
851 if (guestfd < 0) {
852 unlock_user(s, arg0, 0);
853 errno = EMFILE;
854 return set_swi_errno(cs, -1);
857 if (strcmp(s, ":tt") == 0) {
858 int result_fileno;
861 * We implement SH_EXT_STDOUT_STDERR, so:
862 * open for read == stdin
863 * open for write == stdout
864 * open for append == stderr
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;
873 associate_guestfd(guestfd, result_fileno);
874 unlock_user(s, arg0, 0);
875 return guestfd;
877 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;
883 return set_swi_errno(cs, -1);
885 init_featurefile_guestfd(guestfd);
886 return guestfd;
889 if (use_gdb_syscalls()) {
890 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]);
894 } else {
895 ret = set_swi_errno(cs, open(s, open_modeflags[arg1], 0644));
896 if (ret == (uint32_t)-1) {
897 dealloc_guestfd(guestfd);
898 } else {
899 associate_guestfd(guestfd, ret);
900 ret = guestfd;
903 unlock_user(s, arg0, 0);
904 return ret;
906 case TARGET_SYS_CLOSE:
907 GET_ARG(0);
909 gf = get_guestfd(arg0);
910 if (!gf) {
911 errno = EBADF;
912 return set_swi_errno(cs, -1);
915 ret = guestfd_fns[gf->type].closefn(cs, gf);
916 dealloc_guestfd(arg0);
917 return ret;
918 case TARGET_SYS_WRITEC:
919 qemu_semihosting_console_outc(cs->env_ptr, args);
920 return 0xdeadbeef;
921 case TARGET_SYS_WRITE0:
922 return qemu_semihosting_console_outs(cs->env_ptr, args);
923 case TARGET_SYS_WRITE:
924 GET_ARG(0);
925 GET_ARG(1);
926 GET_ARG(2);
927 len = arg2;
929 gf = get_guestfd(arg0);
930 if (!gf) {
931 errno = EBADF;
932 return set_swi_errno(cs, -1);
935 return guestfd_fns[gf->type].writefn(cs, gf, arg1, len);
936 case TARGET_SYS_READ:
937 GET_ARG(0);
938 GET_ARG(1);
939 GET_ARG(2);
940 len = arg2;
942 gf = get_guestfd(arg0);
943 if (!gf) {
944 errno = EBADF;
945 return set_swi_errno(cs, -1);
948 return guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
949 case TARGET_SYS_READC:
950 return qemu_semihosting_console_inc(cs->env_ptr);
951 case TARGET_SYS_ISERROR:
952 GET_ARG(0);
953 return (target_long) arg0 < 0 ? 1 : 0;
954 case TARGET_SYS_ISTTY:
955 GET_ARG(0);
957 gf = get_guestfd(arg0);
958 if (!gf) {
959 errno = EBADF;
960 return set_swi_errno(cs, -1);
963 return guestfd_fns[gf->type].isattyfn(cs, gf);
964 case TARGET_SYS_SEEK:
965 GET_ARG(0);
966 GET_ARG(1);
968 gf = get_guestfd(arg0);
969 if (!gf) {
970 errno = EBADF;
971 return set_swi_errno(cs, -1);
974 return guestfd_fns[gf->type].seekfn(cs, gf, arg1);
975 case TARGET_SYS_FLEN:
976 GET_ARG(0);
978 gf = get_guestfd(arg0);
979 if (!gf) {
980 errno = EBADF;
981 return set_swi_errno(cs, -1);
984 return guestfd_fns[gf->type].flenfn(cs, gf);
985 case TARGET_SYS_TMPNAM:
986 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;
993 ul_ret = (target_ulong) -1;
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;
1002 free(s);
1003 return ul_ret;
1004 case TARGET_SYS_REMOVE:
1005 GET_ARG(0);
1006 GET_ARG(1);
1007 if (use_gdb_syscalls()) {
1008 ret = common_semi_gdb_syscall(cs, common_semi_cb, "unlink,%s",
1009 arg0, (int)arg1 + 1);
1010 } else {
1011 s = lock_user_string(arg0);
1012 if (!s) {
1013 errno = EFAULT;
1014 return set_swi_errno(cs, -1);
1016 ret = set_swi_errno(cs, remove(s));
1017 unlock_user(s, arg0, 0);
1019 return ret;
1020 case TARGET_SYS_RENAME:
1021 GET_ARG(0);
1022 GET_ARG(1);
1023 GET_ARG(2);
1024 GET_ARG(3);
1025 if (use_gdb_syscalls()) {
1026 return common_semi_gdb_syscall(cs, common_semi_cb, "rename,%s,%s",
1027 arg0, (int)arg1 + 1, arg2,
1028 (int)arg3 + 1);
1029 } else {
1030 char *s2;
1031 s = lock_user_string(arg0);
1032 s2 = lock_user_string(arg2);
1033 if (!s || !s2) {
1034 errno = EFAULT;
1035 ret = set_swi_errno(cs, -1);
1036 } else {
1037 ret = set_swi_errno(cs, rename(s, s2));
1039 if (s2)
1040 unlock_user(s2, arg2, 0);
1041 if (s)
1042 unlock_user(s, arg0, 0);
1043 return ret;
1045 case TARGET_SYS_CLOCK:
1046 return clock() / (CLOCKS_PER_SEC / 100);
1047 case TARGET_SYS_TIME:
1048 return set_swi_errno(cs, time(NULL));
1049 case TARGET_SYS_SYSTEM:
1050 GET_ARG(0);
1051 GET_ARG(1);
1052 if (use_gdb_syscalls()) {
1053 return common_semi_gdb_syscall(cs, common_semi_cb, "system,%s",
1054 arg0, (int)arg1 + 1);
1055 } else {
1056 s = lock_user_string(arg0);
1057 if (!s) {
1058 errno = EFAULT;
1059 return set_swi_errno(cs, -1);
1061 ret = set_swi_errno(cs, system(s));
1062 unlock_user(s, arg0, 0);
1063 return ret;
1065 case TARGET_SYS_ERRNO:
1066 return get_swi_errno(cs);
1067 case TARGET_SYS_GET_CMDLINE:
1069 /* Build a command-line from the original argv.
1071 * The inputs are:
1072 * * 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
1075 * bytes.
1077 * The outputs are:
1078 * * arg0, pointer to null-terminated string of the
1079 * command line.
1080 * * arg1, length of the string pointed to by arg0.
1083 char *output_buffer;
1084 size_t input_size;
1085 size_t output_size;
1086 int status = 0;
1087 #if !defined(CONFIG_USER_ONLY)
1088 const char *cmdline;
1089 #else
1090 TaskState *ts = cs->opaque;
1091 #endif
1092 GET_ARG(0);
1093 GET_ARG(1);
1094 input_size = arg1;
1095 /* Compute the size of the output string. */
1096 #if !defined(CONFIG_USER_ONLY)
1097 cmdline = semihosting_get_cmdline();
1098 if (cmdline == NULL) {
1099 cmdline = ""; /* Default to an empty line. */
1101 output_size = strlen(cmdline) + 1; /* Count terminating 0. */
1102 #else
1103 unsigned int i;
1105 output_size = ts->info->arg_end - ts->info->arg_start;
1106 if (!output_size) {
1108 * We special-case the "empty command line" case (argc==0).
1109 * Just provide the terminating 0.
1111 output_size = 1;
1113 #endif
1115 if (output_size > input_size) {
1116 /* Not enough space to store command-line arguments. */
1117 errno = E2BIG;
1118 return set_swi_errno(cs, -1);
1121 /* Adjust the command-line length. */
1122 if (SET_ARG(1, output_size - 1)) {
1123 /* Couldn't write back to argument block */
1124 errno = EFAULT;
1125 return set_swi_errno(cs, -1);
1128 /* Lock the buffer on the ARM side. */
1129 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
1130 if (!output_buffer) {
1131 errno = EFAULT;
1132 return set_swi_errno(cs, -1);
1135 /* Copy the command-line arguments. */
1136 #if !defined(CONFIG_USER_ONLY)
1137 pstrcpy(output_buffer, output_size, cmdline);
1138 #else
1139 if (output_size == 1) {
1140 /* Empty command-line. */
1141 output_buffer[0] = '\0';
1142 goto out;
1145 if (copy_from_user(output_buffer, ts->info->arg_start,
1146 output_size)) {
1147 errno = EFAULT;
1148 status = set_swi_errno(cs, -1);
1149 goto out;
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] = ' ';
1158 out:
1159 #endif
1160 /* Unlock the buffer on the ARM side. */
1161 unlock_user(output_buffer, arg0, output_size);
1163 return status;
1165 case TARGET_SYS_HEAPINFO:
1167 target_ulong retvals[4];
1168 target_ulong limit;
1169 int i;
1170 #ifdef CONFIG_USER_ONLY
1171 TaskState *ts = cs->opaque;
1172 #else
1173 target_ulong rambase = common_semi_rambase(cs);
1174 #endif
1176 GET_ARG(0);
1178 #ifdef CONFIG_USER_ONLY
1180 * Some C libraries assume the heap immediately follows .bss, so
1181 * allocate it using sbrk.
1183 if (!ts->heap_limit) {
1184 abi_ulong ret;
1186 ts->heap_base = do_brk(0);
1187 limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE;
1188 /* Try a big heap, and reduce the size if that fails. */
1189 for (;;) {
1190 ret = do_brk(limit);
1191 if (ret >= limit) {
1192 break;
1194 limit = (ts->heap_base >> 1) + (limit >> 1);
1196 ts->heap_limit = limit;
1199 retvals[0] = ts->heap_base;
1200 retvals[1] = ts->heap_limit;
1201 retvals[2] = ts->stack_base;
1202 retvals[3] = 0; /* Stack limit. */
1203 #else
1204 limit = current_machine->ram_size;
1205 /* TODO: Make this use the limit of the loaded application. */
1206 retvals[0] = rambase + limit / 2;
1207 retvals[1] = rambase + limit;
1208 retvals[2] = rambase + limit; /* Stack base */
1209 retvals[3] = rambase; /* Stack limit. */
1210 #endif
1212 for (i = 0; i < ARRAY_SIZE(retvals); i++) {
1213 bool fail;
1215 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);
1221 if (fail) {
1222 /* Couldn't write back to argument block */
1223 errno = EFAULT;
1224 return set_swi_errno(cs, -1);
1227 return 0;
1229 case TARGET_SYS_EXIT:
1230 case TARGET_SYS_EXIT_EXTENDED:
1231 if (common_semi_sys_exit_extended(cs, nr)) {
1233 * The A64 version of SYS_EXIT takes a parameter block,
1234 * so the application-exit type can return a subcode which
1235 * is the exit status code from the application.
1236 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1237 * which allows A32/T32 guests to also provide a status code.
1239 GET_ARG(0);
1240 GET_ARG(1);
1242 if (arg0 == ADP_Stopped_ApplicationExit) {
1243 ret = arg1;
1244 } else {
1245 ret = 1;
1247 } else {
1249 * 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.
1254 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
1256 gdb_exit(ret);
1257 exit(ret);
1258 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));
1266 return 0;
1267 case TARGET_SYS_TICKFREQ:
1268 /* qemu always uses nsec */
1269 return 1000000000;
1270 case TARGET_SYS_SYNCCACHE:
1272 * Clean the D-cache and invalidate the I-cache for the specified
1273 * virtual address range. This is a nop for us since we don't
1274 * implement caches. This is only present on A64.
1276 #ifdef TARGET_ARM
1277 if (is_a64(cs->env_ptr)) {
1278 return 0;
1280 #endif
1281 #ifdef TARGET_RISCV
1282 return 0;
1283 #endif
1284 /* fall through -- invalid for A32/T32 */
1285 default:
1286 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
1287 cpu_dump_state(cs, stderr, 0);
1288 abort();