xref: /openbmc/qemu/semihosting/syscalls.c (revision fb08790b)
1 /*
2  * Syscall implementations for semihosting.
3  *
4  * Copyright (c) 2022 Linaro
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "qemu/osdep.h"
10 #include "exec/gdbstub.h"
11 #include "semihosting/guestfd.h"
12 #include "semihosting/syscalls.h"
13 #ifdef CONFIG_USER_ONLY
14 #include "qemu.h"
15 #else
16 #include "semihosting/softmmu-uaccess.h"
17 #endif
18 
19 
20 /*
21  * Validate or compute the length of the string (including terminator).
22  */
23 static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen)
24 {
25     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
26     char c;
27 
28     if (tlen == 0) {
29         ssize_t slen = target_strlen(str);
30 
31         if (slen < 0) {
32             return -EFAULT;
33         }
34         if (slen >= INT32_MAX) {
35             return -ENAMETOOLONG;
36         }
37         return slen + 1;
38     }
39     if (tlen > INT32_MAX) {
40         return -ENAMETOOLONG;
41     }
42     if (get_user_u8(c, str + tlen - 1)) {
43         return -EFAULT;
44     }
45     if (c != 0) {
46         return -EINVAL;
47     }
48     return tlen;
49 }
50 
51 static int validate_lock_user_string(char **pstr, CPUState *cs,
52                                      target_ulong tstr, target_ulong tlen)
53 {
54     int ret = validate_strlen(cs, tstr, tlen);
55     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
56     char *str = NULL;
57 
58     if (ret > 0) {
59         str = lock_user(VERIFY_READ, tstr, ret, true);
60         ret = str ? 0 : -EFAULT;
61     }
62     *pstr = str;
63     return ret;
64 }
65 
66 /*
67  * TODO: Note that gdb always stores the stat structure big-endian.
68  * So far, that's ok, as the only two targets using this are also
69  * big-endian.  Until we do something with gdb, also produce the
70  * same big-endian result from the host.
71  */
72 static int copy_stat_to_user(CPUState *cs, target_ulong addr,
73                              const struct stat *s)
74 {
75     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
76     struct gdb_stat *p;
77 
78     if (s->st_dev != (uint32_t)s->st_dev ||
79         s->st_ino != (uint32_t)s->st_ino) {
80         return -EOVERFLOW;
81     }
82 
83     p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0);
84     if (!p) {
85         return -EFAULT;
86     }
87 
88     p->gdb_st_dev = cpu_to_be32(s->st_dev);
89     p->gdb_st_ino = cpu_to_be32(s->st_ino);
90     p->gdb_st_mode = cpu_to_be32(s->st_mode);
91     p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
92     p->gdb_st_uid = cpu_to_be32(s->st_uid);
93     p->gdb_st_gid = cpu_to_be32(s->st_gid);
94     p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
95     p->gdb_st_size = cpu_to_be64(s->st_size);
96 #ifdef _WIN32
97     /* Windows stat is missing some fields.  */
98     p->gdb_st_blksize = 0;
99     p->gdb_st_blocks = 0;
100 #else
101     p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
102     p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
103 #endif
104     p->gdb_st_atime = cpu_to_be32(s->st_atime);
105     p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
106     p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
107 
108     unlock_user(p, addr, sizeof(struct gdb_stat));
109     return 0;
110 }
111 
112 /*
113  * GDB semihosting syscall implementations.
114  */
115 
116 static gdb_syscall_complete_cb gdb_open_complete;
117 
118 static void gdb_open_cb(CPUState *cs, uint64_t ret, int err)
119 {
120     if (!err) {
121         int guestfd = alloc_guestfd();
122         associate_guestfd(guestfd, ret);
123         ret = guestfd;
124     }
125     gdb_open_complete(cs, ret, err);
126 }
127 
128 static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete,
129                      target_ulong fname, target_ulong fname_len,
130                      int gdb_flags, int mode)
131 {
132     int len = validate_strlen(cs, fname, fname_len);
133     if (len < 0) {
134         complete(cs, -1, -len);
135         return;
136     }
137 
138     gdb_open_complete = complete;
139     gdb_do_syscall(gdb_open_cb, "open,%s,%x,%x",
140                    fname, len, (target_ulong)gdb_flags, (target_ulong)mode);
141 }
142 
143 static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete,
144                       GuestFD *gf)
145 {
146     gdb_do_syscall(complete, "close,%x", (target_ulong)gf->hostfd);
147 }
148 
149 static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete,
150                      GuestFD *gf, target_ulong buf, target_ulong len)
151 {
152     gdb_do_syscall(complete, "read,%x,%x,%x",
153                    (target_ulong)gf->hostfd, buf, len);
154 }
155 
156 static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete,
157                       GuestFD *gf, target_ulong buf, target_ulong len)
158 {
159     gdb_do_syscall(complete, "write,%x,%x,%x",
160                    (target_ulong)gf->hostfd, buf, len);
161 }
162 
163 static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
164                       GuestFD *gf, int64_t off, int gdb_whence)
165 {
166     gdb_do_syscall(complete, "lseek,%x,%lx,%x",
167                    (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence);
168 }
169 
170 static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
171                        GuestFD *gf)
172 {
173     gdb_do_syscall(complete, "isatty,%x", (target_ulong)gf->hostfd);
174 }
175 
176 static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
177                       GuestFD *gf, target_ulong addr)
178 {
179     gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr);
180 }
181 
182 static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete,
183                      target_ulong fname, target_ulong fname_len,
184                      target_ulong addr)
185 {
186     int len = validate_strlen(cs, fname, fname_len);
187     if (len < 0) {
188         complete(cs, -1, -len);
189         return;
190     }
191 
192     gdb_do_syscall(complete, "stat,%s,%x", fname, len, addr);
193 }
194 
195 static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
196                        target_ulong fname, target_ulong fname_len)
197 {
198     int len = validate_strlen(cs, fname, fname_len);
199     if (len < 0) {
200         complete(cs, -1, -len);
201         return;
202     }
203 
204     gdb_do_syscall(complete, "unlink,%s", fname, len);
205 }
206 
207 static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete,
208                        target_ulong oname, target_ulong oname_len,
209                        target_ulong nname, target_ulong nname_len)
210 {
211     int olen, nlen;
212 
213     olen = validate_strlen(cs, oname, oname_len);
214     if (olen < 0) {
215         complete(cs, -1, -olen);
216         return;
217     }
218     nlen = validate_strlen(cs, nname, nname_len);
219     if (nlen < 0) {
220         complete(cs, -1, -nlen);
221         return;
222     }
223 
224     gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen);
225 }
226 
227 static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete,
228                        target_ulong cmd, target_ulong cmd_len)
229 {
230     int len = validate_strlen(cs, cmd, cmd_len);
231     if (len < 0) {
232         complete(cs, -1, -len);
233         return;
234     }
235 
236     gdb_do_syscall(complete, "system,%s", cmd, len);
237 }
238 
239 static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
240                              target_ulong tv_addr, target_ulong tz_addr)
241 {
242     gdb_do_syscall(complete, "gettimeofday,%x,%x", tv_addr, tz_addr);
243 }
244 
245 /*
246  * Host semihosting syscall implementations.
247  */
248 
249 static void host_open(CPUState *cs, gdb_syscall_complete_cb complete,
250                       target_ulong fname, target_ulong fname_len,
251                       int gdb_flags, int mode)
252 {
253     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
254     char *p;
255     int ret, host_flags;
256 
257     ret = validate_lock_user_string(&p, cs, fname, fname_len);
258     if (ret < 0) {
259         complete(cs, -1, -ret);
260         return;
261     }
262 
263     if (gdb_flags & GDB_O_WRONLY) {
264         host_flags = O_WRONLY;
265     } else if (gdb_flags & GDB_O_RDWR) {
266         host_flags = O_RDWR;
267     } else {
268         host_flags = O_RDONLY;
269     }
270     if (gdb_flags & GDB_O_CREAT) {
271         host_flags |= O_CREAT;
272     }
273     if (gdb_flags & GDB_O_TRUNC) {
274         host_flags |= O_TRUNC;
275     }
276     if (gdb_flags & GDB_O_EXCL) {
277         host_flags |= O_EXCL;
278     }
279 
280     ret = open(p, host_flags, mode);
281     if (ret < 0) {
282         complete(cs, -1, errno);
283     } else {
284         int guestfd = alloc_guestfd();
285         associate_guestfd(guestfd, ret);
286         complete(cs, guestfd, 0);
287     }
288     unlock_user(p, fname, 0);
289 }
290 
291 static void host_close(CPUState *cs, gdb_syscall_complete_cb complete,
292                        GuestFD *gf)
293 {
294     /*
295      * Only close the underlying host fd if it's one we opened on behalf
296      * of the guest in SYS_OPEN.
297      */
298     if (gf->hostfd != STDIN_FILENO &&
299         gf->hostfd != STDOUT_FILENO &&
300         gf->hostfd != STDERR_FILENO &&
301         close(gf->hostfd) < 0) {
302         complete(cs, -1, errno);
303     } else {
304         complete(cs, 0, 0);
305     }
306 }
307 
308 static void host_read(CPUState *cs, gdb_syscall_complete_cb complete,
309                       GuestFD *gf, target_ulong buf, target_ulong len)
310 {
311     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
312     void *ptr = lock_user(VERIFY_WRITE, buf, len, 0);
313     ssize_t ret;
314 
315     if (!ptr) {
316         complete(cs, -1, EFAULT);
317         return;
318     }
319     do {
320         ret = read(gf->hostfd, ptr, len);
321     } while (ret == -1 && errno == EINTR);
322     if (ret == -1) {
323         complete(cs, -1, errno);
324         unlock_user(ptr, buf, 0);
325     } else {
326         complete(cs, ret, 0);
327         unlock_user(ptr, buf, ret);
328     }
329 }
330 
331 static void host_write(CPUState *cs, gdb_syscall_complete_cb complete,
332                        GuestFD *gf, target_ulong buf, target_ulong len)
333 {
334     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
335     void *ptr = lock_user(VERIFY_READ, buf, len, 1);
336     ssize_t ret;
337 
338     if (!ptr) {
339         complete(cs, -1, EFAULT);
340         return;
341     }
342     ret = write(gf->hostfd, ptr, len);
343     complete(cs, ret, ret == -1 ? errno : 0);
344     unlock_user(ptr, buf, 0);
345 }
346 
347 static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
348                        GuestFD *gf, int64_t off, int whence)
349 {
350     /* So far, all hosts use the same values. */
351     QEMU_BUILD_BUG_ON(GDB_SEEK_SET != SEEK_SET);
352     QEMU_BUILD_BUG_ON(GDB_SEEK_CUR != SEEK_CUR);
353     QEMU_BUILD_BUG_ON(GDB_SEEK_END != SEEK_END);
354 
355     off_t ret = off;
356     int err = 0;
357 
358     if (ret == off) {
359         ret = lseek(gf->hostfd, ret, whence);
360         if (ret == -1) {
361             err = errno;
362         }
363     } else {
364         ret = -1;
365         err = EINVAL;
366     }
367     complete(cs, ret, err);
368 }
369 
370 static void host_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
371                         GuestFD *gf)
372 {
373     int ret = isatty(gf->hostfd);
374     complete(cs, ret, ret ? 0 : errno);
375 }
376 
377 static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete,
378                       GuestFD *gf)
379 {
380     struct stat buf;
381 
382     if (fstat(gf->hostfd, &buf) < 0) {
383         complete(cs, -1, errno);
384     } else {
385         complete(cs, buf.st_size, 0);
386     }
387 }
388 
389 static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
390                        GuestFD *gf, target_ulong addr)
391 {
392     struct stat buf;
393     int ret;
394 
395     ret = fstat(gf->hostfd, &buf);
396     if (ret) {
397         complete(cs, -1, errno);
398         return;
399     }
400     ret = copy_stat_to_user(cs, addr, &buf);
401     complete(cs, ret ? -1 : 0, ret ? -ret : 0);
402 }
403 
404 static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete,
405                       target_ulong fname, target_ulong fname_len,
406                       target_ulong addr)
407 {
408     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
409     struct stat buf;
410     char *name;
411     int ret, err;
412 
413     ret = validate_lock_user_string(&name, cs, fname, fname_len);
414     if (ret < 0) {
415         complete(cs, -1, -ret);
416         return;
417     }
418 
419     ret = stat(name, &buf);
420     if (ret) {
421         err = errno;
422     } else {
423         ret = copy_stat_to_user(cs, addr, &buf);
424         err = 0;
425         if (ret < 0) {
426             err = -ret;
427             ret = -1;
428         }
429     }
430     complete(cs, ret, err);
431     unlock_user(name, fname, 0);
432 }
433 
434 static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
435                         target_ulong fname, target_ulong fname_len)
436 {
437     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
438     char *p;
439     int ret;
440 
441     ret = validate_lock_user_string(&p, cs, fname, fname_len);
442     if (ret < 0) {
443         complete(cs, -1, -ret);
444         return;
445     }
446 
447     ret = remove(p);
448     complete(cs, ret, ret ? errno : 0);
449     unlock_user(p, fname, 0);
450 }
451 
452 static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
453                         target_ulong oname, target_ulong oname_len,
454                         target_ulong nname, target_ulong nname_len)
455 {
456     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
457     char *ostr, *nstr;
458     int ret;
459 
460     ret = validate_lock_user_string(&ostr, cs, oname, oname_len);
461     if (ret < 0) {
462         complete(cs, -1, -ret);
463         return;
464     }
465     ret = validate_lock_user_string(&nstr, cs, nname, nname_len);
466     if (ret < 0) {
467         unlock_user(ostr, oname, 0);
468         complete(cs, -1, -ret);
469         return;
470     }
471 
472     ret = rename(ostr, nstr);
473     complete(cs, ret, ret ? errno : 0);
474     unlock_user(ostr, oname, 0);
475     unlock_user(nstr, nname, 0);
476 }
477 
478 static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
479                         target_ulong cmd, target_ulong cmd_len)
480 {
481     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
482     char *p;
483     int ret;
484 
485     ret = validate_lock_user_string(&p, cs, cmd, cmd_len);
486     if (ret < 0) {
487         complete(cs, -1, -ret);
488         return;
489     }
490 
491     ret = system(p);
492     complete(cs, ret, ret == -1 ? errno : 0);
493     unlock_user(p, cmd, 0);
494 }
495 
496 static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
497                               target_ulong tv_addr, target_ulong tz_addr)
498 {
499     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
500     struct gdb_timeval *p;
501     int64_t rt;
502 
503     /* GDB fails on non-null TZ, so be consistent. */
504     if (tz_addr != 0) {
505         complete(cs, -1, EINVAL);
506         return;
507     }
508 
509     p = lock_user(VERIFY_WRITE, tv_addr, sizeof(struct gdb_timeval), 0);
510     if (!p) {
511         complete(cs, -1, EFAULT);
512         return;
513     }
514 
515     /* TODO: Like stat, gdb always produces big-endian results; match it. */
516     rt = g_get_real_time();
517     p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC);
518     p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC);
519     unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
520 }
521 
522 /*
523  * Static file semihosting syscall implementations.
524  */
525 
526 static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete,
527                             GuestFD *gf, target_ulong buf, target_ulong len)
528 {
529     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
530     target_ulong rest = gf->staticfile.len - gf->staticfile.off;
531     void *ptr;
532 
533     if (len > rest) {
534         len = rest;
535     }
536     ptr = lock_user(VERIFY_WRITE, buf, len, 0);
537     if (!ptr) {
538         complete(cs, -1, EFAULT);
539         return;
540     }
541     memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len);
542     gf->staticfile.off += len;
543     complete(cs, len, 0);
544     unlock_user(ptr, buf, len);
545 }
546 
547 static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
548                              GuestFD *gf, int64_t off, int gdb_whence)
549 {
550     int64_t ret;
551 
552     switch (gdb_whence) {
553     case GDB_SEEK_SET:
554         ret = off;
555         break;
556     case GDB_SEEK_CUR:
557         ret = gf->staticfile.off + off;
558         break;
559     case GDB_SEEK_END:
560         ret = gf->staticfile.len + off;
561         break;
562     default:
563         ret = -1;
564         break;
565     }
566     if (ret >= 0 && ret <= gf->staticfile.len) {
567         gf->staticfile.off = ret;
568         complete(cs, ret, 0);
569     } else {
570         complete(cs, -1, EINVAL);
571     }
572 }
573 
574 static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete,
575                             GuestFD *gf)
576 {
577     complete(cs, gf->staticfile.len, 0);
578 }
579 
580 /*
581  * Syscall entry points.
582  */
583 
584 void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
585                        target_ulong fname, target_ulong fname_len,
586                        int gdb_flags, int mode)
587 {
588     if (use_gdb_syscalls()) {
589         gdb_open(cs, complete, fname, fname_len, gdb_flags, mode);
590     } else {
591         host_open(cs, complete, fname, fname_len, gdb_flags, mode);
592     }
593 }
594 
595 void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
596 {
597     GuestFD *gf = get_guestfd(fd);
598 
599     if (!gf) {
600         complete(cs, -1, EBADF);
601         return;
602     }
603     switch (gf->type) {
604     case GuestFDGDB:
605         gdb_close(cs, complete, gf);
606         break;
607     case GuestFDHost:
608         host_close(cs, complete, gf);
609         break;
610     case GuestFDStatic:
611         complete(cs, 0, 0);
612         break;
613     default:
614         g_assert_not_reached();
615     }
616     dealloc_guestfd(fd);
617 }
618 
619 void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
620                           GuestFD *gf, target_ulong buf, target_ulong len)
621 {
622     /*
623      * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t.
624      * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
625      * idea to do this unconditionally.
626      */
627     if (len > INT32_MAX) {
628         len = INT32_MAX;
629     }
630     switch (gf->type) {
631     case GuestFDGDB:
632         gdb_read(cs, complete, gf, buf, len);
633         break;
634     case GuestFDHost:
635         host_read(cs, complete, gf, buf, len);
636         break;
637     case GuestFDStatic:
638         staticfile_read(cs, complete, gf, buf, len);
639         break;
640     default:
641         g_assert_not_reached();
642     }
643 }
644 
645 void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
646                        int fd, target_ulong buf, target_ulong len)
647 {
648     GuestFD *gf = get_guestfd(fd);
649 
650     if (gf) {
651         semihost_sys_read_gf(cs, complete, gf, buf, len);
652     } else {
653         complete(cs, -1, EBADF);
654     }
655 }
656 
657 void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
658                            GuestFD *gf, target_ulong buf, target_ulong len)
659 {
660     /*
661      * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t.
662      * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
663      * idea to do this unconditionally.
664      */
665     if (len > INT32_MAX) {
666         len = INT32_MAX;
667     }
668     switch (gf->type) {
669     case GuestFDGDB:
670         gdb_write(cs, complete, gf, buf, len);
671         break;
672     case GuestFDHost:
673         host_write(cs, complete, gf, buf, len);
674         break;
675     case GuestFDStatic:
676         /* Static files are never open for writing: EBADF. */
677         complete(cs, -1, EBADF);
678         break;
679     default:
680         g_assert_not_reached();
681     }
682 }
683 
684 void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
685                         int fd, target_ulong buf, target_ulong len)
686 {
687     GuestFD *gf = get_guestfd(fd);
688 
689     if (gf) {
690         semihost_sys_write_gf(cs, complete, gf, buf, len);
691     } else {
692         complete(cs, -1, EBADF);
693     }
694 }
695 
696 void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
697                         int fd, int64_t off, int gdb_whence)
698 {
699     GuestFD *gf = get_guestfd(fd);
700 
701     if (!gf) {
702         complete(cs, -1, EBADF);
703         return;
704     }
705     switch (gf->type) {
706     case GuestFDGDB:
707         gdb_lseek(cs, complete, gf, off, gdb_whence);
708         return;
709     case GuestFDHost:
710         host_lseek(cs, complete, gf, off, gdb_whence);
711         break;
712     case GuestFDStatic:
713         staticfile_lseek(cs, complete, gf, off, gdb_whence);
714         break;
715     default:
716         g_assert_not_reached();
717     }
718 }
719 
720 void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
721 {
722     GuestFD *gf = get_guestfd(fd);
723 
724     if (!gf) {
725         complete(cs, 0, EBADF);
726         return;
727     }
728     switch (gf->type) {
729     case GuestFDGDB:
730         gdb_isatty(cs, complete, gf);
731         break;
732     case GuestFDHost:
733         host_isatty(cs, complete, gf);
734         break;
735     case GuestFDStatic:
736         complete(cs, 0, ENOTTY);
737         break;
738     default:
739         g_assert_not_reached();
740     }
741 }
742 
743 void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
744                        gdb_syscall_complete_cb flen_cb, int fd,
745                        target_ulong fstat_addr)
746 {
747     GuestFD *gf = get_guestfd(fd);
748 
749     if (!gf) {
750         flen_cb(cs, -1, EBADF);
751         return;
752     }
753     switch (gf->type) {
754     case GuestFDGDB:
755         gdb_fstat(cs, fstat_cb, gf, fstat_addr);
756         break;
757     case GuestFDHost:
758         host_flen(cs, flen_cb, gf);
759         break;
760     case GuestFDStatic:
761         staticfile_flen(cs, flen_cb, gf);
762         break;
763     default:
764         g_assert_not_reached();
765     }
766 }
767 
768 void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
769                         int fd, target_ulong addr)
770 {
771     GuestFD *gf = get_guestfd(fd);
772 
773     if (!gf) {
774         complete(cs, -1, EBADF);
775         return;
776     }
777     switch (gf->type) {
778     case GuestFDGDB:
779         gdb_fstat(cs, complete, gf, addr);
780         break;
781     case GuestFDHost:
782         host_fstat(cs, complete, gf, addr);
783         break;
784     case GuestFDStatic:
785     default:
786         g_assert_not_reached();
787     }
788 }
789 
790 void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
791                        target_ulong fname, target_ulong fname_len,
792                        target_ulong addr)
793 {
794     if (use_gdb_syscalls()) {
795         gdb_stat(cs, complete, fname, fname_len, addr);
796     } else {
797         host_stat(cs, complete, fname, fname_len, addr);
798     }
799 }
800 
801 void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
802                          target_ulong fname, target_ulong fname_len)
803 {
804     if (use_gdb_syscalls()) {
805         gdb_remove(cs, complete, fname, fname_len);
806     } else {
807         host_remove(cs, complete, fname, fname_len);
808     }
809 }
810 
811 void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
812                          target_ulong oname, target_ulong oname_len,
813                          target_ulong nname, target_ulong nname_len)
814 {
815     if (use_gdb_syscalls()) {
816         gdb_rename(cs, complete, oname, oname_len, nname, nname_len);
817     } else {
818         host_rename(cs, complete, oname, oname_len, nname, nname_len);
819     }
820 }
821 
822 void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
823                          target_ulong cmd, target_ulong cmd_len)
824 {
825     if (use_gdb_syscalls()) {
826         gdb_system(cs, complete, cmd, cmd_len);
827     } else {
828         host_system(cs, complete, cmd, cmd_len);
829     }
830 }
831 
832 void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
833                                target_ulong tv_addr, target_ulong tz_addr)
834 {
835     if (use_gdb_syscalls()) {
836         gdb_gettimeofday(cs, complete, tv_addr, tz_addr);
837     } else {
838         host_gettimeofday(cs, complete, tv_addr, tz_addr);
839     }
840 }
841