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"
29 #include "hw/semihosting/semihost.h"
30 #include "hw/semihosting/console.h"
32 #ifdef CONFIG_USER_ONLY
35 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
37 #include "exec/gdbstub.h"
38 #include "qemu/cutils.h"
39 #include "hw/arm/boot.h"
42 #define TARGET_SYS_OPEN 0x01
43 #define TARGET_SYS_CLOSE 0x02
44 #define TARGET_SYS_WRITEC 0x03
45 #define TARGET_SYS_WRITE0 0x04
46 #define TARGET_SYS_WRITE 0x05
47 #define TARGET_SYS_READ 0x06
48 #define TARGET_SYS_READC 0x07
49 #define TARGET_SYS_ISTTY 0x09
50 #define TARGET_SYS_SEEK 0x0a
51 #define TARGET_SYS_FLEN 0x0c
52 #define TARGET_SYS_TMPNAM 0x0d
53 #define TARGET_SYS_REMOVE 0x0e
54 #define TARGET_SYS_RENAME 0x0f
55 #define TARGET_SYS_CLOCK 0x10
56 #define TARGET_SYS_TIME 0x11
57 #define TARGET_SYS_SYSTEM 0x12
58 #define TARGET_SYS_ERRNO 0x13
59 #define TARGET_SYS_GET_CMDLINE 0x15
60 #define TARGET_SYS_HEAPINFO 0x16
61 #define TARGET_SYS_EXIT 0x18
62 #define TARGET_SYS_SYNCCACHE 0x19
63 #define TARGET_SYS_EXIT_EXTENDED 0x20
65 /* ADP_Stopped_ApplicationExit is used for exit(0),
66 * anything else is implemented as exit(1) */
67 #define ADP_Stopped_ApplicationExit (0x20026)
73 #define GDB_O_RDONLY 0x000
74 #define GDB_O_WRONLY 0x001
75 #define GDB_O_RDWR 0x002
76 #define GDB_O_APPEND 0x008
77 #define GDB_O_CREAT 0x200
78 #define GDB_O_TRUNC 0x400
79 #define GDB_O_BINARY 0
81 static int gdb_open_modeflags
[12] = {
83 GDB_O_RDONLY
| GDB_O_BINARY
,
85 GDB_O_RDWR
| GDB_O_BINARY
,
86 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_TRUNC
,
87 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_TRUNC
| GDB_O_BINARY
,
88 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_TRUNC
,
89 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_TRUNC
| GDB_O_BINARY
,
90 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_APPEND
,
91 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_APPEND
| GDB_O_BINARY
,
92 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_APPEND
,
93 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_APPEND
| GDB_O_BINARY
96 static int open_modeflags
[12] = {
101 O_WRONLY
| O_CREAT
| O_TRUNC
,
102 O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
,
103 O_RDWR
| O_CREAT
| O_TRUNC
,
104 O_RDWR
| O_CREAT
| O_TRUNC
| O_BINARY
,
105 O_WRONLY
| O_CREAT
| O_APPEND
,
106 O_WRONLY
| O_CREAT
| O_APPEND
| O_BINARY
,
107 O_RDWR
| O_CREAT
| O_APPEND
,
108 O_RDWR
| O_CREAT
| O_APPEND
| O_BINARY
111 typedef enum GuestFDType
{
115 GuestFDFeatureFile
= 3,
119 * Guest file descriptors are integer indexes into an array of
120 * these structures (we will dynamically resize as necessary).
122 typedef struct GuestFD
{
126 target_ulong featurefile_offset
;
130 static GArray
*guestfd_array
;
133 * Allocate a new guest file descriptor and return it; if we
134 * couldn't allocate a new fd then return -1.
135 * This is a fairly simplistic implementation because we don't
136 * expect that most semihosting guest programs will make very
137 * heavy use of opening and closing fds.
139 static int alloc_guestfd(void)
143 if (!guestfd_array
) {
144 /* New entries zero-initialized, i.e. type GuestFDUnused */
145 guestfd_array
= g_array_new(FALSE
, TRUE
, sizeof(GuestFD
));
148 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
149 for (i
= 1; i
< guestfd_array
->len
; i
++) {
150 GuestFD
*gf
= &g_array_index(guestfd_array
, GuestFD
, i
);
152 if (gf
->type
== GuestFDUnused
) {
157 /* All elements already in use: expand the array */
158 g_array_set_size(guestfd_array
, i
+ 1);
163 * Look up the guestfd in the data structure; return NULL
164 * for out of bounds, but don't check whether the slot is unused.
165 * This is used internally by the other guestfd functions.
167 static GuestFD
*do_get_guestfd(int guestfd
)
169 if (!guestfd_array
) {
173 if (guestfd
<= 0 || guestfd
>= guestfd_array
->len
) {
177 return &g_array_index(guestfd_array
, GuestFD
, guestfd
);
181 * Associate the specified guest fd (which must have been
182 * allocated via alloc_fd() and not previously used) with
183 * the specified host/gdb fd.
185 static void associate_guestfd(int guestfd
, int hostfd
)
187 GuestFD
*gf
= do_get_guestfd(guestfd
);
190 gf
->type
= use_gdb_syscalls() ? GuestFDGDB
: GuestFDHost
;
195 * Deallocate the specified guest file descriptor. This doesn't
196 * close the host fd, it merely undoes the work of alloc_fd().
198 static void dealloc_guestfd(int guestfd
)
200 GuestFD
*gf
= do_get_guestfd(guestfd
);
203 gf
->type
= GuestFDUnused
;
207 * Given a guest file descriptor, get the associated struct.
208 * If the fd is not valid, return NULL. This is the function
209 * used by the various semihosting calls to validate a handle
211 * Note: calling alloc_guestfd() or dealloc_guestfd() will
212 * invalidate any GuestFD* obtained by calling this function.
214 static GuestFD
*get_guestfd(int guestfd
)
216 GuestFD
*gf
= do_get_guestfd(guestfd
);
218 if (!gf
|| gf
->type
== GuestFDUnused
) {
225 * The semihosting API has no concept of its errno being thread-safe,
226 * as the API design predates SMP CPUs and was intended as a simple
227 * real-hardware set of debug functionality. For QEMU, we make the
228 * errno be per-thread in linux-user mode; in softmmu it is a simple
229 * global, and we assume that the guest takes care of avoiding any races.
231 #ifndef CONFIG_USER_ONLY
232 static target_ulong syscall_err
;
234 #include "exec/softmmu-semi.h"
237 static inline uint32_t set_swi_errno(CPUARMState
*env
, uint32_t code
)
239 if (code
== (uint32_t)-1) {
240 #ifdef CONFIG_USER_ONLY
241 CPUState
*cs
= env_cpu(env
);
242 TaskState
*ts
= cs
->opaque
;
244 ts
->swi_errno
= errno
;
252 static inline uint32_t get_swi_errno(CPUARMState
*env
)
254 #ifdef CONFIG_USER_ONLY
255 CPUState
*cs
= env_cpu(env
);
256 TaskState
*ts
= cs
->opaque
;
258 return ts
->swi_errno
;
264 static target_ulong arm_semi_syscall_len
;
266 static void arm_semi_cb(CPUState
*cs
, target_ulong ret
, target_ulong err
)
268 ARMCPU
*cpu
= ARM_CPU(cs
);
269 CPUARMState
*env
= &cpu
->env
;
270 target_ulong reg0
= is_a64(env
) ? env
->xregs
[0] : env
->regs
[0];
272 if (ret
== (target_ulong
)-1) {
274 set_swi_errno(env
, -1);
277 /* Fixup syscalls that use nonstardard return conventions. */
279 case TARGET_SYS_WRITE
:
280 case TARGET_SYS_READ
:
281 reg0
= arm_semi_syscall_len
- ret
;
283 case TARGET_SYS_SEEK
:
292 env
->xregs
[0] = reg0
;
298 static target_ulong
arm_flen_buf(ARMCPU
*cpu
)
300 /* Return an address in target memory of 64 bytes where the remote
301 * gdb should write its stat struct. (The format of this structure
302 * is defined by GDB's remote protocol and is not target-specific.)
303 * We put this on the guest's stack just below SP.
305 CPUARMState
*env
= &cpu
->env
;
317 static void arm_semi_flen_cb(CPUState
*cs
, target_ulong ret
, target_ulong err
)
319 ARMCPU
*cpu
= ARM_CPU(cs
);
320 CPUARMState
*env
= &cpu
->env
;
321 /* The size is always stored in big-endian order, extract
322 the value. We assume the size always fit in 32 bits. */
324 cpu_memory_rw_debug(cs
, arm_flen_buf(cpu
) + 32, (uint8_t *)&size
, 4, 0);
325 size
= be32_to_cpu(size
);
327 env
->xregs
[0] = size
;
332 set_swi_errno(env
, -1);
335 static int arm_semi_open_guestfd
;
337 static void arm_semi_open_cb(CPUState
*cs
, target_ulong ret
, target_ulong err
)
339 ARMCPU
*cpu
= ARM_CPU(cs
);
340 CPUARMState
*env
= &cpu
->env
;
341 if (ret
== (target_ulong
)-1) {
343 set_swi_errno(env
, -1);
344 dealloc_guestfd(arm_semi_open_guestfd
);
346 associate_guestfd(arm_semi_open_guestfd
, ret
);
347 ret
= arm_semi_open_guestfd
;
357 static target_ulong
arm_gdb_syscall(ARMCPU
*cpu
, gdb_syscall_complete_cb cb
,
358 const char *fmt
, ...)
361 CPUARMState
*env
= &cpu
->env
;
364 gdb_do_syscallv(cb
, fmt
, va
);
368 * FIXME: in softmmu mode, the gdbstub will schedule our callback
369 * to occur, but will not actually call it to complete the syscall
370 * until after this function has returned and we are back in the
371 * CPU main loop. Therefore callers to this function must not
372 * do anything with its return value, because it is not necessarily
373 * the result of the syscall, but could just be the old value of X0.
374 * The only thing safe to do with this is that the callers of
375 * do_arm_semihosting() will write it straight back into X0.
376 * (In linux-user mode, the callback will have happened before
377 * gdb_do_syscallv() returns.)
379 * We should tidy this up so neither this function nor
380 * do_arm_semihosting() return a value, so the mistake of
381 * doing something with the return value is not possible to make.
384 return is_a64(env
) ? env
->xregs
[0] : env
->regs
[0];
388 * Types for functions implementing various semihosting calls
389 * for specific types of guest file descriptor. These must all
390 * do the work and return the required return value for the guest,
391 * setting the guest errno if appropriate.
393 typedef uint32_t sys_closefn(ARMCPU
*cpu
, GuestFD
*gf
);
394 typedef uint32_t sys_writefn(ARMCPU
*cpu
, GuestFD
*gf
,
395 target_ulong buf
, uint32_t len
);
396 typedef uint32_t sys_readfn(ARMCPU
*cpu
, GuestFD
*gf
,
397 target_ulong buf
, uint32_t len
);
398 typedef uint32_t sys_isattyfn(ARMCPU
*cpu
, GuestFD
*gf
);
399 typedef uint32_t sys_seekfn(ARMCPU
*cpu
, GuestFD
*gf
,
400 target_ulong offset
);
401 typedef uint32_t sys_flenfn(ARMCPU
*cpu
, GuestFD
*gf
);
403 static uint32_t host_closefn(ARMCPU
*cpu
, GuestFD
*gf
)
405 CPUARMState
*env
= &cpu
->env
;
408 * Only close the underlying host fd if it's one we opened on behalf
409 * of the guest in SYS_OPEN.
411 if (gf
->hostfd
== STDIN_FILENO
||
412 gf
->hostfd
== STDOUT_FILENO
||
413 gf
->hostfd
== STDERR_FILENO
) {
416 return set_swi_errno(env
, close(gf
->hostfd
));
419 static uint32_t host_writefn(ARMCPU
*cpu
, GuestFD
*gf
,
420 target_ulong buf
, uint32_t len
)
423 CPUARMState
*env
= &cpu
->env
;
424 char *s
= lock_user(VERIFY_READ
, buf
, len
, 1);
426 /* Return bytes not written on error */
429 ret
= set_swi_errno(env
, write(gf
->hostfd
, s
, len
));
430 unlock_user(s
, buf
, 0);
431 if (ret
== (uint32_t)-1) {
434 /* Return bytes not written */
438 static uint32_t host_readfn(ARMCPU
*cpu
, GuestFD
*gf
,
439 target_ulong buf
, uint32_t len
)
442 CPUARMState
*env
= &cpu
->env
;
443 char *s
= lock_user(VERIFY_WRITE
, buf
, len
, 0);
445 /* return bytes not read */
449 ret
= set_swi_errno(env
, read(gf
->hostfd
, s
, len
));
450 } while (ret
== -1 && errno
== EINTR
);
451 unlock_user(s
, buf
, len
);
452 if (ret
== (uint32_t)-1) {
455 /* Return bytes not read */
459 static uint32_t host_isattyfn(ARMCPU
*cpu
, GuestFD
*gf
)
461 return isatty(gf
->hostfd
);
464 static uint32_t host_seekfn(ARMCPU
*cpu
, GuestFD
*gf
, target_ulong offset
)
466 CPUARMState
*env
= &cpu
->env
;
467 uint32_t ret
= set_swi_errno(env
, lseek(gf
->hostfd
, offset
, SEEK_SET
));
468 if (ret
== (uint32_t)-1) {
474 static uint32_t host_flenfn(ARMCPU
*cpu
, GuestFD
*gf
)
476 CPUARMState
*env
= &cpu
->env
;
478 uint32_t ret
= set_swi_errno(env
, fstat(gf
->hostfd
, &buf
));
479 if (ret
== (uint32_t)-1) {
485 static uint32_t gdb_closefn(ARMCPU
*cpu
, GuestFD
*gf
)
487 return arm_gdb_syscall(cpu
, arm_semi_cb
, "close,%x", gf
->hostfd
);
490 static uint32_t gdb_writefn(ARMCPU
*cpu
, GuestFD
*gf
,
491 target_ulong buf
, uint32_t len
)
493 arm_semi_syscall_len
= len
;
494 return arm_gdb_syscall(cpu
, arm_semi_cb
, "write,%x,%x,%x",
495 gf
->hostfd
, buf
, len
);
498 static uint32_t gdb_readfn(ARMCPU
*cpu
, GuestFD
*gf
,
499 target_ulong buf
, uint32_t len
)
501 arm_semi_syscall_len
= len
;
502 return arm_gdb_syscall(cpu
, arm_semi_cb
, "read,%x,%x,%x",
503 gf
->hostfd
, buf
, len
);
506 static uint32_t gdb_isattyfn(ARMCPU
*cpu
, GuestFD
*gf
)
508 return arm_gdb_syscall(cpu
, arm_semi_cb
, "isatty,%x", gf
->hostfd
);
511 static uint32_t gdb_seekfn(ARMCPU
*cpu
, GuestFD
*gf
, target_ulong offset
)
513 return arm_gdb_syscall(cpu
, arm_semi_cb
, "lseek,%x,%x,0",
517 static uint32_t gdb_flenfn(ARMCPU
*cpu
, GuestFD
*gf
)
519 return arm_gdb_syscall(cpu
, arm_semi_flen_cb
, "fstat,%x,%x",
520 gf
->hostfd
, arm_flen_buf(cpu
));
523 #define SHFB_MAGIC_0 0x53
524 #define SHFB_MAGIC_1 0x48
525 #define SHFB_MAGIC_2 0x46
526 #define SHFB_MAGIC_3 0x42
528 /* Feature bits reportable in feature byte 0 */
529 #define SH_EXT_EXIT_EXTENDED (1 << 0)
530 #define SH_EXT_STDOUT_STDERR (1 << 1)
532 static const uint8_t featurefile_data
[] = {
537 SH_EXT_EXIT_EXTENDED
| SH_EXT_STDOUT_STDERR
, /* Feature byte 0 */
540 static void init_featurefile_guestfd(int guestfd
)
542 GuestFD
*gf
= do_get_guestfd(guestfd
);
545 gf
->type
= GuestFDFeatureFile
;
546 gf
->featurefile_offset
= 0;
549 static uint32_t featurefile_closefn(ARMCPU
*cpu
, GuestFD
*gf
)
555 static uint32_t featurefile_writefn(ARMCPU
*cpu
, GuestFD
*gf
,
556 target_ulong buf
, uint32_t len
)
558 /* This fd can never be open for writing */
559 CPUARMState
*env
= &cpu
->env
;
562 return set_swi_errno(env
, -1);
565 static uint32_t featurefile_readfn(ARMCPU
*cpu
, GuestFD
*gf
,
566 target_ulong buf
, uint32_t len
)
569 #ifndef CONFIG_USER_ONLY
570 CPUARMState
*env
= &cpu
->env
;
574 s
= lock_user(VERIFY_WRITE
, buf
, len
, 0);
579 for (i
= 0; i
< len
; i
++) {
580 if (gf
->featurefile_offset
>= sizeof(featurefile_data
)) {
583 s
[i
] = featurefile_data
[gf
->featurefile_offset
];
584 gf
->featurefile_offset
++;
587 unlock_user(s
, buf
, len
);
589 /* Return number of bytes not read */
593 static uint32_t featurefile_isattyfn(ARMCPU
*cpu
, GuestFD
*gf
)
598 static uint32_t featurefile_seekfn(ARMCPU
*cpu
, GuestFD
*gf
,
601 gf
->featurefile_offset
= offset
;
605 static uint32_t featurefile_flenfn(ARMCPU
*cpu
, GuestFD
*gf
)
607 return sizeof(featurefile_data
);
610 typedef struct GuestFDFunctions
{
611 sys_closefn
*closefn
;
612 sys_writefn
*writefn
;
614 sys_isattyfn
*isattyfn
;
619 static const GuestFDFunctions guestfd_fns
[] = {
621 .closefn
= host_closefn
,
622 .writefn
= host_writefn
,
623 .readfn
= host_readfn
,
624 .isattyfn
= host_isattyfn
,
625 .seekfn
= host_seekfn
,
626 .flenfn
= host_flenfn
,
629 .closefn
= gdb_closefn
,
630 .writefn
= gdb_writefn
,
631 .readfn
= gdb_readfn
,
632 .isattyfn
= gdb_isattyfn
,
633 .seekfn
= gdb_seekfn
,
634 .flenfn
= gdb_flenfn
,
636 [GuestFDFeatureFile
] = {
637 .closefn
= featurefile_closefn
,
638 .writefn
= featurefile_writefn
,
639 .readfn
= featurefile_readfn
,
640 .isattyfn
= featurefile_isattyfn
,
641 .seekfn
= featurefile_seekfn
,
642 .flenfn
= featurefile_flenfn
,
646 /* Read the input value from the argument block; fail the semihosting
647 * call if the memory read fails.
649 #define GET_ARG(n) do { \
651 if (get_user_u64(arg ## n, args + (n) * 8)) { \
653 return set_swi_errno(env, -1); \
656 if (get_user_u32(arg ## n, args + (n) * 4)) { \
658 return set_swi_errno(env, -1); \
663 #define SET_ARG(n, val) \
665 put_user_u64(val, args + (n) * 8) : \
666 put_user_u32(val, args + (n) * 4))
669 * Do a semihosting call.
671 * The specification always says that the "return register" either
672 * returns a specific value or is corrupted, so we don't need to
673 * report to our caller whether we are returning a value or trying to
674 * leave the register unchanged. We use 0xdeadbeef as the return value
675 * when there isn't a defined return value for the call.
677 target_ulong
do_arm_semihosting(CPUARMState
*env
)
679 ARMCPU
*cpu
= env_archcpu(env
);
680 CPUState
*cs
= env_cpu(env
);
682 target_ulong arg0
, arg1
, arg2
, arg3
;
690 /* Note that the syscall number is in W0, not X0 */
691 nr
= env
->xregs
[0] & 0xffffffffU
;
692 args
= env
->xregs
[1];
699 case TARGET_SYS_OPEN
:
706 s
= lock_user_string(arg0
);
709 return set_swi_errno(env
, -1);
712 unlock_user(s
, arg0
, 0);
714 return set_swi_errno(env
, -1);
717 guestfd
= alloc_guestfd();
719 unlock_user(s
, arg0
, 0);
721 return set_swi_errno(env
, -1);
724 if (strcmp(s
, ":tt") == 0) {
728 * We implement SH_EXT_STDOUT_STDERR, so:
729 * open for read == stdin
730 * open for write == stdout
731 * open for append == stderr
734 result_fileno
= STDIN_FILENO
;
735 } else if (arg1
< 8) {
736 result_fileno
= STDOUT_FILENO
;
738 result_fileno
= STDERR_FILENO
;
740 associate_guestfd(guestfd
, result_fileno
);
741 unlock_user(s
, arg0
, 0);
744 if (strcmp(s
, ":semihosting-features") == 0) {
745 unlock_user(s
, arg0
, 0);
746 /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
747 if (arg1
!= 0 && arg1
!= 1) {
748 dealloc_guestfd(guestfd
);
750 return set_swi_errno(env
, -1);
752 init_featurefile_guestfd(guestfd
);
756 if (use_gdb_syscalls()) {
757 arm_semi_open_guestfd
= guestfd
;
758 ret
= arm_gdb_syscall(cpu
, arm_semi_open_cb
, "open,%s,%x,1a4", arg0
,
759 (int)arg2
+ 1, gdb_open_modeflags
[arg1
]);
761 ret
= set_swi_errno(env
, open(s
, open_modeflags
[arg1
], 0644));
762 if (ret
== (uint32_t)-1) {
763 dealloc_guestfd(guestfd
);
765 associate_guestfd(guestfd
, ret
);
769 unlock_user(s
, arg0
, 0);
772 case TARGET_SYS_CLOSE
:
775 gf
= get_guestfd(arg0
);
778 return set_swi_errno(env
, -1);
781 ret
= guestfd_fns
[gf
->type
].closefn(cpu
, gf
);
782 dealloc_guestfd(arg0
);
784 case TARGET_SYS_WRITEC
:
785 qemu_semihosting_console_outc(env
, args
);
787 case TARGET_SYS_WRITE0
:
788 return qemu_semihosting_console_outs(env
, args
);
789 case TARGET_SYS_WRITE
:
795 gf
= get_guestfd(arg0
);
798 return set_swi_errno(env
, -1);
801 return guestfd_fns
[gf
->type
].writefn(cpu
, gf
, arg1
, len
);
802 case TARGET_SYS_READ
:
808 gf
= get_guestfd(arg0
);
811 return set_swi_errno(env
, -1);
814 return guestfd_fns
[gf
->type
].readfn(cpu
, gf
, arg1
, len
);
815 case TARGET_SYS_READC
:
816 return qemu_semihosting_console_inc(env
);
817 case TARGET_SYS_ISTTY
:
820 gf
= get_guestfd(arg0
);
823 return set_swi_errno(env
, -1);
826 return guestfd_fns
[gf
->type
].isattyfn(cpu
, gf
);
827 case TARGET_SYS_SEEK
:
831 gf
= get_guestfd(arg0
);
834 return set_swi_errno(env
, -1);
837 return guestfd_fns
[gf
->type
].seekfn(cpu
, gf
, arg1
);
838 case TARGET_SYS_FLEN
:
841 gf
= get_guestfd(arg0
);
844 return set_swi_errno(env
, -1);
847 return guestfd_fns
[gf
->type
].flenfn(cpu
, gf
);
848 case TARGET_SYS_TMPNAM
:
849 qemu_log_mask(LOG_UNIMP
, "%s: SYS_TMPNAM not implemented", __func__
);
851 case TARGET_SYS_REMOVE
:
854 if (use_gdb_syscalls()) {
855 ret
= arm_gdb_syscall(cpu
, arm_semi_cb
, "unlink,%s",
856 arg0
, (int)arg1
+ 1);
858 s
= lock_user_string(arg0
);
861 return set_swi_errno(env
, -1);
863 ret
= set_swi_errno(env
, remove(s
));
864 unlock_user(s
, arg0
, 0);
867 case TARGET_SYS_RENAME
:
872 if (use_gdb_syscalls()) {
873 return arm_gdb_syscall(cpu
, arm_semi_cb
, "rename,%s,%s",
874 arg0
, (int)arg1
+ 1, arg2
, (int)arg3
+ 1);
877 s
= lock_user_string(arg0
);
878 s2
= lock_user_string(arg2
);
881 ret
= set_swi_errno(env
, -1);
883 ret
= set_swi_errno(env
, rename(s
, s2
));
886 unlock_user(s2
, arg2
, 0);
888 unlock_user(s
, arg0
, 0);
891 case TARGET_SYS_CLOCK
:
892 return clock() / (CLOCKS_PER_SEC
/ 100);
893 case TARGET_SYS_TIME
:
894 return set_swi_errno(env
, time(NULL
));
895 case TARGET_SYS_SYSTEM
:
898 if (use_gdb_syscalls()) {
899 return arm_gdb_syscall(cpu
, arm_semi_cb
, "system,%s",
900 arg0
, (int)arg1
+ 1);
902 s
= lock_user_string(arg0
);
905 return set_swi_errno(env
, -1);
907 ret
= set_swi_errno(env
, system(s
));
908 unlock_user(s
, arg0
, 0);
911 case TARGET_SYS_ERRNO
:
912 return get_swi_errno(env
);
913 case TARGET_SYS_GET_CMDLINE
:
915 /* Build a command-line from the original argv.
918 * * arg0, pointer to a buffer of at least the size
920 * * arg1, size of the buffer pointed to by arg0 in
924 * * arg0, pointer to null-terminated string of the
926 * * arg1, length of the string pointed to by arg0.
933 #if !defined(CONFIG_USER_ONLY)
936 TaskState
*ts
= cs
->opaque
;
941 /* Compute the size of the output string. */
942 #if !defined(CONFIG_USER_ONLY)
943 cmdline
= semihosting_get_cmdline();
944 if (cmdline
== NULL
) {
945 cmdline
= ""; /* Default to an empty line. */
947 output_size
= strlen(cmdline
) + 1; /* Count terminating 0. */
951 output_size
= ts
->info
->arg_end
- ts
->info
->arg_start
;
954 * We special-case the "empty command line" case (argc==0).
955 * Just provide the terminating 0.
961 if (output_size
> input_size
) {
962 /* Not enough space to store command-line arguments. */
964 return set_swi_errno(env
, -1);
967 /* Adjust the command-line length. */
968 if (SET_ARG(1, output_size
- 1)) {
969 /* Couldn't write back to argument block */
971 return set_swi_errno(env
, -1);
974 /* Lock the buffer on the ARM side. */
975 output_buffer
= lock_user(VERIFY_WRITE
, arg0
, output_size
, 0);
976 if (!output_buffer
) {
978 return set_swi_errno(env
, -1);
981 /* Copy the command-line arguments. */
982 #if !defined(CONFIG_USER_ONLY)
983 pstrcpy(output_buffer
, output_size
, cmdline
);
985 if (output_size
== 1) {
986 /* Empty command-line. */
987 output_buffer
[0] = '\0';
991 if (copy_from_user(output_buffer
, ts
->info
->arg_start
,
994 status
= set_swi_errno(env
, -1);
998 /* Separate arguments by white spaces. */
999 for (i
= 0; i
< output_size
- 1; i
++) {
1000 if (output_buffer
[i
] == 0) {
1001 output_buffer
[i
] = ' ';
1006 /* Unlock the buffer on the ARM side. */
1007 unlock_user(output_buffer
, arg0
, output_size
);
1011 case TARGET_SYS_HEAPINFO
:
1013 target_ulong retvals
[4];
1016 #ifdef CONFIG_USER_ONLY
1017 TaskState
*ts
= cs
->opaque
;
1019 const struct arm_boot_info
*info
= env
->boot_info
;
1020 target_ulong rambase
= info
->loader_start
;
1025 #ifdef CONFIG_USER_ONLY
1027 * Some C libraries assume the heap immediately follows .bss, so
1028 * allocate it using sbrk.
1030 if (!ts
->heap_limit
) {
1033 ts
->heap_base
= do_brk(0);
1034 limit
= ts
->heap_base
+ ARM_ANGEL_HEAP_SIZE
;
1035 /* Try a big heap, and reduce the size if that fails. */
1037 ret
= do_brk(limit
);
1041 limit
= (ts
->heap_base
>> 1) + (limit
>> 1);
1043 ts
->heap_limit
= limit
;
1046 retvals
[0] = ts
->heap_base
;
1047 retvals
[1] = ts
->heap_limit
;
1048 retvals
[2] = ts
->stack_base
;
1049 retvals
[3] = 0; /* Stack limit. */
1052 /* TODO: Make this use the limit of the loaded application. */
1053 retvals
[0] = rambase
+ limit
/ 2;
1054 retvals
[1] = rambase
+ limit
;
1055 retvals
[2] = rambase
+ limit
; /* Stack base */
1056 retvals
[3] = rambase
; /* Stack limit. */
1059 for (i
= 0; i
< ARRAY_SIZE(retvals
); i
++) {
1063 fail
= put_user_u64(retvals
[i
], arg0
+ i
* 8);
1065 fail
= put_user_u32(retvals
[i
], arg0
+ i
* 4);
1069 /* Couldn't write back to argument block */
1071 return set_swi_errno(env
, -1);
1076 case TARGET_SYS_EXIT
:
1077 case TARGET_SYS_EXIT_EXTENDED
:
1078 if (nr
== TARGET_SYS_EXIT_EXTENDED
|| is_a64(env
)) {
1080 * The A64 version of SYS_EXIT takes a parameter block,
1081 * so the application-exit type can return a subcode which
1082 * is the exit status code from the application.
1083 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1084 * which allows A32/T32 guests to also provide a status code.
1089 if (arg0
== ADP_Stopped_ApplicationExit
) {
1096 * The A32/T32 version of SYS_EXIT specifies only
1097 * Stopped_ApplicationExit as normal exit, but does not
1098 * allow the guest to specify the exit status code.
1099 * Everything else is considered an error.
1101 ret
= (args
== ADP_Stopped_ApplicationExit
) ? 0 : 1;
1105 case TARGET_SYS_SYNCCACHE
:
1107 * Clean the D-cache and invalidate the I-cache for the specified
1108 * virtual address range. This is a nop for us since we don't
1109 * implement caches. This is only present on A64.
1114 /* fall through -- invalid for A32/T32 */
1116 fprintf(stderr
, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr
);
1117 cpu_dump_state(cs
, stderr
, 0);