xref: /openbmc/qemu/semihosting/guestfd.c (revision e4a4aaa51b4c71914a6f30ca504ab78e8f695aee)
11c6ff720SRichard Henderson /*
21c6ff720SRichard Henderson  * Hosted file support for semihosting syscalls.
31c6ff720SRichard Henderson  *
41c6ff720SRichard Henderson  * Copyright (c) 2005, 2007 CodeSourcery.
51c6ff720SRichard Henderson  * Copyright (c) 2019 Linaro
61c6ff720SRichard Henderson  * Copyright © 2020 by Keith Packard <keithp@keithp.com>
71c6ff720SRichard Henderson  *
81c6ff720SRichard Henderson  * SPDX-License-Identifier: GPL-2.0-or-later
91c6ff720SRichard Henderson  */
101c6ff720SRichard Henderson 
111c6ff720SRichard Henderson #include "qemu/osdep.h"
121c6ff720SRichard Henderson #include "exec/gdbstub.h"
13*e4a4aaa5SRichard Henderson #include "semihosting/semihost.h"
141c6ff720SRichard Henderson #include "semihosting/guestfd.h"
155b3f39cbSRichard Henderson #ifdef CONFIG_USER_ONLY
165b3f39cbSRichard Henderson #include "qemu.h"
175b3f39cbSRichard Henderson #else
185b3f39cbSRichard Henderson #include "semihosting/softmmu-uaccess.h"
19*e4a4aaa5SRichard Henderson #include CONFIG_DEVICES
205b3f39cbSRichard Henderson #endif
211c6ff720SRichard Henderson 
221c6ff720SRichard Henderson static GArray *guestfd_array;
231c6ff720SRichard Henderson 
24*e4a4aaa5SRichard Henderson #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
25*e4a4aaa5SRichard Henderson GuestFD console_in_gf;
26*e4a4aaa5SRichard Henderson GuestFD console_out_gf;
27*e4a4aaa5SRichard Henderson #endif
28*e4a4aaa5SRichard Henderson 
29*e4a4aaa5SRichard Henderson void qemu_semihosting_guestfd_init(void)
30*e4a4aaa5SRichard Henderson {
31*e4a4aaa5SRichard Henderson     /* New entries zero-initialized, i.e. type GuestFDUnused */
32*e4a4aaa5SRichard Henderson     guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
33*e4a4aaa5SRichard Henderson 
34*e4a4aaa5SRichard Henderson #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
35*e4a4aaa5SRichard Henderson     /* For ARM-compat, the console is in a separate namespace. */
36*e4a4aaa5SRichard Henderson     if (use_gdb_syscalls()) {
37*e4a4aaa5SRichard Henderson         console_in_gf.type = GuestFDGDB;
38*e4a4aaa5SRichard Henderson         console_in_gf.hostfd = 0;
39*e4a4aaa5SRichard Henderson         console_out_gf.type = GuestFDGDB;
40*e4a4aaa5SRichard Henderson         console_out_gf.hostfd = 2;
41*e4a4aaa5SRichard Henderson     } else {
42*e4a4aaa5SRichard Henderson         console_in_gf.type = GuestFDConsole;
43*e4a4aaa5SRichard Henderson         console_out_gf.type = GuestFDConsole;
44*e4a4aaa5SRichard Henderson     }
45*e4a4aaa5SRichard Henderson #else
46*e4a4aaa5SRichard Henderson     /* Otherwise, the stdio file descriptors apply. */
47*e4a4aaa5SRichard Henderson     guestfd_array = g_array_set_size(guestfd_array, 3);
48*e4a4aaa5SRichard Henderson #ifndef CONFIG_USER_ONLY
49*e4a4aaa5SRichard Henderson     if (!use_gdb_syscalls()) {
50*e4a4aaa5SRichard Henderson         GuestFD *gf = &g_array_index(guestfd_array, GuestFD, 0);
51*e4a4aaa5SRichard Henderson         gf[0].type = GuestFDConsole;
52*e4a4aaa5SRichard Henderson         gf[1].type = GuestFDConsole;
53*e4a4aaa5SRichard Henderson         gf[2].type = GuestFDConsole;
54*e4a4aaa5SRichard Henderson         return;
55*e4a4aaa5SRichard Henderson     }
56*e4a4aaa5SRichard Henderson #endif
57*e4a4aaa5SRichard Henderson     associate_guestfd(0, 0);
58*e4a4aaa5SRichard Henderson     associate_guestfd(1, 1);
59*e4a4aaa5SRichard Henderson     associate_guestfd(2, 2);
60*e4a4aaa5SRichard Henderson #endif
61*e4a4aaa5SRichard Henderson }
62*e4a4aaa5SRichard Henderson 
631c6ff720SRichard Henderson /*
641c6ff720SRichard Henderson  * Allocate a new guest file descriptor and return it; if we
651c6ff720SRichard Henderson  * couldn't allocate a new fd then return -1.
661c6ff720SRichard Henderson  * This is a fairly simplistic implementation because we don't
671c6ff720SRichard Henderson  * expect that most semihosting guest programs will make very
681c6ff720SRichard Henderson  * heavy use of opening and closing fds.
691c6ff720SRichard Henderson  */
701c6ff720SRichard Henderson int alloc_guestfd(void)
711c6ff720SRichard Henderson {
721c6ff720SRichard Henderson     guint i;
731c6ff720SRichard Henderson 
741c6ff720SRichard Henderson     /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
751c6ff720SRichard Henderson     for (i = 1; i < guestfd_array->len; i++) {
761c6ff720SRichard Henderson         GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
771c6ff720SRichard Henderson 
781c6ff720SRichard Henderson         if (gf->type == GuestFDUnused) {
791c6ff720SRichard Henderson             return i;
801c6ff720SRichard Henderson         }
811c6ff720SRichard Henderson     }
821c6ff720SRichard Henderson 
831c6ff720SRichard Henderson     /* All elements already in use: expand the array */
841c6ff720SRichard Henderson     g_array_set_size(guestfd_array, i + 1);
851c6ff720SRichard Henderson     return i;
861c6ff720SRichard Henderson }
871c6ff720SRichard Henderson 
885eadbbfcSRichard Henderson static void do_dealloc_guestfd(GuestFD *gf)
895eadbbfcSRichard Henderson {
905eadbbfcSRichard Henderson     gf->type = GuestFDUnused;
915eadbbfcSRichard Henderson }
925eadbbfcSRichard Henderson 
931c6ff720SRichard Henderson /*
941c6ff720SRichard Henderson  * Look up the guestfd in the data structure; return NULL
951c6ff720SRichard Henderson  * for out of bounds, but don't check whether the slot is unused.
961c6ff720SRichard Henderson  * This is used internally by the other guestfd functions.
971c6ff720SRichard Henderson  */
981c6ff720SRichard Henderson static GuestFD *do_get_guestfd(int guestfd)
991c6ff720SRichard Henderson {
100*e4a4aaa5SRichard Henderson     if (guestfd < 0 || guestfd >= guestfd_array->len) {
1011c6ff720SRichard Henderson         return NULL;
1021c6ff720SRichard Henderson     }
1031c6ff720SRichard Henderson 
1041c6ff720SRichard Henderson     return &g_array_index(guestfd_array, GuestFD, guestfd);
1051c6ff720SRichard Henderson }
1061c6ff720SRichard Henderson 
1071c6ff720SRichard Henderson /*
1081c6ff720SRichard Henderson  * Given a guest file descriptor, get the associated struct.
1091c6ff720SRichard Henderson  * If the fd is not valid, return NULL. This is the function
1101c6ff720SRichard Henderson  * used by the various semihosting calls to validate a handle
1111c6ff720SRichard Henderson  * from the guest.
1121c6ff720SRichard Henderson  * Note: calling alloc_guestfd() or dealloc_guestfd() will
1131c6ff720SRichard Henderson  * invalidate any GuestFD* obtained by calling this function.
1141c6ff720SRichard Henderson  */
1151c6ff720SRichard Henderson GuestFD *get_guestfd(int guestfd)
1161c6ff720SRichard Henderson {
1171c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1181c6ff720SRichard Henderson 
1191c6ff720SRichard Henderson     if (!gf || gf->type == GuestFDUnused) {
1201c6ff720SRichard Henderson         return NULL;
1211c6ff720SRichard Henderson     }
1221c6ff720SRichard Henderson     return gf;
1231c6ff720SRichard Henderson }
1241c6ff720SRichard Henderson 
1251c6ff720SRichard Henderson /*
1261c6ff720SRichard Henderson  * Associate the specified guest fd (which must have been
1271c6ff720SRichard Henderson  * allocated via alloc_fd() and not previously used) with
1281c6ff720SRichard Henderson  * the specified host/gdb fd.
1291c6ff720SRichard Henderson  */
1301c6ff720SRichard Henderson void associate_guestfd(int guestfd, int hostfd)
1311c6ff720SRichard Henderson {
1321c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1331c6ff720SRichard Henderson 
1341c6ff720SRichard Henderson     assert(gf);
1351c6ff720SRichard Henderson     gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
1361c6ff720SRichard Henderson     gf->hostfd = hostfd;
1371c6ff720SRichard Henderson }
1381c6ff720SRichard Henderson 
1391c6ff720SRichard Henderson void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
1401c6ff720SRichard Henderson {
1411c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1421c6ff720SRichard Henderson 
1431c6ff720SRichard Henderson     assert(gf);
1441c6ff720SRichard Henderson     gf->type = GuestFDStatic;
1451c6ff720SRichard Henderson     gf->staticfile.data = data;
1461c6ff720SRichard Henderson     gf->staticfile.len = len;
1471c6ff720SRichard Henderson     gf->staticfile.off = 0;
1481c6ff720SRichard Henderson }
1491c6ff720SRichard Henderson 
1501c6ff720SRichard Henderson /*
1511c6ff720SRichard Henderson  * Deallocate the specified guest file descriptor. This doesn't
1521c6ff720SRichard Henderson  * close the host fd, it merely undoes the work of alloc_fd().
1531c6ff720SRichard Henderson  */
1541c6ff720SRichard Henderson void dealloc_guestfd(int guestfd)
1551c6ff720SRichard Henderson {
1561c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1571c6ff720SRichard Henderson 
1581c6ff720SRichard Henderson     assert(gf);
1595eadbbfcSRichard Henderson     do_dealloc_guestfd(gf);
1601c6ff720SRichard Henderson }
161