xref: /openbmc/qemu/semihosting/guestfd.c (revision 5eadbbfca6232710036ccb9f5cf1481be537c0e7)
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"
131c6ff720SRichard Henderson #include "semihosting/guestfd.h"
145b3f39cbSRichard Henderson #ifdef CONFIG_USER_ONLY
155b3f39cbSRichard Henderson #include "qemu.h"
165b3f39cbSRichard Henderson #else
175b3f39cbSRichard Henderson #include "semihosting/softmmu-uaccess.h"
185b3f39cbSRichard Henderson #endif
191c6ff720SRichard Henderson 
201c6ff720SRichard Henderson static GArray *guestfd_array;
211c6ff720SRichard Henderson 
221c6ff720SRichard Henderson /*
231c6ff720SRichard Henderson  * Allocate a new guest file descriptor and return it; if we
241c6ff720SRichard Henderson  * couldn't allocate a new fd then return -1.
251c6ff720SRichard Henderson  * This is a fairly simplistic implementation because we don't
261c6ff720SRichard Henderson  * expect that most semihosting guest programs will make very
271c6ff720SRichard Henderson  * heavy use of opening and closing fds.
281c6ff720SRichard Henderson  */
291c6ff720SRichard Henderson int alloc_guestfd(void)
301c6ff720SRichard Henderson {
311c6ff720SRichard Henderson     guint i;
321c6ff720SRichard Henderson 
331c6ff720SRichard Henderson     if (!guestfd_array) {
341c6ff720SRichard Henderson         /* New entries zero-initialized, i.e. type GuestFDUnused */
351c6ff720SRichard Henderson         guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
361c6ff720SRichard Henderson     }
371c6ff720SRichard Henderson 
381c6ff720SRichard Henderson     /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
391c6ff720SRichard Henderson     for (i = 1; i < guestfd_array->len; i++) {
401c6ff720SRichard Henderson         GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
411c6ff720SRichard Henderson 
421c6ff720SRichard Henderson         if (gf->type == GuestFDUnused) {
431c6ff720SRichard Henderson             return i;
441c6ff720SRichard Henderson         }
451c6ff720SRichard Henderson     }
461c6ff720SRichard Henderson 
471c6ff720SRichard Henderson     /* All elements already in use: expand the array */
481c6ff720SRichard Henderson     g_array_set_size(guestfd_array, i + 1);
491c6ff720SRichard Henderson     return i;
501c6ff720SRichard Henderson }
511c6ff720SRichard Henderson 
52*5eadbbfcSRichard Henderson static void do_dealloc_guestfd(GuestFD *gf)
53*5eadbbfcSRichard Henderson {
54*5eadbbfcSRichard Henderson     gf->type = GuestFDUnused;
55*5eadbbfcSRichard Henderson }
56*5eadbbfcSRichard Henderson 
571c6ff720SRichard Henderson /*
581c6ff720SRichard Henderson  * Look up the guestfd in the data structure; return NULL
591c6ff720SRichard Henderson  * for out of bounds, but don't check whether the slot is unused.
601c6ff720SRichard Henderson  * This is used internally by the other guestfd functions.
611c6ff720SRichard Henderson  */
621c6ff720SRichard Henderson static GuestFD *do_get_guestfd(int guestfd)
631c6ff720SRichard Henderson {
641c6ff720SRichard Henderson     if (!guestfd_array) {
651c6ff720SRichard Henderson         return NULL;
661c6ff720SRichard Henderson     }
671c6ff720SRichard Henderson 
681c6ff720SRichard Henderson     if (guestfd <= 0 || guestfd >= guestfd_array->len) {
691c6ff720SRichard Henderson         return NULL;
701c6ff720SRichard Henderson     }
711c6ff720SRichard Henderson 
721c6ff720SRichard Henderson     return &g_array_index(guestfd_array, GuestFD, guestfd);
731c6ff720SRichard Henderson }
741c6ff720SRichard Henderson 
751c6ff720SRichard Henderson /*
761c6ff720SRichard Henderson  * Given a guest file descriptor, get the associated struct.
771c6ff720SRichard Henderson  * If the fd is not valid, return NULL. This is the function
781c6ff720SRichard Henderson  * used by the various semihosting calls to validate a handle
791c6ff720SRichard Henderson  * from the guest.
801c6ff720SRichard Henderson  * Note: calling alloc_guestfd() or dealloc_guestfd() will
811c6ff720SRichard Henderson  * invalidate any GuestFD* obtained by calling this function.
821c6ff720SRichard Henderson  */
831c6ff720SRichard Henderson GuestFD *get_guestfd(int guestfd)
841c6ff720SRichard Henderson {
851c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
861c6ff720SRichard Henderson 
871c6ff720SRichard Henderson     if (!gf || gf->type == GuestFDUnused) {
881c6ff720SRichard Henderson         return NULL;
891c6ff720SRichard Henderson     }
901c6ff720SRichard Henderson     return gf;
911c6ff720SRichard Henderson }
921c6ff720SRichard Henderson 
931c6ff720SRichard Henderson /*
941c6ff720SRichard Henderson  * Associate the specified guest fd (which must have been
951c6ff720SRichard Henderson  * allocated via alloc_fd() and not previously used) with
961c6ff720SRichard Henderson  * the specified host/gdb fd.
971c6ff720SRichard Henderson  */
981c6ff720SRichard Henderson void associate_guestfd(int guestfd, int hostfd)
991c6ff720SRichard Henderson {
1001c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1011c6ff720SRichard Henderson 
1021c6ff720SRichard Henderson     assert(gf);
1031c6ff720SRichard Henderson     gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
1041c6ff720SRichard Henderson     gf->hostfd = hostfd;
1051c6ff720SRichard Henderson }
1061c6ff720SRichard Henderson 
1071c6ff720SRichard Henderson void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
1081c6ff720SRichard Henderson {
1091c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1101c6ff720SRichard Henderson 
1111c6ff720SRichard Henderson     assert(gf);
1121c6ff720SRichard Henderson     gf->type = GuestFDStatic;
1131c6ff720SRichard Henderson     gf->staticfile.data = data;
1141c6ff720SRichard Henderson     gf->staticfile.len = len;
1151c6ff720SRichard Henderson     gf->staticfile.off = 0;
1161c6ff720SRichard Henderson }
1171c6ff720SRichard Henderson 
1181c6ff720SRichard Henderson /*
1191c6ff720SRichard Henderson  * Deallocate the specified guest file descriptor. This doesn't
1201c6ff720SRichard Henderson  * close the host fd, it merely undoes the work of alloc_fd().
1211c6ff720SRichard Henderson  */
1221c6ff720SRichard Henderson void dealloc_guestfd(int guestfd)
1231c6ff720SRichard Henderson {
1241c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1251c6ff720SRichard Henderson 
1261c6ff720SRichard Henderson     assert(gf);
127*5eadbbfcSRichard Henderson     do_dealloc_guestfd(gf);
1281c6ff720SRichard Henderson }
129