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:
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
43 #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
45 #include "exec/gdbstub.h"
46 #include "qemu/cutils.h"
48 #include "hw/arm/boot.h"
50 #include "hw/boards.h"
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)
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] = {
97 GDB_O_RDONLY
| GDB_O_BINARY
,
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] = {
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
{
129 GuestFDFeatureFile
= 3,
133 * Guest file descriptors are integer indexes into an array of
134 * these structures (we will dynamically resize as necessary).
136 typedef struct GuestFD
{
140 target_ulong featurefile_offset
;
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
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
,
163 if (subregion
->ram
&& !subregion
->readonly
) {
164 Int128 top128
= int128_add(int128_make64(subregion
->addr
),
166 Int128 addr128
= int128_make64(addr
);
167 if (subregion
->addr
<= addr
&& int128_lt(addr128
, top128
)) {
168 return subregion
->addr
;
177 static inline target_ulong
178 common_semi_arg(CPUState
*cs
, int argno
)
180 ARMCPU
*cpu
= ARM_CPU(cs
);
181 CPUARMState
*env
= &cpu
->env
;
183 return env
->xregs
[argno
];
185 return env
->regs
[argno
];
190 common_semi_set_ret(CPUState
*cs
, target_ulong ret
)
192 ARMCPU
*cpu
= ARM_CPU(cs
);
193 CPUARMState
*env
= &cpu
->env
;
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
;
217 return info
->loader_start
;
225 return common_semi_find_region_base(sp
);
229 #endif /* TARGET_ARM */
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
];
241 common_semi_set_ret(CPUState
*cs
, target_ulong ret
)
243 RISCVCPU
*cpu
= RISCV_CPU(cs
);
244 CPURISCVState
*env
= &cpu
->env
;
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
]);
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)
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
) {
292 /* All elements already in use: expand the array */
293 g_array_set_size(guestfd_array
, i
+ 1);
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
) {
308 if (guestfd
<= 0 || guestfd
>= guestfd_array
->len
) {
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
);
325 gf
->type
= use_gdb_syscalls() ? GuestFDGDB
: GuestFDHost
;
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
);
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
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
) {
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"
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
;
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
;
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) {
405 set_swi_errno(cs
, -1);
408 /* Fixup syscalls that use nonstardard return conventions. */
410 case TARGET_SYS_WRITE
:
411 case TARGET_SYS_READ
:
412 reg0
= common_semi_syscall_len
- ret
;
414 case TARGET_SYS_SEEK
:
422 common_semi_set_ret(cs
, reg0
);
425 static target_ulong
common_semi_flen_buf(CPUState
*cs
)
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
;
444 RISCVCPU
*cpu
= RISCV_CPU(cs
);
445 CPURISCVState
*env
= &cpu
->env
;
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. */
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
);
464 set_swi_errno(cs
, -1);
467 static int common_semi_open_guestfd
;
470 common_semi_open_cb(CPUState
*cs
, target_ulong ret
, target_ulong err
)
472 if (ret
== (target_ulong
)-1) {
474 set_swi_errno(cs
, -1);
475 dealloc_guestfd(common_semi_open_guestfd
);
477 associate_guestfd(common_semi_open_guestfd
, ret
);
478 ret
= common_semi_open_guestfd
;
480 common_semi_set_ret(cs
, ret
);
484 common_semi_gdb_syscall(CPUState
*cs
, gdb_syscall_complete_cb cb
,
485 const char *fmt
, ...)
490 gdb_do_syscallv(cb
, fmt
, 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
) {
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
;
548 char *s
= lock_user(VERIFY_READ
, buf
, len
, 1);
549 (void) env
; /* Used in arm softmmu lock_user implicitly */
551 /* Return bytes not written on error */
554 ret
= set_swi_errno(cs
, write(gf
->hostfd
, s
, len
));
555 unlock_user(s
, buf
, 0);
556 if (ret
== (uint32_t)-1) {
559 /* Return bytes not written */
563 static uint32_t host_readfn(CPUState
*cs
, GuestFD
*gf
,
564 target_ulong buf
, uint32_t len
)
566 CPUArchState
*env
= cs
->env_ptr
;
568 char *s
= lock_user(VERIFY_WRITE
, buf
, len
, 0);
569 (void) env
; /* Used in arm softmmu lock_user implicitly */
571 /* return bytes not read */
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) {
581 /* Return bytes not read */
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) {
599 static uint32_t host_flenfn(CPUState
*cs
, GuestFD
*gf
)
602 uint32_t ret
= set_swi_errno(cs
, fstat(gf
->hostfd
, &buf
));
603 if (ret
== (uint32_t)-1) {
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",
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
[] = {
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
);
669 gf
->type
= GuestFDFeatureFile
;
670 gf
->featurefile_offset
= 0;
673 static uint32_t featurefile_closefn(CPUState
*cs
, GuestFD
*gf
)
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 */
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
;
695 (void) env
; /* Used in arm softmmu lock_user implicitly */
696 s
= lock_user(VERIFY_WRITE
, buf
, len
, 0);
701 for (i
= 0; i
< len
; i
++) {
702 if (gf
->featurefile_offset
>= sizeof(featurefile_data
)) {
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 */
715 static uint32_t featurefile_isattyfn(CPUState
*cs
, GuestFD
*gf
)
720 static uint32_t featurefile_seekfn(CPUState
*cs
, GuestFD
*gf
,
723 gf
->featurefile_offset
= offset
;
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
;
736 sys_isattyfn
*isattyfn
;
741 static const GuestFDFunctions guestfd_fns
[] = {
743 .closefn
= host_closefn
,
744 .writefn
= host_writefn
,
745 .readfn
= host_readfn
,
746 .isattyfn
= host_isattyfn
,
747 .seekfn
= host_seekfn
,
748 .flenfn
= host_flenfn
,
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)
777 #elif defined(TARGET_RISCV)
778 return !riscv_cpu_is_32bit(env
);
780 #error un-handled architecture
785 #define GET_ARG(n) do { \
786 if (is_64bit_semihosting(env)) { \
787 if (get_user_u64(arg ## n, args + (n) * 8)) { \
789 return set_swi_errno(cs, -1); \
792 if (get_user_u32(arg ## n, args + (n) * 4)) { \
794 return set_swi_errno(cs, -1); \
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
;
818 target_ulong arg0
, arg1
, arg2
, arg3
;
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);
832 case TARGET_SYS_OPEN
:
839 s
= lock_user_string(arg0
);
842 return set_swi_errno(cs
, -1);
845 unlock_user(s
, arg0
, 0);
847 return set_swi_errno(cs
, -1);
850 guestfd
= alloc_guestfd();
852 unlock_user(s
, arg0
, 0);
854 return set_swi_errno(cs
, -1);
857 if (strcmp(s
, ":tt") == 0) {
861 * We implement SH_EXT_STDOUT_STDERR, so:
862 * open for read == stdin
863 * open for write == stdout
864 * open for append == stderr
867 result_fileno
= STDIN_FILENO
;
868 } else if (arg1
< 8) {
869 result_fileno
= STDOUT_FILENO
;
871 result_fileno
= STDERR_FILENO
;
873 associate_guestfd(guestfd
, result_fileno
);
874 unlock_user(s
, arg0
, 0);
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
);
883 return set_swi_errno(cs
, -1);
885 init_featurefile_guestfd(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
]);
895 ret
= set_swi_errno(cs
, open(s
, open_modeflags
[arg1
], 0644));
896 if (ret
== (uint32_t)-1) {
897 dealloc_guestfd(guestfd
);
899 associate_guestfd(guestfd
, ret
);
903 unlock_user(s
, arg0
, 0);
906 case TARGET_SYS_CLOSE
:
909 gf
= get_guestfd(arg0
);
912 return set_swi_errno(cs
, -1);
915 ret
= guestfd_fns
[gf
->type
].closefn(cs
, gf
);
916 dealloc_guestfd(arg0
);
918 case TARGET_SYS_WRITEC
:
919 qemu_semihosting_console_outc(cs
->env_ptr
, args
);
921 case TARGET_SYS_WRITE0
:
922 return qemu_semihosting_console_outs(cs
->env_ptr
, args
);
923 case TARGET_SYS_WRITE
:
929 gf
= get_guestfd(arg0
);
932 return set_swi_errno(cs
, -1);
935 return guestfd_fns
[gf
->type
].writefn(cs
, gf
, arg1
, len
);
936 case TARGET_SYS_READ
:
942 gf
= get_guestfd(arg0
);
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
:
953 return (target_long
) arg0
< 0 ? 1 : 0;
954 case TARGET_SYS_ISTTY
:
957 gf
= get_guestfd(arg0
);
960 return set_swi_errno(cs
, -1);
963 return guestfd_fns
[gf
->type
].isattyfn(cs
, gf
);
964 case TARGET_SYS_SEEK
:
968 gf
= get_guestfd(arg0
);
971 return set_swi_errno(cs
, -1);
974 return guestfd_fns
[gf
->type
].seekfn(cs
, gf
, arg1
);
975 case TARGET_SYS_FLEN
:
978 gf
= get_guestfd(arg0
);
981 return set_swi_errno(cs
, -1);
984 return guestfd_fns
[gf
->type
].flenfn(cs
, gf
);
985 case TARGET_SYS_TMPNAM
:
989 if (asprintf(&s
, "/tmp/qemu-%x%02x", getpid(),
990 (int) (arg1
& 0xff)) < 0) {
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);
999 unlock_user(output
, arg0
, arg2
);
1004 case TARGET_SYS_REMOVE
:
1007 if (use_gdb_syscalls()) {
1008 ret
= common_semi_gdb_syscall(cs
, common_semi_cb
, "unlink,%s",
1009 arg0
, (int)arg1
+ 1);
1011 s
= lock_user_string(arg0
);
1014 return set_swi_errno(cs
, -1);
1016 ret
= set_swi_errno(cs
, remove(s
));
1017 unlock_user(s
, arg0
, 0);
1020 case TARGET_SYS_RENAME
:
1025 if (use_gdb_syscalls()) {
1026 return common_semi_gdb_syscall(cs
, common_semi_cb
, "rename,%s,%s",
1027 arg0
, (int)arg1
+ 1, arg2
,
1031 s
= lock_user_string(arg0
);
1032 s2
= lock_user_string(arg2
);
1035 ret
= set_swi_errno(cs
, -1);
1037 ret
= set_swi_errno(cs
, rename(s
, s2
));
1040 unlock_user(s2
, arg2
, 0);
1042 unlock_user(s
, arg0
, 0);
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
:
1052 if (use_gdb_syscalls()) {
1053 return common_semi_gdb_syscall(cs
, common_semi_cb
, "system,%s",
1054 arg0
, (int)arg1
+ 1);
1056 s
= lock_user_string(arg0
);
1059 return set_swi_errno(cs
, -1);
1061 ret
= set_swi_errno(cs
, system(s
));
1062 unlock_user(s
, arg0
, 0);
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.
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
1078 * * arg0, pointer to null-terminated string of the
1080 * * arg1, length of the string pointed to by arg0.
1083 char *output_buffer
;
1087 #if !defined(CONFIG_USER_ONLY)
1088 const char *cmdline
;
1090 TaskState
*ts
= cs
->opaque
;
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. */
1105 output_size
= ts
->info
->arg_end
- ts
->info
->arg_start
;
1108 * We special-case the "empty command line" case (argc==0).
1109 * Just provide the terminating 0.
1115 if (output_size
> input_size
) {
1116 /* Not enough space to store command-line arguments. */
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 */
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
) {
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
);
1139 if (output_size
== 1) {
1140 /* Empty command-line. */
1141 output_buffer
[0] = '\0';
1145 if (copy_from_user(output_buffer
, ts
->info
->arg_start
,
1148 status
= set_swi_errno(cs
, -1);
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
] = ' ';
1160 /* Unlock the buffer on the ARM side. */
1161 unlock_user(output_buffer
, arg0
, output_size
);
1165 case TARGET_SYS_HEAPINFO
:
1167 target_ulong retvals
[4];
1170 #ifdef CONFIG_USER_ONLY
1171 TaskState
*ts
= cs
->opaque
;
1173 target_ulong rambase
= common_semi_rambase(cs
);
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
) {
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. */
1190 ret
= do_brk(limit
);
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. */
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. */
1212 for (i
= 0; i
< ARRAY_SIZE(retvals
); i
++) {
1215 if (is_64bit_semihosting(env
)) {
1216 fail
= put_user_u64(retvals
[i
], arg0
+ i
* 8);
1218 fail
= put_user_u32(retvals
[i
], arg0
+ i
* 4);
1222 /* Couldn't write back to argument block */
1224 return set_swi_errno(cs
, -1);
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.
1242 if (arg0
== ADP_Stopped_ApplicationExit
) {
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;
1258 case TARGET_SYS_ELAPSED
:
1259 elapsed
= get_clock() - clock_start
;
1260 if (sizeof(target_ulong
) == 8) {
1261 SET_ARG(0, elapsed
);
1263 SET_ARG(0, (uint32_t) elapsed
);
1264 SET_ARG(1, (uint32_t) (elapsed
>> 32));
1267 case TARGET_SYS_TICKFREQ
:
1268 /* qemu always uses nsec */
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.
1277 if (is_a64(cs
->env_ptr
)) {
1284 /* fall through -- invalid for A32/T32 */
1286 fprintf(stderr
, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr
);
1287 cpu_dump_state(cs
, stderr
, 0);