xref: /openbmc/qemu/semihosting/guestfd.c (revision 5b3f39cb04fda32226e84502f858bab06d83e5c1)
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"
14*5b3f39cbSRichard Henderson #ifdef CONFIG_USER_ONLY
15*5b3f39cbSRichard Henderson #include "qemu.h"
16*5b3f39cbSRichard Henderson #else
17*5b3f39cbSRichard Henderson #include "semihosting/softmmu-uaccess.h"
18*5b3f39cbSRichard 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 
521c6ff720SRichard Henderson /*
531c6ff720SRichard Henderson  * Look up the guestfd in the data structure; return NULL
541c6ff720SRichard Henderson  * for out of bounds, but don't check whether the slot is unused.
551c6ff720SRichard Henderson  * This is used internally by the other guestfd functions.
561c6ff720SRichard Henderson  */
571c6ff720SRichard Henderson static GuestFD *do_get_guestfd(int guestfd)
581c6ff720SRichard Henderson {
591c6ff720SRichard Henderson     if (!guestfd_array) {
601c6ff720SRichard Henderson         return NULL;
611c6ff720SRichard Henderson     }
621c6ff720SRichard Henderson 
631c6ff720SRichard Henderson     if (guestfd <= 0 || guestfd >= guestfd_array->len) {
641c6ff720SRichard Henderson         return NULL;
651c6ff720SRichard Henderson     }
661c6ff720SRichard Henderson 
671c6ff720SRichard Henderson     return &g_array_index(guestfd_array, GuestFD, guestfd);
681c6ff720SRichard Henderson }
691c6ff720SRichard Henderson 
701c6ff720SRichard Henderson /*
711c6ff720SRichard Henderson  * Given a guest file descriptor, get the associated struct.
721c6ff720SRichard Henderson  * If the fd is not valid, return NULL. This is the function
731c6ff720SRichard Henderson  * used by the various semihosting calls to validate a handle
741c6ff720SRichard Henderson  * from the guest.
751c6ff720SRichard Henderson  * Note: calling alloc_guestfd() or dealloc_guestfd() will
761c6ff720SRichard Henderson  * invalidate any GuestFD* obtained by calling this function.
771c6ff720SRichard Henderson  */
781c6ff720SRichard Henderson GuestFD *get_guestfd(int guestfd)
791c6ff720SRichard Henderson {
801c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
811c6ff720SRichard Henderson 
821c6ff720SRichard Henderson     if (!gf || gf->type == GuestFDUnused) {
831c6ff720SRichard Henderson         return NULL;
841c6ff720SRichard Henderson     }
851c6ff720SRichard Henderson     return gf;
861c6ff720SRichard Henderson }
871c6ff720SRichard Henderson 
881c6ff720SRichard Henderson /*
891c6ff720SRichard Henderson  * Associate the specified guest fd (which must have been
901c6ff720SRichard Henderson  * allocated via alloc_fd() and not previously used) with
911c6ff720SRichard Henderson  * the specified host/gdb fd.
921c6ff720SRichard Henderson  */
931c6ff720SRichard Henderson void associate_guestfd(int guestfd, int hostfd)
941c6ff720SRichard Henderson {
951c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
961c6ff720SRichard Henderson 
971c6ff720SRichard Henderson     assert(gf);
981c6ff720SRichard Henderson     gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
991c6ff720SRichard Henderson     gf->hostfd = hostfd;
1001c6ff720SRichard Henderson }
1011c6ff720SRichard Henderson 
1021c6ff720SRichard Henderson void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
1031c6ff720SRichard Henderson {
1041c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1051c6ff720SRichard Henderson 
1061c6ff720SRichard Henderson     assert(gf);
1071c6ff720SRichard Henderson     gf->type = GuestFDStatic;
1081c6ff720SRichard Henderson     gf->staticfile.data = data;
1091c6ff720SRichard Henderson     gf->staticfile.len = len;
1101c6ff720SRichard Henderson     gf->staticfile.off = 0;
1111c6ff720SRichard Henderson }
1121c6ff720SRichard Henderson 
1131c6ff720SRichard Henderson /*
1141c6ff720SRichard Henderson  * Deallocate the specified guest file descriptor. This doesn't
1151c6ff720SRichard Henderson  * close the host fd, it merely undoes the work of alloc_fd().
1161c6ff720SRichard Henderson  */
1171c6ff720SRichard Henderson void dealloc_guestfd(int guestfd)
1181c6ff720SRichard Henderson {
1191c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
1201c6ff720SRichard Henderson 
1211c6ff720SRichard Henderson     assert(gf);
1221c6ff720SRichard Henderson     gf->type = GuestFDUnused;
1231c6ff720SRichard Henderson }
124