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