]> git.proxmox.com Git - mirror_qemu.git/blame - semihosting/guestfd.c
ci: Add a migration compatibility test job
[mirror_qemu.git] / semihosting / guestfd.c
CommitLineData
1c6ff720
RH
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"
c566080c 12#include "gdbstub/syscalls.h"
e4a4aaa5 13#include "semihosting/semihost.h"
1c6ff720 14#include "semihosting/guestfd.h"
5b3f39cb
RH
15#ifdef CONFIG_USER_ONLY
16#include "qemu.h"
17#else
f14eced5 18#include "semihosting/uaccess.h"
e4a4aaa5 19#include CONFIG_DEVICES
5b3f39cb 20#endif
1c6ff720
RH
21
22static GArray *guestfd_array;
23
e4a4aaa5
RH
24#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
25GuestFD console_in_gf;
26GuestFD console_out_gf;
27#endif
28
29void qemu_semihosting_guestfd_init(void)
30{
31 /* New entries zero-initialized, i.e. type GuestFDUnused */
32 guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
33
34#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
35 /* For ARM-compat, the console is in a separate namespace. */
36 if (use_gdb_syscalls()) {
37 console_in_gf.type = GuestFDGDB;
38 console_in_gf.hostfd = 0;
39 console_out_gf.type = GuestFDGDB;
40 console_out_gf.hostfd = 2;
41 } else {
42 console_in_gf.type = GuestFDConsole;
43 console_out_gf.type = GuestFDConsole;
44 }
45#else
46 /* Otherwise, the stdio file descriptors apply. */
47 guestfd_array = g_array_set_size(guestfd_array, 3);
48#ifndef CONFIG_USER_ONLY
49 if (!use_gdb_syscalls()) {
50 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, 0);
51 gf[0].type = GuestFDConsole;
52 gf[1].type = GuestFDConsole;
53 gf[2].type = GuestFDConsole;
54 return;
55 }
56#endif
57 associate_guestfd(0, 0);
58 associate_guestfd(1, 1);
59 associate_guestfd(2, 2);
60#endif
61}
62
1c6ff720
RH
63/*
64 * Allocate a new guest file descriptor and return it; if we
65 * couldn't allocate a new fd then return -1.
66 * This is a fairly simplistic implementation because we don't
67 * expect that most semihosting guest programs will make very
68 * heavy use of opening and closing fds.
69 */
70int alloc_guestfd(void)
71{
72 guint i;
73
1c6ff720
RH
74 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
75 for (i = 1; i < guestfd_array->len; i++) {
76 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
77
78 if (gf->type == GuestFDUnused) {
79 return i;
80 }
81 }
82
83 /* All elements already in use: expand the array */
84 g_array_set_size(guestfd_array, i + 1);
85 return i;
86}
87
5eadbbfc
RH
88static void do_dealloc_guestfd(GuestFD *gf)
89{
90 gf->type = GuestFDUnused;
91}
92
1c6ff720
RH
93/*
94 * Look up the guestfd in the data structure; return NULL
95 * for out of bounds, but don't check whether the slot is unused.
96 * This is used internally by the other guestfd functions.
97 */
98static GuestFD *do_get_guestfd(int guestfd)
99{
e4a4aaa5 100 if (guestfd < 0 || guestfd >= guestfd_array->len) {
1c6ff720
RH
101 return NULL;
102 }
103
104 return &g_array_index(guestfd_array, GuestFD, guestfd);
105}
106
107/*
108 * Given a guest file descriptor, get the associated struct.
109 * If the fd is not valid, return NULL. This is the function
110 * used by the various semihosting calls to validate a handle
111 * from the guest.
112 * Note: calling alloc_guestfd() or dealloc_guestfd() will
113 * invalidate any GuestFD* obtained by calling this function.
114 */
115GuestFD *get_guestfd(int guestfd)
116{
117 GuestFD *gf = do_get_guestfd(guestfd);
118
119 if (!gf || gf->type == GuestFDUnused) {
120 return NULL;
121 }
122 return gf;
123}
124
125/*
126 * Associate the specified guest fd (which must have been
127 * allocated via alloc_fd() and not previously used) with
128 * the specified host/gdb fd.
129 */
130void associate_guestfd(int guestfd, int hostfd)
131{
132 GuestFD *gf = do_get_guestfd(guestfd);
133
134 assert(gf);
135 gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
136 gf->hostfd = hostfd;
137}
138
139void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
140{
141 GuestFD *gf = do_get_guestfd(guestfd);
142
143 assert(gf);
144 gf->type = GuestFDStatic;
145 gf->staticfile.data = data;
146 gf->staticfile.len = len;
147 gf->staticfile.off = 0;
148}
149
150/*
151 * Deallocate the specified guest file descriptor. This doesn't
152 * close the host fd, it merely undoes the work of alloc_fd().
153 */
154void dealloc_guestfd(int guestfd)
155{
156 GuestFD *gf = do_get_guestfd(guestfd);
157
158 assert(gf);
5eadbbfc 159 do_dealloc_guestfd(gf);
1c6ff720 160}