Peter Maydell <peter.mayd...@linaro.org> writes:
> Version 2.0 of the semihosting specification added support for > allowing a guest to detect whether the implementation supported > particular features. This works by the guest opening a magic > file ":semihosting-features", which contains a fixed set of > data with some magic numbers followed by a sequence of bytes > with feature flags. The file is expected to behave sensibly > for the various semihosting calls which operate on files > (SYS_FLEN, SYS_SEEK, etc). > > Implement this as another kind of guest FD using our function > table dispatch mechanism. Initially we report no extended > features, so we have just one feature flag byte which is zero. > > Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> with your EACCESS suggestion: Reviewed-by: Alex Bennée <alex.ben...@linaro.org> > --- > target/arm/arm-semi.c | 107 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 106 insertions(+), 1 deletion(-) > > diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c > index f9019b00b8d..531084b7799 100644 > --- a/target/arm/arm-semi.c > +++ b/target/arm/arm-semi.c > @@ -117,6 +117,7 @@ typedef enum GuestFDType { > GuestFDUnused = 0, > GuestFDHost = 1, > GuestFDGDB = 2, > + GuestFDFeatureFile = 3, > } GuestFDType; > > /* > @@ -125,7 +126,10 @@ typedef enum GuestFDType { > */ > typedef struct GuestFD { > GuestFDType type; > - int hostfd; > + union { > + int hostfd; > + target_ulong featurefile_offset; > + }; > } GuestFD; > > static GArray *guestfd_array; > @@ -467,6 +471,87 @@ static uint32_t gdb_flenfn(TaskState *ts, ARMCPU *cpu, > GuestFD *gf) > gf->hostfd, arm_flen_buf(cpu)); > } > > +#define SHFB_MAGIC_0 0x53 > +#define SHFB_MAGIC_1 0x48 > +#define SHFB_MAGIC_2 0x46 > +#define SHFB_MAGIC_3 0x42 > + > +static const uint8_t featurefile_data[] = { > + SHFB_MAGIC_0, > + SHFB_MAGIC_1, > + SHFB_MAGIC_2, > + SHFB_MAGIC_3, > + 0, /* 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(TaskState *ts, ARMCPU *cpu, GuestFD *gf) > +{ > + /* Nothing to do */ > + return 0; > +} > + > +static uint32_t featurefile_writefn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, > + target_ulong buf, uint32_t len) > +{ > + /* This fd can never be open for writing */ > + errno = EBADF; > + return set_swi_errno(ts, -1); > +} > + > +static uint32_t featurefile_readfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, > + target_ulong buf, uint32_t len) > +{ > + uint32_t i; > +#ifndef CONFIG_USER_ONLY > + CPUARMState *env = &cpu->env; > +#endif > + char *s; > + > + s = lock_user(VERIFY_WRITE, buf, len, 0); > + if (!s) { > + return len; > + } > + > + for (i = 0; i < len; i++) { > + if (gf->featurefile_offset >= sizeof(featurefile_data)) { > + break; > + } > + s[i] = featurefile_data[gf->featurefile_offset]; > + gf->featurefile_offset++; > + } > + > + unlock_user(s, buf, len); > + > + /* Return number of bytes not read */ > + return len - i; > +} > + > +static uint32_t featurefile_isattyfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) > +{ > + return 0; > +} > + > +static uint32_t featurefile_seekfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf, > + target_ulong offset) > +{ > + gf->featurefile_offset = offset; > + return 0; > +} > + > +static uint32_t featurefile_flenfn(TaskState *ts, ARMCPU *cpu, GuestFD *gf) > +{ > + return sizeof(featurefile_data); > +} > + > typedef struct GuestFDFunctions { > sys_closefn *closefn; > sys_writefn *writefn; > @@ -493,6 +578,14 @@ 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, > + }, > }; > > /* Read the input value from the argument block; fail the semihosting > @@ -586,6 +679,18 @@ target_ulong do_arm_semihosting(CPUARMState *env) > unlock_user(s, arg0, 0); > return guestfd; > } > + if (strcmp(s, ":semihosting-features") == 0) { > + unlock_user(s, arg0, 0); > + /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ > + if (arg1 != 0 && arg1 != 1) { > + dealloc_guestfd(guestfd); > + errno = EINVAL; > + return set_swi_errno(ts, -1); > + } > + init_featurefile_guestfd(guestfd); > + return guestfd; > + } > + > if (use_gdb_syscalls()) { > ret = arm_gdb_syscall(cpu, arm_semi_cb, "open,%s,%x,1a4", arg0, > (int)arg2+1, gdb_open_modeflags[arg1]); -- Alex Bennée