1 /*
2  *  Semihosting support for systems modeled on the Arm "Angel"
3  *  semihosting syscalls design. This includes Arm and RISC-V processors
4  *
5  *  Copyright (c) 2005, 2007 CodeSourcery.
6  *  Copyright (c) 2019 Linaro
7  *  Written by Paul Brook.
8  *
9  *  Copyright © 2020 by Keith Packard <keithp@keithp.com>
10  *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
11  *
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.
16  *
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.
21  *
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/>.
24  *
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
28  *
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
32  */
33 
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"
41 
42 #ifdef CONFIG_USER_ONLY
43 #include "qemu.h"
44 
45 #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
46 #else
47 #include "qemu/cutils.h"
48 #include "hw/loader.h"
49 #ifdef TARGET_ARM
50 #include "hw/arm/boot.h"
51 #endif
52 #include "hw/boards.h"
53 #endif
54 
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
80 
81 /* ADP_Stopped_ApplicationExit is used for exit(0),
82  * anything else is implemented as exit(1) */
83 #define ADP_Stopped_ApplicationExit     (0x20026)
84 
85 #ifndef O_BINARY
86 #define O_BINARY 0
87 #endif
88 
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
95 #define GDB_O_BINARY  0
96 
97 static int gdb_open_modeflags[12] = {
98     GDB_O_RDONLY,
99     GDB_O_RDONLY | GDB_O_BINARY,
100     GDB_O_RDWR,
101     GDB_O_RDWR | GDB_O_BINARY,
102     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
103     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
104     GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
105     GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
106     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
107     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
108     GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
109     GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
110 };
111 
112 static int open_modeflags[12] = {
113     O_RDONLY,
114     O_RDONLY | O_BINARY,
115     O_RDWR,
116     O_RDWR | O_BINARY,
117     O_WRONLY | O_CREAT | O_TRUNC,
118     O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
119     O_RDWR | O_CREAT | O_TRUNC,
120     O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
121     O_WRONLY | O_CREAT | O_APPEND,
122     O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
123     O_RDWR | O_CREAT | O_APPEND,
124     O_RDWR | O_CREAT | O_APPEND | O_BINARY
125 };
126 
127 #ifndef CONFIG_USER_ONLY
128 
129 /**
130  * common_semi_find_bases: find information about ram and heap base
131  *
132  * This function attempts to provide meaningful numbers for RAM and
133  * HEAP base addresses. The rambase is simply the lowest addressable
134  * RAM position. For the heapbase we ask the loader to scan the
135  * address space and the largest available gap by querying the "ROM"
136  * regions.
137  *
138  * Returns: a structure with the numbers we need.
139  */
140 
141 typedef struct LayoutInfo {
142     target_ulong rambase;
143     size_t ramsize;
144     hwaddr heapbase;
145     hwaddr heaplimit;
146 } LayoutInfo;
147 
148 static bool find_ram_cb(Int128 start, Int128 len, const MemoryRegion *mr,
149                         hwaddr offset_in_region, void *opaque)
150 {
151     LayoutInfo *info = (LayoutInfo *) opaque;
152     uint64_t size = int128_get64(len);
153 
154     if (!mr->ram || mr->readonly) {
155         return false;
156     }
157 
158     if (size > info->ramsize) {
159         info->rambase = int128_get64(start);
160         info->ramsize = size;
161     }
162 
163     /* search exhaustively for largest RAM */
164     return false;
165 }
166 
167 static LayoutInfo common_semi_find_bases(CPUState *cs)
168 {
169     FlatView *fv;
170     LayoutInfo info = { 0, 0, 0, 0 };
171 
172     RCU_READ_LOCK_GUARD();
173 
174     fv = address_space_to_flatview(cs->as);
175     flatview_for_each_range(fv, find_ram_cb, &info);
176 
177     /*
178      * If we have found the RAM lets iterate through the ROM blobs to
179      * work out the best place for the remainder of RAM and split it
180      * equally between stack and heap.
181      */
182     if (info.rambase || info.ramsize > 0) {
183         RomGap gap = rom_find_largest_gap_between(info.rambase, info.ramsize);
184         info.heapbase = gap.base;
185         info.heaplimit = gap.base + gap.size;
186     }
187 
188     return info;
189 }
190 
191 #endif
192 
193 #ifdef TARGET_ARM
194 static inline target_ulong
195 common_semi_arg(CPUState *cs, int argno)
196 {
197     ARMCPU *cpu = ARM_CPU(cs);
198     CPUARMState *env = &cpu->env;
199     if (is_a64(env)) {
200         return env->xregs[argno];
201     } else {
202         return env->regs[argno];
203     }
204 }
205 
206 static inline void
207 common_semi_set_ret(CPUState *cs, target_ulong ret)
208 {
209     ARMCPU *cpu = ARM_CPU(cs);
210     CPUARMState *env = &cpu->env;
211     if (is_a64(env)) {
212         env->xregs[0] = ret;
213     } else {
214         env->regs[0] = ret;
215     }
216 }
217 
218 static inline bool
219 common_semi_sys_exit_extended(CPUState *cs, int nr)
220 {
221     return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
222 }
223 
224 #endif /* TARGET_ARM */
225 
226 #ifdef TARGET_RISCV
227 static inline target_ulong
228 common_semi_arg(CPUState *cs, int argno)
229 {
230     RISCVCPU *cpu = RISCV_CPU(cs);
231     CPURISCVState *env = &cpu->env;
232     return env->gpr[xA0 + argno];
233 }
234 
235 static inline void
236 common_semi_set_ret(CPUState *cs, target_ulong ret)
237 {
238     RISCVCPU *cpu = RISCV_CPU(cs);
239     CPURISCVState *env = &cpu->env;
240     env->gpr[xA0] = ret;
241 }
242 
243 static inline bool
244 common_semi_sys_exit_extended(CPUState *cs, int nr)
245 {
246     return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
247 }
248 
249 #endif
250 
251 /*
252  * The semihosting API has no concept of its errno being thread-safe,
253  * as the API design predates SMP CPUs and was intended as a simple
254  * real-hardware set of debug functionality. For QEMU, we make the
255  * errno be per-thread in linux-user mode; in softmmu it is a simple
256  * global, and we assume that the guest takes care of avoiding any races.
257  */
258 #ifndef CONFIG_USER_ONLY
259 static target_ulong syscall_err;
260 
261 #include "semihosting/softmmu-uaccess.h"
262 #endif
263 
264 static inline uint32_t get_swi_errno(CPUState *cs)
265 {
266 #ifdef CONFIG_USER_ONLY
267     TaskState *ts = cs->opaque;
268 
269     return ts->swi_errno;
270 #else
271     return syscall_err;
272 #endif
273 }
274 
275 static target_ulong common_semi_syscall_len;
276 
277 static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
278 {
279     if (err) {
280 #ifdef CONFIG_USER_ONLY
281         TaskState *ts = cs->opaque;
282         ts->swi_errno = err;
283 #else
284         syscall_err = err;
285 #endif
286     } else {
287         /* Fixup syscalls that use nonstardard return conventions.  */
288         target_ulong reg0 = common_semi_arg(cs, 0);
289         switch (reg0) {
290         case TARGET_SYS_WRITE:
291         case TARGET_SYS_READ:
292             ret = common_semi_syscall_len - ret;
293             break;
294         case TARGET_SYS_SEEK:
295             ret = 0;
296             break;
297         default:
298             break;
299         }
300     }
301     common_semi_set_ret(cs, ret);
302 }
303 
304 static target_ulong common_semi_flen_buf(CPUState *cs)
305 {
306     target_ulong sp;
307 #ifdef TARGET_ARM
308     /* Return an address in target memory of 64 bytes where the remote
309      * gdb should write its stat struct. (The format of this structure
310      * is defined by GDB's remote protocol and is not target-specific.)
311      * We put this on the guest's stack just below SP.
312      */
313     ARMCPU *cpu = ARM_CPU(cs);
314     CPUARMState *env = &cpu->env;
315 
316     if (is_a64(env)) {
317         sp = env->xregs[31];
318     } else {
319         sp = env->regs[13];
320     }
321 #endif
322 #ifdef TARGET_RISCV
323     RISCVCPU *cpu = RISCV_CPU(cs);
324     CPURISCVState *env = &cpu->env;
325 
326     sp = env->gpr[xSP];
327 #endif
328 
329     return sp - 64;
330 }
331 
332 static void
333 common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
334 {
335     if (!err) {
336         /*
337          * The size is always stored in big-endian order, extract
338          * the value. We assume the size always fit in 32 bits.
339          */
340         uint32_t size;
341         cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32,
342                             (uint8_t *)&size, 4, 0);
343         ret = be32_to_cpu(size);
344     }
345     common_semi_cb(cs, ret, err);
346 }
347 
348 static int common_semi_open_guestfd;
349 
350 static void
351 common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
352 {
353     if (err) {
354         dealloc_guestfd(common_semi_open_guestfd);
355     } else {
356         associate_guestfd(common_semi_open_guestfd, ret);
357         ret = common_semi_open_guestfd;
358     }
359     common_semi_cb(cs, ret, err);
360 }
361 
362 /*
363  * Types for functions implementing various semihosting calls
364  * for specific types of guest file descriptor. These must all
365  * do the work and return the required return value to the guest
366  * via common_semi_cb.
367  */
368 typedef void sys_closefn(CPUState *cs, GuestFD *gf);
369 typedef void sys_writefn(CPUState *cs, GuestFD *gf,
370                          target_ulong buf, uint32_t len);
371 typedef void sys_readfn(CPUState *cs, GuestFD *gf,
372                         target_ulong buf, uint32_t len);
373 typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
374 typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
375 typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
376 
377 static void host_closefn(CPUState *cs, GuestFD *gf)
378 {
379     int ret;
380     /*
381      * Only close the underlying host fd if it's one we opened on behalf
382      * of the guest in SYS_OPEN.
383      */
384     if (gf->hostfd == STDIN_FILENO ||
385         gf->hostfd == STDOUT_FILENO ||
386         gf->hostfd == STDERR_FILENO) {
387         ret = 0;
388     } else {
389         ret = close(gf->hostfd);
390     }
391     common_semi_cb(cs, ret, ret ? errno : 0);
392 }
393 
394 static void host_writefn(CPUState *cs, GuestFD *gf,
395                          target_ulong buf, uint32_t len)
396 {
397     CPUArchState *env = cs->env_ptr;
398     uint32_t ret = 0;
399     char *s = lock_user(VERIFY_READ, buf, len, 1);
400     (void) env; /* Used in arm softmmu lock_user implicitly */
401     if (s) {
402         ret = write(gf->hostfd, s, len);
403         unlock_user(s, buf, 0);
404         if (ret == (uint32_t)-1) {
405             ret = 0;
406         }
407     }
408     /* Return bytes not written, on error as well. */
409     common_semi_cb(cs, len - ret, 0);
410 }
411 
412 static void host_readfn(CPUState *cs, GuestFD *gf,
413                         target_ulong buf, uint32_t len)
414 {
415     CPUArchState *env = cs->env_ptr;
416     uint32_t ret = 0;
417     char *s = lock_user(VERIFY_WRITE, buf, len, 0);
418     (void) env; /* Used in arm softmmu lock_user implicitly */
419     if (s) {
420         do {
421             ret = read(gf->hostfd, s, len);
422         } while (ret == -1 && errno == EINTR);
423         unlock_user(s, buf, len);
424         if (ret == (uint32_t)-1) {
425             ret = 0;
426         }
427     }
428     /* Return bytes not read, on error as well. */
429     common_semi_cb(cs, len - ret, 0);
430 }
431 
432 static void host_isattyfn(CPUState *cs, GuestFD *gf)
433 {
434     common_semi_cb(cs, isatty(gf->hostfd), 0);
435 }
436 
437 static void host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
438 {
439     off_t ret = lseek(gf->hostfd, offset, SEEK_SET);
440     common_semi_cb(cs, ret, ret == -1 ? errno : 0);
441 }
442 
443 static void host_flenfn(CPUState *cs, GuestFD *gf)
444 {
445     struct stat buf;
446 
447     if (fstat(gf->hostfd, &buf)) {
448         common_semi_cb(cs, -1, errno);
449     } else {
450         common_semi_cb(cs, buf.st_size, 0);
451     }
452 }
453 
454 static void gdb_closefn(CPUState *cs, GuestFD *gf)
455 {
456     gdb_do_syscall(common_semi_cb, "close,%x", gf->hostfd);
457 }
458 
459 static void gdb_writefn(CPUState *cs, GuestFD *gf,
460                         target_ulong buf, uint32_t len)
461 {
462     common_semi_syscall_len = len;
463     gdb_do_syscall(common_semi_cb, "write,%x,%x,%x", gf->hostfd, buf, len);
464 }
465 
466 static void gdb_readfn(CPUState *cs, GuestFD *gf,
467                        target_ulong buf, uint32_t len)
468 {
469     common_semi_syscall_len = len;
470     gdb_do_syscall(common_semi_cb, "read,%x,%x,%x", gf->hostfd, buf, len);
471 }
472 
473 static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
474 {
475     gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
476 }
477 
478 static void gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
479 {
480     gdb_do_syscall(common_semi_cb, "lseek,%x,%x,0", gf->hostfd, offset);
481 }
482 
483 static void gdb_flenfn(CPUState *cs, GuestFD *gf)
484 {
485     gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
486                    gf->hostfd, common_semi_flen_buf(cs));
487 }
488 
489 #define SHFB_MAGIC_0 0x53
490 #define SHFB_MAGIC_1 0x48
491 #define SHFB_MAGIC_2 0x46
492 #define SHFB_MAGIC_3 0x42
493 
494 /* Feature bits reportable in feature byte 0 */
495 #define SH_EXT_EXIT_EXTENDED (1 << 0)
496 #define SH_EXT_STDOUT_STDERR (1 << 1)
497 
498 static const uint8_t featurefile_data[] = {
499     SHFB_MAGIC_0,
500     SHFB_MAGIC_1,
501     SHFB_MAGIC_2,
502     SHFB_MAGIC_3,
503     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
504 };
505 
506 static void staticfile_closefn(CPUState *cs, GuestFD *gf)
507 {
508     /* Nothing to do */
509     common_semi_cb(cs, 0, 0);
510 }
511 
512 static void staticfile_writefn(CPUState *cs, GuestFD *gf,
513                                target_ulong buf, uint32_t len)
514 {
515     /* This fd can never be open for writing */
516     common_semi_cb(cs, -1, EBADF);
517 }
518 
519 static void staticfile_readfn(CPUState *cs, GuestFD *gf,
520                               target_ulong buf, uint32_t len)
521 {
522     CPUArchState *env = cs->env_ptr;
523     uint32_t i = 0;
524     char *s;
525 
526     (void) env; /* Used in arm softmmu lock_user implicitly */
527     s = lock_user(VERIFY_WRITE, buf, len, 0);
528     if (s) {
529         for (i = 0; i < len; i++) {
530             if (gf->staticfile.off >= gf->staticfile.len) {
531                 break;
532             }
533             s[i] = gf->staticfile.data[gf->staticfile.off];
534             gf->staticfile.off++;
535         }
536         unlock_user(s, buf, len);
537     }
538 
539     /* Return number of bytes not read */
540     common_semi_cb(cs, len - i, 0);
541 }
542 
543 static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
544 {
545     common_semi_cb(cs, 0, 0);
546 }
547 
548 static void staticfile_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
549 {
550     gf->staticfile.off = offset;
551     common_semi_cb(cs, 0, 0);
552 }
553 
554 static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
555 {
556     common_semi_cb(cs, gf->staticfile.len, 0);
557 }
558 
559 typedef struct GuestFDFunctions {
560     sys_closefn *closefn;
561     sys_writefn *writefn;
562     sys_readfn *readfn;
563     sys_isattyfn *isattyfn;
564     sys_seekfn *seekfn;
565     sys_flenfn *flenfn;
566 } GuestFDFunctions;
567 
568 static const GuestFDFunctions guestfd_fns[] = {
569     [GuestFDHost] = {
570         .closefn = host_closefn,
571         .writefn = host_writefn,
572         .readfn = host_readfn,
573         .isattyfn = host_isattyfn,
574         .seekfn = host_seekfn,
575         .flenfn = host_flenfn,
576     },
577     [GuestFDGDB] = {
578         .closefn = gdb_closefn,
579         .writefn = gdb_writefn,
580         .readfn = gdb_readfn,
581         .isattyfn = gdb_isattyfn,
582         .seekfn = gdb_seekfn,
583         .flenfn = gdb_flenfn,
584     },
585     [GuestFDStatic] = {
586         .closefn = staticfile_closefn,
587         .writefn = staticfile_writefn,
588         .readfn = staticfile_readfn,
589         .isattyfn = staticfile_isattyfn,
590         .seekfn = staticfile_seekfn,
591         .flenfn = staticfile_flenfn,
592     },
593 };
594 
595 /*
596  * Read the input value from the argument block; fail the semihosting
597  * call if the memory read fails. Eventually we could use a generic
598  * CPUState helper function here.
599  */
600 static inline bool is_64bit_semihosting(CPUArchState *env)
601 {
602 #if defined(TARGET_ARM)
603     return is_a64(env);
604 #elif defined(TARGET_RISCV)
605     return riscv_cpu_mxl(env) != MXL_RV32;
606 #else
607 #error un-handled architecture
608 #endif
609 }
610 
611 
612 #define GET_ARG(n) do {                                 \
613     if (is_64bit_semihosting(env)) {                    \
614         if (get_user_u64(arg ## n, args + (n) * 8)) {   \
615             goto do_fault;                              \
616         }                                               \
617     } else {                                            \
618         if (get_user_u32(arg ## n, args + (n) * 4)) {   \
619             goto do_fault;                              \
620         }                                               \
621     }                                                   \
622 } while (0)
623 
624 #define SET_ARG(n, val)                                 \
625     (is_64bit_semihosting(env) ?                        \
626      put_user_u64(val, args + (n) * 8) :                \
627      put_user_u32(val, args + (n) * 4))
628 
629 
630 /*
631  * Do a semihosting call.
632  *
633  * The specification always says that the "return register" either
634  * returns a specific value or is corrupted, so we don't need to
635  * report to our caller whether we are returning a value or trying to
636  * leave the register unchanged. We use 0xdeadbeef as the return value
637  * when there isn't a defined return value for the call.
638  */
639 void do_common_semihosting(CPUState *cs)
640 {
641     CPUArchState *env = cs->env_ptr;
642     target_ulong args;
643     target_ulong arg0, arg1, arg2, arg3;
644     target_ulong ul_ret;
645     char * s;
646     int nr;
647     uint32_t ret;
648     uint32_t len;
649     GuestFD *gf;
650     int64_t elapsed;
651 
652     (void) env; /* Used implicitly by arm lock_user macro */
653     nr = common_semi_arg(cs, 0) & 0xffffffffU;
654     args = common_semi_arg(cs, 1);
655 
656     switch (nr) {
657     case TARGET_SYS_OPEN:
658     {
659         int ret, err = 0;
660         int hostfd;
661 
662         GET_ARG(0);
663         GET_ARG(1);
664         GET_ARG(2);
665         s = lock_user_string(arg0);
666         if (!s) {
667             goto do_fault;
668         }
669         if (arg1 >= 12) {
670             unlock_user(s, arg0, 0);
671             common_semi_cb(cs, -1, EINVAL);
672             break;
673         }
674 
675         if (strcmp(s, ":tt") == 0) {
676             /*
677              * We implement SH_EXT_STDOUT_STDERR, so:
678              *  open for read == stdin
679              *  open for write == stdout
680              *  open for append == stderr
681              */
682             if (arg1 < 4) {
683                 hostfd = STDIN_FILENO;
684             } else if (arg1 < 8) {
685                 hostfd = STDOUT_FILENO;
686             } else {
687                 hostfd = STDERR_FILENO;
688             }
689             ret = alloc_guestfd();
690             associate_guestfd(ret, hostfd);
691         } else if (strcmp(s, ":semihosting-features") == 0) {
692             /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
693             if (arg1 != 0 && arg1 != 1) {
694                 ret = -1;
695                 err = EACCES;
696             } else {
697                 ret = alloc_guestfd();
698                 staticfile_guestfd(ret, featurefile_data,
699                                    sizeof(featurefile_data));
700             }
701         } else if (use_gdb_syscalls()) {
702             unlock_user(s, arg0, 0);
703             common_semi_open_guestfd = alloc_guestfd();
704             gdb_do_syscall(common_semi_open_cb,
705                            "open,%s,%x,1a4", arg0, (int)arg2 + 1,
706                            gdb_open_modeflags[arg1]);
707             break;
708         } else {
709             hostfd = open(s, open_modeflags[arg1], 0644);
710             if (hostfd < 0) {
711                 ret = -1;
712                 err = errno;
713             } else {
714                 ret = alloc_guestfd();
715                 associate_guestfd(ret, hostfd);
716             }
717         }
718         unlock_user(s, arg0, 0);
719         common_semi_cb(cs, ret, err);
720         break;
721     }
722 
723     case TARGET_SYS_CLOSE:
724         GET_ARG(0);
725 
726         gf = get_guestfd(arg0);
727         if (!gf) {
728             goto do_badf;
729         }
730         guestfd_fns[gf->type].closefn(cs, gf);
731         dealloc_guestfd(arg0);
732         break;
733 
734     case TARGET_SYS_WRITEC:
735         qemu_semihosting_console_outc(cs->env_ptr, args);
736         common_semi_set_ret(cs, 0xdeadbeef);
737         break;
738 
739     case TARGET_SYS_WRITE0:
740         ret = qemu_semihosting_console_outs(cs->env_ptr, args);
741         common_semi_set_ret(cs, ret);
742         break;
743 
744     case TARGET_SYS_WRITE:
745         GET_ARG(0);
746         GET_ARG(1);
747         GET_ARG(2);
748         len = arg2;
749 
750         gf = get_guestfd(arg0);
751         if (!gf) {
752             goto do_badf;
753         }
754         guestfd_fns[gf->type].writefn(cs, gf, arg1, len);
755         break;
756 
757     case TARGET_SYS_READ:
758         GET_ARG(0);
759         GET_ARG(1);
760         GET_ARG(2);
761         len = arg2;
762 
763         gf = get_guestfd(arg0);
764         if (!gf) {
765             goto do_badf;
766         }
767         guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
768         break;
769 
770     case TARGET_SYS_READC:
771         ret = qemu_semihosting_console_inc(cs->env_ptr);
772         common_semi_set_ret(cs, ret);
773         break;
774 
775     case TARGET_SYS_ISERROR:
776         GET_ARG(0);
777         common_semi_set_ret(cs, (target_long)arg0 < 0);
778         break;
779 
780     case TARGET_SYS_ISTTY:
781         GET_ARG(0);
782 
783         gf = get_guestfd(arg0);
784         if (!gf) {
785             goto do_badf;
786         }
787         guestfd_fns[gf->type].isattyfn(cs, gf);
788         break;
789 
790     case TARGET_SYS_SEEK:
791         GET_ARG(0);
792         GET_ARG(1);
793 
794         gf = get_guestfd(arg0);
795         if (!gf) {
796             goto do_badf;
797         }
798         guestfd_fns[gf->type].seekfn(cs, gf, arg1);
799         break;
800 
801     case TARGET_SYS_FLEN:
802         GET_ARG(0);
803 
804         gf = get_guestfd(arg0);
805         if (!gf) {
806             goto do_badf;
807         }
808         guestfd_fns[gf->type].flenfn(cs, gf);
809         break;
810 
811     case TARGET_SYS_TMPNAM:
812     {
813         int len;
814         char *p;
815 
816         GET_ARG(0);
817         GET_ARG(1);
818         GET_ARG(2);
819         len = asprintf(&s, "/tmp/qemu-%x%02x", getpid(), (int)arg1 & 0xff);
820         /* Make sure there's enough space in the buffer */
821         if (len < 0 || len >= arg2) {
822             common_semi_set_ret(cs, -1);
823             break;
824         }
825         p = lock_user(VERIFY_WRITE, arg0, len, 0);
826         if (!p) {
827             goto do_fault;
828         }
829         memcpy(p, s, len + 1);
830         unlock_user(p, arg0, len);
831         free(s);
832         common_semi_set_ret(cs, 0);
833         break;
834     }
835 
836     case TARGET_SYS_REMOVE:
837         GET_ARG(0);
838         GET_ARG(1);
839         if (use_gdb_syscalls()) {
840             gdb_do_syscall(common_semi_cb, "unlink,%s",
841                            arg0, (int)arg1 + 1);
842             break;
843         }
844         s = lock_user_string(arg0);
845         if (!s) {
846             goto do_fault;
847         }
848         ret = remove(s);
849         unlock_user(s, arg0, 0);
850         common_semi_cb(cs, ret, ret ? errno : 0);
851         break;
852 
853     case TARGET_SYS_RENAME:
854         GET_ARG(0);
855         GET_ARG(1);
856         GET_ARG(2);
857         GET_ARG(3);
858         if (use_gdb_syscalls()) {
859             gdb_do_syscall(common_semi_cb, "rename,%s,%s",
860                            arg0, (int)arg1 + 1, arg2, (int)arg3 + 1);
861         } else {
862             char *s2;
863 
864             s = lock_user_string(arg0);
865             if (!s) {
866                 goto do_fault;
867             }
868             s2 = lock_user_string(arg2);
869             if (!s2) {
870                 unlock_user(s, arg0, 0);
871                 goto do_fault;
872             }
873             ret = rename(s, s2);
874             unlock_user(s2, arg2, 0);
875             unlock_user(s, arg0, 0);
876             common_semi_cb(cs, ret, ret ? errno : 0);
877         }
878         break;
879 
880     case TARGET_SYS_CLOCK:
881         common_semi_set_ret(cs, clock() / (CLOCKS_PER_SEC / 100));
882         break;
883 
884     case TARGET_SYS_TIME:
885         ul_ret = time(NULL);
886         common_semi_cb(cs, ul_ret, ul_ret == -1 ? errno : 0);
887         break;
888 
889     case TARGET_SYS_SYSTEM:
890         GET_ARG(0);
891         GET_ARG(1);
892         if (use_gdb_syscalls()) {
893             gdb_do_syscall(common_semi_cb, "system,%s", arg0, (int)arg1 + 1);
894             break;
895         }
896         s = lock_user_string(arg0);
897         if (!s) {
898             goto do_fault;
899         }
900         ret = system(s);
901         unlock_user(s, arg0, 0);
902         common_semi_cb(cs, ret, ret == -1 ? errno : 0);
903         break;
904 
905     case TARGET_SYS_ERRNO:
906         common_semi_set_ret(cs, get_swi_errno(cs));
907         break;
908 
909     case TARGET_SYS_GET_CMDLINE:
910         {
911             /* Build a command-line from the original argv.
912              *
913              * The inputs are:
914              *     * arg0, pointer to a buffer of at least the size
915              *               specified in arg1.
916              *     * arg1, size of the buffer pointed to by arg0 in
917              *               bytes.
918              *
919              * The outputs are:
920              *     * arg0, pointer to null-terminated string of the
921              *               command line.
922              *     * arg1, length of the string pointed to by arg0.
923              */
924 
925             char *output_buffer;
926             size_t input_size;
927             size_t output_size;
928             int status = 0;
929 #if !defined(CONFIG_USER_ONLY)
930             const char *cmdline;
931 #else
932             TaskState *ts = cs->opaque;
933 #endif
934             GET_ARG(0);
935             GET_ARG(1);
936             input_size = arg1;
937             /* Compute the size of the output string.  */
938 #if !defined(CONFIG_USER_ONLY)
939             cmdline = semihosting_get_cmdline();
940             if (cmdline == NULL) {
941                 cmdline = ""; /* Default to an empty line. */
942             }
943             output_size = strlen(cmdline) + 1; /* Count terminating 0. */
944 #else
945             unsigned int i;
946 
947             output_size = ts->info->env_strings - ts->info->arg_strings;
948             if (!output_size) {
949                 /*
950                  * We special-case the "empty command line" case (argc==0).
951                  * Just provide the terminating 0.
952                  */
953                 output_size = 1;
954             }
955 #endif
956 
957             if (output_size > input_size) {
958                 /* Not enough space to store command-line arguments.  */
959                 common_semi_cb(cs, -1, E2BIG);
960                 break;
961             }
962 
963             /* Adjust the command-line length.  */
964             if (SET_ARG(1, output_size - 1)) {
965                 /* Couldn't write back to argument block */
966                 goto do_fault;
967             }
968 
969             /* Lock the buffer on the ARM side.  */
970             output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
971             if (!output_buffer) {
972                 goto do_fault;
973             }
974 
975             /* Copy the command-line arguments.  */
976 #if !defined(CONFIG_USER_ONLY)
977             pstrcpy(output_buffer, output_size, cmdline);
978 #else
979             if (output_size == 1) {
980                 /* Empty command-line.  */
981                 output_buffer[0] = '\0';
982                 goto out;
983             }
984 
985             if (copy_from_user(output_buffer, ts->info->arg_strings,
986                                output_size)) {
987                 unlock_user(output_buffer, arg0, 0);
988                 goto do_fault;
989             }
990 
991             /* Separate arguments by white spaces.  */
992             for (i = 0; i < output_size - 1; i++) {
993                 if (output_buffer[i] == 0) {
994                     output_buffer[i] = ' ';
995                 }
996             }
997         out:
998 #endif
999             /* Unlock the buffer on the ARM side.  */
1000             unlock_user(output_buffer, arg0, output_size);
1001             common_semi_cb(cs, status, 0);
1002         }
1003         break;
1004 
1005     case TARGET_SYS_HEAPINFO:
1006         {
1007             target_ulong retvals[4];
1008             int i;
1009 #ifdef CONFIG_USER_ONLY
1010             TaskState *ts = cs->opaque;
1011             target_ulong limit;
1012 #else
1013             LayoutInfo info = common_semi_find_bases(cs);
1014 #endif
1015 
1016             GET_ARG(0);
1017 
1018 #ifdef CONFIG_USER_ONLY
1019             /*
1020              * Some C libraries assume the heap immediately follows .bss, so
1021              * allocate it using sbrk.
1022              */
1023             if (!ts->heap_limit) {
1024                 abi_ulong ret;
1025 
1026                 ts->heap_base = do_brk(0);
1027                 limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE;
1028                 /* Try a big heap, and reduce the size if that fails.  */
1029                 for (;;) {
1030                     ret = do_brk(limit);
1031                     if (ret >= limit) {
1032                         break;
1033                     }
1034                     limit = (ts->heap_base >> 1) + (limit >> 1);
1035                 }
1036                 ts->heap_limit = limit;
1037             }
1038 
1039             retvals[0] = ts->heap_base;
1040             retvals[1] = ts->heap_limit;
1041             retvals[2] = ts->stack_base;
1042             retvals[3] = 0; /* Stack limit.  */
1043 #else
1044             retvals[0] = info.heapbase;  /* Heap Base */
1045             retvals[1] = info.heaplimit; /* Heap Limit */
1046             retvals[2] = info.heaplimit; /* Stack base */
1047             retvals[3] = info.heapbase;  /* Stack limit.  */
1048 #endif
1049 
1050             for (i = 0; i < ARRAY_SIZE(retvals); i++) {
1051                 bool fail;
1052 
1053                 if (is_64bit_semihosting(env)) {
1054                     fail = put_user_u64(retvals[i], arg0 + i * 8);
1055                 } else {
1056                     fail = put_user_u32(retvals[i], arg0 + i * 4);
1057                 }
1058 
1059                 if (fail) {
1060                     /* Couldn't write back to argument block */
1061                     goto do_fault;
1062                 }
1063             }
1064             common_semi_set_ret(cs, 0);
1065         }
1066         break;
1067 
1068     case TARGET_SYS_EXIT:
1069     case TARGET_SYS_EXIT_EXTENDED:
1070         if (common_semi_sys_exit_extended(cs, nr)) {
1071             /*
1072              * The A64 version of SYS_EXIT takes a parameter block,
1073              * so the application-exit type can return a subcode which
1074              * is the exit status code from the application.
1075              * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1076              * which allows A32/T32 guests to also provide a status code.
1077              */
1078             GET_ARG(0);
1079             GET_ARG(1);
1080 
1081             if (arg0 == ADP_Stopped_ApplicationExit) {
1082                 ret = arg1;
1083             } else {
1084                 ret = 1;
1085             }
1086         } else {
1087             /*
1088              * The A32/T32 version of SYS_EXIT specifies only
1089              * Stopped_ApplicationExit as normal exit, but does not
1090              * allow the guest to specify the exit status code.
1091              * Everything else is considered an error.
1092              */
1093             ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
1094         }
1095         gdb_exit(ret);
1096         exit(ret);
1097 
1098     case TARGET_SYS_ELAPSED:
1099         elapsed = get_clock() - clock_start;
1100         if (sizeof(target_ulong) == 8) {
1101             SET_ARG(0, elapsed);
1102         } else {
1103             SET_ARG(0, (uint32_t) elapsed);
1104             SET_ARG(1, (uint32_t) (elapsed >> 32));
1105         }
1106         common_semi_set_ret(cs, 0);
1107         break;
1108 
1109     case TARGET_SYS_TICKFREQ:
1110         /* qemu always uses nsec */
1111         common_semi_set_ret(cs, 1000000000);
1112         break;
1113 
1114     case TARGET_SYS_SYNCCACHE:
1115         /*
1116          * Clean the D-cache and invalidate the I-cache for the specified
1117          * virtual address range. This is a nop for us since we don't
1118          * implement caches. This is only present on A64.
1119          */
1120 #ifdef TARGET_ARM
1121         if (is_a64(cs->env_ptr)) {
1122             common_semi_set_ret(cs, 0);
1123             break;
1124         }
1125 #endif
1126 #ifdef TARGET_RISCV
1127         common_semi_set_ret(cs, 0);
1128 #endif
1129         /* fall through -- invalid for A32/T32 */
1130     default:
1131         fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
1132         cpu_dump_state(cs, stderr, 0);
1133         abort();
1134 
1135     do_badf:
1136         common_semi_cb(cs, -1, EBADF);
1137         break;
1138     do_fault:
1139         common_semi_cb(cs, -1, EFAULT);
1140         break;
1141     }
1142 }
1143