2 * Hosted file support for semihosting syscalls.
4 * Copyright (c) 2005, 2007 CodeSourcery.
5 * Copyright (c) 2019 Linaro
6 * Copyright © 2020 by Keith Packard <keithp@keithp.com>
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "qemu/osdep.h"
12 #include "gdbstub/syscalls.h"
13 #include "semihosting/semihost.h"
14 #include "semihosting/guestfd.h"
15 #ifndef CONFIG_USER_ONLY
16 #include CONFIG_DEVICES
19 static GArray
*guestfd_array
;
21 #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
22 GuestFD console_in_gf
;
23 GuestFD console_out_gf
;
26 void qemu_semihosting_guestfd_init(void)
28 /* New entries zero-initialized, i.e. type GuestFDUnused */
29 guestfd_array
= g_array_new(FALSE
, TRUE
, sizeof(GuestFD
));
31 #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
32 /* For ARM-compat, the console is in a separate namespace. */
33 if (use_gdb_syscalls()) {
34 console_in_gf
.type
= GuestFDGDB
;
35 console_in_gf
.hostfd
= 0;
36 console_out_gf
.type
= GuestFDGDB
;
37 console_out_gf
.hostfd
= 2;
39 console_in_gf
.type
= GuestFDConsole
;
40 console_out_gf
.type
= GuestFDConsole
;
43 /* Otherwise, the stdio file descriptors apply. */
44 guestfd_array
= g_array_set_size(guestfd_array
, 3);
45 #ifndef CONFIG_USER_ONLY
46 if (!use_gdb_syscalls()) {
47 GuestFD
*gf
= &g_array_index(guestfd_array
, GuestFD
, 0);
48 gf
[0].type
= GuestFDConsole
;
49 gf
[1].type
= GuestFDConsole
;
50 gf
[2].type
= GuestFDConsole
;
54 associate_guestfd(0, 0);
55 associate_guestfd(1, 1);
56 associate_guestfd(2, 2);
61 * Allocate a new guest file descriptor and return it; if we
62 * couldn't allocate a new fd then return -1.
63 * This is a fairly simplistic implementation because we don't
64 * expect that most semihosting guest programs will make very
65 * heavy use of opening and closing fds.
67 int alloc_guestfd(void)
71 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
72 for (i
= 1; i
< guestfd_array
->len
; i
++) {
73 GuestFD
*gf
= &g_array_index(guestfd_array
, GuestFD
, i
);
75 if (gf
->type
== GuestFDUnused
) {
80 /* All elements already in use: expand the array */
81 g_array_set_size(guestfd_array
, i
+ 1);
85 static void do_dealloc_guestfd(GuestFD
*gf
)
87 gf
->type
= GuestFDUnused
;
91 * Look up the guestfd in the data structure; return NULL
92 * for out of bounds, but don't check whether the slot is unused.
93 * This is used internally by the other guestfd functions.
95 static GuestFD
*do_get_guestfd(int guestfd
)
97 if (guestfd
< 0 || guestfd
>= guestfd_array
->len
) {
101 return &g_array_index(guestfd_array
, GuestFD
, guestfd
);
105 * Given a guest file descriptor, get the associated struct.
106 * If the fd is not valid, return NULL. This is the function
107 * used by the various semihosting calls to validate a handle
109 * Note: calling alloc_guestfd() or dealloc_guestfd() will
110 * invalidate any GuestFD* obtained by calling this function.
112 GuestFD
*get_guestfd(int guestfd
)
114 GuestFD
*gf
= do_get_guestfd(guestfd
);
116 if (!gf
|| gf
->type
== GuestFDUnused
) {
123 * Associate the specified guest fd (which must have been
124 * allocated via alloc_fd() and not previously used) with
125 * the specified host/gdb fd.
127 void associate_guestfd(int guestfd
, int hostfd
)
129 GuestFD
*gf
= do_get_guestfd(guestfd
);
132 gf
->type
= use_gdb_syscalls() ? GuestFDGDB
: GuestFDHost
;
136 void staticfile_guestfd(int guestfd
, const uint8_t *data
, size_t len
)
138 GuestFD
*gf
= do_get_guestfd(guestfd
);
141 gf
->type
= GuestFDStatic
;
142 gf
->staticfile
.data
= data
;
143 gf
->staticfile
.len
= len
;
144 gf
->staticfile
.off
= 0;
148 * Deallocate the specified guest file descriptor. This doesn't
149 * close the host fd, it merely undoes the work of alloc_fd().
151 void dealloc_guestfd(int guestfd
)
153 GuestFD
*gf
= do_get_guestfd(guestfd
);
156 do_dealloc_guestfd(gf
);