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