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"
35 #include "semihosting/semihost.h"
36 #include "semihosting/console.h"
37 #include "semihosting/common-semi.h"
38 #include "semihosting/guestfd.h"
39 #include "qemu/timer.h"
40 #include "exec/gdbstub.h"
42 #ifdef CONFIG_USER_ONLY
45 #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
47 #include "qemu/cutils.h"
48 #include "hw/loader.h"
50 #include "hw/arm/boot.h"
52 #include "hw/boards.h"
55 #define TARGET_SYS_OPEN 0x01
56 #define TARGET_SYS_CLOSE 0x02
57 #define TARGET_SYS_WRITEC 0x03
58 #define TARGET_SYS_WRITE0 0x04
59 #define TARGET_SYS_WRITE 0x05
60 #define TARGET_SYS_READ 0x06
61 #define TARGET_SYS_READC 0x07
62 #define TARGET_SYS_ISERROR 0x08
63 #define TARGET_SYS_ISTTY 0x09
64 #define TARGET_SYS_SEEK 0x0a
65 #define TARGET_SYS_FLEN 0x0c
66 #define TARGET_SYS_TMPNAM 0x0d
67 #define TARGET_SYS_REMOVE 0x0e
68 #define TARGET_SYS_RENAME 0x0f
69 #define TARGET_SYS_CLOCK 0x10
70 #define TARGET_SYS_TIME 0x11
71 #define TARGET_SYS_SYSTEM 0x12
72 #define TARGET_SYS_ERRNO 0x13
73 #define TARGET_SYS_GET_CMDLINE 0x15
74 #define TARGET_SYS_HEAPINFO 0x16
75 #define TARGET_SYS_EXIT 0x18
76 #define TARGET_SYS_SYNCCACHE 0x19
77 #define TARGET_SYS_EXIT_EXTENDED 0x20
78 #define TARGET_SYS_ELAPSED 0x30
79 #define TARGET_SYS_TICKFREQ 0x31
81 /* ADP_Stopped_ApplicationExit is used for exit(0),
82 * anything else is implemented as exit(1) */
83 #define ADP_Stopped_ApplicationExit (0x20026)
89 #define GDB_O_RDONLY 0x000
90 #define GDB_O_WRONLY 0x001
91 #define GDB_O_RDWR 0x002
92 #define GDB_O_APPEND 0x008
93 #define GDB_O_CREAT 0x200
94 #define GDB_O_TRUNC 0x400
96 static int gdb_open_modeflags
[12] = {
101 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_TRUNC
,
102 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_TRUNC
,
103 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_TRUNC
,
104 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_TRUNC
,
105 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_APPEND
,
106 GDB_O_WRONLY
| GDB_O_CREAT
| GDB_O_APPEND
,
107 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_APPEND
,
108 GDB_O_RDWR
| GDB_O_CREAT
| GDB_O_APPEND
,
111 static int open_modeflags
[12] = {
116 O_WRONLY
| O_CREAT
| O_TRUNC
,
117 O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
,
118 O_RDWR
| O_CREAT
| O_TRUNC
,
119 O_RDWR
| O_CREAT
| O_TRUNC
| O_BINARY
,
120 O_WRONLY
| O_CREAT
| O_APPEND
,
121 O_WRONLY
| O_CREAT
| O_APPEND
| O_BINARY
,
122 O_RDWR
| O_CREAT
| O_APPEND
,
123 O_RDWR
| O_CREAT
| O_APPEND
| O_BINARY
126 #ifndef CONFIG_USER_ONLY
129 * common_semi_find_bases: find information about ram and heap base
131 * This function attempts to provide meaningful numbers for RAM and
132 * HEAP base addresses. The rambase is simply the lowest addressable
133 * RAM position. For the heapbase we ask the loader to scan the
134 * address space and the largest available gap by querying the "ROM"
137 * Returns: a structure with the numbers we need.
140 typedef struct LayoutInfo
{
141 target_ulong rambase
;
147 static bool find_ram_cb(Int128 start
, Int128 len
, const MemoryRegion
*mr
,
148 hwaddr offset_in_region
, void *opaque
)
150 LayoutInfo
*info
= (LayoutInfo
*) opaque
;
151 uint64_t size
= int128_get64(len
);
153 if (!mr
->ram
|| mr
->readonly
) {
157 if (size
> info
->ramsize
) {
158 info
->rambase
= int128_get64(start
);
159 info
->ramsize
= size
;
162 /* search exhaustively for largest RAM */
166 static LayoutInfo
common_semi_find_bases(CPUState
*cs
)
169 LayoutInfo info
= { 0, 0, 0, 0 };
171 RCU_READ_LOCK_GUARD();
173 fv
= address_space_to_flatview(cs
->as
);
174 flatview_for_each_range(fv
, find_ram_cb
, &info
);
177 * If we have found the RAM lets iterate through the ROM blobs to
178 * work out the best place for the remainder of RAM and split it
179 * equally between stack and heap.
181 if (info
.rambase
|| info
.ramsize
> 0) {
182 RomGap gap
= rom_find_largest_gap_between(info
.rambase
, info
.ramsize
);
183 info
.heapbase
= gap
.base
;
184 info
.heaplimit
= gap
.base
+ gap
.size
;
193 static inline target_ulong
194 common_semi_arg(CPUState
*cs
, int argno
)
196 ARMCPU
*cpu
= ARM_CPU(cs
);
197 CPUARMState
*env
= &cpu
->env
;
199 return env
->xregs
[argno
];
201 return env
->regs
[argno
];
206 common_semi_set_ret(CPUState
*cs
, target_ulong ret
)
208 ARMCPU
*cpu
= ARM_CPU(cs
);
209 CPUARMState
*env
= &cpu
->env
;
218 common_semi_sys_exit_extended(CPUState
*cs
, int nr
)
220 return (nr
== TARGET_SYS_EXIT_EXTENDED
|| is_a64(cs
->env_ptr
));
223 #endif /* TARGET_ARM */
226 static inline target_ulong
227 common_semi_arg(CPUState
*cs
, int argno
)
229 RISCVCPU
*cpu
= RISCV_CPU(cs
);
230 CPURISCVState
*env
= &cpu
->env
;
231 return env
->gpr
[xA0
+ argno
];
235 common_semi_set_ret(CPUState
*cs
, target_ulong ret
)
237 RISCVCPU
*cpu
= RISCV_CPU(cs
);
238 CPURISCVState
*env
= &cpu
->env
;
243 common_semi_sys_exit_extended(CPUState
*cs
, int nr
)
245 return (nr
== TARGET_SYS_EXIT_EXTENDED
|| sizeof(target_ulong
) == 8);
251 * The semihosting API has no concept of its errno being thread-safe,
252 * as the API design predates SMP CPUs and was intended as a simple
253 * real-hardware set of debug functionality. For QEMU, we make the
254 * errno be per-thread in linux-user mode; in softmmu it is a simple
255 * global, and we assume that the guest takes care of avoiding any races.
257 #ifndef CONFIG_USER_ONLY
258 static target_ulong syscall_err
;
260 #include "semihosting/softmmu-uaccess.h"
263 static inline uint32_t get_swi_errno(CPUState
*cs
)
265 #ifdef CONFIG_USER_ONLY
266 TaskState
*ts
= cs
->opaque
;
268 return ts
->swi_errno
;
274 static target_ulong common_semi_syscall_len
;
276 static void common_semi_cb(CPUState
*cs
, target_ulong ret
, target_ulong err
)
279 #ifdef CONFIG_USER_ONLY
280 TaskState
*ts
= cs
->opaque
;
286 /* Fixup syscalls that use nonstardard return conventions. */
287 target_ulong reg0
= common_semi_arg(cs
, 0);
289 case TARGET_SYS_WRITE
:
290 case TARGET_SYS_READ
:
291 ret
= common_semi_syscall_len
- ret
;
293 case TARGET_SYS_SEEK
:
300 common_semi_set_ret(cs
, ret
);
303 static target_ulong
common_semi_flen_buf(CPUState
*cs
)
307 /* Return an address in target memory of 64 bytes where the remote
308 * gdb should write its stat struct. (The format of this structure
309 * is defined by GDB's remote protocol and is not target-specific.)
310 * We put this on the guest's stack just below SP.
312 ARMCPU
*cpu
= ARM_CPU(cs
);
313 CPUARMState
*env
= &cpu
->env
;
322 RISCVCPU
*cpu
= RISCV_CPU(cs
);
323 CPURISCVState
*env
= &cpu
->env
;
332 common_semi_flen_cb(CPUState
*cs
, target_ulong ret
, target_ulong err
)
336 * The size is always stored in big-endian order, extract
337 * the value. We assume the size always fit in 32 bits.
340 cpu_memory_rw_debug(cs
, common_semi_flen_buf(cs
) + 32,
341 (uint8_t *)&size
, 4, 0);
342 ret
= be32_to_cpu(size
);
344 common_semi_cb(cs
, ret
, err
);
347 static int common_semi_open_guestfd
;
350 common_semi_open_cb(CPUState
*cs
, target_ulong ret
, target_ulong err
)
353 dealloc_guestfd(common_semi_open_guestfd
);
355 associate_guestfd(common_semi_open_guestfd
, ret
);
356 ret
= common_semi_open_guestfd
;
358 common_semi_cb(cs
, ret
, err
);
362 * Types for functions implementing various semihosting calls
363 * for specific types of guest file descriptor. These must all
364 * do the work and return the required return value to the guest
365 * via common_semi_cb.
367 typedef void sys_closefn(CPUState
*cs
, GuestFD
*gf
);
368 typedef void sys_writefn(CPUState
*cs
, GuestFD
*gf
,
369 target_ulong buf
, uint32_t len
);
370 typedef void sys_readfn(CPUState
*cs
, GuestFD
*gf
,
371 target_ulong buf
, uint32_t len
);
372 typedef void sys_isattyfn(CPUState
*cs
, GuestFD
*gf
);
373 typedef void sys_seekfn(CPUState
*cs
, GuestFD
*gf
, target_ulong offset
);
374 typedef void sys_flenfn(CPUState
*cs
, GuestFD
*gf
);
376 static void host_closefn(CPUState
*cs
, GuestFD
*gf
)
380 * Only close the underlying host fd if it's one we opened on behalf
381 * of the guest in SYS_OPEN.
383 if (gf
->hostfd
== STDIN_FILENO
||
384 gf
->hostfd
== STDOUT_FILENO
||
385 gf
->hostfd
== STDERR_FILENO
) {
388 ret
= close(gf
->hostfd
);
390 common_semi_cb(cs
, ret
, ret
? errno
: 0);
393 static void host_writefn(CPUState
*cs
, GuestFD
*gf
,
394 target_ulong buf
, uint32_t len
)
396 CPUArchState
*env
= cs
->env_ptr
;
398 char *s
= lock_user(VERIFY_READ
, buf
, len
, 1);
399 (void) env
; /* Used in arm softmmu lock_user implicitly */
401 ret
= write(gf
->hostfd
, s
, len
);
402 unlock_user(s
, buf
, 0);
403 if (ret
== (uint32_t)-1) {
407 /* Return bytes not written, on error as well. */
408 common_semi_cb(cs
, len
- ret
, 0);
411 static void host_readfn(CPUState
*cs
, GuestFD
*gf
,
412 target_ulong buf
, uint32_t len
)
414 CPUArchState
*env
= cs
->env_ptr
;
416 char *s
= lock_user(VERIFY_WRITE
, buf
, len
, 0);
417 (void) env
; /* Used in arm softmmu lock_user implicitly */
420 ret
= read(gf
->hostfd
, s
, len
);
421 } while (ret
== -1 && errno
== EINTR
);
422 unlock_user(s
, buf
, len
);
423 if (ret
== (uint32_t)-1) {
427 /* Return bytes not read, on error as well. */
428 common_semi_cb(cs
, len
- ret
, 0);
431 static void host_isattyfn(CPUState
*cs
, GuestFD
*gf
)
433 common_semi_cb(cs
, isatty(gf
->hostfd
), 0);
436 static void host_seekfn(CPUState
*cs
, GuestFD
*gf
, target_ulong offset
)
438 off_t ret
= lseek(gf
->hostfd
, offset
, SEEK_SET
);
439 common_semi_cb(cs
, ret
, ret
== -1 ? errno
: 0);
442 static void host_flenfn(CPUState
*cs
, GuestFD
*gf
)
446 if (fstat(gf
->hostfd
, &buf
)) {
447 common_semi_cb(cs
, -1, errno
);
449 common_semi_cb(cs
, buf
.st_size
, 0);
453 static void gdb_closefn(CPUState
*cs
, GuestFD
*gf
)
455 gdb_do_syscall(common_semi_cb
, "close,%x", gf
->hostfd
);
458 static void gdb_writefn(CPUState
*cs
, GuestFD
*gf
,
459 target_ulong buf
, uint32_t len
)
461 common_semi_syscall_len
= len
;
462 gdb_do_syscall(common_semi_cb
, "write,%x,%x,%x", gf
->hostfd
, buf
, len
);
465 static void gdb_readfn(CPUState
*cs
, GuestFD
*gf
,
466 target_ulong buf
, uint32_t len
)
468 common_semi_syscall_len
= len
;
469 gdb_do_syscall(common_semi_cb
, "read,%x,%x,%x", gf
->hostfd
, buf
, len
);
472 static void gdb_isattyfn(CPUState
*cs
, GuestFD
*gf
)
474 gdb_do_syscall(common_semi_cb
, "isatty,%x", gf
->hostfd
);
477 static void gdb_seekfn(CPUState
*cs
, GuestFD
*gf
, target_ulong offset
)
479 gdb_do_syscall(common_semi_cb
, "lseek,%x,%x,0", gf
->hostfd
, offset
);
482 static void gdb_flenfn(CPUState
*cs
, GuestFD
*gf
)
484 gdb_do_syscall(common_semi_flen_cb
, "fstat,%x,%x",
485 gf
->hostfd
, common_semi_flen_buf(cs
));
488 #define SHFB_MAGIC_0 0x53
489 #define SHFB_MAGIC_1 0x48
490 #define SHFB_MAGIC_2 0x46
491 #define SHFB_MAGIC_3 0x42
493 /* Feature bits reportable in feature byte 0 */
494 #define SH_EXT_EXIT_EXTENDED (1 << 0)
495 #define SH_EXT_STDOUT_STDERR (1 << 1)
497 static const uint8_t featurefile_data
[] = {
502 SH_EXT_EXIT_EXTENDED
| SH_EXT_STDOUT_STDERR
, /* Feature byte 0 */
505 static void staticfile_closefn(CPUState
*cs
, GuestFD
*gf
)
508 common_semi_cb(cs
, 0, 0);
511 static void staticfile_writefn(CPUState
*cs
, GuestFD
*gf
,
512 target_ulong buf
, uint32_t len
)
514 /* This fd can never be open for writing */
515 common_semi_cb(cs
, -1, EBADF
);
518 static void staticfile_readfn(CPUState
*cs
, GuestFD
*gf
,
519 target_ulong buf
, uint32_t len
)
521 CPUArchState
*env
= cs
->env_ptr
;
525 (void) env
; /* Used in arm softmmu lock_user implicitly */
526 s
= lock_user(VERIFY_WRITE
, buf
, len
, 0);
528 for (i
= 0; i
< len
; i
++) {
529 if (gf
->staticfile
.off
>= gf
->staticfile
.len
) {
532 s
[i
] = gf
->staticfile
.data
[gf
->staticfile
.off
];
533 gf
->staticfile
.off
++;
535 unlock_user(s
, buf
, len
);
538 /* Return number of bytes not read */
539 common_semi_cb(cs
, len
- i
, 0);
542 static void staticfile_isattyfn(CPUState
*cs
, GuestFD
*gf
)
544 common_semi_cb(cs
, 0, 0);
547 static void staticfile_seekfn(CPUState
*cs
, GuestFD
*gf
, target_ulong offset
)
549 gf
->staticfile
.off
= offset
;
550 common_semi_cb(cs
, 0, 0);
553 static void staticfile_flenfn(CPUState
*cs
, GuestFD
*gf
)
555 common_semi_cb(cs
, gf
->staticfile
.len
, 0);
558 typedef struct GuestFDFunctions
{
559 sys_closefn
*closefn
;
560 sys_writefn
*writefn
;
562 sys_isattyfn
*isattyfn
;
567 static const GuestFDFunctions guestfd_fns
[] = {
569 .closefn
= host_closefn
,
570 .writefn
= host_writefn
,
571 .readfn
= host_readfn
,
572 .isattyfn
= host_isattyfn
,
573 .seekfn
= host_seekfn
,
574 .flenfn
= host_flenfn
,
577 .closefn
= gdb_closefn
,
578 .writefn
= gdb_writefn
,
579 .readfn
= gdb_readfn
,
580 .isattyfn
= gdb_isattyfn
,
581 .seekfn
= gdb_seekfn
,
582 .flenfn
= gdb_flenfn
,
585 .closefn
= staticfile_closefn
,
586 .writefn
= staticfile_writefn
,
587 .readfn
= staticfile_readfn
,
588 .isattyfn
= staticfile_isattyfn
,
589 .seekfn
= staticfile_seekfn
,
590 .flenfn
= staticfile_flenfn
,
595 * Read the input value from the argument block; fail the semihosting
596 * call if the memory read fails. Eventually we could use a generic
597 * CPUState helper function here.
599 static inline bool is_64bit_semihosting(CPUArchState
*env
)
601 #if defined(TARGET_ARM)
603 #elif defined(TARGET_RISCV)
604 return riscv_cpu_mxl(env
) != MXL_RV32
;
606 #error un-handled architecture
611 #define GET_ARG(n) do { \
612 if (is_64bit_semihosting(env)) { \
613 if (get_user_u64(arg ## n, args + (n) * 8)) { \
617 if (get_user_u32(arg ## n, args + (n) * 4)) { \
623 #define SET_ARG(n, val) \
624 (is_64bit_semihosting(env) ? \
625 put_user_u64(val, args + (n) * 8) : \
626 put_user_u32(val, args + (n) * 4))
630 * Do a semihosting call.
632 * The specification always says that the "return register" either
633 * returns a specific value or is corrupted, so we don't need to
634 * report to our caller whether we are returning a value or trying to
635 * leave the register unchanged. We use 0xdeadbeef as the return value
636 * when there isn't a defined return value for the call.
638 void do_common_semihosting(CPUState
*cs
)
640 CPUArchState
*env
= cs
->env_ptr
;
642 target_ulong arg0
, arg1
, arg2
, arg3
;
651 (void) env
; /* Used implicitly by arm lock_user macro */
652 nr
= common_semi_arg(cs
, 0) & 0xffffffffU
;
653 args
= common_semi_arg(cs
, 1);
656 case TARGET_SYS_OPEN
:
664 s
= lock_user_string(arg0
);
669 unlock_user(s
, arg0
, 0);
670 common_semi_cb(cs
, -1, EINVAL
);
674 if (strcmp(s
, ":tt") == 0) {
676 * We implement SH_EXT_STDOUT_STDERR, so:
677 * open for read == stdin
678 * open for write == stdout
679 * open for append == stderr
682 hostfd
= STDIN_FILENO
;
683 } else if (arg1
< 8) {
684 hostfd
= STDOUT_FILENO
;
686 hostfd
= STDERR_FILENO
;
688 ret
= alloc_guestfd();
689 associate_guestfd(ret
, hostfd
);
690 } else if (strcmp(s
, ":semihosting-features") == 0) {
691 /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
692 if (arg1
!= 0 && arg1
!= 1) {
696 ret
= alloc_guestfd();
697 staticfile_guestfd(ret
, featurefile_data
,
698 sizeof(featurefile_data
));
700 } else if (use_gdb_syscalls()) {
701 unlock_user(s
, arg0
, 0);
702 common_semi_open_guestfd
= alloc_guestfd();
703 gdb_do_syscall(common_semi_open_cb
,
704 "open,%s,%x,1a4", arg0
, (int)arg2
+ 1,
705 gdb_open_modeflags
[arg1
]);
708 hostfd
= open(s
, open_modeflags
[arg1
], 0644);
713 ret
= alloc_guestfd();
714 associate_guestfd(ret
, hostfd
);
717 unlock_user(s
, arg0
, 0);
718 common_semi_cb(cs
, ret
, err
);
722 case TARGET_SYS_CLOSE
:
725 gf
= get_guestfd(arg0
);
729 guestfd_fns
[gf
->type
].closefn(cs
, gf
);
730 dealloc_guestfd(arg0
);
733 case TARGET_SYS_WRITEC
:
734 qemu_semihosting_console_outc(cs
->env_ptr
, args
);
735 common_semi_set_ret(cs
, 0xdeadbeef);
738 case TARGET_SYS_WRITE0
:
739 ret
= qemu_semihosting_console_outs(cs
->env_ptr
, args
);
740 common_semi_set_ret(cs
, ret
);
743 case TARGET_SYS_WRITE
:
749 gf
= get_guestfd(arg0
);
753 guestfd_fns
[gf
->type
].writefn(cs
, gf
, arg1
, len
);
756 case TARGET_SYS_READ
:
762 gf
= get_guestfd(arg0
);
766 guestfd_fns
[gf
->type
].readfn(cs
, gf
, arg1
, len
);
769 case TARGET_SYS_READC
:
770 ret
= qemu_semihosting_console_inc(cs
->env_ptr
);
771 common_semi_set_ret(cs
, ret
);
774 case TARGET_SYS_ISERROR
:
776 common_semi_set_ret(cs
, (target_long
)arg0
< 0);
779 case TARGET_SYS_ISTTY
:
782 gf
= get_guestfd(arg0
);
786 guestfd_fns
[gf
->type
].isattyfn(cs
, gf
);
789 case TARGET_SYS_SEEK
:
793 gf
= get_guestfd(arg0
);
797 guestfd_fns
[gf
->type
].seekfn(cs
, gf
, arg1
);
800 case TARGET_SYS_FLEN
:
803 gf
= get_guestfd(arg0
);
807 guestfd_fns
[gf
->type
].flenfn(cs
, gf
);
810 case TARGET_SYS_TMPNAM
:
818 len
= asprintf(&s
, "/tmp/qemu-%x%02x", getpid(), (int)arg1
& 0xff);
819 /* Make sure there's enough space in the buffer */
820 if (len
< 0 || len
>= arg2
) {
821 common_semi_set_ret(cs
, -1);
824 p
= lock_user(VERIFY_WRITE
, arg0
, len
, 0);
828 memcpy(p
, s
, len
+ 1);
829 unlock_user(p
, arg0
, len
);
831 common_semi_set_ret(cs
, 0);
835 case TARGET_SYS_REMOVE
:
838 if (use_gdb_syscalls()) {
839 gdb_do_syscall(common_semi_cb
, "unlink,%s",
840 arg0
, (int)arg1
+ 1);
843 s
= lock_user_string(arg0
);
848 unlock_user(s
, arg0
, 0);
849 common_semi_cb(cs
, ret
, ret
? errno
: 0);
852 case TARGET_SYS_RENAME
:
857 if (use_gdb_syscalls()) {
858 gdb_do_syscall(common_semi_cb
, "rename,%s,%s",
859 arg0
, (int)arg1
+ 1, arg2
, (int)arg3
+ 1);
863 s
= lock_user_string(arg0
);
867 s2
= lock_user_string(arg2
);
869 unlock_user(s
, arg0
, 0);
873 unlock_user(s2
, arg2
, 0);
874 unlock_user(s
, arg0
, 0);
875 common_semi_cb(cs
, ret
, ret
? errno
: 0);
879 case TARGET_SYS_CLOCK
:
880 common_semi_set_ret(cs
, clock() / (CLOCKS_PER_SEC
/ 100));
883 case TARGET_SYS_TIME
:
885 common_semi_cb(cs
, ul_ret
, ul_ret
== -1 ? errno
: 0);
888 case TARGET_SYS_SYSTEM
:
891 if (use_gdb_syscalls()) {
892 gdb_do_syscall(common_semi_cb
, "system,%s", arg0
, (int)arg1
+ 1);
895 s
= lock_user_string(arg0
);
900 unlock_user(s
, arg0
, 0);
901 common_semi_cb(cs
, ret
, ret
== -1 ? errno
: 0);
904 case TARGET_SYS_ERRNO
:
905 common_semi_set_ret(cs
, get_swi_errno(cs
));
908 case TARGET_SYS_GET_CMDLINE
:
910 /* Build a command-line from the original argv.
913 * * arg0, pointer to a buffer of at least the size
915 * * arg1, size of the buffer pointed to by arg0 in
919 * * arg0, pointer to null-terminated string of the
921 * * arg1, length of the string pointed to by arg0.
928 #if !defined(CONFIG_USER_ONLY)
931 TaskState
*ts
= cs
->opaque
;
936 /* Compute the size of the output string. */
937 #if !defined(CONFIG_USER_ONLY)
938 cmdline
= semihosting_get_cmdline();
939 if (cmdline
== NULL
) {
940 cmdline
= ""; /* Default to an empty line. */
942 output_size
= strlen(cmdline
) + 1; /* Count terminating 0. */
946 output_size
= ts
->info
->env_strings
- ts
->info
->arg_strings
;
949 * We special-case the "empty command line" case (argc==0).
950 * Just provide the terminating 0.
956 if (output_size
> input_size
) {
957 /* Not enough space to store command-line arguments. */
958 common_semi_cb(cs
, -1, E2BIG
);
962 /* Adjust the command-line length. */
963 if (SET_ARG(1, output_size
- 1)) {
964 /* Couldn't write back to argument block */
968 /* Lock the buffer on the ARM side. */
969 output_buffer
= lock_user(VERIFY_WRITE
, arg0
, output_size
, 0);
970 if (!output_buffer
) {
974 /* Copy the command-line arguments. */
975 #if !defined(CONFIG_USER_ONLY)
976 pstrcpy(output_buffer
, output_size
, cmdline
);
978 if (output_size
== 1) {
979 /* Empty command-line. */
980 output_buffer
[0] = '\0';
984 if (copy_from_user(output_buffer
, ts
->info
->arg_strings
,
986 unlock_user(output_buffer
, arg0
, 0);
990 /* Separate arguments by white spaces. */
991 for (i
= 0; i
< output_size
- 1; i
++) {
992 if (output_buffer
[i
] == 0) {
993 output_buffer
[i
] = ' ';
998 /* Unlock the buffer on the ARM side. */
999 unlock_user(output_buffer
, arg0
, output_size
);
1000 common_semi_cb(cs
, status
, 0);
1004 case TARGET_SYS_HEAPINFO
:
1006 target_ulong retvals
[4];
1008 #ifdef CONFIG_USER_ONLY
1009 TaskState
*ts
= cs
->opaque
;
1012 LayoutInfo info
= common_semi_find_bases(cs
);
1017 #ifdef CONFIG_USER_ONLY
1019 * Some C libraries assume the heap immediately follows .bss, so
1020 * allocate it using sbrk.
1022 if (!ts
->heap_limit
) {
1025 ts
->heap_base
= do_brk(0);
1026 limit
= ts
->heap_base
+ COMMON_SEMI_HEAP_SIZE
;
1027 /* Try a big heap, and reduce the size if that fails. */
1029 ret
= do_brk(limit
);
1033 limit
= (ts
->heap_base
>> 1) + (limit
>> 1);
1035 ts
->heap_limit
= limit
;
1038 retvals
[0] = ts
->heap_base
;
1039 retvals
[1] = ts
->heap_limit
;
1040 retvals
[2] = ts
->stack_base
;
1041 retvals
[3] = 0; /* Stack limit. */
1043 retvals
[0] = info
.heapbase
; /* Heap Base */
1044 retvals
[1] = info
.heaplimit
; /* Heap Limit */
1045 retvals
[2] = info
.heaplimit
; /* Stack base */
1046 retvals
[3] = info
.heapbase
; /* Stack limit. */
1049 for (i
= 0; i
< ARRAY_SIZE(retvals
); i
++) {
1052 if (is_64bit_semihosting(env
)) {
1053 fail
= put_user_u64(retvals
[i
], arg0
+ i
* 8);
1055 fail
= put_user_u32(retvals
[i
], arg0
+ i
* 4);
1059 /* Couldn't write back to argument block */
1063 common_semi_set_ret(cs
, 0);
1067 case TARGET_SYS_EXIT
:
1068 case TARGET_SYS_EXIT_EXTENDED
:
1069 if (common_semi_sys_exit_extended(cs
, nr
)) {
1071 * The A64 version of SYS_EXIT takes a parameter block,
1072 * so the application-exit type can return a subcode which
1073 * is the exit status code from the application.
1074 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1075 * which allows A32/T32 guests to also provide a status code.
1080 if (arg0
== ADP_Stopped_ApplicationExit
) {
1087 * The A32/T32 version of SYS_EXIT specifies only
1088 * Stopped_ApplicationExit as normal exit, but does not
1089 * allow the guest to specify the exit status code.
1090 * Everything else is considered an error.
1092 ret
= (args
== ADP_Stopped_ApplicationExit
) ? 0 : 1;
1097 case TARGET_SYS_ELAPSED
:
1098 elapsed
= get_clock() - clock_start
;
1099 if (sizeof(target_ulong
) == 8) {
1100 SET_ARG(0, elapsed
);
1102 SET_ARG(0, (uint32_t) elapsed
);
1103 SET_ARG(1, (uint32_t) (elapsed
>> 32));
1105 common_semi_set_ret(cs
, 0);
1108 case TARGET_SYS_TICKFREQ
:
1109 /* qemu always uses nsec */
1110 common_semi_set_ret(cs
, 1000000000);
1113 case TARGET_SYS_SYNCCACHE
:
1115 * Clean the D-cache and invalidate the I-cache for the specified
1116 * virtual address range. This is a nop for us since we don't
1117 * implement caches. This is only present on A64.
1120 if (is_a64(cs
->env_ptr
)) {
1121 common_semi_set_ret(cs
, 0);
1126 common_semi_set_ret(cs
, 0);
1128 /* fall through -- invalid for A32/T32 */
1130 fprintf(stderr
, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr
);
1131 cpu_dump_state(cs
, stderr
, 0);
1135 common_semi_cb(cs
, -1, EBADF
);
1138 common_semi_cb(cs
, -1, EFAULT
);