xref: /openbmc/qemu/semihosting/guestfd.c (revision 1c6ff7205bff49870dc3511f237b3ad90da5f5f7)
1*1c6ff720SRichard Henderson /*
2*1c6ff720SRichard Henderson  * Hosted file support for semihosting syscalls.
3*1c6ff720SRichard Henderson  *
4*1c6ff720SRichard Henderson  * Copyright (c) 2005, 2007 CodeSourcery.
5*1c6ff720SRichard Henderson  * Copyright (c) 2019 Linaro
6*1c6ff720SRichard Henderson  * Copyright © 2020 by Keith Packard <keithp@keithp.com>
7*1c6ff720SRichard Henderson  *
8*1c6ff720SRichard Henderson  * SPDX-License-Identifier: GPL-2.0-or-later
9*1c6ff720SRichard Henderson  */
10*1c6ff720SRichard Henderson 
11*1c6ff720SRichard Henderson #include "qemu/osdep.h"
12*1c6ff720SRichard Henderson #include "exec/gdbstub.h"
13*1c6ff720SRichard Henderson #include "semihosting/guestfd.h"
14*1c6ff720SRichard Henderson 
15*1c6ff720SRichard Henderson static GArray *guestfd_array;
16*1c6ff720SRichard Henderson 
17*1c6ff720SRichard Henderson /*
18*1c6ff720SRichard Henderson  * Allocate a new guest file descriptor and return it; if we
19*1c6ff720SRichard Henderson  * couldn't allocate a new fd then return -1.
20*1c6ff720SRichard Henderson  * This is a fairly simplistic implementation because we don't
21*1c6ff720SRichard Henderson  * expect that most semihosting guest programs will make very
22*1c6ff720SRichard Henderson  * heavy use of opening and closing fds.
23*1c6ff720SRichard Henderson  */
24*1c6ff720SRichard Henderson int alloc_guestfd(void)
25*1c6ff720SRichard Henderson {
26*1c6ff720SRichard Henderson     guint i;
27*1c6ff720SRichard Henderson 
28*1c6ff720SRichard Henderson     if (!guestfd_array) {
29*1c6ff720SRichard Henderson         /* New entries zero-initialized, i.e. type GuestFDUnused */
30*1c6ff720SRichard Henderson         guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
31*1c6ff720SRichard Henderson     }
32*1c6ff720SRichard Henderson 
33*1c6ff720SRichard Henderson     /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
34*1c6ff720SRichard Henderson     for (i = 1; i < guestfd_array->len; i++) {
35*1c6ff720SRichard Henderson         GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
36*1c6ff720SRichard Henderson 
37*1c6ff720SRichard Henderson         if (gf->type == GuestFDUnused) {
38*1c6ff720SRichard Henderson             return i;
39*1c6ff720SRichard Henderson         }
40*1c6ff720SRichard Henderson     }
41*1c6ff720SRichard Henderson 
42*1c6ff720SRichard Henderson     /* All elements already in use: expand the array */
43*1c6ff720SRichard Henderson     g_array_set_size(guestfd_array, i + 1);
44*1c6ff720SRichard Henderson     return i;
45*1c6ff720SRichard Henderson }
46*1c6ff720SRichard Henderson 
47*1c6ff720SRichard Henderson /*
48*1c6ff720SRichard Henderson  * Look up the guestfd in the data structure; return NULL
49*1c6ff720SRichard Henderson  * for out of bounds, but don't check whether the slot is unused.
50*1c6ff720SRichard Henderson  * This is used internally by the other guestfd functions.
51*1c6ff720SRichard Henderson  */
52*1c6ff720SRichard Henderson static GuestFD *do_get_guestfd(int guestfd)
53*1c6ff720SRichard Henderson {
54*1c6ff720SRichard Henderson     if (!guestfd_array) {
55*1c6ff720SRichard Henderson         return NULL;
56*1c6ff720SRichard Henderson     }
57*1c6ff720SRichard Henderson 
58*1c6ff720SRichard Henderson     if (guestfd <= 0 || guestfd >= guestfd_array->len) {
59*1c6ff720SRichard Henderson         return NULL;
60*1c6ff720SRichard Henderson     }
61*1c6ff720SRichard Henderson 
62*1c6ff720SRichard Henderson     return &g_array_index(guestfd_array, GuestFD, guestfd);
63*1c6ff720SRichard Henderson }
64*1c6ff720SRichard Henderson 
65*1c6ff720SRichard Henderson /*
66*1c6ff720SRichard Henderson  * Given a guest file descriptor, get the associated struct.
67*1c6ff720SRichard Henderson  * If the fd is not valid, return NULL. This is the function
68*1c6ff720SRichard Henderson  * used by the various semihosting calls to validate a handle
69*1c6ff720SRichard Henderson  * from the guest.
70*1c6ff720SRichard Henderson  * Note: calling alloc_guestfd() or dealloc_guestfd() will
71*1c6ff720SRichard Henderson  * invalidate any GuestFD* obtained by calling this function.
72*1c6ff720SRichard Henderson  */
73*1c6ff720SRichard Henderson GuestFD *get_guestfd(int guestfd)
74*1c6ff720SRichard Henderson {
75*1c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
76*1c6ff720SRichard Henderson 
77*1c6ff720SRichard Henderson     if (!gf || gf->type == GuestFDUnused) {
78*1c6ff720SRichard Henderson         return NULL;
79*1c6ff720SRichard Henderson     }
80*1c6ff720SRichard Henderson     return gf;
81*1c6ff720SRichard Henderson }
82*1c6ff720SRichard Henderson 
83*1c6ff720SRichard Henderson /*
84*1c6ff720SRichard Henderson  * Associate the specified guest fd (which must have been
85*1c6ff720SRichard Henderson  * allocated via alloc_fd() and not previously used) with
86*1c6ff720SRichard Henderson  * the specified host/gdb fd.
87*1c6ff720SRichard Henderson  */
88*1c6ff720SRichard Henderson void associate_guestfd(int guestfd, int hostfd)
89*1c6ff720SRichard Henderson {
90*1c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
91*1c6ff720SRichard Henderson 
92*1c6ff720SRichard Henderson     assert(gf);
93*1c6ff720SRichard Henderson     gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
94*1c6ff720SRichard Henderson     gf->hostfd = hostfd;
95*1c6ff720SRichard Henderson }
96*1c6ff720SRichard Henderson 
97*1c6ff720SRichard Henderson void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
98*1c6ff720SRichard Henderson {
99*1c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
100*1c6ff720SRichard Henderson 
101*1c6ff720SRichard Henderson     assert(gf);
102*1c6ff720SRichard Henderson     gf->type = GuestFDStatic;
103*1c6ff720SRichard Henderson     gf->staticfile.data = data;
104*1c6ff720SRichard Henderson     gf->staticfile.len = len;
105*1c6ff720SRichard Henderson     gf->staticfile.off = 0;
106*1c6ff720SRichard Henderson }
107*1c6ff720SRichard Henderson 
108*1c6ff720SRichard Henderson /*
109*1c6ff720SRichard Henderson  * Deallocate the specified guest file descriptor. This doesn't
110*1c6ff720SRichard Henderson  * close the host fd, it merely undoes the work of alloc_fd().
111*1c6ff720SRichard Henderson  */
112*1c6ff720SRichard Henderson void dealloc_guestfd(int guestfd)
113*1c6ff720SRichard Henderson {
114*1c6ff720SRichard Henderson     GuestFD *gf = do_get_guestfd(guestfd);
115*1c6ff720SRichard Henderson 
116*1c6ff720SRichard Henderson     assert(gf);
117*1c6ff720SRichard Henderson     gf->type = GuestFDUnused;
118*1c6ff720SRichard Henderson }
119