summaryrefslogtreecommitdiffstats
path: root/semihosting
diff options
context:
space:
mode:
authorRichard Henderson2022-04-28 06:38:02 +0200
committerRichard Henderson2022-06-28 01:05:07 +0200
commit1c6ff7205bff49870dc3511f237b3ad90da5f5f7 (patch)
tree0819760edaf7d88f6c43b3a040a861cab40e6cdb /semihosting
parentsemihosting: Simplify softmmu_lock_user_string (diff)
downloadqemu-1c6ff7205bff49870dc3511f237b3ad90da5f5f7.tar.gz
qemu-1c6ff7205bff49870dc3511f237b3ad90da5f5f7.tar.xz
qemu-1c6ff7205bff49870dc3511f237b3ad90da5f5f7.zip
semihosting: Split out guestfd.c
In arm-compat-semi.c, we have more advanced treatment of guest file descriptors than we do in other implementations. Split out GuestFD and related functions to a new file so that they can be shared. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'semihosting')
-rw-r--r--semihosting/arm-compat-semi.c164
-rw-r--r--semihosting/guestfd.c118
-rw-r--r--semihosting/meson.build4
3 files changed, 144 insertions, 142 deletions
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 1033e751ef..2fa7f23d8b 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -32,12 +32,13 @@
*/
#include "qemu/osdep.h"
-
#include "semihosting/semihost.h"
#include "semihosting/console.h"
#include "semihosting/common-semi.h"
+#include "semihosting/guestfd.h"
#include "qemu/timer.h"
#include "exec/gdbstub.h"
+
#ifdef CONFIG_USER_ONLY
#include "qemu.h"
@@ -123,27 +124,6 @@ static int open_modeflags[12] = {
O_RDWR | O_CREAT | O_APPEND | O_BINARY
};
-typedef enum GuestFDType {
- GuestFDUnused = 0,
- GuestFDHost = 1,
- GuestFDGDB = 2,
- GuestFDFeatureFile = 3,
-} GuestFDType;
-
-/*
- * Guest file descriptors are integer indexes into an array of
- * these structures (we will dynamically resize as necessary).
- */
-typedef struct GuestFD {
- GuestFDType type;
- union {
- int hostfd;
- target_ulong featurefile_offset;
- };
-} GuestFD;
-
-static GArray *guestfd_array;
-
#ifndef CONFIG_USER_ONLY
/**
@@ -269,98 +249,6 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
#endif
/*
- * 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.
- */
-static 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;
-}
-
-/*
- * 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);
-}
-
-/*
- * Associate the specified guest fd (which must have been
- * allocated via alloc_fd() and not previously used) with
- * the specified host/gdb fd.
- */
-static 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;
-}
-
-/*
- * Deallocate the specified guest file descriptor. This doesn't
- * close the host fd, it merely undoes the work of alloc_fd().
- */
-static void dealloc_guestfd(int guestfd)
-{
- GuestFD *gf = do_get_guestfd(guestfd);
-
- assert(gf);
- gf->type = GuestFDUnused;
-}
-
-/*
- * 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.
- */
-static GuestFD *get_guestfd(int guestfd)
-{
- GuestFD *gf = do_get_guestfd(guestfd);
-
- if (!gf || gf->type == GuestFDUnused) {
- return NULL;
- }
- return gf;
-}
-
-/*
* The semihosting API has no concept of its errno being thread-safe,
* as the API design predates SMP CPUs and was intended as a simple
* real-hardware set of debug functionality. For QEMU, we make the
@@ -665,22 +553,13 @@ static const uint8_t featurefile_data[] = {
SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
};
-static void init_featurefile_guestfd(int guestfd)
-{
- GuestFD *gf = do_get_guestfd(guestfd);
-
- assert(gf);
- gf->type = GuestFDFeatureFile;
- gf->featurefile_offset = 0;
-}
-
-static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf)
+static uint32_t staticfile_closefn(CPUState *cs, GuestFD *gf)
{
/* Nothing to do */
return 0;
}
-static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf,
+static uint32_t staticfile_writefn(CPUState *cs, GuestFD *gf,
target_ulong buf, uint32_t len)
{
/* This fd can never be open for writing */
@@ -689,7 +568,7 @@ static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf,
return set_swi_errno(cs, -1);
}
-static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
+static uint32_t staticfile_readfn(CPUState *cs, GuestFD *gf,
target_ulong buf, uint32_t len)
{
CPUArchState *env = cs->env_ptr;
@@ -703,11 +582,11 @@ static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
}
for (i = 0; i < len; i++) {
- if (gf->featurefile_offset >= sizeof(featurefile_data)) {
+ if (gf->staticfile.off >= gf->staticfile.len) {
break;
}
- s[i] = featurefile_data[gf->featurefile_offset];
- gf->featurefile_offset++;
+ s[i] = gf->staticfile.data[gf->staticfile.off];
+ gf->staticfile.off++;
}
unlock_user(s, buf, len);
@@ -716,21 +595,21 @@ static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
return len - i;
}
-static uint32_t featurefile_isattyfn(CPUState *cs, GuestFD *gf)
+static uint32_t staticfile_isattyfn(CPUState *cs, GuestFD *gf)
{
return 0;
}
-static uint32_t featurefile_seekfn(CPUState *cs, GuestFD *gf,
+static uint32_t staticfile_seekfn(CPUState *cs, GuestFD *gf,
target_ulong offset)
{
- gf->featurefile_offset = offset;
+ gf->staticfile.off = offset;
return 0;
}
-static uint32_t featurefile_flenfn(CPUState *cs, GuestFD *gf)
+static uint32_t staticfile_flenfn(CPUState *cs, GuestFD *gf)
{
- return sizeof(featurefile_data);
+ return gf->staticfile.len;
}
typedef struct GuestFDFunctions {
@@ -759,13 +638,13 @@ static const GuestFDFunctions guestfd_fns[] = {
.seekfn = gdb_seekfn,
.flenfn = gdb_flenfn,
},
- [GuestFDFeatureFile] = {
- .closefn = featurefile_closefn,
- .writefn = featurefile_writefn,
- .readfn = featurefile_readfn,
- .isattyfn = featurefile_isattyfn,
- .seekfn = featurefile_seekfn,
- .flenfn = featurefile_flenfn,
+ [GuestFDStatic] = {
+ .closefn = staticfile_closefn,
+ .writefn = staticfile_writefn,
+ .readfn = staticfile_readfn,
+ .isattyfn = staticfile_isattyfn,
+ .seekfn = staticfile_seekfn,
+ .flenfn = staticfile_flenfn,
},
};
@@ -886,7 +765,8 @@ target_ulong do_common_semihosting(CPUState *cs)
errno = EACCES;
return set_swi_errno(cs, -1);
}
- init_featurefile_guestfd(guestfd);
+ staticfile_guestfd(guestfd, featurefile_data,
+ sizeof(featurefile_data));
return guestfd;
}
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
new file mode 100644
index 0000000000..b6405f5663
--- /dev/null
+++ b/semihosting/guestfd.c
@@ -0,0 +1,118 @@
+/*
+ * 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"
+
+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;
+}
+
+/*
+ * 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);
+ gf->type = GuestFDUnused;
+}
diff --git a/semihosting/meson.build b/semihosting/meson.build
index 10b3b99921..d2c1c37bfd 100644
--- a/semihosting/meson.build
+++ b/semihosting/meson.build
@@ -1,3 +1,7 @@
+specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
+ 'guestfd.c',
+))
+
specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SOFTMMU'], if_true: files(
'config.c',
'console.c',