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