diff options
Diffstat (limited to 'semihosting')
-rw-r--r-- | semihosting/arm-compat-semi.c | 164 | ||||
-rw-r--r-- | semihosting/guestfd.c | 118 | ||||
-rw-r--r-- | semihosting/meson.build | 4 |
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', |