xref: /openbmc/qemu/semihosting/syscalls.c (revision 4e245a9e)
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     do {
321         ret = read(gf->hostfd, ptr, len);
322     } while (ret == -1 && errno == EINTR);
323     if (ret == -1) {
324         complete(cs, -1, errno);
325         unlock_user(ptr, buf, 0);
326     } else {
327         complete(cs, ret, 0);
328         unlock_user(ptr, buf, ret);
329     }
330 }
331 
332 static void host_write(CPUState *cs, gdb_syscall_complete_cb complete,
333                        GuestFD *gf, target_ulong buf, target_ulong len)
334 {
335     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
336     void *ptr = lock_user(VERIFY_READ, buf, len, 1);
337     ssize_t ret;
338 
339     if (!ptr) {
340         complete(cs, -1, EFAULT);
341         return;
342     }
343     ret = write(gf->hostfd, ptr, len);
344     complete(cs, ret, ret == -1 ? errno : 0);
345     unlock_user(ptr, buf, 0);
346 }
347 
348 static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
349                        GuestFD *gf, int64_t off, int whence)
350 {
351     /* So far, all hosts use the same values. */
352     QEMU_BUILD_BUG_ON(GDB_SEEK_SET != SEEK_SET);
353     QEMU_BUILD_BUG_ON(GDB_SEEK_CUR != SEEK_CUR);
354     QEMU_BUILD_BUG_ON(GDB_SEEK_END != SEEK_END);
355 
356     off_t ret = off;
357     int err = 0;
358 
359     if (ret == off) {
360         ret = lseek(gf->hostfd, ret, whence);
361         if (ret == -1) {
362             err = errno;
363         }
364     } else {
365         ret = -1;
366         err = EINVAL;
367     }
368     complete(cs, ret, err);
369 }
370 
371 static void host_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
372                         GuestFD *gf)
373 {
374     int ret = isatty(gf->hostfd);
375     complete(cs, ret, ret ? 0 : errno);
376 }
377 
378 static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete,
379                       GuestFD *gf)
380 {
381     struct stat buf;
382 
383     if (fstat(gf->hostfd, &buf) < 0) {
384         complete(cs, -1, errno);
385     } else {
386         complete(cs, buf.st_size, 0);
387     }
388 }
389 
390 static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
391                        GuestFD *gf, target_ulong addr)
392 {
393     struct stat buf;
394     int ret;
395 
396     ret = fstat(gf->hostfd, &buf);
397     if (ret) {
398         complete(cs, -1, errno);
399         return;
400     }
401     ret = copy_stat_to_user(cs, addr, &buf);
402     complete(cs, ret ? -1 : 0, ret ? -ret : 0);
403 }
404 
405 static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete,
406                       target_ulong fname, target_ulong fname_len,
407                       target_ulong addr)
408 {
409     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
410     struct stat buf;
411     char *name;
412     int ret, err;
413 
414     ret = validate_lock_user_string(&name, cs, fname, fname_len);
415     if (ret < 0) {
416         complete(cs, -1, -ret);
417         return;
418     }
419 
420     ret = stat(name, &buf);
421     if (ret) {
422         err = errno;
423     } else {
424         ret = copy_stat_to_user(cs, addr, &buf);
425         err = 0;
426         if (ret < 0) {
427             err = -ret;
428             ret = -1;
429         }
430     }
431     complete(cs, ret, err);
432     unlock_user(name, fname, 0);
433 }
434 
435 static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
436                         target_ulong fname, target_ulong fname_len)
437 {
438     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
439     char *p;
440     int ret;
441 
442     ret = validate_lock_user_string(&p, cs, fname, fname_len);
443     if (ret < 0) {
444         complete(cs, -1, -ret);
445         return;
446     }
447 
448     ret = remove(p);
449     complete(cs, ret, ret ? errno : 0);
450     unlock_user(p, fname, 0);
451 }
452 
453 static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
454                         target_ulong oname, target_ulong oname_len,
455                         target_ulong nname, target_ulong nname_len)
456 {
457     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
458     char *ostr, *nstr;
459     int ret;
460 
461     ret = validate_lock_user_string(&ostr, cs, oname, oname_len);
462     if (ret < 0) {
463         complete(cs, -1, -ret);
464         return;
465     }
466     ret = validate_lock_user_string(&nstr, cs, nname, nname_len);
467     if (ret < 0) {
468         unlock_user(ostr, oname, 0);
469         complete(cs, -1, -ret);
470         return;
471     }
472 
473     ret = rename(ostr, nstr);
474     complete(cs, ret, ret ? errno : 0);
475     unlock_user(ostr, oname, 0);
476     unlock_user(nstr, nname, 0);
477 }
478 
479 static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
480                         target_ulong cmd, target_ulong cmd_len)
481 {
482     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
483     char *p;
484     int ret;
485 
486     ret = validate_lock_user_string(&p, cs, cmd, cmd_len);
487     if (ret < 0) {
488         complete(cs, -1, -ret);
489         return;
490     }
491 
492     ret = system(p);
493     complete(cs, ret, ret == -1 ? errno : 0);
494     unlock_user(p, cmd, 0);
495 }
496 
497 static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
498                               target_ulong tv_addr, target_ulong tz_addr)
499 {
500     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
501     struct gdb_timeval *p;
502     int64_t rt;
503 
504     /* GDB fails on non-null TZ, so be consistent. */
505     if (tz_addr != 0) {
506         complete(cs, -1, EINVAL);
507         return;
508     }
509 
510     p = lock_user(VERIFY_WRITE, tv_addr, sizeof(struct gdb_timeval), 0);
511     if (!p) {
512         complete(cs, -1, EFAULT);
513         return;
514     }
515 
516     /* TODO: Like stat, gdb always produces big-endian results; match it. */
517     rt = g_get_real_time();
518     p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC);
519     p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC);
520     unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
521 }
522 
523 #ifndef CONFIG_USER_ONLY
524 static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
525                           GuestFD *gf, GIOCondition cond, int timeout)
526 {
527     /*
528      * Since this is only used by xtensa in system mode, and stdio is
529      * handled through GuestFDConsole, and there are no semihosting
530      * system calls for sockets and the like, that means this descriptor
531      * must be a normal file.  Normal files never block and are thus
532      * always ready.
533      */
534     complete(cs, cond & (G_IO_IN | G_IO_OUT), 0);
535 }
536 #endif
537 
538 /*
539  * Static file semihosting syscall implementations.
540  */
541 
542 static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete,
543                             GuestFD *gf, target_ulong buf, target_ulong len)
544 {
545     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
546     target_ulong rest = gf->staticfile.len - gf->staticfile.off;
547     void *ptr;
548 
549     if (len > rest) {
550         len = rest;
551     }
552     ptr = lock_user(VERIFY_WRITE, buf, len, 0);
553     if (!ptr) {
554         complete(cs, -1, EFAULT);
555         return;
556     }
557     memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len);
558     gf->staticfile.off += len;
559     complete(cs, len, 0);
560     unlock_user(ptr, buf, len);
561 }
562 
563 static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
564                              GuestFD *gf, int64_t off, int gdb_whence)
565 {
566     int64_t ret;
567 
568     switch (gdb_whence) {
569     case GDB_SEEK_SET:
570         ret = off;
571         break;
572     case GDB_SEEK_CUR:
573         ret = gf->staticfile.off + off;
574         break;
575     case GDB_SEEK_END:
576         ret = gf->staticfile.len + off;
577         break;
578     default:
579         ret = -1;
580         break;
581     }
582     if (ret >= 0 && ret <= gf->staticfile.len) {
583         gf->staticfile.off = ret;
584         complete(cs, ret, 0);
585     } else {
586         complete(cs, -1, EINVAL);
587     }
588 }
589 
590 static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete,
591                             GuestFD *gf)
592 {
593     complete(cs, gf->staticfile.len, 0);
594 }
595 
596 /*
597  * Console semihosting syscall implementations.
598  */
599 
600 static void console_read(CPUState *cs, gdb_syscall_complete_cb complete,
601                          GuestFD *gf, target_ulong buf, target_ulong len)
602 {
603     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
604     char *ptr;
605     int ret;
606 
607     ptr = lock_user(VERIFY_WRITE, buf, len, 0);
608     if (!ptr) {
609         complete(cs, -1, EFAULT);
610         return;
611     }
612     ret = qemu_semihosting_console_read(cs, ptr, len);
613     complete(cs, ret, 0);
614     unlock_user(ptr, buf, ret);
615 }
616 
617 static void console_write(CPUState *cs, gdb_syscall_complete_cb complete,
618                           GuestFD *gf, target_ulong buf, target_ulong len)
619 {
620     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
621     char *ptr = lock_user(VERIFY_READ, buf, len, 1);
622     int ret;
623 
624     if (!ptr) {
625         complete(cs, -1, EFAULT);
626         return;
627     }
628     ret = qemu_semihosting_console_write(ptr, len);
629     complete(cs, ret ? ret : -1, ret ? 0 : EIO);
630     unlock_user(ptr, buf, ret);
631 }
632 
633 static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
634                           GuestFD *gf, target_ulong addr)
635 {
636     static const struct stat tty_buf = {
637         .st_mode = 020666,  /* S_IFCHR, ugo+rw */
638         .st_rdev = 5,       /* makedev(5, 0) -- linux /dev/tty */
639     };
640     int ret;
641 
642     ret = copy_stat_to_user(cs, addr, &tty_buf);
643     complete(cs, ret ? -1 : 0, ret ? -ret : 0);
644 }
645 
646 #ifndef CONFIG_USER_ONLY
647 static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
648                              GuestFD *gf, GIOCondition cond, int timeout)
649 {
650     /* The semihosting console does not support urgent data or errors. */
651     cond &= G_IO_IN | G_IO_OUT;
652 
653     /*
654      * Since qemu_semihosting_console_write never blocks, we can
655      * consider output always ready -- leave G_IO_OUT alone.
656      * All that remains is to conditionally signal input ready.
657      * Since output ready causes an immediate return, only block
658      * for G_IO_IN alone.
659      *
660      * TODO: Implement proper timeout.  For now, only support
661      * indefinite wait or immediate poll.
662      */
663     if (cond == G_IO_IN && timeout < 0) {
664         qemu_semihosting_console_block_until_ready(cs);
665         /* We returned -- input must be ready. */
666     } else if ((cond & G_IO_IN) && !qemu_semihosting_console_ready()) {
667         cond &= ~G_IO_IN;
668     }
669 
670     complete(cs, cond, 0);
671 }
672 #endif
673 
674 /*
675  * Syscall entry points.
676  */
677 
678 void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
679                        target_ulong fname, target_ulong fname_len,
680                        int gdb_flags, int mode)
681 {
682     if (use_gdb_syscalls()) {
683         gdb_open(cs, complete, fname, fname_len, gdb_flags, mode);
684     } else {
685         host_open(cs, complete, fname, fname_len, gdb_flags, mode);
686     }
687 }
688 
689 void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
690 {
691     GuestFD *gf = get_guestfd(fd);
692 
693     if (!gf) {
694         complete(cs, -1, EBADF);
695         return;
696     }
697     switch (gf->type) {
698     case GuestFDGDB:
699         gdb_close(cs, complete, gf);
700         break;
701     case GuestFDHost:
702         host_close(cs, complete, gf);
703         break;
704     case GuestFDStatic:
705     case GuestFDConsole:
706         complete(cs, 0, 0);
707         break;
708     default:
709         g_assert_not_reached();
710     }
711     dealloc_guestfd(fd);
712 }
713 
714 void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
715                           GuestFD *gf, target_ulong buf, target_ulong len)
716 {
717     /*
718      * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t.
719      * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
720      * idea to do this unconditionally.
721      */
722     if (len > INT32_MAX) {
723         len = INT32_MAX;
724     }
725     switch (gf->type) {
726     case GuestFDGDB:
727         gdb_read(cs, complete, gf, buf, len);
728         break;
729     case GuestFDHost:
730         host_read(cs, complete, gf, buf, len);
731         break;
732     case GuestFDStatic:
733         staticfile_read(cs, complete, gf, buf, len);
734         break;
735     case GuestFDConsole:
736         console_read(cs, complete, gf, buf, len);
737         break;
738     default:
739         g_assert_not_reached();
740     }
741 }
742 
743 void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
744                        int fd, target_ulong buf, target_ulong len)
745 {
746     GuestFD *gf = get_guestfd(fd);
747 
748     if (gf) {
749         semihost_sys_read_gf(cs, complete, gf, buf, len);
750     } else {
751         complete(cs, -1, EBADF);
752     }
753 }
754 
755 void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
756                            GuestFD *gf, target_ulong buf, target_ulong len)
757 {
758     /*
759      * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t.
760      * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
761      * idea to do this unconditionally.
762      */
763     if (len > INT32_MAX) {
764         len = INT32_MAX;
765     }
766     switch (gf->type) {
767     case GuestFDGDB:
768         gdb_write(cs, complete, gf, buf, len);
769         break;
770     case GuestFDHost:
771         host_write(cs, complete, gf, buf, len);
772         break;
773     case GuestFDConsole:
774         console_write(cs, complete, gf, buf, len);
775         break;
776     case GuestFDStatic:
777         /* Static files are never open for writing: EBADF. */
778         complete(cs, -1, EBADF);
779         break;
780     default:
781         g_assert_not_reached();
782     }
783 }
784 
785 void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
786                         int fd, target_ulong buf, target_ulong len)
787 {
788     GuestFD *gf = get_guestfd(fd);
789 
790     if (gf) {
791         semihost_sys_write_gf(cs, complete, gf, buf, len);
792     } else {
793         complete(cs, -1, EBADF);
794     }
795 }
796 
797 void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
798                         int fd, int64_t off, int gdb_whence)
799 {
800     GuestFD *gf = get_guestfd(fd);
801 
802     if (!gf) {
803         complete(cs, -1, EBADF);
804         return;
805     }
806     switch (gf->type) {
807     case GuestFDGDB:
808         gdb_lseek(cs, complete, gf, off, gdb_whence);
809         return;
810     case GuestFDHost:
811         host_lseek(cs, complete, gf, off, gdb_whence);
812         break;
813     case GuestFDStatic:
814         staticfile_lseek(cs, complete, gf, off, gdb_whence);
815         break;
816     case GuestFDConsole:
817         complete(cs, -1, ESPIPE);
818         break;
819     default:
820         g_assert_not_reached();
821     }
822 }
823 
824 void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
825 {
826     GuestFD *gf = get_guestfd(fd);
827 
828     if (!gf) {
829         complete(cs, 0, EBADF);
830         return;
831     }
832     switch (gf->type) {
833     case GuestFDGDB:
834         gdb_isatty(cs, complete, gf);
835         break;
836     case GuestFDHost:
837         host_isatty(cs, complete, gf);
838         break;
839     case GuestFDStatic:
840         complete(cs, 0, ENOTTY);
841         break;
842     case GuestFDConsole:
843         complete(cs, 1, 0);
844         break;
845     default:
846         g_assert_not_reached();
847     }
848 }
849 
850 void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
851                        gdb_syscall_complete_cb flen_cb, int fd,
852                        target_ulong fstat_addr)
853 {
854     GuestFD *gf = get_guestfd(fd);
855 
856     if (!gf) {
857         flen_cb(cs, -1, EBADF);
858         return;
859     }
860     switch (gf->type) {
861     case GuestFDGDB:
862         gdb_fstat(cs, fstat_cb, gf, fstat_addr);
863         break;
864     case GuestFDHost:
865         host_flen(cs, flen_cb, gf);
866         break;
867     case GuestFDStatic:
868         staticfile_flen(cs, flen_cb, gf);
869         break;
870     case GuestFDConsole:
871     default:
872         g_assert_not_reached();
873     }
874 }
875 
876 void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
877                         int fd, target_ulong addr)
878 {
879     GuestFD *gf = get_guestfd(fd);
880 
881     if (!gf) {
882         complete(cs, -1, EBADF);
883         return;
884     }
885     switch (gf->type) {
886     case GuestFDGDB:
887         gdb_fstat(cs, complete, gf, addr);
888         break;
889     case GuestFDHost:
890         host_fstat(cs, complete, gf, addr);
891         break;
892     case GuestFDConsole:
893         console_fstat(cs, complete, gf, addr);
894         break;
895     case GuestFDStatic:
896     default:
897         g_assert_not_reached();
898     }
899 }
900 
901 void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
902                        target_ulong fname, target_ulong fname_len,
903                        target_ulong addr)
904 {
905     if (use_gdb_syscalls()) {
906         gdb_stat(cs, complete, fname, fname_len, addr);
907     } else {
908         host_stat(cs, complete, fname, fname_len, addr);
909     }
910 }
911 
912 void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
913                          target_ulong fname, target_ulong fname_len)
914 {
915     if (use_gdb_syscalls()) {
916         gdb_remove(cs, complete, fname, fname_len);
917     } else {
918         host_remove(cs, complete, fname, fname_len);
919     }
920 }
921 
922 void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
923                          target_ulong oname, target_ulong oname_len,
924                          target_ulong nname, target_ulong nname_len)
925 {
926     if (use_gdb_syscalls()) {
927         gdb_rename(cs, complete, oname, oname_len, nname, nname_len);
928     } else {
929         host_rename(cs, complete, oname, oname_len, nname, nname_len);
930     }
931 }
932 
933 void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
934                          target_ulong cmd, target_ulong cmd_len)
935 {
936     if (use_gdb_syscalls()) {
937         gdb_system(cs, complete, cmd, cmd_len);
938     } else {
939         host_system(cs, complete, cmd, cmd_len);
940     }
941 }
942 
943 void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
944                                target_ulong tv_addr, target_ulong tz_addr)
945 {
946     if (use_gdb_syscalls()) {
947         gdb_gettimeofday(cs, complete, tv_addr, tz_addr);
948     } else {
949         host_gettimeofday(cs, complete, tv_addr, tz_addr);
950     }
951 }
952 
953 #ifndef CONFIG_USER_ONLY
954 void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
955                            int fd, GIOCondition cond, int timeout)
956 {
957     GuestFD *gf = get_guestfd(fd);
958 
959     if (!gf) {
960         complete(cs, G_IO_NVAL, 1);
961         return;
962     }
963     switch (gf->type) {
964     case GuestFDGDB:
965         complete(cs, G_IO_NVAL, 1);
966         break;
967     case GuestFDHost:
968         host_poll_one(cs, complete, gf, cond, timeout);
969         break;
970     case GuestFDConsole:
971         console_poll_one(cs, complete, gf, cond, timeout);
972         break;
973     case GuestFDStatic:
974     default:
975         g_assert_not_reached();
976     }
977 }
978 #endif
979