|
@@ -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
|
|
|
|
|
|
/**
|
|
@@ -268,98 +248,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
|
|
@@ -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;
|
|
|
}
|
|
|
|