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