]> git.proxmox.com Git - mirror_qemu.git/blame - semihosting/syscalls.c
linux-user/hppa: Increase guest stack size to 80MB for hppa target
[mirror_qemu.git] / semihosting / syscalls.c
CommitLineData
5b3f39cb
RH
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"
008e1475 13#include "semihosting/console.h"
5b3f39cb
RH
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 */
24static 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
52static 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
dffeb775
RH
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 */
73static 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
5b3f39cb
RH
113/*
114 * GDB semihosting syscall implementations.
115 */
116
117static gdb_syscall_complete_cb gdb_open_complete;
118
64c8c6a9 119static void gdb_open_cb(CPUState *cs, uint64_t ret, int err)
5b3f39cb
RH
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
129static 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
5eadbbfc
RH
144static 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
af0484b5
RH
150static 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
aa915bd0
RH
157static 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
9a894704
RH
164static 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
a2212474
RH
171static 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
a6300ed6
RH
177static 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
dffeb775
RH
183static 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
d49e79b8
RH
196static 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
25a95da0
RH
208static 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
90d8e0b0
RH
228static 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
1875dab0
RH
240static 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
5b3f39cb
RH
246/*
247 * Host semihosting syscall implementations.
248 */
249
250static 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
5eadbbfc
RH
292static 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
af0484b5
RH
309static 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
aa915bd0
RH
332static 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
9a894704
RH
348static 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
a2212474
RH
371static 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
a6300ed6
RH
378static 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
dffeb775
RH
390static 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
405static 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
d49e79b8
RH
435static 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
25a95da0
RH
453static 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
90d8e0b0
RH
479static 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
1875dab0
RH
497static 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
1b9177f7
RH
523#ifndef CONFIG_USER_ONLY
524static 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
af0484b5
RH
538/*
539 * Static file semihosting syscall implementations.
540 */
541
542static 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
9a894704
RH
563static 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
a6300ed6
RH
590static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete,
591 GuestFD *gf)
592{
593 complete(cs, gf->staticfile.len, 0);
594}
595
008e1475
RH
596/*
597 * Console semihosting syscall implementations.
598 */
599
600static 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
617static 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);
45704e89 630 unlock_user(ptr, buf, 0);
008e1475
RH
631}
632
633static 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
1b9177f7
RH
646#ifndef CONFIG_USER_ONLY
647static 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
5b3f39cb
RH
674/*
675 * Syscall entry points.
676 */
677
678void 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}
5eadbbfc
RH
688
689void 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:
008e1475 705 case GuestFDConsole:
5eadbbfc
RH
706 complete(cs, 0, 0);
707 break;
708 default:
709 g_assert_not_reached();
710 }
711 dealloc_guestfd(fd);
712}
af0484b5
RH
713
714void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
715 GuestFD *gf, target_ulong buf, target_ulong len)
716{
40f1219a
RH
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 }
af0484b5
RH
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;
008e1475
RH
735 case GuestFDConsole:
736 console_read(cs, complete, gf, buf, len);
737 break;
af0484b5
RH
738 default:
739 g_assert_not_reached();
740 }
741}
742
743void 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}
aa915bd0
RH
754
755void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
756 GuestFD *gf, target_ulong buf, target_ulong len)
757{
40f1219a
RH
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 }
aa915bd0
RH
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;
008e1475
RH
773 case GuestFDConsole:
774 console_write(cs, complete, gf, buf, len);
775 break;
aa915bd0
RH
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
785void 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}
9a894704
RH
796
797void 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;
008e1475
RH
816 case GuestFDConsole:
817 complete(cs, -1, ESPIPE);
818 break;
9a894704
RH
819 default:
820 g_assert_not_reached();
821 }
822}
a2212474
RH
823
824void 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;
008e1475
RH
842 case GuestFDConsole:
843 complete(cs, 1, 0);
844 break;
a2212474
RH
845 default:
846 g_assert_not_reached();
847 }
848}
a6300ed6
RH
849
850void 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;
008e1475 870 case GuestFDConsole:
a6300ed6
RH
871 default:
872 g_assert_not_reached();
873 }
874}
d49e79b8 875
dffeb775
RH
876void 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;
008e1475
RH
892 case GuestFDConsole:
893 console_fstat(cs, complete, gf, addr);
894 break;
dffeb775
RH
895 case GuestFDStatic:
896 default:
897 g_assert_not_reached();
898 }
899}
900
901void 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
d49e79b8
RH
912void 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}
25a95da0
RH
921
922void 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}
90d8e0b0
RH
932
933void 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}
1875dab0
RH
942
943void 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}
1b9177f7
RH
952
953#ifndef CONFIG_USER_ONLY
954void 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